2 ;-----------------------------------------------------------------------------
5 ; El Torito Bootable CD-ROM driver which does not reset the CD-ROM drive upon
6 ; loading, but instead accesses the drive through BIOS system calls
10 ; (c) 2000 by Gary Tong
11 ; (c) 2001-2009 by Bart Lagerweij
13 ; Permission is hereby granted, free of charge, to any person obtaining a copy
14 ; of this software and associated documentation files (the "Software"), to deal
15 ; in the Software without restriction, including without limitation the rights
16 ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 ; copies of the Software, and to permit persons to whom the Software is
18 ; furnished to do so, subject to the following conditions:
20 ; The above copyright notice and this permission notice shall be included in
21 ; all copies or substantial portions of the Software.
23 ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 ;-----------------------------------------------------------------------------
33 ; To assemble and link, use these commands with NASM 2.x:
34 ; nasm -Ox -f bin -o eltorito.sys eltorito.asm
36 ; To enable Trace markers uncomment the line below
39 ; To enable debug info uncomment the line below
50 %endif
; DEBUG_TRACERS
57 section .text
align=16
60 ;=============================================================================
65 Attributes
dw 0C800h
; |
66 Pointers
dw Strategy
; |
67 dw Commands
; | MSCDEX requires this
68 DeviceName
db 'ELTORITO' ; | data in these locations
73 DriverName
db 'El-Torito CD-ROM Device Driver',0
79 ReadBytes
db 0 ;0 --> 2048 bytes/sector
80 ;1 --> 1024 bytes/sector
81 ;2 --> 512 bytes/sector
83 Routines
dw Init
;Init ;0
84 dw Unsupported
;MediaCheck ;1
85 dw Unsupported
;BuildBPB ;2
86 dw IoctlInput
;IoctlInput ;3
87 dw Unsupported
;Input ;4
88 dw Unsupported
;NonDesInput ;5
89 dw Unsupported
;InputStatus ;6
90 dw Unsupported
;InputFlush ;7
91 dw Unsupported
;Output ;8
92 dw Unsupported
;OutputVerify ;9
93 dw Unsupported
;OutputStatus ;10
94 dw Unsupported
;OutputFlush ;11
95 dw IoctlOutput
;IoctlOutput ;12
96 dw DoNothing
;DeviceOpen ;13
97 dw DoNothing
;DeviceClose ;14
100 IoctlICtrl
dw Raddr
;Raddr ;0
101 dw Unsupported
;LocHead ;1
102 dw Unsupported
;(Reserved) ;2
103 dw Unsupported
;ErrStat ;3
104 dw Unsupported
;AudInfo ;4
105 dw DrvBytes
;DrvBytes ;5
106 dw DevStat
;DevStat ;6
107 dw SectSize
;SectSize ;7
108 dw VolSize
;VolSize ;8
109 dw MedChng
;MedChng ;9
111 SpecPkt times
19 db 0 ; offset 77h in 1.4
112 times
13 db 0 ; unknown extra 00s in 1.4
114 Greeting
db 'El-Torito Bootable CD-ROM Driver for Dos v',Ver
,', http://www.nu2.nu/eltorito/',CR
115 db ' (c) 2000 by Gary Tong',CR
116 db ' (c) 2001-2002 by Bart Lagerweij',CR
,0
119 ;=============================================================================
123 mov word [cs:ReqHdrLoc
],bx
124 mov word [cs:ReqHdrLoc
+2],es
128 ;=============================================================================
145 sti ;Enable interrupts
150 les bx,[ReqHdrLoc
] ;seg:offset ptr into es:bx
152 mov al,[es:bx+2] ;Get Command code
159 jb UnknownCmd
;If 15-127
162 UnknownCmd: mov al,121 ;8 = Unsupported (Reserved)
163 ShiftDown: sub al,113 ;128 --> 15, 121 --> 8
164 Mult2: shl al,1 ;Convert into offset (*2)
167 call word [di] ;Execute desired command
168 or ax,100h ;Set Return Status's Done bit
169 lds bx,[ReqHdrLoc
] ;seg:offset ptr into ds:bx
170 mov [bx+3],ax ;Save Status
173 cmp byte [cs:buffer
+2048], 96h
195 ;=============================================================================
197 Unsupported: ;Unsupported Command
199 mov ax,8003h ;Set Status Error bit,
202 retn ; Error 3 = Unknown Command
205 ;=============================================================================
207 IoctlInput: ;IOCTL Input Routine
209 mov di,[es:bx+14] ;es:bx --> Request Header
210 mov es,[es:bx+16] ;Get Xfer Address into es:di
211 xor ax,ax ;Get Control Block Code
220 mov al,2 ;Map to Unsupported
221 UnkIoctlI: shl al,1 ;Convert into offset (*2)
224 call word [si] ;Execute desired command
228 ;=============================================================================
230 Raddr: ;Return Device Header Address
235 xor ax, ax ;Set Return Status = success
240 ;=============================================================================
242 DrvBytes: ;Read Drive Bytes
245 push di ;Save original Xfer Addr
246 add di,2 ;Point to 1st dest byte
247 mov si,Greeting
;Point to Greeting
248 DrvB: movsb ;Copy over a byte
249 cmp byte [si],13 ;Is next char a CR?
250 jne DrvB
;Loop if not
252 sub di,2 ;Get #bytes copied into ax
254 pop di ;Retrieve original Xfer Addr
256 mov byte [es:di+1],al ;and save it
257 mov ax,0 ;Set Return Status = success
262 ;=============================================================================
264 DevStat: ;Return Device Status
267 mov word [es:di+1],202h ;Door closed
268 mov word [es:di+3],0 ;Door unlocked
269 ;Supports only cooked reading
274 ;No audio channel manipulation
275 ;Supports both HSG and Redbook
278 xor ax, ax ;Set Return Status = success
283 ;=============================================================================
285 SectSize: ;Return Sector Size
288 mov word [es:di+2],2048
289 mov ax,0 ;Set Return Status = success
294 ;=============================================================================
296 VolSize: ;Return Volume Size
299 call PriVolDesc
;Get and Check Primary Volume
301 mov ax,800Fh
;Assume Invalid Disk Change
302 jc VolExit
;If Read Failure
304 mov ax,word [Buffer
+80] ;Read Successful
305 mov word [es:di+1],ax ;Copy over Volume Size
306 mov ax,word [Buffer
+82]
307 mov word [es:di+3],ax
308 mov ax,0 ;Set Return Status = success
314 ;=============================================================================
316 MedChng: ;Return Media Changed Status
319 call PriVolDesc
;Get and Check Primary Volume
321 mov byte [es:di+1],-1 ;Assume Media Changed
322 mov ax,800Fh
; and Invalid Disk Change
323 jc MedExit
;If Media Changed or Bad
325 mov byte [es:di+1],1 ;Media has not changed
326 mov ax,0 ;Set Return Status = success
332 ;=============================================================================
334 PriVolDesc: ;Get and Check Primary Volume
337 mov ax,cs ;Set ds:si --> SpecPkt
342 mov byte [SpecPkt
],16 ;SpecPkt Size
343 mov byte [SpecPkt
+1],0 ;Reserved
344 mov word [SpecPkt
+2],1 ;Transfer one 2048-byte sector
346 mov cl,byte [ReadBytes
] ;Multiply by 4 if reading 512
347 shl word [SpecPkt
+2],cl ; bytes at a time
349 mov word [SpecPkt
+6],cs ;Into our Buffer
350 mov word [SpecPkt
+4], Buffer
351 mov word [SpecPkt
+8],16 ;From CD Sector 16
352 mov word [SpecPkt
+10],0
353 mov word [SpecPkt
+12],0
354 mov word [SpecPkt
+14],0
357 mov dl, [DriveNumber
]
358 mov ah, 42h ;Extended Read
360 jnc PriVolPass
;If success
367 ; read retries exhausted
372 mov si,Buffer
;Point input to Buffer
373 mov ax,-1 ;Init Checksum registers
374 mov bx,ax ; bx,ax = 0FFFFFFFFh
375 jc PriNew
;If Read Failure
377 push di ;Read Successful,
378 ; so Calculate Checksum
379 mov di,1024 ;Init Word counter
380 PriWord: mov dx,[cs:si] ;Grab next word from buffer
381 mov cx,16 ;Init bit counter
382 PriBit: shr dx,1 ;Shift everything right 1 bit
385 jnc NoMult
;If a zero shifted out
387 xor bx,RPolyH
;A one shifted out, so XOR
388 xor ax,RPolyL
; Checksum with RPoly
392 add si,2 ;Inc Word Pointer
397 pop di ;Checksum calculation complete
398 cmp bx,[Checksum
+2] ;Has Checksum changed?
399 jne PriNew
;If Checksum Changed
402 jne PriNew
;If Checksum Changed
404 clc ;Checksum not changed, CF=0
405 mov ax,0 ;Status = success
409 mov WORD [Checksum
+2],bx ;Save New Checksum
410 mov [Checksum
],ax ; or 0FFFFFFFFh if bad read
411 stc ;Checksum change, CF=1
412 mov ax, 800bh ;Status = read fault
415 PriNew: mov WORD [Checksum
+2],bx ;Save New Checksum
416 mov [Checksum
],ax ; or 0FFFFFFFFh if bad read
417 stc ;Checksum Changed, CF=1
418 mov ax,800Fh
;Status = Invalid Media Change
424 ;=============================================================================
426 IoctlOutput: ;IOCTL Output Routine
429 mov di,[es:bx+14] ;es:bx --> Request Header
430 mov es,[es:bx+16] ;Get Xfer Address into es:di
431 xor ax,ax ;Get Control Block Code
434 jne UnkIoctlO
;If not 2 (ResetDrv)
435 call DoNothing
;Reset Drive
438 call Unsupported
;Unsupported command
444 ;=============================================================================
446 DoNothing: ;Do Nothing Command
448 mov ax,0 ;Set Return Status = success
452 ;=============================================================================
454 ReadL: ;Read Long Command
459 ;es:bx --> Request Header
460 cmp byte [es:bx+24],0 ;Check Data Read Mode
461 jne ReadLErr
;If Cooked Mode
463 cmp byte [es:bx+13],2 ;Check Addressing Mode
464 jb ReadLOK
;If HSG or Redbook Mode
468 mov ax,8003h ;Set Return Status = Unknown
469 jmp ReadLExit
; Command Error and exit
472 mov ax,[es:bx+20] ;Get Starting Sector Number,
473 mov dx,[es:bx+22] ; Assume HSG Addressing Mode
474 cmp byte [es:bx+13],0 ;Check Addressing Mode again
475 je ReadLHSG
;If HSG Addressing Mode
478 ;Using Redbook Addressing Mode. Convert to HSG format
479 mov al,dl ;Get Minutes
481 mul dl ;ax = Minutes * 60
482 add al,byte [es:bx+21] ;Add in Seconds
485 mul dx ; ((Min * 60) + Sec) * 75
486 add al,byte [es:bx+20] ;Add in Frames
489 sub ax,150 ;Subtract 2-Second offset
490 sbb dx,0 ;dx:ax = HSG Starting Sector
493 mov word [SpecPkt
+8], ax ;Store Starting
494 mov word [SpecPkt
+10], dx ; Sector Number
495 mov word [SpecPkt
+12], 0 ; (HSG Format)
496 mov word [SpecPkt
+14], 0
498 mov ax,[es:bx+14] ;Get Transfer Address
499 mov word [SpecPkt
+4],ax
501 mov word [SpecPkt
+6],ax
503 mov byte [SpecPkt
],16 ;Size of Disk Address Packet
504 mov byte [SpecPkt
+1],0 ;Reserved
508 mov ax,[es:bx+18] ;Get number of sectors to read
509 mov word [SpecPkt
+2],ax
510 cmp ax, 3FFFh
;Too large?
514 mov cl,byte [ReadBytes
] ;Multiply by 4 if reading 512
515 shl word [SpecPkt
+2],cl ; bytes at a time
524 ReadDump: mov al, ' '
526 mov al, byte [si] ;Hexdump a SpecPkt byte
528 inc si ;Point to next byte
536 mov ah,42h ;Extended Read
538 jnc ReadLGd
;If success
548 xor ax, ax ;Status 0 = success
553 mov ax, 800Bh ;Set Read Fault Error
554 ; flow into ReadLExit
566 mov ah,0Eh
;BIOS video teletype output
571 mov bx,[bp+9*4] ; Get return address
572 mov al,[cs:bx] ; Get data byte
573 inc word [bp+9*4] ; Return to after data byte
575 mov ah,0Eh
;BIOS video teletype output
580 mov ah,0Eh
;BIOS video teletype output
589 ;-----------------------------------------------------------------------------
591 ;-----------------------------------------------------------------------------
592 ; print a 4 bits integer in hex
595 ; AL - 4 bits integer to print (low)
599 ; Registers destroyed: None
604 and al, 0fh
; we only need the first nibble
617 ;-----------------------------------------------------------------------------
619 ;-----------------------------------------------------------------------------
620 ; print a 8 bits integer in hex
623 ; AL - 8 bits integer to print
627 ; Registers destroyed: None
647 ;=============================================================================
648 ; print_hex16 - print a 16 bits integer in hex
651 ; AX - 16 bits integer to print
655 ; Registers destroyed: None
656 ;=============================================================================
667 loop print_hex16_loop
674 ;=============================================================================
675 ; print_hex32 - print a 32 bits integer in hex
678 ; EAX - 32 bits integer to print
682 ; Registers destroyed: None
683 ;=============================================================================
694 loop print_hex32_loop
701 ;=============================================================================
702 ; print_string - print string at current cursor location
705 ; DS:SI - ASCIIZ string to print
709 ; Registers destroyed: None
710 ;=============================================================================
721 jmp print_string_again
728 ;-----------------------------------------------------------------------------
730 ;-----------------------------------------------------------------------------
731 ; Print's a character at current cursor position
734 ; AL - Character to print
738 ; Registers destroyed: None
745 mov ah,0Eh
;BIOS video teletype output
755 ;=============================================================================
757 ;This space is used as a 2048-byte read buffer plus one test byte.
758 ;The 96h data is used for testing the number of bytes returned by an Extended
762 Buffer times
2049 db 96h
764 ;=============================================================================
766 Init: ;Initialization Routine
773 ; print CS value (load segment)
777 mov si, Greeting
;Display Greeting
780 mov ax,Unsupported
;Init is executed only once
784 int 13h ; Get diskemu status
785 jc FindBoot
; If CF=1 no diskemu loaded
787 mov [DriveNumber
], cl ; Store drive number
790 and al, 8 ; alt key ?
793 mov si, DrvNumMsg
; Display "drive number="
795 mov al, [DriveNumber
]
797 mov si, LineEnd
; CR/LF
801 ; Diskemu is not loaded
802 ; so loop to find drive number
803 ; *** start of 1.4 changes ***
804 ; ??? mov dl, 0ffh ;Start at Drive 0xff
805 ; *** FindBoot at c47 in 1.4, at c0c in 1.3 ***
806 FindBoot: call ScanDrives
; call new helper in 1.4
807 jnc FoundBoot
; ded*df3
808 ; mov si,offset SpecPkt ;Locate booted CD-ROM drive
809 ; mov [SpecPkt],0 ;Clear 1st byte of SpecPkt
810 ; mov ax,4B01h ;Get Bootable CD-ROM Status
812 ; jnc FindPass ;If booted CD found
814 ; Carry is not cleared in buggy Dell BIOSes,
815 ; so I'm checking packet size byte
816 ; some bogus bioses (Dell Inspiron 2500) returns packet size 0xff when failed
817 ; Dell Dimension XPsT returns packet size 0x14 when OK
822 ; cmp [SpecPkt], 13h ; anything between 13h and 20h should be OK
826 ; jmp short FoundBoot
831 ; jae FindBoot ;Check from ffh..80h
832 ; *** end of 1.4 changes ***
834 mov si,NoBootCD
;No booted CD found,
836 jmp NoEndAddr
;Do not install driver
839 ; mov dl, [SpecPkt+2] ; 1.4 change
840 ; *** next line at c57 in 1.4, at c3d in 1.3 ***
841 mov [DriveNumber
],dl ;Booted CD-ROM found,
845 and al, 8 ; alt key ?
850 mov si, SpecPkt
;Point to returned CD SpecPkt
851 mov cx, 19 ; containing 19 bytes
852 StatDump: mov al, ' ' ;Print a space
854 mov al, byte [si] ;Hexdump a SpecPkt byte
856 inc si ;Point to next byte
859 mov si, LineEnd
;Print a CR/LF
863 ;See how many CD Sector bytes are returned by an Extended Read
864 mov byte [SpecPkt
],16 ;SpecPkt Size
865 mov byte [SpecPkt
+1],0 ;Reserved
866 mov word [SpecPkt
+2],1 ;Transfer one sector
867 mov word [SpecPkt
+6],cs ;Into our Buffer
868 mov word [SpecPkt
+4],Buffer
869 mov word [SpecPkt
+8],16 ;From CD Sector 16
870 mov word [SpecPkt
+10],0
871 mov word [SpecPkt
+12],0
872 mov word [SpecPkt
+14],0
874 mov si, SpecPkt
;Set ds:si --> SpecPkt
875 mov dl, [DriveNumber
]
876 mov ah, 42h ;Extended Read
878 jnc SecSize
;If success
880 mov ah, 42h ;Always make 2 read attempts
882 ;How many bytes did we get?
883 SecSize: std ;Count down
884 mov ax,cs ;Point to end of Buffer
886 mov di,Buffer
+2047 ;Find end of read data
889 repe cmpsb ;cx = number of bytes read
891 cld ;Restore count direction to up
892 mov si,CDBytes
;Display number of bytes read
895 mov al, [DriveNumber
]
898 mov si,CDBytesA
;Remainder A of message
901 mov al,ch ;Hex-dump cx
902 and al,0Fh
;Second nibble
903 call print_hex8
; (don't need the First)
905 call print_hex8
; (don't need the First)
907 mov si,CDBytesB
;Remainder B of message
910 cmp cx,2048 ;Did we read 2048 bytes?
911 je ParseParm
;If yes <-- O.K.
913 mov byte [ReadBytes
],1
914 cmp cx,1024 ;Did we read 1024 bytes?
915 je ParseParm
;If yes <-- O.K.
917 mov byte [ReadBytes
],2
918 cmp cx,512 ;Did we read 512 bytes?
919 jne NoEndAddr
;If not, do not load driver
921 ParseParm: mov bx,word [cs:ReqHdrLoc
] ;Parse command line
922 mov es,word [cs:ReqHdrLoc
+2] ; parameters
923 mov si,[es:bx+18] ;Get BPB array ptr into DS:SI
926 FindParm1: cmp byte [si],0Dh ;CR? (End of parameters)
929 cmp byte [si],0Ah ;LF?
932 cmp byte [si],'/' ;A parameter?
936 cmp byte [si],'D' ;Device Name parameter?
945 mov si, DevName
;Device Name is at ds:si
946 push ds ;Keep ptr to Device Name
950 pop ds ;Retrieve Device Name ptr
952 mov cx, 8 ;Get next 8 chars
953 inc si ; = Device Name
957 NextChar: cmp byte [si],' '
960 mov ax,cs ;Pad end of Device Name with
961 mov ds,ax ; spaces if necessary
962 mov si,DblSpace
;A space
963 AboveSpace: mov al, [si]
965 movsb ;ds:[si] --> es:[di]
973 mov ax,Init
-2 ;Last byte of driver to keep
974 jmp EndAddr
;Install driver
977 mov ax, cs ; Restore segment registers (fix)
981 mov si,NoDevName
;No Device Name Found
984 NoEndAddr: mov ax,0 ;Do not install driver
986 EndAddr: mov es,[ReqHdrLoc
+2] ;Write End Address
990 mov bx,ax ;Hold onto install status
992 mov si, DrvInst
;Display driver install status
994 mov si, DrvInst1
;Assume driver installed
995 cmp bx,0 ;Was driver installed?
996 jne DrvStatus
;If yes
997 mov si, NoDrvInst
;Driver not installed
998 DrvStatus: call print_string
1000 mov ax,0 ;Set Return Status = success
1001 cmp bx,0 ;Was INIT successful?
1002 jne InitStat
;If yes
1003 mov ax,800Ch ;Status = General Failure
1005 push ax ;Save Return Status
1008 and al, 8 ; alt key ?
1012 mov si, WaitMsg
;Display Halted message
1017 and al, 8 ; Alt key?
1018 jnz AltWait
; Pressed? yes -> wait
1021 pop ax ;Retrieve Return Status
1023 retn ;That's it for Init!
1025 ; *** start 1.4 changes at ded ***
1026 SpecGo: mov si,SpecPkt
1030 ScanDrives: push ax ; at df3 in 1.4
1032 mov dl, 7fh
;Start at Drive 0x80
1035 mov ax,4B01h ;Get Bootable CD-ROM Status
1036 mov BYTE [SpecPkt
],0 ;Clear 1st byte of SpecPkt
1038 ; Carry is not cleared in buggy Dell BIOSes,
1039 ; so I'm checking packet size byte
1040 ; some bogus bioses (Dell Inspiron 2500) returns packet size 0xff when failed
1041 ; Dell Dimension XPsT returns packet size 0x14 when OK
1043 cmp BYTE [SpecPkt
], 13h ; anything between 13h and 20h should be OK
1045 cmp BYTE [SpecPkt
], 20h
1046 ja FindFail
; in 1.4 at e16
1047 jmp short SendFound
; in 1.4 at e26
1049 FindFail: cmp dl, 0ffh
1050 je SendFail
; Check from 80h..ffh
1051 jmp short NextDrv
;Next drive
1055 SendFound: mov dl, [SpecPkt
+2]
1060 ; *** end 1.4 changes ***
1062 ;=============================================================================
1064 ;------------------------------------------------------------
1065 ; keyboard flags - return keyboard flags in AL
1067 keyflag: ; at dbc in 1.3, at e2e in 1.4
1074 ;=============================================================================
1076 DrvNumMsg
db ' Diskemxx.bin returned drive number=', 0
1077 NoBootCD
db ' No booted CD-ROM found.',CR
,0
1079 CDStat
db ' INT 13h / AX=4B01h Specification Packet for '
1080 db 'Booted CD-ROM:',CR
,' ', 0
1082 CDBytes
db ' Drive ', 0
1083 CDBytesA
db ' returns ', 0
1084 CDBytesB
db 'h bytes per Sector.',CR
,0
1086 DevName
db ' Device Name: ', 0
1087 NoDevName
db ' No Device Name found. '
1088 db 'Usage: device=eltorito.sys /D:<DevName>',CR
,0
1090 DrvInst
db ' Driver ', 0
1091 NoDrvInst
db 7,'not ' ;7 = Ctrl-G = Beep
1092 DrvInst1
db 'installed',CR
,0
1094 WaitMsg
db ' Alt pressed, waiting...', CR
, 0
1095 ;ContMsg db ' Continuing...'
1099 ;=============================================================================