Fix a couple of problems with FreeLDR portability.
[reactos.git] / reactos / boot / freeldr / bootsect / isoboot.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 ; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.
34 ;%define DEBUG_MESSAGES ; Uncomment to get debugging messages
35
36 %define WAIT_FOR_KEY
37
38
39 ; ---------------------------------------------------------------------------
40 ; BEGIN THE BIOS/CODE/DATA SEGMENT
41 ; ---------------------------------------------------------------------------
42
43 absolute 0400h
44 serial_base resw 4 ; Base addresses for 4 serial ports
45 absolute 0413h
46 BIOS_fbm resw 1 ; Free Base Memory (kilobytes)
47 absolute 046Ch
48 BIOS_timer resw 1 ; Timer ticks
49 absolute 0472h
50 BIOS_magic resw 1 ; BIOS reset magic
51 absolute 0484h
52 BIOS_vidrows resb 1 ; Number of screen rows
53
54 ;
55 ; Memory below this point is reserved for the BIOS and the MBR
56 ;
57 absolute 1000h
58 trackbuf resb 8192 ; Track buffer goes here
59 trackbufsize equ $-trackbuf
60 ; trackbuf ends at 3000h
61
62 struc open_file_t
63 file_sector resd 1 ; Sector pointer (0 = structure free)
64 file_left resd 1 ; Number of sectors left
65 endstruc
66
67 struc dir_t
68 dir_lba resd 1 ; Directory start (LBA)
69 dir_len resd 1 ; Length in bytes
70 dir_clust resd 1 ; Length in clusters
71 endstruc
72
73
74 MAX_OPEN_LG2 equ 2 ; log2(Max number of open files)
75 MAX_OPEN equ (1 << MAX_OPEN_LG2)
76 SECTORSIZE_LG2 equ 11 ; 2048 bytes/sector (El Torito requirement)
77 SECTORSIZE equ (1 << SECTORSIZE_LG2)
78 CR equ 13 ; Carriage Return
79 LF equ 10 ; Line Feed
80 retry_count equ 6 ; How patient are we with the BIOS?
81
82
83
84 absolute 5000h ; Here we keep our BSS stuff
85
86 DriveNo resb 1 ; CD-ROM BIOS drive number
87 DiskError resb 1 ; Error code for disk I/O
88 RetryCount resb 1 ; Used for disk access retries
89 TimeoutCount resb 1 ; Timeout counter
90 ISOFlags resb 1 ; Flags for ISO directory search
91 RootDir resb dir_t_size ; Root directory
92 CurDir resb dir_t_size ; Current directory
93 ISOFileName resb 64 ; ISO filename canonicalization buffer
94 ISOFileNameEnd equ $
95
96
97 alignb open_file_t_size
98 Files resb MAX_OPEN*open_file_t_size
99
100
101
102 section .text
103 org 7000h
104
105 start:
106 cli ; Disable interrupts
107 xor ax, ax ; ax = segment zero
108 mov ss, ax ; Initialize stack segment
109 mov sp, start ; Set up stack
110 mov ds, ax ; Initialize other segment registers
111 mov es, ax
112 mov fs, ax
113 mov gs, ax
114 sti ; Enable interrupts
115 cld ; Increment pointers
116
117 mov cx, 2048 >> 2 ; Copy the bootsector
118 mov si, 0x7C00 ; from 0000:7C00
119 mov di, 0x7000 ; to 0000:7000
120 rep movsd ; copy the program
121 jmp 0:relocate ; jump into relocated code
122
123 relocate:
124 ; Display the banner and copyright
125 %ifdef DEBUG_MESSAGES
126 mov si, isolinux_banner ; si points to hello message
127 call writestr ; display the message
128 mov si,copyright_str
129 call writestr
130 %endif
131
132
133 ; Make sure the keyboard buffer is empty
134 %ifdef WAIT_FOR_KEY
135 .kbd_buffer_test:
136 call pollchar
137 jz .kbd_buffer_empty
138 call getchar
139 jmp .kbd_buffer_test
140 .kbd_buffer_empty:
141
142 ; Check for MBR on harddisk
143 pusha
144 mov ax, 0201h
145 mov dx, 0080h
146 mov cx, 0001h
147 mov bx, trackbuf
148 int 13h
149 popa
150 jc .boot_cdrom ; could not read hdd
151
152 push ax
153 mov ax, word [trackbuf]
154 cmp ax, 0
155 je .boot_cdrom ; no boot sector found (hopefully there are no weird bootsectors which begin with 0)
156 pop ax
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