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

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

For the record... (LOAD/SAVE ERROR ISSUES) [v1.1.1-testing]

This is the bug that might have caused many 'LOAD/SAVE' errors.
We'll fix it here but this whole 'DriveIO_GatherDiskInfo' routine is
an ugly beast full of incorrect assumptions and about to be removed
all together.

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