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

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

Added function to validate BIOS disk number [v1.1.1-testing]

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

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