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 1994-2009 H. Peter Anvin - All Rights Reserved
12 ; Copyright 2009 Intel Corporation; author: H. Peter Anvin
14 ; This program is free software; you can redistribute it and/or modify
15 ; it under the terms of the GNU General Public License as published by
16 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
17 ; Boston MA 02111-1307, USA; either version 2 of the License, or
18 ; (at your option) any later version; incorporated herein by reference.
20 ; ****************************************************************************
26 ; Some semi-configurable constants... change on your own risk.
29 FILENAME_MAX_LG2
equ 8 ; log2(Max filename size Including final null)
30 FILENAME_MAX
equ (1 << FILENAME_MAX_LG2
)
31 NULLFILE
equ 0 ; Zero byte == null file name
32 NULLOFFSET
equ 0 ; Position in which to look
33 retry_count
equ 6 ; How patient are we with the BIOS?
34 %assign HIGHMEM_SLOP
128*1024 ; Avoid this much memory near the top
35 MAX_OPEN_LG2
equ 6 ; log2(Max number of open files)
36 MAX_OPEN
equ (1 << MAX_OPEN_LG2
)
37 SECTOR_SHIFT
equ 11 ; 2048 bytes/sector (El Torito requirement)
38 SECTOR_SIZE
equ (1 << SECTOR_SHIFT
)
40 ROOT_DIR_WORD
equ 0x002F
43 ; The following structure is used for "virtual kernels"; i.e. LILO-style
44 ; option labels. The options we permit here are `kernel' and `append
45 ; Since there is no room in the bottom 64K for all of these, we
46 ; stick them in high memory and copy them down before we need them.
49 vk_vname: resb FILENAME_MAX
; Virtual name **MUST BE FIRST!**
50 vk_rname: resb FILENAME_MAX
; Real name
52 vk_type: resb
1 ; Type of file
54 vk_append: resb max_cmd_len
+1 ; Command line
56 vk_end: equ $
; Should be <= vk_size
60 ; File structure. This holds the information for each currently open file.
63 file_sector resd
1 ; Sector pointer (0 = structure free)
64 file_bytesleft resd
1 ; Number of bytes left
65 file_left resd
1 ; Number of sectors left
70 %if
(open_file_t_size
& (open_file_t_size
-1))
71 %error
"open_file_t is not a power of 2"
76 dir_lba resd
1 ; Directory start (LBA)
77 dir_len resd
1 ; Length in bytes
78 dir_clust resd
1 ; Length in clusters
81 ; ---------------------------------------------------------------------------
83 ; ---------------------------------------------------------------------------
86 ; Memory below this point is reserved for the BIOS and the MBR
90 trackbuf resb trackbufsize
; Track buffer goes here
93 ; Some of these are touched before the whole image
94 ; is loaded. DO NOT move this to .bss16/.uibss.
97 ISOFileName resb
64 ; ISO filename canonicalization buffer
99 CurrentDir resb dir_t_size
; Current directory
100 RootDir resb dir_t_size
; Root directory
101 FirstSecSum resd
1 ; Checksum of bytes 64-2048
102 ImageDwords resd
1 ; isolinux.bin size, dwords
103 InitStack resd
1 ; Initial stack pointer (SS:SP)
104 DiskSys resw
1 ; Last INT 13h call
105 ImageSectors resw
1 ; isolinux.bin size, sectors
106 ; These following two are accessed as a single dword...
107 GetlinsecPtr resw
1 ; The sector-read pointer
108 BIOSName resw
1 ; Display string for BIOS type
109 %define HAVE_BIOSNAME
1
111 DiskError resb
1 ; Error code for disk I/O
112 DriveNumber resb
1 ; CD-ROM BIOS drive number
113 ISOFlags resb
1 ; Flags for ISO directory search
114 RetryCount resb
1 ; Used for disk access retries
115 bsSecPerTrack resw
1 ; Used in hybrid mode
116 bsHeads resw
1 ; Used in hybrid mode
121 ; El Torito spec packet
125 spec_packet: resb
1 ; Size of packet
126 sp_media: resb
1 ; Media type
127 sp_drive: resb
1 ; Drive number
128 sp_controller: resb
1 ; Controller index
129 sp_lba: resd
1 ; LBA for emulated disk image
130 sp_devspec: resw
1 ; IDE/SCSI information
131 sp_buffer: resw
1 ; User-provided buffer
132 sp_loadseg: resw
1 ; Load segment
133 sp_sectors: resw
1 ; Sector count
134 sp_chs: resb
3 ; Simulated CHS geometry
135 sp_dummy: resb
1 ; Scratch, safe to overwrite
138 ; EBIOS drive parameter packet
141 drive_params: resw
1 ; Buffer size
142 dp_flags: resw
1 ; Information flags
143 dp_cyl: resd
1 ; Physical cylinders
144 dp_head: resd
1 ; Physical heads
145 dp_sec: resd
1 ; Physical sectors/track
146 dp_totalsec: resd
2 ; Total sectors
147 dp_secsize: resw
1 ; Bytes per sector
148 dp_dpte: resd
1 ; Device Parameter Table
149 dp_dpi_key: resw
1 ; 0BEDDh if rest valid
150 dp_dpi_len: resb
1 ; DPI len
153 dp_bus: resb
4 ; Host bus type
154 dp_interface: resb
8 ; Interface type
155 db_i_path: resd
2 ; Interface path
156 db_d_path: resd
2 ; Device path
158 db_dpi_csum: resb
1 ; Checksum for DPI info
161 ; EBIOS disk address packet
164 dapa: resw
1 ; Packet size
165 .
count: resw
1 ; Block count
166 .
off: resw
1 ; Offset of buffer
167 .
seg: resw
1 ; Segment of buffer
168 .
lba: resd
2 ; LBA (LSW, MSW)
171 ; Spec packet for disk image emulation
174 dspec_packet: resb
1 ; Size of packet
175 dsp_media: resb
1 ; Media type
176 dsp_drive: resb
1 ; Drive number
177 dsp_controller: resb
1 ; Controller index
178 dsp_lba: resd
1 ; LBA for emulated disk image
179 dsp_devspec: resw
1 ; IDE/SCSI information
180 dsp_buffer: resw
1 ; User-provided buffer
181 dsp_loadseg: resw
1 ; Load segment
182 dsp_sectors: resw
1 ; Sector count
183 dsp_chs: resb
3 ; Simulated CHS geometry
184 dsp_dummy: resb
1 ; Scratch, safe to overwrite
188 _spec_len
equ _spec_end
- _spec_start
191 alignb open_file_t_size
192 Files resb MAX_OPEN
*open_file_t_size
196 ;; Primary entry point. Because BIOSes are buggy, we only load the first
197 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
200 StackBuf
equ $
-44 ; 44 bytes needed for
201 ; the bootsector chainloading
203 OrigESDI
equ StackBuf
-4 ; The high dword on the stack
204 StackTop
equ OrigESDI
208 _start: ; Far jump makes sure we canonicalize the address
211 times
8-($
-$$
) nop ; Pad to file offset 8
213 ; This table hopefully gets filled in by mkisofs using the
214 ; -boot-info-table option. If not, the values in this
215 ; table are default values that we can use to get us what
216 ; we need, at least under a certain set of assumptions.
217 bi_pvd: dd 16 ; LBA of primary volume descriptor
218 bi_file: dd 0 ; LBA of boot file
219 bi_length: dd 0xdeadbeef ; Length of boot file
220 bi_csum: dd 0xdeadbeef ; Checksum of boot file
221 bi_reserved: times
10 dd 0xdeadbeef ; Reserved
224 ; Custom entry point for the hybrid-mode disk.
225 ; The following values will have been pushed onto the
230 ; - DX (including drive number)
234 %ifndef DEBUG_MESSAGES
236 dd 0x7078c0fb ; An arbitrary number...
245 pop word [cs:bsSecPerTrack
]
246 pop word [cs:bsHeads
]
257 mov [cs:InitStack
],sp ; Save initial stack pointer
258 mov [cs:InitStack
+2],ss
261 mov sp,StackBuf
; Set up stack
262 push es ; Save initial ES:DI -> $PnP pointer
273 mov [GetlinsecPtr
],eax
276 mov si,syslinux_banner
278 %ifdef DEBUG_MESSAGES
286 ; Before modifying any memory, get the checksum of bytes
289 initial_csum: xor edi,edi
291 mov cx,(SECTOR_SIZE
-64) >> 2
295 mov [FirstSecSum
],edi
298 %ifdef DEBUG_MESSAGES
306 ; Initialize spec packet buffers
309 mov cx,_spec_len
>> 2
313 ; Initialize length field of the various packets
314 mov byte [spec_packet
],13h
315 mov byte [drive_params
],30
317 mov byte [dspec_packet
],13h
319 ; Other nonzero fields
320 inc word [dsp_sectors
]
322 ; Are we just pretending to be a CD-ROM?
323 cmp word [BIOSType
],bios_cdrom
324 jne found_drive
; If so, no spec packet...
326 ; Now figure out what we're actually doing
327 ; Note: use passed-in DL value rather than 7Fh because
328 ; at least some BIOSes will get the wrong value otherwise
329 mov ax,4B01h ; Get disk emulation status
333 jc award_hack
; changed for BrokenAwardHack
335 cmp [sp_drive
],dl ; Should contain the drive number
336 jne spec_query_failed
338 %ifdef DEBUG_MESSAGES
341 mov al,byte [sp_drive
]
347 ; Alright, we have found the drive. Now, try to find the
348 ; boot file itself. If we have a boot info table, life is
349 ; good; if not, we have to make some assumptions, and try
350 ; to figure things out ourselves. In particular, the
351 ; assumptions we have to make are:
352 ; - single session only
353 ; - only one boot entry (no menu or other alternatives)
355 cmp dword [bi_file
],0 ; Address of code to load
356 jne found_file
; Boot info table present :)
358 %ifdef DEBUG_MESSAGES
359 mov si,noinfotable_msg
363 ; No such luck. See if the spec packet contained one.
366 jz set_file
; Good enough
368 %ifdef DEBUG_MESSAGES
369 mov si,noinfoinspec_msg
373 ; No such luck. Get the Boot Record Volume, assuming single
374 ; session disk, and that we're the first entry in the chain.
375 mov eax,17 ; Assumed address of BRV
379 mov eax,[trackbuf
+47h] ; Get boot catalog address
381 call getonesec
; Get boot catalog
383 mov eax,[trackbuf
+28h] ; First boot entry
384 ; And hope and pray this is us...
386 ; Some BIOSes apparently have limitations on the size
387 ; that may be loaded (despite the El Torito spec being very
388 ; clear on the fact that it must all be loaded.) Therefore,
389 ; we load it ourselves, and *bleep* the BIOS.
395 ; Set up boot file sizes
397 sub eax,SECTOR_SIZE
-3 ; ... minus sector loaded
398 shr eax,2 ; bytes->dwords
399 mov [ImageDwords
],eax ; boot file dwords
401 shr eax,9 ; dwords->sectors
402 mov [ImageSectors
],ax ; boot file sectors
404 mov eax,[bi_file
] ; Address of code to load
405 inc eax ; Don't reload bootstrap code
406 %ifdef DEBUG_MESSAGES
413 ; Just in case some BIOSes have problems with
414 ; segment wraparound, use the normalized address
415 mov bx,((7C00h
+2048) >> 4)
418 mov bp,[ImageSectors
]
419 %ifdef DEBUG_MESSAGES
433 %ifdef DEBUG_MESSAGES
438 ; Verify the checksum on the loaded image.
442 mov ecx,[ImageDwords
]
443 mov edi,[FirstSecSum
] ; First sector checksum
450 ; SI wrapped around, advance ES
464 %ifdef DEBUG_MESSAGES
468 jmp all_read
; Jump to main code
470 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
471 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
472 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474 ;; There is a problem with certain versions of the AWARD BIOS ...
475 ;; the boot sector will be loaded and executed correctly, but, because the
476 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
477 ;; load the spec packet will fail. We scan for the equivalent of
486 ;; and use <direct far> as the new vector for int 13. The code above is
487 ;; used to load the boot code into ram, and there should be no reason
488 ;; for anybody to change it now or in the future. There are no opcodes
489 ;; that use encodings relativ to IP, so scanning is easy. If we find the
490 ;; code above in the BIOS code we can be pretty sure to run on a machine
491 ;; with an broken AWARD BIOS ...
493 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
495 %ifdef DEBUG_MESSAGES
;;
497 award_notice
db "Trying BrokenAwardHack first ...",CR
,LF
,0 ;;
498 award_not_orig
db "BAH: Original Int 13 vector : ",0 ;;
499 award_not_new
db "BAH: Int 13 vector changed to : ",0 ;;
500 award_not_succ
db "BAH: SUCCESS",CR
,LF
,0 ;;
501 award_not_fail
db "BAH: FAILURE" ;;
502 award_not_crlf
db CR
,LF
,0 ;;
506 award_oldint13
dd 0 ;;
507 award_string
db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah
,80h,1,09ch,09ah ;;
509 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
510 award_hack: mov si,spec_err_msg
; Moved to this place from
511 call writemsg
; spec_query_faild
513 %ifdef DEBUG_MESSAGES
;
515 mov si,award_notice
; display our plan
517 mov si,award_not_orig
; display original int 13
518 call writemsg
; vector
521 mov [award_oldint13
],eax ;
523 %ifdef DEBUG_MESSAGES
;
526 mov si,award_not_crlf
;
527 call writestr_early
;
530 mov ax,0f000h
; ES = BIOS Seg
533 xor di,di ; start at ES:DI = f000:0
534 award_loop: push di ; save DI
535 mov si,award_string
; scan for award_string
536 mov cx,7 ; length of award_string = 7dw
539 jcxz award_found
; jmp if found
540 inc di ; not found, inc di
543 award_failed: pop es ; No, not this way :-((
546 %ifdef DEBUG_MESSAGES
;
548 mov si,award_not_fail
; display failure ...
551 mov eax,[award_oldint13
] ; restore the original int
552 or eax,eax ; 13 vector if there is one
553 jz spec_query_failed
; and try other workarounds
555 jmp spec_query_failed
;
557 award_found: mov eax,[es:di+0eh
] ; load possible int 13 addr
560 cmp eax,[award_oldint13
] ; give up if this is the
561 jz award_failed
; active int 13 vector,
562 mov [13h*4],eax ; otherwise change 0:13h*4
565 %ifdef DEBUG_MESSAGES
;
567 push eax ; display message and
568 mov si,award_not_new
; new vector address
572 mov si,award_not_crlf
;
573 call writestr_early
;
575 mov ax,4B01h ; try to read the spec packet
576 mov dl,[DriveNumber
] ; now ... it should not fail
577 mov si,spec_packet
; any longer
581 %ifdef DEBUG_MESSAGES
;
583 mov si,award_not_succ
; display our SUCCESS
586 jmp found_drive
; and leave error recovery code
588 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
589 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
590 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
593 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
594 ; Try to scan the entire 80h-FFh from the end.
598 ; some code moved to BrokenAwardHack
604 mov byte [si],13h ; Size of buffer
615 cmp byte [sp_drive
],dl
618 ; Okay, good enough...
621 .
found_drive0: mov [DriveNumber
],dl
622 .
found_drive: jmp found_drive
624 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
625 ; but if this was the drive number originally passed in
626 ; DL then consider it "good enough"
632 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
633 ; passes garbage in sp_drive, and the drive number originally
634 ; passed in DL does not have 80h bit set.
639 .
still_broken: dec dx
643 ; No spec packet anywhere. Some particularly pathetic
644 ; BIOSes apparently don't even implement function
645 ; 4B01h, so we can't query a spec packet no matter
646 ; what. If we got a drive number in DL, then try to
647 ; use it, and if it works, then well...
649 cmp dl,81h ; Should be 81-FF at least
650 jb fatal_error
; If not, it's hopeless
652 ; Write a warning to indicate we're on *very* thin ice now
660 jmp .found_drive
; Pray that this works...
666 .
norge: jmp short .norge
668 ; Information message (DS:SI) output
669 ; Prefix with "isolinux: "
681 ; Write a character to the screen. There is a more "sophisticated"
682 ; version of this in the subsequent code, so we patch the pointer
698 ; int13: save all the segment registers and call INT 13h
699 ; Some CD-ROM BIOSes have been found to corrupt segment registers.
715 ; Get one sector. Convenience entry point.
719 ; Fall through to getlinsec
722 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
725 ; EAX - Linear sector number
726 ; ES:BX - Target buffer
729 getlinsec: jmp word [cs:GetlinsecPtr
]
731 %ifndef DEBUG_MESSAGES
734 ; First, the variants that we use when actually loading off a disk
735 ; (hybrid mode.) These are adapted versions of the equivalent routines
742 ; getlinsec implementation for floppy/HDD EBIOS (EDD)
747 shl eax,2 ; Convert to HDD sectors
751 push bp ; Sectors left
753 call maxtrans
; Enforce maximum transfer size
754 movzx edi,bp ; Sectors we are about to read
771 mov ah,42h ; Extended Read
775 lea sp,[si+16] ; Remove DAPA
778 add eax,edi ; Advance sector pointer
780 sub bp,di ; Sectors left
781 shl di,9 ; 512-byte sectors
782 add bx,di ; Advance buffer pointer
789 ; Some systems seem to get "stuck" in an error state when
790 ; using EBIOS. Doesn't happen when using CBIOS, which is
791 ; good, since some other systems get timeout failures
792 ; waiting for the floppy disk to spin up.
794 pushad ; Try resetting the device
799 loop .retry
; CX-- and jump if not zero
801 ;shr word [MaxTransfer],1 ; Reduce the transfer size
804 ; Total failure. Try falling back to CBIOS.
805 mov word [GetlinsecPtr
], getlinsec_cbios
806 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
809 jmp getlinsec_cbios.
loop
814 ; getlinsec implementation for legacy CBIOS
817 shl eax,2 ; Convert to HDD sectors
826 movzx esi,word [bsSecPerTrack
]
827 movzx edi,word [bsHeads
]
829 ; Dividing by sectors to get (track,sector): we may have
830 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
834 xchg cx,dx ; CX <- sector index (0-based)
837 div edi ; Convert track to head/cyl
839 ; We should test this, but it doesn't fit...
844 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
845 ; BP = sectors to transfer, SI = bsSecPerTrack,
846 ; ES:BX = data target
849 call maxtrans
; Enforce maximum transfer size
851 ; Must not cross track boundaries, so BP <= SI-CX
858 shl ah,6 ; Because IBM was STOOPID
859 ; and thought 8 bits were enough
860 ; then thought 10 bits were enough...
861 inc cx ; Sector numbers are 1-based, sigh
866 xchg ax,bp ; Sector to transfer count
867 mov ah,02h ; Read sectors
875 movzx ecx,al ; ECX <- sectors transferred
876 shl ax,9 ; Convert sectors in AL to bytes in AX
891 xchg ax,bp ; Sectors transferred <- 0
892 shr word [MaxTransfer
],1
897 ; Truncate BP to MaxTransfer
908 ; This is the variant we use for real CD-ROMs:
909 ; LBA, 2K sectors, some special error handling.
912 mov si,dapa
; Load up the DAPA
917 push bp ; Sectors left
918 cmp bp,[MaxTransferCD
]
920 mov bp,[MaxTransferCD
]
925 mov ah,42h ; Extended Read
929 movzx eax,word [si+2] ; Sectors we read
930 add [si+8],eax ; Advance sector pointer
931 sub bp,ax ; Sectors left
932 shl ax,SECTOR_SHIFT
-4 ; 2048-byte sectors -> segment
933 add [si+6],ax ; Advance buffer pointer
936 mov eax,[si+8] ; Next sector
940 xint13: mov byte [RetryCount
],retry_count
944 add sp,byte 8*4 ; Clean up stack
947 mov [DiskError
],ah ; Save error code
949 mov [DiskSys
],ax ; Save system call number
950 dec byte [RetryCount
]
954 mov ah,[dapa
+2] ; Sector transfer count
955 cmp al,2 ; Only 2 attempts left
957 mov ah,1 ; Drop transfer size to 1
961 ja .again
; First time, just try again
962 shr ah,1 ; Otherwise, try to reduce
963 adc ah,0 ; the max transfer size, but not to 0
965 mov [MaxTransferCD
],ah
971 .
real_error: mov si,diskerr_msg
984 ; Fall through to kaboom
987 ; kaboom: write a message and bail out. Wait for a user keypress,
988 ; then do a hard reboot.
992 RESET_STACK_AND_SEGS
AX
993 mov si,err_bootfailed
997 mov word [BIOS_magic
],0 ; Cold reboot
998 jmp 0F000h:0FFF0h
; Reset vector address
1000 ; -----------------------------------------------------------------------------
1001 ; Common modules needed in the first sector
1002 ; -----------------------------------------------------------------------------
1004 %include "writestr.inc" ; String output
1005 writestr_early
equ writestr
1006 %include "writehex.inc" ; Hexadecimal output
1008 ; -----------------------------------------------------------------------------
1009 ; Data that needs to be in the first sector
1010 ; -----------------------------------------------------------------------------
1012 syslinux_banner
db CR
, LF
, 'ISOLINUX ', VERSION_STR
, ' ', DATE_STR
, ' ', 0
1013 copyright_str
db ' Copyright (C) 1994-'
1015 db ' H. Peter Anvin et al', CR
, LF
, 0
1016 isolinux_str
db 'isolinux: ', 0
1017 %ifdef DEBUG_MESSAGES
1018 startup_msg: db 'Starting up, DL = ', 0
1019 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1020 secsize_msg: db 'Sector size ', 0
1021 offset_msg: db 'Main image LBA = ', 0
1022 size_msg: db 'Sectors to load = ', 0
1023 loaded_msg: db 'Loaded boot image, verifying...', CR
, LF
, 0
1024 verify_msg: db 'Image checksum verified.', CR
, LF
, 0
1025 allread_msg
db 'Main image read, jumping to main code...', CR
, LF
, 0
1027 noinfotable_msg
db 'No boot info table, assuming single session disk...', CR
, LF
, 0
1028 noinfoinspec_msg
db 'Spec packet missing LBA information, trying to wing it...', CR
, LF
, 0
1029 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR
, LF
, 0
1030 maybe_msg: db 'Found something at drive = ', 0
1031 alright_msg: db 'Looks reasonable, continuing...', CR
, LF
, 0
1032 nospec_msg
db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1033 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR
, LF
1034 trysbm_msg
db 'See http://syslinux.zytor.com/sbm for more information.', CR
, LF
, 0
1035 diskerr_msg: db 'Disk error ', 0
1036 oncall_str: db ', AX = ',0
1037 ondrive_str: db ', drive ', 0
1038 checkerr_msg: db 'Image checksum error, sorry...', CR
, LF
, 0
1040 err_bootfailed
db CR
, LF
, 'Boot failed: press a key to retry...'
1041 bailmsg
equ err_bootfailed
1045 bios_cdrom_str
db 'ETCD', 0
1046 %ifndef DEBUG_MESSAGES
1047 bios_cbios_str
db 'CHDD', 0
1048 bios_ebios_str
db 'EHDD' ,0
1052 bios_cdrom: dw getlinsec_cdrom
, bios_cdrom_str
1053 %ifndef DEBUG_MESSAGES
1054 bios_cbios: dw getlinsec_cbios
, bios_cbios_str
1055 bios_ebios: dw getlinsec_ebios
, bios_ebios_str
1058 ; Maximum transfer size
1059 MaxTransfer
dw 127 ; Hard disk modes
1060 MaxTransferCD
dw 32 ; CD mode
1062 rl_checkpt
equ $
; Must be <= 800h
1064 ; This pads to the end of sector 0 and errors out on
1066 times
2048-($
-$$
) db 0
1068 ; ----------------------------------------------------------------------------
1069 ; End of code and data that have to be in the first sector
1070 ; ----------------------------------------------------------------------------
1081 ; Common initialization code
1084 %include "cpuinit.inc"
1086 ; Patch the writechr routine to point to the full code
1090 mov ax,writechr_full
-2
1094 ; Tell the user we got this far...
1095 %ifndef DEBUG_MESSAGES
; Gets messy with debugging on
1096 mov si,copyright_str
1101 ; Now we're all set to start with our *real* business. First load the
1102 ; configuration file (if any) and parse it.
1104 ; In previous versions I avoided using 32-bit registers because of a
1105 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1106 ; random. I figure, though, that if there are any of those still left
1107 ; they probably won't be trying to install Linux on them...
1109 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1110 ; to take'm out. In fact, we may want to put them back if we're going
1111 ; to boot ELKS at some point.
1115 ; Now, we need to sniff out the actual filesystem data structures.
1116 ; mkisofs gave us a pointer to the primary volume descriptor
1117 ; (which will be at 16 only for a single-session disk!); from the PVD
1118 ; we should be able to find the rest of what we need to know.
1125 mov eax,[trackbuf
+156+2]
1126 mov [RootDir
+dir_lba
],eax
1127 mov [CurrentDir
+dir_lba
],eax
1128 %ifdef DEBUG_MESSAGES
1129 mov si,dbg_rootdir_msg
1134 mov eax,[trackbuf
+156+10]
1135 mov [RootDir
+dir_len
],eax
1136 mov [CurrentDir
+dir_len
],eax
1137 add eax,SECTOR_SIZE
-1
1138 shr eax,SECTOR_SHIFT
1139 mov [RootDir
+dir_clust
],eax
1140 mov [CurrentDir
+dir_clust
],eax
1142 ; Look for an isolinux directory, and if found,
1143 ; make it the current directory instead of the root
1145 ; Also copy the name of the directory to CurrentDirName
1146 mov word [CurrentDirName
],ROOT_DIR_WORD
; Write '/',0 to the CurrentDirName
1147 mov di,boot_dir
; Search for /boot/isolinux
1154 mov al,02h ; Search for /isolinux
1160 ; Copy current directory name to CurrentDirName
1164 mov di,CurrentDirName
1166 mov byte [di],0 ;done in case it's not word aligned
1172 mov [CurrentDir
+dir_len
],eax
1173 mov eax,[si+file_left
]
1174 mov [CurrentDir
+dir_clust
],eax
1175 xor eax,eax ; Free this file pointer entry
1176 xchg eax,[si+file_sector
]
1177 mov [CurrentDir
+dir_lba
],eax
1178 %ifdef DEBUG_MESSAGES
1180 mov si,dbg_isodir_msg
1189 ; Locate the configuration file
1192 %ifdef DEBUG_MESSAGES
1193 mov si,dbg_config_msg
1203 jz no_config_file
; Not found or empty
1205 %ifdef DEBUG_MESSAGES
1206 mov si,dbg_configok_msg
1211 ; Now we have the config file open. Parse the config file and
1212 ; run the user interface.
1217 ; Enable disk emulation. The kind of disk we emulate is dependent on the
1218 ; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
1226 mov edx,eax ; File size
1228 mov cx,img_table_count
1229 mov eax,[si+file_sector
] ; Starting LBA of file
1230 mov [dsp_lba
],eax ; Location of file
1231 mov byte [dsp_drive
], 0 ; 00h floppy, 80h hard disk
1240 ; Hard disk image. Need to examine the partition table
1241 ; in order to deduce the C/H/S geometry. Sigh.
1248 mov cx,1 ; Load 1 sector
1251 cmp word [trackbuf
+510],0aa55h
; Boot signature
1252 jne .bad_image
; Image not bootable
1254 mov cx,4 ; 4 partition entries
1255 mov di,trackbuf
+446 ; Start of partition table
1257 xor ax,ax ; Highest sector(al) head(ah)
1271 push edx ; File size
1274 inc bx ; # of heads in BX
1275 xor ah,ah ; # of sectors in AX
1276 cwde ; EAX[31:16] <- 0
1278 shl eax,9 ; Convert to bytes
1279 ; Now eax contains the number of bytes per cylinder
1285 inc eax ; Fractional cylinder...
1286 ; Now (e)ax contains the number of cylinders
1287 .
no_remainder: cmp eax,1024
1289 mov ax,1024 ; Max possible #
1290 .
ok_cyl: dec ax ; Convert to max cylinder no
1291 pop ebx ; S(bl) H(bh)
1297 mov al,4 ; Hard disk boot
1298 mov byte [dsp_drive
], 80h ; Drive 80h = hard disk
1303 and bl,0F0h
; Copy controller info bits
1305 mov [dsp_media
],al ; Emulation type
1307 mov [dsp_chs
],eax ; C/H/S geometry
1308 mov ax,[sp_devspec
] ; Copy device spec
1309 mov [dsp_devspec
],ax
1310 mov al,[sp_controller
] ; Copy controller index
1311 mov [dsp_controller
],al
1314 call vgaclearmode
; Reset video
1316 mov ax,4C00h
; Enable emulation and boot
1318 mov dl,[DriveNumber
]
1324 ; If this returns, we have problems
1326 mov si,err_disk_image
1331 ; Look for the highest seen H/S geometry
1332 ; We compute cylinders separately
1335 mov bl,[si] ; Head #
1338 mov ah,bl ; New highest head #
1339 .
done_track: mov bl,[si+1]
1340 and bl,3Fh
; Sector #
1348 ; Deallocates a file structure (pointer in SI)
1354 mov dword [si],0 ; First dword == file_left
1368 ; EAX = file length in bytes
1372 ; Assumes CS == DS == ES, and trashes BX and CX.
1374 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
1375 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
1376 ; for searching for directories.
1387 call allocate_file
; Temporary file structure for directory
1393 cmp byte [di],'/' ; If filename begins with slash
1395 inc di ; Skip leading slash
1396 mov si,RootDir
; Reference root directory instead
1398 mov eax,[si+dir_clust
]
1399 mov [bx+file_left
],eax
1400 shl eax,SECTOR_SHIFT
1401 mov [bx+file_bytesleft
],eax
1402 mov eax,[si+dir_lba
]
1403 mov [bx+file_sector
],eax
1404 mov edx,[si+dir_len
]
1415 mov [di-1],byte 0 ; Terminate at directory name
1416 mov cl,02h ; Search for directory
1419 push di ; Save these...
1422 ; Create recursion stack frame...
1423 push word .resume
; Where to "return" to
1428 ; Get a chunk of the directory
1429 ; This relies on the fact that ISOLINUX doesn't change SI
1439 movzx eax,byte [si] ; Length of directory entry
1445 test cl, byte 8Eh
; Unwanted file attributes!
1448 movzx cx,byte [si+32] ; File identifier length
1449 add si,byte 33 ; File identifier offset
1451 call iso_compare_names
1455 sub edx,eax ; Decrease bytes left
1457 add si,ax ; Advance pointer
1460 ; Did we finish the buffer?
1461 cmp si,trackbuf
+trackbufsize
1462 jb .compare
; No, keep going
1464 jmp short .getsome
; Get some more directory
1467 ; Advance to the beginning of next sector
1468 lea ax,[si+SECTOR_SIZE
-1]
1469 and ax,~
(SECTOR_SIZE
-1)
1471 jmp short .not_file
; We still need to do length checks
1473 .
failure: xor eax,eax ; ZF = 1
1474 mov [bx+file_sector
],eax
1479 mov eax,[si+2] ; Location of extent
1480 mov [bx+file_sector
],eax
1481 mov eax,[si+10] ; Data length
1482 mov [bx+file_bytesleft
],eax
1484 add eax,SECTOR_SIZE
-1
1485 shr eax,SECTOR_SHIFT
1486 mov [bx+file_left
],eax
1488 jz .failure
; Empty file?
1494 .
resume: ; We get here if we were only doing part of a lookup
1495 ; This relies on the fact that .success returns bx == si
1496 xchg edx,eax ; Directory length in edx
1497 pop cx ; Old ISOFlags
1498 pop di ; Next filename pointer
1499 mov byte [di-1], '/' ; Restore slash
1500 mov [ISOFlags
],cl ; Restore the flags
1501 jz .failure
; Did we fail? If so fail for real!
1502 jmp .look_for_slash
; Otherwise, next level
1505 ; allocate_file: Allocate a file structure
1518 .
check: cmp dword [bx], byte 0
1520 add bx,open_file_t_size
; ZF = 0
1522 ; ZF = 0 if we fell out of the loop
1527 ; iso_compare_names:
1528 ; Compare the names DS:SI and DS:DI and report if they are
1529 ; equal from an ISO 9660 perspective. SI is the name from
1530 ; the filesystem; CX indicates its length, and ';' terminates.
1531 ; DI is expected to end with a null.
1533 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
1537 ; First, terminate and canonicalize input filename
1540 .
canon_loop: jcxz .canon_end
1548 cmp di,ISOFileNameEnd
-1 ; Guard against buffer overrun
1553 cmp byte [di-1],'.' ; Remove terminal dots
1556 jmp short .canon_end
1558 mov [di],byte 0 ; Null-terminate string
1566 jz .success
; End of string for both
1567 and al,al ; Is either one end of string?
1568 jz .failure
; If so, failure
1571 or ax,2020h ; Convert to lower case
1574 .
failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
1578 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1579 ; to by ES:DI; ends on encountering any whitespace.
1582 ; This verifies that a filename is < FILENAME_MAX characters,
1583 ; doesn't contain whitespace, zero-pads the output buffer,
1584 ; and removes trailing dots and redundant slashes,
1585 ; so "repe cmpsb" can do a compare, and the
1586 ; path-searching routine gets a bit of an easier job.
1592 mov cx,FILENAME_MAX
-1
1597 cmp al,' ' ; If control or space, end
1599 cmp al,ah ; Repeated slash?
1606 .
mn_skip: loop .mn_loop
1608 cmp bx,di ; At the beginning of the buffer?
1610 cmp byte [es:di-1],'.' ; Terminal dot?
1612 cmp byte [es:di-1],'/' ; Terminal slash?
1614 .
mn_kill: dec di ; If so, remove it
1618 inc cx ; At least one null byte
1619 xor ax,ax ; Zero-fill name
1626 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1627 ; filename to the conventional representation. This is needed
1628 ; for the BOOT_IMAGE= parameter for the kernel.
1630 ; DS:SI -> input mangled file name
1631 ; ES:DI -> output buffer
1633 ; On return, DI points to the first byte after the output name,
1634 ; which is set to a null byte.
1636 unmangle_name: call strcpy
1637 dec di ; Point to final null byte
1641 ; getfssec: Get multiple clusters from a file, given the file pointer.
1645 ; SI -> File pointer
1646 ; CX -> Cluster count
1648 ; SI -> File pointer (or 0 on EOF)
1650 ; ECX -> Bytes actually read
1659 cmp ecx,[si+file_left
]
1661 mov ecx,[si+file_left
]
1665 mov eax,[si+file_sector
]
1671 ; ECX[31:16] == 0 here...
1672 add [si+file_sector
],ecx
1673 sub [si+file_left
],ecx
1674 shl ecx,SECTOR_SHIFT
; Convert to bytes
1675 cmp ecx,[si+file_bytesleft
]
1677 mov ecx,[si+file_bytesleft
]
1678 .
not_all: sub [si+file_bytesleft
],ecx
1679 jnz .
ret ; CF = 0 in this case...
1682 mov [si+file_sector
],eax ; Unused
1691 ; -----------------------------------------------------------------------------
1693 ; -----------------------------------------------------------------------------
1695 %include "common.inc" ; Universal modules
1696 %include "rawcon.inc" ; Console I/O w/o using the console functions
1697 %include "localboot.inc" ; Disk-based local boot
1699 ; -----------------------------------------------------------------------------
1700 ; Begin data section
1701 ; -----------------------------------------------------------------------------
1705 default_str
db 'default', 0
1706 default_len
equ ($
-default_str
)
1707 boot_dir
db '/boot' ; /boot/isolinux
1708 isolinux_dir
db '/isolinux', 0
1709 config_name
db 'isolinux.cfg', 0
1710 err_disk_image
db 'Cannot load disk image (invalid file)?', CR
, LF
, 0
1712 %ifdef DEBUG_MESSAGES
1713 dbg_rootdir_msg
db 'Root directory at LBA = ', 0
1714 dbg_isodir_msg
db 'isolinux directory at LBA = ', 0
1715 dbg_config_msg
db 'About to load config file...', CR
, LF
, 0
1716 dbg_configok_msg
db 'Configuration file opened...', CR
, LF
, 0
1720 ; Config file keyword table
1722 %include "keywords.inc"
1725 ; Extensions to search for (in *forward* order).
1728 exten_table: db '.cbt' ; COMBOOT (specific)
1729 db '.img' ; Disk image
1730 db '.bin' ; CD boot sector
1731 db '.com' ; COMBOOT (same as DOS)
1734 dd 0, 0 ; Need 8 null bytes here
1737 ; Floppy image table
1740 img_table_count
equ 3
1742 dd 1200*1024 ; 1200K floppy
1743 db 1 ; Emulation type
1744 db 80-1 ; Max cylinder
1748 dd 1440*1024 ; 1440K floppy
1749 db 2 ; Emulation type
1750 db 80-1 ; Max cylinder
1754 dd 2880*1024 ; 2880K floppy
1755 db 3 ; Emulation type
1756 db 80-1 ; Max cylinder
1761 ; Misc initialized (data) variables
1765 ; Variables that are uninitialized in SYSLINUX but initialized here
1767 ; **** ISOLINUX:: We may have to make this flexible, based on what the
1768 ; **** BIOS expects our "sector size" to be.
1771 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1772 BufSafeBytes
dw trackbufsize
; = how many bytes?
1774 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1775 %error trackbufsize must be a multiple of SECTOR_SIZE