118863400fb8336f7c80dd8cedd43c2621ed383e
[reactos.git] / reactos / boot / freeldr / bootsect / isobtrt.asm
1 ; ****************************************************************************
2 ;
3 ; isolinux.asm
4 ;
5 ; A program to boot Linux kernels off a CD-ROM using the El Torito
6 ; boot standard in "no emulation" mode, making the entire filesystem
7 ; available. It is based on the SYSLINUX boot loader for MS-DOS
8 ; floppies.
9 ;
10 ; Copyright (C) 1994-2001 H. Peter Anvin
11 ;
12 ; This program is free software; you can redistribute it and/or modify
13 ; it under the terms of the GNU General Public License as published by
14 ; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
15 ; USA; either version 2 of the License, or (at your option) any later
16 ; version; incorporated herein by reference.
17 ;
18 ; ****************************************************************************
19 ;
20 ; THIS FILE IS A MODIFIED VERSION OF ISOLINUX.ASM
21 ; MODIFICATION DONE BY MICHAEL K TER LOUW
22 ; LAST UPDATED 3-9-2002
23 ; SEE "COPYING" FOR INFORMATION ABOUT THE LICENSE THAT APPLIES TO THIS RELEASE
24 ;
25 ; ****************************************************************************
26 ;
27 ; This file is a modified version of ISOLINUX.ASM.
28 ; Modification done by Eric Kohl
29 ; Last update 04-25-2002
30 ;
31 ; ****************************************************************************
32 ;
33 ; This file is a modified version of ISOLINUX.ASM.
34 ; (for ReactOS regression testing)
35 ; Modification done by Christoph von Wittich
36 ; Last update 08-27-2006
37 ;
38 ; ****************************************************************************
39
40
41 ; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.
42 ;%define DEBUG_MESSAGES ; Uncomment to get debugging messages
43
44 %define WAIT_FOR_KEY
45
46
47 ; ---------------------------------------------------------------------------
48 ; BEGIN THE BIOS/CODE/DATA SEGMENT
49 ; ---------------------------------------------------------------------------
50
51 absolute 0400h
52 serial_base resw 4 ; Base addresses for 4 serial ports
53 absolute 0413h
54 BIOS_fbm resw 1 ; Free Base Memory (kilobytes)
55 absolute 046Ch
56 BIOS_timer resw 1 ; Timer ticks
57 absolute 0472h
58 BIOS_magic resw 1 ; BIOS reset magic
59 absolute 0484h
60 BIOS_vidrows resb 1 ; Number of screen rows
61
62 ;
63 ; Memory below this point is reserved for the BIOS and the MBR
64 ;
65 absolute 1000h
66 trackbuf resb 8192 ; Track buffer goes here
67 trackbufsize equ $-trackbuf
68 ; trackbuf ends at 3000h
69
70 struc open_file_t
71 file_sector resd 1 ; Sector pointer (0 = structure free)
72 file_left resd 1 ; Number of sectors left
73 endstruc
74
75 struc dir_t
76 dir_lba resd 1 ; Directory start (LBA)
77 dir_len resd 1 ; Length in bytes
78 dir_clust resd 1 ; Length in clusters
79 endstruc
80
81
82 MAX_OPEN_LG2 equ 2 ; log2(Max number of open files)
83 MAX_OPEN equ (1 << MAX_OPEN_LG2)
84 SECTORSIZE_LG2 equ 11 ; 2048 bytes/sector (El Torito requirement)
85 SECTORSIZE equ (1 << SECTORSIZE_LG2)
86 CR equ 13 ; Carriage Return
87 LF equ 10 ; Line Feed
88 retry_count equ 6 ; How patient are we with the BIOS?
89
90
91
92 absolute 5000h ; Here we keep our BSS stuff
93
94 DriveNo resb 1 ; CD-ROM BIOS drive number
95 DiskError resb 1 ; Error code for disk I/O
96 RetryCount resb 1 ; Used for disk access retries
97 TimeoutCount resb 1 ; Timeout counter
98 ISOFlags resb 1 ; Flags for ISO directory search
99 RootDir resb dir_t_size ; Root directory
100 CurDir resb dir_t_size ; Current directory
101 ISOFileName resb 64 ; ISO filename canonicalization buffer
102 ISOFileNameEnd equ $
103
104
105 alignb open_file_t_size
106 Files resb MAX_OPEN*open_file_t_size
107
108
109
110 section .text
111 org 7000h
112
113 start:
114 cli ; Disable interrupts
115 xor ax, ax ; ax = segment zero
116 mov ss, ax ; Initialize stack segment
117 mov sp, start ; Set up stack
118 mov ds, ax ; Initialize other segment registers
119 mov es, ax
120 mov fs, ax
121 mov gs, ax
122 sti ; Enable interrupts
123 cld ; Increment pointers
124
125 mov cx, 2048 >> 2 ; Copy the bootsector
126 mov si, 0x7C00 ; from 0000:7C00
127 mov di, 0x7000 ; to 0000:7000
128 rep movsd ; copy the program
129 jmp 0:relocate ; jump into relocated code
130
131 relocate:
132 ; Display the banner and copyright
133 %ifdef DEBUG_MESSAGES
134 mov si, isolinux_banner ; si points to hello message
135 call writestr ; display the message
136 mov si,copyright_str
137 call writestr
138 %endif
139
140
141 ; Make sure the keyboard buffer is empty
142 %ifdef WAIT_FOR_KEY
143 .kbd_buffer_test:
144 call pollchar
145 jz .kbd_buffer_empty
146 call getchar
147 jmp .kbd_buffer_test
148 .kbd_buffer_empty:
149
150 ; Check if there is harddisk
151 pusha
152 mov ax, 0800h
153 mov dx, 0080h
154 int 13h
155 popa
156 jmp .boot_cdrom
157
158 ; Display the 'Press key' message and wait for a maximum of 5 seconds
159 call crlf
160 mov si, presskey_msg ; si points to 'Press key' message
161 call writestr ; display the message
162
163 mov byte [TimeoutCount], 5
164 .next_second:
165 mov eax, [BIOS_timer] ; load current tick counter
166 add eax, 19 ;
167
168 .poll_again:
169 call pollchar
170 jnz .boot_cdrom
171
172 mov ebx, [BIOS_timer]
173 cmp eax, ebx
174 jnz .poll_again
175
176 mov si, dot_msg ; print '.'
177 call writestr
178 dec byte [TimeoutCount] ; decrement timeout counter
179 jz .boot_harddisk
180 jmp .next_second
181
182 .boot_harddisk:
183 call crlf
184
185 ; Boot first harddisk (drive 0x80)
186 mov ax, 0201h
187 mov dx, 0080h
188 mov cx, 0001h
189 mov bx, 7C00h
190 int 13h
191 jnc .go_hd
192 jmp kaboom
193 .go_hd:
194 mov ax, cs
195 mov ds, ax
196 mov es, ax
197 mov fs, ax
198 mov gs, ax
199 mov dx, 0080h
200
201 jmp 0:0x7C00
202 %endif
203
204 .boot_cdrom:
205 %ifdef WAIT_FOR_KEY
206 call crlf
207 call crlf
208 %endif
209
210 ; Save and display the boot drive number
211 mov [DriveNo], dl
212 %ifdef DEBUG_MESSAGES
213 mov si, startup_msg
214 call writemsg
215 mov al, dl
216 call writehex2
217 call crlf
218 %endif
219
220 ; Now figure out what we're actually doing
221 ; Note: use passed-in DL value rather than 7Fh because
222 ; at least some BIOSes will get the wrong value otherwise
223 mov ax, 4B01h ; Get disk emulation status
224 mov dl, [DriveNo]
225 mov si, spec_packet
226 int 13h
227 jc near spec_query_failed ; Shouldn't happen (BIOS bug)
228 mov dl, [DriveNo]
229 cmp [sp_drive], dl ; Should contain the drive number
230 jne near spec_query_failed
231
232 %ifdef DEBUG_MESSAGES
233 mov si, spec_ok_msg
234 call writemsg
235 mov al, byte [sp_drive]
236 call writehex2
237 call crlf
238 %endif
239
240 found_drive:
241 ; Get drive information
242 mov ah, 48h
243 mov dl, [DriveNo]
244 mov si, drive_params
245 int 13h
246 jnc params_ok
247
248 ; mov si, nosecsize_msg No use in reporting this
249 ; call writemsg
250
251 params_ok:
252 ; Check for the sector size (should be 2048, but
253 ; some BIOSes apparently think we're 512-byte media)
254 ;
255 ; FIX: We need to check what the proper behaviour
256 ; is for getlinsec when the BIOS thinks the sector
257 ; size is 512!!! For that, we need such a BIOS, though...
258 %ifdef DEBUG_MESSAGES
259 mov si, secsize_msg
260 call writemsg
261 mov ax, [dp_secsize]
262 call writehex4
263 call crlf
264 %endif
265
266
267 ;
268 ; Clear Files structures
269 ;
270 mov di, Files
271 mov cx, (MAX_OPEN*open_file_t_size)/4
272 xor eax, eax
273 rep stosd
274
275 ;
276 ; Now, we need to sniff out the actual filesystem data structures.
277 ; mkisofs gave us a pointer to the primary volume descriptor
278 ; (which will be at 16 only for a single-session disk!); from the PVD
279 ; we should be able to find the rest of what we need to know.
280 ;
281 get_fs_structures:
282 mov eax, 16 ; Primary Volume Descriptor (sector 16)
283 mov bx, trackbuf
284 call getonesec
285
286 mov eax, [trackbuf+156+2]
287 mov [RootDir+dir_lba],eax
288 mov [CurDir+dir_lba],eax
289 %ifdef DEBUG_MESSAGES
290 mov si, rootloc_msg
291 call writemsg
292 call writehex8
293 call crlf
294 %endif
295
296 mov eax,[trackbuf+156+10]
297 mov [RootDir+dir_len],eax
298 mov [CurDir+dir_len],eax
299 %ifdef DEBUG_MESSAGES
300 mov si, rootlen_msg
301 call writemsg
302 call writehex8
303 call crlf
304 %endif
305 add eax,SECTORSIZE-1
306 shr eax,SECTORSIZE_LG2
307 mov [RootDir+dir_clust],eax
308 mov [CurDir+dir_clust],eax
309 %ifdef DEBUG_MESSAGES
310 mov si, rootsect_msg
311 call writemsg
312 call writehex8
313 call crlf
314 %endif
315
316 ; Look for the "REACTOS" directory, and if found,
317 ; make it the current directory instead of the root
318 ; directory.
319 mov di,isolinux_dir
320 mov al,02h ; Search for a directory
321 call searchdir_iso
322 jnz .dir_found
323 mov si,no_dir_msg
324 call writemsg
325 jmp kaboom
326
327 .dir_found:
328 mov [CurDir+dir_len],eax
329 mov eax,[si+file_left]
330 mov [CurDir+dir_clust],eax
331 xor eax,eax ; Free this file pointer entry
332 xchg eax,[si+file_sector]
333 mov [CurDir+dir_lba],eax
334
335
336 mov di, isolinux_bin ; di points to Isolinux filename
337 call searchdir ; look for the file
338 jnz .isolinux_opened ; got the file
339 mov si, no_isolinux_msg ; si points to error message
340 call writemsg ; display the message
341 jmp kaboom ; fail boot
342
343 .isolinux_opened:
344 mov di, si ; save file pointer
345
346 %ifdef DEBUG_MESSAGES
347 mov si, filelen_msg
348 call writemsg
349 call writehex8
350 call crlf
351 %endif
352
353 mov ecx, eax ; calculate sector count
354 shr ecx, 11
355 test eax, 0x7FF
356 jz .full_sector
357 inc ecx
358 .full_sector:
359
360 %ifdef DEBUG_MESSAGES
361 mov eax, ecx
362 mov si, filesect_msg
363 call writemsg
364 call writehex8
365 call crlf
366 %endif
367
368 mov bx, 0x8000 ; bx = load address
369 mov si, di ; restore file pointer
370 mov cx, 0xFFFF ; load the whole file
371 call getfssec ; get the whole file
372
373 %ifdef DEBUG_MESSAGES
374 mov si, startldr_msg
375 call writemsg
376 call crlf
377 %endif
378
379 mov dl, [DriveNo] ; dl = boot drive
380 mov dh, 0 ; dh = boot partition
381 jmp 0:0x8000 ; jump into OSLoader
382
383
384
385 ;
386 ; searchdir:
387 ;
388 ; Open a file
389 ;
390 ; On entry:
391 ; DS:DI = filename
392 ; If successful:
393 ; ZF clear
394 ; SI = file pointer
395 ; DX:AX or EAX = file length in bytes
396 ; If unsuccessful
397 ; ZF set
398 ;
399
400 ;
401 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
402 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
403 ; for searching for directories.
404 ;
405 alloc_failure:
406 xor ax,ax ; ZF <- 1
407 ret
408
409 searchdir:
410 xor al,al
411 searchdir_iso:
412 mov [ISOFlags],al
413 call allocate_file ; Temporary file structure for directory
414 jnz alloc_failure
415 push es
416 push ds
417 pop es ; ES = DS
418 mov si,CurDir
419 cmp byte [di],'\' ; If filename begins with slash
420 jne .not_rooted
421 inc di ; Skip leading slash
422 mov si,RootDir ; Reference root directory instead
423 .not_rooted:
424 mov eax,[si+dir_clust]
425 mov [bx+file_left],eax
426 mov eax,[si+dir_lba]
427 mov [bx+file_sector],eax
428 mov edx,[si+dir_len]
429
430 .look_for_slash:
431 mov ax,di
432 .scan:
433 mov cl,[di]
434 inc di
435 and cl,cl
436 jz .isfile
437 cmp cl,'\'
438 jne .scan
439 mov [di-1],byte 0 ; Terminate at directory name
440 mov cl,02h ; Search for directory
441 xchg cl,[ISOFlags]
442 push di
443 push cx
444 push word .resume ; Where to "return" to
445 push es
446 .isfile:
447 xchg ax,di
448
449 .getsome:
450 ; Get a chunk of the directory
451 mov si,trackbuf
452 pushad
453 xchg bx,si
454 mov cx,1 ; load one sector
455 call getfssec
456 popad
457
458 .compare:
459 movzx eax, byte [si] ; Length of directory entry
460 cmp al, 33
461 jb .next_sector
462 mov cl, [si+25]
463 xor cl, [ISOFlags]
464 test cl, byte 8Eh ; Unwanted file attributes!
465 jnz .not_file
466 pusha
467 movzx cx, byte [si+32] ; File identifier length
468 add si, byte 33 ; File identifier offset
469 call iso_compare_names
470 popa
471 je .success
472 .not_file:
473 sub edx, eax ; Decrease bytes left
474 jbe .failure
475 add si, ax ; Advance pointer
476
477 .check_overrun:
478 ; Did we finish the buffer?
479 cmp si, trackbuf+trackbufsize
480 jb .compare ; No, keep going
481
482 jmp short .getsome ; Get some more directory
483
484 .next_sector:
485 ; Advance to the beginning of next sector
486 lea ax, [si+SECTORSIZE-1]
487 and ax, ~(SECTORSIZE-1)
488 sub ax, si
489 jmp short .not_file ; We still need to do length checks
490
491 .failure:
492 %ifdef DEBUG_MESSAGES
493 mov si, findfail_msg
494 call writemsg
495 call crlf
496 %endif
497 xor eax, eax ; ZF = 1
498 mov [bx+file_sector], eax
499 pop es
500 ret
501
502 .success:
503 mov eax, [si+2] ; Location of extent
504 mov [bx+file_sector], eax
505 mov eax, [si+10] ; Data length
506 push eax
507 add eax, SECTORSIZE-1
508 shr eax, SECTORSIZE_LG2
509 mov [bx+file_left], eax
510 pop eax
511 mov edx, eax
512 shr edx, 16
513 and bx, bx ; ZF = 0
514 mov si, bx
515 pop es
516 ret
517
518 .resume:
519 ; We get here if we were only doing part of a lookup
520 ; This relies on the fact that .success returns bx == si
521 xchg edx, eax ; Directory length in edx
522 pop cx ; Old ISOFlags
523 pop di ; Next filename pointer
524
525 mov byte [di-1], '\' ; restore the backslash in the filename
526
527 mov [ISOFlags], cl ; Restore the flags
528 jz .failure ; Did we fail? If so fail for real!
529 jmp .look_for_slash ; Otherwise, next level
530
531 ;
532 ; allocate_file: Allocate a file structure
533 ;
534 ; If successful:
535 ; ZF set
536 ; BX = file pointer
537 ; In unsuccessful:
538 ; ZF clear
539 ;
540 allocate_file:
541 push cx
542 mov bx, Files
543 mov cx, MAX_OPEN
544 .check:
545 cmp dword [bx], byte 0
546 je .found
547 add bx, open_file_t_size ; ZF = 0
548 loop .check
549 ; ZF = 0 if we fell out of the loop
550 .found:
551 pop cx
552 ret
553
554 ;
555 ; iso_compare_names:
556 ; Compare the names DS:SI and DS:DI and report if they are
557 ; equal from an ISO 9660 perspective. SI is the name from
558 ; the filesystem; CX indicates its length, and ';' terminates.
559 ; DI is expected to end with a null.
560 ;
561 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
562 ;
563 iso_compare_names:
564 ; First, terminate and canonicalize input filename
565 push di
566 mov di, ISOFileName
567 .canon_loop:
568 jcxz .canon_end
569 lodsb
570 dec cx
571 cmp al, ';'
572 je .canon_end
573 and al, al
574 je .canon_end
575 stosb
576 cmp di, ISOFileNameEnd-1 ; Guard against buffer overrun
577 jb .canon_loop
578 .canon_end:
579 cmp di, ISOFileName
580 jbe .canon_done
581 cmp byte [di-1], '.' ; Remove terminal dots
582 jne .canon_done
583 dec di
584 jmp short .canon_end
585 .canon_done:
586 mov [di], byte 0 ; Null-terminate string
587 pop di
588 mov si, ISOFileName
589 .compare:
590 lodsb
591 mov ah, [di]
592 inc di
593 and ax, ax
594 jz .success ; End of string for both
595 and al, al ; Is either one end of string?
596 jz .failure ; If so, failure
597 and ah, ah
598 jz .failure
599 or ax, 2020h ; Convert to lower case
600 cmp al, ah
601 je .compare
602 .failure:
603 and ax, ax ; ZF = 0 (at least one will be nonzero)
604 .success:
605 ret
606
607
608
609
610
611
612
613 ;
614 ; getfssec: Get multiple clusters from a file, given the file pointer.
615 ;
616 ; On entry:
617 ; ES:BX -> Buffer
618 ; SI -> File pointer
619 ; CX -> Cluster count; 0FFFFh = until end of file
620 ; On exit:
621 ; SI -> File pointer (or 0 on EOF)
622 ; CF = 1 -> Hit EOF
623 ;
624 getfssec:
625 cmp cx, [si+file_left]
626 jna .ok_size
627 mov cx, [si+file_left]
628
629 .ok_size:
630 mov bp, cx
631 push cx
632 push si
633 mov eax, [si+file_sector]
634 call getlinsec
635 xor ecx, ecx
636 pop si
637 pop cx
638
639 add [si+file_sector], ecx
640 sub [si+file_left], ecx
641 ja .not_eof ; CF = 0
642
643 xor ecx, ecx
644 mov [si+file_sector], ecx ; Mark as unused
645 xor si,si
646 stc
647
648 .not_eof:
649 ret
650
651
652
653 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
654 ; Try to scan the entire 80h-FFh from the end.
655 spec_query_failed:
656 mov si,spec_err_msg
657 call writemsg
658
659 mov dl, 0FFh
660 .test_loop:
661 pusha
662 mov ax, 4B01h
663 mov si, spec_packet
664 mov byte [si], 13 ; Size of buffer
665 int 13h
666 popa
667 jc .still_broken
668
669 mov si, maybe_msg
670 call writemsg
671 mov al, dl
672 call writehex2
673 call crlf
674
675 cmp byte [sp_drive], dl
676 jne .maybe_broken
677
678 ; Okay, good enough...
679 mov si, alright_msg
680 call writemsg
681 mov [DriveNo], dl
682 .found_drive:
683 jmp found_drive
684
685 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
686 ; but if this was the drive number originally passed in
687 ; DL then consider it "good enough"
688 .maybe_broken:
689 cmp byte [DriveNo], dl
690 je .found_drive
691
692 .still_broken:
693 dec dx
694 cmp dl, 80h
695 jnb .test_loop
696
697 fatal_error:
698 mov si, nothing_msg
699 call writemsg
700
701 .norge:
702 jmp short .norge
703
704
705
706 ; Information message (DS:SI) output
707 ; Prefix with "isolinux: "
708 ;
709 writemsg:
710 push ax
711 push si
712 mov si, isolinux_str
713 call writestr
714 pop si
715 call writestr
716 pop ax
717 ret
718
719 ;
720 ; crlf: Print a newline
721 ;
722 crlf:
723 mov si, crlf_msg
724 ; Fall through
725
726 ;
727 ; writestr: write a null-terminated string to the console, saving
728 ; registers on entry.
729 ;
730 writestr:
731 pushfd
732 pushad
733 .top:
734 lodsb
735 and al, al
736 jz .end
737 call writechr
738 jmp short .top
739 .end:
740 popad
741 popfd
742 ret
743
744
745 ;
746 ; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
747 ;
748 writehex2:
749 pushfd
750 pushad
751 shl eax, 24
752 mov cx, 2
753 jmp short writehex_common
754 writehex4:
755 pushfd
756 pushad
757 shl eax, 16
758 mov cx, 4
759 jmp short writehex_common
760 writehex8:
761 pushfd
762 pushad
763 mov cx, 8
764 writehex_common:
765 .loop:
766 rol eax, 4
767 push eax
768 and al, 0Fh
769 cmp al, 10
770 jae .high
771 .low:
772 add al, '0'
773 jmp short .ischar
774 .high:
775 add al, 'A'-10
776 .ischar:
777 call writechr
778 pop eax
779 loop .loop
780 popad
781 popfd
782 ret
783
784 ;
785 ; Write a character to the screen. There is a more "sophisticated"
786 ; version of this in the subsequent code, so we patch the pointer
787 ; when appropriate.
788 ;
789
790 writechr:
791 pushfd
792 pushad
793 mov ah, 0Eh
794 xor bx, bx
795 int 10h
796 popad
797 popfd
798 ret
799
800 ;
801 ; Get one sector. Convenience entry point.
802 ;
803 getonesec:
804 mov bp, 1
805 ; Fall through to getlinsec
806
807 ;
808 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
809 ;
810 ; Note that we can't always do this as a single request, because at least
811 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
812 ; to 32 sectors (64K) per request.
813 ;
814 ; Input:
815 ; EAX - Linear sector number
816 ; ES:BX - Target buffer
817 ; BP - Sector count
818 ;
819 getlinsec:
820 mov si,dapa ; Load up the DAPA
821 mov [si+4],bx
822 mov bx,es
823 mov [si+6],bx
824 mov [si+8],eax
825 .loop2:
826 push bp ; Sectors left
827 cmp bp,[MaxTransfer]
828 jbe .bp_ok
829 mov bp,[MaxTransfer]
830 .bp_ok:
831 mov [si+2],bp
832 push si
833 mov dl,[DriveNo]
834 mov ah,42h ; Extended Read
835 call xint13
836 pop si
837 pop bp
838 movzx eax,word [si+2] ; Sectors we read
839 add [si+8],eax ; Advance sector pointer
840 sub bp,ax ; Sectors left
841 shl ax,SECTORSIZE_LG2-4 ; 2048-byte sectors -> segment
842 add [si+6],ax ; Advance buffer pointer
843 and bp,bp
844 jnz .loop2
845 mov eax,[si+8] ; Next sector
846 ret
847
848 ; INT 13h with retry
849 xint13:
850 mov byte [RetryCount], retry_count
851 .try:
852 pushad
853 int 13h
854 jc .error
855 add sp, byte 8*4 ; Clean up stack
856 ret
857 .error:
858 mov [DiskError], ah ; Save error code
859 popad
860 dec byte [RetryCount]
861 jz .real_error
862 push ax
863 mov al,[RetryCount]
864 mov ah,[dapa+2] ; Sector transfer count
865 cmp al,2 ; Only 2 attempts left
866 ja .nodanger
867 mov ah,1 ; Drop transfer size to 1
868 jmp short .setsize
869 .nodanger:
870 cmp al,retry_count-2
871 ja .again ; First time, just try again
872 shr ah,1 ; Otherwise, try to reduce
873 adc ah,0 ; the max transfer size, but not to 0
874 .setsize:
875 mov [MaxTransfer],ah
876 mov [dapa+2],ah
877 .again:
878 pop ax
879 jmp .try
880
881 .real_error:
882 mov si, diskerr_msg
883 call writemsg
884 mov al, [DiskError]
885 call writehex2
886 mov si, ondrive_str
887 call writestr
888 mov al, dl
889 call writehex2
890 call crlf
891 ; Fall through to kaboom
892
893 ;
894 ; kaboom: write a message and bail out. Wait for a user keypress,
895 ; then do a hard reboot.
896 ;
897 kaboom:
898 mov ax, cs
899 mov ds, ax
900 mov es, ax
901 mov fs, ax
902 mov gs, ax
903 sti
904 mov si, err_bootfailed
905 call writestr
906 call getchar
907 cli
908 mov word [BIOS_magic], 0 ; Cold reboot
909 jmp 0F000h:0FFF0h ; Reset vector address
910
911 getchar:
912 .again:
913 mov ah, 1 ; Poll keyboard
914 int 16h
915 jz .again
916 .kbd:
917 xor ax, ax ; Get keyboard input
918 int 16h
919 .func_key:
920 ret
921
922
923 ;
924 ; pollchar: check if we have an input character pending (ZF = 0)
925 ;
926 pollchar:
927 pushad
928 mov ah,1 ; Poll keyboard
929 int 16h
930 popad
931 ret
932
933
934
935 isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0
936 copyright_str db ' Copyright (C) 1994-2002 H. Peter Anvin', CR, LF, 0
937 presskey_msg db 'Press any key to boot from CD', 0
938 dot_msg db '.',0
939
940 %ifdef DEBUG_MESSAGES
941 startup_msg: db 'Starting up, DL = ', 0
942 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
943 secsize_msg: db 'Sector size appears to be ', 0
944 rootloc_msg: db 'Root directory location: ', 0
945 rootlen_msg: db 'Root directory length: ', 0
946 rootsect_msg: db 'Root directory length(sectors): ', 0
947 fileloc_msg: db 'SETUPLDR.SYS location: ', 0
948 filelen_msg: db 'SETUPLDR.SYS length: ', 0
949 filesect_msg: db 'SETUPLDR.SYS length(sectors): ', 0
950 findfail_msg: db 'Failed to find file!', 0
951 startldr_msg: db 'Starting SETUPLDR.SYS', 0
952 %endif
953
954 nosecsize_msg: db 'Failed to get sector size, assuming 0800', CR, LF, 0
955 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
956 maybe_msg: db 'Found something at drive = ', 0
957 alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0
958 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF, 0
959 isolinux_str db 'IsoBoot: ', 0
960 crlf_msg db CR, LF, 0
961 diskerr_msg: db 'Disk error ', 0
962 ondrive_str: db ', drive ', 0
963 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
964 isolinux_dir db '\LOADER', 0
965 no_dir_msg db 'Could not find the LOADER directory.', CR, LF, 0
966 isolinux_bin db 'SETUPLDR.SYS', 0
967 no_isolinux_msg db 'Could not find SETUPLDR.SYS.', CR, LF, 0
968
969 ;
970 ; El Torito spec packet
971 ;
972 align 8, db 0
973 spec_packet: db 13h ; Size of packet
974 sp_media: db 0 ; Media type
975 sp_drive: db 0 ; Drive number
976 sp_controller: db 0 ; Controller index
977 sp_lba: dd 0 ; LBA for emulated disk image
978 sp_devspec: dw 0 ; IDE/SCSI information
979 sp_buffer: dw 0 ; User-provided buffer
980 sp_loadseg: dw 0 ; Load segment
981 sp_sectors: dw 0 ; Sector count
982 sp_chs: db 0,0,0 ; Simulated CHS geometry
983 sp_dummy: db 0 ; Scratch, safe to overwrite
984
985 ;
986 ; EBIOS drive parameter packet
987 ;
988 align 8, db 0
989 drive_params: dw 30 ; Buffer size
990 dp_flags: dw 0 ; Information flags
991 dp_cyl: dd 0 ; Physical cylinders
992 dp_head: dd 0 ; Physical heads
993 dp_sec: dd 0 ; Physical sectors/track
994 dp_totalsec: dd 0,0 ; Total sectors
995 dp_secsize: dw 0 ; Bytes per sector
996 dp_dpte: dd 0 ; Device Parameter Table
997 dp_dpi_key: dw 0 ; 0BEDDh if rest valid
998 dp_dpi_len: db 0 ; DPI len
999 db 0
1000 dw 0
1001 dp_bus: times 4 db 0 ; Host bus type
1002 dp_interface: times 8 db 0 ; Interface type
1003 db_i_path: dd 0,0 ; Interface path
1004 db_d_path: dd 0,0 ; Device path
1005 db 0
1006 db_dpi_csum: db 0 ; Checksum for DPI info
1007
1008 ;
1009 ; EBIOS disk address packet
1010 ;
1011 align 8, db 0
1012 dapa: dw 16 ; Packet size
1013 .count: dw 0 ; Block count
1014 .off: dw 0 ; Offset of buffer
1015 .seg: dw 0 ; Segment of buffer
1016 .lba: dd 0 ; LBA (LSW)
1017 dd 0 ; LBA (MSW)
1018
1019 alignb 4, db 0
1020 MaxTransfer dw 2 ;32 ; Max sectors per transfer
1021
1022 times 2046-($-$$) db 0 ; Pad to file offset 2046
1023 dw 0aa55h ; BootSector signature