1 |
; -*- fundamental -*- (asm-mode sucks) |
; -*- fundamental -*- (asm-mode sucks) |
|
; $Id: isolinux.asm,v 1.1 2007-09-01 22:44:04 niro Exp $ |
|
2 |
; **************************************************************************** |
; **************************************************************************** |
3 |
; |
; |
4 |
; isolinux.asm |
; isolinux.asm |
8 |
; available. It is based on the SYSLINUX boot loader for MS-DOS |
; available. It is based on the SYSLINUX boot loader for MS-DOS |
9 |
; floppies. |
; floppies. |
10 |
; |
; |
11 |
; Copyright (C) 1994-2005 H. Peter Anvin |
; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved |
12 |
|
; Copyright 2009 Intel Corporation; author: H. Peter Anvin |
13 |
; |
; |
14 |
; This program is free software; you can redistribute it and/or modify |
; 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 |
; it under the terms of the GNU General Public License as published by |
20 |
; **************************************************************************** |
; **************************************************************************** |
21 |
|
|
22 |
%define IS_ISOLINUX 1 |
%define IS_ISOLINUX 1 |
23 |
%include "macros.inc" |
%include "head.inc" |
|
%include "config.inc" |
|
|
%include "kernel.inc" |
|
|
%include "bios.inc" |
|
|
%include "tracers.inc" |
|
|
%include "layout.inc" |
|
24 |
|
|
25 |
; |
; |
26 |
; Some semi-configurable constants... change on your own risk. |
; Some semi-configurable constants... change on your own risk. |
37 |
SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement) |
SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement) |
38 |
SECTOR_SIZE equ (1 << SECTOR_SHIFT) |
SECTOR_SIZE equ (1 << SECTOR_SHIFT) |
39 |
|
|
40 |
; |
ROOT_DIR_WORD equ 0x002F |
|
; This is what we need to do when idle |
|
|
; |
|
|
%macro RESET_IDLE 0 |
|
|
; Nothing |
|
|
%endmacro |
|
|
%macro DO_IDLE 0 |
|
|
; Nothing |
|
|
%endmacro |
|
41 |
|
|
42 |
; |
; |
43 |
; The following structure is used for "virtual kernels"; i.e. LILO-style |
; The following structure is used for "virtual kernels"; i.e. LILO-style |
44 |
; option labels. The options we permit here are `kernel' and `append |
; 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 |
; Since there is no room in the bottom 64K for all of these, we |
46 |
; stick them at vk_seg:0000 and copy them down before we need them. |
; stick them in high memory and copy them down before we need them. |
47 |
; |
; |
48 |
struc vkernel |
struc vkernel |
49 |
vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** |
vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** |
50 |
vk_rname: resb FILENAME_MAX ; Real name |
vk_rname: resb FILENAME_MAX ; Real name |
51 |
vk_appendlen: resw 1 |
vk_appendlen: resw 1 |
52 |
|
vk_type: resb 1 ; Type of file |
53 |
alignb 4 |
alignb 4 |
54 |
vk_append: resb max_cmd_len+1 ; Command line |
vk_append: resb max_cmd_len+1 ; Command line |
55 |
alignb 4 |
alignb 4 |
57 |
endstruc |
endstruc |
58 |
|
|
59 |
; |
; |
|
; Segment assignments in the bottom 640K |
|
|
; 0000h - main code/data segment (and BIOS segment) |
|
|
; |
|
|
real_mode_seg equ 3000h |
|
|
vk_seg equ 2000h ; Virtual kernels |
|
|
xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem |
|
|
comboot_seg equ real_mode_seg ; COMBOOT image loading zone |
|
|
|
|
|
; |
|
60 |
; File structure. This holds the information for each currently open file. |
; File structure. This holds the information for each currently open file. |
61 |
; |
; |
62 |
struc open_file_t |
struc open_file_t |
63 |
file_sector resd 1 ; Sector pointer (0 = structure free) |
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 |
file_left resd 1 ; Number of sectors left |
66 |
|
resd 1 ; Unused |
67 |
endstruc |
endstruc |
68 |
|
|
69 |
%ifndef DEPEND |
%ifndef DEPEND |
88 |
section .earlybss |
section .earlybss |
89 |
trackbufsize equ 8192 |
trackbufsize equ 8192 |
90 |
trackbuf resb trackbufsize ; Track buffer goes here |
trackbuf resb trackbufsize ; Track buffer goes here |
91 |
getcbuf resb trackbufsize |
; ends at 2800h |
|
; ends at 4800h |
|
92 |
|
|
93 |
section .bss |
; Some of these are touched before the whole image |
94 |
|
; is loaded. DO NOT move this to .uibss. |
95 |
|
section .bss2 |
96 |
alignb 4 |
alignb 4 |
97 |
ISOFileName resb 64 ; ISO filename canonicalization buffer |
ISOFileName resb 64 ; ISO filename canonicalization buffer |
98 |
ISOFileNameEnd equ $ |
ISOFileNameEnd equ $ |
99 |
CurDir resb dir_t_size ; Current directory |
CurrentDir resb dir_t_size ; Current directory |
100 |
RootDir resb dir_t_size ; Root directory |
RootDir resb dir_t_size ; Root directory |
101 |
FirstSecSum resd 1 ; Checksum of bytes 64-2048 |
FirstSecSum resd 1 ; Checksum of bytes 64-2048 |
102 |
ImageDwords resd 1 ; isolinux.bin size, dwords |
ImageDwords resd 1 ; isolinux.bin size, dwords |
103 |
InitStack resd 1 ; Initial stack pointer (SS:SP) |
InitStack resd 1 ; Initial stack pointer (SS:SP) |
104 |
DiskSys resw 1 ; Last INT 13h call |
DiskSys resw 1 ; Last INT 13h call |
105 |
ImageSectors resw 1 ; isolinux.bin size, sectors |
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 |
110 |
|
BIOSType resw 1 |
111 |
DiskError resb 1 ; Error code for disk I/O |
DiskError resb 1 ; Error code for disk I/O |
112 |
DriveNo resb 1 ; CD-ROM BIOS drive number |
DriveNumber resb 1 ; CD-ROM BIOS drive number |
113 |
ISOFlags resb 1 ; Flags for ISO directory search |
ISOFlags resb 1 ; Flags for ISO directory search |
114 |
RetryCount resb 1 ; Used for disk access retries |
RetryCount resb 1 ; Used for disk access retries |
115 |
|
|
116 |
_spec_start equ $ |
alignb 8 |
117 |
|
bsHidden resq 1 ; Used in hybrid mode |
118 |
|
bsSecPerTrack resw 1 ; Used in hybrid mode |
119 |
|
bsHeads resw 1 ; Used in hybrid mode |
120 |
|
|
121 |
|
|
122 |
; |
; |
123 |
; El Torito spec packet |
; El Torito spec packet |
124 |
; |
; |
125 |
|
|
126 |
alignb 8 |
alignb 8 |
127 |
|
_spec_start equ $ |
128 |
spec_packet: resb 1 ; Size of packet |
spec_packet: resb 1 ; Size of packet |
129 |
sp_media: resb 1 ; Media type |
sp_media: resb 1 ; Media type |
130 |
sp_drive: resb 1 ; Drive number |
sp_drive: resb 1 ; Drive number |
134 |
sp_buffer: resw 1 ; User-provided buffer |
sp_buffer: resw 1 ; User-provided buffer |
135 |
sp_loadseg: resw 1 ; Load segment |
sp_loadseg: resw 1 ; Load segment |
136 |
sp_sectors: resw 1 ; Sector count |
sp_sectors: resw 1 ; Sector count |
137 |
sp_chs: resb 3 ; Simulated CHS geometry |
sp_chs: resb 3 ; Simulated CHS geometry |
138 |
sp_dummy: resb 1 ; Scratch, safe to overwrite |
sp_dummy: resb 1 ; Scratch, safe to overwrite |
139 |
|
|
140 |
; |
; |
193 |
alignb open_file_t_size |
alignb open_file_t_size |
194 |
Files resb MAX_OPEN*open_file_t_size |
Files resb MAX_OPEN*open_file_t_size |
195 |
|
|
|
; |
|
|
; Constants for the xfer_buf_seg |
|
|
; |
|
|
; The xfer_buf_seg is also used to store message file buffers. We |
|
|
; need two trackbuffers (text and graphics), plus a work buffer |
|
|
; for the graphics decompressor. |
|
|
; |
|
|
xbs_textbuf equ 0 ; Also hard-coded, do not change |
|
|
xbs_vgabuf equ trackbufsize |
|
|
xbs_vgatmpbuf equ 2*trackbufsize |
|
|
|
|
196 |
section .text |
section .text |
197 |
;; |
;; |
198 |
;; Primary entry point. Because BIOSes are buggy, we only load the first |
;; 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 |
;; CD-ROM sector (2K) of the file, so the number one priority is actually |
200 |
;; loading the rest. |
;; loading the rest. |
201 |
;; |
;; |
202 |
StackBuf equ $ |
StackBuf equ STACK_TOP-44 ; 44 bytes needed for |
203 |
|
; the bootsector chainloading |
204 |
|
; code! |
205 |
|
OrigESDI equ StackBuf-4 ; The high dword on the stack |
206 |
|
|
207 |
bootsec equ $ |
bootsec equ $ |
208 |
|
|
220 |
bi_length: dd 0xdeadbeef ; Length of boot file |
bi_length: dd 0xdeadbeef ; Length of boot file |
221 |
bi_csum: dd 0xdeadbeef ; Checksum of boot file |
bi_csum: dd 0xdeadbeef ; Checksum of boot file |
222 |
bi_reserved: times 10 dd 0xdeadbeef ; Reserved |
bi_reserved: times 10 dd 0xdeadbeef ; Reserved |
223 |
|
bi_end: |
224 |
|
|
225 |
_start1: mov [cs:InitStack],sp ; Save initial stack pointer |
; Custom entry point for the hybrid-mode disk. |
226 |
|
; The following values will have been pushed onto the |
227 |
|
; entry stack: |
228 |
|
; - partition offset (qword) |
229 |
|
; - ES |
230 |
|
; - DI |
231 |
|
; - DX (including drive number) |
232 |
|
; - CBIOS Heads |
233 |
|
; - CBIOS Sectors |
234 |
|
; - EBIOS flag |
235 |
|
; (top of stack) |
236 |
|
; |
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 |
241 |
|
_hybrid_signature: |
242 |
|
dd 0x7078c0fb ; An arbitrary number... |
243 |
|
|
244 |
|
_start_hybrid: |
245 |
|
pop cx ; EBIOS flag |
246 |
|
pop word [cs:bsSecPerTrack] |
247 |
|
pop word [cs:bsHeads] |
248 |
|
pop dx |
249 |
|
pop di |
250 |
|
pop es |
251 |
|
xor eax,eax |
252 |
|
xor ebx,ebx |
253 |
|
cmp sp,7C00h |
254 |
|
jae .nooffset |
255 |
|
pop eax |
256 |
|
pop ebx |
257 |
|
.nooffset: |
258 |
|
mov [cs:bsHidden],eax |
259 |
|
mov [cs:bsHidden+4],ebx |
260 |
|
|
261 |
|
mov si,bios_cbios |
262 |
|
jcxz _start_common |
263 |
|
mov si,bios_ebios |
264 |
|
jmp _start_common |
265 |
|
%endif |
266 |
|
|
267 |
|
_start1: |
268 |
|
mov si,bios_cdrom |
269 |
|
_start_common: |
270 |
|
mov [cs:InitStack],sp ; Save initial stack pointer |
271 |
mov [cs:InitStack+2],ss |
mov [cs:InitStack+2],ss |
272 |
xor ax,ax |
xor ax,ax |
273 |
mov ss,ax |
mov ss,ax |
274 |
mov sp,StackBuf ; Set up stack |
mov sp,StackBuf ; Set up stack |
275 |
|
push es ; Save initial ES:DI -> $PnP pointer |
276 |
|
push di |
277 |
mov ds,ax |
mov ds,ax |
278 |
mov es,ax |
mov es,ax |
279 |
mov fs,ax |
mov fs,ax |
280 |
mov gs,ax |
mov gs,ax |
281 |
sti |
sti |
|
|
|
282 |
cld |
cld |
283 |
|
|
284 |
|
mov [BIOSType],si |
285 |
|
mov eax,[si] |
286 |
|
mov [GetlinsecPtr],eax |
287 |
|
|
288 |
; Show signs of life |
; Show signs of life |
289 |
mov si,syslinux_banner |
mov si,syslinux_banner |
290 |
call writestr |
call writestr_early |
291 |
%ifdef DEBUG_MESSAGES |
%ifdef DEBUG_MESSAGES |
292 |
mov si,copyright_str |
mov si,copyright_str |
293 |
call writestr |
%else |
294 |
|
mov si,[BIOSName] |
295 |
%endif |
%endif |
296 |
|
call writestr_early |
297 |
|
|
298 |
; |
; |
299 |
; Before modifying any memory, get the checksum of bytes |
; Before modifying any memory, get the checksum of bytes |
300 |
; 64-2048 |
; 64-2048 |
301 |
; |
; |
302 |
initial_csum: xor edi,edi |
initial_csum: xor edi,edi |
303 |
mov si,_start1 |
mov si,bi_end |
304 |
mov cx,(SECTOR_SIZE-64) >> 2 |
mov cx,(SECTOR_SIZE-64) >> 2 |
305 |
.loop: lodsd |
.loop: lodsd |
306 |
add edi,eax |
add edi,eax |
307 |
loop .loop |
loop .loop |
308 |
mov [FirstSecSum],edi |
mov [FirstSecSum],edi |
309 |
|
|
310 |
mov [DriveNo],dl |
mov [DriveNumber],dl |
311 |
%ifdef DEBUG_MESSAGES |
%ifdef DEBUG_MESSAGES |
312 |
mov si,startup_msg |
mov si,startup_msg |
313 |
call writemsg |
call writemsg |
332 |
; Other nonzero fields |
; Other nonzero fields |
333 |
inc word [dsp_sectors] |
inc word [dsp_sectors] |
334 |
|
|
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... |
338 |
|
|
339 |
; Now figure out what we're actually doing |
; Now figure out what we're actually doing |
340 |
; Note: use passed-in DL value rather than 7Fh because |
; Note: use passed-in DL value rather than 7Fh because |
341 |
; at least some BIOSes will get the wrong value otherwise |
; at least some BIOSes will get the wrong value otherwise |
342 |
mov ax,4B01h ; Get disk emulation status |
mov ax,4B01h ; Get disk emulation status |
343 |
mov dl,[DriveNo] |
mov dl,[DriveNumber] |
344 |
mov si,spec_packet |
mov si,spec_packet |
345 |
int 13h |
call int13 |
346 |
jc award_hack ; changed for BrokenAwardHack |
jc award_hack ; changed for BrokenAwardHack |
347 |
mov dl,[DriveNo] |
mov dl,[DriveNumber] |
348 |
cmp [sp_drive],dl ; Should contain the drive number |
cmp [sp_drive],dl ; Should contain the drive number |
349 |
jne spec_query_failed |
jne spec_query_failed |
350 |
|
|
372 |
mov si,noinfotable_msg |
mov si,noinfotable_msg |
373 |
call writemsg |
call writemsg |
374 |
%endif |
%endif |
375 |
|
|
376 |
; No such luck. See if the the spec packet contained one. |
; No such luck. See if the spec packet contained one. |
377 |
mov eax,[sp_lba] |
mov eax,[sp_lba] |
378 |
and eax,eax |
and eax,eax |
379 |
jz set_file ; Good enough |
jz set_file ; Good enough |
382 |
mov si,noinfoinspec_msg |
mov si,noinfoinspec_msg |
383 |
call writemsg |
call writemsg |
384 |
%endif |
%endif |
385 |
|
|
386 |
; No such luck. Get the Boot Record Volume, assuming single |
; No such luck. Get the Boot Record Volume, assuming single |
387 |
; session disk, and that we're the first entry in the chain |
; session disk, and that we're the first entry in the chain. |
388 |
mov eax,17 ; Assumed address of BRV |
mov eax,17 ; Assumed address of BRV |
389 |
mov bx,trackbuf |
mov bx,trackbuf |
390 |
call getonesec |
call getonesec |
396 |
mov eax,[trackbuf+28h] ; First boot entry |
mov eax,[trackbuf+28h] ; First boot entry |
397 |
; And hope and pray this is us... |
; And hope and pray this is us... |
398 |
|
|
399 |
; Some BIOSes apparently have limitations on the size |
; Some BIOSes apparently have limitations on the size |
400 |
; that may be loaded (despite the El Torito spec being very |
; that may be loaded (despite the El Torito spec being very |
401 |
; clear on the fact that it must all be loaded.) Therefore, |
; clear on the fact that it must all be loaded.) Therefore, |
402 |
; we load it ourselves, and *bleep* the BIOS. |
; we load it ourselves, and *bleep* the BIOS. |
407 |
found_file: |
found_file: |
408 |
; Set up boot file sizes |
; Set up boot file sizes |
409 |
mov eax,[bi_length] |
mov eax,[bi_length] |
410 |
sub eax,SECTOR_SIZE-3 |
sub eax,SECTOR_SIZE-3 ; ... minus sector loaded |
411 |
shr eax,2 ; bytes->dwords |
shr eax,2 ; bytes->dwords |
412 |
mov [ImageDwords],eax ; boot file dwords |
mov [ImageDwords],eax ; boot file dwords |
413 |
add eax,(2047 >> 2) |
add eax,(2047 >> 2) |
484 |
;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de |
;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de |
485 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
486 |
;; |
;; |
487 |
;; There is a problem with certain versions of the AWARD BIOS ... |
;; There is a problem with certain versions of the AWARD BIOS ... |
488 |
;; the boot sector will be loaded and executed correctly, but, because the |
;; 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 |
;; 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 |
;; load the spec packet will fail. We scan for the equivalent of |
501 |
;; for anybody to change it now or in the future. There are no opcodes |
;; 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 |
;; 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 |
;; code above in the BIOS code we can be pretty sure to run on a machine |
504 |
;; with an broken AWARD BIOS ... |
;; with an broken AWARD BIOS ... |
505 |
;; |
;; |
506 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
507 |
;; |
;; |
520 |
award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;; |
award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;; |
521 |
;; |
;; |
522 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
523 |
award_hack: mov si,spec_err_msg ; Moved to this place from |
award_hack: mov si,spec_err_msg ; Moved to this place from |
524 |
call writemsg ; spec_query_faild |
call writemsg ; spec_query_faild |
525 |
; |
; |
526 |
%ifdef DEBUG_MESSAGES ; |
%ifdef DEBUG_MESSAGES ; |
527 |
; |
; |
536 |
%ifdef DEBUG_MESSAGES ; |
%ifdef DEBUG_MESSAGES ; |
537 |
; |
; |
538 |
call writehex8 ; |
call writehex8 ; |
539 |
mov si,award_not_crlf ; |
mov si,award_not_crlf ; |
540 |
call writestr ; |
call writestr_early ; |
541 |
%endif ; |
%endif ; |
542 |
push es ; save ES |
push es ; save ES |
543 |
mov ax,0f000h ; ES = BIOS Seg |
mov ax,0f000h ; ES = BIOS Seg |
544 |
mov es,ax ; |
mov es,ax ; |
545 |
cld ; |
cld ; |
546 |
xor di,di ; start at ES:DI = f000:0 |
xor di,di ; start at ES:DI = f000:0 |
547 |
award_loop: push di ; save DI |
award_loop: push di ; save DI |
548 |
mov si,award_string ; scan for award_string |
mov si,award_string ; scan for award_string |
549 |
mov cx,7 ; length of award_string = 7dw |
mov cx,7 ; length of award_string = 7dw |
550 |
repz cmpsw ; compare |
repz cmpsw ; compare |
551 |
pop di ; restore DI |
pop di ; restore DI |
552 |
jcxz award_found ; jmp if found |
jcxz award_found ; jmp if found |
553 |
inc di ; not found, inc di |
inc di ; not found, inc di |
554 |
jno award_loop ; |
jno award_loop ; |
555 |
; |
; |
556 |
award_failed: pop es ; No, not this way :-(( |
award_failed: pop es ; No, not this way :-(( |
557 |
award_fail2: ; |
award_fail2: ; |
577 |
; |
; |
578 |
%ifdef DEBUG_MESSAGES ; |
%ifdef DEBUG_MESSAGES ; |
579 |
; |
; |
580 |
push eax ; display message and |
push eax ; display message and |
581 |
mov si,award_not_new ; new vector address |
mov si,award_not_new ; new vector address |
582 |
call writemsg ; |
call writemsg ; |
583 |
pop eax ; |
pop eax ; |
584 |
call writehex8 ; |
call writehex8 ; |
585 |
mov si,award_not_crlf ; |
mov si,award_not_crlf ; |
586 |
call writestr ; |
call writestr_early ; |
587 |
%endif ; |
%endif ; |
588 |
mov ax,4B01h ; try to read the spec packet |
mov ax,4B01h ; try to read the spec packet |
589 |
mov dl,[DriveNo] ; now ... it should not fail |
mov dl,[DriveNumber] ; now ... it should not fail |
590 |
mov si,spec_packet ; any longer |
mov si,spec_packet ; any longer |
591 |
int 13h ; |
int 13h ; |
592 |
jc award_fail2 ; |
jc award_fail2 ; |
593 |
; |
; |
594 |
%ifdef DEBUG_MESSAGES ; |
%ifdef DEBUG_MESSAGES ; |
614 |
.test_loop: pusha |
.test_loop: pusha |
615 |
mov ax,4B01h |
mov ax,4B01h |
616 |
mov si,spec_packet |
mov si,spec_packet |
617 |
mov byte [si],13 ; Size of buffer |
mov byte [si],13h ; Size of buffer |
618 |
int 13h |
call int13 |
619 |
popa |
popa |
620 |
jc .still_broken |
jc .still_broken |
621 |
|
|
631 |
; Okay, good enough... |
; Okay, good enough... |
632 |
mov si,alright_msg |
mov si,alright_msg |
633 |
call writemsg |
call writemsg |
634 |
mov [DriveNo],dl |
.found_drive0: mov [DriveNumber],dl |
635 |
.found_drive: jmp found_drive |
.found_drive: jmp found_drive |
636 |
|
|
637 |
; Award BIOS 4.51 apparently passes garbage in sp_drive, |
; Award BIOS 4.51 apparently passes garbage in sp_drive, |
638 |
; but if this was the drive number originally passed in |
; but if this was the drive number originally passed in |
639 |
; DL then consider it "good enough" |
; DL then consider it "good enough" |
640 |
.maybe_broken: |
.maybe_broken: |
641 |
cmp byte [DriveNo],dl |
mov al,[DriveNumber] |
642 |
|
cmp al,dl |
643 |
je .found_drive |
je .found_drive |
644 |
|
|
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. |
648 |
|
or al,80h |
649 |
|
cmp al,dl |
650 |
|
je .found_drive0 |
651 |
|
|
652 |
.still_broken: dec dx |
.still_broken: dec dx |
653 |
cmp dl, 80h |
cmp dl, 80h |
654 |
jnb .test_loop |
jnb .test_loop |
658 |
; 4B01h, so we can't query a spec packet no matter |
; 4B01h, so we can't query a spec packet no matter |
659 |
; what. If we got a drive number in DL, then try to |
; what. If we got a drive number in DL, then try to |
660 |
; use it, and if it works, then well... |
; use it, and if it works, then well... |
661 |
mov dl,[DriveNo] |
mov dl,[DriveNumber] |
662 |
cmp dl,81h ; Should be 81-FF at least |
cmp dl,81h ; Should be 81-FF at least |
663 |
jb fatal_error ; If not, it's hopeless |
jb fatal_error ; If not, it's hopeless |
664 |
|
|
684 |
writemsg: push ax |
writemsg: push ax |
685 |
push si |
push si |
686 |
mov si,isolinux_str |
mov si,isolinux_str |
687 |
call writestr |
call writestr_early |
688 |
pop si |
pop si |
689 |
call writestr |
call writestr_early |
690 |
pop ax |
pop ax |
691 |
ret |
ret |
692 |
|
|
693 |
; |
; |
710 |
ret |
ret |
711 |
|
|
712 |
; |
; |
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. |
716 |
|
; |
717 |
|
int13: |
718 |
|
pushf |
719 |
|
push bp |
720 |
|
push ds |
721 |
|
push es |
722 |
|
push fs |
723 |
|
push gs |
724 |
|
int 13h |
725 |
|
mov bp,sp |
726 |
|
setc [bp+10] ; Propagate CF to the caller |
727 |
|
pop gs |
728 |
|
pop fs |
729 |
|
pop es |
730 |
|
pop ds |
731 |
|
pop bp |
732 |
|
popf |
733 |
|
ret |
734 |
|
|
735 |
|
; |
736 |
; Get one sector. Convenience entry point. |
; Get one sector. Convenience entry point. |
737 |
; |
; |
738 |
getonesec: |
getonesec: |
742 |
; |
; |
743 |
; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. |
; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. |
744 |
; |
; |
|
; Note that we can't always do this as a single request, because at least |
|
|
; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick |
|
|
; to 32 sectors (64K) per request. |
|
|
; |
|
745 |
; Input: |
; Input: |
746 |
; EAX - Linear sector number |
; EAX - Linear sector number |
747 |
; ES:BX - Target buffer |
; ES:BX - Target buffer |
748 |
; BP - Sector count |
; BP - Sector count |
749 |
; |
; |
750 |
getlinsec: |
getlinsec: jmp word [cs:GetlinsecPtr] |
751 |
|
|
752 |
|
%ifndef DEBUG_MESSAGES |
753 |
|
|
754 |
|
; |
755 |
|
; First, the variants that we use when actually loading off a disk |
756 |
|
; (hybrid mode.) These are adapted versions of the equivalent routines |
757 |
|
; in ldlinux.asm. |
758 |
|
; |
759 |
|
|
760 |
|
; |
761 |
|
; getlinsec_ebios: |
762 |
|
; |
763 |
|
; getlinsec implementation for floppy/HDD EBIOS (EDD) |
764 |
|
; |
765 |
|
getlinsec_ebios: |
766 |
|
xor edx,edx |
767 |
|
shld edx,eax,2 |
768 |
|
shl eax,2 ; Convert to HDD sectors |
769 |
|
add eax,[bsHidden] |
770 |
|
adc edx,[bsHidden+4] |
771 |
|
shl bp,2 |
772 |
|
|
773 |
|
.loop: |
774 |
|
push bp ; Sectors left |
775 |
|
.retry2: |
776 |
|
call maxtrans ; Enforce maximum transfer size |
777 |
|
movzx edi,bp ; Sectors we are about to read |
778 |
|
mov cx,retry_count |
779 |
|
.retry: |
780 |
|
|
781 |
|
; Form DAPA on stack |
782 |
|
push edx |
783 |
|
push eax |
784 |
|
push es |
785 |
|
push bx |
786 |
|
push di |
787 |
|
push word 16 |
788 |
|
mov si,sp |
789 |
|
pushad |
790 |
|
mov dl,[DriveNumber] |
791 |
|
push ds |
792 |
|
push ss |
793 |
|
pop ds ; DS <- SS |
794 |
|
mov ah,42h ; Extended Read |
795 |
|
call int13 |
796 |
|
pop ds |
797 |
|
popad |
798 |
|
lea sp,[si+16] ; Remove DAPA |
799 |
|
jc .error |
800 |
|
pop bp |
801 |
|
add eax,edi ; Advance sector pointer |
802 |
|
adc edx,0 |
803 |
|
sub bp,di ; Sectors left |
804 |
|
shl di,9 ; 512-byte sectors |
805 |
|
add bx,di ; Advance buffer pointer |
806 |
|
and bp,bp |
807 |
|
jnz .loop |
808 |
|
|
809 |
|
ret |
810 |
|
|
811 |
|
.error: |
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. |
816 |
|
|
817 |
|
pushad ; Try resetting the device |
818 |
|
xor ax,ax |
819 |
|
mov dl,[DriveNumber] |
820 |
|
call int13 |
821 |
|
popad |
822 |
|
loop .retry ; CX-- and jump if not zero |
823 |
|
|
824 |
|
;shr word [MaxTransfer],1 ; Reduce the transfer size |
825 |
|
;jnz .retry2 |
826 |
|
|
827 |
|
; Total failure. Try falling back to CBIOS. |
828 |
|
mov word [GetlinsecPtr], getlinsec_cbios |
829 |
|
;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer |
830 |
|
|
831 |
|
pop bp |
832 |
|
jmp getlinsec_cbios.loop |
833 |
|
|
834 |
|
; |
835 |
|
; getlinsec_cbios: |
836 |
|
; |
837 |
|
; getlinsec implementation for legacy CBIOS |
838 |
|
; |
839 |
|
getlinsec_cbios: |
840 |
|
xor edx,edx |
841 |
|
shl eax,2 ; Convert to HDD sectors |
842 |
|
add eax,[bsHidden] |
843 |
|
shl bp,2 |
844 |
|
|
845 |
|
.loop: |
846 |
|
push edx |
847 |
|
push eax |
848 |
|
push bp |
849 |
|
push bx |
850 |
|
|
851 |
|
movzx esi,word [bsSecPerTrack] |
852 |
|
movzx edi,word [bsHeads] |
853 |
|
; |
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. |
856 |
|
; |
857 |
|
div esi |
858 |
|
xor cx,cx |
859 |
|
xchg cx,dx ; CX <- sector index (0-based) |
860 |
|
; EDX <- 0 |
861 |
|
; eax = track # |
862 |
|
div edi ; Convert track to head/cyl |
863 |
|
|
864 |
|
; We should test this, but it doesn't fit... |
865 |
|
; cmp eax,1023 |
866 |
|
; ja .error |
867 |
|
|
868 |
|
; |
869 |
|
; Now we have AX = cyl, DX = head, CX = sector (0-based), |
870 |
|
; BP = sectors to transfer, SI = bsSecPerTrack, |
871 |
|
; ES:BX = data target |
872 |
|
; |
873 |
|
|
874 |
|
call maxtrans ; Enforce maximum transfer size |
875 |
|
|
876 |
|
; Must not cross track boundaries, so BP <= SI-CX |
877 |
|
sub si,cx |
878 |
|
cmp bp,si |
879 |
|
jna .bp_ok |
880 |
|
mov bp,si |
881 |
|
.bp_ok: |
882 |
|
|
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 |
887 |
|
or cl,ah |
888 |
|
mov ch,al |
889 |
|
mov dh,dl |
890 |
|
mov dl,[DriveNumber] |
891 |
|
xchg ax,bp ; Sector to transfer count |
892 |
|
mov ah,02h ; Read sectors |
893 |
|
mov bp,retry_count |
894 |
|
.retry: |
895 |
|
pushad |
896 |
|
call int13 |
897 |
|
popad |
898 |
|
jc .error |
899 |
|
.resume: |
900 |
|
movzx ecx,al ; ECX <- sectors transferred |
901 |
|
shl ax,9 ; Convert sectors in AL to bytes in AX |
902 |
|
pop bx |
903 |
|
add bx,ax |
904 |
|
pop bp |
905 |
|
pop eax |
906 |
|
pop edx |
907 |
|
add eax,ecx |
908 |
|
sub bp,cx |
909 |
|
jnz .loop |
910 |
|
ret |
911 |
|
|
912 |
|
.error: |
913 |
|
dec bp |
914 |
|
jnz .retry |
915 |
|
|
916 |
|
xchg ax,bp ; Sectors transferred <- 0 |
917 |
|
shr word [MaxTransfer],1 |
918 |
|
jnz .resume |
919 |
|
jmp disk_error |
920 |
|
|
921 |
|
; |
922 |
|
; Truncate BP to MaxTransfer |
923 |
|
; |
924 |
|
maxtrans: |
925 |
|
cmp bp,[MaxTransfer] |
926 |
|
jna .ok |
927 |
|
mov bp,[MaxTransfer] |
928 |
|
.ok: ret |
929 |
|
|
930 |
|
%endif |
931 |
|
|
932 |
|
; |
933 |
|
; This is the variant we use for real CD-ROMs: |
934 |
|
; LBA, 2K sectors, some special error handling. |
935 |
|
; |
936 |
|
getlinsec_cdrom: |
937 |
mov si,dapa ; Load up the DAPA |
mov si,dapa ; Load up the DAPA |
938 |
mov [si+4],bx |
mov [si+4],bx |
939 |
mov bx,es |
mov [si+6],es |
|
mov [si+6],bx |
|
940 |
mov [si+8],eax |
mov [si+8],eax |
941 |
.loop: |
.loop: |
942 |
push bp ; Sectors left |
push bp ; Sectors left |
943 |
cmp bp,[MaxTransfer] |
cmp bp,[MaxTransferCD] |
944 |
jbe .bp_ok |
jbe .bp_ok |
945 |
mov bp,[MaxTransfer] |
mov bp,[MaxTransferCD] |
946 |
.bp_ok: |
.bp_ok: |
947 |
mov [si+2],bp |
mov [si+2],bp |
948 |
push si |
push si |
949 |
mov dl,[DriveNo] |
mov dl,[DriveNumber] |
950 |
mov ah,42h ; Extended Read |
mov ah,42h ; Extended Read |
951 |
call xint13 |
call xint13 |
952 |
pop si |
pop si |
964 |
; INT 13h with retry |
; INT 13h with retry |
965 |
xint13: mov byte [RetryCount],retry_count |
xint13: mov byte [RetryCount],retry_count |
966 |
.try: pushad |
.try: pushad |
967 |
int 13h |
call int13 |
968 |
jc .error |
jc .error |
969 |
add sp,byte 8*4 ; Clean up stack |
add sp,byte 8*4 ; Clean up stack |
970 |
ret |
ret |
987 |
shr ah,1 ; Otherwise, try to reduce |
shr ah,1 ; Otherwise, try to reduce |
988 |
adc ah,0 ; the max transfer size, but not to 0 |
adc ah,0 ; the max transfer size, but not to 0 |
989 |
.setsize: |
.setsize: |
990 |
mov [MaxTransfer],ah |
mov [MaxTransferCD],ah |
991 |
mov [dapa+2],ah |
mov [dapa+2],ah |
992 |
.again: |
.again: |
993 |
pop ax |
pop ax |
998 |
mov al,[DiskError] |
mov al,[DiskError] |
999 |
call writehex2 |
call writehex2 |
1000 |
mov si,oncall_str |
mov si,oncall_str |
1001 |
call writestr |
call writestr_early |
1002 |
mov ax,[DiskSys] |
mov ax,[DiskSys] |
1003 |
call writehex4 |
call writehex4 |
1004 |
mov si,ondrive_str |
mov si,ondrive_str |
1005 |
call writestr |
call writestr_early |
1006 |
mov al,dl |
mov al,dl |
1007 |
call writehex2 |
call writehex2 |
1008 |
call crlf |
call crlf |
1012 |
; kaboom: write a message and bail out. Wait for a user keypress, |
; kaboom: write a message and bail out. Wait for a user keypress, |
1013 |
; then do a hard reboot. |
; then do a hard reboot. |
1014 |
; |
; |
1015 |
|
disk_error: |
1016 |
kaboom: |
kaboom: |
1017 |
lss sp,[cs:StackPtr] |
RESET_STACK_AND_SEGS AX |
|
mov ax,cs |
|
|
mov ds,ax |
|
|
mov es,ax |
|
|
mov fs,ax |
|
|
mov gs,ax |
|
|
sti |
|
1018 |
mov si,err_bootfailed |
mov si,err_bootfailed |
1019 |
call cwritestr |
call writestr |
1020 |
call getchar |
call getchar |
1021 |
cli |
cli |
1022 |
mov word [BIOS_magic],0 ; Cold reboot |
mov word [BIOS_magic],0 ; Cold reboot |
1027 |
; ----------------------------------------------------------------------------- |
; ----------------------------------------------------------------------------- |
1028 |
|
|
1029 |
%include "writestr.inc" ; String output |
%include "writestr.inc" ; String output |
1030 |
writestr equ cwritestr |
writestr_early equ writestr |
1031 |
%include "writehex.inc" ; Hexadecimal output |
%include "writehex.inc" ; Hexadecimal output |
1032 |
|
|
1033 |
; ----------------------------------------------------------------------------- |
; ----------------------------------------------------------------------------- |
1034 |
; Data that needs to be in the first sector |
; Data that needs to be in the first sector |
1035 |
; ----------------------------------------------------------------------------- |
; ----------------------------------------------------------------------------- |
1036 |
|
|
1037 |
syslinux_banner db CR, LF, 'ISOLINUX ', version_str, ' ', date, ' ', 0 |
syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0 |
1038 |
copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' |
copyright_str db ' Copyright (C) 1994-' |
1039 |
db CR, LF, 0 |
asciidec YEAR |
1040 |
|
db ' H. Peter Anvin et al', CR, LF, 0 |
1041 |
isolinux_str db 'isolinux: ', 0 |
isolinux_str db 'isolinux: ', 0 |
1042 |
%ifdef DEBUG_MESSAGES |
%ifdef DEBUG_MESSAGES |
1043 |
startup_msg: db 'Starting up, DL = ', 0 |
startup_msg: db 'Starting up, DL = ', 0 |
1044 |
spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 |
spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 |
1045 |
secsize_msg: db 'Sector size appears to be ', 0 |
secsize_msg: db 'Sector size ', 0 |
1046 |
offset_msg: db 'Loading main image from LBA = ', 0 |
offset_msg: db 'Main image LBA = ', 0 |
1047 |
size_msg: db 'Sectors to load = ', 0 |
size_msg: db 'Sectors to load = ', 0 |
1048 |
loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0 |
loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0 |
1049 |
verify_msg: db 'Image checksum verified.', CR, LF, 0 |
verify_msg: db 'Image checksum verified.', CR, LF, 0 |
1053 |
noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0 |
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 |
spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0 |
1055 |
maybe_msg: db 'Found something at drive = ', 0 |
maybe_msg: db 'Found something at drive = ', 0 |
1056 |
alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0 |
alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0 |
1057 |
nospec_msg db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0 |
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 |
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 |
trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0 |
1060 |
diskerr_msg: db 'Disk error ', 0 |
diskerr_msg: db 'Disk error ', 0 |
1067 |
crlf_msg db CR, LF |
crlf_msg db CR, LF |
1068 |
null_msg db 0 |
null_msg db 0 |
1069 |
|
|
1070 |
alignb 4, db 0 |
bios_cdrom_str db 'ETCD', 0 |
1071 |
StackPtr dw StackBuf, 0 ; SS:SP for stack reset |
%ifndef DEBUG_MESSAGES |
1072 |
MaxTransfer dw 32 ; Max sectors per transfer |
bios_cbios_str db 'CHDD', 0 |
1073 |
|
bios_ebios_str db 'EHDD' ,0 |
1074 |
|
%endif |
1075 |
|
|
1076 |
|
alignz 4 |
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 |
1081 |
|
%endif |
1082 |
|
|
1083 |
|
; Maximum transfer size |
1084 |
|
MaxTransfer dw 127 ; Hard disk modes |
1085 |
|
MaxTransferCD dw 32 ; CD mode |
1086 |
|
|
1087 |
rl_checkpt equ $ ; Must be <= 800h |
rl_checkpt equ $ ; Must be <= 800h |
1088 |
|
|
1089 |
rl_checkpt_off equ ($-$$) |
; This pads to the end of sector 0 and errors out on |
1090 |
;%ifndef DEPEND |
; overflow. |
1091 |
;%if rl_checkpt_off > 0x800 |
times 2048-($-$$) db 0 |
|
;%error "Sector 0 overflow" |
|
|
;%endif |
|
|
;%endif |
|
1092 |
|
|
1093 |
; ---------------------------------------------------------------------------- |
; ---------------------------------------------------------------------------- |
1094 |
; End of code and data that have to be in the first sector |
; End of code and data that have to be in the first sector |
1095 |
; ---------------------------------------------------------------------------- |
; ---------------------------------------------------------------------------- |
1096 |
|
|
1097 |
all_read: |
all_read: |
|
; |
|
|
; Initialize screen (if we're using one) |
|
|
; |
|
|
; Now set up screen parameters |
|
|
call adjust_screen |
|
|
|
|
|
; Wipe the F-key area |
|
|
mov al,NULLFILE |
|
|
mov di,FKeyName |
|
|
mov cx,10*(1 << FILENAME_MAX_LG2) |
|
|
rep stosb |
|
|
|
|
|
; Patch the writechr routine to point to the full code |
|
|
mov word [writechr+1], writechr_full-(writechr+3) |
|
|
|
|
|
; Tell the user we got this far... |
|
|
%ifndef DEBUG_MESSAGES ; Gets messy with debugging on |
|
|
mov si,copyright_str |
|
|
call writestr |
|
|
%endif |
|
1098 |
|
|
1099 |
; Test tracers |
; Test tracers |
1100 |
TRACER 'T' |
TRACER 'T' |
1106 |
%include "init.inc" |
%include "init.inc" |
1107 |
%include "cpuinit.inc" |
%include "cpuinit.inc" |
1108 |
|
|
1109 |
|
; Patch the writechr routine to point to the full code |
1110 |
|
mov word [writechr+1], writechr_full-(writechr+3) |
1111 |
|
|
1112 |
|
; Tell the user we got this far... |
1113 |
|
%ifndef DEBUG_MESSAGES ; Gets messy with debugging on |
1114 |
|
mov si,copyright_str |
1115 |
|
call writestr_early |
1116 |
|
%endif |
1117 |
|
|
1118 |
; |
; |
1119 |
; Now we're all set to start with our *real* business. First load the |
; Now we're all set to start with our *real* business. First load the |
1120 |
; configuration file (if any) and parse it. |
; configuration file (if any) and parse it. |
1134 |
; mkisofs gave us a pointer to the primary volume descriptor |
; 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 |
; (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. |
; we should be able to find the rest of what we need to know. |
1137 |
; |
; |
1138 |
get_fs_structures: |
get_fs_structures: |
1139 |
mov eax,[bi_pvd] |
mov eax,[bi_pvd] |
1140 |
mov bx,trackbuf |
mov bx,trackbuf |
1142 |
|
|
1143 |
mov eax,[trackbuf+156+2] |
mov eax,[trackbuf+156+2] |
1144 |
mov [RootDir+dir_lba],eax |
mov [RootDir+dir_lba],eax |
1145 |
mov [CurDir+dir_lba],eax |
mov [CurrentDir+dir_lba],eax |
1146 |
%ifdef DEBUG_MESSAGES |
%ifdef DEBUG_MESSAGES |
1147 |
mov si,dbg_rootdir_msg |
mov si,dbg_rootdir_msg |
1148 |
call writemsg |
call writemsg |
1150 |
call crlf |
call crlf |
1151 |
%endif |
%endif |
1152 |
mov eax,[trackbuf+156+10] |
mov eax,[trackbuf+156+10] |
1153 |
mov [RootDir+dir_len],eax |
mov [RootDir+dir_len],eax |
1154 |
mov [CurDir+dir_len],eax |
mov [CurrentDir+dir_len],eax |
1155 |
add eax,SECTOR_SIZE-1 |
add eax,SECTOR_SIZE-1 |
1156 |
shr eax,SECTOR_SHIFT |
shr eax,SECTOR_SHIFT |
1157 |
mov [RootDir+dir_clust],eax |
mov [RootDir+dir_clust],eax |
1158 |
mov [CurDir+dir_clust],eax |
mov [CurrentDir+dir_clust],eax |
1159 |
|
|
1160 |
; Look for an isolinux directory, and if found, |
; Look for an isolinux directory, and if found, |
1161 |
; make it the current directory instead of the root |
; make it the current directory instead of the root |
1162 |
; directory. |
; directory. |
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 |
mov di,boot_dir ; Search for /boot/isolinux |
1166 |
mov al,02h |
mov al,02h |
1167 |
|
push di |
1168 |
call searchdir_iso |
call searchdir_iso |
1169 |
|
pop di |
1170 |
jnz .found_dir |
jnz .found_dir |
1171 |
mov di,isolinux_dir |
mov di,isolinux_dir |
1172 |
mov al,02h ; Search for /isolinux |
mov al,02h ; Search for /isolinux |
1173 |
|
push di |
1174 |
call searchdir_iso |
call searchdir_iso |
1175 |
|
pop di |
1176 |
jz .no_isolinux_dir |
jz .no_isolinux_dir |
1177 |
.found_dir: |
.found_dir: |
1178 |
mov [CurDir+dir_len],eax |
; Copy current directory name to CurrentDirName |
1179 |
|
push si |
1180 |
|
push di |
1181 |
|
mov si,di |
1182 |
|
mov di,CurrentDirName |
1183 |
|
call strcpy |
1184 |
|
mov byte [di],0 ;done in case it's not word aligned |
1185 |
|
dec di |
1186 |
|
mov byte [di],'/' |
1187 |
|
pop di |
1188 |
|
pop si |
1189 |
|
|
1190 |
|
mov [CurrentDir+dir_len],eax |
1191 |
mov eax,[si+file_left] |
mov eax,[si+file_left] |
1192 |
mov [CurDir+dir_clust],eax |
mov [CurrentDir+dir_clust],eax |
1193 |
xor eax,eax ; Free this file pointer entry |
xor eax,eax ; Free this file pointer entry |
1194 |
xchg eax,[si+file_sector] |
xchg eax,[si+file_sector] |
1195 |
mov [CurDir+dir_lba],eax |
mov [CurrentDir+dir_lba],eax |
1196 |
%ifdef DEBUG_MESSAGES |
%ifdef DEBUG_MESSAGES |
1197 |
push si |
push si |
1198 |
mov si,dbg_isodir_msg |
mov si,dbg_isodir_msg |
1212 |
call writemsg |
call writemsg |
1213 |
%endif |
%endif |
1214 |
|
|
1215 |
mov di,isolinux_cfg |
mov si,config_name |
1216 |
|
mov di,ConfigName |
1217 |
|
call strcpy |
1218 |
|
|
1219 |
|
mov di,ConfigName |
1220 |
call open |
call open |
1221 |
jz no_config_file ; Not found or empty |
jz no_config_file ; Not found or empty |
1222 |
|
|
1232 |
%include "ui.inc" |
%include "ui.inc" |
1233 |
|
|
1234 |
; |
; |
1235 |
; Linux kernel loading code is common. |
; 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. |
|
%include "runkernel.inc" |
|
|
|
|
|
; |
|
|
; COMBOOT-loading code |
|
|
; |
|
|
%include "comboot.inc" |
|
|
%include "com32.inc" |
|
|
%include "cmdline.inc" |
|
|
|
|
|
; |
|
|
; Boot sector loading code |
|
|
; |
|
|
%include "bootsect.inc" |
|
|
|
|
|
; |
|
|
; Enable disk emulation. The kind of disk we emulate is dependent on the size of |
|
|
; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk. |
|
1237 |
; |
; |
1238 |
is_disk_image: |
is_disk_image: |
1239 |
TRACER CR |
TRACER CR |
1241 |
TRACER 'D' |
TRACER 'D' |
1242 |
TRACER ':' |
TRACER ':' |
1243 |
|
|
1244 |
shl edx,16 |
mov edx,eax ; File size |
|
mov dx,ax ; Set EDX <- file size |
|
1245 |
mov di,img_table |
mov di,img_table |
1246 |
mov cx,img_table_count |
mov cx,img_table_count |
1247 |
mov eax,[si+file_sector] ; Starting LBA of file |
mov eax,[si+file_sector] ; Starting LBA of file |
1265 |
mov bx,trackbuf |
mov bx,trackbuf |
1266 |
mov cx,1 ; Load 1 sector |
mov cx,1 ; Load 1 sector |
1267 |
call getfssec |
call getfssec |
1268 |
|
|
1269 |
cmp word [trackbuf+510],0aa55h ; Boot signature |
cmp word [trackbuf+510],0aa55h ; Boot signature |
1270 |
jne .bad_image ; Image not bootable |
jne .bad_image ; Image not bootable |
1271 |
|
|
1284 |
.part_loop: |
.part_loop: |
1285 |
add di,byte 16 |
add di,byte 16 |
1286 |
loop .part_scan |
loop .part_scan |
1287 |
|
|
1288 |
push eax ; H/S |
push eax ; H/S |
1289 |
push edx ; File size |
push edx ; File size |
1290 |
mov bl,ah |
mov bl,ah |
1333 |
|
|
1334 |
mov ax,4C00h ; Enable emulation and boot |
mov ax,4C00h ; Enable emulation and boot |
1335 |
mov si,dspec_packet |
mov si,dspec_packet |
1336 |
mov dl,[DriveNo] |
mov dl,[DriveNumber] |
1337 |
lss sp,[InitStack] |
lss sp,[InitStack] |
1338 |
TRACER 'X' |
TRACER 'X' |
1339 |
|
|
1340 |
int 13h |
call int13 |
1341 |
|
|
1342 |
; If this returns, we have problems |
; If this returns, we have problems |
1343 |
.bad_image: |
.bad_image: |
1344 |
mov si,err_disk_image |
mov si,err_disk_image |
1345 |
call cwritestr |
call writestr |
1346 |
jmp enter_command |
jmp enter_command |
1347 |
|
|
1348 |
; |
; |
1362 |
.done_sector: ret |
.done_sector: ret |
1363 |
|
|
1364 |
; |
; |
1365 |
; Boot a specified local disk. AX specifies the BIOS disk number; or |
; close_file: |
1366 |
; 0xFFFF in case we should execute INT 18h ("next device.") |
; Deallocates a file structure (pointer in SI) |
1367 |
|
; Assumes CS == DS. |
1368 |
; |
; |
1369 |
local_boot: |
close_file: |
1370 |
call vgaclearmode |
and si,si |
1371 |
lss sp,[cs:Stack] ; Restore stack pointer |
jz .closed |
1372 |
xor dx,dx |
mov dword [si],0 ; First dword == file_left |
1373 |
mov ds,dx |
xor si,si |
1374 |
mov es,dx |
.closed: ret |
|
mov fs,dx |
|
|
mov gs,dx |
|
|
mov si,localboot_msg |
|
|
call writestr |
|
|
cmp ax,-1 |
|
|
je .int18 |
|
|
|
|
|
; Load boot sector from the specified BIOS device and jump to it. |
|
|
mov dl,al |
|
|
xor dh,dh |
|
|
push dx |
|
|
xor ax,ax ; Reset drive |
|
|
call xint13 |
|
|
mov ax,0201h ; Read one sector |
|
|
mov cx,0001h ; C/H/S = 0/0/1 (first sector) |
|
|
mov bx,trackbuf |
|
|
call xint13 |
|
|
pop dx |
|
|
cli ; Abandon hope, ye who enter here |
|
|
mov si,trackbuf |
|
|
mov di,07C00h |
|
|
mov cx,512 ; Probably overkill, but should be safe |
|
|
rep movsd |
|
|
lss sp,[cs:InitStack] |
|
|
jmp 0:07C00h ; Jump to new boot sector |
|
|
|
|
|
.int18: |
|
|
int 18h ; Hope this does the right thing... |
|
|
jmp kaboom ; If we returned, oh boy... |
|
|
|
|
|
; |
|
|
; Abort loading code |
|
|
; |
|
|
%include "abort.inc" |
|
1375 |
|
|
1376 |
; |
; |
1377 |
; searchdir: |
; searchdir: |
1383 |
; If successful: |
; If successful: |
1384 |
; ZF clear |
; ZF clear |
1385 |
; SI = file pointer |
; SI = file pointer |
1386 |
; DX:AX or EAX = file length in bytes |
; EAX = file length in bytes |
1387 |
; If unsuccessful |
; If unsuccessful |
1388 |
; ZF set |
; ZF set |
1389 |
; |
; |
1407 |
push es |
push es |
1408 |
push ds |
push ds |
1409 |
pop es ; ES = DS |
pop es ; ES = DS |
1410 |
mov si,CurDir |
mov si,CurrentDir |
1411 |
cmp byte [di],'/' ; If filename begins with slash |
cmp byte [di],'/' ; If filename begins with slash |
1412 |
jne .not_rooted |
jne .not_rooted |
1413 |
inc di ; Skip leading slash |
inc di ; Skip leading slash |
1415 |
.not_rooted: |
.not_rooted: |
1416 |
mov eax,[si+dir_clust] |
mov eax,[si+dir_clust] |
1417 |
mov [bx+file_left],eax |
mov [bx+file_left],eax |
1418 |
|
shl eax,SECTOR_SHIFT |
1419 |
|
mov [bx+file_bytesleft],eax |
1420 |
mov eax,[si+dir_lba] |
mov eax,[si+dir_lba] |
1421 |
mov [bx+file_sector],eax |
mov [bx+file_sector],eax |
1422 |
mov edx,[si+dir_len] |
mov edx,[si+dir_len] |
1497 |
mov eax,[si+2] ; Location of extent |
mov eax,[si+2] ; Location of extent |
1498 |
mov [bx+file_sector],eax |
mov [bx+file_sector],eax |
1499 |
mov eax,[si+10] ; Data length |
mov eax,[si+10] ; Data length |
1500 |
|
mov [bx+file_bytesleft],eax |
1501 |
push eax |
push eax |
1502 |
add eax,SECTOR_SIZE-1 |
add eax,SECTOR_SIZE-1 |
1503 |
shr eax,SECTOR_SHIFT |
shr eax,SECTOR_SHIFT |
1504 |
mov [bx+file_left],eax |
mov [bx+file_left],eax |
1505 |
pop eax |
pop eax |
1506 |
mov edx,eax |
jz .failure ; Empty file? |
1507 |
shr edx,16 |
; ZF = 0 |
|
and bx,bx ; ZF = 0 |
|
1508 |
mov si,bx |
mov si,bx |
1509 |
pop es |
pop es |
1510 |
ret |
ret |
1542 |
ret |
ret |
1543 |
|
|
1544 |
; |
; |
1545 |
; iso_compare_names: |
; iso_compare_names: |
1546 |
; Compare the names DS:SI and DS:DI and report if they are |
; 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 |
; equal from an ISO 9660 perspective. SI is the name from |
1548 |
; the filesystem; CX indicates its length, and ';' terminates. |
; the filesystem; CX indicates its length, and ';' terminates. |
1595 |
; |
; |
1596 |
; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed |
; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed |
1597 |
; to by ES:DI; ends on encountering any whitespace. |
; to by ES:DI; ends on encountering any whitespace. |
1598 |
|
; DI is preserved. |
1599 |
; |
; |
1600 |
; This verifies that a filename is < FILENAME_MAX characters, |
; This verifies that a filename is < FILENAME_MAX characters, |
1601 |
; doesn't contain whitespace, zero-pads the output buffer, |
; doesn't contain whitespace, zero-pads the output buffer, |
1602 |
; and removes trailing dots and redundant slashes, |
; and removes trailing dots and redundant slashes, |
1603 |
; so "repe cmpsb" can do a compare, and the |
; so "repe cmpsb" can do a compare, and the |
1604 |
; path-searching routine gets a bit of an easier job. |
; path-searching routine gets a bit of an easier job. |
1605 |
; |
; |
1606 |
mangle_name: |
mangle_name: |
1607 |
|
push di |
1608 |
push bx |
push bx |
1609 |
xor ax,ax |
xor ax,ax |
1610 |
mov cx,FILENAME_MAX-1 |
mov cx,FILENAME_MAX-1 |
1625 |
.mn_end: |
.mn_end: |
1626 |
cmp bx,di ; At the beginning of the buffer? |
cmp bx,di ; At the beginning of the buffer? |
1627 |
jbe .mn_zero |
jbe .mn_zero |
1628 |
cmp byte [di-1],'.' ; Terminal dot? |
cmp byte [es:di-1],'.' ; Terminal dot? |
1629 |
je .mn_kill |
je .mn_kill |
1630 |
cmp byte [di-1],'/' ; Terminal slash? |
cmp byte [es:di-1],'/' ; Terminal slash? |
1631 |
jne .mn_zero |
jne .mn_zero |
1632 |
.mn_kill: dec di ; If so, remove it |
.mn_kill: dec di ; If so, remove it |
1633 |
inc cx |
inc cx |
1637 |
xor ax,ax ; Zero-fill name |
xor ax,ax ; Zero-fill name |
1638 |
rep stosb |
rep stosb |
1639 |
pop bx |
pop bx |
1640 |
|
pop di |
1641 |
ret ; Done |
ret ; Done |
1642 |
|
|
1643 |
; |
; |
1644 |
; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled |
; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled |
1645 |
; filename to the conventional representation. This is needed |
; filename to the conventional representation. This is needed |
1646 |
; for the BOOT_IMAGE= parameter for the kernel. |
; for the BOOT_IMAGE= parameter for the kernel. |
|
; NOTE: A 13-byte buffer is mandatory, even if the string is |
|
|
; known to be shorter. |
|
1647 |
; |
; |
1648 |
; DS:SI -> input mangled file name |
; DS:SI -> input mangled file name |
1649 |
; ES:DI -> output buffer |
; ES:DI -> output buffer |
1665 |
; On exit: |
; On exit: |
1666 |
; SI -> File pointer (or 0 on EOF) |
; SI -> File pointer (or 0 on EOF) |
1667 |
; CF = 1 -> Hit EOF |
; CF = 1 -> Hit EOF |
1668 |
|
; ECX -> Bytes actually read |
1669 |
; |
; |
1670 |
getfssec: |
getfssec: |
1671 |
TRACER 'F' |
TRACER 'F' |
|
|
|
1672 |
push ds |
push ds |
1673 |
push cs |
push cs |
1674 |
pop ds ; DS <- CS |
pop ds ; DS <- CS |
1679 |
mov ecx,[si+file_left] |
mov ecx,[si+file_left] |
1680 |
.ok_size: |
.ok_size: |
1681 |
|
|
1682 |
mov bp,cx |
pushad |
|
push cx |
|
|
push si |
|
1683 |
mov eax,[si+file_sector] |
mov eax,[si+file_sector] |
1684 |
|
mov bp,cx |
1685 |
TRACER 'l' |
TRACER 'l' |
1686 |
call getlinsec |
call getlinsec |
1687 |
xor ecx,ecx |
popad |
|
pop si |
|
|
pop cx |
|
1688 |
|
|
1689 |
|
; ECX[31:16] == 0 here... |
1690 |
add [si+file_sector],ecx |
add [si+file_sector],ecx |
1691 |
sub [si+file_left],ecx |
sub [si+file_left],ecx |
1692 |
ja .not_eof ; CF = 0 |
shl ecx,SECTOR_SHIFT ; Convert to bytes |
1693 |
|
cmp ecx,[si+file_bytesleft] |
1694 |
xor ecx,ecx |
jb .not_all |
1695 |
mov [si+file_sector],ecx ; Mark as unused |
mov ecx,[si+file_bytesleft] |
1696 |
xor si,si |
.not_all: sub [si+file_bytesleft],ecx |
1697 |
|
jnz .ret ; CF = 0 in this case... |
1698 |
|
push eax |
1699 |
|
xor eax,eax |
1700 |
|
mov [si+file_sector],eax ; Unused |
1701 |
|
mov si,ax |
1702 |
|
pop eax |
1703 |
stc |
stc |
1704 |
|
.ret: |
|
.not_eof: |
|
1705 |
pop ds |
pop ds |
1706 |
TRACER 'f' |
TRACER 'f' |
1707 |
ret |
ret |
1712 |
|
|
1713 |
%include "getc.inc" ; getc et al |
%include "getc.inc" ; getc et al |
1714 |
%include "conio.inc" ; Console I/O |
%include "conio.inc" ; Console I/O |
1715 |
|
%include "configinit.inc" ; Initialize configuration |
1716 |
%include "parseconfig.inc" ; High-level config file handling |
%include "parseconfig.inc" ; High-level config file handling |
1717 |
%include "parsecmd.inc" ; Low-level config file handling |
%include "parsecmd.inc" ; Low-level config file handling |
1718 |
%include "bcopy32.inc" ; 32-bit bcopy |
%include "bcopy32.inc" ; 32-bit bcopy |
1722 |
%include "highmem.inc" ; High memory sizing |
%include "highmem.inc" ; High memory sizing |
1723 |
%include "strcpy.inc" ; strcpy() |
%include "strcpy.inc" ; strcpy() |
1724 |
%include "rawcon.inc" ; Console I/O w/o using the console functions |
%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 |
1728 |
|
|
1729 |
; ----------------------------------------------------------------------------- |
; ----------------------------------------------------------------------------- |
1730 |
; Begin data section |
; Begin data section |
1732 |
|
|
1733 |
section .data |
section .data |
1734 |
|
|
|
boot_prompt db 'boot: ', 0 |
|
|
wipe_char db BS, ' ', BS, 0 |
|
|
err_notfound db 'Could not find kernel image: ',0 |
|
|
err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 |
|
|
err_noram db 'It appears your computer has less than ' |
|
|
asciidec dosram_k |
|
|
db 'K of low ("DOS")' |
|
|
db CR, LF |
|
|
db 'RAM. Linux needs at least this amount to boot. If you get' |
|
|
db CR, LF |
|
|
db 'this message in error, hold down the Ctrl key while' |
|
|
db CR, LF |
|
|
db 'booting, and I will take your word for it.', CR, LF, 0 |
|
|
err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 |
|
|
err_noparm db 'Missing parameter in config file.', CR, LF, 0 |
|
|
err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 |
|
|
err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 |
|
|
err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 |
|
|
err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' |
|
|
db CR, LF, 0 |
|
|
err_notdos db ': attempted DOS system call', CR, LF, 0 |
|
|
err_comlarge db 'COMBOOT image too large.', CR, LF, 0 |
|
|
err_bssimage db 'BSS images not supported.', CR, LF, 0 |
|
|
err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 |
|
|
notfound_msg db 'not found', CR, LF, 0 |
|
|
localboot_msg db 'Booting from local disk...', CR, LF, 0 |
|
|
cmdline_msg db 'Command line: ', CR, LF, 0 |
|
|
ready_msg db 'Ready.', CR, LF, 0 |
|
|
trying_msg db 'Trying to load: ', 0 |
|
|
crlfloading_msg db CR, LF ; Fall through |
|
|
loading_msg db 'Loading ', 0 |
|
|
dotdot_msg db '.' |
|
|
dot_msg db '.', 0 |
|
|
fourbs_msg db BS, BS, BS, BS, 0 |
|
|
aborted_msg db ' aborted.', CR, LF, 0 |
|
|
crff_msg db CR, FF, 0 |
|
1735 |
default_str db 'default', 0 |
default_str db 'default', 0 |
1736 |
default_len equ ($-default_str) |
default_len equ ($-default_str) |
1737 |
boot_dir db '/boot' ; /boot/isolinux |
boot_dir db '/boot' ; /boot/isolinux |
1738 |
isolinux_dir db '/isolinux', 0 |
isolinux_dir db '/isolinux', 0 |
1739 |
ConfigName equ $ |
config_name db 'isolinux.cfg', 0 |
|
isolinux_cfg db 'isolinux.cfg', 0 |
|
1740 |
err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 |
err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 |
1741 |
|
|
1742 |
%ifdef DEBUG_MESSAGES |
%ifdef DEBUG_MESSAGES |
1745 |
dbg_config_msg db 'About to load config file...', CR, LF, 0 |
dbg_config_msg db 'About to load config file...', CR, LF, 0 |
1746 |
dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 |
dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 |
1747 |
%endif |
%endif |
|
; |
|
|
; Command line options we'd like to take a look at |
|
|
; |
|
|
; mem= and vga= are handled as normal 32-bit integer values |
|
|
initrd_cmd db 'initrd=' |
|
|
initrd_cmd_len equ 7 |
|
1748 |
|
|
1749 |
; |
; |
1750 |
; Config file keyword table |
; Config file keyword table |
1754 |
; |
; |
1755 |
; Extensions to search for (in *forward* order). |
; Extensions to search for (in *forward* order). |
1756 |
; |
; |
1757 |
align 4, db 0 |
alignz 4 |
1758 |
exten_table: db '.cbt' ; COMBOOT (specific) |
exten_table: db '.cbt' ; COMBOOT (specific) |
1759 |
db '.img' ; Disk image |
db '.img' ; Disk image |
1760 |
db '.bin' ; CD boot sector |
db '.bin' ; CD boot sector |
1766 |
; |
; |
1767 |
; Floppy image table |
; Floppy image table |
1768 |
; |
; |
1769 |
align 4, db 0 |
alignz 4 |
1770 |
img_table_count equ 3 |
img_table_count equ 3 |
1771 |
img_table: |
img_table: |
1772 |
dd 1200*1024 ; 1200K floppy |
dd 1200*1024 ; 1200K floppy |
1797 |
; **** ISOLINUX:: We may have to make this flexible, based on what the |
; **** ISOLINUX:: We may have to make this flexible, based on what the |
1798 |
; **** BIOS expects our "sector size" to be. |
; **** BIOS expects our "sector size" to be. |
1799 |
; |
; |
1800 |
alignb 4, db 0 |
alignz 4 |
1801 |
BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf |
BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf |
|
BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? |
|
1802 |
BufSafeBytes dw trackbufsize ; = how many bytes? |
BufSafeBytes dw trackbufsize ; = how many bytes? |
|
EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes |
|
1803 |
%ifndef DEPEND |
%ifndef DEPEND |
1804 |
%if ( trackbufsize % SECTOR_SIZE ) != 0 |
%if ( trackbufsize % SECTOR_SIZE ) != 0 |
1805 |
%error trackbufsize must be a multiple of SECTOR_SIZE |
%error trackbufsize must be a multiple of SECTOR_SIZE |