[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 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 mov bx, 0x8000 ; bx = load address
364 mov si, di ; restore file pointer
365 mov cx, 0xFFFF ; load the whole file
366 call getfssec ; get the whole file
367
368 %ifdef DEBUG_MESSAGES
369 mov si, startldr_msg
370 call writemsg
371 call crlf
372 %endif
373
374 mov dl, [DriveNo] ; dl = boot drive
375 mov dh, 0 ; dh = boot partition
376 push 0 ; push segment (0x0000)
377 mov eax, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
378 add eax, 0x8000 ; RVA -> VA
379 push ax ; push offset
380 retf ; Transfer control to ROSLDR
381
382
383
384 ;
385 ; searchdir:
386 ;
387 ; Open a file
388 ;
389 ; On entry:
390 ; DS:DI = filename
391 ; If successful:
392 ; ZF clear
393 ; SI = file pointer
394 ; DX:AX or EAX = file length in bytes
395 ; If unsuccessful
396 ; ZF set
397 ;
398
399 ;
400 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
401 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
402 ; for searching for directories.
403 ;
404 alloc_failure:
405 xor ax,ax ; ZF <- 1
406 ret
407
408 searchdir:
409 xor al,al
410 searchdir_iso:
411 mov [ISOFlags],al
412 call allocate_file ; Temporary file structure for directory
413 jnz alloc_failure
414 push es
415 push ds
416 pop es ; ES = DS
417 mov si,CurDir
418 cmp byte [di],'\' ; If filename begins with slash
419 jne .not_rooted
420 inc di ; Skip leading slash
421 mov si,RootDir ; Reference root directory instead
422 .not_rooted:
423 mov eax,[si+dir_clust]
424 mov [bx+file_left],eax
425 mov eax,[si+dir_lba]
426 mov [bx+file_sector],eax
427 mov edx,[si+dir_len]
428
429 .look_for_slash:
430 mov ax,di
431 .scan:
432 mov cl,[di]
433 inc di
434 and cl,cl
435 jz .isfile
436 cmp cl,'\'
437 jne .scan
438 mov [di-1],byte 0 ; Terminate at directory name
439 mov cl,02h ; Search for directory
440 xchg cl,[ISOFlags]
441 push di
442 push cx
443 push word .resume ; Where to "return" to
444 push es
445 .isfile:
446 xchg ax,di
447
448 .getsome:
449 ; Get a chunk of the directory
450 mov si,trackbuf
451 pushad
452 xchg bx,si
453 mov cx,1 ; load one sector
454 call getfssec
455 popad
456
457 .compare:
458 movzx eax, byte [si] ; Length of directory entry
459 cmp al, 33
460 jb .next_sector
461 mov cl, [si+25]
462 xor cl, [ISOFlags]
463 test cl, byte 8Eh ; Unwanted file attributes!
464 jnz .not_file
465 pusha
466 movzx cx, byte [si+32] ; File identifier length
467 add si, byte 33 ; File identifier offset
468 call iso_compare_names
469 popa
470 je .success
471 .not_file:
472 sub edx, eax ; Decrease bytes left
473 jbe .failure
474 add si, ax ; Advance pointer
475
476 .check_overrun:
477 ; Did we finish the buffer?
478 cmp si, trackbuf+trackbufsize
479 jb .compare ; No, keep going
480
481 jmp short .getsome ; Get some more directory
482
483 .next_sector:
484 ; Advance to the beginning of next sector
485 lea ax, [si+SECTORSIZE-1]
486 and ax, ~(SECTORSIZE-1)
487 sub ax, si
488 jmp short .not_file ; We still need to do length checks
489
490 .failure:
491 %ifdef DEBUG_MESSAGES
492 mov si, findfail_msg
493 call writemsg
494 call crlf
495 %endif
496 xor eax, eax ; ZF = 1
497 mov [bx+file_sector], eax
498 pop es
499 ret
500
501 .success:
502 mov eax, [si+2] ; Location of extent
503 mov [bx+file_sector], eax
504 mov eax, [si+10] ; Data length
505 push eax
506 add eax, SECTORSIZE-1
507 shr eax, SECTORSIZE_LG2
508 mov [bx+file_left], eax
509 pop eax
510 mov edx, eax
511 shr edx, 16
512 and bx, bx ; ZF = 0
513 mov si, bx
514 pop es
515 ret
516
517 .resume:
518 ; We get here if we were only doing part of a lookup
519 ; This relies on the fact that .success returns bx == si
520 xchg edx, eax ; Directory length in edx
521 pop cx ; Old ISOFlags
522 pop di ; Next filename pointer
523
524 mov byte [di-1], '\' ; restore the backslash in the filename
525
526 mov [ISOFlags], cl ; Restore the flags
527 jz .failure ; Did we fail? If so fail for real!
528 jmp .look_for_slash ; Otherwise, next level
529
530 ;
531 ; allocate_file: Allocate a file structure
532 ;
533 ; If successful:
534 ; ZF set
535 ; BX = file pointer
536 ; In unsuccessful:
537 ; ZF clear
538 ;
539 allocate_file:
540 push cx
541 mov bx, Files
542 mov cx, MAX_OPEN
543 .check:
544 cmp dword [bx], byte 0
545 je .found
546 add bx, open_file_t_size ; ZF = 0
547 loop .check
548 ; ZF = 0 if we fell out of the loop
549 .found:
550 pop cx
551 ret
552
553 ;
554 ; iso_compare_names:
555 ; Compare the names DS:SI and DS:DI and report if they are
556 ; equal from an ISO 9660 perspective. SI is the name from
557 ; the filesystem; CX indicates its length, and ';' terminates.
558 ; DI is expected to end with a null.
559 ;
560 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
561 ;
562 iso_compare_names:
563 ; First, terminate and canonicalize input filename
564 push di
565 mov di, ISOFileName
566 .canon_loop:
567 jcxz .canon_end
568 lodsb
569 dec cx
570 cmp al, ';'
571 je .canon_end
572 and al, al
573 je .canon_end
574 stosb
575 cmp di, ISOFileNameEnd-1 ; Guard against buffer overrun
576 jb .canon_loop
577 .canon_end:
578 cmp di, ISOFileName
579 jbe .canon_done
580 cmp byte [di-1], '.' ; Remove terminal dots
581 jne .canon_done
582 dec di
583 jmp short .canon_end
584 .canon_done:
585 mov [di], byte 0 ; Null-terminate string
586 pop di
587 mov si, ISOFileName
588 .compare:
589 lodsb
590 mov ah, [di]
591 inc di
592 and ax, ax
593 jz .success ; End of string for both
594 and al, al ; Is either one end of string?
595 jz .failure ; If so, failure
596 and ah, ah
597 jz .failure
598 or ax, 2020h ; Convert to lower case
599 cmp al, ah
600 je .compare
601 .failure:
602 and ax, ax ; ZF = 0 (at least one will be nonzero)
603 .success:
604 ret
605
606
607
608
609
610
611
612 ;
613 ; getfssec: Get multiple clusters from a file, given the file pointer.
614 ;
615 ; On entry:
616 ; ES:BX -> Buffer
617 ; SI -> File pointer
618 ; CX -> Cluster count; 0FFFFh = until end of file
619 ; On exit:
620 ; SI -> File pointer (or 0 on EOF)
621 ; CF = 1 -> Hit EOF
622 ;
623 getfssec:
624 cmp cx, [si+file_left]
625 jna .ok_size
626 mov cx, [si+file_left]
627
628 .ok_size:
629 mov bp, cx
630 push cx
631 push si
632 mov eax, [si+file_sector]
633 call getlinsec
634 xor ecx, ecx
635 pop si
636 pop cx
637
638 add [si+file_sector], ecx
639 sub [si+file_left], ecx
640 ja .not_eof ; CF = 0
641
642 xor ecx, ecx
643 mov [si+file_sector], ecx ; Mark as unused
644 xor si,si
645 stc
646
647 .not_eof:
648 ret
649
650
651
652 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
653 ; Try to scan the entire 80h-FFh from the end.
654 spec_query_failed:
655 mov si,spec_err_msg
656 call writemsg
657
658 mov dl, 0FFh
659 .test_loop:
660 pusha
661 mov ax, 4B01h
662 mov si, spec_packet
663 mov byte [si], 13 ; Size of buffer
664 int 13h
665 popa
666 jc .still_broken
667
668 mov si, maybe_msg
669 call writemsg
670 mov al, dl
671 call writehex2
672 call crlf
673
674 cmp byte [sp_drive], dl
675 jne .maybe_broken
676
677 ; Okay, good enough...
678 mov si, alright_msg
679 call writemsg
680 mov [DriveNo], dl
681 .found_drive:
682 jmp found_drive
683
684 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
685 ; but if this was the drive number originally passed in
686 ; DL then consider it "good enough"
687 .maybe_broken:
688 cmp byte [DriveNo], dl
689 je .found_drive
690
691 .still_broken:
692 dec dx
693 cmp dl, 80h
694 jnb .test_loop
695
696 fatal_error:
697 mov si, nothing_msg
698 call writemsg
699
700 .norge:
701 jmp short .norge
702
703
704
705 ; Information message (DS:SI) output
706 ; Prefix with "isolinux: "
707 ;
708 writemsg:
709 push ax
710 push si
711 mov si, isolinux_str
712 call writestr
713 pop si
714 call writestr
715 pop ax
716 ret
717
718 ;
719 ; crlf: Print a newline
720 ;
721 crlf:
722 mov si, crlf_msg
723 ; Fall through
724
725 ;
726 ; writestr: write a null-terminated string to the console, saving
727 ; registers on entry.
728 ;
729 writestr:
730 pushfd
731 pushad
732 .top:
733 lodsb
734 and al, al
735 jz .end
736 call writechr
737 jmp short .top
738 .end:
739 popad
740 popfd
741 ret
742
743
744 ;
745 ; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
746 ;
747 writehex2:
748 pushfd
749 pushad
750 shl eax, 24
751 mov cx, 2
752 jmp short writehex_common
753 writehex4:
754 pushfd
755 pushad
756 shl eax, 16
757 mov cx, 4
758 jmp short writehex_common
759 writehex8:
760 pushfd
761 pushad
762 mov cx, 8
763 writehex_common:
764 .loop:
765 rol eax, 4
766 push eax
767 and al, 0Fh
768 cmp al, 10
769 jae .high
770 .low:
771 add al, '0'
772 jmp short .ischar
773 .high:
774 add al, 'A'-10
775 .ischar:
776 call writechr
777 pop eax
778 loop .loop
779 popad
780 popfd
781 ret
782
783 ;
784 ; Write a character to the screen. There is a more "sophisticated"
785 ; version of this in the subsequent code, so we patch the pointer
786 ; when appropriate.
787 ;
788
789 writechr:
790 pushfd
791 pushad
792 mov ah, 0Eh
793 xor bx, bx
794 int 10h
795 popad
796 popfd
797 ret
798
799 ;
800 ; Get one sector. Convenience entry point.
801 ;
802 getonesec:
803 mov bp, 1
804 ; Fall through to getlinsec
805
806 ;
807 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
808 ;
809 ; Note that we can't always do this as a single request, because at least
810 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
811 ; to 32 sectors (64K) per request.
812 ;
813 ; Input:
814 ; EAX - Linear sector number
815 ; ES:BX - Target buffer
816 ; BP - Sector count
817 ;
818 getlinsec:
819 mov si,dapa ; Load up the DAPA
820 mov [si+4],bx
821 mov bx,es
822 mov [si+6],bx
823 mov [si+8],eax
824 .loop2:
825 push bp ; Sectors left
826 cmp bp,[MaxTransfer]
827 jbe .bp_ok
828 mov bp,[MaxTransfer]
829 .bp_ok:
830 mov [si+2],bp
831 push si
832 mov dl,[DriveNo]
833 mov ah,42h ; Extended Read
834 call xint13
835 pop si
836 pop bp
837 movzx eax,word [si+2] ; Sectors we read
838 add [si+8],eax ; Advance sector pointer
839 sub bp,ax ; Sectors left
840 shl ax,SECTORSIZE_LG2-4 ; 2048-byte sectors -> segment
841 add [si+6],ax ; Advance buffer pointer
842 and bp,bp
843 jnz .loop2
844 mov eax,[si+8] ; Next sector
845 ret
846
847 ; INT 13h with retry
848 xint13:
849 mov byte [RetryCount], retry_count
850 .try:
851 pushad
852 int 13h
853 jc .error
854 add sp, byte 8*4 ; Clean up stack
855 ret
856 .error:
857 mov [DiskError], ah ; Save error code
858 popad
859 dec byte [RetryCount]
860 jz .real_error
861 push ax
862 mov al,[RetryCount]
863 mov ah,[dapa+2] ; Sector transfer count
864 cmp al,2 ; Only 2 attempts left
865 ja .nodanger
866 mov ah,1 ; Drop transfer size to 1
867 jmp short .setsize
868 .nodanger:
869 cmp al,retry_count-2
870 ja .again ; First time, just try again
871 shr ah,1 ; Otherwise, try to reduce
872 adc ah,0 ; the max transfer size, but not to 0
873 .setsize:
874 mov [MaxTransfer],ah
875 mov [dapa+2],ah
876 .again:
877 pop ax
878 jmp .try
879
880 .real_error:
881 mov si, diskerr_msg
882 call writemsg
883 mov al, [DiskError]
884 call writehex2
885 mov si, ondrive_str
886 call writestr
887 mov al, dl
888 call writehex2
889 call crlf
890 ; Fall through to kaboom
891
892 ;
893 ; kaboom: write a message and bail out. Wait for a user keypress,
894 ; then do a hard reboot.
895 ;
896 kaboom:
897 mov ax, cs
898 mov ds, ax
899 mov es, ax
900 mov fs, ax
901 mov gs, ax
902 sti
903 mov si, err_bootfailed
904 call writestr
905 xor ax, ax ; Wait for keypress
906 int 16h
907 cli
908 mov word [BIOS_magic], 0 ; Cold reboot
909 jmp 0F000h:0FFF0h ; Reset vector address
910
911
912 ;
913 ; pollchar_and_empty: check if we have an input character pending (ZF = 0) and empty the input buffer afterwards
914 ;
915 pollchar_and_empty:
916 pushad
917 mov ah, 1 ; Did the user press a key?
918 int 16h
919 jz .end ; No, then we're done
920 mov ah, 0 ; Otherwise empty the buffer by reading it
921 int 16h
922 .end:
923 popad
924 ret
925
926
927
928 isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0
929 copyright_str db ' (C) 1994-2002 H. Peter Anvin', CR, LF, 0
930 presskey_msg db 'Press any key to boot from CD', 0
931 dot_msg db '.',0
932
933 %ifdef DEBUG_MESSAGES
934 startup_msg: db 'Startup, DL = ', 0
935 spec_ok_msg: db 'packet OK, drive = ', 0
936 secsize_msg: db 'size appears to be ', 0
937 rootloc_msg: db 'Root dir loc: ', 0
938 rootlen_msg: db 'Root dir len: ', 0
939 rootsect_msg: db 'Root dir len(sect): ', 0
940 fileloc_msg: db 'SETUPLDR loc: ', 0
941 filelen_msg: db 'SETUPLDR len: ', 0
942 filesect_msg: db 'SETUPLDR len(sect): ', 0
943 findfail_msg: db 'Failed to find file!', 0
944 startldr_msg: db 'Starting SETUPLDR.SYS', 0
945 %endif
946
947 nosecsize_msg: db 'No sector size, assume 0800', CR, LF, 0
948 spec_err_msg: db 'Load spec failed, trying wing ...', CR, LF, 0
949 maybe_msg: db 'Found smth at drive = ', 0
950 alright_msg: db 'might be ok, continuing...', CR, LF, 0
951 nothing_msg: db 'Failed locate CD-ROM; boot failed.', CR, LF, 0
952 isolinux_str db 'IsoBoot: ', 0
953 crlf_msg db CR, LF, 0
954 diskerr_msg: db 'Disk error ', 0
955 ondrive_str: db ', drive ', 0
956 err_bootfailed db CR, LF, 'failed..', 0
957 isolinux_dir db '\LOADER', 0
958 no_dir_msg db 'LOADER dir not found.', CR, LF, 0
959 isolinux_bin db 'SETUPLDR.SYS', 0
960 no_isolinux_msg db 'SETUPLDR not found.', CR, LF, 0
961
962 ;
963 ; El Torito spec packet
964 ;
965 align 8, db 0
966 spec_packet: db 13h ; Size of packet
967 sp_media: db 0 ; Media type
968 sp_drive: db 0 ; Drive number
969 sp_controller: db 0 ; Controller index
970 sp_lba: dd 0 ; LBA for emulated disk image
971 sp_devspec: dw 0 ; IDE/SCSI information
972 sp_buffer: dw 0 ; User-provided buffer
973 sp_loadseg: dw 0 ; Load segment
974 sp_sectors: dw 0 ; Sector count
975 sp_chs: db 0,0,0 ; Simulated CHS geometry
976 sp_dummy: db 0 ; Scratch, safe to overwrite
977
978 ;
979 ; EBIOS drive parameter packet
980 ;
981 align 8, db 0
982 drive_params: dw 30 ; Buffer size
983 dp_flags: dw 0 ; Information flags
984 dp_cyl: dd 0 ; Physical cylinders
985 dp_head: dd 0 ; Physical heads
986 dp_sec: dd 0 ; Physical sectors/track
987 dp_totalsec: dd 0,0 ; Total sectors
988 dp_secsize: dw 0 ; Bytes per sector
989 dp_dpte: dd 0 ; Device Parameter Table
990 dp_dpi_key: dw 0 ; 0BEDDh if rest valid
991 dp_dpi_len: db 0 ; DPI len
992 db 0
993 dw 0
994 dp_bus: times 4 db 0 ; Host bus type
995 dp_interface: times 8 db 0 ; Interface type
996 db_i_path: dd 0,0 ; Interface path
997 db_d_path: dd 0,0 ; Device path
998 db 0
999 db_dpi_csum: db 0 ; Checksum for DPI info
1000
1001 ;
1002 ; EBIOS disk address packet
1003 ;
1004 align 8, db 0
1005 dapa: dw 16 ; Packet size
1006 .count: dw 0 ; Block count
1007 .off: dw 0 ; Offset of buffer
1008 .seg: dw 0 ; Segment of buffer
1009 .lba: dd 0 ; LBA (LSW)
1010 dd 0 ; LBA (MSW)
1011
1012 alignb 4, db 0
1013 MaxTransfer dw 2 ;32 ; Max sectors per transfer
1014
1015 times 2046-($-$$) db 0 ; Pad to file offset 2046
1016 dw 0aa55h ; BootSector signature