1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
6 ; A program to boot Linux kernels off a CD-ROM using the El Torito
7 ; boot standard in "no emulation" mode, making the entire filesystem
8 ; available. It is based on the SYSLINUX boot loader for MS-DOS
11 ; Copyright (C) 1994-2006 H. Peter Anvin
13 ; This program is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
16 ; Boston MA 02111-1307, USA; either version 2 of the License, or
17 ; (at your option) any later version; incorporated herein by reference.
19 ; ****************************************************************************
25 ; Some semi-configurable constants... change on your own risk.
28 FILENAME_MAX_LG2
equ 8 ; log2(Max filename size Including final null)
29 FILENAME_MAX
equ (1 << FILENAME_MAX_LG2
)
30 NULLFILE
equ 0 ; Zero byte == null file name
31 NULLOFFSET
equ 0 ; Position in which to look
32 retry_count
equ 6 ; How patient are we with the BIOS?
33 %assign HIGHMEM_SLOP
128*1024 ; Avoid this much memory near the top
34 MAX_OPEN_LG2
equ 6 ; log2(Max number of open files)
35 MAX_OPEN
equ (1 << MAX_OPEN_LG2
)
36 SECTOR_SHIFT
equ 11 ; 2048 bytes/sector (El Torito requirement)
37 SECTOR_SIZE
equ (1 << SECTOR_SHIFT
)
40 ; This is what we need to do when idle
50 ; The following structure is used for "virtual kernels"; i.e. LILO-style
51 ; option labels. The options we permit here are `kernel' and `append
52 ; Since there is no room in the bottom 64K for all of these, we
53 ; stick them at vk_seg:0000 and copy them down before we need them.
56 vk_vname: resb FILENAME_MAX
; Virtual name **MUST BE FIRST!**
57 vk_rname: resb FILENAME_MAX
; Real name
59 vk_type: resb
1 ; Type of file
61 vk_append: resb max_cmd_len
+1 ; Command line
63 vk_end: equ $
; Should be <= vk_size
67 ; Segment assignments in the bottom 640K
68 ; 0000h - main code/data segment (and BIOS segment)
70 real_mode_seg
equ 3000h
71 vk_seg
equ 2000h ; Virtual kernels
72 xfer_buf_seg
equ 1000h ; Bounce buffer for I/O to high mem
73 comboot_seg
equ real_mode_seg
; COMBOOT image loading zone
76 ; File structure. This holds the information for each currently open file.
79 file_sector resd
1 ; Sector pointer (0 = structure free)
80 file_left resd
1 ; Number of sectors left
84 %if
(open_file_t_size
& (open_file_t_size
-1))
85 %error
"open_file_t is not a power of 2"
90 dir_lba resd
1 ; Directory start (LBA)
91 dir_len resd
1 ; Length in bytes
92 dir_clust resd
1 ; Length in clusters
95 ; ---------------------------------------------------------------------------
97 ; ---------------------------------------------------------------------------
100 ; Memory below this point is reserved for the BIOS and the MBR
103 trackbufsize
equ 8192
104 trackbuf resb trackbufsize
; Track buffer goes here
105 getcbuf resb trackbufsize
108 ; Some of these are touched before the whole image
109 ; is loaded. DO NOT move this to .uibss.
112 ISOFileName resb
64 ; ISO filename canonicalization buffer
114 CurDir resb dir_t_size
; Current directory
115 RootDir resb dir_t_size
; Root directory
116 FirstSecSum resd
1 ; Checksum of bytes 64-2048
117 ImageDwords resd
1 ; isolinux.bin size, dwords
118 InitStack resd
1 ; Initial stack pointer (SS:SP)
119 DiskSys resw
1 ; Last INT 13h call
120 ImageSectors resw
1 ; isolinux.bin size, sectors
121 DiskError resb
1 ; Error code for disk I/O
122 DriveNumber resb
1 ; CD-ROM BIOS drive number
123 ISOFlags resb
1 ; Flags for ISO directory search
124 RetryCount resb
1 ; Used for disk access retries
129 ; El Torito spec packet
133 spec_packet: resb
1 ; Size of packet
134 sp_media: resb
1 ; Media type
135 sp_drive: resb
1 ; Drive number
136 sp_controller: resb
1 ; Controller index
137 sp_lba: resd
1 ; LBA for emulated disk image
138 sp_devspec: resw
1 ; IDE/SCSI information
139 sp_buffer: resw
1 ; User-provided buffer
140 sp_loadseg: resw
1 ; Load segment
141 sp_sectors: resw
1 ; Sector count
142 sp_chs: resb
3 ; Simulated CHS geometry
143 sp_dummy: resb
1 ; Scratch, safe to overwrite
146 ; EBIOS drive parameter packet
149 drive_params: resw
1 ; Buffer size
150 dp_flags: resw
1 ; Information flags
151 dp_cyl: resd
1 ; Physical cylinders
152 dp_head: resd
1 ; Physical heads
153 dp_sec: resd
1 ; Physical sectors/track
154 dp_totalsec: resd
2 ; Total sectors
155 dp_secsize: resw
1 ; Bytes per sector
156 dp_dpte: resd
1 ; Device Parameter Table
157 dp_dpi_key: resw
1 ; 0BEDDh if rest valid
158 dp_dpi_len: resb
1 ; DPI len
161 dp_bus: resb
4 ; Host bus type
162 dp_interface: resb
8 ; Interface type
163 db_i_path: resd
2 ; Interface path
164 db_d_path: resd
2 ; Device path
166 db_dpi_csum: resb
1 ; Checksum for DPI info
169 ; EBIOS disk address packet
172 dapa: resw
1 ; Packet size
173 .
count: resw
1 ; Block count
174 .
off: resw
1 ; Offset of buffer
175 .
seg: resw
1 ; Segment of buffer
176 .
lba: resd
2 ; LBA (LSW, MSW)
179 ; Spec packet for disk image emulation
182 dspec_packet: resb
1 ; Size of packet
183 dsp_media: resb
1 ; Media type
184 dsp_drive: resb
1 ; Drive number
185 dsp_controller: resb
1 ; Controller index
186 dsp_lba: resd
1 ; LBA for emulated disk image
187 dsp_devspec: resw
1 ; IDE/SCSI information
188 dsp_buffer: resw
1 ; User-provided buffer
189 dsp_loadseg: resw
1 ; Load segment
190 dsp_sectors: resw
1 ; Sector count
191 dsp_chs: resb
3 ; Simulated CHS geometry
192 dsp_dummy: resb
1 ; Scratch, safe to overwrite
196 _spec_len
equ _spec_end
- _spec_start
198 alignb open_file_t_size
199 Files resb MAX_OPEN
*open_file_t_size
202 ; Constants for the xfer_buf_seg
204 ; The xfer_buf_seg is also used to store message file buffers. We
205 ; need two trackbuffers (text and graphics), plus a work buffer
206 ; for the graphics decompressor.
208 xbs_textbuf
equ 0 ; Also hard-coded, do not change
209 xbs_vgabuf
equ trackbufsize
210 xbs_vgatmpbuf
equ 2*trackbufsize
214 ;; Primary entry point. Because BIOSes are buggy, we only load the first
215 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
218 StackBuf
equ $
-44 ; 44 bytes needed for
219 ; the bootsector chainloading
221 OrigESDI
equ StackBuf
-4 ; The high dword on the stack
225 _start: ; Far jump makes sure we canonicalize the address
228 times
8-($
-$$
) nop ; Pad to file offset 8
230 ; This table hopefully gets filled in by mkisofs using the
231 ; -boot-info-table option. If not, the values in this
232 ; table are default values that we can use to get us what
233 ; we need, at least under a certain set of assumptions.
234 bi_pvd: dd 16 ; LBA of primary volume descriptor
235 bi_file: dd 0 ; LBA of boot file
236 bi_length: dd 0xdeadbeef ; Length of boot file
237 bi_csum: dd 0xdeadbeef ; Checksum of boot file
238 bi_reserved: times
10 dd 0xdeadbeef ; Reserved
240 _start1: mov [cs:InitStack
],sp ; Save initial stack pointer
241 mov [cs:InitStack
+2],ss
244 mov sp,StackBuf
; Set up stack
245 push es ; Save initial ES:DI -> $PnP pointer
255 mov si,syslinux_banner
257 %ifdef DEBUG_MESSAGES
263 ; Before modifying any memory, get the checksum of bytes
266 initial_csum: xor edi,edi
268 mov cx,(SECTOR_SIZE
-64) >> 2
272 mov [FirstSecSum
],edi
275 %ifdef DEBUG_MESSAGES
283 ; Initialize spec packet buffers
286 mov cx,_spec_len
>> 2
290 ; Initialize length field of the various packets
291 mov byte [spec_packet
],13h
292 mov byte [drive_params
],30
294 mov byte [dspec_packet
],13h
296 ; Other nonzero fields
297 inc word [dsp_sectors
]
299 ; Now figure out what we're actually doing
300 ; Note: use passed-in DL value rather than 7Fh because
301 ; at least some BIOSes will get the wrong value otherwise
302 mov ax,4B01h ; Get disk emulation status
306 jc award_hack
; changed for BrokenAwardHack
308 cmp [sp_drive
],dl ; Should contain the drive number
309 jne spec_query_failed
311 %ifdef DEBUG_MESSAGES
314 mov al,byte [sp_drive
]
320 ; Alright, we have found the drive. Now, try to find the
321 ; boot file itself. If we have a boot info table, life is
322 ; good; if not, we have to make some assumptions, and try
323 ; to figure things out ourselves. In particular, the
324 ; assumptions we have to make are:
325 ; - single session only
326 ; - only one boot entry (no menu or other alternatives)
328 cmp dword [bi_file
],0 ; Address of code to load
329 jne found_file
; Boot info table present :)
331 %ifdef DEBUG_MESSAGES
332 mov si,noinfotable_msg
336 ; No such luck. See if the the spec packet contained one.
339 jz set_file
; Good enough
341 %ifdef DEBUG_MESSAGES
342 mov si,noinfoinspec_msg
346 ; No such luck. Get the Boot Record Volume, assuming single
347 ; session disk, and that we're the first entry in the chain
348 mov eax,17 ; Assumed address of BRV
352 mov eax,[trackbuf
+47h] ; Get boot catalog address
354 call getonesec
; Get boot catalog
356 mov eax,[trackbuf
+28h] ; First boot entry
357 ; And hope and pray this is us...
359 ; Some BIOSes apparently have limitations on the size
360 ; that may be loaded (despite the El Torito spec being very
361 ; clear on the fact that it must all be loaded.) Therefore,
362 ; we load it ourselves, and *bleep* the BIOS.
368 ; Set up boot file sizes
370 sub eax,SECTOR_SIZE
-3
371 shr eax,2 ; bytes->dwords
372 mov [ImageDwords
],eax ; boot file dwords
374 shr eax,9 ; dwords->sectors
375 mov [ImageSectors
],ax ; boot file sectors
377 mov eax,[bi_file
] ; Address of code to load
378 inc eax ; Don't reload bootstrap code
379 %ifdef DEBUG_MESSAGES
386 ; Just in case some BIOSes have problems with
387 ; segment wraparound, use the normalized address
388 mov bx,((7C00h
+2048) >> 4)
391 mov bp,[ImageSectors
]
392 %ifdef DEBUG_MESSAGES
406 %ifdef DEBUG_MESSAGES
411 ; Verify the checksum on the loaded image.
415 mov ecx,[ImageDwords
]
416 mov edi,[FirstSecSum
] ; First sector checksum
423 ; SI wrapped around, advance ES
437 %ifdef DEBUG_MESSAGES
441 jmp all_read
; Jump to main code
443 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
444 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
445 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
447 ;; There is a problem with certain versions of the AWARD BIOS ...
448 ;; the boot sector will be loaded and executed correctly, but, because the
449 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
450 ;; load the spec packet will fail. We scan for the equivalent of
459 ;; and use <direct far> as the new vector for int 13. The code above is
460 ;; used to load the boot code into ram, and there should be no reason
461 ;; for anybody to change it now or in the future. There are no opcodes
462 ;; that use encodings relativ to IP, so scanning is easy. If we find the
463 ;; code above in the BIOS code we can be pretty sure to run on a machine
464 ;; with an broken AWARD BIOS ...
466 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
468 %ifdef DEBUG_MESSAGES
;;
470 award_notice
db "Trying BrokenAwardHack first ...",CR
,LF
,0 ;;
471 award_not_orig
db "BAH: Original Int 13 vector : ",0 ;;
472 award_not_new
db "BAH: Int 13 vector changed to : ",0 ;;
473 award_not_succ
db "BAH: SUCCESS",CR
,LF
,0 ;;
474 award_not_fail
db "BAH: FAILURE" ;;
475 award_not_crlf
db CR
,LF
,0 ;;
479 award_oldint13
dd 0 ;;
480 award_string
db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah
,80h,1,09ch,09ah ;;
482 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
483 award_hack: mov si,spec_err_msg
; Moved to this place from
484 call writemsg
; spec_query_faild
486 %ifdef DEBUG_MESSAGES
;
488 mov si,award_notice
; display our plan
490 mov si,award_not_orig
; display original int 13
491 call writemsg
; vector
494 mov [award_oldint13
],eax ;
496 %ifdef DEBUG_MESSAGES
;
499 mov si,award_not_crlf
;
503 mov ax,0f000h
; ES = BIOS Seg
506 xor di,di ; start at ES:DI = f000:0
507 award_loop: push di ; save DI
508 mov si,award_string
; scan for award_string
509 mov cx,7 ; length of award_string = 7dw
512 jcxz award_found
; jmp if found
513 inc di ; not found, inc di
516 award_failed: pop es ; No, not this way :-((
519 %ifdef DEBUG_MESSAGES
;
521 mov si,award_not_fail
; display failure ...
524 mov eax,[award_oldint13
] ; restore the original int
525 or eax,eax ; 13 vector if there is one
526 jz spec_query_failed
; and try other workarounds
528 jmp spec_query_failed
;
530 award_found: mov eax,[es:di+0eh
] ; load possible int 13 addr
533 cmp eax,[award_oldint13
] ; give up if this is the
534 jz award_failed
; active int 13 vector,
535 mov [13h*4],eax ; otherwise change 0:13h*4
538 %ifdef DEBUG_MESSAGES
;
540 push eax ; display message and
541 mov si,award_not_new
; new vector address
545 mov si,award_not_crlf
;
548 mov ax,4B01h ; try to read the spec packet
549 mov dl,[DriveNumber
] ; now ... it should not fail
550 mov si,spec_packet
; any longer
554 %ifdef DEBUG_MESSAGES
;
556 mov si,award_not_succ
; display our SUCCESS
559 jmp found_drive
; and leave error recovery code
561 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
562 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
563 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
566 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
567 ; Try to scan the entire 80h-FFh from the end.
571 ; some code moved to BrokenAwardHack
577 mov byte [si],13 ; Size of buffer
588 cmp byte [sp_drive
],dl
591 ; Okay, good enough...
595 .
found_drive: jmp found_drive
597 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
598 ; but if this was the drive number originally passed in
599 ; DL then consider it "good enough"
601 cmp byte [DriveNumber
],dl
604 .
still_broken: dec dx
608 ; No spec packet anywhere. Some particularly pathetic
609 ; BIOSes apparently don't even implement function
610 ; 4B01h, so we can't query a spec packet no matter
611 ; what. If we got a drive number in DL, then try to
612 ; use it, and if it works, then well...
614 cmp dl,81h ; Should be 81-FF at least
615 jb fatal_error
; If not, it's hopeless
617 ; Write a warning to indicate we're on *very* thin ice now
625 jmp .found_drive
; Pray that this works...
631 .
norge: jmp short .norge
633 ; Information message (DS:SI) output
634 ; Prefix with "isolinux: "
646 ; Write a character to the screen. There is a more "sophisticated"
647 ; version of this in the subsequent code, so we patch the pointer
652 jmp near writechr_simple
; 3-byte jump
665 ; int13: save all the segment registers and call INT 13h
666 ; Some CD-ROM BIOSes have been found to corrupt segment registers.
682 ; Get one sector. Convenience entry point.
686 ; Fall through to getlinsec
689 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
691 ; Note that we can't always do this as a single request, because at least
692 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
693 ; to 32 sectors (64K) per request.
696 ; EAX - Linear sector number
697 ; ES:BX - Target buffer
701 mov si,dapa
; Load up the DAPA
707 push bp ; Sectors left
715 mov ah,42h ; Extended Read
719 movzx eax,word [si+2] ; Sectors we read
720 add [si+8],eax ; Advance sector pointer
721 sub bp,ax ; Sectors left
722 shl ax,SECTOR_SHIFT
-4 ; 2048-byte sectors -> segment
723 add [si+6],ax ; Advance buffer pointer
726 mov eax,[si+8] ; Next sector
730 xint13: mov byte [RetryCount
],retry_count
734 add sp,byte 8*4 ; Clean up stack
737 mov [DiskError
],ah ; Save error code
739 mov [DiskSys
],ax ; Save system call number
740 dec byte [RetryCount
]
744 mov ah,[dapa
+2] ; Sector transfer count
745 cmp al,2 ; Only 2 attempts left
747 mov ah,1 ; Drop transfer size to 1
751 ja .again
; First time, just try again
752 shr ah,1 ; Otherwise, try to reduce
753 adc ah,0 ; the max transfer size, but not to 0
761 .
real_error: mov si,diskerr_msg
774 ; Fall through to kaboom
777 ; kaboom: write a message and bail out. Wait for a user keypress,
778 ; then do a hard reboot.
781 RESET_STACK_AND_SEGS
AX
782 mov si,err_bootfailed
786 mov word [BIOS_magic
],0 ; Cold reboot
787 jmp 0F000h:0FFF0h
; Reset vector address
789 ; -----------------------------------------------------------------------------
790 ; Common modules needed in the first sector
791 ; -----------------------------------------------------------------------------
793 %include "writestr.inc" ; String output
794 writestr
equ cwritestr
795 %include "writehex.inc" ; Hexadecimal output
797 ; -----------------------------------------------------------------------------
798 ; Data that needs to be in the first sector
799 ; -----------------------------------------------------------------------------
801 syslinux_banner
db CR
, LF
, 'ISOLINUX ', version_str
, ' ', date
, ' ', 0
802 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
804 isolinux_str
db 'isolinux: ', 0
805 %ifdef DEBUG_MESSAGES
806 startup_msg: db 'Starting up, DL = ', 0
807 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
808 secsize_msg: db 'Sector size appears to be ', 0
809 offset_msg: db 'Loading main image from LBA = ', 0
810 size_msg: db 'Sectors to load = ', 0
811 loaded_msg: db 'Loaded boot image, verifying...', CR
, LF
, 0
812 verify_msg: db 'Image checksum verified.', CR
, LF
, 0
813 allread_msg
db 'Main image read, jumping to main code...', CR
, LF
, 0
815 noinfotable_msg
db 'No boot info table, assuming single session disk...', CR
, LF
, 0
816 noinfoinspec_msg
db 'Spec packet missing LBA information, trying to wing it...', CR
, LF
, 0
817 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR
, LF
, 0
818 maybe_msg: db 'Found something at drive = ', 0
819 alright_msg: db 'Looks like it might be right, continuing...', CR
, LF
, 0
820 nospec_msg
db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0
821 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR
, LF
822 trysbm_msg
db 'See http://syslinux.zytor.com/sbm for more information.', CR
, LF
, 0
823 diskerr_msg: db 'Disk error ', 0
824 oncall_str: db ', AX = ',0
825 ondrive_str: db ', drive ', 0
826 checkerr_msg: db 'Image checksum error, sorry...', CR
, LF
, 0
828 err_bootfailed
db CR
, LF
, 'Boot failed: press a key to retry...'
829 bailmsg
equ err_bootfailed
834 MaxTransfer
dw 32 ; Max sectors per transfer
836 rl_checkpt
equ $
; Must be <= 800h
838 rl_checkpt_off
equ ($
-$$
)
840 ;%if rl_checkpt_off > 0x800
841 ;%error "Sector 0 overflow"
845 ; ----------------------------------------------------------------------------
846 ; End of code and data that have to be in the first sector
847 ; ----------------------------------------------------------------------------
856 ; Common initialization code
859 %include "cpuinit.inc"
861 ; Patch the writechr routine to point to the full code
862 mov word [writechr
+1], writechr_full
-(writechr
+3)
864 ; Tell the user we got this far...
865 %ifndef DEBUG_MESSAGES
; Gets messy with debugging on
871 ; Now we're all set to start with our *real* business. First load the
872 ; configuration file (if any) and parse it.
874 ; In previous versions I avoided using 32-bit registers because of a
875 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
876 ; random. I figure, though, that if there are any of those still left
877 ; they probably won't be trying to install Linux on them...
879 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
880 ; to take'm out. In fact, we may want to put them back if we're going
881 ; to boot ELKS at some point.
885 ; Now, we need to sniff out the actual filesystem data structures.
886 ; mkisofs gave us a pointer to the primary volume descriptor
887 ; (which will be at 16 only for a single-session disk!); from the PVD
888 ; we should be able to find the rest of what we need to know.
895 mov eax,[trackbuf
+156+2]
896 mov [RootDir
+dir_lba
],eax
897 mov [CurDir
+dir_lba
],eax
898 %ifdef DEBUG_MESSAGES
899 mov si,dbg_rootdir_msg
904 mov eax,[trackbuf
+156+10]
905 mov [RootDir
+dir_len
],eax
906 mov [CurDir
+dir_len
],eax
907 add eax,SECTOR_SIZE
-1
909 mov [RootDir
+dir_clust
],eax
910 mov [CurDir
+dir_clust
],eax
912 ; Look for an isolinux directory, and if found,
913 ; make it the current directory instead of the root
915 mov di,boot_dir
; Search for /boot/isolinux
920 mov al,02h ; Search for /isolinux
924 mov [CurDir
+dir_len
],eax
925 mov eax,[si+file_left
]
926 mov [CurDir
+dir_clust
],eax
927 xor eax,eax ; Free this file pointer entry
928 xchg eax,[si+file_sector
]
929 mov [CurDir
+dir_lba
],eax
930 %ifdef DEBUG_MESSAGES
932 mov si,dbg_isodir_msg
941 ; Locate the configuration file
944 %ifdef DEBUG_MESSAGES
945 mov si,dbg_config_msg
955 jz no_config_file
; Not found or empty
957 %ifdef DEBUG_MESSAGES
958 mov si,dbg_configok_msg
963 ; Now we have the config file open. Parse the config file and
964 ; run the user interface.
969 ; Enable disk emulation. The kind of disk we emulate is dependent on the size of
970 ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
979 mov dx,ax ; Set EDX <- file size
981 mov cx,img_table_count
982 mov eax,[si+file_sector
] ; Starting LBA of file
983 mov [dsp_lba
],eax ; Location of file
984 mov byte [dsp_drive
], 0 ; 00h floppy, 80h hard disk
993 ; Hard disk image. Need to examine the partition table
994 ; in order to deduce the C/H/S geometry. Sigh.
1001 mov cx,1 ; Load 1 sector
1004 cmp word [trackbuf
+510],0aa55h
; Boot signature
1005 jne .bad_image
; Image not bootable
1007 mov cx,4 ; 4 partition entries
1008 mov di,trackbuf
+446 ; Start of partition table
1010 xor ax,ax ; Highest sector(al) head(ah)
1024 push edx ; File size
1027 inc bx ; # of heads in BX
1028 xor ah,ah ; # of sectors in AX
1029 cwde ; EAX[31:16] <- 0
1031 shl eax,9 ; Convert to bytes
1032 ; Now eax contains the number of bytes per cylinder
1038 inc eax ; Fractional cylinder...
1039 ; Now (e)ax contains the number of cylinders
1040 .
no_remainder: cmp eax,1024
1042 mov ax,1024 ; Max possible #
1043 .
ok_cyl: dec ax ; Convert to max cylinder no
1044 pop ebx ; S(bl) H(bh)
1050 mov al,4 ; Hard disk boot
1051 mov byte [dsp_drive
], 80h ; Drive 80h = hard disk
1056 and bl,0F0h
; Copy controller info bits
1058 mov [dsp_media
],al ; Emulation type
1060 mov [dsp_chs
],eax ; C/H/S geometry
1061 mov ax,[sp_devspec
] ; Copy device spec
1062 mov [dsp_devspec
],ax
1063 mov al,[sp_controller
] ; Copy controller index
1064 mov [dsp_controller
],al
1067 call vgaclearmode
; Reset video
1069 mov ax,4C00h
; Enable emulation and boot
1071 mov dl,[DriveNumber
]
1077 ; If this returns, we have problems
1079 mov si,err_disk_image
1084 ; Look for the highest seen H/S geometry
1085 ; We compute cylinders separately
1088 mov bl,[si] ; Head #
1091 mov ah,bl ; New highest head #
1092 .
done_track: mov bl,[si+1]
1093 and bl,3Fh
; Sector #
1100 ; Boot a specified local disk. AX specifies the BIOS disk number; or
1101 ; 0xFFFF in case we should execute INT 18h ("next device.")
1105 lss sp,[cs:Stack
] ; Restore stack pointer
1111 mov si,localboot_msg
1116 ; Load boot sector from the specified BIOS device and jump to it.
1120 xor ax,ax ; Reset drive
1122 mov ax,0201h ; Read one sector
1123 mov cx,0001h ; C/H/S = 0/0/1 (first sector)
1127 cli ; Abandon hope, ye who enter here
1130 mov cx,512 ; Probably overkill, but should be safe
1132 lss sp,[cs:InitStack
]
1133 jmp 0:07C00h
; Jump to new boot sector
1136 int 18h ; Hope this does the right thing...
1137 jmp kaboom
; If we returned, oh boy...
1141 ; Deallocates a file structure (pointer in SI)
1147 mov dword [si],0 ; First dword == file_left
1160 ; DX:AX or EAX = file length in bytes
1164 ; Assumes CS == DS == ES, and trashes BX and CX.
1166 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
1167 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
1168 ; for searching for directories.
1179 call allocate_file
; Temporary file structure for directory
1185 cmp byte [di],'/' ; If filename begins with slash
1187 inc di ; Skip leading slash
1188 mov si,RootDir
; Reference root directory instead
1190 mov eax,[si+dir_clust
]
1191 mov [bx+file_left
],eax
1192 mov eax,[si+dir_lba
]
1193 mov [bx+file_sector
],eax
1194 mov edx,[si+dir_len
]
1205 mov [di-1],byte 0 ; Terminate at directory name
1206 mov cl,02h ; Search for directory
1209 push di ; Save these...
1212 ; Create recursion stack frame...
1213 push word .resume
; Where to "return" to
1218 ; Get a chunk of the directory
1219 ; This relies on the fact that ISOLINUX doesn't change SI
1229 movzx eax,byte [si] ; Length of directory entry
1235 test cl, byte 8Eh
; Unwanted file attributes!
1238 movzx cx,byte [si+32] ; File identifier length
1239 add si,byte 33 ; File identifier offset
1241 call iso_compare_names
1245 sub edx,eax ; Decrease bytes left
1247 add si,ax ; Advance pointer
1250 ; Did we finish the buffer?
1251 cmp si,trackbuf
+trackbufsize
1252 jb .compare
; No, keep going
1254 jmp short .getsome
; Get some more directory
1257 ; Advance to the beginning of next sector
1258 lea ax,[si+SECTOR_SIZE
-1]
1259 and ax,~
(SECTOR_SIZE
-1)
1261 jmp short .not_file
; We still need to do length checks
1263 .
failure: xor eax,eax ; ZF = 1
1264 mov [bx+file_sector
],eax
1269 mov eax,[si+2] ; Location of extent
1270 mov [bx+file_sector
],eax
1271 mov eax,[si+10] ; Data length
1273 add eax,SECTOR_SIZE
-1
1274 shr eax,SECTOR_SHIFT
1275 mov [bx+file_left
],eax
1284 .
resume: ; We get here if we were only doing part of a lookup
1285 ; This relies on the fact that .success returns bx == si
1286 xchg edx,eax ; Directory length in edx
1287 pop cx ; Old ISOFlags
1288 pop di ; Next filename pointer
1289 mov byte [di-1], '/' ; Restore slash
1290 mov [ISOFlags
],cl ; Restore the flags
1291 jz .failure
; Did we fail? If so fail for real!
1292 jmp .look_for_slash
; Otherwise, next level
1295 ; allocate_file: Allocate a file structure
1308 .
check: cmp dword [bx], byte 0
1310 add bx,open_file_t_size
; ZF = 0
1312 ; ZF = 0 if we fell out of the loop
1317 ; iso_compare_names:
1318 ; Compare the names DS:SI and DS:DI and report if they are
1319 ; equal from an ISO 9660 perspective. SI is the name from
1320 ; the filesystem; CX indicates its length, and ';' terminates.
1321 ; DI is expected to end with a null.
1323 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
1327 ; First, terminate and canonicalize input filename
1330 .
canon_loop: jcxz .canon_end
1338 cmp di,ISOFileNameEnd
-1 ; Guard against buffer overrun
1343 cmp byte [di-1],'.' ; Remove terminal dots
1346 jmp short .canon_end
1348 mov [di],byte 0 ; Null-terminate string
1356 jz .success
; End of string for both
1357 and al,al ; Is either one end of string?
1358 jz .failure
; If so, failure
1361 or ax,2020h ; Convert to lower case
1364 .
failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
1368 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1369 ; to by ES:DI; ends on encountering any whitespace.
1372 ; This verifies that a filename is < FILENAME_MAX characters,
1373 ; doesn't contain whitespace, zero-pads the output buffer,
1374 ; and removes trailing dots and redundant slashes,
1375 ; so "repe cmpsb" can do a compare, and the
1376 ; path-searching routine gets a bit of an easier job.
1382 mov cx,FILENAME_MAX
-1
1387 cmp al,' ' ; If control or space, end
1389 cmp al,ah ; Repeated slash?
1396 .
mn_skip: loop .mn_loop
1398 cmp bx,di ; At the beginning of the buffer?
1400 cmp byte [es:di-1],'.' ; Terminal dot?
1402 cmp byte [es:di-1],'/' ; Terminal slash?
1404 .
mn_kill: dec di ; If so, remove it
1408 inc cx ; At least one null byte
1409 xor ax,ax ; Zero-fill name
1416 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1417 ; filename to the conventional representation. This is needed
1418 ; for the BOOT_IMAGE= parameter for the kernel.
1419 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1420 ; known to be shorter.
1422 ; DS:SI -> input mangled file name
1423 ; ES:DI -> output buffer
1425 ; On return, DI points to the first byte after the output name,
1426 ; which is set to a null byte.
1428 unmangle_name: call strcpy
1429 dec di ; Point to final null byte
1433 ; getfssec: Get multiple clusters from a file, given the file pointer.
1437 ; SI -> File pointer
1438 ; CX -> Cluster count
1440 ; SI -> File pointer (or 0 on EOF)
1451 cmp ecx,[si+file_left
]
1453 mov ecx,[si+file_left
]
1459 mov eax,[si+file_sector
]
1466 add [si+file_sector
],ecx
1467 sub [si+file_left
],ecx
1468 ja .not_eof
; CF = 0
1471 mov [si+file_sector
],ecx ; Mark as unused
1480 ; -----------------------------------------------------------------------------
1482 ; -----------------------------------------------------------------------------
1484 %include "getc.inc" ; getc et al
1485 %include "conio.inc" ; Console I/O
1486 %include "configinit.inc" ; Initialize configuration
1487 %include "parseconfig.inc" ; High-level config file handling
1488 %include "parsecmd.inc" ; Low-level config file handling
1489 %include "bcopy32.inc" ; 32-bit bcopy
1490 %include "loadhigh.inc" ; Load a file into high memory
1491 %include "font.inc" ; VGA font stuff
1492 %include "graphics.inc" ; VGA graphics
1493 %include "highmem.inc" ; High memory sizing
1494 %include "strcpy.inc" ; strcpy()
1495 %include "rawcon.inc" ; Console I/O w/o using the console functions
1497 ; -----------------------------------------------------------------------------
1498 ; Begin data section
1499 ; -----------------------------------------------------------------------------
1503 localboot_msg
db 'Booting from local disk...', CR
, LF
, 0
1504 default_str
db 'default', 0
1505 default_len
equ ($
-default_str
)
1506 boot_dir
db '/boot' ; /boot/isolinux
1507 isolinux_dir
db '/isolinux', 0
1508 config_name
db 'isolinux.cfg', 0
1509 err_disk_image
db 'Cannot load disk image (invalid file)?', CR
, LF
, 0
1511 %ifdef DEBUG_MESSAGES
1512 dbg_rootdir_msg
db 'Root directory at LBA = ', 0
1513 dbg_isodir_msg
db 'isolinux directory at LBA = ', 0
1514 dbg_config_msg
db 'About to load config file...', CR
, LF
, 0
1515 dbg_configok_msg
db 'Configuration file opened...', CR
, LF
, 0
1518 ; Command line options we'd like to take a look at
1520 ; mem= and vga= are handled as normal 32-bit integer values
1521 initrd_cmd
db 'initrd='
1522 initrd_cmd_len
equ 7
1525 ; Config file keyword table
1527 %include "keywords.inc"
1530 ; Extensions to search for (in *forward* order).
1533 exten_table: db '.cbt' ; COMBOOT (specific)
1534 db '.img' ; Disk image
1535 db '.bin' ; CD boot sector
1536 db '.com' ; COMBOOT (same as DOS)
1539 dd 0, 0 ; Need 8 null bytes here
1542 ; Floppy image table
1545 img_table_count
equ 3
1547 dd 1200*1024 ; 1200K floppy
1548 db 1 ; Emulation type
1549 db 80-1 ; Max cylinder
1553 dd 1440*1024 ; 1440K floppy
1554 db 2 ; Emulation type
1555 db 80-1 ; Max cylinder
1559 dd 2880*1024 ; 2880K floppy
1560 db 3 ; Emulation type
1561 db 80-1 ; Max cylinder
1566 ; Misc initialized (data) variables
1570 ; Variables that are uninitialized in SYSLINUX but initialized here
1572 ; **** ISOLINUX:: We may have to make this flexible, based on what the
1573 ; **** BIOS expects our "sector size" to be.
1576 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1577 BufSafeBytes
dw trackbufsize
; = how many bytes?
1579 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1580 %error trackbufsize must be a multiple of SECTOR_SIZE