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