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 .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
117 bsHidden resq
1 ; Used in hybrid mode
118 bsSecPerTrack resw
1 ; Used in hybrid mode
119 bsHeads resw
1 ; Used in hybrid mode
123 ; El Torito spec packet
128 spec_packet: resb
1 ; Size of packet
129 sp_media: resb
1 ; Media type
130 sp_drive: resb
1 ; Drive number
131 sp_controller: resb
1 ; Controller index
132 sp_lba: resd
1 ; LBA for emulated disk image
133 sp_devspec: resw
1 ; IDE/SCSI information
134 sp_buffer: resw
1 ; User-provided buffer
135 sp_loadseg: resw
1 ; Load segment
136 sp_sectors: resw
1 ; Sector count
137 sp_chs: resb
3 ; Simulated CHS geometry
138 sp_dummy: resb
1 ; Scratch, safe to overwrite
141 ; EBIOS drive parameter packet
144 drive_params: resw
1 ; Buffer size
145 dp_flags: resw
1 ; Information flags
146 dp_cyl: resd
1 ; Physical cylinders
147 dp_head: resd
1 ; Physical heads
148 dp_sec: resd
1 ; Physical sectors/track
149 dp_totalsec: resd
2 ; Total sectors
150 dp_secsize: resw
1 ; Bytes per sector
151 dp_dpte: resd
1 ; Device Parameter Table
152 dp_dpi_key: resw
1 ; 0BEDDh if rest valid
153 dp_dpi_len: resb
1 ; DPI len
156 dp_bus: resb
4 ; Host bus type
157 dp_interface: resb
8 ; Interface type
158 db_i_path: resd
2 ; Interface path
159 db_d_path: resd
2 ; Device path
161 db_dpi_csum: resb
1 ; Checksum for DPI info
164 ; EBIOS disk address packet
167 dapa: resw
1 ; Packet size
168 .
count: resw
1 ; Block count
169 .
off: resw
1 ; Offset of buffer
170 .
seg: resw
1 ; Segment of buffer
171 .
lba: resd
2 ; LBA (LSW, MSW)
174 ; Spec packet for disk image emulation
177 dspec_packet: resb
1 ; Size of packet
178 dsp_media: resb
1 ; Media type
179 dsp_drive: resb
1 ; Drive number
180 dsp_controller: resb
1 ; Controller index
181 dsp_lba: resd
1 ; LBA for emulated disk image
182 dsp_devspec: resw
1 ; IDE/SCSI information
183 dsp_buffer: resw
1 ; User-provided buffer
184 dsp_loadseg: resw
1 ; Load segment
185 dsp_sectors: resw
1 ; Sector count
186 dsp_chs: resb
3 ; Simulated CHS geometry
187 dsp_dummy: resb
1 ; Scratch, safe to overwrite
191 _spec_len
equ _spec_end
- _spec_start
193 alignb open_file_t_size
194 Files resb MAX_OPEN
*open_file_t_size
198 ;; Primary entry point. Because BIOSes are buggy, we only load the first
199 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
202 StackBuf
equ STACK_TOP
-44 ; 44 bytes needed for
203 ; the bootsector chainloading
205 OrigESDI
equ StackBuf
-4 ; The high dword on the stack
209 _start: ; Far jump makes sure we canonicalize the address
212 times
8-($
-$$
) nop ; Pad to file offset 8
214 ; This table hopefully gets filled in by mkisofs using the
215 ; -boot-info-table option. If not, the values in this
216 ; table are default values that we can use to get us what
217 ; we need, at least under a certain set of assumptions.
218 bi_pvd: dd 16 ; LBA of primary volume descriptor
219 bi_file: dd 0 ; LBA of boot file
220 bi_length: dd 0xdeadbeef ; Length of boot file
221 bi_csum: dd 0xdeadbeef ; Checksum of boot file
222 bi_reserved: times
10 dd 0xdeadbeef ; Reserved
225 ; Custom entry point for the hybrid-mode disk.
226 ; The following values will have been pushed onto the
228 ; - partition offset (qword)
231 ; - DX (including drive number)
237 ; If we had an old isohybrid, the partition offset will
238 ; be missing; we can check for that with sp >= 0x7c00.
239 ; Serious hack alert.
240 %ifndef DEBUG_MESSAGES
242 dd 0x7078c0fb ; An arbitrary number...
246 pop word [cs:bsSecPerTrack
]
247 pop word [cs:bsHeads
]
258 mov [cs:bsHidden
],eax
259 mov [cs:bsHidden
+4],ebx
270 mov [cs:InitStack
],sp ; Save initial stack pointer
271 mov [cs:InitStack
+2],ss
274 mov sp,StackBuf
; Set up stack
275 push es ; Save initial ES:DI -> $PnP pointer
286 mov [GetlinsecPtr
],eax
289 mov si,syslinux_banner
291 %ifdef DEBUG_MESSAGES
299 ; Before modifying any memory, get the checksum of bytes
302 initial_csum: xor edi,edi
304 mov cx,(SECTOR_SIZE
-64) >> 2
308 mov [FirstSecSum
],edi
311 %ifdef DEBUG_MESSAGES
319 ; Initialize spec packet buffers
322 mov cx,_spec_len
>> 2
326 ; Initialize length field of the various packets
327 mov byte [spec_packet
],13h
328 mov byte [drive_params
],30
330 mov byte [dspec_packet
],13h
332 ; Other nonzero fields
333 inc word [dsp_sectors
]
335 ; Are we just pretending to be a CD-ROM?
336 cmp word [BIOSType
],bios_cdrom
337 jne found_drive
; If so, no spec packet...
339 ; Now figure out what we're actually doing
340 ; Note: use passed-in DL value rather than 7Fh because
341 ; at least some BIOSes will get the wrong value otherwise
342 mov ax,4B01h ; Get disk emulation status
346 jc award_hack
; changed for BrokenAwardHack
348 cmp [sp_drive
],dl ; Should contain the drive number
349 jne spec_query_failed
351 %ifdef DEBUG_MESSAGES
354 mov al,byte [sp_drive
]
360 ; Alright, we have found the drive. Now, try to find the
361 ; boot file itself. If we have a boot info table, life is
362 ; good; if not, we have to make some assumptions, and try
363 ; to figure things out ourselves. In particular, the
364 ; assumptions we have to make are:
365 ; - single session only
366 ; - only one boot entry (no menu or other alternatives)
368 cmp dword [bi_file
],0 ; Address of code to load
369 jne found_file
; Boot info table present :)
371 %ifdef DEBUG_MESSAGES
372 mov si,noinfotable_msg
376 ; No such luck. See if the spec packet contained one.
379 jz set_file
; Good enough
381 %ifdef DEBUG_MESSAGES
382 mov si,noinfoinspec_msg
386 ; No such luck. Get the Boot Record Volume, assuming single
387 ; session disk, and that we're the first entry in the chain.
388 mov eax,17 ; Assumed address of BRV
392 mov eax,[trackbuf
+47h] ; Get boot catalog address
394 call getonesec
; Get boot catalog
396 mov eax,[trackbuf
+28h] ; First boot entry
397 ; And hope and pray this is us...
399 ; Some BIOSes apparently have limitations on the size
400 ; that may be loaded (despite the El Torito spec being very
401 ; clear on the fact that it must all be loaded.) Therefore,
402 ; we load it ourselves, and *bleep* the BIOS.
408 ; Set up boot file sizes
410 sub eax,SECTOR_SIZE
-3 ; ... minus sector loaded
411 shr eax,2 ; bytes->dwords
412 mov [ImageDwords
],eax ; boot file dwords
414 shr eax,9 ; dwords->sectors
415 mov [ImageSectors
],ax ; boot file sectors
417 mov eax,[bi_file
] ; Address of code to load
418 inc eax ; Don't reload bootstrap code
419 %ifdef DEBUG_MESSAGES
426 ; Just in case some BIOSes have problems with
427 ; segment wraparound, use the normalized address
428 mov bx,((7C00h
+2048) >> 4)
431 mov bp,[ImageSectors
]
432 %ifdef DEBUG_MESSAGES
446 %ifdef DEBUG_MESSAGES
451 ; Verify the checksum on the loaded image.
455 mov ecx,[ImageDwords
]
456 mov edi,[FirstSecSum
] ; First sector checksum
463 ; SI wrapped around, advance ES
477 %ifdef DEBUG_MESSAGES
481 jmp all_read
; Jump to main code
483 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
487 ;; There is a problem with certain versions of the AWARD BIOS ...
488 ;; the boot sector will be loaded and executed correctly, but, because the
489 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
490 ;; load the spec packet will fail. We scan for the equivalent of
499 ;; and use <direct far> as the new vector for int 13. The code above is
500 ;; used to load the boot code into ram, and there should be no reason
501 ;; for anybody to change it now or in the future. There are no opcodes
502 ;; that use encodings relativ to IP, so scanning is easy. If we find the
503 ;; code above in the BIOS code we can be pretty sure to run on a machine
504 ;; with an broken AWARD BIOS ...
506 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
508 %ifdef DEBUG_MESSAGES
;;
510 award_notice
db "Trying BrokenAwardHack first ...",CR
,LF
,0 ;;
511 award_not_orig
db "BAH: Original Int 13 vector : ",0 ;;
512 award_not_new
db "BAH: Int 13 vector changed to : ",0 ;;
513 award_not_succ
db "BAH: SUCCESS",CR
,LF
,0 ;;
514 award_not_fail
db "BAH: FAILURE" ;;
515 award_not_crlf
db CR
,LF
,0 ;;
519 award_oldint13
dd 0 ;;
520 award_string
db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah
,80h,1,09ch,09ah ;;
522 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523 award_hack: mov si,spec_err_msg
; Moved to this place from
524 call writemsg
; spec_query_faild
526 %ifdef DEBUG_MESSAGES
;
528 mov si,award_notice
; display our plan
530 mov si,award_not_orig
; display original int 13
531 call writemsg
; vector
534 mov [award_oldint13
],eax ;
536 %ifdef DEBUG_MESSAGES
;
539 mov si,award_not_crlf
;
540 call writestr_early
;
543 mov ax,0f000h
; ES = BIOS Seg
546 xor di,di ; start at ES:DI = f000:0
547 award_loop: push di ; save DI
548 mov si,award_string
; scan for award_string
549 mov cx,7 ; length of award_string = 7dw
552 jcxz award_found
; jmp if found
553 inc di ; not found, inc di
556 award_failed: pop es ; No, not this way :-((
559 %ifdef DEBUG_MESSAGES
;
561 mov si,award_not_fail
; display failure ...
564 mov eax,[award_oldint13
] ; restore the original int
565 or eax,eax ; 13 vector if there is one
566 jz spec_query_failed
; and try other workarounds
568 jmp spec_query_failed
;
570 award_found: mov eax,[es:di+0eh
] ; load possible int 13 addr
573 cmp eax,[award_oldint13
] ; give up if this is the
574 jz award_failed
; active int 13 vector,
575 mov [13h*4],eax ; otherwise change 0:13h*4
578 %ifdef DEBUG_MESSAGES
;
580 push eax ; display message and
581 mov si,award_not_new
; new vector address
585 mov si,award_not_crlf
;
586 call writestr_early
;
588 mov ax,4B01h ; try to read the spec packet
589 mov dl,[DriveNumber
] ; now ... it should not fail
590 mov si,spec_packet
; any longer
594 %ifdef DEBUG_MESSAGES
;
596 mov si,award_not_succ
; display our SUCCESS
599 jmp found_drive
; and leave error recovery code
601 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
602 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
603 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
606 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
607 ; Try to scan the entire 80h-FFh from the end.
611 ; some code moved to BrokenAwardHack
617 mov byte [si],13h ; Size of buffer
628 cmp byte [sp_drive
],dl
631 ; Okay, good enough...
634 .
found_drive0: mov [DriveNumber
],dl
635 .
found_drive: jmp found_drive
637 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
638 ; but if this was the drive number originally passed in
639 ; DL then consider it "good enough"
645 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
646 ; passes garbage in sp_drive, and the drive number originally
647 ; passed in DL does not have 80h bit set.
652 .
still_broken: dec dx
656 ; No spec packet anywhere. Some particularly pathetic
657 ; BIOSes apparently don't even implement function
658 ; 4B01h, so we can't query a spec packet no matter
659 ; what. If we got a drive number in DL, then try to
660 ; use it, and if it works, then well...
662 cmp dl,81h ; Should be 81-FF at least
663 jb fatal_error
; If not, it's hopeless
665 ; Write a warning to indicate we're on *very* thin ice now
673 jmp .found_drive
; Pray that this works...
679 .
norge: jmp short .norge
681 ; Information message (DS:SI) output
682 ; Prefix with "isolinux: "
694 ; Write a character to the screen. There is a more "sophisticated"
695 ; version of this in the subsequent code, so we patch the pointer
700 jmp near writechr_simple
; 3-byte jump
713 ; int13: save all the segment registers and call INT 13h.
714 ; Some CD-ROM BIOSes have been found to corrupt segment registers
715 ; and/or disable interrupts.
726 setc [bp+10] ; Propagate CF to the caller
736 ; Get one sector. Convenience entry point.
740 ; Fall through to getlinsec
743 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
746 ; EAX - Linear sector number
747 ; ES:BX - Target buffer
750 getlinsec: jmp word [cs:GetlinsecPtr
]
752 %ifndef DEBUG_MESSAGES
755 ; First, the variants that we use when actually loading off a disk
756 ; (hybrid mode.) These are adapted versions of the equivalent routines
763 ; getlinsec implementation for floppy/HDD EBIOS (EDD)
768 shl eax,2 ; Convert to HDD sectors
774 push bp ; Sectors left
776 call maxtrans
; Enforce maximum transfer size
777 movzx edi,bp ; Sectors we are about to read
794 mov ah,42h ; Extended Read
798 lea sp,[si+16] ; Remove DAPA
801 add eax,edi ; Advance sector pointer
803 sub bp,di ; Sectors left
804 shl di,9 ; 512-byte sectors
805 add bx,di ; Advance buffer pointer
812 ; Some systems seem to get "stuck" in an error state when
813 ; using EBIOS. Doesn't happen when using CBIOS, which is
814 ; good, since some other systems get timeout failures
815 ; waiting for the floppy disk to spin up.
817 pushad ; Try resetting the device
822 loop .retry
; CX-- and jump if not zero
824 ;shr word [MaxTransfer],1 ; Reduce the transfer size
827 ; Total failure. Try falling back to CBIOS.
828 mov word [GetlinsecPtr
], getlinsec_cbios
829 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
832 jmp getlinsec_cbios.
loop
837 ; getlinsec implementation for legacy CBIOS
841 shl eax,2 ; Convert to HDD sectors
851 movzx esi,word [bsSecPerTrack
]
852 movzx edi,word [bsHeads
]
854 ; Dividing by sectors to get (track,sector): we may have
855 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
859 xchg cx,dx ; CX <- sector index (0-based)
862 div edi ; Convert track to head/cyl
864 ; We should test this, but it doesn't fit...
869 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
870 ; BP = sectors to transfer, SI = bsSecPerTrack,
871 ; ES:BX = data target
874 call maxtrans
; Enforce maximum transfer size
876 ; Must not cross track boundaries, so BP <= SI-CX
883 shl ah,6 ; Because IBM was STOOPID
884 ; and thought 8 bits were enough
885 ; then thought 10 bits were enough...
886 inc cx ; Sector numbers are 1-based, sigh
891 xchg ax,bp ; Sector to transfer count
892 mov ah,02h ; Read sectors
900 movzx ecx,al ; ECX <- sectors transferred
901 shl ax,9 ; Convert sectors in AL to bytes in AX
916 xchg ax,bp ; Sectors transferred <- 0
917 shr word [MaxTransfer
],1
922 ; Truncate BP to MaxTransfer
933 ; This is the variant we use for real CD-ROMs:
934 ; LBA, 2K sectors, some special error handling.
937 mov si,dapa
; Load up the DAPA
942 push bp ; Sectors left
943 cmp bp,[MaxTransferCD
]
945 mov bp,[MaxTransferCD
]
950 mov ah,42h ; Extended Read
954 movzx eax,word [si+2] ; Sectors we read
955 add [si+8],eax ; Advance sector pointer
956 sub bp,ax ; Sectors left
957 shl ax,SECTOR_SHIFT
-4 ; 2048-byte sectors -> segment
958 add [si+6],ax ; Advance buffer pointer
961 mov eax,[si+8] ; Next sector
965 xint13: mov byte [RetryCount
],retry_count
969 add sp,byte 8*4 ; Clean up stack
972 mov [DiskError
],ah ; Save error code
974 mov [DiskSys
],ax ; Save system call number
975 dec byte [RetryCount
]
979 mov ah,[dapa
+2] ; Sector transfer count
980 cmp al,2 ; Only 2 attempts left
982 mov ah,1 ; Drop transfer size to 1
986 ja .again
; First time, just try again
987 shr ah,1 ; Otherwise, try to reduce
988 adc ah,0 ; the max transfer size, but not to 0
990 mov [MaxTransferCD
],ah
996 .
real_error: mov si,diskerr_msg
1009 ; Fall through to kaboom
1012 ; kaboom: write a message and bail out. Wait for a user keypress,
1013 ; then do a hard reboot.
1017 RESET_STACK_AND_SEGS
AX
1018 mov si,err_bootfailed
1022 mov word [BIOS_magic
],0 ; Cold reboot
1023 jmp 0F000h:0FFF0h
; Reset vector address
1025 ; -----------------------------------------------------------------------------
1026 ; Common modules needed in the first sector
1027 ; -----------------------------------------------------------------------------
1029 %include "writestr.inc" ; String output
1030 writestr_early
equ writestr
1031 %include "writehex.inc" ; Hexadecimal output
1033 ; -----------------------------------------------------------------------------
1034 ; Data that needs to be in the first sector
1035 ; -----------------------------------------------------------------------------
1037 syslinux_banner
db CR
, LF
, MY_NAME
, ' ', VERSION_STR
, ' ', DATE_STR
, ' ', 0
1038 copyright_str
db ' Copyright (C) 1994-'
1040 db ' H. Peter Anvin et al', CR
, LF
, 0
1041 isolinux_str
db 'isolinux: ', 0
1042 %ifdef DEBUG_MESSAGES
1043 startup_msg: db 'Starting up, DL = ', 0
1044 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1045 secsize_msg: db 'Sector size ', 0
1046 offset_msg: db 'Main image LBA = ', 0
1047 size_msg: db 'Sectors to load = ', 0
1048 loaded_msg: db 'Loaded boot image, verifying...', CR
, LF
, 0
1049 verify_msg: db 'Image checksum verified.', CR
, LF
, 0
1050 allread_msg
db 'Main image read, jumping to main code...', CR
, LF
, 0
1052 noinfotable_msg
db 'No boot info table, assuming single session disk...', CR
, LF
, 0
1053 noinfoinspec_msg
db 'Spec packet missing LBA information, trying to wing it...', CR
, LF
, 0
1054 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR
, LF
, 0
1055 maybe_msg: db 'Found something at drive = ', 0
1056 alright_msg: db 'Looks reasonable, continuing...', CR
, LF
, 0
1057 nospec_msg
db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1058 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR
, LF
1059 trysbm_msg
db 'See http://syslinux.zytor.com/sbm for more information.', CR
, LF
, 0
1060 diskerr_msg: db 'Disk error ', 0
1061 oncall_str: db ', AX = ',0
1062 ondrive_str: db ', drive ', 0
1063 checkerr_msg: db 'Image checksum error, sorry...', CR
, LF
, 0
1065 err_bootfailed
db CR
, LF
, 'Boot failed: press a key to retry...'
1066 bailmsg
equ err_bootfailed
1070 bios_cdrom_str
db 'ETCD', 0
1071 %ifndef DEBUG_MESSAGES
1072 bios_cbios_str
db 'CHDD', 0
1073 bios_ebios_str
db 'EHDD' ,0
1077 bios_cdrom: dw getlinsec_cdrom
, bios_cdrom_str
1078 %ifndef DEBUG_MESSAGES
1079 bios_cbios: dw getlinsec_cbios
, bios_cbios_str
1080 bios_ebios: dw getlinsec_ebios
, bios_ebios_str
1083 ; Maximum transfer size
1084 MaxTransfer
dw 127 ; Hard disk modes
1085 MaxTransferCD
dw 32 ; CD mode
1087 rl_checkpt
equ $
; Must be <= 800h
1089 ; This pads to the end of sector 0 and errors out on
1091 times
2048-($
-$$
) db 0
1093 ; ----------------------------------------------------------------------------
1094 ; End of code and data that have to be in the first sector
1095 ; ----------------------------------------------------------------------------
1104 ; Common initialization code
1107 %include "cpuinit.inc"
1109 ; Patch the writechr routine to point to the full code
1110 mov word [writechr
+1], writechr_full
-(writechr
+3)
1112 ; Tell the user we got this far...
1113 %ifndef DEBUG_MESSAGES
; Gets messy with debugging on
1114 mov si,copyright_str
1119 ; Now we're all set to start with our *real* business. First load the
1120 ; configuration file (if any) and parse it.
1122 ; In previous versions I avoided using 32-bit registers because of a
1123 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1124 ; random. I figure, though, that if there are any of those still left
1125 ; they probably won't be trying to install Linux on them...
1127 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1128 ; to take'm out. In fact, we may want to put them back if we're going
1129 ; to boot ELKS at some point.
1133 ; Now, we need to sniff out the actual filesystem data structures.
1134 ; mkisofs gave us a pointer to the primary volume descriptor
1135 ; (which will be at 16 only for a single-session disk!); from the PVD
1136 ; we should be able to find the rest of what we need to know.
1143 mov eax,[trackbuf
+156+2]
1144 mov [RootDir
+dir_lba
],eax
1145 mov [CurrentDir
+dir_lba
],eax
1146 %ifdef DEBUG_MESSAGES
1147 mov si,dbg_rootdir_msg
1152 mov eax,[trackbuf
+156+10]
1153 mov [RootDir
+dir_len
],eax
1154 mov [CurrentDir
+dir_len
],eax
1155 add eax,SECTOR_SIZE
-1
1156 shr eax,SECTOR_SHIFT
1157 mov [RootDir
+dir_clust
],eax
1158 mov [CurrentDir
+dir_clust
],eax
1160 ; Look for an isolinux directory, and if found,
1161 ; make it the current directory instead of the root
1163 ; Also copy the name of the directory to CurrentDirName
1164 mov word [CurrentDirName
],ROOT_DIR_WORD
; Write '/',0 to the CurrentDirName
1165 mov di,boot_dir
; Search for /boot/isolinux
1172 mov al,02h ; Search for /isolinux
1178 ; Copy current directory name to CurrentDirName
1182 mov di,CurrentDirName
1184 mov byte [di],0 ;done in case it's not word aligned
1190 mov [CurrentDir
+dir_len
],eax
1191 mov eax,[si+file_left
]
1192 mov [CurrentDir
+dir_clust
],eax
1193 xor eax,eax ; Free this file pointer entry
1194 xchg eax,[si+file_sector
]
1195 mov [CurrentDir
+dir_lba
],eax
1196 %ifdef DEBUG_MESSAGES
1198 mov si,dbg_isodir_msg
1207 ; Locate the configuration file
1210 %ifdef DEBUG_MESSAGES
1211 mov si,dbg_config_msg
1221 jz no_config_file
; Not found or empty
1223 %ifdef DEBUG_MESSAGES
1224 mov si,dbg_configok_msg
1229 ; Now we have the config file open. Parse the config file and
1230 ; run the user interface.
1235 ; Enable disk emulation. The kind of disk we emulate is dependent on the
1236 ; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
1244 mov edx,eax ; File size
1246 mov cx,img_table_count
1247 mov eax,[si+file_sector
] ; Starting LBA of file
1248 mov [dsp_lba
],eax ; Location of file
1249 mov byte [dsp_drive
], 0 ; 00h floppy, 80h hard disk
1258 ; Hard disk image. Need to examine the partition table
1259 ; in order to deduce the C/H/S geometry. Sigh.
1266 mov cx,1 ; Load 1 sector
1269 cmp word [trackbuf
+510],0aa55h
; Boot signature
1270 jne .bad_image
; Image not bootable
1272 mov cx,4 ; 4 partition entries
1273 mov di,trackbuf
+446 ; Start of partition table
1275 xor ax,ax ; Highest sector(al) head(ah)
1289 push edx ; File size
1292 inc bx ; # of heads in BX
1293 xor ah,ah ; # of sectors in AX
1294 cwde ; EAX[31:16] <- 0
1296 shl eax,9 ; Convert to bytes
1297 ; Now eax contains the number of bytes per cylinder
1303 inc eax ; Fractional cylinder...
1304 ; Now (e)ax contains the number of cylinders
1305 .
no_remainder: cmp eax,1024
1307 mov ax,1024 ; Max possible #
1308 .
ok_cyl: dec ax ; Convert to max cylinder no
1309 pop ebx ; S(bl) H(bh)
1315 mov al,4 ; Hard disk boot
1316 mov byte [dsp_drive
], 80h ; Drive 80h = hard disk
1321 and bl,0F0h
; Copy controller info bits
1323 mov [dsp_media
],al ; Emulation type
1325 mov [dsp_chs
],eax ; C/H/S geometry
1326 mov ax,[sp_devspec
] ; Copy device spec
1327 mov [dsp_devspec
],ax
1328 mov al,[sp_controller
] ; Copy controller index
1329 mov [dsp_controller
],al
1332 call vgaclearmode
; Reset video
1334 mov ax,4C00h
; Enable emulation and boot
1336 mov dl,[DriveNumber
]
1342 ; If this returns, we have problems
1344 mov si,err_disk_image
1349 ; Look for the highest seen H/S geometry
1350 ; We compute cylinders separately
1353 mov bl,[si] ; Head #
1356 mov ah,bl ; New highest head #
1357 .
done_track: mov bl,[si+1]
1358 and bl,3Fh
; Sector #
1366 ; Deallocates a file structure (pointer in SI)
1372 mov dword [si],0 ; First dword == file_left
1386 ; EAX = file length in bytes
1390 ; Assumes CS == DS == ES, and trashes BX and CX.
1392 ; searchdir_iso is a special entry point for ISOLINUX only. In addition
1393 ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
1394 ; for searching for directories.
1405 call allocate_file
; Temporary file structure for directory
1411 cmp byte [di],'/' ; If filename begins with slash
1413 inc di ; Skip leading slash
1414 mov si,RootDir
; Reference root directory instead
1416 mov eax,[si+dir_clust
]
1417 mov [bx+file_left
],eax
1418 shl eax,SECTOR_SHIFT
1419 mov [bx+file_bytesleft
],eax
1420 mov eax,[si+dir_lba
]
1421 mov [bx+file_sector
],eax
1422 mov edx,[si+dir_len
]
1433 mov [di-1],byte 0 ; Terminate at directory name
1434 mov cl,02h ; Search for directory
1437 push di ; Save these...
1440 ; Create recursion stack frame...
1441 push word .resume
; Where to "return" to
1446 ; Get a chunk of the directory
1447 ; This relies on the fact that ISOLINUX doesn't change SI
1457 movzx eax,byte [si] ; Length of directory entry
1463 test cl, byte 8Eh
; Unwanted file attributes!
1466 movzx cx,byte [si+32] ; File identifier length
1467 add si,byte 33 ; File identifier offset
1469 call iso_compare_names
1473 sub edx,eax ; Decrease bytes left
1475 add si,ax ; Advance pointer
1478 ; Did we finish the buffer?
1479 cmp si,trackbuf
+trackbufsize
1480 jb .compare
; No, keep going
1482 jmp short .getsome
; Get some more directory
1485 ; Advance to the beginning of next sector
1486 lea ax,[si+SECTOR_SIZE
-1]
1487 and ax,~
(SECTOR_SIZE
-1)
1489 jmp short .not_file
; We still need to do length checks
1491 .
failure: xor eax,eax ; ZF = 1
1492 mov [bx+file_sector
],eax
1497 mov eax,[si+2] ; Location of extent
1498 mov [bx+file_sector
],eax
1499 mov eax,[si+10] ; Data length
1500 mov [bx+file_bytesleft
],eax
1502 add eax,SECTOR_SIZE
-1
1503 shr eax,SECTOR_SHIFT
1504 mov [bx+file_left
],eax
1506 jz .failure
; Empty file?
1512 .
resume: ; We get here if we were only doing part of a lookup
1513 ; This relies on the fact that .success returns bx == si
1514 xchg edx,eax ; Directory length in edx
1515 pop cx ; Old ISOFlags
1516 pop di ; Next filename pointer
1517 mov byte [di-1], '/' ; Restore slash
1518 mov [ISOFlags
],cl ; Restore the flags
1519 jz .failure
; Did we fail? If so fail for real!
1520 jmp .look_for_slash
; Otherwise, next level
1523 ; allocate_file: Allocate a file structure
1536 .
check: cmp dword [bx], byte 0
1538 add bx,open_file_t_size
; ZF = 0
1540 ; ZF = 0 if we fell out of the loop
1545 ; iso_compare_names:
1546 ; Compare the names DS:SI and DS:DI and report if they are
1547 ; equal from an ISO 9660 perspective. SI is the name from
1548 ; the filesystem; CX indicates its length, and ';' terminates.
1549 ; DI is expected to end with a null.
1551 ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
1555 ; First, terminate and canonicalize input filename
1558 .
canon_loop: jcxz .canon_end
1566 cmp di,ISOFileNameEnd
-1 ; Guard against buffer overrun
1571 cmp byte [di-1],'.' ; Remove terminal dots
1574 jmp short .canon_end
1576 mov [di],byte 0 ; Null-terminate string
1584 jz .success
; End of string for both
1585 and al,al ; Is either one end of string?
1586 jz .failure
; If so, failure
1589 or ax,2020h ; Convert to lower case
1592 .
failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
1596 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1597 ; to by ES:DI; ends on encountering any whitespace.
1600 ; This verifies that a filename is < FILENAME_MAX characters,
1601 ; doesn't contain whitespace, zero-pads the output buffer,
1602 ; and removes trailing dots and redundant slashes,
1603 ; so "repe cmpsb" can do a compare, and the
1604 ; path-searching routine gets a bit of an easier job.
1610 mov cx,FILENAME_MAX
-1
1615 cmp al,' ' ; If control or space, end
1617 cmp al,ah ; Repeated slash?
1624 .
mn_skip: loop .mn_loop
1626 cmp bx,di ; At the beginning of the buffer?
1628 cmp byte [es:di-1],'.' ; Terminal dot?
1630 cmp byte [es:di-1],'/' ; Terminal slash?
1632 .
mn_kill: dec di ; If so, remove it
1636 inc cx ; At least one null byte
1637 xor ax,ax ; Zero-fill name
1644 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1645 ; filename to the conventional representation. This is needed
1646 ; for the BOOT_IMAGE= parameter for the kernel.
1648 ; DS:SI -> input mangled file name
1649 ; ES:DI -> output buffer
1651 ; On return, DI points to the first byte after the output name,
1652 ; which is set to a null byte.
1654 unmangle_name: call strcpy
1655 dec di ; Point to final null byte
1659 ; getfssec: Get multiple clusters from a file, given the file pointer.
1663 ; SI -> File pointer
1664 ; CX -> Cluster count
1666 ; SI -> File pointer (or 0 on EOF)
1668 ; ECX -> Bytes actually read
1677 cmp ecx,[si+file_left
]
1679 mov ecx,[si+file_left
]
1683 mov eax,[si+file_sector
]
1689 ; ECX[31:16] == 0 here...
1690 add [si+file_sector
],ecx
1691 sub [si+file_left
],ecx
1692 shl ecx,SECTOR_SHIFT
; Convert to bytes
1693 cmp ecx,[si+file_bytesleft
]
1695 mov ecx,[si+file_bytesleft
]
1696 .
not_all: sub [si+file_bytesleft
],ecx
1697 jnz .
ret ; CF = 0 in this case...
1700 mov [si+file_sector
],eax ; Unused
1709 ; -----------------------------------------------------------------------------
1711 ; -----------------------------------------------------------------------------
1713 %include "getc.inc" ; getc et al
1714 %include "conio.inc" ; Console I/O
1715 %include "configinit.inc" ; Initialize configuration
1716 %include "parseconfig.inc" ; High-level config file handling
1717 %include "parsecmd.inc" ; Low-level config file handling
1718 %include "bcopy32.inc" ; 32-bit bcopy
1719 %include "loadhigh.inc" ; Load a file into high memory
1720 %include "font.inc" ; VGA font stuff
1721 %include "graphics.inc" ; VGA graphics
1722 %include "highmem.inc" ; High memory sizing
1723 %include "strcpy.inc" ; strcpy()
1724 %include "rawcon.inc" ; Console I/O w/o using the console functions
1725 %include "idle.inc" ; Idle handling
1726 %include "adv.inc" ; Auxillary Data Vector
1727 %include "localboot.inc" ; Disk-based local boot
1729 ; -----------------------------------------------------------------------------
1730 ; Begin data section
1731 ; -----------------------------------------------------------------------------
1735 default_str
db 'default', 0
1736 default_len
equ ($
-default_str
)
1737 boot_dir
db '/boot' ; /boot/isolinux
1738 isolinux_dir
db '/isolinux', 0
1739 config_name
db 'isolinux.cfg', 0
1740 err_disk_image
db 'Cannot load disk image (invalid file)?', CR
, LF
, 0
1742 %ifdef DEBUG_MESSAGES
1743 dbg_rootdir_msg
db 'Root directory at LBA = ', 0
1744 dbg_isodir_msg
db 'isolinux directory at LBA = ', 0
1745 dbg_config_msg
db 'About to load config file...', CR
, LF
, 0
1746 dbg_configok_msg
db 'Configuration file opened...', CR
, LF
, 0
1750 ; Config file keyword table
1752 %include "keywords.inc"
1755 ; Extensions to search for (in *forward* order).
1758 exten_table: db '.cbt' ; COMBOOT (specific)
1759 db '.img' ; Disk image
1760 db '.bin' ; CD boot sector
1761 db '.com' ; COMBOOT (same as DOS)
1764 dd 0, 0 ; Need 8 null bytes here
1767 ; Floppy image table
1770 img_table_count
equ 3
1772 dd 1200*1024 ; 1200K floppy
1773 db 1 ; Emulation type
1774 db 80-1 ; Max cylinder
1778 dd 1440*1024 ; 1440K floppy
1779 db 2 ; Emulation type
1780 db 80-1 ; Max cylinder
1784 dd 2880*1024 ; 2880K floppy
1785 db 3 ; Emulation type
1786 db 80-1 ; Max cylinder
1791 ; Misc initialized (data) variables
1795 ; Variables that are uninitialized in SYSLINUX but initialized here
1797 ; **** ISOLINUX:: We may have to make this flexible, based on what the
1798 ; **** BIOS expects our "sector size" to be.
1801 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1802 BufSafeBytes
dw trackbufsize
; = how many bytes?
1804 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1805 %error trackbufsize must be a multiple of SECTOR_SIZE