1 ; -*- fundamental -*- (asm-mode sucks)
3 ; ****************************************************************************
7 ; A program to boot Linux kernels off a CD-ROM using the El Torito
8 ; boot standard in "no emulation" mode, making the entire filesystem
9 ; available. It is based on the SYSLINUX boot loader for MS-DOS
12 ; Copyright (C) 1994-2004 H. Peter Anvin
14 ; This program is free software; you can redistribute it and/or modify
15 ; it under the terms of the GNU General Public License as published by
16 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
17 ; Boston MA 02111-1307, USA; either version 2 of the License, or
18 ; (at your option) any later version; incorporated herein by reference.
20 ; ****************************************************************************
27 %include "tracers.inc"
30 ; Some semi-configurable constants... change on your own risk.
33 FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
34 FILENAME_MAX equ (1 << FILENAME_MAX_LG2)
35 NULLFILE equ 0 ; Zero byte == null file name
36 retry_count equ 6 ; How patient are we with the BIOS?
37 %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
38 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
39 MAX_OPEN equ (1 << MAX_OPEN_LG2)
40 SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
41 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
44 ; This is what we need to do when idle
54 ; The following structure is used for "virtual kernels"; i.e. LILO-style
55 ; option labels. The options we permit here are `kernel' and `append
56 ; Since there is no room in the bottom 64K for all of these, we
57 ; stick them at vk_seg:0000 and copy them down before we need them.
60 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
61 vk_rname: resb FILENAME_MAX ; Real name
64 vk_append: resb max_cmd_len+1 ; Command line
66 vk_end: equ $ ; Should be <= vk_size
70 ; Segment assignments in the bottom 640K
71 ; 0000h - main code/data segment (and BIOS segment)
73 real_mode_seg equ 3000h
74 vk_seg equ 2000h ; Virtual kernels
75 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
76 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
79 ; File structure. This holds the information for each currently open file.
82 file_sector resd 1 ; Sector pointer (0 = structure free)
83 file_left resd 1 ; Number of sectors left
87 %if (open_file_t_size & (open_file_t_size-1))
88 %error "open_file_t is not a power of 2"
93 dir_lba resd 1 ; Directory start (LBA)
94 dir_len resd 1 ; Length in bytes
95 dir_clust resd 1 ; Length in clusters
98 ; ---------------------------------------------------------------------------
100 ; ---------------------------------------------------------------------------
103 ; Memory below this point is reserved for the BIOS and the MBR
106 section .bss start=BSS_START
107 trackbufsize equ 8192
108 trackbuf resb trackbufsize ; Track buffer goes here
109 getcbuf resb trackbufsize
113 ISOFileName resb 64 ; ISO filename canonicalization buffer
115 CurDir resb dir_t_size ; Current directory
116 RootDir resb dir_t_size ; Root directory
117 FirstSecSum resd 1 ; Checksum of bytes 64-2048
118 ImageDwords resd 1 ; isolinux.bin size, dwords
119 InitStack resd 1 ; Initial stack pointer (SS:SP)
120 DiskSys resw 1 ; Last INT 13h call
121 ImageSectors resw 1 ; isolinux.bin size, sectors
122 DiskError resb 1 ; Error code for disk I/O
123 DriveNo resb 1 ; CD-ROM BIOS drive number
124 ISOFlags resb 1 ; Flags for ISO directory search
125 RetryCount resb 1 ; Used for disk access retries
127 alignb open_file_t_size
128 Files resb MAX_OPEN*open_file_t_size
131 ; Constants for the xfer_buf_seg
133 ; The xfer_buf_seg is also used to store message file buffers. We
134 ; need two trackbuffers (text and graphics), plus a work buffer
135 ; for the graphics decompressor.
137 xbs_textbuf equ 0 ; Also hard-coded, do not change
138 xbs_vgabuf equ trackbufsize
139 xbs_vgatmpbuf equ 2*trackbufsize
144 ;; Primary entry point. Because BIOSes are buggy, we only load the first
145 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
152 _start: ; Far jump makes sure we canonicalize the address
155 times 8-($-$$) nop ; Pad to file offset 8
157 ; This table hopefully gets filled in by mkisofs using the
158 ; -boot-info-table option. If not, the values in this
159 ; table are default values that we can use to get us what
160 ; we need, at least under a certain set of assumptions.
161 bi_pvd: dd 16 ; LBA of primary volume descriptor
162 bi_file: dd 0 ; LBA of boot file
163 bi_length: dd 0xdeadbeef ; Length of boot file
164 bi_csum: dd 0xdeadbeef ; Checksum of boot file
165 bi_reserved: times 10 dd 0xdeadbeef ; Reserved
167 _start1: mov [cs:InitStack],sp ; Save initial stack pointer
168 mov [cs:InitStack+2],ss
171 mov sp,StackBuf ; Set up stack
180 mov si,syslinux_banner
182 %ifdef DEBUG_MESSAGES
188 ; Before modifying any memory, get the checksum of bytes
191 initial_csum: xor edi,edi
193 mov cx,(SECTOR_SIZE-64) >> 2
197 mov [FirstSecSum],edi
200 %ifdef DEBUG_MESSAGES
208 ; Now figure out what we're actually doing
209 ; Note: use passed-in DL value rather than 7Fh because
210 ; at least some BIOSes will get the wrong value otherwise
211 mov ax,4B01h ; Get disk emulation status
215 jc award_hack ; changed for BrokenAwardHack
217 cmp [sp_drive],dl ; Should contain the drive number
218 jne spec_query_failed
220 %ifdef DEBUG_MESSAGES
223 mov al,byte [sp_drive]
229 ; Alright, we have found the drive. Now, try to find the
230 ; boot file itself. If we have a boot info table, life is
231 ; good; if not, we have to make some assumptions, and try
232 ; to figure things out ourselves. In particular, the
233 ; assumptions we have to make are:
234 ; - single session only
235 ; - only one boot entry (no menu or other alternatives)
237 cmp dword [bi_file],0 ; Address of code to load
238 jne found_file ; Boot info table present :)
240 %ifdef DEBUG_MESSAGES
241 mov si,noinfotable_msg
245 ; No such luck. See if the the spec packet contained one.
248 jz set_file ; Good enough
250 %ifdef DEBUG_MESSAGES
251 mov si,noinfoinspec_msg
255 ; No such luck. Get the Boot Record Volume, assuming single
256 ; session disk, and that we're the first entry in the chain
257 mov eax,17 ; Assumed address of BRV
261 mov eax,[trackbuf+47h] ; Get boot catalog address
263 call getonesec ; Get boot catalog
265 mov eax,[trackbuf+28h] ; First boot entry
266 ; And hope and pray this is us...
268 ; Some BIOSes apparently have limitations on the size
269 ; that may be loaded (despite the El Torito spec being very
270 ; clear on the fact that it must all be loaded.) Therefore,
271 ; we load it ourselves, and *bleep* the BIOS.
277 ; Set up boot file sizes
279 sub eax,SECTOR_SIZE-3
280 shr eax,2 ; bytes->dwords
281 mov [ImageDwords],eax ; boot file dwords
283 shr eax,9 ; dwords->sectors
284 mov [ImageSectors],ax ; boot file sectors
286 mov eax,[bi_file] ; Address of code to load
287 inc eax ; Don't reload bootstrap code
288 %ifdef DEBUG_MESSAGES
295 ; Just in case some BIOSes have problems with
296 ; segment wraparound, use the normalized address
297 mov bx,((7C00h+2048) >> 4)
300 mov bp,[ImageSectors]
301 %ifdef DEBUG_MESSAGES
315 %ifdef DEBUG_MESSAGES
320 ; Verify the checksum on the loaded image.
324 mov ecx,[ImageDwords]
325 mov edi,[FirstSecSum] ; First sector checksum
332 ; SI wrapped around, advance ES
346 %ifdef DEBUG_MESSAGES
350 jmp all_read ; Jump to main code
352 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
353 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
354 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
356 ;; There is a problem with certain versions of the AWARD BIOS ...
357 ;; the boot sector will be loaded and executed correctly, but, because the
358 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
359 ;; load the spec packet will fail. We scan for the equivalent of
368 ;; and use <direct far> as the new vector for int 13. The code above is
369 ;; used to load the boot code into ram, and there should be no reason
370 ;; for anybody to change it now or in the future. There are no opcodes
371 ;; that use encodings relativ to IP, so scanning is easy. If we find the
372 ;; code above in the BIOS code we can be pretty sure to run on a machine
373 ;; with an broken AWARD BIOS ...
375 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
377 %ifdef DEBUG_MESSAGES ;;
379 award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
380 award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
381 award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
382 award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
383 award_not_fail db "BAH: FAILURE" ;;
384 award_not_crlf db CR,LF,0 ;;
388 award_oldint13 dd 0 ;;
389 award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
391 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
392 award_hack: mov si,spec_err_msg ; Moved to this place from
393 call writemsg ; spec_query_faild
395 %ifdef DEBUG_MESSAGES ;
397 mov si,award_notice ; display our plan
399 mov si,award_not_orig ; display original int 13
400 call writemsg ; vector
403 mov [award_oldint13],eax ;
405 %ifdef DEBUG_MESSAGES ;
408 mov si,award_not_crlf ;
412 mov ax,0f000h ; ES = BIOS Seg
415 xor di,di ; start at ES:DI = f000:0
416 award_loop: push di ; save DI
417 mov si,award_string ; scan for award_string
418 mov cx,7 ; length of award_string = 7dw
421 jcxz award_found ; jmp if found
422 inc di ; not found, inc di
425 award_failed: pop es ; No, not this way :-((
428 %ifdef DEBUG_MESSAGES ;
430 mov si,award_not_fail ; display failure ...
433 mov eax,[award_oldint13] ; restore the original int
434 or eax,eax ; 13 vector if there is one
435 jz spec_query_failed ; and try other workarounds
437 jmp spec_query_failed ;
439 award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
442 cmp eax,[award_oldint13] ; give up if this is the
443 jz award_failed ; active int 13 vector,
444 mov [13h*4],eax ; otherwise change 0:13h*4
447 %ifdef DEBUG_MESSAGES ;
449 push eax ; display message and
450 mov si,award_not_new ; new vector address
454 mov si,award_not_crlf ;
457 mov ax,4B01h ; try to read the spec packet
458 mov dl,[DriveNo] ; now ... it should not fail
459 mov si,spec_packet ; any longer
463 %ifdef DEBUG_MESSAGES ;
465 mov si,award_not_succ ; display our SUCCESS
468 jmp found_drive ; and leave error recovery code
470 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
471 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
472 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
476 ; Try to scan the entire 80h-FFh from the end.
480 ; some code moved to BrokenAwardHack
486 mov byte [si],13 ; Size of buffer
497 cmp byte [sp_drive],dl
500 ; Okay, good enough...
504 .found_drive: jmp found_drive
506 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
507 ; but if this was the drive number originally passed in
508 ; DL then consider it "good enough"
510 cmp byte [DriveNo],dl
513 .still_broken: dec dx
517 ; No spec packet anywhere. Some particularly pathetic
518 ; BIOSes apparently don't even implement function
519 ; 4B01h, so we can't query a spec packet no matter
520 ; what. If we got a drive number in DL, then try to
521 ; use it, and if it works, then well...
523 cmp dl,81h ; Should be 81-FF at least
524 jb fatal_error ; If not, it's hopeless
526 ; Write a warning to indicate we're on *very* thin ice now
532 jmp .found_drive ; Pray that this works...
538 .norge: jmp short .norge
540 ; Information message (DS:SI) output
541 ; Prefix with "isolinux: "
553 ; Write a character to the screen. There is a more "sophisticated"
554 ; version of this in the subsequent code, so we patch the pointer
559 jmp near writechr_simple ; 3-byte jump
572 ; Get one sector. Convenience entry point.
576 ; Fall through to getlinsec
579 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
581 ; Note that we can't always do this as a single request, because at least
582 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
583 ; to 32 sectors (64K) per request.
586 ; EAX - Linear sector number
587 ; ES:BX - Target buffer
591 mov si,dapa ; Load up the DAPA
597 push bp ; Sectors left
605 mov ah,42h ; Extended Read
609 movzx eax,word [si+2] ; Sectors we read
610 add [si+8],eax ; Advance sector pointer
611 sub bp,ax ; Sectors left
612 shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
613 add [si+6],ax ; Advance buffer pointer
616 mov eax,[si+8] ; Next sector
620 xint13: mov byte [RetryCount],retry_count
624 add sp,byte 8*4 ; Clean up stack
627 mov [DiskError],ah ; Save error code
629 mov [DiskSys],ax ; Save system call number
630 dec byte [RetryCount]
634 mov ah,[dapa+2] ; Sector transfer count
635 cmp al,2 ; Only 2 attempts left
637 mov ah,1 ; Drop transfer size to 1
641 ja .again ; First time, just try again
642 shr ah,1 ; Otherwise, try to reduce
643 adc ah,0 ; the max transfer size, but not to 0
651 .real_error: mov si,diskerr_msg
664 ; Fall through to kaboom
667 ; kaboom: write a message and bail out. Wait for a user keypress,
668 ; then do a hard reboot.
678 mov si,err_bootfailed
682 mov word [BIOS_magic],0 ; Cold reboot
683 jmp 0F000h:0FFF0h ; Reset vector address
685 ; -----------------------------------------------------------------------------
686 ; Common modules needed in the first sector
687 ; -----------------------------------------------------------------------------
689 %include "writestr.inc" ; String output
690 writestr equ cwritestr
691 %include "writehex.inc" ; Hexadecimal output
693 ; -----------------------------------------------------------------------------
694 ; Data that needs to be in the first sector
695 ; -----------------------------------------------------------------------------
697 syslinux_banner db CR, LF, 'ISOLINUX ', version_str, ' ', date, ' ', 0
698 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
700 isolinux_str db 'isolinux: ', 0
701 %ifdef DEBUG_MESSAGES
702 startup_msg: db 'Starting up, DL = ', 0
703 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
704 secsize_msg: db 'Sector size appears to be ', 0
705 offset_msg: db 'Loading main image from LBA = ', 0
706 size_msg: db 'Sectors to load = ', 0
707 loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0
708 verify_msg: db 'Image checksum verified.', CR, LF, 0
709 allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
711 noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
712 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
713 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
714 maybe_msg: db 'Found something at drive = ', 0
715 alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0
716 nospec_msg db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0
717 nosecsize_msg: db 'Failed to get sector size, assuming 0800', CR, LF, 0
718 diskerr_msg: db 'Disk error ', 0
719 oncall_str: db ', AX = ',0
720 ondrive_str: db ', drive ', 0
721 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF, 0
722 checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
724 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
725 bailmsg equ err_bootfailed
730 ; El Torito spec packet
733 spec_packet: db 13h ; Size of packet
734 sp_media: db 0 ; Media type
735 sp_drive: db 0 ; Drive number
736 sp_controller: db 0 ; Controller index
737 sp_lba: dd 0 ; LBA for emulated disk image
738 sp_devspec: dw 0 ; IDE/SCSI information
739 sp_buffer: dw 0 ; User-provided buffer
740 sp_loadseg: dw 0 ; Load segment
741 sp_sectors: dw 0 ; Sector count
742 sp_chs: db 0,0,0 ; Simulated CHS geometry
743 sp_dummy: db 0 ; Scratch, safe to overwrite
746 ; EBIOS drive parameter packet
749 drive_params: dw 30 ; Buffer size
750 dp_flags: dw 0 ; Information flags
751 dp_cyl: dd 0 ; Physical cylinders
752 dp_head: dd 0 ; Physical heads
753 dp_sec: dd 0 ; Physical sectors/track
754 dp_totalsec: dd 0,0 ; Total sectors
755 dp_secsize: dw 0 ; Bytes per sector
756 dp_dpte: dd 0 ; Device Parameter Table
757 dp_dpi_key: dw 0 ; 0BEDDh if rest valid
758 dp_dpi_len: db 0 ; DPI len
761 dp_bus: times 4 db 0 ; Host bus type
762 dp_interface: times 8 db 0 ; Interface type
763 db_i_path: dd 0,0 ; Interface path
764 db_d_path: dd 0,0 ; Device path
766 db_dpi_csum: db 0 ; Checksum for DPI info
769 ; EBIOS disk address packet
772 dapa: dw 16 ; Packet size
773 .count: dw 0 ; Block count
774 .off: dw 0 ; Offset of buffer
775 .seg: dw 0 ; Segment of buffer
776 .lba: dd 0 ; LBA (LSW)
780 Stack dw _start, 0 ; SS:SP for stack reset
781 MaxTransfer dw 32 ; Max sectors per transfer
783 rl_checkpt equ $ ; Must be <= 800h
785 rl_checkpt_off equ ($-$$)
787 %if rl_checkpt_off > 0x800
788 %error "Sector 0 overflow"
792 ; ----------------------------------------------------------------------------
793 ; End of code and data that have to be in the first sector
794 ; ----------------------------------------------------------------------------
798 ; Initialize screen (if we're using one)
800 ; Now set up screen parameters
803 ; Wipe the F-key area
806 mov cx,10*(1 << FILENAME_MAX_LG2)
809 ; Patch the writechr routine to point to the full code
810 mov word [writechr+1], writechr_full-(writechr+3)
812 ; Tell the user we got this far...
813 %ifndef DEBUG_MESSAGES ; Gets messy with debugging on
823 ; Common initialization code
826 %include "cpuinit.inc"
829 ; Now we're all set to start with our *real* business. First load the
830 ; configuration file (if any) and parse it.
832 ; In previous versions I avoided using 32-bit registers because of a
833 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
834 ; random. I figure, though, that if there are any of those still left
835 ; they probably won't be trying to install Linux on them...
837 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
838 ; to take'm out. In fact, we may want to put them back if we're going
839 ; to boot ELKS at some point.
843 ; Now, we need to sniff out the actual filesystem data structures.
844 ; mkisofs gave us a pointer to the primary volume descriptor
845 ; (which will be at 16 only for a single-session disk!); from the PVD
846 ; we should be able to find the rest of what we need to know.
853 mov eax,[trackbuf+156+2]
854 mov [RootDir+dir_lba],eax
855 mov [CurDir+dir_lba],eax
856 %ifdef DEBUG_MESSAGES
857 mov si,dbg_rootdir_msg
862 mov eax,[trackbuf+156+10]
863 mov [RootDir+dir_len],eax
864 mov [CurDir+dir_len],eax
865 add eax,SECTOR_SIZE-1
867 mov [RootDir+dir_clust],eax
868 mov [CurDir+dir_clust],eax
870 ; Look for an isolinux directory, and if found,
871 ; make it the current directory instead of the root
873 mov di,boot_dir ; Search for /boot/isolinux
878 mov al,02h ; Search for /isolinux
882 mov [CurDir+dir_len],eax
883 mov eax,[si+file_left]
884 mov [CurDir+dir_clust],eax
885 xor eax,eax ; Free this file pointer entry
886 xchg eax,[si+file_sector]
887 mov [CurDir+dir_lba],eax
888 %ifdef DEBUG_MESSAGES
890 mov si,dbg_isodir_msg
899 ; Locate the configuration file
902 %ifdef DEBUG_MESSAGES
903 mov si,dbg_config_msg
909 jz no_config_file ; Not found or empty
911 %ifdef DEBUG_MESSAGES
912 mov si,dbg_configok_msg
917 ; Now we have the config file open. Parse the config file and
918 ; run the user interface.
923 ; Linux kernel loading code is common.
925 %include "runkernel.inc"
928 ; COMBOOT-loading code
930 %include "comboot.inc"
932 %include "cmdline.inc"
935 ; Boot sector loading code
937 %include "bootsect.inc"
940 ; Enable disk emulation. The kind of disk we emulate is dependent on the size of
941 ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
950 mov dx,ax ; Set EDX <- file size
952 mov cx,img_table_count
953 mov eax,[si+file_sector] ; Starting LBA of file
954 mov [dsp_lba],eax ; Location of file
955 mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk
964 ; Hard disk image. Need to examine the partition table
965 ; in order to deduce the C/H/S geometry. Sigh.
972 mov cx,1 ; Load 1 sector
975 cmp word [trackbuf+510],0aa55h ; Boot signature
976 jne .bad_image ; Image not bootable
978 mov cx,4 ; 4 partition entries
979 mov di,trackbuf+446 ; Start of partition table
981 xor ax,ax ; Highest sector(al) head(ah)
998 inc bx ; # of heads in BX
999 xor ah,ah ; # of sectors in AX
1000 cwde ; EAX[31:16] <- 0
1002 shl eax,9 ; Convert to bytes
1003 ; Now eax contains the number of bytes per cylinder
1009 inc eax ; Fractional cylinder...
1010 ; Now (e)ax contains the number of cylinders
1011 .no_remainder: cmp eax,1024
1013 mov ax,1024 ; Max possible #
1014 .ok_cyl: dec ax ; Convert to max cylinder no
1015 pop ebx ; S(bl) H(bh)
1021 mov al,4 ; Hard disk boot
1022 mov byte [dsp_drive], 80h ; Drive 80h = hard disk
1027 and bl,0F0h ; Copy controller info bits
1029 mov [dsp_media],al ; Emulation type
1031 mov [dsp_chs],eax ; C/H/S geometry
1032 mov ax,[sp_devspec] ; Copy device spec
1033 mov [dsp_devspec],ax
1034 mov al,[sp_controller] ; Copy controller index
1035 mov [dsp_controller],al
1038 call vgaclearmode ; Reset video
1040 mov ax,4C00h ; Enable emulation and boot
1048 ; If this returns, we have problems
1050 mov si,err_disk_image
1055 ; Look for the highest seen H/S geometry
1056 ; We compute cylinders separately
1059 mov bl,[si] ; Head #
1062 mov ah,bl ; New highest head #
1063 .done_track: mov bl,[si+1]
1064 and bl,3Fh ; Sector #
1071 ; Boot a specified local disk. AX specifies the BIOS disk number; or
1072 ; 0xFFFF in case we should execute INT 18h ("next device.")
1076 lss sp,[cs:Stack] ; Restore stack pointer
1082 mov si,localboot_msg
1087 ; Load boot sector from the specified BIOS device and jump to it.
1091 xor ax,ax ; Reset drive
1093 mov ax,0201h ; Read one sector
1094 mov cx,0001h ; C/H/S = 0/0/1 (first sector)
1098 cli ; Abandon hope, ye who enter here
1101 mov cx,512 ; Probably overkill, but should be safe
1103 lss sp,[cs:InitStack]
1104 jmp 0:07C00h ; Jump to new boot sector
1107 int 18h ; Hope this does the right thing...
1108 jmp kaboom ; If we returned, oh boy...
1111 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
1122 ac_kill: mov si,aborted_msg
1125 ; abort_load: Called by various routines which wants to print a fatal
1126 ; error message and return to the command prompt. Since this
1127 ; may happen at just about any stage of the boot process, assume
1128 ; our state is messed up, and just reset the segment registers
1129 ; and the stack forcibly.
1131 ; SI = offset (in _text) of error message to print
1134 mov ax,cs ; Restore CS = DS = ES
1138 lss sp,[cs:Stack] ; Reset the stack
1140 call cwritestr ; Expects SI -> error msg
1141 al_ok: jmp enter_command ; Return to command prompt
1143 ; End of abort_check
1159 ; DX:AX or EAX = file length in bytes
1165 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
1166 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
1167 ; for searching for directories.
1178 call allocate_file ; Temporary file structure for directory
1184 cmp byte [di],'/' ; If filename begins with slash
1186 inc di ; Skip leading slash
1187 mov si,RootDir ; Reference root directory instead
1189 mov eax,[si+dir_clust]
1190 mov [bx+file_left],eax
1191 mov eax,[si+dir_lba]
1192 mov [bx+file_sector],eax
1193 mov edx,[si+dir_len]
1204 mov [di-1],byte 0 ; Terminate at directory name
1205 mov cl,02h ; Search for directory
1208 push di ; Save these...
1211 ; Create recursion stack frame...
1212 push word .resume ; Where to "return" to
1217 ; Get a chunk of the directory
1218 ; This relies on the fact that ISOLINUX doesn't change SI
1228 movzx eax,byte [si] ; Length of directory entry
1234 test cl, byte 8Eh ; Unwanted file attributes!
1237 movzx cx,byte [si+32] ; File identifier length
1238 add si,byte 33 ; File identifier offset
1240 call iso_compare_names
1244 sub edx,eax ; Decrease bytes left
1246 add si,ax ; Advance pointer
1249 ; Did we finish the buffer?
1250 cmp si,trackbuf+trackbufsize
1251 jb .compare ; No, keep going
1253 jmp short .getsome ; Get some more directory
1256 ; Advance to the beginning of next sector
1257 lea ax,[si+SECTOR_SIZE-1]
1258 and ax,~(SECTOR_SIZE-1)
1260 jmp short .not_file ; We still need to do length checks
1262 .failure: xor eax,eax ; ZF = 1
1263 mov [bx+file_sector],eax
1268 mov eax,[si+2] ; Location of extent
1269 mov [bx+file_sector],eax
1270 mov eax,[si+10] ; Data length
1272 add eax,SECTOR_SIZE-1
1273 shr eax,SECTOR_SHIFT
1274 mov [bx+file_left],eax
1283 .resume: ; We get here if we were only doing part of a lookup
1284 ; This relies on the fact that .success returns bx == si
1285 xchg edx,eax ; Directory length in edx
1286 pop cx ; Old ISOFlags
1287 pop di ; Next filename pointer
1288 mov byte [di-1], '/' ; Restore slash
1289 mov [ISOFlags],cl ; Restore the flags
1290 jz .failure ; Did we fail? If so fail for real!
1291 jmp .look_for_slash ; Otherwise, next level
1294 ; allocate_file: Allocate a file structure
1307 .check: cmp dword [bx], byte 0
1309 add bx,open_file_t_size ; ZF = 0
1311 ; ZF = 0 if we fell out of the loop
1316 ; iso_compare_names:
1317 ; Compare the names DS:SI and DS:DI and report if they are
1318 ; equal from an ISO 9660 perspective. SI is the name from
1319 ; the filesystem; CX indicates its length, and ';' terminates.
1320 ; DI is expected to end with a null.
1322 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
1326 ; First, terminate and canonicalize input filename
1329 .canon_loop: jcxz .canon_end
1337 cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun
1342 cmp byte [di-1],'.' ; Remove terminal dots
1345 jmp short .canon_end
1347 mov [di],byte 0 ; Null-terminate string
1355 jz .success ; End of string for both
1356 and al,al ; Is either one end of string?
1357 jz .failure ; If so, failure
1360 or ax,2020h ; Convert to lower case
1363 .failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
1367 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1368 ; to by ES:DI; ends on encountering any whitespace.
1370 ; This verifies that a filename is < FILENAME_MAX characters,
1371 ; doesn't contain whitespace, zero-pads the output buffer,
1372 ; and removes trailing dots and redundant slashes,
1373 ; so "repe cmpsb" can do a compare, and the
1374 ; path-searching routine gets a bit of an easier job.
1379 mov cx,FILENAME_MAX-1
1384 cmp al,' ' ; If control or space, end
1386 cmp al,ah ; Repeated slash?
1393 .mn_skip: loop .mn_loop
1395 cmp bx,di ; At the beginning of the buffer?
1397 cmp byte [di-1],'.' ; Terminal dot?
1399 cmp byte [di-1],'/' ; Terminal slash?
1401 .mn_kill: dec di ; If so, remove it
1405 inc cx ; At least one null byte
1406 xor ax,ax ; Zero-fill name
1412 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1413 ; filename to the conventional representation. This is needed
1414 ; for the BOOT_IMAGE= parameter for the kernel.
1415 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1416 ; known to be shorter.
1418 ; DS:SI -> input mangled file name
1419 ; ES:DI -> output buffer
1421 ; On return, DI points to the first byte after the output name,
1422 ; which is set to a null byte.
1424 unmangle_name: call strcpy
1425 dec di ; Point to final null byte
1429 ; getfssec: Get multiple clusters from a file, given the file pointer.
1433 ; SI -> File pointer
1434 ; CX -> Cluster count
1436 ; SI -> File pointer (or 0 on EOF)
1447 cmp ecx,[si+file_left]
1449 mov ecx,[si+file_left]
1455 mov eax,[si+file_sector]
1462 add [si+file_sector],ecx
1463 sub [si+file_left],ecx
1464 ja .not_eof ; CF = 0
1467 mov [si+file_sector],ecx ; Mark as unused
1476 ; -----------------------------------------------------------------------------
1478 ; -----------------------------------------------------------------------------
1480 %include "getc.inc" ; getc et al
1481 %include "conio.inc" ; Console I/O
1482 %include "parseconfig.inc" ; High-level config file handling
1483 %include "parsecmd.inc" ; Low-level config file handling
1484 %include "bcopy32.inc" ; 32-bit bcopy
1485 %include "loadhigh.inc" ; Load a file into high memory
1486 %include "font.inc" ; VGA font stuff
1487 %include "graphics.inc" ; VGA graphics
1488 %include "highmem.inc" ; High memory sizing
1489 %include "strcpy.inc" ; strcpy()
1490 %include "rawcon.inc" ; Console I/O w/o using the console functions
1492 ; -----------------------------------------------------------------------------
1493 ; Begin data section
1494 ; -----------------------------------------------------------------------------
1498 boot_prompt db 'boot: ', 0
1499 wipe_char db BS, ' ', BS, 0
1500 err_notfound db 'Could not find kernel image: ',0
1501 err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1502 err_noram db 'It appears your computer has less than '
1504 db 'K of low ("DOS")'
1506 db 'RAM. Linux needs at least this amount to boot. If you get'
1508 db 'this message in error, hold down the Ctrl key while'
1510 db 'booting, and I will take your word for it.', CR, LF, 0
1511 err_badcfg db 'Unknown keyword in config file.', CR, LF, 0
1512 err_noparm db 'Missing parameter in config file.', CR, LF, 0
1513 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1514 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1515 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1516 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1518 err_notdos db ': attempted DOS system call', CR, LF, 0
1519 err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1520 err_bssimage db 'BSS images not supported.', CR, LF, 0
1521 err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1522 notfound_msg db 'not found', CR, LF, 0
1523 localboot_msg db 'Booting from local disk...', CR, LF, 0
1524 cmdline_msg db 'Command line: ', CR, LF, 0
1525 ready_msg db 'Ready.', CR, LF, 0
1526 trying_msg db 'Trying to load: ', 0
1527 crlfloading_msg db CR, LF ; Fall through
1528 loading_msg db 'Loading ', 0
1531 fourbs_msg db BS, BS, BS, BS, 0
1532 aborted_msg db ' aborted.', CR, LF, 0
1533 crff_msg db CR, FF, 0
1534 default_str db 'default', 0
1535 default_len equ ($-default_str)
1536 boot_dir db '/boot' ; /boot/isolinux
1537 isolinux_dir db '/isolinux', 0
1539 isolinux_cfg db 'isolinux.cfg', 0
1540 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
1542 %ifdef DEBUG_MESSAGES
1543 dbg_rootdir_msg db 'Root directory at LBA = ', 0
1544 dbg_isodir_msg db 'isolinux directory at LBA = ', 0
1545 dbg_config_msg db 'About to load config file...', CR, LF, 0
1546 dbg_configok_msg db 'Configuration file opened...', CR, LF, 0
1549 ; Command line options we'd like to take a look at
1551 ; mem= and vga= are handled as normal 32-bit integer values
1552 initrd_cmd db 'initrd='
1553 initrd_cmd_len equ 7
1556 ; Config file keyword table
1558 %include "keywords.inc"
1561 ; Extensions to search for (in *forward* order).
1564 exten_table: db '.cbt' ; COMBOOT (specific)
1565 db '.img' ; Disk image
1566 db '.bin' ; CD boot sector
1567 db '.com' ; COMBOOT (same as DOS)
1570 dd 0, 0 ; Need 8 null bytes here
1573 ; Floppy image table
1576 img_table_count equ 3
1578 dd 1200*1024 ; 1200K floppy
1579 db 1 ; Emulation type
1580 db 80-1 ; Max cylinder
1584 dd 1440*1024 ; 1440K floppy
1585 db 2 ; Emulation type
1586 db 80-1 ; Max cylinder
1590 dd 2880*1024 ; 2880K floppy
1591 db 3 ; Emulation type
1592 db 80-1 ; Max cylinder
1597 ; Misc initialized (data) variables
1601 ; Spec packet for disk image emulation
1604 dspec_packet: db 13h ; Size of packet
1605 dsp_media: db 0 ; Media type
1606 dsp_drive: db 0 ; Drive number
1607 dsp_controller: db 0 ; Controller index
1608 dsp_lba: dd 0 ; LBA for emulated disk image
1609 dsp_devspec: dw 0 ; IDE/SCSI information
1610 dsp_buffer: dw 0 ; User-provided buffer
1611 dsp_loadseg: dw 0 ; Load segment
1612 dsp_sectors: dw 1 ; Sector count
1613 dsp_chs: db 0,0,0 ; Simulated CHS geometry
1614 dsp_dummy: db 0 ; Scratch, safe to overwrite
1617 ; Variables that are uninitialized in SYSLINUX but initialized here
1619 ; **** ISOLINUX:: We may have to make this flexible, based on what the
1620 ; **** BIOS expects our "sector size" to be.
1623 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1624 BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1625 BufSafeBytes dw trackbufsize ; = how many bytes?
1626 EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1628 %if ( trackbufsize % SECTOR_SIZE ) != 0
1629 %error trackbufsize must be a multiple of SECTOR_SIZE