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
60 vk_append: resb max_cmd_len
+1 ; Command line
62 vk_end: equ $
; Should be <= vk_size
66 ; Segment assignments in the bottom 640K
67 ; 0000h - main code/data segment (and BIOS segment)
69 real_mode_seg
equ 3000h
70 vk_seg
equ 2000h ; Virtual kernels
71 xfer_buf_seg
equ 1000h ; Bounce buffer for I/O to high mem
72 comboot_seg
equ real_mode_seg
; COMBOOT image loading zone
75 ; File structure. This holds the information for each currently open file.
78 file_sector resd
1 ; Sector pointer (0 = structure free)
79 file_left resd
1 ; Number of sectors left
83 %if
(open_file_t_size
& (open_file_t_size
-1))
84 %error
"open_file_t is not a power of 2"
89 dir_lba resd
1 ; Directory start (LBA)
90 dir_len resd
1 ; Length in bytes
91 dir_clust resd
1 ; Length in clusters
94 ; ---------------------------------------------------------------------------
96 ; ---------------------------------------------------------------------------
99 ; Memory below this point is reserved for the BIOS and the MBR
102 trackbufsize
equ 8192
103 trackbuf resb trackbufsize
; Track buffer goes here
104 getcbuf resb trackbufsize
109 ISOFileName resb
64 ; ISO filename canonicalization buffer
111 CurDir resb dir_t_size
; Current directory
112 RootDir resb dir_t_size
; Root directory
113 FirstSecSum resd
1 ; Checksum of bytes 64-2048
114 ImageDwords resd
1 ; isolinux.bin size, dwords
115 InitStack resd
1 ; Initial stack pointer (SS:SP)
116 DiskSys resw
1 ; Last INT 13h call
117 ImageSectors resw
1 ; isolinux.bin size, sectors
118 DiskError resb
1 ; Error code for disk I/O
119 DriveNo resb
1 ; CD-ROM BIOS drive number
120 ISOFlags resb
1 ; Flags for ISO directory search
121 RetryCount resb
1 ; Used for disk access retries
126 ; El Torito spec packet
130 spec_packet: resb
1 ; Size of packet
131 sp_media: resb
1 ; Media type
132 sp_drive: resb
1 ; Drive number
133 sp_controller: resb
1 ; Controller index
134 sp_lba: resd
1 ; LBA for emulated disk image
135 sp_devspec: resw
1 ; IDE/SCSI information
136 sp_buffer: resw
1 ; User-provided buffer
137 sp_loadseg: resw
1 ; Load segment
138 sp_sectors: resw
1 ; Sector count
139 sp_chs: resb
3 ; Simulated CHS geometry
140 sp_dummy: resb
1 ; Scratch, safe to overwrite
143 ; EBIOS drive parameter packet
146 drive_params: resw
1 ; Buffer size
147 dp_flags: resw
1 ; Information flags
148 dp_cyl: resd
1 ; Physical cylinders
149 dp_head: resd
1 ; Physical heads
150 dp_sec: resd
1 ; Physical sectors/track
151 dp_totalsec: resd
2 ; Total sectors
152 dp_secsize: resw
1 ; Bytes per sector
153 dp_dpte: resd
1 ; Device Parameter Table
154 dp_dpi_key: resw
1 ; 0BEDDh if rest valid
155 dp_dpi_len: resb
1 ; DPI len
158 dp_bus: resb
4 ; Host bus type
159 dp_interface: resb
8 ; Interface type
160 db_i_path: resd
2 ; Interface path
161 db_d_path: resd
2 ; Device path
163 db_dpi_csum: resb
1 ; Checksum for DPI info
166 ; EBIOS disk address packet
169 dapa: resw
1 ; Packet size
170 .
count: resw
1 ; Block count
171 .
off: resw
1 ; Offset of buffer
172 .
seg: resw
1 ; Segment of buffer
173 .
lba: resd
2 ; LBA (LSW, MSW)
176 ; Spec packet for disk image emulation
179 dspec_packet: resb
1 ; Size of packet
180 dsp_media: resb
1 ; Media type
181 dsp_drive: resb
1 ; Drive number
182 dsp_controller: resb
1 ; Controller index
183 dsp_lba: resd
1 ; LBA for emulated disk image
184 dsp_devspec: resw
1 ; IDE/SCSI information
185 dsp_buffer: resw
1 ; User-provided buffer
186 dsp_loadseg: resw
1 ; Load segment
187 dsp_sectors: resw
1 ; Sector count
188 dsp_chs: resb
3 ; Simulated CHS geometry
189 dsp_dummy: resb
1 ; Scratch, safe to overwrite
193 _spec_len
equ _spec_end
- _spec_start
195 alignb open_file_t_size
196 Files resb MAX_OPEN
*open_file_t_size
199 ; Constants for the xfer_buf_seg
201 ; The xfer_buf_seg is also used to store message file buffers. We
202 ; need two trackbuffers (text and graphics), plus a work buffer
203 ; for the graphics decompressor.
205 xbs_textbuf
equ 0 ; Also hard-coded, do not change
206 xbs_vgabuf
equ trackbufsize
207 xbs_vgatmpbuf
equ 2*trackbufsize
211 ;; Primary entry point. Because BIOSes are buggy, we only load the first
212 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
219 _start: ; Far jump makes sure we canonicalize the address
222 times
8-($
-$$
) nop ; Pad to file offset 8
224 ; This table hopefully gets filled in by mkisofs using the
225 ; -boot-info-table option. If not, the values in this
226 ; table are default values that we can use to get us what
227 ; we need, at least under a certain set of assumptions.
228 bi_pvd: dd 16 ; LBA of primary volume descriptor
229 bi_file: dd 0 ; LBA of boot file
230 bi_length: dd 0xdeadbeef ; Length of boot file
231 bi_csum: dd 0xdeadbeef ; Checksum of boot file
232 bi_reserved: times
10 dd 0xdeadbeef ; Reserved
234 _start1: mov [cs:InitStack
],sp ; Save initial stack pointer
235 mov [cs:InitStack
+2],ss
238 mov sp,StackBuf
; Set up stack
247 mov si,syslinux_banner
249 %ifdef DEBUG_MESSAGES
255 ; Before modifying any memory, get the checksum of bytes
258 initial_csum: xor edi,edi
260 mov cx,(SECTOR_SIZE
-64) >> 2
264 mov [FirstSecSum
],edi
267 %ifdef DEBUG_MESSAGES
275 ; Initialize spec packet buffers
278 mov cx,_spec_len
>> 2
282 ; Initialize length field of the various packets
283 mov byte [spec_packet
],13h
284 mov byte [drive_params
],30
286 mov byte [dspec_packet
],13h
288 ; Other nonzero fields
289 inc word [dsp_sectors
]
291 ; Now figure out what we're actually doing
292 ; Note: use passed-in DL value rather than 7Fh because
293 ; at least some BIOSes will get the wrong value otherwise
294 mov ax,4B01h ; Get disk emulation status
298 jc award_hack
; changed for BrokenAwardHack
300 cmp [sp_drive
],dl ; Should contain the drive number
301 jne spec_query_failed
303 %ifdef DEBUG_MESSAGES
306 mov al,byte [sp_drive
]
312 ; Alright, we have found the drive. Now, try to find the
313 ; boot file itself. If we have a boot info table, life is
314 ; good; if not, we have to make some assumptions, and try
315 ; to figure things out ourselves. In particular, the
316 ; assumptions we have to make are:
317 ; - single session only
318 ; - only one boot entry (no menu or other alternatives)
320 cmp dword [bi_file
],0 ; Address of code to load
321 jne found_file
; Boot info table present :)
323 %ifdef DEBUG_MESSAGES
324 mov si,noinfotable_msg
328 ; No such luck. See if the the spec packet contained one.
331 jz set_file
; Good enough
333 %ifdef DEBUG_MESSAGES
334 mov si,noinfoinspec_msg
338 ; No such luck. Get the Boot Record Volume, assuming single
339 ; session disk, and that we're the first entry in the chain
340 mov eax,17 ; Assumed address of BRV
344 mov eax,[trackbuf
+47h] ; Get boot catalog address
346 call getonesec
; Get boot catalog
348 mov eax,[trackbuf
+28h] ; First boot entry
349 ; And hope and pray this is us...
351 ; Some BIOSes apparently have limitations on the size
352 ; that may be loaded (despite the El Torito spec being very
353 ; clear on the fact that it must all be loaded.) Therefore,
354 ; we load it ourselves, and *bleep* the BIOS.
360 ; Set up boot file sizes
362 sub eax,SECTOR_SIZE
-3
363 shr eax,2 ; bytes->dwords
364 mov [ImageDwords
],eax ; boot file dwords
366 shr eax,9 ; dwords->sectors
367 mov [ImageSectors
],ax ; boot file sectors
369 mov eax,[bi_file
] ; Address of code to load
370 inc eax ; Don't reload bootstrap code
371 %ifdef DEBUG_MESSAGES
378 ; Just in case some BIOSes have problems with
379 ; segment wraparound, use the normalized address
380 mov bx,((7C00h
+2048) >> 4)
383 mov bp,[ImageSectors
]
384 %ifdef DEBUG_MESSAGES
398 %ifdef DEBUG_MESSAGES
403 ; Verify the checksum on the loaded image.
407 mov ecx,[ImageDwords
]
408 mov edi,[FirstSecSum
] ; First sector checksum
415 ; SI wrapped around, advance ES
429 %ifdef DEBUG_MESSAGES
433 jmp all_read
; Jump to main code
435 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
436 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
437 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
439 ;; There is a problem with certain versions of the AWARD BIOS ...
440 ;; the boot sector will be loaded and executed correctly, but, because the
441 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
442 ;; load the spec packet will fail. We scan for the equivalent of
451 ;; and use <direct far> as the new vector for int 13. The code above is
452 ;; used to load the boot code into ram, and there should be no reason
453 ;; for anybody to change it now or in the future. There are no opcodes
454 ;; that use encodings relativ to IP, so scanning is easy. If we find the
455 ;; code above in the BIOS code we can be pretty sure to run on a machine
456 ;; with an broken AWARD BIOS ...
458 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
460 %ifdef DEBUG_MESSAGES
;;
462 award_notice
db "Trying BrokenAwardHack first ...",CR
,LF
,0 ;;
463 award_not_orig
db "BAH: Original Int 13 vector : ",0 ;;
464 award_not_new
db "BAH: Int 13 vector changed to : ",0 ;;
465 award_not_succ
db "BAH: SUCCESS",CR
,LF
,0 ;;
466 award_not_fail
db "BAH: FAILURE" ;;
467 award_not_crlf
db CR
,LF
,0 ;;
471 award_oldint13
dd 0 ;;
472 award_string
db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah
,80h,1,09ch,09ah ;;
474 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 award_hack: mov si,spec_err_msg
; Moved to this place from
476 call writemsg
; spec_query_faild
478 %ifdef DEBUG_MESSAGES
;
480 mov si,award_notice
; display our plan
482 mov si,award_not_orig
; display original int 13
483 call writemsg
; vector
486 mov [award_oldint13
],eax ;
488 %ifdef DEBUG_MESSAGES
;
491 mov si,award_not_crlf
;
495 mov ax,0f000h
; ES = BIOS Seg
498 xor di,di ; start at ES:DI = f000:0
499 award_loop: push di ; save DI
500 mov si,award_string
; scan for award_string
501 mov cx,7 ; length of award_string = 7dw
504 jcxz award_found
; jmp if found
505 inc di ; not found, inc di
508 award_failed: pop es ; No, not this way :-((
511 %ifdef DEBUG_MESSAGES
;
513 mov si,award_not_fail
; display failure ...
516 mov eax,[award_oldint13
] ; restore the original int
517 or eax,eax ; 13 vector if there is one
518 jz spec_query_failed
; and try other workarounds
520 jmp spec_query_failed
;
522 award_found: mov eax,[es:di+0eh
] ; load possible int 13 addr
525 cmp eax,[award_oldint13
] ; give up if this is the
526 jz award_failed
; active int 13 vector,
527 mov [13h*4],eax ; otherwise change 0:13h*4
530 %ifdef DEBUG_MESSAGES
;
532 push eax ; display message and
533 mov si,award_not_new
; new vector address
537 mov si,award_not_crlf
;
540 mov ax,4B01h ; try to read the spec packet
541 mov dl,[DriveNo
] ; now ... it should not fail
542 mov si,spec_packet
; any longer
546 %ifdef DEBUG_MESSAGES
;
548 mov si,award_not_succ
; display our SUCCESS
551 jmp found_drive
; and leave error recovery code
553 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
554 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
558 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
559 ; Try to scan the entire 80h-FFh from the end.
563 ; some code moved to BrokenAwardHack
569 mov byte [si],13 ; Size of buffer
580 cmp byte [sp_drive
],dl
583 ; Okay, good enough...
587 .
found_drive: jmp found_drive
589 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
590 ; but if this was the drive number originally passed in
591 ; DL then consider it "good enough"
593 cmp byte [DriveNo
],dl
596 .
still_broken: dec dx
600 ; No spec packet anywhere. Some particularly pathetic
601 ; BIOSes apparently don't even implement function
602 ; 4B01h, so we can't query a spec packet no matter
603 ; what. If we got a drive number in DL, then try to
604 ; use it, and if it works, then well...
606 cmp dl,81h ; Should be 81-FF at least
607 jb fatal_error
; If not, it's hopeless
609 ; Write a warning to indicate we're on *very* thin ice now
617 jmp .found_drive
; Pray that this works...
623 .
norge: jmp short .norge
625 ; Information message (DS:SI) output
626 ; Prefix with "isolinux: "
638 ; Write a character to the screen. There is a more "sophisticated"
639 ; version of this in the subsequent code, so we patch the pointer
644 jmp near writechr_simple
; 3-byte jump
657 ; Get one sector. Convenience entry point.
661 ; Fall through to getlinsec
664 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
666 ; Note that we can't always do this as a single request, because at least
667 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
668 ; to 32 sectors (64K) per request.
671 ; EAX - Linear sector number
672 ; ES:BX - Target buffer
676 mov si,dapa
; Load up the DAPA
682 push bp ; Sectors left
690 mov ah,42h ; Extended Read
694 movzx eax,word [si+2] ; Sectors we read
695 add [si+8],eax ; Advance sector pointer
696 sub bp,ax ; Sectors left
697 shl ax,SECTOR_SHIFT
-4 ; 2048-byte sectors -> segment
698 add [si+6],ax ; Advance buffer pointer
701 mov eax,[si+8] ; Next sector
705 xint13: mov byte [RetryCount
],retry_count
709 add sp,byte 8*4 ; Clean up stack
712 mov [DiskError
],ah ; Save error code
714 mov [DiskSys
],ax ; Save system call number
715 dec byte [RetryCount
]
719 mov ah,[dapa
+2] ; Sector transfer count
720 cmp al,2 ; Only 2 attempts left
722 mov ah,1 ; Drop transfer size to 1
726 ja .again
; First time, just try again
727 shr ah,1 ; Otherwise, try to reduce
728 adc ah,0 ; the max transfer size, but not to 0
736 .
real_error: mov si,diskerr_msg
749 ; Fall through to kaboom
752 ; kaboom: write a message and bail out. Wait for a user keypress,
753 ; then do a hard reboot.
763 mov si,err_bootfailed
767 mov word [BIOS_magic
],0 ; Cold reboot
768 jmp 0F000h:0FFF0h
; Reset vector address
770 ; -----------------------------------------------------------------------------
771 ; Common modules needed in the first sector
772 ; -----------------------------------------------------------------------------
774 %include "writestr.inc" ; String output
775 writestr
equ cwritestr
776 %include "writehex.inc" ; Hexadecimal output
778 ; -----------------------------------------------------------------------------
779 ; Data that needs to be in the first sector
780 ; -----------------------------------------------------------------------------
782 syslinux_banner
db CR
, LF
, 'ISOLINUX ', version_str
, ' ', date
, ' ', 0
783 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
785 isolinux_str
db 'isolinux: ', 0
786 %ifdef DEBUG_MESSAGES
787 startup_msg: db 'Starting up, DL = ', 0
788 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
789 secsize_msg: db 'Sector size appears to be ', 0
790 offset_msg: db 'Loading main image from LBA = ', 0
791 size_msg: db 'Sectors to load = ', 0
792 loaded_msg: db 'Loaded boot image, verifying...', CR
, LF
, 0
793 verify_msg: db 'Image checksum verified.', CR
, LF
, 0
794 allread_msg
db 'Main image read, jumping to main code...', CR
, LF
, 0
796 noinfotable_msg
db 'No boot info table, assuming single session disk...', CR
, LF
, 0
797 noinfoinspec_msg
db 'Spec packet missing LBA information, trying to wing it...', CR
, LF
, 0
798 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR
, LF
, 0
799 maybe_msg: db 'Found something at drive = ', 0
800 alright_msg: db 'Looks like it might be right, continuing...', CR
, LF
, 0
801 nospec_msg
db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0
802 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR
, LF
803 trysbm_msg
db 'See http://syslinux.zytor.com/sbm for more information.', CR
, LF
, 0
804 diskerr_msg: db 'Disk error ', 0
805 oncall_str: db ', AX = ',0
806 ondrive_str: db ', drive ', 0
807 checkerr_msg: db 'Image checksum error, sorry...', CR
, LF
, 0
809 err_bootfailed
db CR
, LF
, 'Boot failed: press a key to retry...'
810 bailmsg
equ err_bootfailed
815 StackPtr
dw StackBuf
, 0 ; SS:SP for stack reset
816 MaxTransfer
dw 32 ; Max sectors per transfer
818 rl_checkpt
equ $
; Must be <= 800h
820 rl_checkpt_off
equ ($
-$$
)
822 ;%if rl_checkpt_off > 0x800
823 ;%error "Sector 0 overflow"
827 ; ----------------------------------------------------------------------------
828 ; End of code and data that have to be in the first sector
829 ; ----------------------------------------------------------------------------
833 ; Initialize screen (if we're using one)
835 ; Now set up screen parameters
838 ; Wipe the F-key area
841 mov cx,10*(1 << FILENAME_MAX_LG2
)
844 ; Patch the writechr routine to point to the full code
845 mov word [writechr
+1], writechr_full
-(writechr
+3)
847 ; Tell the user we got this far...
848 %ifndef DEBUG_MESSAGES
; Gets messy with debugging on
858 ; Common initialization code
861 %include "cpuinit.inc"
864 ; Now we're all set to start with our *real* business. First load the
865 ; configuration file (if any) and parse it.
867 ; In previous versions I avoided using 32-bit registers because of a
868 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
869 ; random. I figure, though, that if there are any of those still left
870 ; they probably won't be trying to install Linux on them...
872 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
873 ; to take'm out. In fact, we may want to put them back if we're going
874 ; to boot ELKS at some point.
878 ; Now, we need to sniff out the actual filesystem data structures.
879 ; mkisofs gave us a pointer to the primary volume descriptor
880 ; (which will be at 16 only for a single-session disk!); from the PVD
881 ; we should be able to find the rest of what we need to know.
888 mov eax,[trackbuf
+156+2]
889 mov [RootDir
+dir_lba
],eax
890 mov [CurDir
+dir_lba
],eax
891 %ifdef DEBUG_MESSAGES
892 mov si,dbg_rootdir_msg
897 mov eax,[trackbuf
+156+10]
898 mov [RootDir
+dir_len
],eax
899 mov [CurDir
+dir_len
],eax
900 add eax,SECTOR_SIZE
-1
902 mov [RootDir
+dir_clust
],eax
903 mov [CurDir
+dir_clust
],eax
905 ; Look for an isolinux directory, and if found,
906 ; make it the current directory instead of the root
908 mov di,boot_dir
; Search for /boot/isolinux
913 mov al,02h ; Search for /isolinux
917 mov [CurDir
+dir_len
],eax
918 mov eax,[si+file_left
]
919 mov [CurDir
+dir_clust
],eax
920 xor eax,eax ; Free this file pointer entry
921 xchg eax,[si+file_sector
]
922 mov [CurDir
+dir_lba
],eax
923 %ifdef DEBUG_MESSAGES
925 mov si,dbg_isodir_msg
934 ; Locate the configuration file
937 %ifdef DEBUG_MESSAGES
938 mov si,dbg_config_msg
944 jz no_config_file
; Not found or empty
946 %ifdef DEBUG_MESSAGES
947 mov si,dbg_configok_msg
952 ; Now we have the config file open. Parse the config file and
953 ; run the user interface.
958 ; Linux kernel loading code is common.
960 %include "runkernel.inc"
963 ; COMBOOT-loading code
965 %include "comboot.inc"
967 %include "cmdline.inc"
970 ; Boot sector loading code
972 %include "bootsect.inc"
975 ; Enable disk emulation. The kind of disk we emulate is dependent on the size of
976 ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
985 mov dx,ax ; Set EDX <- file size
987 mov cx,img_table_count
988 mov eax,[si+file_sector
] ; Starting LBA of file
989 mov [dsp_lba
],eax ; Location of file
990 mov byte [dsp_drive
], 0 ; 00h floppy, 80h hard disk
999 ; Hard disk image. Need to examine the partition table
1000 ; in order to deduce the C/H/S geometry. Sigh.
1007 mov cx,1 ; Load 1 sector
1010 cmp word [trackbuf
+510],0aa55h
; Boot signature
1011 jne .bad_image
; Image not bootable
1013 mov cx,4 ; 4 partition entries
1014 mov di,trackbuf
+446 ; Start of partition table
1016 xor ax,ax ; Highest sector(al) head(ah)
1030 push edx ; File size
1033 inc bx ; # of heads in BX
1034 xor ah,ah ; # of sectors in AX
1035 cwde ; EAX[31:16] <- 0
1037 shl eax,9 ; Convert to bytes
1038 ; Now eax contains the number of bytes per cylinder
1044 inc eax ; Fractional cylinder...
1045 ; Now (e)ax contains the number of cylinders
1046 .
no_remainder: cmp eax,1024
1048 mov ax,1024 ; Max possible #
1049 .
ok_cyl: dec ax ; Convert to max cylinder no
1050 pop ebx ; S(bl) H(bh)
1056 mov al,4 ; Hard disk boot
1057 mov byte [dsp_drive
], 80h ; Drive 80h = hard disk
1062 and bl,0F0h
; Copy controller info bits
1064 mov [dsp_media
],al ; Emulation type
1066 mov [dsp_chs
],eax ; C/H/S geometry
1067 mov ax,[sp_devspec
] ; Copy device spec
1068 mov [dsp_devspec
],ax
1069 mov al,[sp_controller
] ; Copy controller index
1070 mov [dsp_controller
],al
1073 call vgaclearmode
; Reset video
1075 mov ax,4C00h
; Enable emulation and boot
1083 ; If this returns, we have problems
1085 mov si,err_disk_image
1090 ; Look for the highest seen H/S geometry
1091 ; We compute cylinders separately
1094 mov bl,[si] ; Head #
1097 mov ah,bl ; New highest head #
1098 .
done_track: mov bl,[si+1]
1099 and bl,3Fh
; Sector #
1106 ; Boot a specified local disk. AX specifies the BIOS disk number; or
1107 ; 0xFFFF in case we should execute INT 18h ("next device.")
1111 lss sp,[cs:Stack
] ; Restore stack pointer
1117 mov si,localboot_msg
1122 ; Load boot sector from the specified BIOS device and jump to it.
1126 xor ax,ax ; Reset drive
1128 mov ax,0201h ; Read one sector
1129 mov cx,0001h ; C/H/S = 0/0/1 (first sector)
1133 cli ; Abandon hope, ye who enter here
1136 mov cx,512 ; Probably overkill, but should be safe
1138 lss sp,[cs:InitStack
]
1139 jmp 0:07C00h
; Jump to new boot sector
1142 int 18h ; Hope this does the right thing...
1143 jmp kaboom
; If we returned, oh boy...
1146 ; Abort loading code
1148 %include "abort.inc"
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.
1371 ; This verifies that a filename is < FILENAME_MAX characters,
1372 ; doesn't contain whitespace, zero-pads the output buffer,
1373 ; and removes trailing dots and redundant slashes,
1374 ; so "repe cmpsb" can do a compare, and the
1375 ; path-searching routine gets a bit of an easier job.
1380 mov cx,FILENAME_MAX
-1
1385 cmp al,' ' ; If control or space, end
1387 cmp al,ah ; Repeated slash?
1394 .
mn_skip: loop .mn_loop
1396 cmp bx,di ; At the beginning of the buffer?
1398 cmp byte [di-1],'.' ; Terminal dot?
1400 cmp byte [di-1],'/' ; Terminal slash?
1402 .
mn_kill: dec di ; If so, remove it
1406 inc cx ; At least one null byte
1407 xor ax,ax ; Zero-fill name
1413 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1414 ; filename to the conventional representation. This is needed
1415 ; for the BOOT_IMAGE= parameter for the kernel.
1416 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1417 ; known to be shorter.
1419 ; DS:SI -> input mangled file name
1420 ; ES:DI -> output buffer
1422 ; On return, DI points to the first byte after the output name,
1423 ; which is set to a null byte.
1425 unmangle_name: call strcpy
1426 dec di ; Point to final null byte
1430 ; getfssec: Get multiple clusters from a file, given the file pointer.
1434 ; SI -> File pointer
1435 ; CX -> Cluster count
1437 ; SI -> File pointer (or 0 on EOF)
1448 cmp ecx,[si+file_left
]
1450 mov ecx,[si+file_left
]
1456 mov eax,[si+file_sector
]
1463 add [si+file_sector
],ecx
1464 sub [si+file_left
],ecx
1465 ja .not_eof
; CF = 0
1468 mov [si+file_sector
],ecx ; Mark as unused
1477 ; -----------------------------------------------------------------------------
1479 ; -----------------------------------------------------------------------------
1481 %include "getc.inc" ; getc et al
1482 %include "conio.inc" ; Console I/O
1483 %include "parseconfig.inc" ; High-level config file handling
1484 %include "parsecmd.inc" ; Low-level config file handling
1485 %include "bcopy32.inc" ; 32-bit bcopy
1486 %include "loadhigh.inc" ; Load a file into high memory
1487 %include "font.inc" ; VGA font stuff
1488 %include "graphics.inc" ; VGA graphics
1489 %include "highmem.inc" ; High memory sizing
1490 %include "strcpy.inc" ; strcpy()
1491 %include "rawcon.inc" ; Console I/O w/o using the console functions
1493 ; -----------------------------------------------------------------------------
1494 ; Begin data section
1495 ; -----------------------------------------------------------------------------
1499 boot_prompt
db 'boot: ', 0
1500 wipe_char
db BS
, ' ', BS
, 0
1501 err_notfound
db 'Could not find kernel image: ',0
1502 err_notkernel
db CR
, LF
, 'Invalid or corrupt kernel image.', CR
, LF
, 0
1503 err_noram
db 'It appears your computer has less than '
1505 db 'K of low ("DOS")'
1507 db 'RAM. Linux needs at least this amount to boot. If you get'
1509 db 'this message in error, hold down the Ctrl key while'
1511 db 'booting, and I will take your word for it.', CR
, LF
, 0
1512 err_badcfg
db 'Unknown keyword in config file.', CR
, LF
, 0
1513 err_noparm
db 'Missing parameter in config file.', CR
, LF
, 0
1514 err_noinitrd
db CR
, LF
, 'Could not find ramdisk image: ', 0
1515 err_nohighmem
db 'Not enough memory to load specified kernel.', CR
, LF
, 0
1516 err_highload
db CR
, LF
, 'Kernel transfer failure.', CR
, LF
, 0
1517 err_oldkernel
db 'Cannot load a ramdisk with an old kernel image.'
1519 err_notdos
db ': attempted DOS system call', CR
, LF
, 0
1520 err_comlarge
db 'COMBOOT image too large.', CR
, LF
, 0
1521 err_bssimage
db 'BSS images not supported.', CR
, LF
, 0
1522 err_a20
db CR
, LF
, 'A20 gate not responding!', CR
, LF
, 0
1523 notfound_msg
db 'not found', CR
, LF
, 0
1524 localboot_msg
db 'Booting from local disk...', CR
, LF
, 0
1525 cmdline_msg
db 'Command line: ', CR
, LF
, 0
1526 ready_msg
db 'Ready.', CR
, LF
, 0
1527 trying_msg
db 'Trying to load: ', 0
1528 crlfloading_msg
db CR
, LF
; Fall through
1529 loading_msg
db 'Loading ', 0
1532 fourbs_msg
db BS
, BS
, BS
, BS
, 0
1533 aborted_msg
db ' aborted.', CR
, LF
, 0
1534 crff_msg
db CR
, FF
, 0
1535 default_str
db 'default', 0
1536 default_len
equ ($
-default_str
)
1537 boot_dir
db '/boot' ; /boot/isolinux
1538 isolinux_dir
db '/isolinux', 0
1540 isolinux_cfg
db 'isolinux.cfg', 0
1541 err_disk_image
db 'Cannot load disk image (invalid file)?', CR
, LF
, 0
1543 %ifdef DEBUG_MESSAGES
1544 dbg_rootdir_msg
db 'Root directory at LBA = ', 0
1545 dbg_isodir_msg
db 'isolinux directory at LBA = ', 0
1546 dbg_config_msg
db 'About to load config file...', CR
, LF
, 0
1547 dbg_configok_msg
db 'Configuration file opened...', CR
, LF
, 0
1550 ; Command line options we'd like to take a look at
1552 ; mem= and vga= are handled as normal 32-bit integer values
1553 initrd_cmd
db 'initrd='
1554 initrd_cmd_len
equ 7
1557 ; Config file keyword table
1559 %include "keywords.inc"
1562 ; Extensions to search for (in *forward* order).
1565 exten_table: db '.cbt' ; COMBOOT (specific)
1566 db '.img' ; Disk image
1567 db '.bin' ; CD boot sector
1568 db '.com' ; COMBOOT (same as DOS)
1571 dd 0, 0 ; Need 8 null bytes here
1574 ; Floppy image table
1577 img_table_count
equ 3
1579 dd 1200*1024 ; 1200K floppy
1580 db 1 ; Emulation type
1581 db 80-1 ; Max cylinder
1585 dd 1440*1024 ; 1440K floppy
1586 db 2 ; Emulation type
1587 db 80-1 ; Max cylinder
1591 dd 2880*1024 ; 2880K floppy
1592 db 3 ; Emulation type
1593 db 80-1 ; Max cylinder
1598 ; Misc initialized (data) variables
1602 ; Variables that are uninitialized in SYSLINUX but initialized here
1604 ; **** ISOLINUX:: We may have to make this flexible, based on what the
1605 ; **** BIOS expects our "sector size" to be.
1608 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1609 BufSafeSec
dw trackbufsize
/SECTOR_SIZE
; = how many sectors?
1610 BufSafeBytes
dw trackbufsize
; = how many bytes?
1611 EndOfGetCBuf
dw getcbuf
+trackbufsize
; = getcbuf+BufSafeBytes
1613 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1614 %error trackbufsize must be a multiple of SECTOR_SIZE