Magellan Linux

Annotation of /tags/mkinitrd-6_1_12/isolinux/ldlinux.asm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 939 - (hide annotations) (download)
Tue Nov 17 21:24:51 2009 UTC (14 years, 6 months ago) by niro
File size: 36902 byte(s)
tagged 'mkinitrd-6_1_12'
1 niro 532 ; -*- fundamental -*- (asm-mode sucks)
2     ; $Id: ldlinux.asm,v 1.1 2007-09-01 22:44:05 niro Exp $
3     ; ****************************************************************************
4     ;
5     ; ldlinux.asm
6     ;
7     ; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This
8     ; functionality is good to have for installation floppies, where it may
9     ; be hard to find a functional Linux system to run LILO off.
10     ;
11     ; This program allows manipulation of the disk to take place entirely
12     ; from MS-LOSS, and can be especially useful in conjunction with the
13     ; umsdos filesystem.
14     ;
15     ; Copyright (C) 1994-2005 H. Peter Anvin
16     ;
17     ; This program is free software; you can redistribute it and/or modify
18     ; it under the terms of the GNU General Public License as published by
19     ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
20     ; Boston MA 02111-1307, USA; either version 2 of the License, or
21     ; (at your option) any later version; incorporated herein by reference.
22     ;
23     ; ****************************************************************************
24    
25     %ifndef IS_MDSLINUX
26     %define IS_SYSLINUX 1
27     %endif
28     %include "macros.inc"
29     %include "config.inc"
30     %include "kernel.inc"
31     %include "bios.inc"
32     %include "tracers.inc"
33     %include "layout.inc"
34     ;
35     ; Some semi-configurable constants... change on your own risk.
36     ;
37     my_id equ syslinux_id
38     FILENAME_MAX_LG2 equ 4 ; log2(Max filename size Including final null)
39     FILENAME_MAX equ 11 ; Max mangled filename size
40     NULLFILE equ ' ' ; First char space == null filename
41     NULLOFFSET equ 0 ; Position in which to look
42     retry_count equ 16 ; How patient are we with the disk?
43     %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
44     LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
45    
46     MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
47     MAX_OPEN equ (1 << MAX_OPEN_LG2)
48    
49     SECTOR_SHIFT equ 9
50     SECTOR_SIZE equ (1 << SECTOR_SHIFT)
51    
52     ;
53     ; This is what we need to do when idle
54     ;
55     %macro RESET_IDLE 0
56     ; Nothing
57     %endmacro
58     %macro DO_IDLE 0
59     ; Nothing
60     %endmacro
61    
62     ;
63     ; The following structure is used for "virtual kernels"; i.e. LILO-style
64     ; option labels. The options we permit here are `kernel' and `append
65     ; Since there is no room in the bottom 64K for all of these, we
66     ; stick them at vk_seg:0000 and copy them down before we need them.
67     ;
68     struc vkernel
69     vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
70     vk_rname: resb FILENAME_MAX ; Real name
71     vk_appendlen: resw 1
72     alignb 4
73     vk_append: resb max_cmd_len+1 ; Command line
74     alignb 4
75     vk_end: equ $ ; Should be <= vk_size
76     endstruc
77    
78     ;
79     ; Segment assignments in the bottom 640K
80     ; Stick to the low 512K in case we're using something like M-systems flash
81     ; which load a driver into low RAM (evil!!)
82     ;
83     ; 0000h - main code/data segment (and BIOS segment)
84     ;
85     real_mode_seg equ 4000h
86     cache_seg equ 3000h ; 64K area for metadata cache
87     vk_seg equ 2000h ; Virtual kernels
88     xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
89     comboot_seg equ real_mode_seg ; COMBOOT image loading zone
90    
91     ;
92     ; File structure. This holds the information for each currently open file.
93     ;
94     struc open_file_t
95     file_sector resd 1 ; Sector pointer (0 = structure free)
96     file_left resd 1 ; Number of sectors left
97     endstruc
98    
99     %ifndef DEPEND
100     %if (open_file_t_size & (open_file_t_size-1))
101     %error "open_file_t is not a power of 2"
102     %endif
103     %endif
104    
105     ; ---------------------------------------------------------------------------
106     ; BEGIN CODE
107     ; ---------------------------------------------------------------------------
108    
109     ;
110     ; Memory below this point is reserved for the BIOS and the MBR
111     ;
112     section .earlybss
113     trackbufsize equ 8192
114     trackbuf resb trackbufsize ; Track buffer goes here
115     getcbuf resb trackbufsize
116     ; ends at 4800h
117    
118     section .bss
119     alignb 8
120    
121     ; Expanded superblock
122     SuperInfo equ $
123     resq 16 ; The first 16 bytes expanded 8 times
124     FAT resd 1 ; Location of (first) FAT
125     RootDirArea resd 1 ; Location of root directory area
126     RootDir resd 1 ; Location of root directory proper
127     DataArea resd 1 ; Location of data area
128     RootDirSize resd 1 ; Root dir size in sectors
129     TotalSectors resd 1 ; Total number of sectors
130     EndSector resd 1 ; Location of filesystem end
131     ClustSize resd 1 ; Bytes/cluster
132     ClustMask resd 1 ; Sectors/cluster - 1
133     CopySuper resb 1 ; Distinguish .bs versus .bss
134     DriveNumber resb 1 ; BIOS drive number
135     ClustShift resb 1 ; Shift count for sectors/cluster
136     ClustByteShift resb 1 ; Shift count for bytes/cluster
137    
138     alignb open_file_t_size
139     Files resb MAX_OPEN*open_file_t_size
140    
141     ;
142     ; Constants for the xfer_buf_seg
143     ;
144     ; The xfer_buf_seg is also used to store message file buffers. We
145     ; need two trackbuffers (text and graphics), plus a work buffer
146     ; for the graphics decompressor.
147     ;
148     xbs_textbuf equ 0 ; Also hard-coded, do not change
149     xbs_vgabuf equ trackbufsize
150     xbs_vgatmpbuf equ 2*trackbufsize
151    
152    
153     section .text
154     ;
155     ; Some of the things that have to be saved very early are saved
156     ; "close" to the initial stack pointer offset, in order to
157     ; reduce the code size...
158     ;
159     StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
160     PartInfo equ StackBuf ; Saved partition table entry
161     FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
162     OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack
163    
164     ;
165     ; Primary entry point. Tempting as though it may be, we can't put the
166     ; initial "cli" here; the jmp opcode in the first byte is part of the
167     ; "magic number" (using the term very loosely) for the DOS superblock.
168     ;
169     bootsec equ $
170     jmp short start ; 2 bytes
171     nop ; 1 byte
172     ;
173     ; "Superblock" follows -- it's in the boot sector, so it's already
174     ; loaded and ready for us
175     ;
176     bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
177     ;
178     ; These are the fields we actually care about. We end up expanding them
179     ; all to dword size early in the code, so generate labels for both
180     ; the expanded and unexpanded versions.
181     ;
182     %macro superb 1
183     bx %+ %1 equ SuperInfo+($-superblock)*8+4
184     bs %+ %1 equ $
185     zb 1
186     %endmacro
187     %macro superw 1
188     bx %+ %1 equ SuperInfo+($-superblock)*8
189     bs %+ %1 equ $
190     zw 1
191     %endmacro
192     %macro superd 1
193     bx %+ %1 equ $ ; no expansion for dwords
194     bs %+ %1 equ $
195     zd 1
196     %endmacro
197     superblock equ $
198     superw BytesPerSec
199     superb SecPerClust
200     superw ResSectors
201     superb FATs
202     superw RootDirEnts
203     superw Sectors
204     superb Media
205     superw FATsecs
206     superw SecPerTrack
207     superw Heads
208     superinfo_size equ ($-superblock)-1 ; How much to expand
209     superd Hidden
210     superd HugeSectors
211     ;
212     ; This is as far as FAT12/16 and FAT32 are consistent
213     ;
214     zb 54 ; FAT12/16 need 26 more bytes,
215     ; FAT32 need 54 more bytes
216     superblock_len equ $-superblock
217    
218     SecPerClust equ bxSecPerClust
219     ;
220     ; Note we don't check the constraints above now; we did that at install
221     ; time (we hope!)
222     ;
223     start:
224     cli ; No interrupts yet, please
225     cld ; Copy upwards
226     ;
227     ; Set up the stack
228     ;
229     xor ax,ax
230     mov ss,ax
231     mov sp,StackBuf ; Just below BSS
232     mov es,ax
233     ;
234     ; DS:SI may contain a partition table entry. Preserve it for us.
235     ;
236     mov cx,8 ; Save partition info
237     mov di,sp
238     rep movsw
239    
240     mov ds,ax ; Now we can initialize DS...
241    
242     ;
243     ; Now sautee the BIOS floppy info block to that it will support decent-
244     ; size transfers; the floppy block is 11 bytes and is stored in the
245     ; INT 1Eh vector (brilliant waste of resources, eh?)
246     ;
247     ; Of course, if BIOSes had been properly programmed, we wouldn't have
248     ; had to waste precious space with this code.
249     ;
250     mov bx,fdctab
251     lfs si,[bx] ; FS:SI -> original fdctab
252     push fs ; Save on stack in case we need to bail
253     push si
254    
255     ; Save the old fdctab even if hard disk so the stack layout
256     ; is the same. The instructions above do not change the flags
257     mov [DriveNumber],dl ; Save drive number in DL
258     and dl,dl ; If floppy disk (00-7F), assume no
259     ; partition table
260     js harddisk
261    
262     floppy:
263     mov cl,6 ; 12 bytes (CX == 0)
264     ; es:di -> FloppyTable already
265     ; This should be safe to do now, interrupts are off...
266     mov [bx],di ; FloppyTable
267     mov [bx+2],ax ; Segment 0
268     fs rep movsw ; Faster to move words
269     mov cl,[bsSecPerTrack] ; Patch the sector count
270     mov [di-8],cl
271     ; AX == 0 here
272     int 13h ; Some BIOSes need this
273    
274     jmp short not_harddisk
275     ;
276     ; The drive number and possibly partition information was passed to us
277     ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
278     ; trust that rather than what the superblock contains.
279     ;
280     ; Would it be better to zero out bsHidden if we don't have a partition table?
281     ;
282     ; Note: di points to beyond the end of PartInfo
283     ;
284     harddisk:
285     test byte [di-16],7Fh ; Sanity check: "active flag" should
286     jnz no_partition ; be 00 or 80
287     mov eax,[di-8] ; Partition offset (dword)
288     mov [bsHidden],eax
289     no_partition:
290     ;
291     ; Get disk drive parameters (don't trust the superblock.) Don't do this for
292     ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
293     ; what the *drive* supports, not about the *media*. Fortunately floppy disks
294     ; tend to have a fixed, well-defined geometry which is stored in the superblock.
295     ;
296     ; DL == drive # still
297     mov ah,08h
298     int 13h
299     jc no_driveparm
300     and ah,ah
301     jnz no_driveparm
302     shr dx,8
303     inc dx ; Contains # of heads - 1
304     mov [bsHeads],dx
305     and cx,3fh
306     mov [bsSecPerTrack],cx
307     no_driveparm:
308     not_harddisk:
309     ;
310     ; Ready to enable interrupts, captain
311     ;
312     sti
313    
314     ;
315     ; Do we have EBIOS (EDD)?
316     ;
317     eddcheck:
318     mov bx,55AAh
319     mov ah,41h ; EDD existence query
320     mov dl,[DriveNumber]
321     int 13h
322     jc .noedd
323     cmp bx,0AA55h
324     jne .noedd
325     test cl,1 ; Extended disk access functionality set
326     jz .noedd
327     ;
328     ; We have EDD support...
329     ;
330     mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
331     .noedd:
332    
333     ;
334     ; Load the first sector of LDLINUX.SYS; this used to be all proper
335     ; with parsing the superblock and root directory; it doesn't fit
336     ; together with EBIOS support, unfortunately.
337     ;
338     mov eax,[FirstSector] ; Sector start
339     mov bx,ldlinux_sys ; Where to load it
340     call getonesec
341    
342     ; Some modicum of integrity checking
343     cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
344     jne kaboom
345    
346     ; Go for it...
347     jmp ldlinux_ent
348    
349     ;
350     ; getonesec: get one disk sector
351     ;
352     getonesec:
353     mov bp,1 ; One sector
354     ; Fall through
355    
356     ;
357     ; getlinsec: load a sequence of BP floppy sector given by the linear sector
358     ; number in EAX into the buffer at ES:BX. We try to optimize
359     ; by loading up to a whole track at a time, but the user
360     ; is responsible for not crossing a 64K boundary.
361     ; (Yes, BP is weird for a count, but it was available...)
362     ;
363     ; On return, BX points to the first byte after the transferred
364     ; block.
365     ;
366     ; This routine assumes CS == DS, and trashes most registers.
367     ;
368     ; Stylistic note: use "xchg" instead of "mov" when the source is a register
369     ; that is dead from that point; this saves space. However, please keep
370     ; the order to dst,src to keep things sane.
371     ;
372     getlinsec:
373     add eax,[bsHidden] ; Add partition offset
374     xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
375    
376     .jmp: jmp strict short getlinsec_cbios
377    
378     ;
379     ; getlinsec_ebios:
380     ;
381     ; getlinsec implementation for EBIOS (EDD)
382     ;
383     getlinsec_ebios:
384     .loop:
385     push bp ; Sectors left
386     .retry2:
387     call maxtrans ; Enforce maximum transfer size
388     movzx edi,bp ; Sectors we are about to read
389     mov cx,retry_count
390     .retry:
391    
392     ; Form DAPA on stack
393     push edx
394     push eax
395     push es
396     push bx
397     push di
398     push word 16
399     mov si,sp
400     pushad
401     mov dl,[DriveNumber]
402     push ds
403     push ss
404     pop ds ; DS <- SS
405     mov ah,42h ; Extended Read
406     int 13h
407     pop ds
408     popad
409     lea sp,[si+16] ; Remove DAPA
410     jc .error
411     pop bp
412     add eax,edi ; Advance sector pointer
413     sub bp,di ; Sectors left
414     shl di,SECTOR_SHIFT ; 512-byte sectors
415     add bx,di ; Advance buffer pointer
416     and bp,bp
417     jnz .loop
418    
419     ret
420    
421     .error:
422     ; Some systems seem to get "stuck" in an error state when
423     ; using EBIOS. Doesn't happen when using CBIOS, which is
424     ; good, since some other systems get timeout failures
425     ; waiting for the floppy disk to spin up.
426    
427     pushad ; Try resetting the device
428     xor ax,ax
429     mov dl,[DriveNumber]
430     int 13h
431     popad
432     loop .retry ; CX-- and jump if not zero
433    
434     ;shr word [MaxTransfer],1 ; Reduce the transfer size
435     ;jnz .retry2
436    
437     ; Total failure. Try falling back to CBIOS.
438     mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
439     ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
440    
441     pop bp
442     ; ... fall through ...
443    
444     ;
445     ; getlinsec_cbios:
446     ;
447     ; getlinsec implementation for legacy CBIOS
448     ;
449     getlinsec_cbios:
450     .loop:
451     push edx
452     push eax
453     push bp
454     push bx
455    
456     movzx esi,word [bsSecPerTrack]
457     movzx edi,word [bsHeads]
458     ;
459     ; Dividing by sectors to get (track,sector): we may have
460     ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
461     ;
462     div esi
463     xor cx,cx
464     xchg cx,dx ; CX <- sector index (0-based)
465     ; EDX <- 0
466     ; eax = track #
467     div edi ; Convert track to head/cyl
468    
469     ; We should test this, but it doesn't fit...
470     ; cmp eax,1023
471     ; ja .error
472    
473     ;
474     ; Now we have AX = cyl, DX = head, CX = sector (0-based),
475     ; BP = sectors to transfer, SI = bsSecPerTrack,
476     ; ES:BX = data target
477     ;
478    
479     call maxtrans ; Enforce maximum transfer size
480    
481     ; Must not cross track boundaries, so BP <= SI-CX
482     sub si,cx
483     cmp bp,si
484     jna .bp_ok
485     mov bp,si
486     .bp_ok:
487    
488     shl ah,6 ; Because IBM was STOOPID
489     ; and thought 8 bits were enough
490     ; then thought 10 bits were enough...
491     inc cx ; Sector numbers are 1-based, sigh
492     or cl,ah
493     mov ch,al
494     mov dh,dl
495     mov dl,[DriveNumber]
496     xchg ax,bp ; Sector to transfer count
497     mov ah,02h ; Read sectors
498     mov bp,retry_count
499     .retry:
500     pushad
501     int 13h
502     popad
503     jc .error
504     .resume:
505     movzx ecx,al ; ECX <- sectors transferred
506     shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
507     pop bx
508     add bx,ax
509     pop bp
510     pop eax
511     pop edx
512     add eax,ecx
513     sub bp,cx
514     jnz .loop
515     ret
516    
517     .error:
518     dec bp
519     jnz .retry
520    
521     xchg ax,bp ; Sectors transferred <- 0
522     shr word [MaxTransfer],1
523     jnz .resume
524     ; Fall through to disk_error
525    
526     ;
527     ; kaboom: write a message and bail out.
528     ;
529     disk_error:
530     kaboom:
531     xor si,si
532     mov ss,si
533     mov sp,StackBuf-4 ; Reset stack
534     mov ds,si ; Reset data segment
535     pop dword [fdctab] ; Restore FDC table
536     .patch: ; When we have full code, intercept here
537     mov si,bailmsg
538    
539     ; Write error message, this assumes screen page 0
540     .loop: lodsb
541     and al,al
542     jz .done
543     mov ah,0Eh ; Write to screen as TTY
544     mov bx,0007h ; Attribute
545     int 10h
546     jmp short .loop
547     .done:
548     cbw ; AH <- 0
549     int 16h ; Wait for keypress
550     int 19h ; And try once more to boot...
551     .norge: jmp short .norge ; If int 19h returned; this is the end
552    
553     ;
554     ; Truncate BP to MaxTransfer
555     ;
556     maxtrans:
557     cmp bp,[MaxTransfer]
558     jna .ok
559     mov bp,[MaxTransfer]
560     .ok: ret
561    
562     ;
563     ; Error message on failure
564     ;
565     bailmsg: db 'Boot error', 0Dh, 0Ah, 0
566    
567     ; This fails if the boot sector overflows
568     zb 1F8h-($-$$)
569    
570     FirstSector dd 0xDEADBEEF ; Location of sector 1
571     MaxTransfer dw 0x007F ; Max transfer size
572     bootsignature dw 0AA55h
573    
574     ;
575     ; ===========================================================================
576     ; End of boot sector
577     ; ===========================================================================
578     ; Start of LDLINUX.SYS
579     ; ===========================================================================
580    
581     ldlinux_sys:
582    
583     syslinux_banner db 0Dh, 0Ah
584     %if IS_MDSLINUX
585     db 'MDSLINUX '
586     %else
587     db 'SYSLINUX '
588     %endif
589     db version_str, ' ', date, ' ', 0
590     db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
591    
592     align 8, db 0
593     ldlinux_magic dd LDLINUX_MAGIC
594     dd LDLINUX_MAGIC^HEXDATE
595    
596     ;
597     ; This area is patched by the installer. It is found by looking for
598     ; LDLINUX_MAGIC, plus 8 bytes.
599     ;
600     patch_area:
601     LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
602     LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
603     CheckSum dd 0 ; Checksum starting at ldlinux_sys
604     ; value = LDLINUX_MAGIC - [sum of dwords]
605    
606     ; Space for up to 64 sectors, the theoretical maximum
607     SectorPtrs times 64 dd 0
608    
609     ldlinux_ent:
610     ;
611     ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
612     ; instead of 0000:7C00 and the like. We don't want to add anything
613     ; more to the boot sector, so it is written to not assume a fixed
614     ; value in CS, but we don't want to deal with that anymore from now
615     ; on.
616     ;
617     jmp 0:.next
618     .next:
619    
620     ;
621     ; Tell the user we got this far
622     ;
623     mov si,syslinux_banner
624     call writestr
625    
626     ;
627     ; Tell the user if we're using EBIOS or CBIOS
628     ;
629     print_bios:
630     mov si,cbios_name
631     cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
632     jne .cbios
633     mov si,ebios_name
634     .cbios:
635     mov [BIOSName],si
636     call writestr
637    
638     section .bss
639     %define HAVE_BIOSNAME 1
640     BIOSName resw 1
641    
642     section .text
643     ;
644     ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
645     ; sector again, though.
646     ;
647     load_rest:
648     mov si,SectorPtrs
649     mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
650     mov cx,[LDLSectors]
651    
652     .get_chunk:
653     jcxz .done
654     xor bp,bp
655     lodsd ; First sector of this chunk
656    
657     mov edx,eax
658    
659     .make_chunk:
660     inc bp
661     dec cx
662     jz .chunk_ready
663     inc edx ; Next linear sector
664     cmp [si],edx ; Does it match
665     jnz .chunk_ready ; If not, this is it
666     add si,4 ; If so, add sector to chunk
667     jmp short .make_chunk
668    
669     .chunk_ready:
670     call getlinsecsr
671     shl bp,SECTOR_SHIFT
672     add bx,bp
673     jmp .get_chunk
674    
675     .done:
676    
677     ;
678     ; All loaded up, verify that we got what we needed.
679     ; Note: the checksum field is embedded in the checksum region, so
680     ; by the time we get to the end it should all cancel out.
681     ;
682     verify_checksum:
683     mov si,ldlinux_sys
684     mov cx,[LDLDwords]
685     mov edx,-LDLINUX_MAGIC
686     .checksum:
687     lodsd
688     add edx,eax
689     loop .checksum
690    
691     and edx,edx ; Should be zero
692     jz all_read ; We're cool, go for it!
693    
694     ;
695     ; Uh-oh, something went bad...
696     ;
697     mov si,checksumerr_msg
698     call writestr
699     jmp kaboom
700    
701     ;
702     ; -----------------------------------------------------------------------------
703     ; Subroutines that have to be in the first sector
704     ; -----------------------------------------------------------------------------
705    
706     ;
707     ;
708     ; writestr: write a null-terminated string to the console
709     ; This assumes we're on page 0. This is only used for early
710     ; messages, so it should be OK.
711     ;
712     writestr:
713     .loop: lodsb
714     and al,al
715     jz .return
716     mov ah,0Eh ; Write to screen as TTY
717     mov bx,0007h ; Attribute
718     int 10h
719     jmp short .loop
720     .return: ret
721    
722    
723     ; getlinsecsr: save registers, call getlinsec, restore registers
724     ;
725     getlinsecsr: pushad
726     call getlinsec
727     popad
728     ret
729    
730     ;
731     ; Checksum error message
732     ;
733     checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
734    
735     ;
736     ; BIOS type string
737     ;
738     cbios_name db 'CBIOS', 0
739     ebios_name db 'EBIOS', 0
740    
741     ;
742     ; Debug routine
743     ;
744     %ifdef debug
745     safedumpregs:
746     cmp word [Debug_Magic],0D00Dh
747     jnz nc_return
748     jmp dumpregs
749     %endif
750    
751     rl_checkpt equ $ ; Must be <= 8000h
752    
753     rl_checkpt_off equ ($-$$)
754     %ifndef DEPEND
755     %if rl_checkpt_off > 400h
756     %error "Sector 1 overflow"
757     %endif
758     %endif
759    
760     ; ----------------------------------------------------------------------------
761     ; End of code and data that have to be in the first sector
762     ; ----------------------------------------------------------------------------
763    
764     all_read:
765     ;
766     ; Let the user (and programmer!) know we got this far. This used to be
767     ; in Sector 1, but makes a lot more sense here.
768     ;
769     mov si,copyright_str
770     call writestr
771    
772    
773     ;
774     ; Insane hack to expand the superblock to dwords
775     ;
776     expand_super:
777     xor eax,eax
778     mov si,superblock
779     mov di,SuperInfo
780     mov cx,superinfo_size
781     .loop:
782     lodsw
783     dec si
784     stosd ; Store expanded word
785     xor ah,ah
786     stosd ; Store expanded byte
787     loop .loop
788    
789     ;
790     ; Compute some information about this filesystem.
791     ;
792    
793     ; First, generate the map of regions
794     genfatinfo:
795     mov edx,[bxSectors]
796     and dx,dx
797     jnz .have_secs
798     mov edx,[bsHugeSectors]
799     .have_secs:
800     mov [TotalSectors],edx
801    
802     add edx,eax
803     mov [EndSector],edx
804    
805     mov eax,[bxResSectors]
806     mov [FAT],eax ; Beginning of FAT
807     mov edx,[bxFATsecs]
808     and dx,dx
809     jnz .have_fatsecs
810     mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
811     .have_fatsecs:
812     imul edx,[bxFATs]
813     add eax,edx
814     mov [RootDirArea],eax ; Beginning of root directory
815     mov [RootDir],eax ; For FAT12/16 == root dir location
816    
817     mov edx,[bxRootDirEnts]
818     add dx,SECTOR_SIZE/32-1
819     shr dx,SECTOR_SHIFT-5
820     mov [RootDirSize],edx
821     add eax,edx
822     mov [DataArea],eax ; Beginning of data area
823    
824     ; Next, generate a cluster size shift count and mask
825     mov eax,[bxSecPerClust]
826     bsr cx,ax
827     mov [ClustShift],cl
828     push cx
829     add cl,9
830     mov [ClustByteShift],cl
831     pop cx
832     dec ax
833     mov [ClustMask],eax
834     inc ax
835     shl eax,9
836     mov [ClustSize],eax
837    
838     ;
839     ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
840     ;
841     getfattype:
842     mov eax,[EndSector]
843     sub eax,[DataArea]
844     shr eax,cl ; cl == ClustShift
845     mov cl,nextcluster_fat12-(nextcluster+2)
846     cmp eax,4085 ; FAT12 limit
847     jb .setsize
848     mov cl,nextcluster_fat16-(nextcluster+2)
849     cmp eax,65525 ; FAT16 limit
850     jb .setsize
851     ;
852     ; FAT32, root directory is a cluster chain
853     ;
854     mov cl,[ClustShift]
855     mov eax,[bootsec+44] ; Root directory cluster
856     sub eax,2
857     shl eax,cl
858     add eax,[DataArea]
859     mov [RootDir],eax
860     mov cl,nextcluster_fat28-(nextcluster+2)
861     .setsize:
862     mov byte [nextcluster+1],cl
863    
864     ;
865     ; Common initialization code
866     ;
867     %include "cpuinit.inc"
868     %include "init.inc"
869    
870     ;
871     ; Clear Files structures
872     ;
873     mov di,Files
874     mov cx,(MAX_OPEN*open_file_t_size)/4
875     xor eax,eax
876     rep stosd
877    
878     ;
879     ; Initialize the metadata cache
880     ;
881     call initcache
882    
883     ;
884     ; Now, everything is "up and running"... patch kaboom for more
885     ; verbosity and using the full screen system
886     ;
887     ; E9 = JMP NEAR
888     mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
889    
890     ;
891     ; Now we're all set to start with our *real* business. First load the
892     ; configuration file (if any) and parse it.
893     ;
894     ; In previous versions I avoided using 32-bit registers because of a
895     ; rumour some BIOSes clobbered the upper half of 32-bit registers at
896     ; random. I figure, though, that if there are any of those still left
897     ; they probably won't be trying to install Linux on them...
898     ;
899     ; The code is still ripe with 16-bitisms, though. Not worth the hassle
900     ; to take'm out. In fact, we may want to put them back if we're going
901     ; to boot ELKS at some point.
902     ;
903    
904     ;
905     ; Load configuration file
906     ;
907     mov di,syslinux_cfg
908     call open
909     jz no_config_file
910    
911     ;
912     ; Now we have the config file open. Parse the config file and
913     ; run the user interface.
914     ;
915     %include "ui.inc"
916    
917     ;
918     ; Linux kernel loading code is common.
919     ;
920     %include "runkernel.inc"
921    
922     ;
923     ; COMBOOT-loading code
924     ;
925     %include "comboot.inc"
926     %include "com32.inc"
927     %include "cmdline.inc"
928    
929     ;
930     ; Boot sector loading code
931     ;
932     %include "bootsect.inc"
933    
934     ;
935     ; Abort loading code
936     ;
937     %include "abort.inc"
938    
939     ;
940     ; allocate_file: Allocate a file structure
941     ;
942     ; If successful:
943     ; ZF set
944     ; BX = file pointer
945     ; In unsuccessful:
946     ; ZF clear
947     ;
948     allocate_file:
949     TRACER 'a'
950     push cx
951     mov bx,Files
952     mov cx,MAX_OPEN
953     .check: cmp dword [bx], byte 0
954     je .found
955     add bx,open_file_t_size ; ZF = 0
956     loop .check
957     ; ZF = 0 if we fell out of the loop
958     .found: pop cx
959     ret
960    
961     ;
962     ; searchdir:
963     ; Search the root directory for a pre-mangled filename in DS:DI.
964     ;
965     ; NOTE: This file considers finding a zero-length file an
966     ; error. This is so we don't have to deal with that special
967     ; case elsewhere in the program (most loops have the test
968     ; at the end).
969     ;
970     ; If successful:
971     ; ZF clear
972     ; SI = file pointer
973     ; DX:AX = file length in bytes
974     ; If unsuccessful
975     ; ZF set
976     ;
977    
978     searchdir:
979     push bx
980     call allocate_file
981     jnz .alloc_failure
982    
983     push cx
984     push gs
985     push es
986     push ds
987     pop es ; ES = DS
988    
989     mov eax,[RootDir] ; First root directory sector
990    
991     .scansector:
992     call getcachesector
993     ; GS:SI now points to this sector
994    
995     mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
996     .scanentry:
997     cmp byte [gs:si],0
998     jz .failure ; Hit directory high water mark
999     push cx
1000     push si
1001     push di
1002     mov cx,11
1003     gs repe cmpsb
1004     pop di
1005     pop si
1006     pop cx
1007     jz .found
1008     add si,32
1009     loop .scanentry
1010    
1011     call nextsector
1012     jnc .scansector ; CF is set if we're at end
1013    
1014     ; If we get here, we failed
1015     .failure:
1016     pop es
1017     pop gs
1018     pop cx
1019     .alloc_failure:
1020     pop bx
1021     xor eax,eax ; ZF <- 1
1022     ret
1023     .found:
1024     mov eax,[gs:si+28] ; File size
1025     add eax,SECTOR_SIZE-1
1026     shr eax,SECTOR_SHIFT
1027     jz .failure ; Zero-length file
1028     mov [bx+4],eax
1029    
1030     mov cl,[ClustShift]
1031     mov dx,[gs:si+20] ; High cluster word
1032     shl edx,16
1033     mov dx,[gs:si+26] ; Low cluster word
1034     sub edx,2
1035     shl edx,cl
1036     add edx,[DataArea]
1037     mov [bx],edx ; Starting sector
1038    
1039     mov eax,[gs:si+28] ; File length again
1040     mov dx,[gs:si+30] ; 16-bitism, sigh
1041     mov si,bx
1042     and eax,eax ; ZF <- 0
1043    
1044     pop es
1045     pop gs
1046     pop cx
1047     pop bx
1048     ret
1049    
1050     ;
1051     ; writechr: Write a single character in AL to the console without
1052     ; mangling any registers; handle video pages correctly.
1053     ;
1054     writechr:
1055     call write_serial ; write to serial port if needed
1056     pushfd
1057     test byte [cs:DisplayCon], 01h
1058     jz .nothing
1059     pushad
1060     mov ah,0Eh
1061     mov bl,07h ; attribute
1062     mov bh,[cs:BIOS_page] ; current page
1063     int 10h
1064     popad
1065     .nothing:
1066     popfd
1067     ret
1068    
1069     ;
1070     ;
1071     ; kaboom2: once everything is loaded, replace the part of kaboom
1072     ; starting with "kaboom.patch" with this part
1073    
1074     kaboom2:
1075     mov si,err_bootfailed
1076     call cwritestr
1077     call getchar
1078     call vgaclearmode
1079     int 19h ; And try once more to boot...
1080     .norge: jmp short .norge ; If int 19h returned; this is the end
1081    
1082     ;
1083     ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
1084     ; to by ES:DI; ends on encountering any whitespace
1085     ;
1086    
1087     mangle_name:
1088     mov cx,11 ; # of bytes to write
1089     mn_loop:
1090     lodsb
1091     cmp al,' ' ; If control or space, end
1092     jna mn_end
1093     cmp al,'.' ; Period -> space-fill
1094     je mn_is_period
1095     cmp al,'a'
1096     jb mn_not_lower
1097     cmp al,'z'
1098     ja mn_not_uslower
1099     sub al,020h
1100     jmp short mn_not_lower
1101     mn_is_period: mov al,' ' ; We need to space-fill
1102     mn_period_loop: cmp cx,3 ; If <= 3 characters left
1103     jbe mn_loop ; Just ignore it
1104     stosb ; Otherwise, write a period
1105     loop mn_period_loop ; Dec CX and (always) jump
1106     mn_not_uslower: cmp al,ucase_low
1107     jb mn_not_lower
1108     cmp al,ucase_high
1109     ja mn_not_lower
1110     mov bx,ucase_tab-ucase_low
1111     cs xlatb
1112     mn_not_lower: stosb
1113     loop mn_loop ; Don't continue if too long
1114     mn_end:
1115     mov al,' ' ; Space-fill name
1116     rep stosb ; Doesn't do anything if CX=0
1117     ret ; Done
1118    
1119     ;
1120     ; Upper-case table for extended characters; this is technically code page 865,
1121     ; but code page 437 users will probably not miss not being able to use the
1122     ; cent sign in kernel images too much :-)
1123     ;
1124     ; The table only covers the range 129 to 164; the rest we can deal with.
1125     ;
1126     ucase_low equ 129
1127     ucase_high equ 164
1128     ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1129     db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1130     db 157, 156, 157, 158, 159, 'AIOU', 165
1131    
1132     ;
1133     ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1134     ; filename to the conventional representation. This is needed
1135     ; for the BOOT_IMAGE= parameter for the kernel.
1136     ; NOTE: A 13-byte buffer is mandatory, even if the string is
1137     ; known to be shorter.
1138     ;
1139     ; DS:SI -> input mangled file name
1140     ; ES:DI -> output buffer
1141     ;
1142     ; On return, DI points to the first byte after the output name,
1143     ; which is set to a null byte.
1144     ;
1145     unmangle_name:
1146     push si ; Save pointer to original name
1147     mov cx,8
1148     mov bp,di
1149     un_copy_body: lodsb
1150     call lower_case
1151     stosb
1152     cmp al,' '
1153     jbe un_cb_space
1154     mov bp,di ; Position of last nonblank+1
1155     un_cb_space: loop un_copy_body
1156     mov di,bp
1157     mov al,'.' ; Don't save
1158     stosb
1159     mov cx,3
1160     un_copy_ext: lodsb
1161     call lower_case
1162     stosb
1163     cmp al,' '
1164     jbe un_ce_space
1165     mov bp,di
1166     un_ce_space: loop un_copy_ext
1167     mov di,bp
1168     mov byte [es:di], 0
1169     pop si
1170     ret
1171    
1172     ;
1173     ; lower_case: Lower case a character in AL
1174     ;
1175     lower_case:
1176     cmp al,'A'
1177     jb lc_ret
1178     cmp al,'Z'
1179     ja lc_1
1180     or al,20h
1181     ret
1182     lc_1: cmp al,lcase_low
1183     jb lc_ret
1184     cmp al,lcase_high
1185     ja lc_ret
1186     push bx
1187     mov bx,lcase_tab-lcase_low
1188     cs xlatb
1189     pop bx
1190     lc_ret: ret
1191    
1192     ;
1193     ; getfssec_edx: Get multiple sectors from a file
1194     ;
1195     ; This routine makes sure the subtransfers do not cross a 64K boundary,
1196     ; and will correct the situation if it does, UNLESS *sectors* cross
1197     ; 64K boundaries.
1198     ;
1199     ; ES:BX -> Buffer
1200     ; EDX -> Current sector number
1201     ; CX -> Sector count (0FFFFh = until end of file)
1202     ; Must not exceed the ES segment
1203     ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1204     ; All arguments are advanced to reflect data read.
1205     ;
1206     getfssec_edx:
1207     push ebp
1208     push eax
1209     .getfragment:
1210     xor ebp,ebp ; Fragment sector count
1211     push edx ; Starting sector pointer
1212     .getseccnt:
1213     inc bp
1214     dec cx
1215     jz .do_read
1216     xor eax,eax
1217     mov ax,es
1218     shl ax,4
1219     add ax,bx ; Now AX = how far into 64K block we are
1220     not ax ; Bytes left in 64K block
1221     inc eax
1222     shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1223     cmp bp,ax
1224     jnb .do_read ; Unless there is at least 1 more sector room...
1225     mov eax,edx ; Current sector
1226     inc edx ; Predict it's the linearly next sector
1227     call nextsector
1228     jc .do_read
1229     cmp edx,eax ; Did it match?
1230     jz .getseccnt
1231     .do_read:
1232     pop eax ; Starting sector pointer
1233     call getlinsecsr
1234     lea eax,[eax+ebp-1] ; This is the last sector actually read
1235     shl bp,9
1236     add bx,bp ; Adjust buffer pointer
1237     call nextsector
1238     jc .eof
1239     mov edx,eax
1240     and cx,cx
1241     jnz .getfragment
1242     .done:
1243     pop eax
1244     pop ebp
1245     ret
1246     .eof:
1247     xor edx,edx
1248     stc
1249     jmp .done
1250    
1251     ;
1252     ; getfssec: Get multiple sectors from a file
1253     ;
1254     ; Same as above, except SI is a pointer to a open_file_t
1255     ;
1256     ; ES:BX -> Buffer
1257     ; DS:SI -> Pointer to open_file_t
1258     ; CX -> Sector count (0FFFFh = until end of file)
1259     ; Must not exceed the ES segment
1260     ; Returns CF=1 on EOF (not necessarily error)
1261     ; All arguments are advanced to reflect data read.
1262     ;
1263     getfssec:
1264     push edx
1265     movzx edx,cx
1266     cmp edx,[si+4]
1267     jbe .sizeok
1268     mov edx,[si+4]
1269     mov cx,dx
1270     .sizeok:
1271     sub [si+4],edx
1272     mov edx,[si]
1273     call getfssec_edx
1274     mov [si],edx
1275     pop edx
1276     ret
1277    
1278     ;
1279     ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1280     ; pointed at in the FAT tables. CF=0 on return if end of file.
1281     ;
1282     nextcluster:
1283     jmp strict short nextcluster_fat28 ; This gets patched
1284    
1285     nextcluster_fat12:
1286     push eax
1287     push edx
1288     push bx
1289     push cx
1290     push si
1291     mov edx,edi
1292     shr edi,1
1293     pushf ; Save the shifted-out LSB (=CF)
1294     add edx,edi
1295     mov eax,edx
1296     shr eax,9
1297     call getfatsector
1298     mov bx,dx
1299     and bx,1FFh
1300     mov cl,[gs:si+bx]
1301     inc edx
1302     mov eax,edx
1303     shr eax,9
1304     call getfatsector
1305     mov bx,dx
1306     and bx,1FFh
1307     mov ch,[gs:si+bx]
1308     popf
1309     jnc .even
1310     shr cx,4
1311     .even: and cx,0FFFh
1312     movzx edi,cx
1313     cmp di,0FF0h
1314     pop si
1315     pop cx
1316     pop bx
1317     pop edx
1318     pop eax
1319     ret
1320    
1321     ;
1322     ; FAT16 decoding routine.
1323     ;
1324     nextcluster_fat16:
1325     push eax
1326     push si
1327     push bx
1328     mov eax,edi
1329     shr eax,SECTOR_SHIFT-1
1330     call getfatsector
1331     mov bx,di
1332     add bx,bx
1333     and bx,1FEh
1334     movzx edi,word [gs:si+bx]
1335     cmp di,0FFF0h
1336     pop bx
1337     pop si
1338     pop eax
1339     ret
1340     ;
1341     ; FAT28 ("FAT32") decoding routine.
1342     ;
1343     nextcluster_fat28:
1344     push eax
1345     push si
1346     push bx
1347     mov eax,edi
1348     shr eax,SECTOR_SHIFT-2
1349     call getfatsector
1350     mov bx,di
1351     add bx,bx
1352     add bx,bx
1353     and bx,1FCh
1354     mov edi,dword [gs:si+bx]
1355     and edi,0FFFFFFFh ; 28 bits only
1356     cmp edi,0FFFFFF0h
1357     pop bx
1358     pop si
1359     pop eax
1360     ret
1361    
1362     ;
1363     ; nextsector: Given a sector in EAX on input, return the next sector
1364     ; of the same filesystem object, which may be the root
1365     ; directory or a cluster chain. Returns EOF.
1366     ;
1367     ; Assumes CS == DS.
1368     ;
1369     nextsector:
1370     push edi
1371     push edx
1372     mov edx,[DataArea]
1373     mov edi,eax
1374     sub edi,edx
1375     jae .isdata
1376    
1377     ; Root directory
1378     inc eax
1379     cmp eax,edx
1380     cmc
1381     jmp .done
1382    
1383     .isdata:
1384     not edi
1385     test edi,[ClustMask]
1386     jz .endcluster
1387    
1388     ; It's not the final sector in a cluster
1389     inc eax
1390     jmp .done
1391    
1392     .endcluster:
1393     push gs ; nextcluster trashes gs
1394     push cx
1395     not edi
1396     mov cl,[ClustShift]
1397     shr edi,cl
1398     add edi,2
1399    
1400     ; Now EDI contains the cluster number
1401     call nextcluster
1402     cmc
1403     jc .exit ; There isn't anything else...
1404    
1405     ; New cluster number now in EDI
1406     sub edi,2
1407     shl edi,cl ; CF <- 0, unless something is very wrong
1408     lea eax,[edi+edx]
1409     .exit:
1410     pop cx
1411     pop gs
1412     .done:
1413     pop edx
1414     pop edi
1415     ret
1416    
1417     ;
1418     ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1419     ; and return a pointer in GS:SI, loading it if needed.
1420     ;
1421     ; Assumes CS == DS.
1422     ;
1423     getfatsector:
1424     add eax,[FAT] ; FAT starting address
1425     jmp getcachesector
1426    
1427     ; -----------------------------------------------------------------------------
1428     ; Common modules
1429     ; -----------------------------------------------------------------------------
1430    
1431     %include "getc.inc" ; getc et al
1432     %include "conio.inc" ; Console I/O
1433     %include "writestr.inc" ; String output
1434     %include "parseconfig.inc" ; High-level config file handling
1435     %include "parsecmd.inc" ; Low-level config file handling
1436     %include "bcopy32.inc" ; 32-bit bcopy
1437     %include "loadhigh.inc" ; Load a file into high memory
1438     %include "font.inc" ; VGA font stuff
1439     %include "graphics.inc" ; VGA graphics
1440     %include "highmem.inc" ; High memory sizing
1441     %include "strcpy.inc" ; strcpy()
1442     %include "cache.inc" ; Metadata disk cache
1443    
1444     ; -----------------------------------------------------------------------------
1445     ; Begin data section
1446     ; -----------------------------------------------------------------------------
1447    
1448     section .data
1449     ;
1450     ; Lower-case table for codepage 865
1451     ;
1452     lcase_low equ 128
1453     lcase_high equ 165
1454     lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
1455     db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
1456     db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
1457     db 161, 162, 163, 164, 164
1458    
1459     copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1460     db CR, LF, 0
1461     boot_prompt db 'boot: ', 0
1462     wipe_char db BS, ' ', BS, 0
1463     err_notfound db 'Could not find kernel image: ',0
1464     err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1465     err_noram db 'It appears your computer has less than '
1466     asciidec dosram_k
1467     db 'K of low ("DOS")'
1468     db CR, LF
1469     db 'RAM. Linux needs at least this amount to boot. If you get'
1470     db CR, LF
1471     db 'this message in error, hold down the Ctrl key while'
1472     db CR, LF
1473     db 'booting, and I will take your word for it.', CR, LF, 0
1474     err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1475     err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1476     err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1477     err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1478     err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1479     err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1480     db CR, LF, 0
1481     err_notdos db ': attempted DOS system call', CR, LF, 0
1482     err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1483     err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1484     err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1485     db 'a key to continue.', CR, LF, 0
1486     ready_msg db 'Ready.', CR, LF, 0
1487     crlfloading_msg db CR, LF
1488     loading_msg db 'Loading ', 0
1489     dotdot_msg db '.'
1490     dot_msg db '.', 0
1491     aborted_msg db ' aborted.' ; Fall through to crlf_msg!
1492     crlf_msg db CR, LF
1493     null_msg db 0
1494     crff_msg db CR, FF, 0
1495     syslinux_cfg db 'SYSLINUXCFG' ; Mangled form
1496     ConfigName db 'syslinux.cfg',0 ; Unmangled form
1497     %if IS_MDSLINUX
1498     manifest db 'MANIFEST '
1499     %endif
1500     ;
1501     ; Command line options we'd like to take a look at
1502     ;
1503     ; mem= and vga= are handled as normal 32-bit integer values
1504     initrd_cmd db 'initrd='
1505     initrd_cmd_len equ 7
1506    
1507     ;
1508     ; Config file keyword table
1509     ;
1510     %include "keywords.inc"
1511    
1512     ;
1513     ; Extensions to search for (in *forward* order).
1514     ;
1515     exten_table: db 'CBT',0 ; COMBOOT (specific)
1516     db 'BSS',0 ; Boot Sector (add superblock)
1517     db 'BS ',0 ; Boot Sector
1518     db 'COM',0 ; COMBOOT (same as DOS)
1519     db 'C32',0 ; COM32
1520     exten_table_end:
1521     dd 0, 0 ; Need 8 null bytes here
1522    
1523     ;
1524     ; Misc initialized (data) variables
1525     ;
1526     %ifdef debug ; This code for debugging only
1527     debug_magic dw 0D00Dh ; Debug code sentinel
1528     %endif
1529    
1530     alignb 4, db 0
1531     BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1532     BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1533     BufSafeBytes dw trackbufsize ; = how many bytes?
1534     EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1535     %ifndef DEPEND
1536     %if ( trackbufsize % SECTOR_SIZE ) != 0
1537     %error trackbufsize must be a multiple of SECTOR_SIZE
1538     %endif
1539     %endif