1
2;-----------------------------------------------------------------------------
3; ElTorito.asm
4;
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
7;
8; MIT License
9;
10; (c) 2000 by Gary Tong
11; (c) 2001-2009 by Bart Lagerweij
12;
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:
19;
20; The above copyright notice and this permission notice shall be included in
21; all copies or substantial portions of the Software.
22;
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
29; THE SOFTWARE.
30;
31;-----------------------------------------------------------------------------
32
33; To assemble and link, use these commands with NASM 2.x:
34;   nasm -Ox -f bin -o eltorito.sys eltorito.asm
35
36; To enable Trace markers uncomment the line below
37; DEBUG_TRACERS=1
38
39; To enable debug info uncomment the line below
40; DEBUG=1
41
42%ifdef DEBUG_TRACERS
43 %macro	TRACER	1
44	call debug_tracer
45	db %1
46 %endmacro
47%else
48 %macro	TRACER	1
49 %endmacro
50%endif	; DEBUG_TRACERS
51
52%define	Ver	'1.5'
53%define CR	0DH, 0Ah
54RPolyH		equ	0EDB8h
55RPolyL		equ	08320h
56
57		section .text align=16
58		org	0
59
60;=============================================================================
61
62Cdrom:
63
64NextDriver	dd	-1			;-+
65Attributes	dw	0C800h			; |
66Pointers	dw	Strategy		; |
67		dw	Commands		; |   MSCDEX requires this
68DeviceName	db	'ELTORITO'		; |  data in these locations
69		dw	0			; |
70DriveLetter	db	0			; |
71NumUnitsSupp	db	1			;-+
72
73DriverName	db	'El-Torito CD-ROM Device Driver',0
74		align 4, db 0
75ReqHdrLoc	dd	0
76XferAddr	dd	0
77Checksum	dd	-1
78DriveNumber	db	0
79ReadBytes	db	0			;0 --> 2048 bytes/sector
80						;1 --> 1024 bytes/sector
81						;2 -->  512 bytes/sector
82
83Routines	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
98		dw	ReadL		;ReadL		;128
99
100IoctlICtrl	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
110
111SpecPkt		times	19	db	0	; offset 77h in 1.4
112		times	13	db	0	; unknown extra 00s in 1.4
113
114Greeting	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
117DblSpace	db	'  ',0
118
119;=============================================================================
120
121Strategy:
122
123		mov	word [cs:ReqHdrLoc],bx
124		mov	word [cs:ReqHdrLoc+2],es
125		retf
126
127
128;=============================================================================
129
130Commands:
131
132		push	ax
133		push	bx
134		push	cx
135		push	dx
136		push	si
137		push	di
138		push	bp
139;		pushad
140		push	ds
141		push	es
142		TRACER 'C'
143
144		cld				;Clear direction
145		sti				;Enable interrupts
146
147		mov	ax, cs			;ds=cs
148		mov	ds, ax
149
150		les	bx,[ReqHdrLoc]	;seg:offset ptr into es:bx
151		xor	ax,ax
152		mov	al,[es:bx+2]		;Get Command code
153%ifdef DEBUG
154		call	print_hex8
155%endif
156		cmp	al,15
157		jb	Mult2			;If 0-14
158		cmp	al,128
159		jb 	UnknownCmd		;If 15-127
160		cmp	al,129
161		jb	ShiftDown		;If 128
162UnknownCmd:	mov	al,121			;8 = Unsupported (Reserved)
163ShiftDown:	sub	al,113			;128 --> 15, 121 --> 8
164Mult2:		shl	al,1			;Convert into offset (*2)
165		mov	di,Routines
166		add	di,ax
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
171
172%ifdef DEBUG
173		cmp	byte [cs:buffer+2048], 96h
174		je	buffer_ok
175		mov	al, '!'
176		call	print_char
177		jmp	$
178buffer_ok:
179%endif
180
181		TRACER 'c'
182		pop	es
183		pop	ds
184;		popad
185		pop	bp
186		pop	di
187		pop	si
188		pop	dx
189		pop	cx
190		pop	bx
191		pop	ax
192		retf
193
194
195;=============================================================================
196
197Unsupported:			;Unsupported Command
198
199		mov	ax,8003h		;Set Status Error bit,
200		TRACER 'U'
201		TRACER 'C'
202		retn				;   Error 3 = Unknown Command
203
204
205;=============================================================================
206
207IoctlInput:			;IOCTL Input Routine
208
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
212		mov	al,[es:di]
213%ifdef DEBUG
214	TRACER 'I'
215	TRACER 'O'
216	call	print_hex8
217%endif
218		cmp	al,10
219		jb	UnkIoctlI		;If 0-9
220		mov	al,2			;Map to Unsupported
221UnkIoctlI:	shl	al,1			;Convert into offset (*2)
222		mov	si,IoctlICtrl
223		add	si,ax
224		call 	word [si]		;Execute desired command
225		retn
226
227
228;=============================================================================
229
230Raddr:			;Return Device Header Address
231
232		TRACER 'A'
233		mov	word [es:di+1],0
234		mov	[es:di+3],cs
235		xor	ax, ax			;Set Return Status = success
236		TRACER 'a'
237		retn
238
239
240;=============================================================================
241
242DrvBytes:			;Read Drive Bytes
243
244		TRACER 'B'
245		push	di			;Save original Xfer Addr
246		add	di,2			;Point to 1st dest byte
247		mov	si,Greeting	;Point to Greeting
248DrvB:		movsb				;Copy over a byte
249		cmp	byte [si],13	;Is next char a CR?
250		jne	DrvB			;Loop if not
251
252		sub	di,2			;Get #bytes copied into ax
253		mov	ax,di
254		pop	di			;Retrieve original Xfer Addr
255		sub	ax,di
256		mov	byte [es:di+1],al	;and save it
257		mov	ax,0			;Set Return Status = success
258		TRACER 'b'
259		retn
260
261
262;=============================================================================
263
264DevStat:			;Return Device Status
265
266		TRACER 'D'
267		mov	word [es:di+1],202h	;Door closed
268		mov	word [es:di+3],0	;Door unlocked
269						;Supports only cooked reading
270						;Read only
271						;Data read only
272						;No interleaving
273						;No prefetching
274						;No audio channel manipulation
275						;Supports both HSG and Redbook
276						;  addressing modes
277
278		xor	ax, ax			;Set Return Status = success
279		TRACER 'd'
280		retn
281
282
283;=============================================================================
284
285SectSize:			;Return Sector Size
286
287		TRACER 'S'
288		mov	word [es:di+2],2048
289		mov	ax,0			;Set Return Status = success
290		TRACER 's'
291		retn
292
293
294;=============================================================================
295
296VolSize:			;Return Volume Size
297
298		TRACER 'V'
299		call	PriVolDesc		;Get and Check Primary Volume
300						;  Descriptor
301		mov	ax,800Fh		;Assume Invalid Disk Change
302		jc	VolExit			;If Read Failure
303
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
309VolExit:
310		TRACER 'v'
311		retn
312
313
314;=============================================================================
315
316MedChng:			;Return Media Changed Status
317
318		TRACER 'M'
319		call	PriVolDesc		;Get and Check Primary Volume
320						;  Descriptor
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
324
325		mov	byte [es:di+1],1	;Media has not changed
326		mov	ax,0			;Set Return Status = success
327MedExit:
328		TRACER 'm'
329		retn
330
331
332;=============================================================================
333
334PriVolDesc:			;Get and Check Primary Volume
335						;  Descriptor
336		TRACER 'P'
337		mov	ax,cs			;Set ds:si --> SpecPkt
338		mov	ds,ax
339
340		mov	cx, 5
341PriVolAgain:
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
345		push	cx
346		mov	cl,byte [ReadBytes]	;Multiply by 4 if reading 512
347		shl	word [SpecPkt+2],cl	;  bytes at a time
348		pop	cx
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
355
356		mov	si, SpecPkt
357		mov	dl, [DriveNumber]
358		mov	ah, 42h			;Extended Read
359		int	13h
360		jnc	PriVolPass		;If success
361
362;		TRACER '1'
363		; read error
364		loop	PriVolAgain
365
366		TRACER '2'
367		; read retries exhausted
368		; flow into below
369		jmp	PriReadErr
370
371PriVolPass:
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
376
377		push	di			;Read Successful,
378						;  so Calculate Checksum
379		mov	di,1024			;Init Word counter
380PriWord:	mov	dx,[cs:si]		;Grab next word from buffer
381		mov	cx,16			;Init bit counter
382PriBit:		shr	dx,1			;Shift everything right 1 bit
383		rcr	bx,1
384		rcr	ax,1
385		jnc	NoMult			;If a zero shifted out
386
387		xor	bx,RPolyH		;A one shifted out, so XOR
388		xor	ax,RPolyL		;  Checksum with RPoly
389NoMult:
390		loop	PriBit
391
392		add	si,2			;Inc Word Pointer
393		dec	di
394		ja	PriWord
395		TRACER '3'
396
397		pop	di			;Checksum calculation complete
398		cmp	bx,[Checksum+2]		;Has Checksum changed?
399		jne	PriNew			;If Checksum Changed
400
401		cmp	ax,[Checksum]
402		jne	PriNew			;If Checksum Changed
403
404		clc				;Checksum not changed, CF=0
405		mov	ax,0			;Status = success
406		jmp	PriOld
407
408PriReadErr:
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
413		jmp	PriOld
414
415PriNew:		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
419PriOld:
420		TRACER 'p'
421		retn
422
423
424;=============================================================================
425
426IoctlOutput:			;IOCTL Output Routine
427
428		TRACER 'O'
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
432		mov	al,[es:di]
433		cmp	al,2
434		jne	UnkIoctlO		;If not 2 (ResetDrv)
435		call	DoNothing		;Reset Drive
436		jmp	IoctlODone
437UnkIoctlO:
438		call	Unsupported		;Unsupported command
439IoctlODone:
440		TRACER 'o'
441		retn
442
443
444;=============================================================================
445
446DoNothing:			;Do Nothing Command
447
448		mov	ax,0			;Set Return Status = success
449		retn
450
451
452;=============================================================================
453
454ReadL:			;Read Long Command
455
456		TRACER 'R'
457		mov	ax,cs			;Set ds=cs
458		mov	ds,ax
459						;es:bx --> Request Header
460		cmp	byte [es:bx+24],0	;Check Data Read Mode
461		jne	ReadLErr		;If Cooked Mode
462
463		cmp	byte [es:bx+13],2	;Check Addressing Mode
464		jb	ReadLOK			;If HSG or Redbook Mode
465
466ReadLErr:
467		TRACER '8'
468		mov	ax,8003h		;Set Return Status = Unknown
469		jmp	ReadLExit		;  Command Error and exit
470
471ReadLOK:
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
476
477		TRACER '7'
478		;Using Redbook Addressing Mode.  Convert to HSG format
479		mov	al,dl			;Get Minutes
480		mov	dl,60
481		mul	dl			;ax = Minutes * 60
482		add	al,byte [es:bx+21]	;Add in Seconds
483		adc	ah,0
484		mov	dx,75			;dx:ax =
485		mul	dx			;  ((Min * 60) + Sec) * 75
486		add	al,byte [es:bx+20]	;Add in Frames
487		adc	ah,0
488		adc	dx,0
489		sub	ax,150			;Subtract 2-Second offset
490		sbb	dx,0			;dx:ax = HSG Starting Sector
491
492ReadLHSG:
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
497
498		mov	ax,[es:bx+14]		;Get Transfer Address
499		mov	word [SpecPkt+4],ax
500		mov	ax,[es:bx+16]
501		mov	word [SpecPkt+6],ax
502
503		mov	byte [SpecPkt],16	;Size of Disk Address Packet
504		mov	byte [SpecPkt+1],0	;Reserved
505
506		mov	cx, 5
507ReadLAgain:
508		mov	ax,[es:bx+18]		;Get number of sectors to read
509		mov	word [SpecPkt+2],ax
510		cmp	ax, 3FFFh		;Too large?
511		ja	ReadLBad		;If yes
512
513		push	cx
514		mov	cl,byte [ReadBytes]	;Multiply by 4 if reading 512
515		shl	word [SpecPkt+2],cl	;  bytes at a time
516		pop	cx
517
518%ifdef DEBUG
519		push	ax
520		push	cx
521		push	si
522		mov	cx, 16
523		mov	si,SpecPkt
524ReadDump:	mov	al, ' '
525		call	print_char
526		mov	al, byte [si]	;Hexdump a SpecPkt byte
527		call	print_hex8
528		inc	si			;Point to next byte
529		loop	ReadDump
530		pop	si
531		pop	cx
532		pop	ax
533%endif
534		mov	si,SpecPkt
535		mov	dl,[DriveNumber]
536		mov	ah,42h			;Extended Read
537		int	13h
538		jnc	ReadLGd			;If success
539
540;hang:
541;		jmp	hang
542;		TRACER '1'
543		loop	ReadLAgain
544		TRACER '2'
545		jmp short ReadLBad
546ReadLGd:
547		TRACER '3'
548		xor	ax, ax 			;Status 0 = success
549		jmp short ReadLExit
550
551ReadLBad:
552		TRACER '9'
553		mov	ax, 800Bh		;Set Read Fault Error
554		; flow into ReadLExit
555ReadLExit:
556		TRACER 'r'
557		retn
558
559
560
561%ifdef DEBUG_TRACERS
562debug_tracer:	pushad
563		pushfd
564
565		mov	al, '['
566		mov	ah,0Eh			;BIOS video teletype output
567		xor	bh, bh
568		int	10h			;Print it
569
570		mov	bp,sp
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
574
575		mov	ah,0Eh			;BIOS video teletype output
576		xor	bh, bh
577		int	10h			;Print it
578
579		mov	al, ']'
580		mov	ah,0Eh			;BIOS video teletype output
581		xor	bh, bh
582		int	10h			;Print it
583
584		popfd
585		popad
586		retn
587%endif
588
589;-----------------------------------------------------------------------------
590; PRINT_HEX4
591;-----------------------------------------------------------------------------
592; print a 4 bits integer in hex
593;
594; Input:
595;	AL - 4 bits integer to print (low)
596;
597; Output: None
598;
599; Registers destroyed: None
600;
601print_hex4:
602
603	push	ax
604	and	al, 0fh		; we only need the first nibble
605	cmp	al, 10
606	jae	hex_A_F
607	add	al, '0'
608	jmp	hex_0_9
609hex_A_F:
610	add	al, 'A'-10
611hex_0_9:
612	call	print_char
613	pop	ax
614	retn
615
616
617;-----------------------------------------------------------------------------
618; print_hex8
619;-----------------------------------------------------------------------------
620; print	a 8 bits integer in hex
621;
622; Input:
623;	AL - 8 bits integer to print
624;
625; Output: None
626;
627; Registers destroyed: None
628;
629print_hex8:
630
631	push	ax
632	push	bx
633
634	mov	ah, al
635	shr	al, 4
636	call	print_hex4
637
638	mov	al, ah
639	and	al, 0fh
640	call	print_hex4
641
642	pop	bx
643	pop	ax
644	retn
645
646
647;=============================================================================
648; print_hex16 - print a 16 bits integer in hex
649;
650; Input:
651;	AX - 16 bits integer to print
652;
653; Output: None
654;
655; Registers destroyed: None
656;=============================================================================
657print_hex16:
658
659	push	ax
660	push	bx
661	push	cx
662
663	mov	cx, 4
664print_hex16_loop:
665	rol	ax, 4
666	call	print_hex4
667	loop	print_hex16_loop
668
669	pop	cx
670	pop	bx
671	pop	ax
672	retn
673
674;=============================================================================
675; print_hex32 - print a 32 bits integer in hex
676;
677; Input:
678;	EAX - 32 bits integer to print
679;
680; Output: None
681;
682; Registers destroyed: None
683;=============================================================================
684print_hex32:
685
686	push	eax
687	push	bx
688	push	cx
689
690	mov	cx, 8
691print_hex32_loop:
692	rol	eax, 4
693	call	print_hex4
694	loop	print_hex32_loop
695
696	pop	cx
697	pop	bx
698	pop	eax
699	retn
700
701;=============================================================================
702; print_string - print string at current cursor location
703;
704; Input:
705;	DS:SI - ASCIIZ string to print
706;
707; Output: None
708;
709; Registers destroyed: None
710;=============================================================================
711print_string:
712		push	ax
713		push	si
714
715print_string_again:
716		mov	al, [si]
717		or	al, al
718		jz	print_string_exit
719		call	print_char
720		inc	si
721		jmp	print_string_again
722
723print_string_exit:
724		pop	si
725		pop	ax
726		retn
727
728;-----------------------------------------------------------------------------
729; PRINT_CHAR
730;-----------------------------------------------------------------------------
731; Print's a character at current cursor position
732;
733; Input:
734;	AL - Character to print
735;
736; Output: None
737;
738; Registers destroyed: None
739;
740print_char:
741
742		push	ax
743		push	bx
744
745		mov	ah,0Eh			;BIOS video teletype output
746		xor	bh, bh
747		int	10h			;Print it
748
749print_char_exit:
750		pop	bx
751		pop	ax
752		retn
753
754
755;=============================================================================
756
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
759;  CD-ROM sector read
760
761		align	16, db 0
762Buffer		times	2049	db	96h
763
764;=============================================================================
765
766Init:			;Initialization Routine
767
768		TRACER 'I'
769		mov	ax,cs			;ds=cs
770		mov	ds,ax
771
772%ifdef DEBUG
773; print CS value (load segment)
774		call	print_hex16
775%endif
776
777		mov	si, Greeting	;Display Greeting
778		call	print_string
779
780		mov	ax,Unsupported	;Init is executed only once
781		mov	[Routines],ax
782
783		mov	ax, 5400h
784		int	13h			; Get diskemu status
785		jc	FindBoot		; If CF=1 no diskemu loaded
786
787		mov	[DriveNumber], cl		; Store drive number
788
789		call	keyflag
790		and	al, 8			; alt key ?
791		jz	extread
792
793		mov	si, DrvNumMsg	; Display "drive number="
794		call	print_string
795		mov	al, [DriveNumber]
796		call	print_hex8
797		mov	si, LineEnd	; CR/LF
798		call	print_string
799		jmp	extread
800
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 ***
806FindBoot:	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
811;		int	13h
812;		jnc	FindPass		;If booted CD found
813;
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
818
819;		cmp	[SpecPkt], 0
820;		jne	FoundBoot
821
822;		cmp	[SpecPkt], 13h	; anything between 13h and 20h should be OK
823;		jb	FindFail
824;		cmp	[SpecPkt], 20h
825;		ja	FindFail
826;		jmp	short FoundBoot
827;
828; FindFail:
829;		dec	dl			;Next drive
830;		cmp	dl, 80h
831;		jae	FindBoot		;Check from ffh..80h
832		; *** end of 1.4 changes ***
833
834		mov	si,NoBootCD	;No booted CD found,
835		call	print_string
836		jmp	NoEndAddr		;Do not install driver
837
838FoundBoot:
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,
842						;  so save Drive #
843
844		call	keyflag
845		and	al, 8			; alt key ?
846		jz	extread
847
848		mov	si, CDStat
849		call	print_string
850		mov	si, SpecPkt	;Point to returned CD SpecPkt
851		mov	cx, 19			;  containing 19 bytes
852StatDump:	mov	al, ' '			;Print a space
853		call	print_char
854		mov	al, byte [si]	;Hexdump a SpecPkt byte
855		call	print_hex8
856		inc	si			;Point to next byte
857		loop	StatDump
858
859		mov	si, LineEnd	;Print a CR/LF
860		call	print_string
861
862extread:
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
873
874		mov	si, SpecPkt	;Set ds:si --> SpecPkt
875		mov	dl, [DriveNumber]
876		mov	ah, 42h			;Extended Read
877		int	13h
878		jnc	SecSize			;If success
879
880		mov	ah, 42h			;Always make 2 read attempts
881		int	13h
882						;How many bytes did we get?
883SecSize:	std				;Count down
884		mov	ax,cs			;Point to end of Buffer
885		mov	es,ax
886		mov	di,Buffer+2047	;Find end of read data
887		mov	si,Buffer+2048
888		mov	cx,2049
889		repe	cmpsb			;cx = number of bytes read
890
891		cld				;Restore count direction to up
892		mov	si,CDBytes	;Display number of bytes read
893		call	print_string
894
895		mov	al, [DriveNumber]
896		call	print_hex8
897
898		mov	si,CDBytesA	;Remainder A of message
899		call	print_string
900
901		mov	al,ch			;Hex-dump cx
902		and	al,0Fh			;Second nibble
903		call	print_hex8		;  (don't need the First)
904		mov	al,cl
905		call	print_hex8		;  (don't need the First)
906
907		mov	si,CDBytesB	;Remainder B of message
908		call	print_string
909
910		cmp	cx,2048			;Did we read 2048 bytes?
911		je	ParseParm		;If yes <-- O.K.
912
913		mov	byte [ReadBytes],1
914		cmp	cx,1024			;Did we read 1024 bytes?
915		je	ParseParm		;If yes <-- O.K.
916
917		mov	byte [ReadBytes],2
918		cmp	cx,512			;Did we read 512 bytes?
919		jne	NoEndAddr		;If not, do not load driver
920
921ParseParm:	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
924		mov	ds,[es:bx+20]
925FindParm:	inc	si
926FindParm1:	cmp	byte [si],0Dh	;CR? (End of parameters)
927		je	EndOfParms
928
929		cmp	byte [si],0Ah	;LF?
930		je	EndOfParms
931
932		cmp	byte [si],'/'	;A parameter?
933		jne	FindParm
934
935		inc	si
936		cmp	byte [si],'D'	;Device Name parameter?
937		jne	FindParm1
938
939		inc	si
940		cmp	byte [si],':'
941		jne	FindParm1
942
943;bbb
944		push	si
945		mov	si, DevName	;Device Name is at ds:si
946		push	ds			;Keep ptr to Device Name
947		mov	ax, cs
948		mov	ds, ax
949		call	print_string
950		pop	ds			;Retrieve Device Name ptr
951		pop	si
952		mov	cx, 8			;Get next 8 chars
953		inc	si			;  = Device Name
954		mov	ax, cs
955		mov	es, ax
956		mov	di, DeviceName
957NextChar:	cmp	byte [si],' '
958		ja	AboveSpace
959
960		mov	ax,cs			;Pad end of Device Name with
961		mov	ds,ax			;  spaces if necessary
962		mov	si,DblSpace	;A space
963AboveSpace:	mov	al, [si]
964		call	print_char
965		movsb				;ds:[si] --> es:[di]
966		loop 	NextChar
967
968		mov	si,LineEnd
969		mov	ax,cs
970		mov	ds,ax
971		call	print_string
972
973		mov	ax,Init-2	;Last byte of driver to keep
974		jmp	EndAddr			;Install driver
975
976EndOfParms:
977		mov	ax, cs			; Restore segment registers (fix)
978		mov	ds, ax
979		mov	es, ax
980
981		mov	si,NoDevName	;No Device Name Found
982		call	print_string
983
984NoEndAddr:	mov	ax,0			;Do not install driver
985
986EndAddr:	mov	es,[ReqHdrLoc+2]		;Write End Address
987		mov	bx,[ReqHdrLoc]
988		mov	[es:bx+14],ax
989		mov	[es:bx+16],cs
990		mov	bx,ax			;Hold onto install status
991
992		mov	si, DrvInst	;Display driver install status
993		call	print_string
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
998DrvStatus:	call	print_string
999
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
1004InitStat:
1005		push	ax			;Save Return Status
1006
1007		call	keyflag
1008		and	al, 8			; alt key ?
1009		jz	InitExit
1010
1011WaitHere:
1012		mov	si, WaitMsg	;Display Halted message
1013		call	print_string
1014
1015AltWait:
1016		call	keyflag
1017		and	al, 8			; Alt key?
1018		jnz	AltWait			; Pressed? yes -> wait
1019
1020InitExit:
1021		pop	ax			;Retrieve Return Status
1022		TRACER 'i'
1023		retn				;That's it for Init!
1024
1025		; *** start 1.4 changes at ded ***
1026SpecGo:		mov	si,SpecPkt
1027		int	13h
1028		retn
1029
1030ScanDrives:	push	ax		; at df3 in 1.4
1031		push	si
1032		mov dl, 7fh		;Start at Drive 0x80
1033NextDrv:	inc	dl
1034		clc
1035		mov	ax,4B01h	;Get Bootable CD-ROM Status
1036		mov	BYTE [SpecPkt],0	;Clear 1st byte of SpecPkt
1037		call	SpecGo
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
1042
1043		cmp	BYTE [SpecPkt], 13h	; anything between 13h and 20h should be OK
1044		jb	FindFail
1045		cmp	BYTE [SpecPkt], 20h
1046		ja	FindFail	; in 1.4 at e16
1047		jmp	short SendFound	; in 1.4 at e26
1048
1049FindFail:	cmp	dl, 0ffh
1050		je	SendFail		; Check from 80h..ffh
1051		jmp	short NextDrv		;Next drive
1052SendFail:	xor	dl,dl
1053		stc
1054		jmp	short ThingDone
1055SendFound:	mov	dl, [SpecPkt+2]
1056		clc
1057ThingDone:	pop	si
1058		pop	ax
1059		retn
1060		; *** end 1.4 changes ***
1061
1062;=============================================================================
1063
1064;------------------------------------------------------------
1065; keyboard flags - return keyboard flags in AL
1066; bit 3 = ALT key
1067keyflag:	; at dbc in 1.3, at e2e in 1.4
1068	push	bx
1069	mov	ah, 2
1070	int	16h
1071	pop	bx
1072	retn
1073
1074;=============================================================================
1075
1076DrvNumMsg	db	'  Diskemxx.bin returned drive number=', 0
1077NoBootCD	db	'  No booted CD-ROM found.',CR,0
1078
1079CDStat		db	'  INT 13h / AX=4B01h Specification Packet for '
1080		db	'Booted CD-ROM:',CR,'     ', 0
1081
1082CDBytes		db	'  Drive ', 0
1083CDBytesA	db	' returns ', 0
1084CDBytesB	db	'h bytes per Sector.',CR,0
1085
1086DevName		db	'  Device Name: ', 0
1087NoDevName	db	'  No Device Name found. '
1088		db	'Usage: device=eltorito.sys /D:<DevName>',CR,0
1089
1090DrvInst		db	'  Driver ', 0
1091NoDrvInst	db	7,'not '		;7 = Ctrl-G = Beep
1092DrvInst1	db	'installed',CR,0
1093
1094WaitMsg		db	'  Alt pressed, waiting...', CR, 0
1095;ContMsg		db	'  Continuing...'
1096LineEnd		db	CR,0
1097
1098
1099;=============================================================================
1100