source: trunk/bootcode/regular/driveio.asm@ 143

Last change on this file since 143 was 143, checked in by Ben Rietbroek, 8 years ago

Added function to scan all disks for base information [v1.1.1-testing]

This function does the initial scanning of disks with the purpose of
populating the DISKINFO structures for each disk.

It precedes the second scanning stage, which involves scanning disks to
gather info about partitions etc.

CAUTION:
This is a testbuild !
AirBoot uses the BIOS to access disks and a small coding error can trash
partition tables or other vital disk structures. You are advised to make
backups of TRACK0 and EBRs before using this testbuild. More info at:
https://rousseaux.github.io/netlabs.air-boot/pdf/AirBoot-v1.1.0-manual.pdf

File size: 65.5 KB
Line 
1; AiR-BOOT (c) Copyright 1998-2008 M. Kiewitz
2;
3; This file is part of AiR-BOOT
4;
5; AiR-BOOT is free software: you can redistribute it and/or modify it under
6; the terms of the GNU General Public License as published by the Free
7; Software Foundation, either version 3 of the License, or (at your option)
8; any later version.
9;
10; AiR-BOOT is distributed in the hope that it will be useful, but WITHOUT ANY
11; WARRANTY: without even the implied warranty of MERCHANTABILITY or FITNESS
12; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13; details.
14;
15; You should have received a copy of the GNU General Public License along with
16; AiR-BOOT. If not, see <http://www.gnu.org/licenses/>.
17;
18;---------------------------------------------------------------------------
19; AiR-BOOT / DRIVE I/O
20;---------------------------------------------------------------------------
21
22
23
24IFDEF MODULE_NAMES
25DB 'DRIVEIO',0
26ENDIF
27
28;
29; Check if INT13X extensions are supported.
30; AirBoot requires these extensions, and will halt if they are not available.
31; Modified: [CurIO_UseExtension]
32DriveIO_CheckFor13extensions Proc Near Uses ax bx cx dx
33 mov ah, 41h
34 mov bx, 55AAh
35 mov dl, [BIOS_BootDisk] ; We check using the boot-disk
36 int 13h
37
38IFDEF AUX_DEBUG
39 IF 0
40 DBG_TEXT_OUT_AUX 'DriveIO_CheckFor13extensions:'
41 PUSHRF
42 call DEBUG_DumpRegisters
43 ;~ call AuxIO_DumpParagraph
44 ;~ call AuxIO_TeletypeNL
45 mov si, offset [Scratch]
46 mov word ptr [si], 50h
47 mov ah, 48h
48 int 13h
49 call DEBUG_DumpRegisters
50 ;~ call AuxIO_DumpSector
51 POPRF
52 ENDIF
53ENDIF
54
55 jc PCCF13E_NotFound ; Error occured
56 cmp bx, 0AA55h
57 je PCCF13E_Found
58 PCCF13E_NotFound:
59 ret
60 PCCF13E_Found:
61 and cx, 1 ; Check 42h-44h,47h,48h supported
62 jz PCCF13E_NotFound ; Sig OK but no support, strange beast
63 mov byte ptr [CurIO_UseExtension], 1
64 ret
65DriveIO_CheckFor13extensions EndP
66
67
68; Note: Some routines set DS/ES to CS or even address via CS, even if its not
69; needed. This was done for SECURITY. So DO NOT remove it.
70; Its there to make sure the correct data is loaded/written to/from
71; harddrive.
72;
73; IF YOU MODIFY ANYTHING IN HERE, YOU MAY EASILY BREAK YOUR HARDDRIVE!
74
75; Will only load base-configuration, will NOT load IPT nor Hide-Config
76; Those are originally loaded on startup and will NOT get reloaded.
77DriveIO_LoadConfiguration Proc Near Uses ax bx cx dx es
78
79IFDEF AUX_DEBUG
80 IF 0
81 DBG_TEXT_OUT_AUX 'DriveIO_LoadConfiguration:'
82 PUSHRF
83 ;~ call DEBUG_DumpRegisters
84 ;~ call AuxIO_DumpParagraph
85 ;~ call AuxIO_TeletypeNL
86 POPRF
87 ENDIF
88ENDIF
89
90;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
91 mov ax, cs
92 mov es, ax
93 mov bx, offset Configuration
94 xor dh, dh
95 mov dl, [BIOS_BootDisk] ; Disk we booted from
96 mov cx, 0037h ; Sector 55 (CHS)
97 mov ax, 0201h ; Function 02, read 1 sector...
98 int 13h
99 jnc DIOLC_NoError
100 call MBR_LoadError ; Will Abort BootUp
101
102
103 DIOLC_NoError:
104 ret
105DriveIO_LoadConfiguration EndP
106
107DriveIO_SaveConfiguration Proc Near Uses ax bx cx dx ds es si
108
109IFDEF AUX_DEBUG
110 IF 0
111 DBG_TEXT_OUT_AUX 'DriveIO_SaveConfiguration:'
112 PUSHRF
113 ;~ call DEBUG_DumpRegisters
114 ;~ call AuxIO_DumpParagraph
115 ;~ call AuxIO_TeletypeNL
116 POPRF
117 ENDIF
118ENDIF
119
120 mov ax, cs
121 mov ds, ax
122 mov es, ax ; Safety first (CS==DS==ES)
123 ; --- Overwrite Floppy-Name with "FloppyDrive"
124 mov si, offset TXT_Floppy_Drive
125 mov di, offset PartitionTable
126 sub di, 30 ; Adjust to Floppy-Name
127 mov cx, 11
128 rep movsb
129 mov si, offset Configuration ; Calculate new checksum
130 xor bx, bx
131
132 ; Changed from 5 to calculated value (not here, see compat. issue below)
133 ; Fixes issue: #2987 -- "air-boot doesn't remember drive letter"
134 ; Size of the ab-configuration in 512 byte sectors
135 ;mov cx, (MBR_BackUpMBR - Configuration) / 200h
136
137 ; AB v1.07 stores a 5 sector configuration with a 5 sector checksum.
138 ; AB v1.0.8+ *should* stores a 7 sector configuration with a
139 ; 7 sector checksum.
140 ; Because 5 was hardcoded here, SET(A)BOOT v1.07 will see see an AB v1.0.8+
141 ; config as corrupted, while this is not the case.
142 ; So, for compatibility reasons, in v1.0.8+, the checksum stored is over
143 ; 5 sectors, to be compatible with v1.07.
144 ; This may change (be corrected) in future versions !
145 mov cx,5
146
147 mov dx, [CFG_CheckConfig]
148 mov [CFG_CheckConfig], bx
149 DIOSC_Loop:
150 call MBR_GetCheckOfSector
151 loop DIOSC_Loop
152 mov [CFG_CheckConfig], bx
153 ; --------------------------------------------------------------------
154 ; ES == CS
155 mov bx, offset Configuration
156 xor dh, dh
157 mov dl, [BIOS_BootDisk] ; Disk we booted from
158 mov cx, 0037h ; Sector 55 (CHS)
159
160 ; Changed from 5 to calculated value
161 ; Fixes issue: #2987 -- "air-boot doesn't remember drive letter"
162 ; Size of the ab-configuration in 512 byte sectors
163 mov al, (MBR_BackUpMBR - Configuration) / 200h
164 mov ah,03h
165;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
166 int 13h
167 jnc DIOSC_NoError
168 call MBR_SaveError ; Will Abort BootUp
169 DIOSC_NoError:
170 ret
171DriveIO_SaveConfiguration EndP
172
173DriveIO_UpdateFloppyName Proc Near Uses bx cx dx ds si es di
174 mov ax, cs
175 mov ds, ax
176 mov es, ax
177
178 mov ah, 00h ; Function 0 - Reset Drive
179 xor dl, dl
180 int 13h
181 xor dx, dx ; Cylinder=0, Head=0
182 mov cx, 1 ; Sector=1, Drive=0
183 mov bx, offset TmpSector ; ES:BX - TmpSector
184 mov ax, 0201h ; Function 2 - Load Sector
185 int 13h
186 jnc DIOUFN_AllFine
187
188 ; --- Overwrite Floppy-Name with "No Disc"
189 mov si, offset TXT_Floppy_NoDisc
190 xor ax, ax
191 DIOUFN_WriteFloppyName:
192 mov di, offset PartitionTable
193 sub di, 30 ; Adjust to Floppy-Name
194 mov cl, 11
195 rep movsb
196 ret ; AX=-1 -> GotDisc, =0 -> NoDisc
197
198 ; --- Floppy found and read, data in TempSector
199 DIOUFN_AllFine:
200 mov ax, -1
201 mov si, offset TXT_Floppy_NoName
202 cmp wptr es:[bx+54], 'AF'
203 jne DIOUFN_WriteFloppyName
204 cmp wptr es:[bx+56], '1T'
205 jne DIOUFN_WriteFloppyName
206 cmp bptr es:[bx+58], '2'
207 jne DIOUFN_WriteFloppyName
208 mov si, bx
209 add si, 43 ; FAT12 - Volume Label Location
210 jmp DIOUFN_WriteFloppyName
211DriveIO_UpdateFloppyName EndP
212
213; =============================================================================
214; HARDDRIVE / GENERAL ACCESS
215; =============================================================================
216; The following routines are used for harddisc/floppy access.
217; The access is done via INT 13h/CHS or INT 13h/LBA.
218; Access will be done prefered by INT 13h/CHS, because it's (I wonder!) much
219; faster, than the LBA-method. I don't know, why LBA is so slow. Perhaps BIOS.
220;
221; Internal access (to AiR-BOOT) is always done via INT 13h/CHS.
222
223DriveIO_GetHardDriveCount Proc Near Uses ds si
224 push ds
225 push si
226 push 0040h
227 pop ds
228 mov si, 0075h
229 mov dh, ds:[si] ; 40:75 -> POST: Total Harddiscs == DL
230 pop si
231 pop ds
232 mov [TotalHarddiscs], dh
233 ret
234DriveIO_GetHardDriveCount EndP
235
236
237; Fills our LBA-Usage table. It holds the LBA-address, where BIOS/CHS access is
238; stopped and BIOS/LBA access is started.
239; This is calculated by Sector*Heads. Comparing will get done with Bit 25-10
240; on LBA sectors, so we actually divide sector number by 1024.
241DriveIO_InitLBASwitchTable Proc Near Uses es di
242 mov di, offset LBASwitchTable
243 mov dh, [TotalHarddiscs]
244 mov dl, 80h ; First disk to process
245 DIOILUT_DriveLoop:
246 push dx
247 push di
248 mov ah, 08h
249 int 13h ; DISK - GET DRIVE PARAMETERS
250 mov ah, 0FBh ; Assume 255 heads/63 sectors, if error
251 jc DIOILUT_Error
252 and cl, 111111b ; Isolate lower 6 bits of CL -> sector count
253;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
254 ;movzx ax, cl
255 mov al,cl
256 mov ah,0
257
258 mov bl, dh ; DH -> max head number
259 mul bl ; AX = Sectors*Heads
260 shl ah, 1
261 shl ah, 1 ; Shift 2 bits, so we are able to compare to
262 ; bit 16-23 of the LBA address
263 DIOILUT_Error:
264 pop di
265 pop dx
266 mov bptr ds:[di], ah ; Save that value
267 inc di ; Go to next BYTE
268 inc dl ; Next disk
269 dec dh ; Decrease disks to process
270 jnz DIOILUT_DriveLoop ; Next disk if DH != 0
271 ret
272DriveIO_InitLBASwitchTable EndP
273
274
275
276
277;FIXME: Only LBA gets updated, need to update CHS too !!!!!!!
278
279; Adjusts BX:AX / CX:DX to meet LVM sector location
280; BX:AX / CX:DX point to MBR or EBR !
281; Destroys SI
282; Rousseau: Enhanced to handle sector-numbers 127 and 255 besides 63 for LVM-info sectors.
283; Ugly, need to cleanup.
284DriveIO_LVMAdjustToInfoSector Proc Near
285
286IFDEF AUX_DEBUG
287 IF 0
288 DBG_TEXT_OUT_AUX 'DriveIO_LVMAdjustToInfoSector:'
289 PUSHRF
290 call DEBUG_DumpRegisters
291 ;~ call AuxIO_DumpParagraph
292 ;~ call AuxIO_TeletypeNL
293 POPRF
294 ENDIF
295ENDIF
296
297 push cx ; Save Cyl/Sec part
298 xor ch,ch ; Clear low Cyl part
299 and cl,63 ; Clear high Cyl part
300 push bx ; We need BX...
301 push dx ; and DX temoraily
302 mov bx,offset [TrueSecs] ; Offset of sector table
303 xor dh,dh ; Clear DH because we use DL as index
304 and dl,01111111b ; Remove high bit of BIOS disk-nr
305 shl dx,2 ; Index to DWORD table
306 add bx,dx ; Point to TrueSecs for this disk
307 mov si,[bx] ; Get SPT for this disk
308 pop dx ; Restore DX...
309 pop bx ; and BX
310 ;~ sub si,cx ; Adjust offset !! INCORRECT FOR LBA (TP CX != 0 !!)
311 dec si
312 pop cx ; Restore Cyl/Sec part
313 add ax,si ; Add offset to low part...
314 adc bx,0 ; and high part of LBA address
315 or cl,63 ; Adjust CHS part !FIX ME for > 63! !! FIX HUGE DRIVE !!
316
317IFDEF AUX_DEBUG
318 IF 0
319 DBG_TEXT_OUT_AUX 'adjusted'
320 PUSHRF
321 call DEBUG_DumpRegisters
322 ;~ call AuxIO_DumpParagraph
323 ;~ call AuxIO_TeletypeNL
324 POPRF
325 ENDIF
326ENDIF
327
328 ret
329
330DriveIO_LVMAdjustToInfoSector EndP
331
332
333
334
335
336
337; #########################################################################
338; Routine: Loads partition to ExecBase and checks for validity
339; #########################################################################
340; Calling : bx:ax - Absolute sector
341; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
342; Returns : Carry Set if invalid partition encountered
343; Preserve: all registers
344; #########################################################################
345DriveIO_LoadPartition Proc Near Uses si
346
347IFDEF AUX_DEBUG
348 IF 0
349 DBG_TEXT_OUT_AUX 'DriveIO_LoadPartition:'
350 PUSHRF
351 call DEBUG_DumpRegisters
352 ;~ call AuxIO_DumpParagraph
353 ;~ call AuxIO_TeletypeNL
354 POPRF
355 ENDIF
356ENDIF
357
358 mov wptr cs:[CurPartition_Location+0], ax
359 mov wptr cs:[CurPartition_Location+2], bx
360 mov wptr cs:[CurPartition_Location+4], dx
361 mov wptr cs:[CurPartition_Location+6], cx ; Saves the location
362 mov si, offset PartitionSector ; DS:SI - ExecBase
363
364
365;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
366 call DriveIO_LoadSector
367
368 clc
369 cmp wptr [si+LocBR_Magic], 0AA55h
370 je DIOLP_Success
371 ; We check, if we are scanning partitions. In that case, if CHS is not 0/0/1
372 ; we will display a "bad partition table" message and halt the system.
373 cmp cx, 0001h
374 jne DIOLP_Failed
375 or dh, dh
376 jnz DIOLP_Failed
377 stc ; Set carry, so no partition table
378 DIOLP_Success:
379
380
381
382 ret
383 DIOLP_Failed:
384 jmp DriveIO_GotLoadError
385DriveIO_LoadPartition EndP
386
387; #########################################################################
388; Routine: Writes a partition from ExecBase to its original sector
389; #########################################################################
390; Calling : none
391; Returns : none
392; Preserve: all registers
393; #########################################################################
394DriveIO_SavePartition Proc Near Uses ax bx cx dx si
395
396IFDEF AUX_DEBUG
397 IF 0
398 DBG_TEXT_OUT_AUX 'DriveIO_SavePartition:'
399 PUSHRF
400 ;~ call DEBUG_DumpRegisters
401 ;~ call AuxIO_DumpParagraph
402 ;~ call AuxIO_TeletypeNL
403 POPRF
404 ENDIF
405ENDIF
406
407 mov ax, wptr cs:[CurPartition_Location+0]
408 mov bx, wptr cs:[CurPartition_Location+2]
409 mov dx, wptr cs:[CurPartition_Location+4]
410 mov cx, wptr cs:[CurPartition_Location+6] ; Gets prev. saved location
411 mov si, offset PartitionSector ; DS:SI - ExecBase
412 cmp wptr [si+LocBR_Magic], 0AA55h ; Checks for signature, if not found
413 jne DIOSP_SevereError ; we assume a really bad error
414 call DriveIO_SaveSector
415 DIOSP_SevereError:
416 ret
417DriveIO_SavePartition EndP
418
419; Keeps DS:SI for caller
420DriveIO_LoadTmpSector Proc Near
421 mov si, offset TmpSector
422 call DriveIO_LoadSector
423 ret
424DriveIO_LoadTmpSector EndP
425
426; Keeps DS:SI for caller
427DriveIO_SaveTmpSector Proc Near
428 mov si, offset TmpSector
429 call DriveIO_SaveSector
430 ret
431DriveIO_SaveTmpSector EndP
432
433
434
435; Keeps DS:SI for caller, sets carry if valid LVM sector encountered
436DriveIO_LoadLVMSector Proc Near Uses ax bx cx dx
437
438IFDEF AUX_DEBUG
439 IF 0
440 DBG_TEXT_OUT_AUX 'DriveIO_LoadLVMSector:'
441 PUSHRF
442 call DEBUG_DumpRegisters
443 call AuxIO_DumpSector
444 ;~ call AuxIO_DumpParagraph
445 ;~ call AuxIO_TeletypeNL
446 POPRF
447 ENDIF
448ENDIF
449
450 test byte ptr [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
451 jnz DIOLLVMS_NoLVMSector ; don't load but declare as bad!
452 mov ax, wptr cs:[CurPartition_Location+0]
453 mov bx, wptr cs:[CurPartition_Location+2]
454 mov dx, wptr cs:[CurPartition_Location+4]
455 mov cx, wptr cs:[CurPartition_Location+6] ; Gets cur. partition location
456
457 call DriveIO_LVMAdjustToInfoSector
458
459 mov si, offset [LVMSector]
460 call DriveIO_LoadSector
461
462IFDEF AUX_DEBUG
463 IF 0
464 DBG_TEXT_OUT_AUX 'lvm record ex'
465 PUSHRF
466 ;~ call AuxIO_TeletypeHexWord
467 ;~ call AuxIO_TeletypeNL
468 call DEBUG_DumpRegisters
469 ;~ call AuxIO_DumpSector
470 mov cx, 7
471 @@:
472 call AuxIO_DumpParagraph
473 call AuxIO_TeletypeNL
474 add si, 16
475 loop @B
476 POPRF
477 ENDIF
478ENDIF
479
480
481 call LVM_CheckSectorSignature
482 jnc DIOLLVMS_NoLVMSector
483 call LVM_CheckSectorCRC
484 jnc DIOLLVMS_NoLVMSector
485 ret
486
487 ; This here is called, if an invalid (or no) LVM information sector is found
488 ; It will truncate the first byte of the sector, so all other routines
489 ; will notice it easily by just comparing the first byte.
490 DIOLLVMS_NoLVMSector:
491 mov bptr [si+LocLVM_SignatureStart], 0
492 ret
493DriveIO_LoadLVMSector EndP
494
495
496
497; Keeps DS:SI for caller, saves at anytime w/o checks (!)
498DriveIO_SaveLVMSector Proc Near Uses ax bx cx dx
499
500IFDEF AUX_DEBUG
501 IF 0
502 DBG_TEXT_OUT_AUX 'DriveIO_SaveLVMSector:'
503 PUSHRF
504 ;~ call DEBUG_DumpRegisters
505 ;~ call AuxIO_DumpParagraph
506 ;~ call AuxIO_TeletypeNL
507 POPRF
508 ENDIF
509ENDIF
510
511 test byte ptr [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
512 jnz DIOSLVMS_SevereError ; don't save at anytime (security!)
513 mov ax, wptr cs:[CurPartition_Location+0]
514 mov bx, wptr cs:[CurPartition_Location+2]
515 mov dx, wptr cs:[CurPartition_Location+4]
516 mov cx, wptr cs:[CurPartition_Location+6] ; Gets cur. partition location
517 call LVM_CheckSectorSignature
518 jnc DIOSLVMS_SevereError ; LVM Signature must be there
519
520IFDEF AUX_DEBUG
521 IF 0
522 pushf
523 pusha
524 ;~ dioatlvm db 'DriveIO_LVMAdjustToInfoSector',10,0
525 ;~ pushf
526 ;~ pusha
527 ;~ mov si,offset dioatlvm
528 ;~ call AuxIO_Print
529 ;~ popa
530 ;~ popf
531 call DEBUG_DumpRegisters
532 call DEBUG_DumpCHS
533 popa
534 popf
535 ENDIF
536ENDIF
537
538 call DriveIO_LVMAdjustToInfoSector
539
540IFDEF AUX_DEBUG
541 IF 0
542 pushf
543 pusha
544 call DEBUG_DumpRegisters
545 call DEBUG_DumpCHS
546 popa
547 popf
548 ENDIF
549ENDIF
550
551 mov si, offset LVMSector
552 call DriveIO_SaveSector
553 DIOSLVMS_SevereError:
554 ret
555DriveIO_SaveLVMSector EndP
556
557
558
559; Special error message instead of "LOAD ERROR" during partition scanning,
560; so users will notice that something is bad with their partition table(s)
561DriveIO_GotLoadError Proc Near
562 test byte ptr cs:[CurIO_Scanning], 1 ; Must be CS:, cause DS!=CS maybe here
563 jnz InScanMode
564 jmp MBR_LoadError
565 InScanMode:
566 mov si, offset TXT_BrokenPartitionTable
567 push cs
568 pop ds
569 call MBR_Teletype
570 mov si, offset BrokenHDD
571 sub dl, 50h ; 80h -> '0'
572 cmp dl, 39h
573 jbe DIOGLE_BelowA
574 add dl, 7 ; 3Ah -> 'A'
575 DIOGLE_BelowA:
576 mov bptr [si+5], dl
577 call MBR_Teletype
578
579 ; JWasm: cannot jump to local label in other procedure.
580 ; Changed to halt here.
581 ;jmp MBRLE_Halt
582 DriveIO_GotLoadError_halt:
583 jmp DriveIO_GotLoadError_halt
584DriveIO_GotLoadError EndP
585
586; #########################################################################
587; Routine: Loads a specified sector to DS:DI
588; #########################################################################
589; Calling : bx:ax - Absolute sector
590; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
591; ds:si - Destination-Adress
592; Returns : none
593; Preserve: all registers
594; #########################################################################
595DriveIO_LoadSector Proc Near Uses ax bx cx dx ds si es di
596
597IFDEF AUX_DEBUG
598 IF 0
599 DBG_TEXT_OUT_AUX 'DriveIO_LoadSector:'
600 PUSHRF
601 call DEBUG_DumpRegisters
602 ;~ call AuxIO_DumpParagraph
603 ;~ call AuxIO_TeletypeNL
604 POPRF
605 ENDIF
606ENDIF
607
608 ; Is the drive not a harddrive?
609 cmp dl, 80h
610 jb DIOLS_UseNormal
611
612 test byte ptr cs:[CurIO_UseExtension], 1
613 jz DIOLS_UseNormal
614 ; Are we forced do use LBA via Setting?
615 jnz DIOLS_UseExtension
616
617 ; Upper 8 bits of LBA-address set?
618 ; Then use LBA (maximum boundary is 16320x16x63 = FB0400h)
619 or bh, bh
620 jnz DIOLS_UseExtension
621 ; Compare Switch-Table value to bit 16-23 of LBA-address
622 mov di, dx
623 and di, 007Fh
624 cmp bptr cs:[LBASwitchTable+di], bl
625 jbe DIOLS_UseExtension
626
627 DIOLS_UseNormal:
628
629IFDEF AUX_DEBUG
630 IF 0
631 DBG_TEXT_OUT_AUX 'DriveIO_ReadSectorCHS:'
632 PUSHRF
633 call DEBUG_DumpRegisters
634 call AuxIO_DumpParagraph
635 call AuxIO_TeletypeNL
636 POPRF
637 ENDIF
638ENDIF
639
640 mov di, 3 ; retry count
641 DIOLS_ErrorLoop:
642 push ds
643 pop es
644 mov bx, si ; ES:BX - Destination
645 mov ax, 0201h ; Function 2 - Load Sector
646 int 13h
647 jnc DIOLS_Success
648 dec di ; decrement retry count
649 jnz DIOLS_ErrorLoop
650
651 ; Sector load failed...
652 jmp DriveIO_GotLoadError
653
654 DIOLS_UseExtension:
655
656 mov di, ds ; segment for transfer address
657 call DriveIO_ReadSectorLBA ; extended read
658 jc DriveIO_GotLoadError ; halt on error
659
660 ;~ push cx
661 ;~ mov cs:[INT13X_DAP_NumBlocks], 1 ; Copy ONE sector
662 ;~ mov wptr cs:[INT13X_DAP_Transfer+0], si
663 ;~ mov cx, ds
664 ;~ mov wptr cs:[INT13X_DAP_Transfer+2], cx ; Fill out Transfer Adress
665 ;~ mov wptr cs:[INT13X_DAP_Absolute+0], ax
666 ;~ mov wptr cs:[INT13X_DAP_Absolute+2], bx ; Fill out Absolute Sector
667 ;~ push cs
668 ;~ pop ds
669 ;~ mov si, offset [INT13X_DAP]
670 ;~ mov ah, 42h ; Extended Read
671 ;~ int 13h
672 ;~ pop cx
673 ;~ jnc DIOLS_Success
674
675 ; Sector load failed...
676 ;~ jmp DriveIO_GotLoadError
677
678 DIOLS_Success:
679
680IFDEF AUX_DEBUG
681 IF 0
682 DBG_TEXT_OUT_AUX 'sector loaded'
683 PUSHRF
684 ;~ call DEBUG_DumpRegisters
685 ;~ call AuxIO_DumpSector
686 mov cx, 32
687 @@:
688 call AuxIO_DumpParagraph
689 call AuxIO_TeletypeNL
690 add si, 16
691 loop @B
692 POPRF
693 ENDIF
694ENDIF
695 ret
696DriveIO_LoadSector EndP
697
698
699;##############################################################################
700;# ACTION : Loads the Master Boot Record from the specified drive into buffer
701;# ----------------------------------------------------------------------------
702;# EFFECTS : Modifies DAP structure and fills or clears transfer buffer
703;# ----------------------------------------------------------------------------
704;# IN : DL - BIOS disk number (80h,81h,etc)
705;# : SI - Pointer to transfer buffer
706;# ----------------------------------------------------------------------------
707;# OUT : CF=1 - failure
708;# : AL.0 - MBR signature present
709;# : AL.1 - Primary partitions present
710;# : AL.2 - Extended partitions present
711;# : AL.3 - AiR-BOOT signature present
712;# : AL.4:7 - Reserved, returned as 0
713;# : AH.0:7 - Reserved, returned as 0
714;##############################################################################
715DriveIO_LoadMBR Proc Near uses bx cx dx si di
716
717 ; Always clear the transfer buffer first
718 call ClearSectorBuffer
719
720 ; Assume an invalid MBR
721 xor ax, ax
722
723 ; Accept only valid harddisks
724 call DriveIO_IsValidHarddisk
725 jc DriveIO_LoadMBR_exit
726
727 ; Save the address of the transfer buffer
728 mov di, si
729
730 ; Read the MBR from disk
731 xor ax, ax ; LBA low
732 xor bx, bx ; LBA high
733 xor dh, dh ; Head 0
734 mov cx, 1 ; Sector 1
735 call DriveIO_LoadSector ; Read the sector from disk
736
737 ; Check the loaded MBR for a signature
738 xor ax, ax ; Assume an invalid MBR
739 mov dx, [si+LocBR_Magic] ; Get word from MBR signature location
740 cmp dx, 0aa55h ; Is it the magic value ?
741 jne DriveIO_LoadMBR_exit ; Nope, no need to test anything else
742
743 ; Indicate we have a MBR signature
744 or al, 01h
745
746 ; Advance to the partition table
747 add si, 01beh
748
749 ; Total of 4 entries to check
750 mov cx, 4
751
752 DriveIO_LoadMBR_next_entry:
753 mov dl, [si+LocBRPT_SystemID] ; Get partition-type / system-id
754 add si, 10h ; Point to next entry
755 test dl, dl ; Nothing in this one ?
756 loopz DriveIO_LoadMBR_next_entry ; Then check next entry
757
758 ; All entries checked and last one was also empty, we're done
759 jz DriveIO_LoadMBR_check_ab
760
761 ; Found a non-empty entry, set bits according to its type
762 cmp dl, 05h ; Old style extended container ?
763 jne @F ; Nope...
764 or al, 04h ; Yep, mark ext. container present
765 @@: cmp dl, 0fh ; New style extended container ?
766 jne @F ; Nope...
767 or al, 04h ; Yep, mark ext. container present
768 @@: or al, 02h ; Then is must be a primary
769 jcxz DriveIO_LoadMBR_check_ab ; CX=0? Then all entries processed,
770 jmp DriveIO_LoadMBR_next_entry ; otherwise check next entry
771
772 ; Check if an AiR-BOOT signature is present
773 DriveIO_LoadMBR_check_ab:
774 mov si, offset [MBR_ABSig] ; Offset of AiR-BOOT signature
775 inc di ; Advance buffer pointer
776 inc di ; to AiR-BOOT signature location
777 mov cx, 7 ; Length of AiR-BOOT signature
778 cld ; Direction upwards
779 repe cmpsb ; Compare 7 bytes
780 jne DriveIO_LoadMBR_exit ; Nope, no AiR-BOOT on this disk
781 or al, 08h ; Yep, AiR-BOOT is on this disk
782 ;~ jmp DriveIO_LoadMBR_exit
783
784 DriveIO_LoadMBR_exit:
785 ret
786DriveIO_LoadMBR EndP
787
788
789;##############################################################################
790;# ACTION : Reads a sector from disk using INT13 extensions
791;# ----------------------------------------------------------------------------
792;# EFFECTS : Modifies DAP structure and fills transfer buffer
793;# ----------------------------------------------------------------------------
794;# IN : BX:AX - LBA address of sector
795;# : DI:SI - SEG:OFF of transfer buffer
796;# ----------------------------------------------------------------------------
797;# OUT : CF=1 - failure
798;##############################################################################
799DriveIO_ReadSectorLBA Proc Near
800
801IFDEF AUX_DEBUG
802 IF 0
803 DBG_TEXT_OUT_AUX 'DriveIO_ReadSectorLBA:'
804 PUSHRF
805 call DEBUG_DumpRegisters
806 call AuxIO_DumpParagraph
807 call AuxIO_TeletypeNL
808 POPRF
809 ENDIF
810ENDIF
811
812 ; Push all registers
813 pusha
814 push ds
815 push es
816
817 ; One sector to read
818 mov cs:[INT13X_DAP_NumBlocks], 1
819
820 ; Setup transfer address
821 mov wptr cs:[INT13X_DAP_Transfer+0], si ; offset
822 mov wptr cs:[INT13X_DAP_Transfer+2], di ; segment
823
824 ; Setup LBA64 address of requested sector
825 mov wptr cs:[INT13X_DAP_Absolute+0], ax ; low word lower part
826 mov wptr cs:[INT13X_DAP_Absolute+2], bx ; high word lower part
827 mov wptr cs:[INT13X_DAP_Absolute+4], 0 ; low word upper part
828 mov wptr cs:[INT13X_DAP_Absolute+6], 0 ; high word upper part
829
830 ; Address of packet
831 mov si, offset [INT13X_DAP] ; disk address packet
832
833 ; Do the extended read
834 mov ah, 42h ; read function
835 int 13h ; transfer to bios
836
837 ; Error occured
838 jc DriveIO_ReadSectorLBA_exit
839
840 ; AH should also be zero
841 test ah, ah
842 stc
843 jnz DriveIO_ReadSectorLBA_exit
844
845 ; Disk read succeeded, clear CF
846 clc
847
848 DriveIO_ReadSectorLBA_exit:
849
850 ; Pop all registers
851 pop es
852 pop ds
853 popa
854
855 ret
856DriveIO_ReadSectorLBA EndP
857
858
859
860;##############################################################################
861;# ACTION : Writes a sector to disk using INT13 extensions
862;# ----------------------------------------------------------------------------
863;# EFFECTS : Modifies DAP structure and mofifies the disk
864;# ----------------------------------------------------------------------------
865;# IN : BX:AX - LBA address of sector
866;# : DI:SI - SEG:OFF of transfer buffer
867;# ----------------------------------------------------------------------------
868;# OUT : CF=1 - failure
869;##############################################################################
870DriveIO_WriteSectorLBA Proc Near
871
872IFDEF AUX_DEBUG
873 IF 0
874 DBG_TEXT_OUT_AUX 'DriveIO_WriteSectorLBA:'
875 PUSHRF
876 call DEBUG_DumpRegisters
877 call AuxIO_DumpParagraph
878 call AuxIO_TeletypeNL
879 POPRF
880 ENDIF
881ENDIF
882
883 ; Push all registers
884 pusha
885 push ds
886 push es
887
888 ; One sector to read
889 mov cs:[INT13X_DAP_NumBlocks], 1
890
891 ; Setup transfer address
892 mov wptr cs:[INT13X_DAP_Transfer+0], si ; offset
893 mov wptr cs:[INT13X_DAP_Transfer+2], di ; segment
894
895 ; Setup LBA64 address of requested sector
896 mov wptr cs:[INT13X_DAP_Absolute+0], ax ; low word lower part
897 mov wptr cs:[INT13X_DAP_Absolute+2], bx ; high word lower part
898 mov wptr cs:[INT13X_DAP_Absolute+4], 0 ; low word upper part
899 mov wptr cs:[INT13X_DAP_Absolute+6], 0 ; high word upper part
900
901 ; Address of packet
902 mov si, offset [INT13X_DAP] ; disk address packet
903
904 ; Do the extended write
905 xor al, al ; no write verify
906 mov ah, 43h ; write function
907 int 13h ; transfer to bios
908
909 ; Error occured
910 jc DriveIO_WriteSectorLBA_exit
911
912 ; AH should also be zero
913 test ah, ah
914 stc
915 jnz DriveIO_WriteSectorLBA_exit
916
917 ; Disk write succeeded, clear CF
918 clc
919
920 DriveIO_WriteSectorLBA_exit:
921
922 ; Pop all registers
923 pop es
924 pop ds
925 popa
926
927 ret
928DriveIO_WriteSectorLBA EndP
929
930
931
932
933;##############################################################################
934;# The Master LVM sector is *not* necessarily located at the end of the BIOS
935;# view of TRACK0. Its location depends on the *OS/2 geometry* active when the
936;# disk was partitioned. For disks < 502MiB this will most likely be LBA sector
937;# 62, but for disks >502MiB, *extended* OS/2 geometry was used and DANIS506
938;# uses SPT=127 for disks < 1TiB while IBMS506 uses SPT=255.
939;# When a huge disk < 1TiB was partitioned with IBMS506, thus using SPT=255,
940;# and the driver was later changed to DANIS506, DANI uses SPT=255, eventhough
941;# the disk < 1TiB. Whether it is DANI that is LVM aware or something else
942;# (maybe LVM itself) that makes DANI use the correct geometry has yet to be
943;# investigated.
944;#
945;# Related geometry issues are also present with USB sticks, which can get
946;# assigned a geometry by OS/2, which can depend if the stick was partitioned
947;# on foreign systems or not, or even OS/2 manufacturing a geometry that is not
948;# the same as the BIOS reports to us here. In both cases, fixed disks and
949;# removable disks, the geometry recorded in the BPB of a partition can also
950;# influence the geometry that OS/2 assigns. This is the case when 'preparing'
951;# disks for LVM use, in which case BPB values could be incorporated.
952;#
953;# What this all boils down to, is that the geometry reported by the BIOS is
954;# of no practical use, especially not when taking BIOS USB MSD emulation into
955;# account. These are among the reasons why AirBoot needs to use LBA addressing
956;# when handling LVM stuff and why LBA use cannot be disabled in the SETUP
957;# anymore.
958;#
959;# So, a Master LVM sector can be present on any sector from LBA 254 downwards
960;# and the only way to locate the correct one is to scan all the way down and,
961;# if one is found, do proper validation on its values, because it may also be
962;# a 'phantom' LVM sector left over from previous partition layouts.
963;# Most of such 'phantoms' can be filtered out by verifying the location of
964;# the found sector against the OS/2 geometry it specifies itself, which means
965;# it must be located at the LBA of the SPT-1 it specifies.
966;##############################################################################
967;# ACTION : Locates the Master LVM sector on the specified disk
968;# ----------------------------------------------------------------------------
969;# EFFECTS : Leaves [Scratch] with last sector read or cleared
970;# ----------------------------------------------------------------------------
971;# IN : DL - BIOS disk number of drive to search
972;# ----------------------------------------------------------------------------
973;# OUT : CF=1 - found
974;# : BX:AX - LBA address of LVM sector if found, 0 otherwise
975;##############################################################################
976DriveIO_LocateMasterLVMSector Proc Near uses cx dx si di ds es
977
978IFDEF AUX_DEBUG
979 IF 1
980 DBG_TEXT_OUT_AUX 'DriveIO_LocateMasterLVMSector:'
981 PUSHRF
982 call DEBUG_DumpRegisters
983 ;~ call AuxIO_DumpSector
984 ;~ call AuxIO_DumpParagraph
985 ;~ call AuxIO_TeletypeNL
986 POPRF
987 ENDIF
988ENDIF
989
990 ; LBA address to start scanning down from
991 mov cx, 255
992
993 ; Make sure ES==DS
994 push ds
995 pop es
996
997 ; Because JCXZ is used, LBA sector 0 is never loaded and checked.
998 ; This is of course no problem since it is the MBR.
999 DriveIO_LocateMasterLVMSector_next:
1000 mov si, offset [Scratch] ; Use scratch area to load sectors
1001 call ClearSectorBuffer ; Clear the scratch area
1002 clc ; Indicate Master LVM sector not found
1003 jcxz DriveIO_LocateMasterLVMSector_done
1004
1005 ; Read the LBA sector specified in CX
1006 mov ax, cx ; LBA low
1007 xor bx, bx ; LBA high
1008 mov di, ds ; Segment of scratch buffer
1009 mov si, offset [Scratch] ; Offset of scratch buffer
1010 call DriveIO_ReadSectorLBA ; Read the sector
1011 lahf ; Save CF
1012 dec cx ; Prepare LBA of next sector to read
1013 sahf ; Restore CF
1014 ; No need to do any LVM sector validation when read error, read next
1015 jc DriveIO_LocateMasterLVMSector_next
1016
1017 ; See if the read sector has a valid signature and checksum
1018 call LVM_ValidateSector
1019
1020 ; NC indicates invalid or none-LVM sector, read next
1021 jnc DriveIO_LocateMasterLVMSector_next
1022
1023 ; We have found a valid LVM sector !
1024 ; So it contains the OS/2 geometry for the disk.
1025 ; That means this LVM sector itself must be located on the last sector
1026 ; of the SPT value its OS/2 geometery specifies, which, in LBA terms
1027 ; is LVM SPT-1 -- let's check that...
1028 mov bx, offset [Scratch] ; Offset of the loaded LVM sector
1029 mov al, [bx+LocLVM_Secs] ; Get the LVM SPT value (<=255)
1030 dec al ; Adjust to LVM LBA
1031 mov ah, cl ; Get next LVM LBA to search
1032 inc ah ; This one was found here
1033 cmp al, ah ; If same, LVM LBA location OK
1034 jne DriveIO_LocateMasterLVMSector_next
1035
1036 ; The LVM sector we found is at the location it should be on disk,
1037 ; so it's almost 99% sure this is the correct one.
1038 ; Now we should compare the start and sizes of the partitions in the
1039 ; MBR with the partitions specified in this LVM record.
1040 ; We'll implement that later after some more research.
1041 ; For now we assume this is the correct Master LVM sector for the disk.
1042 inc cx ; CX was prepared to read next, correct that
1043 stc ; Indicate we have found the Master LVM sector
1044
1045 DriveIO_LocateMasterLVMSector_done:
1046 mov bx, 0 ; A Master LVM sector always has high LBA=0
1047 mov ax, cx ; Low LBA of Master LVM sector
1048
1049 ; We leave it up to the caller to store the value in a proper place
1050 ret
1051DriveIO_LocateMasterLVMSector EndP
1052
1053
1054
1055;
1056; ############################################################
1057; # Check for a valid MBR-sector to be written to disk #
1058; ############################################################
1059;
1060; In
1061; --
1062; DL = Physical Disk
1063; BX:CX = LBA sector
1064; DI:SI = Source buffer
1065;
1066; Out
1067; ---
1068; CY = 1 if invalid MBR in source buffer, 0 if valid
1069;
1070; This routine is called when DriveIO_SaveSector attempts to write to the MBR.
1071; It checks if the sector to be written has some sensible values in certain
1072; places. In fact, if the sector is written to the boot-disk, the AiR-BOOT
1073; signature should be present and the partition table should be the same
1074; as the one at the start of the AiR-BOOT code in memory, except maybe for the
1075; active flags.
1076; For other disks, only the active flags are checked to be 00h or 80h and
1077; the AA55h MBR signature.
1078;
1079DriveIO_ProtectMBR Proc Near
1080 pusha ; Push all registers
1081 push es ; Push ES because we need it for string instructions
1082 push cs ; Make ES point...
1083 pop es ; to CS
1084
1085 ; Save the pointer to the sector to write in BX
1086 mov bx,si
1087
1088 ;
1089 ; If the sector to be written is not the boot-disk, then skip
1090 ; checking the AiR-BOOT MBR.
1091 ;
1092 cmp dl, [BIOS_BootDisk]
1093 jne DriveIO_ProtectMBR_is_not_bootdisk
1094
1095 ;
1096 ; The boot-disk is accessed so the sector to be written must be
1097 ; the AiR-BOOT MBR. This is the same as the first 512 bytes
1098 ; relocated to 8000:0000 and this the start of the AB-code.
1099 ;
1100 mov si,bx ; Get pointer to sector to write
1101 xor di,di ; Point DI to start of AB-code (MBR)
1102 mov cx, offset [MBR_PartTable] ; Bytes upto P-table must be same
1103 cld ; Compare upwards
1104 repe cmpsb ; Compare upto P-table
1105
1106 ; If not the same this is not the an AiR-BOOT boot-disk MBR !
1107 jne DriveIO_ProtectMBR_not_valid_MBR ; SEVERE ERROR !
1108
1109 ; Continue with signature check
1110 jmp DriveIO_ProtectMBR_check_signature
1111
1112
1113 ;
1114 ; The disk is not the boot-disk so we don't know what kind of MBR is on it.
1115 ; Some sanity checks should be here.
1116 ;
1117 DriveIO_ProtectMBR_is_not_bootdisk:
1118
1119 ;
1120 ; sanity checks...
1121 ;
1122
1123 ; Continue with signature check
1124 jmp DriveIO_ProtectMBR_check_signature
1125
1126
1127 DriveIO_ProtectMBR_check_signature:
1128 ; See if the sector to write contains a valid signature
1129 mov si,bx ; Get pointer to sector to write
1130 mov di, offset [MBR_Sig] ; Offset to MBR signature
1131 add si,di ; Make SI point to it in sec to write
1132 lodsw ; Load it
1133 cmp ax,0aa55h ; See if it is valid
1134
1135 ; If no signature this cannot be a valid MBR !
1136 jne DriveIO_ProtectMBR_not_valid_MBR ; SEVERE ERROR !
1137
1138
1139 ;
1140 ; The sector to be written seems to be valid.
1141 ; Set CY=0 to indicate a valid MBR.
1142 ;
1143 DriveIO_ProtectMBR_is_valid_MBR:
1144 clc
1145 jmp DriveIO_ProtectMBR_end
1146
1147 ;
1148 ; Something is terribly wrong; a non-MBR sector seems about to be written.
1149 ; Set CY=1 and let the calling code handle this situation.
1150 ;
1151 DriveIO_ProtectMBR_not_valid_MBR:
1152 stc
1153 jmp DriveIO_ProtectMBR_end
1154
1155 ;
1156 ; Return to the caller with no registers modyfied except FLAGS.
1157 ;
1158 DriveIO_ProtectMBR_end:
1159 pop es
1160 popa
1161 ret
1162DriveIO_ProtectMBR Endp
1163
1164
1165
1166; #########################################################################
1167; Routine: Checks if the MBR is addressed by either CHS or LBA
1168; #########################################################################
1169; Calling : bx:ax - Absolute sector
1170; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
1171; Returns : ZF=1 if MBR is addressed, else ZF=0
1172; Preserve: all registers
1173; #########################################################################
1174DriveIO_MBR_Addressed Proc
1175 push ax
1176 push bx
1177
1178 or bx,ax ; Results in 0 in BX if MBR is addressed by LBA
1179 jz DriveIO_MBR_Addressed_done
1180
1181 mov ax,cx ; Results in 1 in AX if CYL 0, SEC 1 is addressed
1182 add al,dh ; Results in 1 in AX if HEAD 0 is addressed
1183 dec ax ; Results in 0 in AX if MBR is addressed by CHS
1184
1185 DriveIO_MBR_Addressed_done:
1186 pop bx
1187 pop ax
1188 ret
1189DriveIO_MBR_Addressed EndP
1190
1191
1192
1193
1194; #########################################################################
1195; Routine: Writes DS:SI to a specified sector
1196; #########################################################################
1197; Calling : bx:ax - Absolute sector
1198; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
1199; ds:si - Source-Adress
1200; Returns : none
1201; Preserve: all registers
1202; #########################################################################
1203DriveIO_SaveSector Proc Near Uses ax bx cx dx ds si es di
1204
1205IFDEF AUX_DEBUG
1206 IF 0
1207 DBG_TEXT_OUT_AUX 'DriveIO_SaveSector:'
1208 PUSHRF
1209 ;~ call DEBUG_DumpRegisters
1210 ;~ call AuxIO_DumpParagraph
1211 ;~ call AuxIO_TeletypeNL
1212 POPRF
1213 ENDIF
1214ENDIF
1215
1216
1217;!
1218;! DEBUG_BLOCK
1219;! Force write to LBA0 to test interception routine.
1220;! Do *NOT* enable unless you are debugging, will overwrite MBR !
1221;!
1222IFDEF AUX_DEBUG
1223 IF 0
1224 pushf
1225 pusha
1226 xor ax,ax
1227 xor bx,bx
1228 xor cx,cx
1229 inc cx
1230 xor dh,dh
1231 popa
1232 popf
1233 ENDIF
1234ENDIF
1235
1236 ;
1237 ; Check if the MBR is the destination for the write.
1238 ; ZF=1 if so.
1239 ;
1240 call DriveIO_MBR_Addressed
1241 jnz DriveIO_SaveSector_continue_write
1242
1243
1244 ; MBR is addressed, check the sector that is requested to be written.
1245 ; For the bootdisk it should contain the AiR-BOOT signature, valid
1246 ; partition-table entries and the AA55h signature.
1247 ; If not, something is terribly wrong in some piece of the AB code.
1248 ; For any other disk (80h+) at least a valid partition table should
1249 ; be present together with the AA55h signature.
1250 call DriveIO_ProtectMBR
1251 jnc DriveIO_SaveSector_continue_write
1252
1253
1254 ;
1255 ; WE HAVE A SEVERE ERROR CONDITION !
1256 ; SOME AB CODE TRIES TO WRITE A NON-MBR TO THE DISK !
1257 ; ASK THE USER TO REPORT THIS !
1258 ; HALT THE SYSTEM !
1259 ;
1260
1261 ; Show error-box
1262 mov cx, 0C04h
1263 mov si, offset NonMBRwrite
1264 call SETUP_ShowErrorBox
1265 mov cx, 0C04h
1266 mov si, offset NonMBRwrite_rep
1267 call SETUP_ShowErrorBox
1268
1269
1270IFDEF AUX_DEBUG
1271 IF 0
1272 pushf
1273 pusha
1274 mov si, offset [NonMBRwrite]
1275 call AuxIO_TeletypeNL
1276 call AuxIO_Print
1277 call AuxIO_TeletypeNL
1278 popa
1279 popf
1280 ENDIF
1281ENDIF
1282
1283 ; Show popup and halt the system.
1284 jmp HaltSystem
1285
1286
1287
1288 ;
1289 ; Continue the write if not MBR sector or MBR to write is validated.
1290 ;
1291 DriveIO_SaveSector_continue_write:
1292 test byte ptr cs:[CurIO_UseExtension], 1
1293 jz DIOSS_UseNormal
1294 ; Are we forced do use LBA via Setting?
1295 ; Always use INT13X on v1.0.8+.
1296 ;~ test byte ptr cs:[CFG_ForceLBAUsage], 1
1297 ;~ jnz DIOSS_UseExtension
1298 jmp DIOSS_UseExtension
1299 ; Is the drive not a harddrive?
1300 cmp dl, 80h
1301 jb DIOSS_UseNormal
1302 ; Upper 8 bits of LBA-address set? -> Use LBA (maximum boundary is FB0400h)
1303 or bh, bh
1304 jnz DIOSS_UseExtension
1305 ; Compare Switch-Table value to bit 16-23 of LBA-address
1306 mov di, dx
1307 and di, 007Fh
1308 cmp bptr cs:[LBASwitchTable+di], bl
1309 jbe DIOSS_UseExtension
1310
1311 DIOSS_UseNormal:
1312
1313IFDEF AUX_DEBUG
1314 IF 0
1315 DBG_TEXT_OUT_AUX 'DriveIO_WriteSectorCHS:'
1316 PUSHRF
1317 call DEBUG_DumpRegisters
1318 call AuxIO_DumpParagraph
1319 call AuxIO_TeletypeNL
1320 POPRF
1321 ENDIF
1322ENDIF
1323
1324 mov di, 3 ; retry count
1325 DIOSS_ErrorLoop:
1326 push ds
1327 pop es
1328 mov bx, si ; ES:BX - Destination
1329 mov ax, 0301h ; Function 3 - Write Sector
1330 int 13h
1331 jnc DIOSS_Success
1332 dec di ; decrement retry count
1333 jnz DIOSS_ErrorLoop
1334 call MBR_SaveError
1335
1336 DIOSS_UseExtension:
1337
1338 mov di, ds ; segment for transfer address
1339 call DriveIO_WriteSectorLBA ; extended write
1340 jc MBR_SaveError ; halt on error
1341
1342 ;~ push cx
1343 ;~ mov cs:[INT13X_DAP_NumBlocks], 1 ; Copy ONE sector
1344 ;~ mov wptr cs:[INT13X_DAP_Transfer+0], si
1345 ;~ mov cx, ds
1346 ;~ mov wptr cs:[INT13X_DAP_Transfer+2], cx ; Fill out Transfer Adress
1347 ;~ mov wptr cs:[INT13X_DAP_Absolute+0], ax
1348 ;~ mov wptr cs:[INT13X_DAP_Absolute+2], bx ; Fill out Absolute Sector
1349 ;~ push cs
1350 ;~ pop ds
1351 ;~ mov si, offset [INT13X_DAP]
1352 ;~ mov ax, 4300h ; Extended Write (No Verify)
1353 ;~ int 13h
1354 ;~ pop cx
1355 ;~ jnc DIOSS_Success
1356 ;~ call MBR_SaveError
1357
1358 DIOSS_Success:
1359 ret
1360DriveIO_SaveSector EndP
1361
1362
1363
1364
1365;##############################################################################
1366;# When a disk has a Master LVM sector, it means it has been prepared for use
1367;# by OS/2 and contains important information about how OS/2 views its geometry
1368;# and other disk related properties. This function assumes the LBA address
1369;# of the Master LVM sector has already been located and simply loads the
1370;# sector into [LVMSector].
1371;#
1372;# Note that because this is an operation similar to the regular loading of
1373;# sectors, the disk I/O semantics are used here. This means CF=0 when an LVM
1374;# sector is successfully loaded and CF=1 otherwise.
1375;##############################################################################
1376;# ACTION : Loads the Master LVM sector if one exists
1377;# ----------------------------------------------------------------------------
1378;# EFFECTS : Modifies DAP structure and [LVMSector]
1379;# ----------------------------------------------------------------------------
1380;# IN : DL - BIOS disk number (80h,81h,etc)
1381;# ----------------------------------------------------------------------------
1382;# OUT : CF=0 - Valid Master LVM sector found and loaded
1383;##############################################################################
1384DriveIO_LoadMasterLVMSector Proc Near
1385
1386IFDEF AUX_DEBUG
1387 IF 0
1388 DBG_TEXT_OUT_AUX 'DriveIO_LoadMasterLVMSector:'
1389 PUSHRF
1390 ;~ call DEBUG_DumpRegisters
1391 ;~ call AuxIO_DumpParagraph
1392 ;~ call AuxIO_TeletypeNL
1393 POPRF
1394 ENDIF
1395ENDIF
1396
1397 ; Save all registers
1398 pusha
1399
1400 ; Check if BIOS disk number is valid
1401 call DriveIO_IsValidHarddisk
1402 jc DriveIO_LoadMasterLVMSector_error
1403
1404 ; Calculate the entry in the DISKINFO array for this disk
1405 call DriveIO_CalcDiskInfoPointer
1406
1407 ; Save the entry for later recalls
1408 mov bp, bx
1409
1410 ; Get the LBA address of the Master LVM sector
1411 mov ax, [bx+LocDISKINFO_LVM_MasterLBA+00h]
1412 mov bx, [bx+LocDISKINFO_LVM_MasterLBA+02h]
1413
1414 ; LBA of Master LVM sector cannot be 0, so none was found during
1415 ; the gathering of disk information.
1416 mov cx, ax
1417 or cx, bx
1418 jz DriveIO_LoadMasterLVMSector_error
1419
1420 ; Load it into [LVMSector]
1421 mov di, ds
1422 mov si, offset [LVMSector]
1423 call DriveIO_ReadSectorLBA
1424 jc DriveIO_LoadMasterLVMSector_error
1425
1426 ; Validate the Master LVM sector
1427 call LVM_ValidateSector
1428
1429 ; Complement success indicator to conform to semantics of this function
1430 cmc
1431
1432 ; Master LVM sector was valid and is now loaded in [LVMSector]
1433 jnc DriveIO_LoadMasterLVMSector_ret
1434
1435 DriveIO_LoadMasterLVMSector_error:
1436
1437 ; Clear the sector buffer for safety reasons
1438 mov si, offset [LVMSector]
1439 call ClearSectorBuffer
1440
1441 ; Indicate no Master LVM sector loaded
1442 stc
1443
1444 DriveIO_LoadMasterLVMSector_ret:
1445
1446 ; Restore all registers
1447 popa
1448
1449 ret
1450DriveIO_LoadMasterLVMSector Endp
1451
1452
1453
1454
1455;##############################################################################
1456;# There is much information to know about the connected disks.
1457;# We also want this information clustered per disk and available before
1458;# further disk and partition scanning takes place.
1459;# This function gathers such information like INT13, INT13X, MBR, LVM, more.
1460;# Especially important is the LVM information, because that contains the
1461;# geometry OS/2 uses to access the disk. Other important information is the
1462;# presence of valid MBRs, logical partitions and whatnot.
1463;# This function gathers such information and stores it in a DISKINFO structure
1464;# for which an instance exists for every disk found.
1465;##############################################################################
1466;# ACTION : Gather disk information and store this in the BSS
1467;# ----------------------------------------------------------------------------
1468;# EFFECTS : Modifies DAP structure and the buffers it uses, fills DISKINFO[n]
1469;# ----------------------------------------------------------------------------
1470;# IN : DL - BIOS disk number (80h,81h,etc)
1471;# ----------------------------------------------------------------------------
1472;# OUT : CF=1 - failure
1473;##############################################################################
1474DriveIO_GatherDiskInfo Proc Near
1475
1476IFDEF AUX_DEBUG
1477 IF 1
1478 DBG_TEXT_OUT_AUX 'DriveIO_GatherDiskInfo:'
1479 PUSHRF
1480 call DEBUG_DumpRegisters
1481 ;~ call AuxIO_DumpParagraph
1482 ;~ call AuxIO_TeletypeNL
1483 POPRF
1484 ENDIF
1485ENDIF
1486
1487 ; Push all registers we use
1488 pusha
1489 push ds
1490 push es
1491
1492 ; Make sure ES=DS
1493 push ds
1494 pop es
1495
1496 ; Check if BIOS disk number is valid
1497 call DriveIO_IsValidHarddisk
1498 jc DriveIO_GatherDiskInfo_error
1499
1500 ; Calculate the entry in the DISKINFO array for this disk
1501 call DriveIO_CalcDiskInfoPointer
1502
1503 ; Save the entry for later recalls
1504 mov bp, bx
1505
1506 ; Store the BIOS disk number in the structure
1507 mov [bx+LocDISKINFO_DiskNum], dl
1508
1509; ------------------------------------------------------------------- [ INT13 ]
1510
1511 ; Get BIOS Disk Parameters (legacy method)
1512 mov ah, 08h ; Get Disk Parameters
1513 int 13h ; Call BIOS
1514
1515 ; CF=1 or AH!=0 indicates error
1516 jc DriveIO_GatherDiskInfo_error
1517 test ah, ah
1518 jnz DriveIO_GatherDiskInfo_error
1519
1520 ; Recall DISKINFO entry
1521 mov bx, bp
1522
1523 ; Store SPT (WORD)
1524 xor ah, ah ; Zero extend SPT to 16 bits
1525 mov al, cl ; Hi 2 bits max cyl and max sec
1526 and al, 3fh ; Mask max sec (1-based)
1527 mov [bx+LocDISKINFO_I13_Secs], ax ; Store SPT
1528
1529 ; Store HEADS (WORD)
1530 xor dl, dl ; Zero extend HEADS to 16 bits
1531 xchg dl, dh ; Get max head (0-based)
1532 inc dx ; Head count
1533 mov [bx+LocDISKINFO_I13_Heads], dx ; Store HEADS
1534
1535 ; Store CYLS (WORD)
1536 shr cl, 6 ; Hi 2 bits of max cyl to 1:0
1537 xchg cl, ch ; Max cyl (0-based)
1538 inc cx ; Cyl count
1539 mov [bx+LocDISKINFO_I13_Cyls], cx ; Store CYLS
1540
1541 ; Recall BIOS disk number
1542 mov dl, [bx+LocDISKINFO_DiskNum]
1543
1544; ------------------------------------------------------------------ [ INT13X ]
1545
1546 ; Get BIOS Disk Parameters (extended method)
1547 mov si, offset [Scratch] ; Buffer to return disk info
1548 mov ax, 80h ; Size of buffer
1549 mov [si], ax ; Store it in first word
1550 mov ah, 48h ; Get Extended Disk Parameters
1551 int 13h ; Call BIOS
1552
1553 ; CF=1 or AH!=0 indicates error
1554 jc DriveIO_GatherDiskInfo_error
1555 test ah, ah
1556 jnz DriveIO_GatherDiskInfo_error
1557
1558 ; Store flags (WORD)
1559 cld ; Direction up
1560 lodsw ; Buffersize, discard
1561 lodsw ; Flags (CHS valid etc)
1562 mov [bx+LocDISKINFO_I13X_Flags], ax ; Store them
1563
1564 ; Store CYLS (DWORD)
1565 lodsw ; Cyl count low
1566 mov [bx+LocDISKINFO_I13X_Cyls+00h], ax ; Store CYLS low
1567 lodsw ; Cyl count high
1568 mov [bx+LocDISKINFO_I13X_Cyls+02h], ax ; Store CYLS high
1569
1570 ; Store HEADS (DWORD)
1571 lodsw ; Head count low
1572 mov [bx+LocDISKINFO_I13X_Heads+00h], ax ; Store HEADS low
1573 lodsw ; Head count high
1574 mov [bx+LocDISKINFO_I13X_Heads+02h], ax ; Store HEADS high
1575
1576 ; Store SPT (DWORD)
1577 lodsw ; Secs per track low
1578 mov [bx+LocDISKINFO_I13X_Secs+00h], ax ; Store SPT low
1579 lodsw ; Secs per track high
1580 mov [bx+LocDISKINFO_I13X_Secs+02h], ax ; Store SPT high
1581
1582 ; Store total LBA sectors (QWORD)
1583 lea di, [bx+LocDISKINFO_I13X_SecsLBA]
1584 mov cx, 4
1585 rep movsw
1586
1587 ; Store sector size (WORD)
1588 lodsw
1589 mov [bx+LocDISKINFO_I13X_SecSize], ax
1590
1591 ; Store bus name (4 bytes, space padded, v3.0+)
1592 lea si, [Scratch+24h]
1593 lea di, [bx+LocDISKINFO_I13X_HostBus]
1594 movsw
1595 movsw
1596
1597 ; Store interface name (8 bytes, space padded, v3.0+)
1598 lea di, [bx+LocDISKINFO_I13X_Interface]
1599 mov cx, 4
1600 rep movsw
1601
1602 ; Should gather some more INT13X info here,
1603 ; like maybe Advanced Format stuff or so.
1604 ; We'll investigate that at a later time.
1605
1606; --------------------------------------------------------------------- [ MBR ]
1607
1608 ; Load the MBR
1609 mov si, offset [TmpSector]
1610 call DriveIO_LoadMBR
1611
1612 ; Store MBR flags (valid sig, partitions present, airboot installed)
1613 mov [bx+LocDISKINFO_MbrFlags], al
1614
1615 ; Recall BIOS disk number
1616 mov dl, [bx+LocDISKINFO_DiskNum]
1617
1618; --------------------------------------------------------------------- [ LVM ]
1619
1620 ; Locate the Master LVM sector, if any
1621 call DriveIO_LocateMasterLVMSector
1622
1623 ; Save Master LVM sector LBA high
1624 mov cx, bx
1625
1626 ; Recall DISKINFO entry
1627 mov bx, bp
1628
1629 ; Store Master LVM sector LBA
1630 mov [bx+LocDISKINFO_LVM_MasterLBA+00h], ax
1631 mov [bx+LocDISKINFO_LVM_MasterLBA+02h], cx
1632
1633 ; No Master LVM sector found, so skip storing LVM info for this disk
1634 jnc DriveIO_GatherDiskInfo_no_master_lvm
1635
1636 ; Load the Master LVM sector into [LVMSector]
1637 call DriveIO_LoadMasterLVMSector
1638
1639 ; No valid Master LVM sector, so skip storing LVM info for this disk
1640 jc DriveIO_GatherDiskInfo_no_master_lvm
1641
1642 ; A valid Master LVM sector has been loaded into [LVMSector]
1643 mov si, offset [LVMSector]
1644
1645 ; Get the number of sectors per track (OS/2 geometry)
1646 mov ax, [si+LocLVM_Secs+00h]
1647 mov cx, [si+LocLVM_Secs+02h]
1648
1649 ; Store it
1650 mov [bx+LocDISKINFO_LVM_Secs+00h], ax
1651 mov [bx+LocDISKINFO_LVM_Secs+02h], cx
1652
1653 ; Get the number of heads (OS/2 geometry)
1654 mov ax, [si+LocLVM_Heads+00h]
1655 mov cx, [si+LocLVM_Heads+02h]
1656
1657 ; Store it
1658 mov [bx+LocDISKINFO_LVM_Heads+00h], ax
1659 mov [bx+LocDISKINFO_LVM_Heads+02h], cx
1660
1661 ; Should gather some more LVM info here,
1662 ; like OS/2 extended geometry and other flags.
1663 ; We'll implement that at a later time.
1664
1665 DriveIO_GatherDiskInfo_no_master_lvm:
1666
1667 ; When no Master LVM sector was found,
1668 ; the LVM info in the DISKINFO structure for the disk
1669 ; will be ZERO because the area was cleared in PRECRAP.
1670
1671 ; Indicate success
1672 clc
1673
1674 jmp DriveIO_GatherDiskInfo_ret
1675
1676 DriveIO_GatherDiskInfo_error:
1677 stc
1678 DriveIO_GatherDiskInfo_ret:
1679
1680
1681IFDEF AUX_DEBUG
1682 IF 1
1683 DBG_TEXT_OUT_AUX '[DISKINFO]'
1684 PUSHRF
1685 call DEBUG_DumpRegisters
1686 ;~ call AuxIO_DumpParagraph
1687 ;~ call AuxIO_TeletypeNL
1688 mov si, bp
1689 mov cx, 4
1690 @@:
1691 call AuxIO_DumpParagraph
1692 call AuxIO_TeletypeNL
1693 add si, 16
1694 loop @B
1695 mov si, offset [Scratch]
1696 mov cx, 4
1697 @@:
1698 call AuxIO_DumpParagraph
1699 call AuxIO_TeletypeNL
1700 add si, 16
1701 loop @B
1702 mov si, offset [LVMSector]
1703 mov cx, 7
1704 @@:
1705 call AuxIO_DumpParagraph
1706 call AuxIO_TeletypeNL
1707 add si, 16
1708 loop @B
1709 POPRF
1710 ENDIF
1711ENDIF
1712
1713 ; Restore registers
1714 pop es
1715 pop ds
1716 popa
1717
1718 ret
1719DriveIO_GatherDiskInfo EndP
1720
1721;------------------------------------------------------------------------------
1722; Scan all disks to gather information
1723;------------------------------------------------------------------------------
1724; IN : None
1725; OUT : CF=1 - some failure occured
1726; : ZF=1 - no harddisks
1727; NOTE : This does the preliminary gathering of disk information
1728;------------------------------------------------------------------------------
1729DriveIO_ScanDisks Proc Near
1730
1731IFDEF AUX_DEBUG
1732 IF 1
1733 DBG_TEXT_OUT_AUX 'DriveIO_ScanDisks:'
1734 PUSHRF
1735 call DEBUG_DumpRegisters
1736 ;~ call AuxIO_DumpParagraph
1737 ;~ call AuxIO_TeletypeNL
1738 POPRF
1739 ENDIF
1740ENDIF
1741
1742 ; Save all registers
1743 pusha
1744
1745 ; Get number of disks in DH
1746 call DriveIO_GetHardDriveCount
1747
1748 ; Check if there are any disks to scan
1749 xor cx, cx ; Prepare 16-bit counter
1750 mov cl, dh ; Number of disks now in CX
1751 jcxz DriveIO_ScanDisks_end ; Quit if no disks
1752
1753 ; Scan disks from 80h upward
1754 mov dl, 80h ; BIOS number of first disk
1755 DriveIO_ScanDisks_next:
1756 call DriveIO_GatherDiskInfo ; Gather info for this disk
1757 jc DriveIO_ScanDisks_end ; Quit if some error occured
1758 inc dl ; Advance to next disk
1759 loop DriveIO_ScanDisks_next ; Scan next disk if there is one
1760 test dl, dl ; Set ZF=0
1761 clc ; Indicate success
1762
1763 DriveIO_ScanDisks_end:
1764 ; Restore all registers
1765 popa
1766
1767 ret
1768DriveIO_ScanDisks EndP
1769
1770;------------------------------------------------------------------------------
1771; Calculate pointer to entry in DISKINFO structure
1772;------------------------------------------------------------------------------
1773; IN : DL BIOS disk number (80h etc)
1774; OUT : BX Pointer to entry
1775; NOTE : BIOS disk number must be valid
1776;------------------------------------------------------------------------------
1777DriveIO_CalcDiskInfoPointer Proc Near
1778 xchg bx, ax ; AX is used for calculation
1779 mov al, DISKINFO_Size ; Size of DISKINFO structure
1780 mov ah, dl ; BIOS disk number
1781 sub ah, 80h ; Now 0-based index
1782 mul ah ; Now offset into DISKINFO array
1783 add ax, offset [DiskInformation] ; Base of DISKINFO array
1784 xchg bx, ax ; BX now points to entry for disk
1785 ret
1786DriveIO_CalcDiskInfoPointer EndP
1787
1788;------------------------------------------------------------------------------
1789; Check if the BIOS disk number in DL is a harddisk and in range
1790;------------------------------------------------------------------------------
1791; IN : DL BIOS disk number (80h etc)
1792; OUT : CF=1 if invalid disk number or out of range
1793; NOTE : Only modifies flags
1794;------------------------------------------------------------------------------
1795DriveIO_IsValidHarddisk Proc Near Uses dx
1796 cmp dl, 80h ; BIOS disk number must be at least 80h
1797 jb @F ; Not a harddisk, exit with CY
1798 mov dh, dl ; Save to do compare
1799 sub dh, 80h ; Now 0 based disk number
1800 inc dh ; Now 1 based disk number
1801 cmp [TotalHarddiscs], dh ; Out of range, exit with CY
1802 @@: ret
1803DriveIO_IsValidHarddisk EndP
1804
1805
1806; Values for sectors per track table corresponding to DriveIO_IsHugeDrive return value.
1807;~ secs_per_track_table db 63,127,255,255,255,255
1808
1809;~ db_lmlvm db 'Load Master LVM -- disk: ',0
Note: See TracBrowser for help on using the repository browser.