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
110 ISOFileName resb
64 ; ISO filename canonicalization buffer
112 CurDir resb dir_t_size
; Current directory
113 RootDir resb dir_t_size
; Root directory
114 FirstSecSum resd
1 ; Checksum of bytes 64-2048
115 ImageDwords resd
1 ; isolinux.bin size, dwords
116 InitStack resd
1 ; Initial stack pointer (SS:SP)
117 DiskSys resw
1 ; Last INT 13h call
118 ImageSectors resw
1 ; isolinux.bin size, sectors
119 DiskError resb
1 ; Error code for disk I/O
120 DriveNo resb
1 ; CD-ROM BIOS drive number
121 ISOFlags resb
1 ; Flags for ISO directory search
122 RetryCount resb
1 ; Used for disk access retries
127 ; El Torito spec packet
131 spec_packet: resb
1 ; Size of packet
132 sp_media: resb
1 ; Media type
133 sp_drive: resb
1 ; Drive number
134 sp_controller: resb
1 ; Controller index
135 sp_lba: resd
1 ; LBA for emulated disk image
136 sp_devspec: resw
1 ; IDE/SCSI information
137 sp_buffer: resw
1 ; User-provided buffer
138 sp_loadseg: resw
1 ; Load segment
139 sp_sectors: resw
1 ; Sector count
140 sp_chs: resb
3 ; Simulated CHS geometry
141 sp_dummy: resb
1 ; Scratch, safe to overwrite
144 ; EBIOS drive parameter packet
147 drive_params: resw
1 ; Buffer size
148 dp_flags: resw
1 ; Information flags
149 dp_cyl: resd
1 ; Physical cylinders
150 dp_head: resd
1 ; Physical heads
151 dp_sec: resd
1 ; Physical sectors/track
152 dp_totalsec: resd
2 ; Total sectors
153 dp_secsize: resw
1 ; Bytes per sector
154 dp_dpte: resd
1 ; Device Parameter Table
155 dp_dpi_key: resw
1 ; 0BEDDh if rest valid
156 dp_dpi_len: resb
1 ; DPI len
159 dp_bus: resb
4 ; Host bus type
160 dp_interface: resb
8 ; Interface type
161 db_i_path: resd
2 ; Interface path
162 db_d_path: resd
2 ; Device path
164 db_dpi_csum: resb
1 ; Checksum for DPI info
167 ; EBIOS disk address packet
170 dapa: resw
1 ; Packet size
171 .
count: resw
1 ; Block count
172 .
off: resw
1 ; Offset of buffer
173 .
seg: resw
1 ; Segment of buffer
174 .
lba: resd
2 ; LBA (LSW, MSW)
177 ; Spec packet for disk image emulation
180 dspec_packet: resb
1 ; Size of packet
181 dsp_media: resb
1 ; Media type
182 dsp_drive: resb
1 ; Drive number
183 dsp_controller: resb
1 ; Controller index
184 dsp_lba: resd
1 ; LBA for emulated disk image
185 dsp_devspec: resw
1 ; IDE/SCSI information
186 dsp_buffer: resw
1 ; User-provided buffer
187 dsp_loadseg: resw
1 ; Load segment
188 dsp_sectors: resw
1 ; Sector count
189 dsp_chs: resb
3 ; Simulated CHS geometry
190 dsp_dummy: resb
1 ; Scratch, safe to overwrite
194 _spec_len
equ _spec_end
- _spec_start
196 alignb open_file_t_size
197 Files resb MAX_OPEN
*open_file_t_size
200 ; Constants for the xfer_buf_seg
202 ; The xfer_buf_seg is also used to store message file buffers. We
203 ; need two trackbuffers (text and graphics), plus a work buffer
204 ; for the graphics decompressor.
206 xbs_textbuf
equ 0 ; Also hard-coded, do not change
207 xbs_vgabuf
equ trackbufsize
208 xbs_vgatmpbuf
equ 2*trackbufsize
212 ;; Primary entry point. Because BIOSes are buggy, we only load the first
213 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
216 StackBuf
equ $
-44 ; 44 bytes needed for
217 ; the bootsector chainloading
222 _start: ; Far jump makes sure we canonicalize the address
225 times
8-($
-$$
) nop ; Pad to file offset 8
227 ; This table hopefully gets filled in by mkisofs using the
228 ; -boot-info-table option. If not, the values in this
229 ; table are default values that we can use to get us what
230 ; we need, at least under a certain set of assumptions.
231 bi_pvd: dd 16 ; LBA of primary volume descriptor
232 bi_file: dd 0 ; LBA of boot file
233 bi_length: dd 0xdeadbeef ; Length of boot file
234 bi_csum: dd 0xdeadbeef ; Checksum of boot file
235 bi_reserved: times
10 dd 0xdeadbeef ; Reserved
237 _start1: mov [cs:InitStack
],sp ; Save initial stack pointer
238 mov [cs:InitStack
+2],ss
241 mov sp,StackBuf
; Set up stack
250 mov si,syslinux_banner
252 %ifdef DEBUG_MESSAGES
258 ; Before modifying any memory, get the checksum of bytes
261 initial_csum: xor edi,edi
263 mov cx,(SECTOR_SIZE
-64) >> 2
267 mov [FirstSecSum
],edi
270 %ifdef DEBUG_MESSAGES
278 ; Initialize spec packet buffers
281 mov cx,_spec_len
>> 2
285 ; Initialize length field of the various packets
286 mov byte [spec_packet
],13h
287 mov byte [drive_params
],30
289 mov byte [dspec_packet
],13h
291 ; Other nonzero fields
292 inc word [dsp_sectors
]
294 ; Now figure out what we're actually doing
295 ; Note: use passed-in DL value rather than 7Fh because
296 ; at least some BIOSes will get the wrong value otherwise
297 mov ax,4B01h ; Get disk emulation status
301 jc award_hack
; changed for BrokenAwardHack
303 cmp [sp_drive
],dl ; Should contain the drive number
304 jne spec_query_failed
306 %ifdef DEBUG_MESSAGES
309 mov al,byte [sp_drive
]
315 ; Alright, we have found the drive. Now, try to find the
316 ; boot file itself. If we have a boot info table, life is
317 ; good; if not, we have to make some assumptions, and try
318 ; to figure things out ourselves. In particular, the
319 ; assumptions we have to make are:
320 ; - single session only
321 ; - only one boot entry (no menu or other alternatives)
323 cmp dword [bi_file
],0 ; Address of code to load
324 jne found_file
; Boot info table present :)
326 %ifdef DEBUG_MESSAGES
327 mov si,noinfotable_msg
331 ; No such luck. See if the the spec packet contained one.
334 jz set_file
; Good enough
336 %ifdef DEBUG_MESSAGES
337 mov si,noinfoinspec_msg
341 ; No such luck. Get the Boot Record Volume, assuming single
342 ; session disk, and that we're the first entry in the chain
343 mov eax,17 ; Assumed address of BRV
347 mov eax,[trackbuf
+47h] ; Get boot catalog address
349 call getonesec
; Get boot catalog
351 mov eax,[trackbuf
+28h] ; First boot entry
352 ; And hope and pray this is us...
354 ; Some BIOSes apparently have limitations on the size
355 ; that may be loaded (despite the El Torito spec being very
356 ; clear on the fact that it must all be loaded.) Therefore,
357 ; we load it ourselves, and *bleep* the BIOS.
363 ; Set up boot file sizes
365 sub eax,SECTOR_SIZE
-3
366 shr eax,2 ; bytes->dwords
367 mov [ImageDwords
],eax ; boot file dwords
369 shr eax,9 ; dwords->sectors
370 mov [ImageSectors
],ax ; boot file sectors
372 mov eax,[bi_file
] ; Address of code to load
373 inc eax ; Don't reload bootstrap code
374 %ifdef DEBUG_MESSAGES
381 ; Just in case some BIOSes have problems with
382 ; segment wraparound, use the normalized address
383 mov bx,((7C00h
+2048) >> 4)
386 mov bp,[ImageSectors
]
387 %ifdef DEBUG_MESSAGES
401 %ifdef DEBUG_MESSAGES
406 ; Verify the checksum on the loaded image.
410 mov ecx,[ImageDwords
]
411 mov edi,[FirstSecSum
] ; First sector checksum
418 ; SI wrapped around, advance ES
432 %ifdef DEBUG_MESSAGES
436 jmp all_read
; Jump to main code
438 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
439 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
440 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
442 ;; There is a problem with certain versions of the AWARD BIOS ...
443 ;; the boot sector will be loaded and executed correctly, but, because the
444 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
445 ;; load the spec packet will fail. We scan for the equivalent of
454 ;; and use <direct far> as the new vector for int 13. The code above is
455 ;; used to load the boot code into ram, and there should be no reason
456 ;; for anybody to change it now or in the future. There are no opcodes
457 ;; that use encodings relativ to IP, so scanning is easy. If we find the
458 ;; code above in the BIOS code we can be pretty sure to run on a machine
459 ;; with an broken AWARD BIOS ...
461 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
463 %ifdef DEBUG_MESSAGES
;;
465 award_notice
db "Trying BrokenAwardHack first ...",CR
,LF
,0 ;;
466 award_not_orig
db "BAH: Original Int 13 vector : ",0 ;;
467 award_not_new
db "BAH: Int 13 vector changed to : ",0 ;;
468 award_not_succ
db "BAH: SUCCESS",CR
,LF
,0 ;;
469 award_not_fail
db "BAH: FAILURE" ;;
470 award_not_crlf
db CR
,LF
,0 ;;
474 award_oldint13
dd 0 ;;
475 award_string
db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah
,80h,1,09ch,09ah ;;
477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
478 award_hack: mov si,spec_err_msg
; Moved to this place from
479 call writemsg
; spec_query_faild
481 %ifdef DEBUG_MESSAGES
;
483 mov si,award_notice
; display our plan
485 mov si,award_not_orig
; display original int 13
486 call writemsg
; vector
489 mov [award_oldint13
],eax ;
491 %ifdef DEBUG_MESSAGES
;
494 mov si,award_not_crlf
;
498 mov ax,0f000h
; ES = BIOS Seg
501 xor di,di ; start at ES:DI = f000:0
502 award_loop: push di ; save DI
503 mov si,award_string
; scan for award_string
504 mov cx,7 ; length of award_string = 7dw
507 jcxz award_found
; jmp if found
508 inc di ; not found, inc di
511 award_failed: pop es ; No, not this way :-((
514 %ifdef DEBUG_MESSAGES
;
516 mov si,award_not_fail
; display failure ...
519 mov eax,[award_oldint13
] ; restore the original int
520 or eax,eax ; 13 vector if there is one
521 jz spec_query_failed
; and try other workarounds
523 jmp spec_query_failed
;
525 award_found: mov eax,[es:di+0eh
] ; load possible int 13 addr
528 cmp eax,[award_oldint13
] ; give up if this is the
529 jz award_failed
; active int 13 vector,
530 mov [13h*4],eax ; otherwise change 0:13h*4
533 %ifdef DEBUG_MESSAGES
;
535 push eax ; display message and
536 mov si,award_not_new
; new vector address
540 mov si,award_not_crlf
;
543 mov ax,4B01h ; try to read the spec packet
544 mov dl,[DriveNo
] ; now ... it should not fail
545 mov si,spec_packet
; any longer
549 %ifdef DEBUG_MESSAGES
;
551 mov si,award_not_succ
; display our SUCCESS
554 jmp found_drive
; and leave error recovery code
556 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
557 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
558 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
561 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
562 ; Try to scan the entire 80h-FFh from the end.
566 ; some code moved to BrokenAwardHack
572 mov byte [si],13 ; Size of buffer
583 cmp byte [sp_drive
],dl
586 ; Okay, good enough...
590 .
found_drive: jmp found_drive
592 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
593 ; but if this was the drive number originally passed in
594 ; DL then consider it "good enough"
596 cmp byte [DriveNo
],dl
599 .
still_broken: dec dx
603 ; No spec packet anywhere. Some particularly pathetic
604 ; BIOSes apparently don't even implement function
605 ; 4B01h, so we can't query a spec packet no matter
606 ; what. If we got a drive number in DL, then try to
607 ; use it, and if it works, then well...
609 cmp dl,81h ; Should be 81-FF at least
610 jb fatal_error
; If not, it's hopeless
612 ; Write a warning to indicate we're on *very* thin ice now
620 jmp .found_drive
; Pray that this works...
626 .
norge: jmp short .norge
628 ; Information message (DS:SI) output
629 ; Prefix with "isolinux: "
641 ; Write a character to the screen. There is a more "sophisticated"
642 ; version of this in the subsequent code, so we patch the pointer
647 jmp near writechr_simple
; 3-byte jump
660 ; Get one sector. Convenience entry point.
664 ; Fall through to getlinsec
667 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
669 ; Note that we can't always do this as a single request, because at least
670 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
671 ; to 32 sectors (64K) per request.
674 ; EAX - Linear sector number
675 ; ES:BX - Target buffer
679 mov si,dapa
; Load up the DAPA
685 push bp ; Sectors left
693 mov ah,42h ; Extended Read
697 movzx eax,word [si+2] ; Sectors we read
698 add [si+8],eax ; Advance sector pointer
699 sub bp,ax ; Sectors left
700 shl ax,SECTOR_SHIFT
-4 ; 2048-byte sectors -> segment
701 add [si+6],ax ; Advance buffer pointer
704 mov eax,[si+8] ; Next sector
708 xint13: mov byte [RetryCount
],retry_count
712 add sp,byte 8*4 ; Clean up stack
715 mov [DiskError
],ah ; Save error code
717 mov [DiskSys
],ax ; Save system call number
718 dec byte [RetryCount
]
722 mov ah,[dapa
+2] ; Sector transfer count
723 cmp al,2 ; Only 2 attempts left
725 mov ah,1 ; Drop transfer size to 1
729 ja .again
; First time, just try again
730 shr ah,1 ; Otherwise, try to reduce
731 adc ah,0 ; the max transfer size, but not to 0
739 .
real_error: mov si,diskerr_msg
752 ; Fall through to kaboom
755 ; kaboom: write a message and bail out. Wait for a user keypress,
756 ; then do a hard reboot.
759 RESET_STACK_AND_SEGS
AX
760 mov si,err_bootfailed
764 mov word [BIOS_magic
],0 ; Cold reboot
765 jmp 0F000h:0FFF0h
; Reset vector address
767 ; -----------------------------------------------------------------------------
768 ; Common modules needed in the first sector
769 ; -----------------------------------------------------------------------------
771 %include "writestr.inc" ; String output
772 writestr
equ cwritestr
773 %include "writehex.inc" ; Hexadecimal output
775 ; -----------------------------------------------------------------------------
776 ; Data that needs to be in the first sector
777 ; -----------------------------------------------------------------------------
779 syslinux_banner
db CR
, LF
, 'ISOLINUX ', version_str
, ' ', date
, ' ', 0
780 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
782 isolinux_str
db 'isolinux: ', 0
783 %ifdef DEBUG_MESSAGES
784 startup_msg: db 'Starting up, DL = ', 0
785 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
786 secsize_msg: db 'Sector size appears to be ', 0
787 offset_msg: db 'Loading main image from LBA = ', 0
788 size_msg: db 'Sectors to load = ', 0
789 loaded_msg: db 'Loaded boot image, verifying...', CR
, LF
, 0
790 verify_msg: db 'Image checksum verified.', CR
, LF
, 0
791 allread_msg
db 'Main image read, jumping to main code...', CR
, LF
, 0
793 noinfotable_msg
db 'No boot info table, assuming single session disk...', CR
, LF
, 0
794 noinfoinspec_msg
db 'Spec packet missing LBA information, trying to wing it...', CR
, LF
, 0
795 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR
, LF
, 0
796 maybe_msg: db 'Found something at drive = ', 0
797 alright_msg: db 'Looks like it might be right, continuing...', CR
, LF
, 0
798 nospec_msg
db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0
799 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR
, LF
800 trysbm_msg
db 'See http://syslinux.zytor.com/sbm for more information.', CR
, LF
, 0
801 diskerr_msg: db 'Disk error ', 0
802 oncall_str: db ', AX = ',0
803 ondrive_str: db ', drive ', 0
804 checkerr_msg: db 'Image checksum error, sorry...', CR
, LF
, 0
806 err_bootfailed
db CR
, LF
, 'Boot failed: press a key to retry...'
807 bailmsg
equ err_bootfailed
812 StackPtr
dw StackBuf
, 0 ; SS:SP for stack reset
813 MaxTransfer
dw 32 ; Max sectors per transfer
815 rl_checkpt
equ $
; Must be <= 800h
817 rl_checkpt_off
equ ($
-$$
)
819 ;%if rl_checkpt_off > 0x800
820 ;%error "Sector 0 overflow"
824 ; ----------------------------------------------------------------------------
825 ; End of code and data that have to be in the first sector
826 ; ----------------------------------------------------------------------------
835 ; Common initialization code
838 %include "cpuinit.inc"
840 ; Patch the writechr routine to point to the full code
841 mov word [writechr
+1], writechr_full
-(writechr
+3)
843 ; Tell the user we got this far...
844 %ifndef DEBUG_MESSAGES
; Gets messy with debugging on
850 ; Now we're all set to start with our *real* business. First load the
851 ; configuration file (if any) and parse it.
853 ; In previous versions I avoided using 32-bit registers because of a
854 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
855 ; random. I figure, though, that if there are any of those still left
856 ; they probably won't be trying to install Linux on them...
858 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
859 ; to take'm out. In fact, we may want to put them back if we're going
860 ; to boot ELKS at some point.
864 ; Now, we need to sniff out the actual filesystem data structures.
865 ; mkisofs gave us a pointer to the primary volume descriptor
866 ; (which will be at 16 only for a single-session disk!); from the PVD
867 ; we should be able to find the rest of what we need to know.
874 mov eax,[trackbuf
+156+2]
875 mov [RootDir
+dir_lba
],eax
876 mov [CurDir
+dir_lba
],eax
877 %ifdef DEBUG_MESSAGES
878 mov si,dbg_rootdir_msg
883 mov eax,[trackbuf
+156+10]
884 mov [RootDir
+dir_len
],eax
885 mov [CurDir
+dir_len
],eax
886 add eax,SECTOR_SIZE
-1
888 mov [RootDir
+dir_clust
],eax
889 mov [CurDir
+dir_clust
],eax
891 ; Look for an isolinux directory, and if found,
892 ; make it the current directory instead of the root
894 mov di,boot_dir
; Search for /boot/isolinux
899 mov al,02h ; Search for /isolinux
903 mov [CurDir
+dir_len
],eax
904 mov eax,[si+file_left
]
905 mov [CurDir
+dir_clust
],eax
906 xor eax,eax ; Free this file pointer entry
907 xchg eax,[si+file_sector
]
908 mov [CurDir
+dir_lba
],eax
909 %ifdef DEBUG_MESSAGES
911 mov si,dbg_isodir_msg
920 ; Locate the configuration file
923 %ifdef DEBUG_MESSAGES
924 mov si,dbg_config_msg
934 jz no_config_file
; Not found or empty
936 %ifdef DEBUG_MESSAGES
937 mov si,dbg_configok_msg
942 ; Now we have the config file open. Parse the config file and
943 ; run the user interface.
948 ; Linux kernel loading code is common.
950 %include "runkernel.inc"
953 ; COMBOOT-loading code
955 %include "comboot.inc"
957 %include "cmdline.inc"
960 ; Boot sector loading code
962 %include "bootsect.inc"
965 ; Enable disk emulation. The kind of disk we emulate is dependent on the size of
966 ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
975 mov dx,ax ; Set EDX <- file size
977 mov cx,img_table_count
978 mov eax,[si+file_sector
] ; Starting LBA of file
979 mov [dsp_lba
],eax ; Location of file
980 mov byte [dsp_drive
], 0 ; 00h floppy, 80h hard disk
989 ; Hard disk image. Need to examine the partition table
990 ; in order to deduce the C/H/S geometry. Sigh.
997 mov cx,1 ; Load 1 sector
1000 cmp word [trackbuf
+510],0aa55h
; Boot signature
1001 jne .bad_image
; Image not bootable
1003 mov cx,4 ; 4 partition entries
1004 mov di,trackbuf
+446 ; Start of partition table
1006 xor ax,ax ; Highest sector(al) head(ah)
1020 push edx ; File size
1023 inc bx ; # of heads in BX
1024 xor ah,ah ; # of sectors in AX
1025 cwde ; EAX[31:16] <- 0
1027 shl eax,9 ; Convert to bytes
1028 ; Now eax contains the number of bytes per cylinder
1034 inc eax ; Fractional cylinder...
1035 ; Now (e)ax contains the number of cylinders
1036 .
no_remainder: cmp eax,1024
1038 mov ax,1024 ; Max possible #
1039 .
ok_cyl: dec ax ; Convert to max cylinder no
1040 pop ebx ; S(bl) H(bh)
1046 mov al,4 ; Hard disk boot
1047 mov byte [dsp_drive
], 80h ; Drive 80h = hard disk
1052 and bl,0F0h
; Copy controller info bits
1054 mov [dsp_media
],al ; Emulation type
1056 mov [dsp_chs
],eax ; C/H/S geometry
1057 mov ax,[sp_devspec
] ; Copy device spec
1058 mov [dsp_devspec
],ax
1059 mov al,[sp_controller
] ; Copy controller index
1060 mov [dsp_controller
],al
1063 call vgaclearmode
; Reset video
1065 mov ax,4C00h
; Enable emulation and boot
1073 ; If this returns, we have problems
1075 mov si,err_disk_image
1080 ; Look for the highest seen H/S geometry
1081 ; We compute cylinders separately
1084 mov bl,[si] ; Head #
1087 mov ah,bl ; New highest head #
1088 .
done_track: mov bl,[si+1]
1089 and bl,3Fh
; Sector #
1096 ; Boot a specified local disk. AX specifies the BIOS disk number; or
1097 ; 0xFFFF in case we should execute INT 18h ("next device.")
1101 lss sp,[cs:Stack
] ; Restore stack pointer
1107 mov si,localboot_msg
1112 ; Load boot sector from the specified BIOS device and jump to it.
1116 xor ax,ax ; Reset drive
1118 mov ax,0201h ; Read one sector
1119 mov cx,0001h ; C/H/S = 0/0/1 (first sector)
1123 cli ; Abandon hope, ye who enter here
1126 mov cx,512 ; Probably overkill, but should be safe
1128 lss sp,[cs:InitStack
]
1129 jmp 0:07C00h
; Jump to new boot sector
1132 int 18h ; Hope this does the right thing...
1133 jmp kaboom
; If we returned, oh boy...
1136 ; Abort loading code
1138 %include "abort.inc"
1150 ; DX:AX or EAX = file length in bytes
1154 ; Assumes CS == DS == ES, and trashes BX and CX.
1156 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
1157 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
1158 ; for searching for directories.
1169 call allocate_file
; Temporary file structure for directory
1175 cmp byte [di],'/' ; If filename begins with slash
1177 inc di ; Skip leading slash
1178 mov si,RootDir
; Reference root directory instead
1180 mov eax,[si+dir_clust
]
1181 mov [bx+file_left
],eax
1182 mov eax,[si+dir_lba
]
1183 mov [bx+file_sector
],eax
1184 mov edx,[si+dir_len
]
1195 mov [di-1],byte 0 ; Terminate at directory name
1196 mov cl,02h ; Search for directory
1199 push di ; Save these...
1202 ; Create recursion stack frame...
1203 push word .resume
; Where to "return" to
1208 ; Get a chunk of the directory
1209 ; This relies on the fact that ISOLINUX doesn't change SI
1219 movzx eax,byte [si] ; Length of directory entry
1225 test cl, byte 8Eh
; Unwanted file attributes!
1228 movzx cx,byte [si+32] ; File identifier length
1229 add si,byte 33 ; File identifier offset
1231 call iso_compare_names
1235 sub edx,eax ; Decrease bytes left
1237 add si,ax ; Advance pointer
1240 ; Did we finish the buffer?
1241 cmp si,trackbuf
+trackbufsize
1242 jb .compare
; No, keep going
1244 jmp short .getsome
; Get some more directory
1247 ; Advance to the beginning of next sector
1248 lea ax,[si+SECTOR_SIZE
-1]
1249 and ax,~
(SECTOR_SIZE
-1)
1251 jmp short .not_file
; We still need to do length checks
1253 .
failure: xor eax,eax ; ZF = 1
1254 mov [bx+file_sector
],eax
1259 mov eax,[si+2] ; Location of extent
1260 mov [bx+file_sector
],eax
1261 mov eax,[si+10] ; Data length
1263 add eax,SECTOR_SIZE
-1
1264 shr eax,SECTOR_SHIFT
1265 mov [bx+file_left
],eax
1274 .
resume: ; We get here if we were only doing part of a lookup
1275 ; This relies on the fact that .success returns bx == si
1276 xchg edx,eax ; Directory length in edx
1277 pop cx ; Old ISOFlags
1278 pop di ; Next filename pointer
1279 mov byte [di-1], '/' ; Restore slash
1280 mov [ISOFlags
],cl ; Restore the flags
1281 jz .failure
; Did we fail? If so fail for real!
1282 jmp .look_for_slash
; Otherwise, next level
1285 ; allocate_file: Allocate a file structure
1298 .
check: cmp dword [bx], byte 0
1300 add bx,open_file_t_size
; ZF = 0
1302 ; ZF = 0 if we fell out of the loop
1307 ; iso_compare_names:
1308 ; Compare the names DS:SI and DS:DI and report if they are
1309 ; equal from an ISO 9660 perspective. SI is the name from
1310 ; the filesystem; CX indicates its length, and ';' terminates.
1311 ; DI is expected to end with a null.
1313 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
1317 ; First, terminate and canonicalize input filename
1320 .
canon_loop: jcxz .canon_end
1328 cmp di,ISOFileNameEnd
-1 ; Guard against buffer overrun
1333 cmp byte [di-1],'.' ; Remove terminal dots
1336 jmp short .canon_end
1338 mov [di],byte 0 ; Null-terminate string
1346 jz .success
; End of string for both
1347 and al,al ; Is either one end of string?
1348 jz .failure
; If so, failure
1351 or ax,2020h ; Convert to lower case
1354 .
failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
1358 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1359 ; to by ES:DI; ends on encountering any whitespace.
1362 ; This verifies that a filename is < FILENAME_MAX characters,
1363 ; doesn't contain whitespace, zero-pads the output buffer,
1364 ; and removes trailing dots and redundant slashes,
1365 ; so "repe cmpsb" can do a compare, and the
1366 ; path-searching routine gets a bit of an easier job.
1372 mov cx,FILENAME_MAX
-1
1377 cmp al,' ' ; If control or space, end
1379 cmp al,ah ; Repeated slash?
1386 .
mn_skip: loop .mn_loop
1388 cmp bx,di ; At the beginning of the buffer?
1390 cmp byte [es:di-1],'.' ; Terminal dot?
1392 cmp byte [es:di-1],'/' ; Terminal slash?
1394 .
mn_kill: dec di ; If so, remove it
1398 inc cx ; At least one null byte
1399 xor ax,ax ; Zero-fill name
1406 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1407 ; filename to the conventional representation. This is needed
1408 ; for the BOOT_IMAGE= parameter for the kernel.
1409 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1410 ; known to be shorter.
1412 ; DS:SI -> input mangled file name
1413 ; ES:DI -> output buffer
1415 ; On return, DI points to the first byte after the output name,
1416 ; which is set to a null byte.
1418 unmangle_name: call strcpy
1419 dec di ; Point to final null byte
1423 ; getfssec: Get multiple clusters from a file, given the file pointer.
1427 ; SI -> File pointer
1428 ; CX -> Cluster count
1430 ; SI -> File pointer (or 0 on EOF)
1441 cmp ecx,[si+file_left
]
1443 mov ecx,[si+file_left
]
1449 mov eax,[si+file_sector
]
1456 add [si+file_sector
],ecx
1457 sub [si+file_left
],ecx
1458 ja .not_eof
; CF = 0
1461 mov [si+file_sector
],ecx ; Mark as unused
1470 ; -----------------------------------------------------------------------------
1472 ; -----------------------------------------------------------------------------
1474 %include "getc.inc" ; getc et al
1475 %include "conio.inc" ; Console I/O
1476 %include "configinit.inc" ; Initialize configuration
1477 %include "parseconfig.inc" ; High-level config file handling
1478 %include "parsecmd.inc" ; Low-level config file handling
1479 %include "bcopy32.inc" ; 32-bit bcopy
1480 %include "loadhigh.inc" ; Load a file into high memory
1481 %include "font.inc" ; VGA font stuff
1482 %include "graphics.inc" ; VGA graphics
1483 %include "highmem.inc" ; High memory sizing
1484 %include "strcpy.inc" ; strcpy()
1485 %include "rawcon.inc" ; Console I/O w/o using the console functions
1487 ; -----------------------------------------------------------------------------
1488 ; Begin data section
1489 ; -----------------------------------------------------------------------------
1493 boot_prompt
db 'boot: ', 0
1494 wipe_char
db BS
, ' ', BS
, 0
1495 err_notfound
db 'Could not find kernel image: ',0
1496 err_notkernel
db CR
, LF
, 'Invalid or corrupt kernel image.', CR
, LF
, 0
1497 err_noram
db 'It appears your computer has less than '
1499 db 'K of low ("DOS")'
1501 db 'RAM. Linux needs at least this amount to boot. If you get'
1503 db 'this message in error, hold down the Ctrl key while'
1505 db 'booting, and I will take your word for it.', CR
, LF
, 0
1506 err_badcfg
db 'Unknown keyword in config file.', CR
, LF
, 0
1507 err_noparm
db 'Missing parameter in config file.', CR
, LF
, 0
1508 err_noinitrd
db CR
, LF
, 'Could not find ramdisk image: ', 0
1509 err_nohighmem
db 'Not enough memory to load specified kernel.', CR
, LF
, 0
1510 err_highload
db CR
, LF
, 'Kernel transfer failure.', CR
, LF
, 0
1511 err_oldkernel
db 'Cannot load a ramdisk with an old kernel image.'
1513 err_notdos
db ': attempted DOS system call', CR
, LF
, 0
1514 err_comlarge
db 'COMBOOT image too large.', CR
, LF
, 0
1515 err_a20
db CR
, LF
, 'A20 gate not responding!', CR
, LF
, 0
1516 notfound_msg
db 'not found', CR
, LF
, 0
1517 localboot_msg
db 'Booting from local disk...', CR
, LF
, 0
1518 cmdline_msg
db 'Command line: ', CR
, LF
, 0
1519 ready_msg
db 'Ready.', CR
, LF
, 0
1520 trying_msg
db 'Trying to load: ', 0
1521 crlfloading_msg
db CR
, LF
; Fall through
1522 loading_msg
db 'Loading ', 0
1525 fourbs_msg
db BS
, BS
, BS
, BS
, 0
1526 aborted_msg
db ' aborted.', CR
, LF
, 0
1527 crff_msg
db CR
, FF
, 0
1528 default_str
db 'default', 0
1529 default_len
equ ($
-default_str
)
1530 boot_dir
db '/boot' ; /boot/isolinux
1531 isolinux_dir
db '/isolinux', 0
1532 config_name
db 'isolinux.cfg', 0
1533 err_disk_image
db 'Cannot load disk image (invalid file)?', CR
, LF
, 0
1535 %ifdef DEBUG_MESSAGES
1536 dbg_rootdir_msg
db 'Root directory at LBA = ', 0
1537 dbg_isodir_msg
db 'isolinux directory at LBA = ', 0
1538 dbg_config_msg
db 'About to load config file...', CR
, LF
, 0
1539 dbg_configok_msg
db 'Configuration file opened...', CR
, LF
, 0
1542 ; Command line options we'd like to take a look at
1544 ; mem= and vga= are handled as normal 32-bit integer values
1545 initrd_cmd
db 'initrd='
1546 initrd_cmd_len
equ 7
1549 ; Config file keyword table
1551 %include "keywords.inc"
1554 ; Extensions to search for (in *forward* order).
1557 exten_table: db '.cbt' ; COMBOOT (specific)
1558 db '.img' ; Disk image
1559 db '.bin' ; CD boot sector
1560 db '.com' ; COMBOOT (same as DOS)
1563 dd 0, 0 ; Need 8 null bytes here
1566 ; Floppy image table
1569 img_table_count
equ 3
1571 dd 1200*1024 ; 1200K floppy
1572 db 1 ; Emulation type
1573 db 80-1 ; Max cylinder
1577 dd 1440*1024 ; 1440K floppy
1578 db 2 ; Emulation type
1579 db 80-1 ; Max cylinder
1583 dd 2880*1024 ; 2880K floppy
1584 db 3 ; Emulation type
1585 db 80-1 ; Max cylinder
1590 ; Misc initialized (data) variables
1594 ; Variables that are uninitialized in SYSLINUX but initialized here
1596 ; **** ISOLINUX:: We may have to make this flexible, based on what the
1597 ; **** BIOS expects our "sector size" to be.
1600 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1601 BufSafeSec
dw trackbufsize
/SECTOR_SIZE
; = how many sectors?
1602 BufSafeBytes
dw trackbufsize
; = how many bytes?
1603 EndOfGetCBuf
dw getcbuf
+trackbufsize
; = getcbuf+BufSafeBytes
1605 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1606 %error trackbufsize must be a multiple of SECTOR_SIZE