Magellan Linux

Contents of /trunk/mkinitrd-magellan/isolinux/ldlinux.asm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 7 months ago) by niro
File size: 36902 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 ; -*- 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