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

Last change on this file since 43 was 43, checked in by Ben Rietbroek, 11 years ago

BSS Corruption Problem located (auxdebug on) [2012-02-21]

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 THESE COMMITS!!

Problem

o Function with Xrefs goes out-of-bounds because hideparttable is too small

Has only 30 entries and should be 45.
Lost partition checker initializes out-of-bounds.

Info

o About the hideparttable

For each partition it can be specified which other partitions need to
be hidden when that partition is booted. This is useful for legacy DOS
but also braindead Windows that presents HPFS/JFS partitions as
unformatted and tries to persuade the user to format them.
With v1.07 the numer of partitions that can be handled was expanded from
30 to 45, but the size of the hideparttable was overseen.

o The need to compress the hideparttable

The old size was 30x30=900 bytes while the required size is 45x45=2045 bytes.
This amount of space is not available in the image.
Since 6 bits are enough to identify the partition number to be hidden,
the solution is to devide the table into bitfields. This will result
in a table of (45*45*6)/8=1519 bytes, which can be fitted.

Changes

Revamped the sources quite a bit and moved the history to a separate
file. (AIR-BOOT.HIS)

New

o FIXCODE script for Linux

Just until the C version is ready...

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