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