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

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

Reimplemented the loading of LVM sectors [v1.1.1-testing]

This new method does away with ugly and faulty adjustments which
assumed LVM sectors were located below actual partition starts,
which is true most of the time, but not always, especially not for
the first primary partition which could be offset more than SPT.

Because MBR and EBR locations are now used, the need to distinguish
between primary and logical partitions is also not needed anymore.

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: 68.3 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
420
421;##############################################################################
422;# The location of LVM sectors depends on the OS/2 geometry used when the disk
423;# was prepared. This geometry is present in the Master LVM sector, which has
424;# already been located if it exists. All partitions, whether primary or
425;# logical, have an entry in a partition table. For primary partitions this
426;# table is located in the MBR, while for logical partitions this table is
427;# located in the EBR for that logical partition. An LVM record is located
428;# LVM_SPT-1 sectors above an MBR or EBR. The Master LVM record contains the
429;# information for all primary partitions. For logical partitions, the LVM
430;# sector only has one entry, because EBRs are chained. The global LVM info,
431;# like disk-name, sectors per track, etc. is replicated between the Master
432;# LVM sector and LVM sectors corresponding to logical partitions. This info
433;# is kept in sync by the OS/2 LVM Engine.
434;##############################################################################
435;# ACTION : Attempts to load the corresponding LVM sector for a partition
436;# ----------------------------------------------------------------------------
437;# EFFECTS : Modifies DAP structure and fills or clears sector buffer
438;# ----------------------------------------------------------------------------
439;# IN : None - Location info is in [CurPartition_Location]
440;# ----------------------------------------------------------------------------
441;# OUT : CF=1 - failure, no valid LVM sector was loaded
442;# : SI - Points to the sector buffer ([LVMSector])
443;##############################################################################
444DriveIO_LoadLVMSector Proc Near Uses ax bx cx dx di
445
446IFDEF AUX_DEBUG
447 IF 1
448 DBG_TEXT_OUT_AUX 'DriveIO_LoadLVMSector:'
449 PUSHRF
450 call DEBUG_DumpRegisters
451 ;~ call AuxIO_DumpSector
452 ;~ call AuxIO_DumpParagraph
453 ;~ call AuxIO_TeletypeNL
454 POPRF
455 ENDIF
456ENDIF
457
458 ; Clear the sector buffer
459 mov si, offset [LVMSector]
460 call ClearSectorBuffer
461
462 ; Quit with CY if LVM is ignored in SETUP
463 test byte ptr [CFG_IgnoreLVM], 1 ; ZF=0 means ignore LVM
464 jnz DIOLLVMS_NoLVMSector ; Quit if so
465
466 ; Calculate the entry in the DISKINFO array for this disk
467 call DriveIO_CalcDiskInfoPointer
468
469 ; If the LVM_SPT is ZERO, no LVM info is present and we quit with CY
470 mov di, [bx+LocDISKINFO_LVM_Secs] ; Get LVM_SPT
471 test di, di ; See if it is 0
472 jz DIOLLVMS_NoLVMSector ; Quit if so
473
474 ; Load the location of the current partition being acted upon.
475 ; Note that this is not the actual LBA of the partition, but the
476 ; sector that has the partition table that contains the entry
477 ; for the partition. In other words, for primary partitions the LBA
478 ; address points to the MBR while for extended partitions it points
479 ; to an EBR. In both cases the LVM sector is located LVM_SPT-1 above.
480 ; Also note that the BIOS CHS values (DH and CX) below are not used,
481 ; because we explicitly use LBA sector loading.
482 mov ax, wptr cs:[CurPartition_Location+0] ; LBA lo of MBR/EBR
483 mov bx, wptr cs:[CurPartition_Location+2] ; LBA hi of MBR/EBR
484 mov dx, wptr cs:[CurPartition_Location+4] ; BIOS disk num & head
485 mov cx, wptr cs:[CurPartition_Location+6] ; BIOS cyl & sec
486
487 ; Adjust the location to point to the LVM sector
488 add ax, di ; Add the LVM sectors-per-track
489 adc bx, 0 ; Propagate LBA lo overflow to LBA hi
490 sub ax, 1 ; LVM sector is located one sector below
491 sbb bx, 0 ; Propagate borrow to LBA hi
492
493 ; Load the LVM sector into [LVMSector]
494 mov si, offset [LVMSector] ; Points to sector buffer
495 mov di, ds ; Segment of that buffer
496 call DriveIO_ReadSectorLBA ; Read the LVM sector
497 jc DIOLLVMS_NoLVMSector ; Quit on error
498
499 ; Check the validity of the LVM sector, quit with CY if invalid
500 call LVM_ValidateSector ; Check signature and CRC
501 jnc DIOLLVMS_NoLVMSector ; Quit if not valid
502
503
504IFDEF AUX_DEBUG
505 IF 1
506 DBG_TEXT_OUT_AUX 'CurPartition'
507 PUSHRF
508 call DEBUG_DumpRegisters
509 call AuxIO_DumpSector
510 ;~ call AuxIO_DumpParagraph
511 ;~ call AuxIO_TeletypeNL
512 POPRF
513 ENDIF
514ENDIF
515
516 ; We're done, indicate success and return
517 clc
518 jmp DIOLLVMS_Done
519
520 DIOLLVMS_NoLVMSector:
521
522 ; Clear the sector buffer
523 mov si, offset [LVMSector]
524 call ClearSectorBuffer
525 mov bptr [si+LocLVM_SignatureStart], 0
526
527 ; Indicate no valid LVM sector was loaded
528 stc
529
530 DIOLLVMS_Done:
531
532 ret
533DriveIO_LoadLVMSector EndP
534
535
536
537; Keeps DS:SI for caller, saves at anytime w/o checks (!)
538DriveIO_SaveLVMSector Proc Near Uses ax bx cx dx
539
540IFDEF AUX_DEBUG
541 IF 0
542 DBG_TEXT_OUT_AUX 'DriveIO_SaveLVMSector:'
543 PUSHRF
544 ;~ call DEBUG_DumpRegisters
545 ;~ call AuxIO_DumpParagraph
546 ;~ call AuxIO_TeletypeNL
547 POPRF
548 ENDIF
549ENDIF
550
551 test byte ptr [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
552 jnz DIOSLVMS_SevereError ; don't save at anytime (security!)
553 mov ax, wptr cs:[CurPartition_Location+0]
554 mov bx, wptr cs:[CurPartition_Location+2]
555 mov dx, wptr cs:[CurPartition_Location+4]
556 mov cx, wptr cs:[CurPartition_Location+6] ; Gets cur. partition location
557 call LVM_CheckSectorSignature
558 jnc DIOSLVMS_SevereError ; LVM Signature must be there
559
560IFDEF AUX_DEBUG
561 IF 0
562 pushf
563 pusha
564 ;~ dioatlvm db 'DriveIO_LVMAdjustToInfoSector',10,0
565 ;~ pushf
566 ;~ pusha
567 ;~ mov si,offset dioatlvm
568 ;~ call AuxIO_Print
569 ;~ popa
570 ;~ popf
571 call DEBUG_DumpRegisters
572 call DEBUG_DumpCHS
573 popa
574 popf
575 ENDIF
576ENDIF
577
578 call DriveIO_LVMAdjustToInfoSector
579
580IFDEF AUX_DEBUG
581 IF 0
582 pushf
583 pusha
584 call DEBUG_DumpRegisters
585 call DEBUG_DumpCHS
586 popa
587 popf
588 ENDIF
589ENDIF
590
591 mov si, offset LVMSector
592 call DriveIO_SaveSector
593 DIOSLVMS_SevereError:
594 ret
595DriveIO_SaveLVMSector EndP
596
597
598
599; Special error message instead of "LOAD ERROR" during partition scanning,
600; so users will notice that something is bad with their partition table(s)
601DriveIO_GotLoadError Proc Near
602 test byte ptr cs:[CurIO_Scanning], 1 ; Must be CS:, cause DS!=CS maybe here
603 jnz InScanMode
604 jmp MBR_LoadError
605 InScanMode:
606 mov si, offset TXT_BrokenPartitionTable
607 push cs
608 pop ds
609 call MBR_Teletype
610 mov si, offset BrokenHDD
611 sub dl, 50h ; 80h -> '0'
612 cmp dl, 39h
613 jbe DIOGLE_BelowA
614 add dl, 7 ; 3Ah -> 'A'
615 DIOGLE_BelowA:
616 mov bptr [si+5], dl
617 call MBR_Teletype
618
619 ; JWasm: cannot jump to local label in other procedure.
620 ; Changed to halt here.
621 ;jmp MBRLE_Halt
622 DriveIO_GotLoadError_halt:
623 jmp DriveIO_GotLoadError_halt
624DriveIO_GotLoadError EndP
625
626; #########################################################################
627; Routine: Loads a specified sector to DS:DI
628; #########################################################################
629; Calling : bx:ax - Absolute sector
630; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
631; ds:si - Destination-Adress
632; Returns : none
633; Preserve: all registers
634; #########################################################################
635DriveIO_LoadSector Proc Near Uses ax bx cx dx ds si es di
636
637IFDEF AUX_DEBUG
638 IF 0
639 DBG_TEXT_OUT_AUX 'DriveIO_LoadSector:'
640 PUSHRF
641 call DEBUG_DumpRegisters
642 ;~ call AuxIO_DumpParagraph
643 ;~ call AuxIO_TeletypeNL
644 POPRF
645 ENDIF
646ENDIF
647
648 ; Is the drive not a harddrive?
649 cmp dl, 80h
650 jb DIOLS_UseNormal
651
652 test byte ptr cs:[CurIO_UseExtension], 1
653 jz DIOLS_UseNormal
654 ; Are we forced do use LBA via Setting?
655 jnz DIOLS_UseExtension
656
657 ; Upper 8 bits of LBA-address set?
658 ; Then use LBA (maximum boundary is 16320x16x63 = FB0400h)
659 or bh, bh
660 jnz DIOLS_UseExtension
661 ; Compare Switch-Table value to bit 16-23 of LBA-address
662 mov di, dx
663 and di, 007Fh
664 cmp bptr cs:[LBASwitchTable+di], bl
665 jbe DIOLS_UseExtension
666
667 DIOLS_UseNormal:
668
669IFDEF AUX_DEBUG
670 IF 0
671 DBG_TEXT_OUT_AUX 'DriveIO_ReadSectorCHS:'
672 PUSHRF
673 call DEBUG_DumpRegisters
674 call AuxIO_DumpParagraph
675 call AuxIO_TeletypeNL
676 POPRF
677 ENDIF
678ENDIF
679
680 mov di, 3 ; retry count
681 DIOLS_ErrorLoop:
682 push ds
683 pop es
684 mov bx, si ; ES:BX - Destination
685 mov ax, 0201h ; Function 2 - Load Sector
686 int 13h
687 jnc DIOLS_Success
688 dec di ; decrement retry count
689 jnz DIOLS_ErrorLoop
690
691 ; Sector load failed...
692 jmp DriveIO_GotLoadError
693
694 DIOLS_UseExtension:
695
696 mov di, ds ; segment for transfer address
697 call DriveIO_ReadSectorLBA ; extended read
698 jc DriveIO_GotLoadError ; halt on error
699
700 ;~ push cx
701 ;~ mov cs:[INT13X_DAP_NumBlocks], 1 ; Copy ONE sector
702 ;~ mov wptr cs:[INT13X_DAP_Transfer+0], si
703 ;~ mov cx, ds
704 ;~ mov wptr cs:[INT13X_DAP_Transfer+2], cx ; Fill out Transfer Adress
705 ;~ mov wptr cs:[INT13X_DAP_Absolute+0], ax
706 ;~ mov wptr cs:[INT13X_DAP_Absolute+2], bx ; Fill out Absolute Sector
707 ;~ push cs
708 ;~ pop ds
709 ;~ mov si, offset [INT13X_DAP]
710 ;~ mov ah, 42h ; Extended Read
711 ;~ int 13h
712 ;~ pop cx
713 ;~ jnc DIOLS_Success
714
715 ; Sector load failed...
716 ;~ jmp DriveIO_GotLoadError
717
718 DIOLS_Success:
719
720IFDEF AUX_DEBUG
721 IF 0
722 DBG_TEXT_OUT_AUX 'sector loaded'
723 PUSHRF
724 ;~ call DEBUG_DumpRegisters
725 ;~ call AuxIO_DumpSector
726 mov cx, 32
727 @@:
728 call AuxIO_DumpParagraph
729 call AuxIO_TeletypeNL
730 add si, 16
731 loop @B
732 POPRF
733 ENDIF
734ENDIF
735 ret
736DriveIO_LoadSector EndP
737
738
739;##############################################################################
740;# ACTION : Loads the Master Boot Record from the specified drive into buffer
741;# ----------------------------------------------------------------------------
742;# EFFECTS : Modifies DAP structure and fills or clears transfer buffer
743;# ----------------------------------------------------------------------------
744;# IN : DL - BIOS disk number (80h,81h,etc)
745;# : SI - Pointer to transfer buffer
746;# ----------------------------------------------------------------------------
747;# OUT : CF=1 - failure
748;# : AL.0 - MBR signature present
749;# : AL.1 - Primary partitions present
750;# : AL.2 - Extended partitions present
751;# : AL.3 - AiR-BOOT signature present
752;# : AL.4:7 - Reserved, returned as 0
753;# : AH.0:7 - Reserved, returned as 0
754;##############################################################################
755DriveIO_LoadMBR Proc Near uses bx cx dx si di
756
757 ; Always clear the transfer buffer first
758 call ClearSectorBuffer
759
760 ; Assume an invalid MBR
761 xor ax, ax
762
763 ; Accept only valid harddisks
764 call DriveIO_IsValidHarddisk
765 jc DriveIO_LoadMBR_exit
766
767 ; Save the address of the transfer buffer
768 mov di, si
769
770 ; Read the MBR from disk
771 xor ax, ax ; LBA low
772 xor bx, bx ; LBA high
773 xor dh, dh ; Head 0
774 mov cx, 1 ; Sector 1
775 call DriveIO_LoadSector ; Read the sector from disk
776
777 ; Check the loaded MBR for a signature
778 xor ax, ax ; Assume an invalid MBR
779 mov dx, [si+LocBR_Magic] ; Get word from MBR signature location
780 cmp dx, 0aa55h ; Is it the magic value ?
781 jne DriveIO_LoadMBR_exit ; Nope, no need to test anything else
782
783 ; Indicate we have a MBR signature
784 or al, 01h
785
786 ; Advance to the partition table
787 add si, 01beh
788
789 ; Total of 4 entries to check
790 mov cx, 4
791
792 DriveIO_LoadMBR_next_entry:
793 mov dl, [si+LocBRPT_SystemID] ; Get partition-type / system-id
794 add si, 10h ; Point to next entry
795 test dl, dl ; Nothing in this one ?
796 loopz DriveIO_LoadMBR_next_entry ; Then check next entry
797
798 ; All entries checked and last one was also empty, we're done
799 jz DriveIO_LoadMBR_check_ab
800
801 ; Found a non-empty entry, set bits according to its type
802 cmp dl, 05h ; Old style extended container ?
803 jne @F ; Nope...
804 or al, 04h ; Yep, mark ext. container present
805 @@: cmp dl, 0fh ; New style extended container ?
806 jne @F ; Nope...
807 or al, 04h ; Yep, mark ext. container present
808 @@: or al, 02h ; Then is must be a primary
809 jcxz DriveIO_LoadMBR_check_ab ; CX=0? Then all entries processed,
810 jmp DriveIO_LoadMBR_next_entry ; otherwise check next entry
811
812 ; Check if an AiR-BOOT signature is present
813 DriveIO_LoadMBR_check_ab:
814 mov si, offset [MBR_ABSig] ; Offset of AiR-BOOT signature
815 inc di ; Advance buffer pointer
816 inc di ; to AiR-BOOT signature location
817 mov cx, 7 ; Length of AiR-BOOT signature
818 cld ; Direction upwards
819 repe cmpsb ; Compare 7 bytes
820 jne DriveIO_LoadMBR_exit ; Nope, no AiR-BOOT on this disk
821 or al, 08h ; Yep, AiR-BOOT is on this disk
822 ;~ jmp DriveIO_LoadMBR_exit
823
824 DriveIO_LoadMBR_exit:
825 ret
826DriveIO_LoadMBR EndP
827
828
829;##############################################################################
830;# ACTION : Reads a sector from disk using INT13 extensions
831;# ----------------------------------------------------------------------------
832;# EFFECTS : Modifies DAP structure and fills transfer buffer
833;# ----------------------------------------------------------------------------
834;# IN : BX:AX - LBA address of sector
835;# : DI:SI - SEG:OFF of transfer buffer
836;# ----------------------------------------------------------------------------
837;# OUT : CF=1 - failure
838;##############################################################################
839DriveIO_ReadSectorLBA Proc Near
840
841IFDEF AUX_DEBUG
842 IF 0
843 DBG_TEXT_OUT_AUX 'DriveIO_ReadSectorLBA:'
844 PUSHRF
845 call DEBUG_DumpRegisters
846 call AuxIO_DumpParagraph
847 call AuxIO_TeletypeNL
848 POPRF
849 ENDIF
850ENDIF
851
852 ; Push all registers
853 pusha
854 push ds
855 push es
856
857 ; One sector to read
858 mov cs:[INT13X_DAP_NumBlocks], 1
859
860 ; Setup transfer address
861 mov wptr cs:[INT13X_DAP_Transfer+0], si ; offset
862 mov wptr cs:[INT13X_DAP_Transfer+2], di ; segment
863
864 ; Setup LBA64 address of requested sector
865 mov wptr cs:[INT13X_DAP_Absolute+0], ax ; low word lower part
866 mov wptr cs:[INT13X_DAP_Absolute+2], bx ; high word lower part
867 mov wptr cs:[INT13X_DAP_Absolute+4], 0 ; low word upper part
868 mov wptr cs:[INT13X_DAP_Absolute+6], 0 ; high word upper part
869
870 ; Address of packet
871 mov si, offset [INT13X_DAP] ; disk address packet
872
873 ; Do the extended read
874 mov ah, 42h ; read function
875 int 13h ; transfer to bios
876
877 ; Error occured
878 jc DriveIO_ReadSectorLBA_exit
879
880 ; AH should also be zero
881 test ah, ah
882 stc
883 jnz DriveIO_ReadSectorLBA_exit
884
885 ; Disk read succeeded, clear CF
886 clc
887
888 DriveIO_ReadSectorLBA_exit:
889
890 ; Pop all registers
891 pop es
892 pop ds
893 popa
894
895 ret
896DriveIO_ReadSectorLBA EndP
897
898
899
900;##############################################################################
901;# ACTION : Writes a sector to disk using INT13 extensions
902;# ----------------------------------------------------------------------------
903;# EFFECTS : Modifies DAP structure and mofifies the disk
904;# ----------------------------------------------------------------------------
905;# IN : BX:AX - LBA address of sector
906;# : DI:SI - SEG:OFF of transfer buffer
907;# ----------------------------------------------------------------------------
908;# OUT : CF=1 - failure
909;##############################################################################
910DriveIO_WriteSectorLBA Proc Near
911
912IFDEF AUX_DEBUG
913 IF 0
914 DBG_TEXT_OUT_AUX 'DriveIO_WriteSectorLBA:'
915 PUSHRF
916 call DEBUG_DumpRegisters
917 call AuxIO_DumpParagraph
918 call AuxIO_TeletypeNL
919 POPRF
920 ENDIF
921ENDIF
922
923 ; Push all registers
924 pusha
925 push ds
926 push es
927
928 ; One sector to read
929 mov cs:[INT13X_DAP_NumBlocks], 1
930
931 ; Setup transfer address
932 mov wptr cs:[INT13X_DAP_Transfer+0], si ; offset
933 mov wptr cs:[INT13X_DAP_Transfer+2], di ; segment
934
935 ; Setup LBA64 address of requested sector
936 mov wptr cs:[INT13X_DAP_Absolute+0], ax ; low word lower part
937 mov wptr cs:[INT13X_DAP_Absolute+2], bx ; high word lower part
938 mov wptr cs:[INT13X_DAP_Absolute+4], 0 ; low word upper part
939 mov wptr cs:[INT13X_DAP_Absolute+6], 0 ; high word upper part
940
941 ; Address of packet
942 mov si, offset [INT13X_DAP] ; disk address packet
943
944 ; Do the extended write
945 xor al, al ; no write verify
946 mov ah, 43h ; write function
947 int 13h ; transfer to bios
948
949 ; Error occured
950 jc DriveIO_WriteSectorLBA_exit
951
952 ; AH should also be zero
953 test ah, ah
954 stc
955 jnz DriveIO_WriteSectorLBA_exit
956
957 ; Disk write succeeded, clear CF
958 clc
959
960 DriveIO_WriteSectorLBA_exit:
961
962 ; Pop all registers
963 pop es
964 pop ds
965 popa
966
967 ret
968DriveIO_WriteSectorLBA EndP
969
970
971
972
973;##############################################################################
974;# The Master LVM sector is *not* necessarily located at the end of the BIOS
975;# view of TRACK0. Its location depends on the *OS/2 geometry* active when the
976;# disk was partitioned. For disks < 502MiB this will most likely be LBA sector
977;# 62, but for disks >502MiB, *extended* OS/2 geometry was used and DANIS506
978;# uses SPT=127 for disks < 1TiB while IBMS506 uses SPT=255.
979;# When a huge disk < 1TiB was partitioned with IBMS506, thus using SPT=255,
980;# and the driver was later changed to DANIS506, DANI uses SPT=255, eventhough
981;# the disk < 1TiB. Whether it is DANI that is LVM aware or something else
982;# (maybe LVM itself) that makes DANI use the correct geometry has yet to be
983;# investigated.
984;#
985;# Related geometry issues are also present with USB sticks, which can get
986;# assigned a geometry by OS/2, which can depend if the stick was partitioned
987;# on foreign systems or not, or even OS/2 manufacturing a geometry that is not
988;# the same as the BIOS reports to us here. In both cases, fixed disks and
989;# removable disks, the geometry recorded in the BPB of a partition can also
990;# influence the geometry that OS/2 assigns. This is the case when 'preparing'
991;# disks for LVM use, in which case BPB values could be incorporated.
992;#
993;# What this all boils down to, is that the geometry reported by the BIOS is
994;# of no practical use, especially not when taking BIOS USB MSD emulation into
995;# account. These are among the reasons why AirBoot needs to use LBA addressing
996;# when handling LVM stuff and why LBA use cannot be disabled in the SETUP
997;# anymore.
998;#
999;# So, a Master LVM sector can be present on any sector from LBA 254 downwards
1000;# and the only way to locate the correct one is to scan all the way down and,
1001;# if one is found, do proper validation on its values, because it may also be
1002;# a 'phantom' LVM sector left over from previous partition layouts.
1003;# Most of such 'phantoms' can be filtered out by verifying the location of
1004;# the found sector against the OS/2 geometry it specifies itself, which means
1005;# it must be located at the LBA of the SPT-1 it specifies.
1006;##############################################################################
1007;# ACTION : Locates the Master LVM sector on the specified disk
1008;# ----------------------------------------------------------------------------
1009;# EFFECTS : Leaves [Scratch] with last sector read or cleared
1010;# ----------------------------------------------------------------------------
1011;# IN : DL - BIOS disk number of drive to search
1012;# ----------------------------------------------------------------------------
1013;# OUT : CF=1 - found
1014;# : BX:AX - LBA address of LVM sector if found, 0 otherwise
1015;##############################################################################
1016DriveIO_LocateMasterLVMSector Proc Near uses cx dx si di ds es
1017
1018IFDEF AUX_DEBUG
1019 IF 1
1020 DBG_TEXT_OUT_AUX 'DriveIO_LocateMasterLVMSector:'
1021 PUSHRF
1022 call DEBUG_DumpRegisters
1023 ;~ call AuxIO_DumpSector
1024 ;~ call AuxIO_DumpParagraph
1025 ;~ call AuxIO_TeletypeNL
1026 POPRF
1027 ENDIF
1028ENDIF
1029
1030 ; LBA address to start scanning down from
1031 mov cx, 255
1032
1033 ; Make sure ES==DS
1034 push ds
1035 pop es
1036
1037 ; Because JCXZ is used, LBA sector 0 is never loaded and checked.
1038 ; This is of course no problem since it is the MBR.
1039 DriveIO_LocateMasterLVMSector_next:
1040 mov si, offset [Scratch] ; Use scratch area to load sectors
1041 call ClearSectorBuffer ; Clear the scratch area
1042 clc ; Indicate Master LVM sector not found
1043 jcxz DriveIO_LocateMasterLVMSector_done
1044
1045 ; Read the LBA sector specified in CX
1046 mov ax, cx ; LBA low
1047 xor bx, bx ; LBA high
1048 mov di, ds ; Segment of scratch buffer
1049 mov si, offset [Scratch] ; Offset of scratch buffer
1050 call DriveIO_ReadSectorLBA ; Read the sector
1051 lahf ; Save CF
1052 dec cx ; Prepare LBA of next sector to read
1053 sahf ; Restore CF
1054 ; No need to do any LVM sector validation when read error, read next
1055 jc DriveIO_LocateMasterLVMSector_next
1056
1057 ; See if the read sector has a valid signature and checksum
1058 call LVM_ValidateSector
1059
1060 ; NC indicates invalid or none-LVM sector, read next
1061 jnc DriveIO_LocateMasterLVMSector_next
1062
1063 ; We have found a valid LVM sector !
1064 ; So it contains the OS/2 geometry for the disk.
1065 ; That means this LVM sector itself must be located on the last sector
1066 ; of the SPT value its OS/2 geometery specifies, which, in LBA terms
1067 ; is LVM SPT-1 -- let's check that...
1068 mov bx, offset [Scratch] ; Offset of the loaded LVM sector
1069 mov al, [bx+LocLVM_Secs] ; Get the LVM SPT value (<=255)
1070 dec al ; Adjust to LVM LBA
1071 mov ah, cl ; Get next LVM LBA to search
1072 inc ah ; This one was found here
1073 cmp al, ah ; If same, LVM LBA location OK
1074 jne DriveIO_LocateMasterLVMSector_next
1075
1076 ; The LVM sector we found is at the location it should be on disk,
1077 ; so it's almost 99% sure this is the correct one.
1078 ; Now we should compare the start and sizes of the partitions in the
1079 ; MBR with the partitions specified in this LVM record.
1080 ; We'll implement that later after some more research.
1081 ; For now we assume this is the correct Master LVM sector for the disk.
1082 inc cx ; CX was prepared to read next, correct that
1083 stc ; Indicate we have found the Master LVM sector
1084
1085 DriveIO_LocateMasterLVMSector_done:
1086 mov bx, 0 ; A Master LVM sector always has high LBA=0
1087 mov ax, cx ; Low LBA of Master LVM sector
1088
1089 ; We leave it up to the caller to store the value in a proper place
1090 ret
1091DriveIO_LocateMasterLVMSector EndP
1092
1093
1094
1095;
1096; ############################################################
1097; # Check for a valid MBR-sector to be written to disk #
1098; ############################################################
1099;
1100; In
1101; --
1102; DL = Physical Disk
1103; BX:CX = LBA sector
1104; DI:SI = Source buffer
1105;
1106; Out
1107; ---
1108; CY = 1 if invalid MBR in source buffer, 0 if valid
1109;
1110; This routine is called when DriveIO_SaveSector attempts to write to the MBR.
1111; It checks if the sector to be written has some sensible values in certain
1112; places. In fact, if the sector is written to the boot-disk, the AiR-BOOT
1113; signature should be present and the partition table should be the same
1114; as the one at the start of the AiR-BOOT code in memory, except maybe for the
1115; active flags.
1116; For other disks, only the active flags are checked to be 00h or 80h and
1117; the AA55h MBR signature.
1118;
1119DriveIO_ProtectMBR Proc Near
1120 pusha ; Push all registers
1121 push es ; Push ES because we need it for string instructions
1122 push cs ; Make ES point...
1123 pop es ; to CS
1124
1125 ; Save the pointer to the sector to write in BX
1126 mov bx,si
1127
1128 ;
1129 ; If the sector to be written is not the boot-disk, then skip
1130 ; checking the AiR-BOOT MBR.
1131 ;
1132 cmp dl, [BIOS_BootDisk]
1133 jne DriveIO_ProtectMBR_is_not_bootdisk
1134
1135 ;
1136 ; The boot-disk is accessed so the sector to be written must be
1137 ; the AiR-BOOT MBR. This is the same as the first 512 bytes
1138 ; relocated to 8000:0000 and this the start of the AB-code.
1139 ;
1140 mov si,bx ; Get pointer to sector to write
1141 xor di,di ; Point DI to start of AB-code (MBR)
1142 mov cx, offset [MBR_PartTable] ; Bytes upto P-table must be same
1143 cld ; Compare upwards
1144 repe cmpsb ; Compare upto P-table
1145
1146 ; If not the same this is not the an AiR-BOOT boot-disk MBR !
1147 jne DriveIO_ProtectMBR_not_valid_MBR ; SEVERE ERROR !
1148
1149 ; Continue with signature check
1150 jmp DriveIO_ProtectMBR_check_signature
1151
1152
1153 ;
1154 ; The disk is not the boot-disk so we don't know what kind of MBR is on it.
1155 ; Some sanity checks should be here.
1156 ;
1157 DriveIO_ProtectMBR_is_not_bootdisk:
1158
1159 ;
1160 ; sanity checks...
1161 ;
1162
1163 ; Continue with signature check
1164 jmp DriveIO_ProtectMBR_check_signature
1165
1166
1167 DriveIO_ProtectMBR_check_signature:
1168 ; See if the sector to write contains a valid signature
1169 mov si,bx ; Get pointer to sector to write
1170 mov di, offset [MBR_Sig] ; Offset to MBR signature
1171 add si,di ; Make SI point to it in sec to write
1172 lodsw ; Load it
1173 cmp ax,0aa55h ; See if it is valid
1174
1175 ; If no signature this cannot be a valid MBR !
1176 jne DriveIO_ProtectMBR_not_valid_MBR ; SEVERE ERROR !
1177
1178
1179 ;
1180 ; The sector to be written seems to be valid.
1181 ; Set CY=0 to indicate a valid MBR.
1182 ;
1183 DriveIO_ProtectMBR_is_valid_MBR:
1184 clc
1185 jmp DriveIO_ProtectMBR_end
1186
1187 ;
1188 ; Something is terribly wrong; a non-MBR sector seems about to be written.
1189 ; Set CY=1 and let the calling code handle this situation.
1190 ;
1191 DriveIO_ProtectMBR_not_valid_MBR:
1192 stc
1193 jmp DriveIO_ProtectMBR_end
1194
1195 ;
1196 ; Return to the caller with no registers modyfied except FLAGS.
1197 ;
1198 DriveIO_ProtectMBR_end:
1199 pop es
1200 popa
1201 ret
1202DriveIO_ProtectMBR Endp
1203
1204
1205
1206; #########################################################################
1207; Routine: Checks if the MBR is addressed by either CHS or LBA
1208; #########################################################################
1209; Calling : bx:ax - Absolute sector
1210; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
1211; Returns : ZF=1 if MBR is addressed, else ZF=0
1212; Preserve: all registers
1213; #########################################################################
1214DriveIO_MBR_Addressed Proc
1215 push ax
1216 push bx
1217
1218 or bx,ax ; Results in 0 in BX if MBR is addressed by LBA
1219 jz DriveIO_MBR_Addressed_done
1220
1221 mov ax,cx ; Results in 1 in AX if CYL 0, SEC 1 is addressed
1222 add al,dh ; Results in 1 in AX if HEAD 0 is addressed
1223 dec ax ; Results in 0 in AX if MBR is addressed by CHS
1224
1225 DriveIO_MBR_Addressed_done:
1226 pop bx
1227 pop ax
1228 ret
1229DriveIO_MBR_Addressed EndP
1230
1231
1232
1233
1234; #########################################################################
1235; Routine: Writes DS:SI to a specified sector
1236; #########################################################################
1237; Calling : bx:ax - Absolute sector
1238; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
1239; ds:si - Source-Adress
1240; Returns : none
1241; Preserve: all registers
1242; #########################################################################
1243DriveIO_SaveSector Proc Near Uses ax bx cx dx ds si es di
1244
1245IFDEF AUX_DEBUG
1246 IF 0
1247 DBG_TEXT_OUT_AUX 'DriveIO_SaveSector:'
1248 PUSHRF
1249 ;~ call DEBUG_DumpRegisters
1250 ;~ call AuxIO_DumpParagraph
1251 ;~ call AuxIO_TeletypeNL
1252 POPRF
1253 ENDIF
1254ENDIF
1255
1256
1257;!
1258;! DEBUG_BLOCK
1259;! Force write to LBA0 to test interception routine.
1260;! Do *NOT* enable unless you are debugging, will overwrite MBR !
1261;!
1262IFDEF AUX_DEBUG
1263 IF 0
1264 pushf
1265 pusha
1266 xor ax,ax
1267 xor bx,bx
1268 xor cx,cx
1269 inc cx
1270 xor dh,dh
1271 popa
1272 popf
1273 ENDIF
1274ENDIF
1275
1276 ;
1277 ; Check if the MBR is the destination for the write.
1278 ; ZF=1 if so.
1279 ;
1280 call DriveIO_MBR_Addressed
1281 jnz DriveIO_SaveSector_continue_write
1282
1283
1284 ; MBR is addressed, check the sector that is requested to be written.
1285 ; For the bootdisk it should contain the AiR-BOOT signature, valid
1286 ; partition-table entries and the AA55h signature.
1287 ; If not, something is terribly wrong in some piece of the AB code.
1288 ; For any other disk (80h+) at least a valid partition table should
1289 ; be present together with the AA55h signature.
1290 call DriveIO_ProtectMBR
1291 jnc DriveIO_SaveSector_continue_write
1292
1293
1294 ;
1295 ; WE HAVE A SEVERE ERROR CONDITION !
1296 ; SOME AB CODE TRIES TO WRITE A NON-MBR TO THE DISK !
1297 ; ASK THE USER TO REPORT THIS !
1298 ; HALT THE SYSTEM !
1299 ;
1300
1301 ; Show error-box
1302 mov cx, 0C04h
1303 mov si, offset NonMBRwrite
1304 call SETUP_ShowErrorBox
1305 mov cx, 0C04h
1306 mov si, offset NonMBRwrite_rep
1307 call SETUP_ShowErrorBox
1308
1309
1310IFDEF AUX_DEBUG
1311 IF 0
1312 pushf
1313 pusha
1314 mov si, offset [NonMBRwrite]
1315 call AuxIO_TeletypeNL
1316 call AuxIO_Print
1317 call AuxIO_TeletypeNL
1318 popa
1319 popf
1320 ENDIF
1321ENDIF
1322
1323 ; Show popup and halt the system.
1324 jmp HaltSystem
1325
1326
1327
1328 ;
1329 ; Continue the write if not MBR sector or MBR to write is validated.
1330 ;
1331 DriveIO_SaveSector_continue_write:
1332 test byte ptr cs:[CurIO_UseExtension], 1
1333 jz DIOSS_UseNormal
1334 ; Are we forced do use LBA via Setting?
1335 ; Always use INT13X on v1.0.8+.
1336 ;~ test byte ptr cs:[CFG_ForceLBAUsage], 1
1337 ;~ jnz DIOSS_UseExtension
1338 jmp DIOSS_UseExtension
1339 ; Is the drive not a harddrive?
1340 cmp dl, 80h
1341 jb DIOSS_UseNormal
1342 ; Upper 8 bits of LBA-address set? -> Use LBA (maximum boundary is FB0400h)
1343 or bh, bh
1344 jnz DIOSS_UseExtension
1345 ; Compare Switch-Table value to bit 16-23 of LBA-address
1346 mov di, dx
1347 and di, 007Fh
1348 cmp bptr cs:[LBASwitchTable+di], bl
1349 jbe DIOSS_UseExtension
1350
1351 DIOSS_UseNormal:
1352
1353IFDEF AUX_DEBUG
1354 IF 0
1355 DBG_TEXT_OUT_AUX 'DriveIO_WriteSectorCHS:'
1356 PUSHRF
1357 call DEBUG_DumpRegisters
1358 call AuxIO_DumpParagraph
1359 call AuxIO_TeletypeNL
1360 POPRF
1361 ENDIF
1362ENDIF
1363
1364 mov di, 3 ; retry count
1365 DIOSS_ErrorLoop:
1366 push ds
1367 pop es
1368 mov bx, si ; ES:BX - Destination
1369 mov ax, 0301h ; Function 3 - Write Sector
1370 int 13h
1371 jnc DIOSS_Success
1372 dec di ; decrement retry count
1373 jnz DIOSS_ErrorLoop
1374 call MBR_SaveError
1375
1376 DIOSS_UseExtension:
1377
1378 mov di, ds ; segment for transfer address
1379 call DriveIO_WriteSectorLBA ; extended write
1380 jc MBR_SaveError ; halt on error
1381
1382 ;~ push cx
1383 ;~ mov cs:[INT13X_DAP_NumBlocks], 1 ; Copy ONE sector
1384 ;~ mov wptr cs:[INT13X_DAP_Transfer+0], si
1385 ;~ mov cx, ds
1386 ;~ mov wptr cs:[INT13X_DAP_Transfer+2], cx ; Fill out Transfer Adress
1387 ;~ mov wptr cs:[INT13X_DAP_Absolute+0], ax
1388 ;~ mov wptr cs:[INT13X_DAP_Absolute+2], bx ; Fill out Absolute Sector
1389 ;~ push cs
1390 ;~ pop ds
1391 ;~ mov si, offset [INT13X_DAP]
1392 ;~ mov ax, 4300h ; Extended Write (No Verify)
1393 ;~ int 13h
1394 ;~ pop cx
1395 ;~ jnc DIOSS_Success
1396 ;~ call MBR_SaveError
1397
1398 DIOSS_Success:
1399 ret
1400DriveIO_SaveSector EndP
1401
1402
1403
1404
1405;##############################################################################
1406;# When a disk has a Master LVM sector, it means it has been prepared for use
1407;# by OS/2 and contains important information about how OS/2 views its geometry
1408;# and other disk related properties. This function assumes the LBA address
1409;# of the Master LVM sector has already been located and simply loads the
1410;# sector into [LVMSector].
1411;#
1412;# Note that because this is an operation similar to the regular loading of
1413;# sectors, the disk I/O semantics are used here. This means CF=0 when an LVM
1414;# sector is successfully loaded and CF=1 otherwise.
1415;##############################################################################
1416;# ACTION : Loads the Master LVM sector if one exists
1417;# ----------------------------------------------------------------------------
1418;# EFFECTS : Modifies DAP structure and [LVMSector]
1419;# ----------------------------------------------------------------------------
1420;# IN : DL - BIOS disk number (80h,81h,etc)
1421;# ----------------------------------------------------------------------------
1422;# OUT : CF=0 - Valid Master LVM sector found and loaded
1423;##############################################################################
1424DriveIO_LoadMasterLVMSector Proc Near
1425
1426IFDEF AUX_DEBUG
1427 IF 0
1428 DBG_TEXT_OUT_AUX 'DriveIO_LoadMasterLVMSector:'
1429 PUSHRF
1430 ;~ call DEBUG_DumpRegisters
1431 ;~ call AuxIO_DumpParagraph
1432 ;~ call AuxIO_TeletypeNL
1433 POPRF
1434 ENDIF
1435ENDIF
1436
1437 ; Save all registers
1438 pusha
1439
1440 ; Check if BIOS disk number is valid
1441 call DriveIO_IsValidHarddisk
1442 jc DriveIO_LoadMasterLVMSector_error
1443
1444 ; Calculate the entry in the DISKINFO array for this disk
1445 call DriveIO_CalcDiskInfoPointer
1446
1447 ; Save the entry for later recalls
1448 mov bp, bx
1449
1450 ; Get the LBA address of the Master LVM sector
1451 mov ax, [bx+LocDISKINFO_LVM_MasterLBA+00h]
1452 mov bx, [bx+LocDISKINFO_LVM_MasterLBA+02h]
1453
1454 ; LBA of Master LVM sector cannot be 0, so none was found during
1455 ; the gathering of disk information.
1456 mov cx, ax
1457 or cx, bx
1458 jz DriveIO_LoadMasterLVMSector_error
1459
1460 ; Load it into [LVMSector]
1461 mov di, ds
1462 mov si, offset [LVMSector]
1463 call DriveIO_ReadSectorLBA
1464 jc DriveIO_LoadMasterLVMSector_error
1465
1466 ; Validate the Master LVM sector
1467 call LVM_ValidateSector
1468
1469 ; Complement success indicator to conform to semantics of this function
1470 cmc
1471
1472 ; Master LVM sector was valid and is now loaded in [LVMSector]
1473 jnc DriveIO_LoadMasterLVMSector_ret
1474
1475 DriveIO_LoadMasterLVMSector_error:
1476
1477 ; Clear the sector buffer for safety reasons
1478 mov si, offset [LVMSector]
1479 call ClearSectorBuffer
1480
1481 ; Indicate no Master LVM sector loaded
1482 stc
1483
1484 DriveIO_LoadMasterLVMSector_ret:
1485
1486 ; Restore all registers
1487 popa
1488
1489 ret
1490DriveIO_LoadMasterLVMSector Endp
1491
1492
1493
1494
1495;##############################################################################
1496;# There is much information to know about the connected disks.
1497;# We also want this information clustered per disk and available before
1498;# further disk and partition scanning takes place.
1499;# This function gathers such information like INT13, INT13X, MBR, LVM, more.
1500;# Especially important is the LVM information, because that contains the
1501;# geometry OS/2 uses to access the disk. Other important information is the
1502;# presence of valid MBRs, logical partitions and whatnot.
1503;# This function gathers such information and stores it in a DISKINFO structure
1504;# for which an instance exists for every disk found.
1505;##############################################################################
1506;# ACTION : Gather disk information and store this in the BSS
1507;# ----------------------------------------------------------------------------
1508;# EFFECTS : Modifies DAP structure and the buffers it uses, fills DISKINFO[n]
1509;# ----------------------------------------------------------------------------
1510;# IN : DL - BIOS disk number (80h,81h,etc)
1511;# ----------------------------------------------------------------------------
1512;# OUT : CF=1 - failure
1513;##############################################################################
1514DriveIO_GatherDiskInfo Proc Near
1515
1516IFDEF AUX_DEBUG
1517 IF 1
1518 DBG_TEXT_OUT_AUX 'DriveIO_GatherDiskInfo:'
1519 PUSHRF
1520 call DEBUG_DumpRegisters
1521 ;~ call AuxIO_DumpParagraph
1522 ;~ call AuxIO_TeletypeNL
1523 POPRF
1524 ENDIF
1525ENDIF
1526
1527 ; Push all registers we use
1528 pusha
1529 push ds
1530 push es
1531
1532 ; Make sure ES=DS
1533 push ds
1534 pop es
1535
1536 ; Check if BIOS disk number is valid
1537 call DriveIO_IsValidHarddisk
1538 jc DriveIO_GatherDiskInfo_error
1539
1540 ; Calculate the entry in the DISKINFO array for this disk
1541 call DriveIO_CalcDiskInfoPointer
1542
1543 ; Save the entry for later recalls
1544 mov bp, bx
1545
1546 ; Store the BIOS disk number in the structure
1547 mov [bx+LocDISKINFO_DiskNum], dl
1548
1549; ------------------------------------------------------------------- [ INT13 ]
1550
1551 ; Get BIOS Disk Parameters (legacy method)
1552 mov ah, 08h ; Get Disk Parameters
1553 int 13h ; Call BIOS
1554
1555 ; CF=1 or AH!=0 indicates error
1556 jc DriveIO_GatherDiskInfo_error
1557 test ah, ah
1558 jnz DriveIO_GatherDiskInfo_error
1559
1560 ; Recall DISKINFO entry
1561 mov bx, bp
1562
1563 ; Store SPT (WORD)
1564 xor ah, ah ; Zero extend SPT to 16 bits
1565 mov al, cl ; Hi 2 bits max cyl and max sec
1566 and al, 3fh ; Mask max sec (1-based)
1567 mov [bx+LocDISKINFO_I13_Secs], ax ; Store SPT
1568
1569 ; Store HEADS (WORD)
1570 xor dl, dl ; Zero extend HEADS to 16 bits
1571 xchg dl, dh ; Get max head (0-based)
1572 inc dx ; Head count
1573 mov [bx+LocDISKINFO_I13_Heads], dx ; Store HEADS
1574
1575 ; Store CYLS (WORD)
1576 shr cl, 6 ; Hi 2 bits of max cyl to 1:0
1577 xchg cl, ch ; Max cyl (0-based)
1578 inc cx ; Cyl count
1579 mov [bx+LocDISKINFO_I13_Cyls], cx ; Store CYLS
1580
1581 ; Recall BIOS disk number
1582 mov dl, [bx+LocDISKINFO_DiskNum]
1583
1584; ------------------------------------------------------------------ [ INT13X ]
1585
1586 ; Get BIOS Disk Parameters (extended method)
1587 mov si, offset [Scratch] ; Buffer to return disk info
1588 mov ax, 80h ; Size of buffer
1589 mov [si], ax ; Store it in first word
1590 mov ah, 48h ; Get Extended Disk Parameters
1591 int 13h ; Call BIOS
1592
1593 ; CF=1 or AH!=0 indicates error
1594 jc DriveIO_GatherDiskInfo_error
1595 test ah, ah
1596 jnz DriveIO_GatherDiskInfo_error
1597
1598 ; Store flags (WORD)
1599 cld ; Direction up
1600 lodsw ; Buffersize, discard
1601 lodsw ; Flags (CHS valid etc)
1602 mov [bx+LocDISKINFO_I13X_Flags], ax ; Store them
1603
1604 ; Store CYLS (DWORD)
1605 lodsw ; Cyl count low
1606 mov [bx+LocDISKINFO_I13X_Cyls+00h], ax ; Store CYLS low
1607 lodsw ; Cyl count high
1608 mov [bx+LocDISKINFO_I13X_Cyls+02h], ax ; Store CYLS high
1609
1610 ; Store HEADS (DWORD)
1611 lodsw ; Head count low
1612 mov [bx+LocDISKINFO_I13X_Heads+00h], ax ; Store HEADS low
1613 lodsw ; Head count high
1614 mov [bx+LocDISKINFO_I13X_Heads+02h], ax ; Store HEADS high
1615
1616 ; Store SPT (DWORD)
1617 lodsw ; Secs per track low
1618 mov [bx+LocDISKINFO_I13X_Secs+00h], ax ; Store SPT low
1619 lodsw ; Secs per track high
1620 mov [bx+LocDISKINFO_I13X_Secs+02h], ax ; Store SPT high
1621
1622 ; Store total LBA sectors (QWORD)
1623 lea di, [bx+LocDISKINFO_I13X_SecsLBA]
1624 mov cx, 4
1625 rep movsw
1626
1627 ; Store sector size (WORD)
1628 lodsw
1629 mov [bx+LocDISKINFO_I13X_SecSize], ax
1630
1631 ; Store bus name (4 bytes, space padded, v3.0+)
1632 lea si, [Scratch+24h]
1633 lea di, [bx+LocDISKINFO_I13X_HostBus]
1634 movsw
1635 movsw
1636
1637 ; Store interface name (8 bytes, space padded, v3.0+)
1638 lea di, [bx+LocDISKINFO_I13X_Interface]
1639 mov cx, 4
1640 rep movsw
1641
1642 ; Should gather some more INT13X info here,
1643 ; like maybe Advanced Format stuff or so.
1644 ; We'll investigate that at a later time.
1645
1646; --------------------------------------------------------------------- [ MBR ]
1647
1648 ; Load the MBR
1649 mov si, offset [TmpSector]
1650 call DriveIO_LoadMBR
1651
1652 ; Store MBR flags (valid sig, partitions present, airboot installed)
1653 mov [bx+LocDISKINFO_MbrFlags], al
1654
1655 ; Recall BIOS disk number
1656 mov dl, [bx+LocDISKINFO_DiskNum]
1657
1658; --------------------------------------------------------------------- [ LVM ]
1659
1660 ; Locate the Master LVM sector, if any
1661 call DriveIO_LocateMasterLVMSector
1662
1663 ; Save Master LVM sector LBA high
1664 mov cx, bx
1665
1666 ; Recall DISKINFO entry
1667 mov bx, bp
1668
1669 ; Store Master LVM sector LBA
1670 mov [bx+LocDISKINFO_LVM_MasterLBA+00h], ax
1671 mov [bx+LocDISKINFO_LVM_MasterLBA+02h], cx
1672
1673 ; No Master LVM sector found, so skip storing LVM info for this disk
1674 jnc DriveIO_GatherDiskInfo_no_master_lvm
1675
1676 ; Load the Master LVM sector into [LVMSector]
1677 call DriveIO_LoadMasterLVMSector
1678
1679 ; No valid Master LVM sector, so skip storing LVM info for this disk
1680 jc DriveIO_GatherDiskInfo_no_master_lvm
1681
1682 ; A valid Master LVM sector has been loaded into [LVMSector]
1683 mov si, offset [LVMSector]
1684
1685 ; Get the number of sectors per track (OS/2 geometry)
1686 mov ax, [si+LocLVM_Secs+00h]
1687 mov cx, [si+LocLVM_Secs+02h]
1688
1689 ; Store it
1690 mov [bx+LocDISKINFO_LVM_Secs+00h], ax
1691 mov [bx+LocDISKINFO_LVM_Secs+02h], cx
1692
1693 ; Get the number of heads (OS/2 geometry)
1694 mov ax, [si+LocLVM_Heads+00h]
1695 mov cx, [si+LocLVM_Heads+02h]
1696
1697 ; Store it
1698 mov [bx+LocDISKINFO_LVM_Heads+00h], ax
1699 mov [bx+LocDISKINFO_LVM_Heads+02h], cx
1700
1701 ; Should gather some more LVM info here,
1702 ; like OS/2 extended geometry and other flags.
1703 ; We'll implement that at a later time.
1704
1705 DriveIO_GatherDiskInfo_no_master_lvm:
1706
1707 ; When no Master LVM sector was found,
1708 ; the LVM info in the DISKINFO structure for the disk
1709 ; will be ZERO because the area was cleared in PRECRAP.
1710
1711 ; Indicate success
1712 clc
1713
1714 jmp DriveIO_GatherDiskInfo_ret
1715
1716 DriveIO_GatherDiskInfo_error:
1717 stc
1718 DriveIO_GatherDiskInfo_ret:
1719
1720
1721IFDEF AUX_DEBUG
1722 IF 1
1723 DBG_TEXT_OUT_AUX '[DISKINFO]'
1724 PUSHRF
1725 call DEBUG_DumpRegisters
1726 ;~ call AuxIO_DumpParagraph
1727 ;~ call AuxIO_TeletypeNL
1728 mov si, bp
1729 mov cx, 4
1730 @@:
1731 call AuxIO_DumpParagraph
1732 call AuxIO_TeletypeNL
1733 add si, 16
1734 loop @B
1735 mov si, offset [Scratch]
1736 mov cx, 4
1737 @@:
1738 call AuxIO_DumpParagraph
1739 call AuxIO_TeletypeNL
1740 add si, 16
1741 loop @B
1742 mov si, offset [LVMSector]
1743 mov cx, 7
1744 @@:
1745 call AuxIO_DumpParagraph
1746 call AuxIO_TeletypeNL
1747 add si, 16
1748 loop @B
1749 POPRF
1750 ENDIF
1751ENDIF
1752
1753 ; Restore registers
1754 pop es
1755 pop ds
1756 popa
1757
1758 ret
1759DriveIO_GatherDiskInfo EndP
1760
1761;------------------------------------------------------------------------------
1762; Scan all disks to gather information
1763;------------------------------------------------------------------------------
1764; IN : None
1765; OUT : CF=1 - some failure occured
1766; : ZF=1 - no harddisks
1767; NOTE : This does the preliminary gathering of disk information
1768;------------------------------------------------------------------------------
1769DriveIO_ScanDisks Proc Near
1770
1771IFDEF AUX_DEBUG
1772 IF 1
1773 DBG_TEXT_OUT_AUX 'DriveIO_ScanDisks:'
1774 PUSHRF
1775 call DEBUG_DumpRegisters
1776 ;~ call AuxIO_DumpParagraph
1777 ;~ call AuxIO_TeletypeNL
1778 POPRF
1779 ENDIF
1780ENDIF
1781
1782 ; Save all registers
1783 pusha
1784
1785 ; Get number of disks in DH
1786 call DriveIO_GetHardDriveCount
1787
1788 ; Check if there are any disks to scan
1789 xor cx, cx ; Prepare 16-bit counter
1790 mov cl, dh ; Number of disks now in CX
1791 jcxz DriveIO_ScanDisks_end ; Quit if no disks
1792
1793 ; Scan disks from 80h upward
1794 mov dl, 80h ; BIOS number of first disk
1795 DriveIO_ScanDisks_next:
1796 call DriveIO_GatherDiskInfo ; Gather info for this disk
1797 jc DriveIO_ScanDisks_end ; Quit if some error occured
1798 inc dl ; Advance to next disk
1799 loop DriveIO_ScanDisks_next ; Scan next disk if there is one
1800 test dl, dl ; Set ZF=0
1801 clc ; Indicate success
1802
1803 DriveIO_ScanDisks_end:
1804 ; Restore all registers
1805 popa
1806
1807 ret
1808DriveIO_ScanDisks EndP
1809
1810;------------------------------------------------------------------------------
1811; Calculate pointer to entry in DISKINFO structure
1812;------------------------------------------------------------------------------
1813; IN : DL BIOS disk number (80h etc)
1814; OUT : BX Pointer to entry
1815; NOTE : BIOS disk number must be valid
1816;------------------------------------------------------------------------------
1817DriveIO_CalcDiskInfoPointer Proc Near
1818 xchg bx, ax ; AX is used for calculation
1819 mov al, DISKINFO_Size ; Size of DISKINFO structure
1820 mov ah, dl ; BIOS disk number
1821 sub ah, 80h ; Now 0-based index
1822 mul ah ; Now offset into DISKINFO array
1823 add ax, offset [DiskInformation] ; Base of DISKINFO array
1824 xchg bx, ax ; BX now points to entry for disk
1825 ret
1826DriveIO_CalcDiskInfoPointer EndP
1827
1828;------------------------------------------------------------------------------
1829; Check if the BIOS disk number in DL is a harddisk and in range
1830;------------------------------------------------------------------------------
1831; IN : DL BIOS disk number (80h etc)
1832; OUT : CF=1 if invalid disk number or out of range
1833; NOTE : Only modifies flags
1834;------------------------------------------------------------------------------
1835DriveIO_IsValidHarddisk Proc Near Uses dx
1836 cmp dl, 80h ; BIOS disk number must be at least 80h
1837 jb @F ; Not a harddisk, exit with CY
1838 mov dh, dl ; Save to do compare
1839 sub dh, 80h ; Now 0 based disk number
1840 inc dh ; Now 1 based disk number
1841 cmp [TotalHarddiscs], dh ; Out of range, exit with CY
1842 @@: ret
1843DriveIO_IsValidHarddisk EndP
1844
1845
1846; Values for sectors per track table corresponding to DriveIO_IsHugeDrive return value.
1847;~ secs_per_track_table db 63,127,255,255,255,255
1848
1849;~ db_lmlvm db 'Load Master LVM -- disk: ',0
Note: See TracBrowser for help on using the repository browser.