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