Merge branch 'json' into libupload
[profile/ivi/syslinux.git] / core / ldlinux.asm
index c08799f..f62f55b 100644 (file)
 ;
 ; ****************************************************************************
 
-%ifndef IS_MDSLINUX
 %define IS_SYSLINUX 1
-%endif
 %include "head.inc"
 
 ;
 ; Some semi-configurable constants... change on your own risk.
 ;
 my_id          equ syslinux_id
-FILENAME_MAX_LG2 equ 6                 ; log2(Max filename size Including final null)
-FILENAME_MAX   equ (1<<FILENAME_MAX_LG2) ; Max mangled filename size
-NULLFILE       equ 0                   ; First char space == null filename
-NULLOFFSET     equ 0                   ; Position in which to look
-retry_count    equ 16                  ; How patient are we with the disk?
-%assign HIGHMEM_SLOP 0                 ; Avoid this much memory near the top
-LDLINUX_MAGIC  equ 0x3eb202fe          ; A random number to identify ourselves with
-
-MAX_OPEN_LG2   equ 6                   ; log2(Max number of open files)
-MAX_OPEN       equ (1 << MAX_OPEN_LG2)
-
-SECTOR_SHIFT   equ 9
-SECTOR_SIZE    equ (1 << SECTOR_SHIFT)
-
-DIRENT_SHIFT   equ 5
-DIRENT_SIZE    equ (1 << DIRENT_SHIFT)
-
-ROOT_DIR_WORD  equ 0x002F
-
-;
-; The following structure is used for "virtual kernels"; i.e. LILO-style
-; option labels.  The options we permit here are `kernel' and `append
-; Since there is no room in the bottom 64K for all of these, we
-; stick them in high memory and copy them down before we need them.
-;
-               struc vkernel
-vk_vname:      resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
-vk_rname:      resb FILENAME_MAX       ; Real name
-vk_appendlen:  resw 1
-vk_type:       resb 1                  ; Type of file
-               alignb 4
-vk_append:     resb max_cmd_len+1      ; Command line
-               alignb 4
-vk_end:                equ $                   ; Should be <= vk_size
-               endstruc
-
-;
-; File structure.  This holds the information for each currently open file.
-;
-               struc open_file_t
-file_sector    resd 1                  ; Sector pointer (0 = structure free)
-file_bytesleft resd 1                  ; Number of bytes left
-file_left      resd 1                  ; Number of sectors left
-               resd 1                  ; Unused
-               endstruc
-
-;
-; Structure for codepage files
-;
-               struc cp
-.magic         resd 2                  ; 8-byte magic number
-.reserved      resd 6                  ; Reserved for future use
-.uppercase     resb 256                ; Internal upper-case table
-.unicode       resw 256                ; Unicode matching table
-.unicode_alt   resw 256                ; Alternate Unicode matching table
-               endstruc
-
-%ifndef DEPEND
-%if (open_file_t_size & (open_file_t_size-1))
-%error "open_file_t is not a power of 2"
-%endif
-%endif
-
-; ---------------------------------------------------------------------------
-;   BEGIN CODE
-; ---------------------------------------------------------------------------
-
-;
-; Memory below this point is reserved for the BIOS and the MBR
-;
-               section .earlybss
-trackbufsize   equ 8192
-trackbuf       resb trackbufsize       ; Track buffer goes here
-               ; ends at 2800h
-
-               section .bss16
-               alignb 4
-FAT            resd 1                  ; Location of (first) FAT
-RootDirArea    resd 1                  ; Location of root directory area
-RootDir                resd 1                  ; Location of root directory proper
-DataArea       resd 1                  ; Location of data area
-RootDirSize    resd 1                  ; Root dir size in sectors
-TotalSectors   resd 1                  ; Total number of sectors
-ClustSize      resd 1                  ; Bytes/cluster
-ClustMask      resd 1                  ; Sectors/cluster - 1
-CopySuper      resb 1                  ; Distinguish .bs versus .bss
-ClustShift     resb 1                  ; Shift count for sectors/cluster
-ClustByteShift resb 1                  ; Shift count for bytes/cluster
-
-               alignb open_file_t_size
-Files          resb MAX_OPEN*open_file_t_size
-
-;
-; Common bootstrap code for disk-based derivatives
-;
-%include "diskstart.inc"
-
-;
-; Common initialization code
-;
-%include "init.inc"
-%include "cpuinit.inc"
-
-;
-; Compute some information about this filesystem.
-;
-
-; First, generate the map of regions
-genfatinfo:
-               mov edx,[bxSectors]
-               and dx,dx
-               jnz .have_secs
-               mov edx,[bsHugeSectors]
-.have_secs:
-               mov [TotalSectors],edx
-
-               mov eax,[bxResSectors]
-               mov [FAT],eax                   ; Beginning of FAT
-               mov edx,[bxFATsecs]
-               and dx,dx
-               jnz .have_fatsecs
-               mov edx,[bootsec+36]            ; FAT32 BPB_FATsz32
-.have_fatsecs:
-               imul edx,[bxFATs]
-               add eax,edx
-               mov [RootDirArea],eax           ; Beginning of root directory
-               mov [RootDir],eax               ; For FAT12/16 == root dir location
-
-               mov edx,[bxRootDirEnts]
-               add dx,SECTOR_SIZE/32-1
-               shr dx,SECTOR_SHIFT-5
-               mov [RootDirSize],edx
-               add eax,edx
-               mov [DataArea],eax              ; Beginning of data area
-
-; Next, generate a cluster size shift count and mask
-               mov eax,[bxSecPerClust]
-               bsr cx,ax
-               mov [ClustShift],cl
-               push cx
-               add cl,SECTOR_SHIFT
-               mov [ClustByteShift],cl
-               pop cx
-               dec ax
-               mov [ClustMask],eax
-               inc ax
-               shl eax,SECTOR_SHIFT
-               mov [ClustSize],eax
-
-;
-; FAT12, FAT16 or FAT28^H^H32?  This computation is fscking ridiculous.
-;
-getfattype:
-               mov eax,[TotalSectors]
-               sub eax,[DataArea]
-               shr eax,cl                      ; cl == ClustShift
-               mov cl,nextcluster_fat12-(nextcluster+2)
-               cmp eax,4085                    ; FAT12 limit
-               jb .setsize
-               mov cl,nextcluster_fat16-(nextcluster+2)
-               cmp eax,65525                   ; FAT16 limit
-               jb .setsize
-               ;
-               ; FAT32, root directory is a cluster chain
-               ;
-               mov cl,[ClustShift]
-               mov eax,[bootsec+44]            ; Root directory cluster
-               sub eax,2
-               shl eax,cl
-               add eax,[DataArea]
-               mov [RootDir],eax
-               mov cl,nextcluster_fat28-(nextcluster+2)
-               mov byte [SuperSize],superblock_len_fat32
-.setsize:
-               mov byte [nextcluster+1],cl
-
-
-;
-; Initialize the metadata cache
-;
-               call initcache
-
-;
-; Now, everything is "up and running"... patch kaboom for more
-; verbosity and using the full screen system
-;
-               ; E9 = JMP NEAR
-               mov di,kaboom.patch
-               mov al,0e9h
-               stosb
-               mov ax,kaboom2-2
-               sub ax,di
-               stosw
-
-;
-; Now we're all set to start with our *real* business. First load the
-; configuration file (if any) and parse it.
-;
-; In previous versions I avoided using 32-bit registers because of a
-; rumour some BIOSes clobbered the upper half of 32-bit registers at
-; random.  I figure, though, that if there are any of those still left
-; they probably won't be trying to install Linux on them...
-;
-; The code is still ripe with 16-bitisms, though.  Not worth the hassle
-; to take'm out.  In fact, we may want to put them back if we're going
-; to boot ELKS at some point.
-;
-
-;
-; Load configuration file
-;
-               mov si,config_name      ; Save configuration file name
-               mov di,ConfigName
-               call strcpy
-               mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
-
-               mov eax,[RootDir]       ; Make the root directory ...
-               mov [CurrentDir],eax    ; ... the current directory
-               mov di,syslinux_cfg1
-               push di
-               call open
-               pop di
-               jnz .config_open
-               mov di,syslinux_cfg2
-               push di
-               call open
-               pop di
-               jnz .config_open
-               mov di,syslinux_cfg3
-               push di
-               call open
-               pop di
-               jz no_config_file
-.config_open:
-               push si
-               mov si,di
-               push si
-               mov di,CurrentDirName
-                       ; This is inefficient as it will copy more than needed
-                       ;   but not by too much
-               call strcpy
-               mov ax,config_name      ;Cut it down
-               pop si
-               sub ax,si
-               mov di,CurrentDirName
-               add di,ax
-               mov byte [di],0
-               pop si
-               mov eax,[PrevDir]       ; Make the directory with syslinux.cfg ...
-               mov [CurrentDir],eax    ; ... the current directory
-
-;
-; Now we have the config file open.  Parse the config file and
-; run the user interface.
-;
-%include "ui.inc"
-
-;
-; allocate_file: Allocate a file structure
-;
-;              If successful:
-;                ZF set
-;                BX = file pointer
-;              In unsuccessful:
-;                ZF clear
-;
-allocate_file:
-               TRACER 'a'
-               push cx
-               mov bx,Files
-               mov cx,MAX_OPEN
-.check:                cmp dword [bx], byte 0
-               je .found
-               add bx,open_file_t_size         ; ZF = 0
-               loop .check
-               ; ZF = 0 if we fell out of the loop
-.found:                pop cx
-               ret
-
-;
-; alloc_fill_dir:
-;      Allocate then fill a file structure for a directory starting in
-;      sector EAX.
-;
-;      Assumes DS == ES == CS.
-;
-;           If successful:
-;              ZF clear
-;              SI      = file pointer
-;           If unsuccessful
-;              ZF set
-;              EAX clobbered
-;
-alloc_fill_dir:
-               push bx
-               call allocate_file
-               jnz .alloc_failure
-.found:
-               mov si,bx
-               mov [si+file_sector],eax        ; Current sector
-               mov dword [si+file_bytesleft],0 ; Current offset
-               mov [si+file_left],eax          ; Beginning sector
-               pop bx
-               ret
-
-.alloc_failure:
-               pop bx
-               xor eax,eax                     ; ZF <- 1
-               ret
-
-;
-; search_dos_dir:
-;           Search a specific directory for a pre-mangled filename in
-;            MangledBuf, in the directory starting in sector EAX.
-;
-;           NOTE: This file considers finding a zero-length file an
-;           error.  This is so we don't have to deal with that special
-;           case elsewhere in the program (most loops have the test
-;           at the end).
-;
-;           Assumes DS == ES == CS.
-;
-;           If successful:
-;              ZF clear
-;              SI      = file pointer
-;              EAX     = file length (MAY BE ZERO!)
-;              DL      = file attribute
-;               DH     = clobbered
-;           If unsuccessful
-;              ZF set
-;              EAX, SI, DX clobbered
-;
-
-search_dos_dir:
-               push bx
-               call allocate_file
-               jnz .alloc_failure
-
-               push cx
-               push gs
-               push es
-               push ds
-               pop es                          ; ES = DS
-
-               ; Compute the value of a possible VFAT longname
-               ; "last" entry (which, of course, comes first...)
-               push ax
-               push dx
-               mov ax,[NameLen]
-               add ax,12
-               xor dx,dx
-               mov cx,13
-               div cx
-               or al,40h
-               mov [VFATInit],al
-               mov [VFATNext],al
-               pop dx
-               pop ax
-
-.scansector:
-               ; EAX <- directory sector to scan
-               call getcachesector
-               ; GS:SI now points to this sector
-
-               mov cx,SECTOR_SIZE/32           ; 32 == directory entry size
-.scanentry:
-               cmp byte [gs:si],0
-               jz .failure                     ; Hit directory high water mark
-               cmp word [gs:si+11],0Fh         ; Long filename
-               jne .short_entry
-
-               ; Process a VFAT long entry
-               pusha
-               mov al,[gs:si]
-               cmp al,[VFATNext]
-               jne .not_us
-               mov bl,[gs:si+13]
-               test al,40h
-               jz .match_csum
-               ; Get the initial checksum value
-               mov [VFATCsum],bl
-               jmp .done_csum
-.match_csum:
-               cmp bl,[VFATCsum]
-               jne .not_us                     ; Checksum mismatch
-.done_csum:
-               and ax,03fh
-               jz .not_us                      ; Can't be zero...
-               dec ax
-               mov [VFATNext],al               ; Optimistically...
-               mov bx,ax
-               shl bx,2                        ; *4
-               add ax,bx                       ; *5
-               add bx,bx                       ; *8
-               add bx,ax                       ; *13
-               cmp bx,[NameLen]
-               jae .not_us
-               mov di,[NameStart]
-               inc si
-               mov cx,13
-.vfat_cmp:
-               gs lodsw
-               push bx
-               cmp bx,[NameLen]
-               jae .vfat_tail
-               movzx bx,byte [bx+di]
-               add bx,bx
-               cmp ax,[cp_unicode+bx]          ; Primary case
-               je .ucs_ok
-               cmp ax,[cp_unicode_alt+bx]      ; Alternate case
-               je .ucs_ok
-               ; Mismatch...
-               jmp .not_us_pop
-.vfat_tail:
-               ; *AT* the end we should have 0x0000, *AFTER* the end
-               ; we should have 0xFFFF...
-               je .vfat_end
-               inc ax                  ; 0xFFFF -> 0x0000
-.vfat_end:
-               and ax,ax
-               jnz .not_us_pop
-.ucs_ok:
-               pop bx
-               inc bx
-               cmp cx,3
-               je .vfat_adj_add2
-               cmp cx,9
-               jne .vfat_adj_add0
-.vfat_adj_add3:        inc si
-.vfat_adj_add2:        inc si
-.vfat_adj_add1:        inc si
-.vfat_adj_add0:
-               loop .vfat_cmp
-               ; Okay, if we got here we had a match on this particular
-               ; entry... live to see another one.
-               popa
-               jmp .next_entry
-
-.not_us_pop:
-               pop bx
-.not_us:
-               popa
-               jmp .nomatch
-
-.short_entry:
-               test byte [gs:si+11],8          ; Ignore volume labels
-               jnz .nomatch
-
-               cmp byte [VFATNext],0           ; Do we have a longname match?
-               jne .no_long_match
-
-               ; We already have a VFAT longname match, however,
-               ; the match is only valid if the checksum matches
-               push cx
-               push si
-               push ax
-               xor ax,ax
-               mov cx,11
-.csum_loop:
-               gs lodsb
-               ror ah,1
-               add ah,al
-               loop .csum_loop
-               cmp ah,[VFATCsum]
-               pop ax
-               pop si
-               pop cx
-               je .found                       ; Got a match on longname
-
-.no_long_match:                                        ; Look for a shortname match
-               push cx
-               push si
-               push di
-               mov di,MangledBuf
-               mov cx,11
-               gs repe cmpsb
-               pop di
-               pop si
-               pop cx
-               je .found
-.nomatch:
-               ; Reset the VFAT matching state machine
-               mov dh,[VFATInit]
-               mov [VFATNext],dh
-.next_entry:
-               add si,32
-               dec cx
-               jnz .scanentry
-
-               call nextsector
-               jnc .scansector                 ; CF is set if we're at end
-
-               ; If we get here, we failed
-.failure:
-               pop es
-               pop gs
-               pop cx
-.alloc_failure:
-               pop bx
-               xor eax,eax                     ; ZF <- 1
-               ret
-.found:
-               mov eax,[gs:si+28]              ; File size
-               add eax,SECTOR_SIZE-1
-               shr eax,SECTOR_SHIFT
-               mov [bx+4],eax                  ; Sector count
-
-               mov cl,[ClustShift]
-               mov dx,[gs:si+20]               ; High cluster word
-               shl edx,16
-               mov dx,[gs:si+26]               ; Low cluster word
-               sub edx,2
-               shl edx,cl
-               add edx,[DataArea]
-               mov [bx],edx                    ; Starting sector
-
-               mov eax,[gs:si+28]              ; File length again
-               mov dl,[gs:si+11]               ; File attribute
-               mov si,bx                       ; File pointer...
-               and si,si                       ; ZF <- 0
-
-               pop es
-               pop gs
-               pop cx
-               pop bx
-               ret
-
-               section .data16
-               alignz 4
-               ; Note: we have no use of the first 32 bytes (header),
-               ; nor of the folloing 32 bytes (case mapping of control
-               ; characters), as long as we adjust the offsets appropriately.
-codepage       equ $-(32+32)
-codepage_data: incbin "codepage.cp",32+32
-cp_uppercase   equ     codepage+cp.uppercase
-cp_unicode     equ     codepage+cp.unicode
-cp_unicode_alt equ     codepage+cp.unicode_alt
-codepage_end   equ $
-
-               section .text16
-;
-; Input:  UCS-2 character in AX
-; Output: Single byte character in AL, ZF = 1
-;         On failure, returns ZF = 0
-;
-ucs2_to_cp:
-               push es
-               push di
-               push cx
-               push cs
-               pop es
-               mov di,cp_unicode
-               mov cx,512
-               repne scasw
-               xchg ax,cx
-               pop cx
-               pop di
-               pop es
-               not ax          ; Doesn't change the flags!
-               ret
-
-               section .bss16
-VFATInit       resb 1
-VFATNext       resb 1
-VFATCsum       resb 1
-
-               section .text16
-;
-; close_file:
-;           Deallocates a file structure (pointer in SI)
-;           Assumes CS == DS.
-;
-close_file:
-               and si,si
-               jz .closed
-               mov dword [si],0                ; First dword == file_sector
-               xor si,si
-.closed:       ret
-
-;
-; close_dir:
-;           Deallocates a directory structure (pointer in SI)
-;           Assumes CS == DS.
-;
-close_dir:
-               and si,si
-               jz .closed
-               mov dword [si],0                ; First dword == file_sector
-               xor si,si
-.closed:       ret
-
-;
-; searchdir:
-;
-;      Open a file
-;
-;           On entry:
-;              DS:DI   = filename
-;           If successful:
-;              ZF clear
-;              SI              = file pointer
-;              EAX             = file length in bytes
-;           If unsuccessful
-;              ZF set
-;
-; Assumes CS == DS == ES, and trashes BX and CX.
-;
-searchdir:
-               mov eax,[CurrentDir]
-               cmp byte [di],'/'       ; Root directory?
-               jne .notroot
-               mov eax,[RootDir]
-               inc di
-.notroot:
-
-.pathwalk:
-               push eax                ; <A> Current directory sector
-               mov si,di
-.findend:
-               lodsb
-               cmp al,' '
-               jbe .endpath
-               cmp al,'/'
-               jne .findend
-.endpath:
-               xchg si,di              ; GRC: si begin; di end[ /]+1
-               pop eax                 ; <A> Current directory sector
-
-                       ; GRC Here I need to check if di-1 = si which signifies
-                       ;       we have the desired directory in EAX
-                       ; What about where the file name = "."; later
-               mov dx,di
-               dec dx
-               cmp dx,si
-               jz .founddir
-
-               mov [PrevDir],eax       ; Remember last directory searched
-
-               push di
-               call mangle_dos_name    ; MangledBuf <- component
-               call search_dos_dir
-               pop di
-               jz .notfound            ; Pathname component missing
-
-               cmp byte [di-1],'/'     ; Do we expect a directory
-               je .isdir
-
-               ; Otherwise, it should be a file
-.isfile:
-               test dl,18h             ; Subdirectory|Volume Label
-               jnz .badfile            ; If not a file, it's a bad thing
-
-               ; SI and EAX are already set
-               mov [si+file_bytesleft],eax
-               push eax
-               add eax,SECTOR_SIZE-1
-               shr eax,SECTOR_SHIFT
-               mov [si+file_left],eax  ; Sectors left
-               pop eax
-               and eax,eax             ; EAX != 0
-               jz .badfile
-               ret                     ; Done!
-
-               ; If we expected a directory, it better be one...
-.isdir:
-               test dl,10h             ; Subdirectory
-               jz .badfile
-
-               xor eax,eax
-               xchg eax,[si+file_sector] ; Get sector number and free file structure
-               jmp .pathwalk           ; Walk the next bit of the path
-
-               ; Found the desired directory; ZF set but EAX not 0
-.founddir:
-               ret
-
-.badfile:
-               xor eax,eax
-               mov [si],eax            ; Free file structure
-
-.notfound:
-               xor eax,eax             ; Zero out EAX
-               ret
-
-;
-; readdir: Read one file from a directory
-;
-;      ES:DI   -> String buffer (filename)
-;      DS:SI   -> Pointer to open_file_t
-;      DS      Must be the SYSLINUX Data Segment
-;
-;      Returns the file's name in the filename string buffer
-;      EAX returns the file size
-;      EBX returns the beginning sector (currently without offsetting)
-;      DL returns the file type
-;      The directory handle's data is incremented to reflect a name read.
-;
-readdir:
-               push ecx
-               push bp         ; Using bp to transfer between segment registers
-               push si
-               push es
-               push fs         ; Using fs to store the current es (from COMBOOT)
-               push gs
-               mov bp,es
-               mov fs,bp
-               cmp si,0
-               jz .fail
-.load_handle:
-               mov eax,[ds:si+file_sector]     ; Current sector
-               mov ebx,[ds:si+file_bytesleft]  ; Current offset
-               cmp eax,0
-               jz .fail
-.fetch_cache:
-               call getcachesector
-.move_current:
-               add si,bx       ; Resume last position in sector
-               mov ecx,SECTOR_SIZE     ; 0 out high part
-               sub cx,bx
-               shr cx,5        ; Number of entries left
-.scanentry:
-               cmp byte [gs:si],0
-               jz .fail
-               cmp word [gs:si+11],0Fh         ; Long filename
-               jne .short_entry
-
-.vfat_entry:
-               push eax
-               push ecx
-               push si
-               push di
-.vfat_ln_info:         ; Get info about the line that we're on
-               mov al,[gs:si]
-               test al,40h
-               jz .vfat_tail_ln
-               and al,03Fh
-               mov ah,1        ; On beginning line
-               jmp .vfat_ck_ln
-
-.vfat_tail_ln: ; VFAT tail line processing (later in VFAT, head in name)
-               test al,80h     ; Invalid data?
-               jnz .vfat_abort
-               mov ah,0        ; Not on beginning line
-               cmp dl,al
-               jne .vfat_abort ; Is this the entry we need?
-               mov bl,[gs:si+13]
-               cmp bl,[VFATCsum]
-               je .vfat_cp_ln
-               jmp .vfat_abort
-
-.vfat_ck_ln:           ; Load this line's VFAT CheckSum
-               mov bl,[gs:si+13]
-               mov [VFATCsum],bl
-.vfat_cp_ln:           ; Copy VFAT line
-               dec al          ; Store the next line we need
-               mov dx,ax       ; Use DX to store the progress
-               mov cx,13       ; 13 characters per VFAT DIRENT
-               cbw             ; AH <- 0
-               mul cl          ; Offset for DI
-               add di,ax       ; Increment DI
-               inc si          ; Align to the real characters
-.vfat_cp_chr:
-               gs lodsw        ; Unicode here!!
-               call ucs2_to_cp ; Convert to local codepage
-               jnz .vfat_abort ; Use short name if character not on codepage
-               stosb           ; CAN NOT OVERRIDE es
-               cmp al,0
-               jz .vfat_find_next ; Null-terminated string; don't process more
-               cmp cx,3
-               je .vfat_adj_add2
-               cmp cx,9
-               jne .vfat_adj_add0
-.vfat_adj_add3:        inc si
-.vfat_adj_add2:        inc si
-.vfat_adj_add1:        inc si
-.vfat_adj_add0:
-               loop .vfat_cp_chr
-               cmp dh,1        ; Is this the first round?
-               jnz .vfat_find_next
-.vfat_null_term:       ; Need to null-terminate if first line as we rolled over the end
-               mov al,0
-               stosb
-
-.vfat_find_next:       ;Find the next part of the name
-               pop di
-               pop si
-               pop ecx
-               pop eax
-               cmp dl,0
-               jz .vfat_find_info      ; We're done with the name
-               add si,DIRENT_SIZE
-               dec cx
-               jnz .vfat_entry
-               call nextsector
-               jnc .vfat_entry                 ; CF is set if we're at end
-               jmp .fail
-.vfat_find_info:       ; Fetch next entry for the size/"INode"
-               add si,DIRENT_SIZE
-               dec cx
-               jnz .get_info
-               call nextsector
-               jnc .get_info                   ; CF is set if we're at end
-               jmp .fail
-.vfat_abort:           ; Something went wrong, skip
-               pop di
-               pop si
-               pop ecx
-               pop eax
-               jmp .skip_entry
-
-.short_entry:
-               test byte [gs:si+11],8          ; Ignore volume labels //HERE
-               jnz .skip_entry
-               mov edx,eax             ;Save current sector
-               push cx
-               push si
-               push di
-               mov cx,8
-.short_file:
-               gs lodsb
-               cmp al,'.'
-               jz .short_dot
-.short_file_loop:
-               cmp al,' '
-               jz .short_skip_bs
-               stosb
-               loop .short_file_loop
-               jmp .short_period
-.short_skip_bs:                ; skip blank spaces in FILENAME (before EXT)
-               add si,cx
-               dec si
-.short_period:
-               mov al,'.'
-               stosb
-               mov cx,3
-.short_ext:
-               gs lodsb
-               cmp al,' '
-               jz .short_done
-               stosb
-               loop .short_ext
-               jmp .short_done
-.short_dot:
-               stosb
-               gs lodsb
-               cmp al,' '
-               jz .short_done
-               stosb
-.short_done:
-               mov al,0        ; Null-terminate the short strings
-               stosb
-               pop di
-               pop si
-               pop cx
-               mov eax,edx
-.get_info:
-               mov ebx,[gs:si+28]      ; length
-               mov dl,[gs:si+11]       ; type
-.next_entry:
-               add si,DIRENT_SIZE
-               dec cx
-               jnz .store_offset
-               call nextsector
-               jnc .store_sect                 ; CF is set if we're at end
-               jmp .fail
-
-.skip_entry:
-               add si,DIRENT_SIZE
-               dec cx
-               jnz .scanentry
-               call nextsector
-               jnc .scanentry                  ; CF is set if we're at end
-               jmp .fail
-
-.store_sect:
-               pop gs
-               pop fs
-               pop es
-               pop si
-               mov [ds:si+file_sector],eax
-               mov eax,0       ; Now at beginning of new sector
-               jmp .success
-
-.store_offset:
-               pop gs
-               pop fs
-               pop es
-               pop si          ; cx=num remain; SECTOR_SIZE-(cx*32)=cur pos
-               shl ecx,DIRENT_SHIFT
-               mov eax,SECTOR_SIZE
-               sub eax,ecx
-               and eax,0ffffh
-
-.success:
-               mov [ds:si+file_bytesleft],eax
-               ; "INode" number = ((CurSector-RootSector)*SECTOR_SIZE + Offset)/DIRENT_SIZE)
-               mov ecx,eax
-               mov eax,[ds:si+file_sector]
-               sub eax,[RootDir]
-               shl eax,SECTOR_SHIFT
-               add eax,ecx
-               shr eax,DIRENT_SHIFT
-               dec eax
-               xchg eax,ebx    ; -> EBX=INode, EAX=FileSize
-               jmp .done
-
-.fail:
-               pop gs
-               pop fs
-               pop es
-               pop si
-               call close_dir
-               xor eax,eax
-               stc
-.done:
-               pop bp
-               pop ecx
-.end:
-               ret
-
-               section .bss16
-               alignb 4
-PrevDir                resd 1                  ; Last scanned directory
-
-               section .text16
-
-;
-;
-; kaboom2: once everything is loaded, replace the part of kaboom
-;         starting with "kaboom.patch" with this part
-
-kaboom2:
-               mov si,err_bootfailed
-               call writestr
-               cmp byte [kaboom.again+1],18h   ; INT 18h version?
-               je .int18
-               call getchar
-               call vgaclearmode
-               int 19h                 ; And try once more to boot...
-.norge:                jmp short .norge        ; If int 19h returned; this is the end
-.int18:
-               call vgaclearmode
-               int 18h
-.noreg:                jmp short .noreg        ; Nynorsk
-
-;
-; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
-;             to by ES:DI; ends on encountering any whitespace.
-;             DI is preserved.
-;
-;             This verifies that a filename is < FILENAME_MAX characters,
-;             doesn't contain whitespace, zero-pads the output buffer,
-;             and removes trailing dots and redundant slashes, plus changes
-;              backslashes to forward slashes,
-;             so "repe cmpsb" can do a compare, and the path-searching routine
-;              gets a bit of an easier job.
-;
-;
-mangle_name:
-               push di
-               push bx
-               xor ax,ax
-               mov cx,FILENAME_MAX-1
-               mov bx,di
-
-.mn_loop:
-               lodsb
-               cmp al,' '                      ; If control or space, end
-               jna .mn_end
-               cmp al,'\'                      ; Backslash?
-               jne .mn_not_bs
-               mov al,'/'                      ; Change to forward slash
-.mn_not_bs:
-               cmp al,ah                       ; Repeated slash?
-               je .mn_skip
-               xor ah,ah
-               cmp al,'/'
-               jne .mn_ok
-               mov ah,al
-.mn_ok         stosb
-.mn_skip:      loop .mn_loop
-.mn_end:
-               cmp bx,di                       ; At the beginning of the buffer?
-               jbe .mn_zero
-               cmp byte [es:di-1],'.'          ; Terminal dot?
-               je .mn_kill
-               cmp byte [es:di-1],'/'          ; Terminal slash?
-               jne .mn_zero
-.mn_kill:      dec di                          ; If so, remove it
-               inc cx
-               jmp short .mn_end
-.mn_zero:
-               inc cx                          ; At least one null byte
-               xor ax,ax                       ; Zero-fill name
-               rep stosb
-               pop bx
-               pop di
-               ret                             ; Done
-
-;
-; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
-;                filename to the conventional representation.  This is needed
-;                for the BOOT_IMAGE= parameter for the kernel.
-;                NOTE: A 13-byte buffer is mandatory, even if the string is
-;                known to be shorter.
-;
-;                DS:SI -> input mangled file name
-;                ES:DI -> output buffer
-;
-;                On return, DI points to the first byte after the output name,
-;                which is set to a null byte.
-;
-unmangle_name: call strcpy
-               dec di                          ; Point to final null byte
-               ret
-
-;
-; mangle_dos_name:
-;              Mangle a DOS filename component pointed to by DS:SI
-;              into [MangledBuf]; ends on encountering any whitespace or
-;              slash.
-;
-;              WARNING: saves pointers into the buffer for longname
-;              matches!
-;
-;              Assumes CS == DS == ES.
-;
-
-mangle_dos_name:
-               pusha
-               mov di,MangledBuf
-               mov [NameStart],si
-
-               mov cx,11                       ; # of bytes to write
-               mov bx,cp_uppercase             ; Case-conversion table
-.loop:
-               lodsb
-               cmp al,' '                      ; If control or space, end
-               jna .end
-               cmp al,'/'                      ; Slash, too
-               je .end
-               cmp al,'.'                      ; Period -> space-fill
-               je .is_period
-               xlatb                           ; Convert to upper case
-               mov ah,cl                       ; If the first byte (only!)...
-               cmp ax,0BE5h                    ; ... equals E5 hex ...
-               jne .charok
-               mov al,05h                      ; ... change it to 05 hex
-.charok:       stosb
-               loop .loop                      ; Don't continue if too long
-               ; Find the end for the benefit of longname search
-.find_end:
-               lodsb
-               cmp al,' '
-               jna .end
-               cmp al,'/'
-               jne .find_end
-.end:
-               dec si
-               sub si,[NameStart]
-               mov [NameLen],si
-               mov al,' '                      ; Space-fill name
-               rep stosb                       ; Doesn't do anything if CX=0
-               popa
-               ret                             ; Done
-
-.is_period:
-               mov al,' '                      ; We need to space-fill
-.period_loop:  cmp cx,3                        ; If <= 3 characters left
-               jbe .loop                       ; Just ignore it
-               stosb                           ; Otherwise, write a space
-               loop .period_loop               ; Dec CX and *always* jump
-
-               section .bss16
-               alignb 2
-NameStart      resw 1
-NameLen                resw 1
-MangledBuf     resb 11
-
-               section .text16
-;
-; getfssec_edx: Get multiple sectors from a file
-;
-;      This routine makes sure the subtransfers do not cross a 64K boundary,
-;      and will correct the situation if it does, UNLESS *sectors* cross
-;      64K boundaries.
-;
-;      ES:BX   -> Buffer
-;      EDX     -> Current sector number
-;      CX      -> Sector count (0FFFFh = until end of file)
-;                  Must not exceed the ES segment
-;      Returns EDX=0, CF=1 on EOF (not necessarily error)
-;      All arguments are advanced to reflect data read.
-;
-getfssec_edx:
-               push ebp
-               push eax
-.getfragment:
-               xor ebp,ebp                     ; Fragment sector count
-               push edx                        ; Starting sector pointer
-.getseccnt:
-               inc bp
-               dec cx
-               jz .do_read
-               xor eax,eax
-               mov ax,es
-               shl ax,4
-               add ax,bx                       ; Now AX = how far into 64K block we are
-               not ax                          ; Bytes left in 64K block
-               inc eax
-               shr eax,SECTOR_SHIFT            ; Sectors left in 64K block
-               cmp bp,ax
-               jnb .do_read                    ; Unless there is at least 1 more sector room...
-               mov eax,edx                     ; Current sector
-               inc edx                         ; Predict it's the linearly next sector
-               call nextsector
-               jc .do_read
-               cmp edx,eax                     ; Did it match?
-               jz .getseccnt
-.do_read:
-               pop eax                         ; Starting sector pointer
-               call getlinsecsr
-               lea eax,[eax+ebp-1]             ; This is the last sector actually read
-               shl bp,9
-               add bx,bp                       ; Adjust buffer pointer
-               call nextsector
-               jc .eof
-               mov edx,eax
-               and cx,cx
-               jnz .getfragment
-.done:
-               pop eax
-               pop ebp
-               ret
-.eof:
-               xor edx,edx
-               stc
-               jmp .done
-
-;
-; getfssec: Get multiple sectors from a file
-;
-;      Same as above, except SI is a pointer to a open_file_t
-;
-;      ES:BX   -> Buffer
-;      DS:SI   -> Pointer to open_file_t
-;      CX      -> Sector count (0FFFFh = until end of file)
-;                  Must not exceed the ES segment
-;      Returns CF=1 on EOF (not necessarily error)
-;      ECX returns number of bytes read.
-;      All arguments are advanced to reflect data read.
-;
-getfssec:
-               push edx
-               movzx edx,cx
-               push edx                ; Zero-extended CX
-               cmp edx,[si+file_left]
-               jbe .sizeok
-               mov edx,[si+file_left]
-               mov cx,dx
-.sizeok:
-               sub [si+file_left],edx
-               mov edx,[si+file_sector]
-               call getfssec_edx
-               mov [si+file_sector],edx
-               pop ecx                 ; Sectors requested read
-               shl ecx,SECTOR_SHIFT
-               cmp ecx,[si+file_bytesleft]
-               ja .eof
-.noteof:
-               sub [si+file_bytesleft],ecx     ; CF <- 0
-               pop edx
-               ret
-.eof:
-               mov ecx,[si+file_bytesleft]
-               call close_file
-               pop edx
-               stc
-               ret
-
-;
-; nextcluster: Advance a cluster pointer in EDI to the next cluster
-;             pointed at in the FAT tables.  CF=0 on return if end of file.
-;
-nextcluster:
-               jmp strict short nextcluster_fat28      ; This gets patched
-
-nextcluster_fat12:
-               push eax
-               push edx
-               push bx
-               push cx
-               push si
-               mov edx,edi
-               shr edi,1
-               pushf                   ; Save the shifted-out LSB (=CF)
-               add edx,edi
-               mov eax,edx
-               shr eax,9
-               call getfatsector
-               mov bx,dx
-               and bx,1FFh
-               mov cl,[gs:si+bx]
-               inc edx
-               mov eax,edx
-               shr eax,9
-               call getfatsector
-               mov bx,dx
-               and bx,1FFh
-               mov ch,[gs:si+bx]
-               popf
-               jnc .even
-               shr cx,4
-.even:         and cx,0FFFh
-               movzx edi,cx
-               cmp di,0FF0h
-               pop si
-               pop cx
-               pop bx
-               pop edx
-               pop eax
-               ret
-
-;
-; FAT16 decoding routine.
-;
-nextcluster_fat16:
-               push eax
-               push si
-               push bx
-               mov eax,edi
-               shr eax,SECTOR_SHIFT-1
-               call getfatsector
-               mov bx,di
-               add bx,bx
-               and bx,1FEh
-               movzx edi,word [gs:si+bx]
-               cmp di,0FFF0h
-               pop bx
-               pop si
-               pop eax
-               ret
-;
-; FAT28 ("FAT32") decoding routine.
-;
-nextcluster_fat28:
-               push eax
-               push si
-               push bx
-               mov eax,edi
-               shr eax,SECTOR_SHIFT-2
-               call getfatsector
-               mov bx,di
-               add bx,bx
-               add bx,bx
-               and bx,1FCh
-               mov edi,dword [gs:si+bx]
-               and edi,0FFFFFFFh       ; 28 bits only
-               cmp edi,0FFFFFF0h
-               pop bx
-               pop si
-               pop eax
-               ret
-
-;
-; nextsector:  Given a sector in EAX on input, return the next sector
-;              of the same filesystem object, which may be the root
-;              directory or a cluster chain.  Returns  EOF.
-;
-;              Assumes CS == DS.
-;
-nextsector:
-               push edi
-               push edx
-               mov edx,[DataArea]
-               mov edi,eax
-               sub edi,edx
-               jae .isdata
-
-               ; Root directory
-               inc eax
-               cmp eax,edx
-               cmc
-               jmp .done
-
-.isdata:
-               not edi
-               test edi,[ClustMask]
-               jz .endcluster
-
-               ; It's not the final sector in a cluster
-               inc eax
-               jmp .done
-
-.endcluster:
-               push gs                 ; nextcluster trashes gs
-               push cx
-               not edi
-               mov cl,[ClustShift]
-               shr edi,cl
-               add edi,2
-
-               ; Now EDI contains the cluster number
-               call nextcluster
-               cmc
-               jc .exit                ; There isn't anything else...
-
-               ; New cluster number now in EDI
-               sub edi,2
-               shl edi,cl              ; CF <- 0, unless something is very wrong
-               lea eax,[edi+edx]
-.exit:
-               pop cx
-               pop gs
-.done:
-               pop edx
-               pop edi
-               ret
-
-;
-; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
-;              and return a pointer in GS:SI, loading it if needed.
-;
-;              Assumes CS == DS.
-;
-getfatsector:
-               add eax,[FAT]           ; FAT starting address
-               jmp getcachesector
-
-; -----------------------------------------------------------------------------
-;  Common modules
-; -----------------------------------------------------------------------------
-
-%include "common.inc"          ; Universal modules
-%include "plaincon.inc"                ; writechr
-%include "writestr.inc"                ; String output
-%include "writehex.inc"                ; Hexadecimal output
-%include "cache.inc"           ; Metadata disk cache
-%include "localboot.inc"       ; Disk-based local boot
-
-; -----------------------------------------------------------------------------
-;  Begin data section
-; -----------------------------------------------------------------------------
-
-               section .data16
-copyright_str   db ' Copyright (C) 1994-'
-               asciidec YEAR
-               db ' H. Peter Anvin et al', CR, LF, 0
-err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
-               db 'a key to continue.', CR, LF, 0
-syslinux_cfg1  db '/boot'                      ; /boot/syslinux/syslinux.cfg
-syslinux_cfg2  db '/syslinux'                  ; /syslinux/syslinux.cfg
-syslinux_cfg3  db '/'                          ; /syslinux.cfg
-config_name    db 'syslinux.cfg', 0            ; syslinux.cfg
-
-;
-; Config file keyword table
-;
-%include "keywords.inc"
-
-;
-; Extensions to search for (in *forward* order).
-;
-exten_table:   db '.cbt'               ; COMBOOT (specific)
-               db '.bss'               ; Boot Sector (add superblock)
-               db '.bs', 0             ; Boot Sector
-               db '.com'               ; COMBOOT (same as DOS)
-               db '.c32'               ; COM32
-exten_table_end:
-               dd 0, 0                 ; Need 8 null bytes here
-
-;
-; Misc initialized (data) variables
-;
-%ifdef debug                           ; This code for debugging only
-debug_magic    dw 0D00Dh               ; Debug code sentinel
-%endif
 
+               section .rodata
                alignz 4
-BufSafe                dw trackbufsize/SECTOR_SIZE     ; Clusters we can load into trackbuf
-BufSafeBytes   dw trackbufsize         ; = how many bytes?
-%ifndef DEPEND
-%if ( trackbufsize % SECTOR_SIZE ) != 0
-%error trackbufsize must be a multiple of SECTOR_SIZE
-%endif
-%endif
+ROOT_FS_OPS:
+               extern vfat_fs_ops
+               dd vfat_fs_ops
+               extern ext2_fs_ops
+               dd ext2_fs_ops
+               extern btrfs_fs_ops
+               dd btrfs_fs_ops
+               dd 0
+
+%include "diskfs.inc"