source: trunk/BOOTCODE/REGULAR/DRIVEIO.ASM@ 32

Last change on this file since 32 was 32, checked in by Ben Rietbroek, 13 years ago

Fixed Win7 boot from FAT32 and HPFS zero-drive ussue [2011-11-20]

Fixes

o Fixed booting Windows 7 from FAT32

Booting Windows (NT/2K/XP/Vista/7) from FAT32 when the actual system
resides on an NTFS partition actually chainload the Windows
boot-loader in the FAT32 partition.
A bug in the handling of such a FAT32 partition with the Windows
boot-loader caused it not to find NTLDR is some cases.

o Fixed HPFS zero-drive issue

The BPB contains a field that indicates the boot-drive to the
OS2BOOT and OS2LDR programs. When creating an HPFS partition and
then restoring a system from archive (i.e. a zip-file) of course
does not set this field, since only files are restored.
This causes the boot process to halt with "...cannot operate..."
or even boot another HPFS partition. This field is now derived from
the LVM drive-letter if it contains an incorrect value.

o Corrected CRC calculations on AiR-BOOT configuration

V1.07 expanded the number of partitions from 30 to 45.
However, this was not done correctly and the configuration CRC was
still caclulated over 5 sectors. Initial v1.0.8 code corrected this
but this results in the v1.07 installer and setaboot programs
breaking on v1.0.8 code. So, for the time being the CRC caclucation
is reverted back to 5 sectors for the sake of v1.07 compatibility.
Save and restore of the configuration use 7 sectors of course.

o Corrected contact information

V1.07 shipped with the wrong contact information, causing issues
to be reported on sourceforge instead of netlabs.

Changes

o Renamed original README.TXT to README.MKW
o Added 1README.TXT
o Added COPYING (GNU License)

Note

This commit and all following commits upto and including the RC3
commit [2012-09-09] are delayed commits from a local repository.
Also, the RC (Release Candidate) naming of the corresponding commits
is a bit misleading. One would label a revision with RC when near to
a final release. Since many things have changed between RC1,RC2 & RC3,
these RC's should be interpreted as mile-stones.

WARNING!!

All commits upto and including the commit of [2012-05-13] contain
a severe bug!! Building from these sources and then disabling
the 'force LBA' feature while also using the drive-letter feature or
editing the label can destroy the MBR on all attached disks!!
DO NOT DISABLE 'FORCE LBA USAGE' WHEN BUILT FROM THE ABOVE COMMITS!!

File size: 42.0 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 ModuleNames
25DB 'DRIVEIO',0
26ENDIF
27
28; Note: Some routines set DS/ES to CS or even address via CS, even if its not
29; needed. This was done for SECURITY. So DO NOT remove it.
30; Its there to make sure the correct data is loaded/written to/from
31; harddrive.
32;
33; IF YOU MODIFY ANYTHING IN HERE, YOU MAY EASILY BREAK YOUR HARDDRIVE!
34
35; Will only load base-configuration, will NOT load IPT nor Hide-Config
36; Those are originally loaded on startup and will NOT get reloaded.
37DriveIO_LoadConfiguration Proc Near Uses ax bx cx dx es
38 mov ax, cs
39 mov es, ax
40 mov bx, offset Configuration
41 mov dx, 0080h ; First harddrive, Sector 55...
42 mov cx, 0037h
43 mov ax, 0201h ; Function 02, read 1 sector...
44 int 13h
45 jnc DIOLC_NoError
46 call MBR_LoadError ; Will Abort BootUp
47 DIOLC_NoError:
48 ret
49DriveIO_LoadConfiguration EndP
50
51DriveIO_SaveConfiguration Proc Near Uses ax bx cx dx ds es si
52 mov ax, cs
53 mov ds, ax
54 mov es, ax ; Safety first (CS==DS==ES)
55 ; --- Overwrite Floppy-Name with "FloppyDrive"
56 mov si, offset TXT_Floppy_Drive
57 mov di, offset PartitionTable
58 sub di, 30 ; Adjust to Floppy-Name
59 mov cx, 11
60 rep movsb
61 mov si, offset Configuration ; Calculate new checksum
62 xor bx, bx
63
64 ; Changed from 5 to calculated value (not here, see compat. issue below)
65 ; Fixes issue: #2987 -- "air-boot doesn't remember drive letter"
66 ; Size of the ab-configuration in 512 byte sectors
67 ;mov cx, (MBR_BackUpMBR - Configuration) / 200h
68
69 ; AB v1.07 stores a 5 sector configuration with a 5 sector checksum.
70 ; AB v1.0.8 *should* stores a 7 sector configuration with a
71 ; 7 sector checksum.
72 ; Because 5 was hardcoded here, SET(A)BOOT v1.07 will see see an AB v1.0.8
73 ; config as corrupted, while this is not the case.
74 ; So, for compatibility reasons, in v1.0.8, the checksum stored is over
75 ; 5 sectors, to be compatible with v1.07.
76 ; This may change (be corrected) in future versions !
77 mov cx,5
78
79 mov dx, [CFG_CheckConfig]
80 mov [CFG_CheckConfig], bx
81 DIOSC_Loop:
82 call MBR_GetCheckOfSector
83 loop DIOSC_Loop
84 mov [CFG_CheckConfig], bx
85 ; --------------------------------------------------------------------
86 ; ES == CS
87 mov bx, offset Configuration
88 mov dx, 0080h ; First harddrive, Sector 55...
89 mov cx, 0037h
90
91 ; Changed from 5 to calculated value
92 ; Fixes issue: #2987 -- "air-boot doesn't remember drive letter"
93 ; Size of the ab-configuration in 512 byte sectors
94 mov al, (MBR_BackUpMBR - Configuration) / 200h
95 mov ah,03h
96
97 int 13h
98 jnc DIOSC_NoError
99 call MBR_SaveError ; Will Abort BootUp
100 DIOSC_NoError:
101 ret
102DriveIO_SaveConfiguration EndP
103
104DriveIO_UpdateFloppyName Proc Near Uses bx cx dx ds si es di
105 mov ax, cs
106 mov ds, ax
107 mov es, ax
108
109 mov ah, 00h ; Function 2 - Reset Drive
110 xor dl, dl
111 int 13h
112 xor dx, dx ; Cylinder=0, Head=0
113 mov cx, 1 ; Sector=1, Drive=0
114 mov bx, offset TmpSector ; ES:BX - TmpSector
115 mov ax, 0201h ; Function 2 - Load Sector
116 int 13h
117 jnc DIOUFN_AllFine
118
119 ; --- Overwrite Floppy-Name with "No Disc"
120 mov si, offset TXT_Floppy_NoDisc
121 xor ax, ax
122 DIOUFN_WriteFloppyName:
123 mov di, offset PartitionTable
124 sub di, 30 ; Adjust to Floppy-Name
125 mov cl, 11
126 rep movsb
127 ret ; AX=-1 -> GotDisc, =0 -> NoDisc
128
129 ; --- Floppy found and read, data in TempSector
130 DIOUFN_AllFine:
131 mov ax, -1
132 mov si, offset TXT_Floppy_NoName
133 cmp wptr es:[bx+54], 'AF'
134 jne DIOUFN_WriteFloppyName
135 cmp wptr es:[bx+56], '1T'
136 jne DIOUFN_WriteFloppyName
137 cmp bptr es:[bx+58], '2'
138 jne DIOUFN_WriteFloppyName
139 mov si, bx
140 add si, 43 ; FAT12 - Volume Label Location
141 jmp DIOUFN_WriteFloppyName
142DriveIO_UpdateFloppyName EndP
143
144; =============================================================================
145; HARDDRIVE / GENERAL ACCESS
146; =============================================================================
147; The following routines are used for harddisc/floppy access.
148; The access is done via INT 13h/CHS or INT 13h/LBA.
149; Access will be done prefered by INT 13h/CHS, because it's (I wonder!) much
150; faster, than the LBA-method. I don't know, why LBA is so slow. Perhaps BIOS.
151;
152; Internal access (to AiR-BOOT) is always done via INT 13h/CHS.
153
154DriveIO_GetHardDriveCount Proc Near Uses ds si
155 push ds si
156 push 0040h
157 pop ds
158 mov si, 0075h
159 mov dh, ds:[si] ; 40:75 -> POST: Total Harddiscs == DL
160 pop si ds
161 mov TotalHarddiscs, dh
162 ret
163DriveIO_GetHardDriveCount EndP
164
165
166; Fills our LBA-Usage table. It holds the LBA-address, where BIOS/CHS access is
167; stopped and BIOS/LBA access is started.
168; This is calculated by Sector*Heads. Comparing will get done with Bit 25-10
169; on LBA sectors, so we actually divide sector number by 1024.
170DriveIO_InitLBASwitchTable Proc Near Uses es di
171 mov di, offset LBASwitchTable
172 mov dh, TotalHarddiscs
173 mov dl, 80h
174 DIOILUT_DriveLoop:
175 push dx di
176 mov ah, 08h
177 int 13h ; DISK - GET DRIVE PARAMETERS
178 mov ah, 0FBh ; Assume 255 heads/63 sectors, if error
179 jc DIOILUT_Error
180 and cl, 111111b ; Isolate lower 6 bits of CL -> sector count
181
182 ; huge disk 127 sec/track on <1TB using DANI
183; mov cl, 07Fh
184
185 ;movzx ax, cl
186 mov al,cl
187 mov ah,0
188
189 mov bl, dh ; DH -> max head number
190 mul bl ; AX = Sectors*Heads
191 shl ah, 1
192 shl ah, 1 ; Shift 2 bits, so we are able to compare to
193 ; bit 16-23 of the LBA address
194 DIOILUT_Error:
195 pop di dx
196 mov bptr ds:[di], ah ; Save that value
197 inc di ; Go to next BYTE
198 inc dl
199 dec dh
200 jnz DIOILUT_DriveLoop
201 ret
202DriveIO_InitLBASwitchTable EndP
203
204
205
206
207; Adjusts BX:AX / CX:DX to meet LVM sector location
208; Destroys SI
209; Rousseau: Enhanced to handle sector-numbers 127 and 255 besides 63 for LVM-info sectors.
210; Ugly, need to cleanup.
211DriveIO_LVMAdjustToInfoSector Proc Near Uses
212
213
214
215; pusha
216; call AuxIO_TeletypeNL
217
218 ; LBA
219; xchg dx,bx
220; call AuxIO_TeletypeHexDWord
221; call AuxIO_TeletypeNL
222; xchg bx,dx
223
224 ; CYL
225; mov al,ch
226; call AuxIO_TeletypeHexByte
227; call AuxIO_TeletypeNL
228
229 ; HEAD
230; mov al,dh
231; call AuxIO_TeletypeHexByte
232; call AuxIO_TeletypeNL
233
234 ; SEC
235; mov al,cl
236; call AuxIO_TeletypeHexByte
237; call AuxIO_TeletypeNL
238
239 ; DRIVE
240; mov al,dl
241; call AuxIO_TeletypeHexByte
242; call AuxIO_TeletypeNL
243
244; popa
245
246
247 ;local ts:word
248 ;local ts2:word
249
250 pusha
251
252 ; Dump drive
253 mov si,offset drive
254; call AuxIO_Print
255 xchg al,dl
256; call AuxIO_TeletypeHexByte
257; call AuxIO_TeletypeNL
258 xchg dl,al
259
260 ; Dump SPT
261 mov si,offset spt_used
262; call AuxIO_Print
263 push dx
264 push bx
265 xor dh,dh
266 and dl,01111111b
267 shl dx,1
268 shl dx,1
269 mov bx, offset TrueSecs
270 add bx,dx
271 mov ax,word ptr [bx]
272
273 ;mov [ts],ax
274
275; call AuxIO_TeletypeHexWord
276; call AuxIO_TeletypeNL
277 pop bx
278 pop dx
279
280 pusha
281 push dx
282 ; Location of extended position
283 mov dx,word ptr [ExtendedAbsPos+02]
284 mov ax,word ptr [ExtendedAbsPos+00]
285; call AuxIO_TeletypeHexDWord
286; call AuxIO_TeletypeNL
287 pop dx
288
289 xor dh,dh
290 and dl,01111111b
291 shl dx,1
292 shl dx,1
293 mov bx, offset TrueSecs
294 add bx,dx
295
296 mov ax, word ptr[bx]
297; call AuxIO_TeletypeHexWord
298; call AuxIO_TeletypeNL
299 mov al,[ExtendedAbsPosSet] ; if true -> 1st sector of extpart (EBR), not logpart(BPB)
300; call AuxIO_TeletypeHexByte
301; call AuxIO_TeletypeNL
302 ; mov si,offset PartitionSector
303 ; call AuxIO_DumpSector
304 popa
305
306 ; LBA
307 mov si,offset before_lvm_adjust
308; call AuxIO_Print
309
310 xchg dx,bx
311; call AuxIO_TeletypeHexDWord
312; call AuxIO_TeletypeNL
313 xchg bx,dx
314 popa
315
316
317 ;or bx,ax
318 test [ExtendedAbsPosSet],1
319 jz pri
320
321
322
323
324 pusha
325 mov si,offset before_lvm_adjust_log
326; call AuxIO_Print
327 ; LBA
328 xchg dx,bx
329; call AuxIO_TeletypeHexDWord
330; call AuxIO_TeletypeNL
331 xchg bx,dx
332 popa
333
334
335 push dx
336 push bx
337 xor dh,dh
338 and dl,01111111b
339 shl dx,1
340 shl dx,1
341 mov bx,offset TrueSecs
342 add bx,dx
343 mov dx,[bx]
344 dec dx
345 add ax,dx
346 pop bx
347 pop dx
348 adc bx,0
349
350
351 pusha
352 mov si,offset after_lvm_adjust_log
353; call AuxIO_Print
354 ; LBA
355 xchg dx,bx
356; call AuxIO_TeletypeHexDWord
357; call AuxIO_TeletypeNL
358 xchg bx,dx
359 popa
360
361 jmp done
362
363
364
365
366pri:
367
368
369 push ax
370 push cx
371 xor ch, ch ; Zero out upper-byte
372
373 push dx
374 xor dh,dh
375 and dl,01111111b
376 shl dx,1
377 shl dx,1
378 push bx
379 mov bx,offset TrueSecs
380 add bx,dx
381 mov ax,[bx]
382 ;mov [ts2],ax
383 pop bx
384 pop dx
385
386
387
388 ;mov al, 63
389 ;call VideoIO_PrintByteDynamicNumber
390 ;self: jmp self
391
392
393
394 ; DEZE WERKT SOMS NIET GOED
395 ; ROMMELT MET CYLINDERS
396 ; ALLEEN TOEPASSEN ALS INT13X NIET ACTIEF !
397
398 and cl, al ; Isolate lower bits, because upper
399 mov ah, 0
400 mov si, ax ; ones may be used for cylinder
401 sub si, cx
402
403 pop cx
404 pop ax
405
406 or cl, al ; Set sector to last sector
407
408 add ax, si ; Adjust lower LBA
409 adc bx, 0 ; Adjust LBA Sector (BX:AX)
410
411
412
413 ;push ax
414 ;call AuxIO_TeletypeHexWord
415 ;call AuxIO_TeletypeNL
416 ;mov ax,[ts]
417 ;call AuxIO_TeletypeHexWord
418 ;call AuxIO_TeletypeNL
419 ;mov ax,[ts2]
420 ;call AuxIO_TeletypeHexWord
421 ;call AuxIO_TeletypeNL
422 ;pop ax
423
424 ;and ax,[ts]
425
426 jmp done
427
428
429
430done:
431
432
433
434 pusha
435 mov si,offset after_lvm_adjust
436; call AuxIO_Print
437 ; LBA
438 xchg dx,bx
439; call AuxIO_TeletypeHexDWord
440; call AuxIO_TeletypeNL
441 xchg bx,dx
442 popa
443
444
445
446; pusha
447; call AuxIO_TeletypeNL
448
449 ; CYL
450; mov al,ch
451; call AuxIO_TeletypeHexByte
452; call AuxIO_TeletypeNL
453
454 ; HEAD
455; mov al,dh
456; call AuxIO_TeletypeHexByte
457; call AuxIO_TeletypeNL
458
459 ; SEC
460; mov al,cl
461; call AuxIO_TeletypeHexByte
462; call AuxIO_TeletypeNL
463
464 ; DRIVE
465; mov al,dl
466; call AuxIO_TeletypeHexByte
467; call AuxIO_TeletypeNL
468
469; popa
470
471
472
473 ret
474DriveIO_LVMAdjustToInfoSector EndP
475
476drive: db 'drive : ',0
477before_lvm_adjust: db 'before lvm adjust : ',0
478after_lvm_adjust: db 'after lvm adjust : ',0
479before_lvm_adjust_log: db 'before lvm logical adjust: ',0
480after_lvm_adjust_log: db 'after lvm logical adjust : ',0
481spt_used: db 'spt used : ',0
482
483
484
485; #########################################################################
486; Routine: Loads partition to ExecBase and checks for validity
487; #########################################################################
488; Calling : bx:ax - Absolute sector
489; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
490; Returns : Carry Set if invalid partition encountered
491; Preserve: all registers
492; #########################################################################
493DriveIO_LoadPartition Proc Near Uses si
494 mov wptr cs:[CurPartition_Location+0], ax
495 mov wptr cs:[CurPartition_Location+2], bx
496 mov wptr cs:[CurPartition_Location+4], dx
497 mov wptr cs:[CurPartition_Location+6], cx ; Saves the location
498 mov si, offset PartitionSector ; DS:SI - ExecBase
499 call DriveIO_LoadSector
500 clc
501 cmp wptr [si+LocBR_Magic], 0AA55h
502 je DIOLP_Success
503 ; We check, if we are scanning partitions. In that case, if CHS is not 0/0/1
504 ; we will display a "bad partition table" message and halt the system.
505 cmp cx, 0001h
506 jne DIOLP_Failed
507 or dh, dh
508 jnz DIOLP_Failed
509 stc ; Set carry, so no partition table
510 DIOLP_Success:
511
512IFDEF AuxDebug
513 ; show current partition location
514 pushf
515 pusha
516 call AuxIO_TeletypeNL
517 mov si,offset db_curpartloc
518 call AuxIO_Print
519 mov dx,word ptr [CurPartition_Location+02]
520 mov ax,word ptr [CurPartition_Location+00]
521 call AuxIO_TeletypeHexDWord
522 call AuxIO_TeletypeNL
523 mov si,offset PartitionSector
524 call AuxIO_DumpSector
525 call AuxIO_TeletypeNL
526 popa
527 popf
528ENDIF
529
530 ret
531 DIOLP_Failed:
532 jmp DriveIO_GotLoadError
533DriveIO_LoadPartition EndP
534
535; #########################################################################
536; Routine: Writes a partition from ExecBase to its original sector
537; #########################################################################
538; Calling : none
539; Returns : none
540; Preserve: all registers
541; #########################################################################
542DriveIO_SavePartition Proc Near Uses ax bx cx dx si
543 mov ax, wptr cs:[CurPartition_Location+0]
544 mov bx, wptr cs:[CurPartition_Location+2]
545 mov dx, wptr cs:[CurPartition_Location+4]
546 mov cx, wptr cs:[CurPartition_Location+6] ; Gets prev. saved location
547 mov si, offset PartitionSector ; DS:SI - ExecBase
548 cmp wptr [si+LocBR_Magic], 0AA55h ; Checks for signature, if not found
549 jne DIOSP_SevereError ; we assume a really bad error
550 call DriveIO_SaveSector
551 DIOSP_SevereError:
552 ret
553DriveIO_SavePartition EndP
554
555; Keeps DS:SI for caller
556DriveIO_LoadTmpSector Proc Near Uses
557 mov si, offset TmpSector
558 call DriveIO_LoadSector ; Uses INT13X if needed
559 ret
560DriveIO_LoadTmpSector EndP
561
562; Keeps DS:SI for caller
563DriveIO_SaveTmpSector Proc Near Uses
564 mov si, offset TmpSector
565 call DriveIO_SaveSector
566 ret
567DriveIO_SaveTmpSector EndP
568
569; Keeps DS:SI for caller, sets carry if valid LVM sector encountered
570DriveIO_LoadLVMSector Proc Near Uses ax bx cx dx
571 test [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
572 jnz DIOLLVMS_NoLVMSector ; don't load but declare as bad!
573 mov ax, wptr cs:[CurPartition_Location+0]
574 mov bx, wptr cs:[CurPartition_Location+2]
575 mov dx, wptr cs:[CurPartition_Location+4]
576 mov cx, wptr cs:[CurPartition_Location+6] ; Gets cur. partition location
577
578 call DriveIO_LVMAdjustToInfoSector
579
580 mov si, offset LVMSector
581 call DriveIO_LoadSector
582
583IFDEF AuxDebug
584 ; show current partition location
585 pushf
586 pusha
587; call AuxIO_TeletypeNL
588 mov si,offset db_curlvmsec
589; call AuxIO_Print
590 mov dx,bx
591; call AuxIO_TeletypeHexDWord
592; call AuxIO_TeletypeNL
593 mov si,offset LVMSector
594; call AuxIO_DumpSector
595; call AuxIO_TeletypeNL
596 popa
597 popf
598ENDIF
599
600 ; Rousseau
601 ;pushf
602 ;pusha
603 ;mov si, offset MyText4
604 ;call VideoIO_Print
605 ;mov si, offset LVMSector
606 ;mov al, [si+LocLVM_VolumeLetter2]
607 ;call VideoIO_PrintByteDynamicNumber
608 ;mov al, [si+LocLVM_Startable]
609 ;call VideoIO_PrintByteDynamicNumber
610 ;mov al, [si+LocLVM_OnBootMenu]
611 ;call VideoIO_PrintByteDynamicNumber
612 ;;self: jmp self
613 ;popa
614 ;popf
615
616 call LVM_CheckSectorSignature
617 jnc DIOLLVMS_NoLVMSector
618 call LVM_CheckSectorCRC
619 jnc DIOLLVMS_NoLVMSector
620 ret
621 ; This here is called, if an invalid (or no) LVM information sector is found
622 ; It will truncate the first byte of the sector, so all other routines
623 ; will notice it easily by just comparing the first byte.
624 DIOLLVMS_NoLVMSector:
625 mov bptr [si+LocLVM_SignatureStart], 0
626 ret
627DriveIO_LoadLVMSector EndP
628
629; Keeps DS:SI for caller, saves at anytime w/o checks (!)
630DriveIO_SaveLVMSector Proc Near Uses ax bx cx dx
631 test [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
632 jnz DIOSLVMS_SevereError ; don't save at anytime (security!)
633 mov ax, wptr cs:[CurPartition_Location+0]
634 mov bx, wptr cs:[CurPartition_Location+2]
635 mov dx, wptr cs:[CurPartition_Location+4]
636 mov cx, wptr cs:[CurPartition_Location+6] ; Gets cur. partition location
637 call LVM_CheckSectorSignature
638 jnc DIOSLVMS_SevereError ; LVM Signature must be there
639 call DriveIO_LVMAdjustToInfoSector
640 mov si, offset LVMSector
641 call DriveIO_SaveSector
642 DIOSLVMS_SevereError:
643 ret
644DriveIO_SaveLVMSector EndP
645
646; Memory-Block that holds information for LBA-access via INT 13h
647DriveIO_DAP: db 10h ; Size of paket
648 db 0 ; Reserved
649DriveIO_DAP_NumBlocks dw 0 ; Number of blocks
650DriveIO_DAP_Transfer dd 0 ; Transfer Adress
651DriveIO_DAP_Absolute dd 0 ; Absolute Sector
652 dd 0 ; Second Part of QWORD
653
654; Special error message instead of "LOAD ERROR" during partition scanning,
655; so users will notice that something is bad with their partition table(s)
656DriveIO_GotLoadError Proc Near
657 test cs:CurIO_Scanning, 1 ; Must be CS:, cause DS!=CS maybe here
658 jnz InScanMode
659 jmp MBR_LoadError
660 InScanMode:
661 mov si, offset TXT_BrokenPartitionTable
662 push cs
663 pop ds
664 call MBR_Teletype
665 mov si, offset BrokenHDD
666 sub dl, 50h ; 80h -> '0'
667 cmp dl, 39h
668 jbe DIOGLE_BelowA
669 add dl, 7 ; 3Ah -> 'A'
670 DIOGLE_BelowA:
671 mov bptr [si+5], dl
672 call MBR_Teletype
673 jmp MBRLE_Halt
674DriveIO_GotLoadError EndP
675
676; #########################################################################
677; Routine: Loads a specified sector to DS:DI
678; #########################################################################
679; Calling : bx:ax - Absolute sector
680; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
681; ds:si - Destination-Adress
682; Returns : none
683; Preserve: all registers
684; #########################################################################
685DriveIO_LoadSector Proc Near Uses ax bx ds si es di
686 test cs:[CurIO_UseExtension], 1
687 jz DIOLS_UseNormal
688 ; Are we forced do use LBA via Setting? ; Rousseau: LBA
689 jnz DIOLS_UseExtension
690 ; Is the drive not a harddrive?
691 cmp dl, 80h
692 jb DIOLS_UseNormal
693 ; Upper 8 bits of LBA-address set? -> Use LBA (maximum boundary is FB0400h)
694 or bh, bh
695 jnz DIOLS_UseExtension
696 ; Compare Switch-Table value to bit 16-23 of LBA-address
697 mov di, dx
698 and di, 007Fh
699 cmp bptr cs:[LBASwitchTable+di], bl
700 jbe DIOLS_UseExtension
701 DIOLS_UseNormal:
702 mov di, 3
703 DIOLS_ErrorLoop:
704 push ds
705 pop es
706 mov bx, si ; ES:BX - Destination
707 mov ax, 0201h ; Function 2 - Load Sector
708 int 13h
709 jnc DIOLS_Success
710 dec di
711 jnz DIOLS_ErrorLoop
712 ; Sector load failed...
713 jmp DriveIO_GotLoadError
714
715 DIOLS_UseExtension:
716 push cx
717 mov cs:[DriveIO_DAP_NumBlocks], 1 ; Copy ONE sector
718 mov wptr cs:[DriveIO_DAP_Transfer+0], si
719 mov cx, ds
720 mov wptr cs:[DriveIO_DAP_Transfer+2], cx ; Fill out Transfer Adress
721 mov wptr cs:[DriveIO_DAP_Absolute+0], ax
722 mov wptr cs:[DriveIO_DAP_Absolute+2], bx ; Fill out Absolute Sector
723 push cs
724 pop ds
725 mov si, offset DriveIO_DAP
726 mov ah, 42h ; Extended Read
727 int 13h
728 pop cx
729 jnc DIOLS_Success
730 ; Sector load failed...
731 jmp DriveIO_GotLoadError
732
733 DIOLS_Success:
734 ret
735DriveIO_LoadSector EndP
736
737
738
739;
740; ############################################################
741; # Load a specified sector from a disk using LBA addressing #
742; ############################################################
743;
744; In
745; --
746; DL = Physical Disk
747; BX:CX = LBA sector
748; DI:SI = Target buffer
749;
750; Out
751; ---
752; AX = Error code
753;
754DriveIO_LoadSectorLBA Proc Near Uses bx cx dx si di ds es
755 ; Get one sector
756 mov cs:[DriveIO_DAP_NumBlocks], 1
757
758 ; Setup buffer address
759 mov wptr cs:[DriveIO_DAP_Transfer+0], si
760 mov wptr cs:[DriveIO_DAP_Transfer+2], di
761
762 ; Setup LBA address of requested sector
763 mov wptr cs:[DriveIO_DAP_Absolute+0], cx
764 mov wptr cs:[DriveIO_DAP_Absolute+2], bx
765 mov wptr cs:[DriveIO_DAP_Absolute+4], 0
766 mov wptr cs:[DriveIO_DAP_Absolute+6], 0
767
768 ; Address of packet
769 mov si, offset DriveIO_DAP
770
771 ; Do the extended read
772 mov ah, 42h
773 int 13h
774
775 ; Looking goot so far
776 jnc DriveIO_LoadSectorLBA_succes1
777
778 ; AH should not be zero, if it is then set to undefined and set carry
779 test ah,ah
780 jnz DriveIO_LoadSectorLBA_error1
781 mov ah, 0bbh ; Undefined error
782 DriveIO_LoadSectorLBA_error1:
783 stc
784 jmp DriveIO_LoadSectorLBA_exit
785
786 ; AL should be zero, if not then set to undefined and set carry
787 DriveIO_LoadSectorLBA_succes1:
788 test ah,ah
789 jz DriveIO_LoadSectorLBA_exit
790 stc
791 jmp DriveIO_LoadSectorLBA_exit
792
793 ; Return to caller
794 DriveIO_LoadSectorLBA_exit:
795 ret
796DriveIO_LoadSectorLBA EndP
797
798
799
800
801; #########################################################################
802; Routine: Writes DS:SI to a specified sector
803; #########################################################################
804; Calling : bx:ax - Absolute sector
805; cx:dx - Cylinder/Sector, Side/Drive (hi/lo-byte)
806; ds:si - Source-Adress
807; Returns : none
808; Preserve: all registers
809; #########################################################################
810DriveIO_SaveSector Proc Near Uses ax bx cx ds si es di
811 test cs:[CurIO_UseExtension], 1
812 jz DIOSS_UseNormal
813 ; Are we forced do use LBA via Setting?
814 test cs:[CFG_ForceLBAUsage], 1
815 jnz DIOSS_UseExtension
816 ; Is the drive not a harddrive?
817 cmp dl, 80h
818 jb DIOSS_UseNormal
819 ; Upper 8 bits of LBA-address set? -> Use LBA (maximum boundary is FB0400h)
820 or bh, bh
821 jnz DIOSS_UseExtension
822 ; Compare Switch-Table value to bit 16-23 of LBA-address
823 mov di, dx
824 and di, 007Fh
825 cmp bptr cs:[LBASwitchTable+di], bl
826 jbe DIOSS_UseExtension
827 DIOSS_UseNormal:
828 mov di, 3
829 DIOSS_ErrorLoop:
830 push ds
831 pop es
832 mov bx, si ; ES:BX - Destination
833 mov ax, 0301h ; Function 3 - Write Sector
834 int 13h
835 jnc DIOSS_Success
836 dec di
837 jnz DIOSS_ErrorLoop
838 call MBR_SaveError
839
840 DIOSS_UseExtension:
841 push cx
842 mov cs:[DriveIO_DAP_NumBlocks], 1 ; Copy ONE sector
843 mov wptr cs:[DriveIO_DAP_Transfer+0], si
844 mov cx, ds
845 mov wptr cs:[DriveIO_DAP_Transfer+2], cx ; Fill out Transfer Adress
846 mov wptr cs:[DriveIO_DAP_Absolute+0], ax
847 mov wptr cs:[DriveIO_DAP_Absolute+2], bx ; Fill out Absolute Sector
848 push cs
849 pop ds
850 mov si, offset DriveIO_DAP
851 mov ax, 4300h ; Extended Write (No Verify)
852 int 13h
853 pop cx
854 jnc DIOSS_Success
855 call MBR_SaveError
856
857 DIOSS_Success:
858 ret
859DriveIO_SaveSector EndP
860
861
862; See if a LVM-sector is valid.
863; In : si, pointer to sector
864; Out : CY if valid LVM sector, NC if not
865DriveIO_LVMSectorValid Proc Near
866 pusha
867
868 call LVM_CheckSectorSignature
869 ; NC if no signature found
870 jnc DriveIO_LVMSectorValid_End
871
872 call LVM_CheckSectorCRC
873 ; Force valid !!!
874 stc
875
876 DriveIO_LVMSectorValid_End:
877 popa
878 ret
879DriveIO_LVMSectorValid EndP
880
881; ------------------------------------------------------
882; Rousseau: # Load the master LVM-sector is one exists #
883; ------------------------------------------------------
884; Load the master LVM-sector to get the number of sectors per track as eCS views the drive.
885; If no master LVM-sector is found it is assumed eCS is not installed.
886; The master LVM-sector can be located at three different places according to drive size
887; and partitioning scheme and driver used.
888; When DANIS506.ADD is used, the eCS extended geometry will be 255/127 for drives >502GiB but <1TiB.
889; Then the location will be sector 127 which is LBA 126 (7Eh).
890; IBM1S506.ADD will always use 255/255 for the extended eCS geometry.
891; DANIS506.ADD will use 255/255 for drives >1TiB.
892; Then the location of the master LVM-sector will be 255 which is LBA 254 (FEh).
893; When eCS is installed on a huge drive that alread had a system on it, eCS will be confined to the
894; lower 502GiB of the drive. In this case the normal geometry from Int13X will be used.
895; This is also the case when no valid master LVM-sector can be found.
896;
897; Return CF when valid master LVM sector found, NC if not.
898; Loads sector at [LVMSector] !
899DriveIO_LoadMasterLVMSector Proc Near
900 pusha
901
902 mov si,offset db_lmlvm
903 ;call AuxIO_Print
904
905 ; Physical disk
906; mov al,'<'
907; call VideoIO_PrintSingleChar
908; mov al,dl
909; call VideoIO_PrintHexByte
910; mov al,'>'
911; call VideoIO_PrintSingleChar
912
913 ;call AuxIO_TeletypeHexByte
914 ;call AuxIO_TeletypeNL
915
916
917 ; Loop over the sector-translation table,
918 ; process the first three values from high (255) to low (bios spt, most likely 63)
919 mov cx,3
920 DriveIO_LoadMasterLVMSector_NextTry:
921 ; Number of sectors to read
922 mov [DriveIO_DAP_NumBlocks],1
923
924 ; Setup destination address
925 mov si, offset LVMSector
926 mov wptr [DriveIO_DAP_Transfer+0],si
927 mov ax, ds
928 mov wptr [DriveIO_DAP_Transfer+2],ax
929
930 ; Get the sector-number of the next possible LVM sector (255,127,63)
931 ; using the translation table and the counter as the index
932 mov bx,offset secs_per_track_table
933 mov ax,cx
934 dec ax
935 xlatb
936 dec al
937
938 ;
939 ; AX now contains the LBA address of the sector
940 ; that could be an LVM sector.
941 ; This is all in track0 so the address will not exceed 64kiB sectors.
942 ;
943
944; push ax
945; push ax
946; mov al,'$'
947; call VideoIO_PrintSingleChar
948; pop ax
949; call VideoIO_PrintHexByte
950; mov al,'$'
951; call VideoIO_PrintSingleChar
952; pop ax
953
954IFDEF AuxDebug
955 ; Dump the value
956 ;call AuxIO_TeletypeHexByte
957 ;call AuxIO_TeletypeNL
958ENDIF
959
960 ; Setup the requested LBA sector number
961 mov wptr [DriveIO_DAP_Absolute+0],ax ; LBA low
962 mov wptr [DriveIO_DAP_Absolute+2],00h ; LBA high
963 mov si, offset DriveIO_DAP ; address request packet
964 mov ah, 42h
965 int 13h ; do the i/o
966 cmc ; Complement carry so we can exit imm. on error
967 jnc DriveIO_LoadMasterLVMSector_End ; oops, return with NC
968
969
970 mov si,offset LVMSector
971
972 ; See if this is a valid LVM-sector
973 call DriveIO_LVMSectorValid
974
975; pushf
976; mov ah,0
977; rcl ah,1
978; mov al,'|'
979; call VideoIO_PrintSingleChar
980; mov al,ah
981; call VideoIO_PrintHexByte
982; mov al,'|'
983; call VideoIO_PrintSingleChar
984; popf
985
986
987 ; Yep, we found the master LVM-sector
988 jc DriveIO_LoadMasterLVMSector_Found
989 ; Try next location
990 loop DriveIO_LoadMasterLVMSector_NextTry
991
992 ; No master LVM-sector found, set CF=false
993 clc
994
995 DriveIO_LoadMasterLVMSector_Found:
996 DriveIO_LoadMasterLVMSector_End:
997 popa
998 ret
999DriveIO_LoadMasterLVMSector Endp
1000
1001
1002
1003
1004; ---------------------------------------------------
1005; Rousseau ## Large drives, (eCS) geometry and LBA ##
1006; ---------------------------------------------------
1007; A sector size of 512 bytes is assumed in the below calculations.
1008; Note that this scheme changes when the sector size will be 4096 or larger,
1009; like with modern drives that do not translate to 512 bytes per sector anymore.
1010; These drives will have a capacity above the 2TiB LBA32 boundary.
1011; For now, we assume drives <=2TiB with a sector size of 512 bytes.
1012
1013; There are a few boundaries that are of importance.
1014; Note that these are disk-boundaries and not partition boundaries.
1015; Even with a small partition, like <502GiB, OS/2 will use extended geometry on an
1016; empty huge disk.
1017; These boundaries are (from high to low):
1018
1019; (code 5)
1020; 2^32 = 4294967296 = 100000000 sectors = 2048 GiB
1021; This is the LBA32 2TiB boundary.
1022; Everything above it must be addressed using LBA48.
1023; OS/2 can currently not address this space above.
1024
1025; (code4)
1026; 65536*255*255 = 4261478400 = FE010000 sectors ~ 2032 GiB
1027; This is the max OS/2 boundary using 255/255 extended geometry.
1028; OS/2 can currently not address this space above.
1029
1030; (code 3)
1031; 2^31 = 2147483648 = 80000000 sectors = 1024 GiB
1032; This is the LBA32 1TiB boundary.
1033; OS/2 can address this space and will use 255/255 extended geometry.
1034
1035; (code 2)
1036; 65536*255*127 = 2122383360 = 7E810000 sectors ~ 1012 GiB
1037; This is the DANI 1TiB boundary.
1038; OS/2 can address this space and will use 255/255 extended geometry.
1039; Below this DANI will use 255/127 extended geometry.
1040; This matters on where the LVM-sectors are located !
1041
1042; (code 1)
1043; 65536*255*63 = 1052835840 = 3EC10000 sectors ~ 502 GiB
1044; This is the current OS/2 limit using this geometry because OS/2 can currently
1045; not address more than 65536 cylinders.
1046; DANI will address space above with 255/127 extended geometry up until the DANI 1TiB boundary (code 2)
1047
1048; (code 0)
1049; Everything below 65536*255*63 will be addressed using standard geometry.
1050
1051
1052;
1053; This function will return the following values:
1054;
1055
1056; 5 = This drive is above the 2^32 LBA32 (2TB) boundary and has more than 4294967296 sectors.
1057; LBA48 addressing is needed to access the complete capacity of the drive.
1058; OS/2 is currently unable to do so.
1059
1060; 4 = This drive is above the 65536*255*255 (4261478400) boundary but below 2^32.
1061; This is an OS/2 boundary and OS/2 is not able to access the drive above this boundary.
1062
1063; 3 = This drive is above the 2^31 (1TB) boundary and has more than 2147483648 sectors.
1064; OS/2 is able to access the drive using it's extended geometry.
1065; Both DANIS506 and IBM1S506 will use the 255/255 scheme.
1066
1067; 2 = This drive is above the 65536*255*127 (2122383360) boundary but below 2^31.
1068; OS/2 is able to access the drive using it's extended geometry.
1069; Both DANIS506 and IBM1S506 will use the 255/255 scheme.
1070
1071; 1 = This drive is above the 65536*255*63 (1052835840) boundary but below 65536*255*127.
1072; OS/2 is able to access the drive using it's extended geometry.
1073; Note that DANIS506 will use 255/127 and IBM1S506 will use 255/255 geometry !
1074; Using DANI or IBM influences the location of the LVM info-sectors !
1075
1076; 0 = This drive is below the 65536*255*63 (1052835840) boundary.
1077; OS/2 is able to access this drive using the standard 255/63 geometry.
1078
1079; So, any return value >0 means OS/2 extended geometry will be used.
1080; Value 1 will use 255/127 with DANIS506 but 255/255 with IBM1S506.
1081; Values 2 and 3 will use 255/255 on both drivers.
1082; You can or with 0x01 and check for 3 in this case.
1083; Any value above 3 will be a drive who's capacity cannot be fully used by OS/2
1084; The upper limit of 65536*255*255 will be in effect here.
1085
1086; Note this function currently handles the boot-drive only !
1087; It should be extended and use dl for the drive-number as a parameter.
1088; Because we use this function to get this info in a number of places,
1089; all regs and flags except AX are saved and restored.
1090
1091; DL contains BIOS disk-number; 80h for first, 81h for second, etc.
1092DriveIO_GatherDiskInfo Proc Near
1093 pushf
1094 push bx
1095 push cx
1096 push dx
1097 push si
1098 push di
1099 push es
1100
1101 ; Set ES to CS for buffer clearing
1102 push cs
1103 pop es
1104
1105 ; Clear the buffer
1106 ; Don't overwrite the word of the buffersize at index 0 !
1107 ; Old Phoenix BIOSses require word (flags) at 02 to be zero,
1108 ; so we clear the whole buffer to be sure.
1109 mov cx, i13xbuf_size
1110 mov di, offset i13xbuf
1111 mov [di],cx
1112 inc di
1113 inc di
1114 xor ah,ah
1115 cld
1116 rep stosb
1117
1118 ; Get the drive parameters
1119 mov ah, 48h ; Get Drive Parameters (extended version)
1120 ;mov dl, 80h ; Drive number
1121 mov si, offset i13xbuf ; Buffer for result-info
1122 push dx
1123 int 13h ; Call the BIOS-function
1124 pop dx
1125
1126 ; Do some error-checking
1127 or ah,ah ; AH is zero if no error (ZF=1 if no error)
1128 mov ax,0 ; Setup code for non-huge drive (does not influence ZF)
1129 jz DriveIO_GatherDiskInfo_ok ; Return if error (AL<>0 thus ZF=0) but CY not set, assuming non-huge drive
1130 jnc DriveIO_GatherDiskInfo_ok ; Return if error (CY=1), assuming non-huge drive
1131 jmp DriveIO_GatherDiskInfo_ret
1132
1133
1134 DriveIO_GatherDiskInfo_ok:
1135
1136 ;
1137 ; Store the drive geometry
1138 ;
1139
1140 mov si, offset i13xbuf
1141
1142 xor dh,dh
1143 and dl,01111111b
1144 shl dx,1
1145 shl dx,1
1146
1147 ; Store number of cylinders on disk
1148 mov bx, offset BIOS_Cyls
1149 add bx,dx
1150 mov ax,[si+04h]
1151
1152 mov word ptr [bx+00],ax
1153 mov ax,[si+06]
1154 mov word ptr [bx+02],ax
1155
1156 ; Store number of heads per cylinder
1157 mov bx, offset BIOS_Heads
1158 add bx,dx
1159 mov ax,[si+08h]
1160 mov word ptr [bx+00],ax
1161 mov ax,[si+0ah]
1162 mov word ptr [bx+02],ax
1163
1164 ; Store number of sectors per track
1165 mov bx, offset BIOS_Secs
1166 add bx,dx
1167 mov ax,[si+0ch]
1168 mov word ptr [bx+00],ax
1169
1170 ; Update first byte of translation-table to conform to BIOS SPT
1171 mov byte ptr [secs_per_track_table], al
1172
1173 mov ax,[si+0eh]
1174 mov word ptr [bx+02],ax
1175
1176 ; Store total secs
1177 mov bx, offset BIOS_TotalSecs
1178 add bx,dx
1179 add bx,dx
1180 mov ax,[si+10h]
1181
1182 mov word ptr [bx+00],ax
1183 mov ax,[si+12h]
1184 mov word ptr [bx+02],ax
1185 mov ax,[si+14h]
1186 mov word ptr [bx+04],ax
1187 mov ax,[si+18h]
1188 mov word ptr [bx+06],ax
1189
1190 ; Store number of bytes per sector
1191 mov bx, offset BIOS_Bytes
1192 add bx,dx
1193 mov ax,[si+18h]
1194 mov [bx],ax
1195
1196
1197 ;
1198 ; See of it's a huge drive of not
1199 ;
1200
1201 ; Drive is larger than 2TiB
1202 mov ax,5 ; Drive code (5)
1203 mov bx, [si+14h] ; Low word of high dword of sector-count
1204 or bx, [si+16h] ; High word of high dword of sector-count
1205 jnz DriveIO_GatherDiskInfo_ret ; If non-zero we have a drive with >2^32 sectors and thus LBA48 addressing
1206
1207 ; Drive is larger than max OS/2 capacity
1208 dec ax ; Drive code (4)
1209 mov bx, [si+12h] ; High word of low dword of sector-count
1210 cmp bx, 0fe01h ; Boundary
1211 jae DriveIO_GatherDiskInfo_ret ; If above or equal to boundary,
1212 ; we have a drive larger than to 65536*255*255 = FE010000 sectors
1213
1214 ; Drive can be completely utilized by OS/2
1215 dec ax ; Drive code (3)
1216 cmp bx, 8000h ; Boundary
1217 jae DriveIO_GatherDiskInfo_ret ; If above or equal to boundary,
1218 ; we have a drive larger than 2^31 sectors but smaller than 65536*255*255
1219
1220 ; This is the small area between DANI 1TiB and LBA 1TiB
1221 dec ax ; Drive code (2)
1222 cmp bx, 7e81h ; Boundary
1223 jae DriveIO_GatherDiskInfo_ret ; If above or equal to boundary,
1224 ; we have a drive larger than 65536*255*127 but <65536*255*255
1225 ; DANIS506.ADD will use 255/255 extended geometry
1226
1227 ; DANI will use 255/127 in this area, this could impact the location of LVM-sectors ! (last sec on track)
1228 dec ax ; Drive code (1)
1229 cmp bx, 3ec1h ; Boundary
1230 jae DriveIO_GatherDiskInfo_ret ; If above or equal to boundary,
1231 ; we have a drive larger than 65536*255*63 sectors (OS/2 502GiB Limit!)
1232 ; DANIS506.ADD will use 255/127 extended geometry !
1233 ; IBM1S506.ADD will use 255/255 extended geometry !
1234
1235 ; We have a drive that can be addressed using standard 255/63 geometry
1236 dec ax ; Drive code (0)
1237 ; We have a drive smaller than 65536*255*63 = 3EC10000 sectors
1238
1239 DriveIO_GatherDiskInfo_ret:
1240 pop es
1241 pop di
1242 pop si
1243 pop dx
1244 pop cx
1245 pop bx
1246
1247 mov [CurIO_UseExtension],1
1248
1249 popf
1250 ret
1251DriveIO_GatherDiskInfo EndP
1252
1253
1254
1255; Values for sectors per track table corresponding to DriveIO_IsHugeDrive return value.
1256secs_per_track_table: db 63,127,255,255,255,255
1257
1258db_lmlvm: db 'Load Master LVM -- disk: ',0
Note: See TracBrowser for help on using the repository browser.