Core:ISOLINUX: convert the isolinux.asm to C
authorLiu Aleaxander <Aleaxander@gmail.com>
Sun, 21 Jun 2009 06:59:46 +0000 (14:59 +0800)
committerLiu Aleaxander <Aleaxander@gmail.com>
Sun, 21 Jun 2009 06:59:46 +0000 (14:59 +0800)
core/Makefile
core/disk.c
core/diskstart.inc
core/fs.c
core/include/core.h
core/include/fs.h
core/include/iso9660_fs.h [new file with mode: 0644]
core/iso9660.c [new file with mode: 0644]
core/isolinux.asm

index c41b423..0f257f1 100644 (file)
@@ -33,7 +33,8 @@ CODEPAGE = cp865
 
 # The targets to build in this directory...
 BTARGET  = kwdhash.gen \
-          extlinux.bin extlinux.bss extlinux.sys
+          extlinux.bin extlinux.bss extlinux.sys \
+          isolinux.bin isolinux-debug.bin
 
 # All primary source files for the main syslinux files
 NASMSRC         := $(wildcard *.asm)
index 8ec880c..69a9c0b 100644 (file)
@@ -6,7 +6,7 @@
 void read_sectors(char *buf, sector_t sector_num, int sectors)
 {
     com32sys_t regs;
-    static __lowmem char low_buf[65536]; 
+    //static __lowmem char low_buf[65536]; 
     /* for safe, we use buf + (sectors << SECTOR_SHIFT) here */
     int high_addr = (buf + (sectors << SECTOR_SHIFT)) > (char *)0x100000;
         
@@ -15,17 +15,17 @@ void read_sectors(char *buf, sector_t sector_num, int sectors)
     regs.ebp.l = sectors;
     
     if (high_addr) {
-        regs.es = SEG(low_buf);
-        regs.ebx.w[0] = OFFS(low_buf);
+        regs.es = SEG(core_xfer_buf);
+        regs.ebx.w[0] = OFFS(core_xfer_buf);
     } else {
         regs.es = SEG(buf);
-        regs.ebx.w[0] = OFFS(buf);
+        regs.ebx.w[0] = OFFS(core_xfer_buf);
     }
 
     call16(getlinsec, &regs, NULL);
 
     if (high_addr)
-        memcpy(buf, low_buf, sectors << SECTOR_SHIFT);
+        memcpy(buf, core_xfer_buf, sectors << SECTOR_SHIFT);
 }
 
 
index a08aa28..3dc8f8a 100644 (file)
@@ -729,6 +729,7 @@ expand_super:
              mov eax,iso_fs_ops
  %endif
              mov dl,[DriveNumber]
+               mov dh,0               ; it's a disk not cdrom
              mov ecx,[bsHidden]
              mov ebx,[bsHidden+4]
 %endif
index 617e3e5..5dc767a 100644 (file)
--- a/core/fs.c
+++ b/core/fs.c
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <stdbool.h>
 #include <string.h>
 #include "fs.h"
 #include "cache.h"
@@ -105,30 +106,24 @@ uint8_t detect_edd(uint8_t device_num)
 /* 
  * initialize the device structure 
  */
-void device_init(struct device *dev, uint8_t device_num, sector_t offset)
+void device_init(struct device *dev, uint8_t device_num, 
+                 bool cdrom, sector_t offset)
 {
     dev->device_number = device_num;
     dev->part_start = offset;
 
     dev->type = detect_edd(device_num);
         
-    /* 
-     * check if we use cache or not, for now I just know ISO fs 
-     * does not use the cache, and I hope the USE_CACHE can detect
-     * it correctly.
-     *
-     */    
-    if ( USE_CACHE(dev->device_number) ) {
+    if (!cdrom) {
         /* I can't use __lowmem here, 'cause it will cause the error:
-           "auxseg/lowmem region collides with xfer_buf_seg" */
-        //static __lowmem char cache_buf[65536];
+           "auxseg/lowmem region collides with xfer_buf_seg"
+           static __lowmem char cache_buf[65536];
+        */
         dev->cache_data = core_cache_buf;
         dev->cache_size = sizeof core_cache_buf;
     } else 
         dev->cache_data = NULL;
-
-    /* I just considered the floppy and disk now */
-    dev->read_sectors = read_sectors;
 }
 
 
@@ -156,7 +151,7 @@ void fs_init(com32sys_t *regs)
     int blk_shift;
     struct fs_ops *ops = (struct fs_ops*)regs->eax.l;
     
-    device_init(&dev, regs->edx.b[0], regs->ecx.l);
+    device_init(&dev, regs->edx.b[0], regs->edx.b[1], regs->ecx.l);
     
     /* set up the fs stucture */    
     fs.fs_name = ops->fs_name;
index 574fd7a..f7a7262 100644 (file)
@@ -11,7 +11,7 @@ extern char CurrentDirName[];
 extern char ConfigName[];
 
 
-/* diskstart.inc */
+/* diskstart.inc isolinux.asm*/
 extern void getlinsec(void);
 
 /* getc.inc */
index 0cb1bfc..208b22d 100644 (file)
@@ -5,10 +5,6 @@
 #include "core.h"
 #include "disk.h"
 
-/* I don't know it's right or not */
-#define USE_CACHE(device_num) (device_num >= 0x00 && device_num < 0xfe)
-
-
 struct fs_info {
     char *fs_name;
     struct fs_ops *fs_ops;
diff --git a/core/include/iso9660_fs.h b/core/include/iso9660_fs.h
new file mode 100644 (file)
index 0000000..ca123b1
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef ISO9660_FS_H
+#define ISO9660_FS_H
+
+#include <stdint.h>
+
+struct iso_dir_entry {
+        uint8_t length;                         /* 00 */
+        uint8_t ext_attr_length;                /* 01 */    
+        uint8_t extent[8];                      /* 02 */    
+        uint8_t size[8];                        /* 0a */  
+        uint8_t date[7];                        /* 12 */
+        uint8_t flags;                          /* 19 */
+        uint8_t file_unit_size;                 /* 1a */
+        uint8_t interleave;                     /* 1b */
+        uint8_t volume_sequence_number[4];      /* 1c */
+        uint8_t name_len;                       /* 20 */
+        //uint8_t name[];                         /* 21 */
+};
+
+
+#endif /* iso9660_fs.h */
diff --git a/core/iso9660.c b/core/iso9660.c
new file mode 100644 (file)
index 0000000..267b8cd
--- /dev/null
@@ -0,0 +1,580 @@
+#include <stdio.h>
+#include <string.h>
+//#include "cache.h"
+#include "core.h"
+#include "disk.h"
+#include "iso9660_fs.h"
+#include "fs.h"
+
+#define DEBUG 1
+
+#define FILENAME_MAX_LG2 8
+#define FILENAME_MAX     (1 << FILENAME_MAX_LG2)
+#define MAX_OPEN_LG2     6
+#define MAX_OPEN         (1 << MAX_OPEN_LG2)
+#define ISO_SECTOR_SHIFT 11
+#define ISO_SECTOR_SIZE  (1 << ISO_SECTOR_SHIFT)
+#define ROOT_DIR_WORD    0x002f
+#define TRACKBUF_SIZE    8192
+
+
+struct open_file_t {
+        uint32_t file_sector;
+        uint32_t file_bytesleft;
+        uint32_t file_left;
+        uint32_t pad;
+};
+extern char Files[];
+
+struct dir_t {
+        uint32_t dir_lba;        /* Directory start (LBA) */
+        uint32_t dir_len;        /* Length in bytes */
+        uint32_t dir_clust;      /* Length in clusters */
+};
+struct dir_t RootDir;
+struct dir_t CurrentDir;
+
+
+extern char trackbuf[TRACKBUF_SIZE];
+uint16_t BufSafe = TRACKBUF_SIZE >> ISO_SECTOR_SHIFT;
+uint16_t BufSafeBytes = TRACKBUF_SIZE;
+
+char ISOFileName[64];      /* ISO filename canonicalizatin buffer */
+char *ISOFileNameEnd = &ISOFileName[64];
+
+uint32_t FirstSecSum;         /* checksum of bytes 64-2048 */
+uint32_t ImageDwords;         /* isolinux.bin size, dwords */
+uint32_t InitStack;           /* Initial stack pointer (SS:SP) */
+uint16_t DiskSys;             /* Last INT 13h call */
+uint16_t ImageSectors;        /* isolinux.bin size, sectors */
+
+/* These following two are accessed as a single dword ... */
+uint16_t GetlinsecPtr;        /* the sector-read pointer */
+uint16_t BIOSType;
+uint8_t  DiskError;           /* Error code for disk I/O */
+uint8_t  DriveNumber;         /* CD-ROM BIOS drive number */
+uint8_t  ISOFlags;            /* Flags for ISO directory search */
+uint8_t  RetryCount;          /* Used for ISO directory search */
+uint16_t bsSecPerTrack;       /* Used in hybrid mode */
+uint16_t bsHeads;             /* Used in hybrid mode */
+
+
+/**
+ * allocate_file:
+ *
+ * allocate a file structure
+ *
+ */
+struct open_file_t *allocate_file()
+{
+    struct open_file_t *file;
+    int i = 0;
+    
+    file = (struct open_file_t *)Files;
+    for (; i < MAX_OPEN; i ++ ) {
+        if ( file->file_sector == 0 ) /* found it */
+            return file;
+        file ++;
+    }
+    
+    return NULL; /* not found */
+}
+  
+
+/**
+ * close_file:
+ * 
+ * Deallocates a file structure 
+ *
+ */
+void close_file(struct open_file_t *file)
+{
+    if (file)
+        file->file_sector = 0;
+}
+
+void getlinsec_cdrom(char *buf, sector_t sector_num, int sectors)
+{
+    com32sys_t regs;
+    //static __lowmem char low_buf[65536]; 
+    /* for safe, we use buf + (sectors << SECTOR_SHIFT) here */
+    int high_addr = (buf + (sectors << ISO_SECTOR_SHIFT)) > (char *)0x100000;
+        
+    memset(&regs, 0, sizeof regs);
+    regs.eax.l = sector_num;
+    regs.ebp.l = sectors;
+    
+    if (high_addr) {
+        regs.es = SEG(core_xfer_buf);
+        regs.ebx.w[0] = OFFS(core_xfer_buf);
+    } else {
+        regs.es = SEG(buf);
+        regs.ebx.w[0] = OFFS(buf);
+    }
+
+    call16(getlinsec, &regs, NULL);
+
+    if (high_addr)
+        memcpy(buf, core_xfer_buf, sectors << ISO_SECTOR_SHIFT);
+}
+
+
+
+
+/**
+ * mangle_name:
+ *
+ * Mangle a filename pointed to by src into a buffer pointed
+ * to by dst; ends on encountering any whitespace.
+ * dst 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 redumndant slashes, so "repe
+ * cmpsb" can do a compare, and the path-searching routine gets
+ * a bit of an easier job.
+ *
+ */
+void iso_mangle_name(char *dst, char *src)
+{
+    char *p = dst;
+    int i = FILENAME_MAX - 1;
+    
+    while ( *src > ' ' ) {
+        if ( *src == '/' ) {
+            if ( *(src+1) == '/' ) {
+                i --;
+                src ++;
+                continue;
+            }
+        }
+        
+        *dst++ = *src ++;
+        i --;
+    }
+    
+    while ( 1 ) {
+        if ( dst == p )
+            break;
+        
+        if ( (*(dst-1) != '.') && (*(dst-1) != '/') ) 
+            break;
+        
+        dst --;
+        i ++;
+    }
+    
+    i ++;
+    for (; i > 0; i -- )
+        *dst++ = '\0';
+}
+    
+
+/**
+ * compare the names si and di and report if they are
+ * equal from an ISO 9600 perspective. 
+ *
+ * @param: de_name, the name from the file system.
+ * @param: len, the length of de_name, and will return the real name of the de_name
+ *              ';' and other terminates excluded.
+ * @param: file_name, the name we want to check, is expected to end with a null
+ *
+ * @return: 1 on match, or 0.
+ *
+ */
+int iso_compare_names(char *de_name, int *len, char *file_name)
+{        
+    char *p  = ISOFileName;
+    char c1, c2;
+    
+    int i = 0;
+    
+    while ( (i < *len) && *de_name && (*de_name != ';') && (p < ISOFileNameEnd - 1) ) {
+        *p++ = *de_name++;
+        i++;
+    }
+    
+    /* Remove terminal dots */
+    while ( *(p-1) == '.' ) {
+        if ( *len <= 2 )
+            break;
+        
+        if ( p <= ISOFileName )
+            break;
+        p --;
+        i--;
+    }
+    
+    if ( i <= 0 )
+        return 0;
+    
+    *p = '\0';
+    
+    /* return the 'real' length of de_name */
+    *len = i;
+    
+    p = ISOFileName;
+    
+    /* i is the 'real' name length of file_name */
+    while ( i ) {
+        c1 = *p++;
+        c2 = *file_name++;
+        
+        if ( (c1 == 0) && (c2 == 0) )
+            return 1; /* success */
+        
+        else if ( (c1 == 0) || ( c2 == 0 ) )
+            return 0;
+        
+        c1 |= 0x20;
+        c2 |= 0x20;          /* convert to lower case */
+        if ( c1 != c2 )
+            return 0;
+        i --;
+    }
+    
+    return 1;
+}
+
+
+/**
+ * iso_getfssec:
+ *
+ * Get multiple clusters from a file, given the file pointer.
+ *
+ * we don't use the fs struct for now
+ *
+ * @param: buf
+ * @param: file, the address of the open file structure
+ * @param: sectors, how many we want to read at once 
+ * @param: have_more, to indicate if we have reach the end of the file
+ *
+ */
+uint32_t iso_getfssec(struct fs_info *fs, char *buf, 
+                   void *open_file, int sectors, int *have_more)
+{
+    uint32_t bytes_read = sectors << ISO_SECTOR_SHIFT;
+    struct open_file_t *file = (struct open_file_t *)open_file;
+    
+    if ( sectors > file->file_left )
+        sectors = file->file_left;
+    
+    getlinsec_cdrom(buf, file->file_sector, sectors);
+    
+    file->file_sector += sectors;
+    file->file_left   -= sectors;
+    
+    if ( bytes_read >= file->file_bytesleft ) {
+        bytes_read = file->file_bytesleft;
+        *have_more = 0;
+    } else
+        *have_more = 1;
+    file->file_bytesleft -= bytes_read;
+    
+    return bytes_read;
+}
+
+
+
+/**
+ * do_search_dir:
+ *
+ * find a file or directory with name within the _dir_ directory.
+ * 
+ * the return value will tell us what we find, it's a file or dir?
+ * on 1 be dir, 2 be file, 0 be error.
+ *
+ * res will return the result.
+ *
+ */
+int do_search_dir(struct dir_t *dir, char *name, uint32_t *file_len, void **res)
+{
+    struct open_file_t *file;
+    struct iso_dir_entry *de;
+    struct iso_dir_entry tmpde;
+    
+    uint32_t offset = 0;  /* let's start it with the start */
+    uint32_t file_pos = 0;
+    char *de_name;
+    int de_len;
+    int de_name_len;
+    int have_more;
+    
+    file = allocate_file();
+    if ( !file )
+        return 0;
+    
+    file->file_left = dir->dir_clust;
+    file->file_sector = dir->dir_lba;
+    
+    iso_getfssec(NULL, trackbuf, file, BufSafe, &have_more);
+    de = (struct iso_dir_entry *)trackbuf;
+    
+    while ( file_pos < dir->dir_len ) {
+        int found = 0;
+        
+        if ( (char *)de >= (char *)(trackbuf + TRACKBUF_SIZE) ) {
+            if ( !have_more ) 
+                return 0;
+            
+            iso_getfssec(NULL, trackbuf, file, BufSafe, &have_more);
+            offset = 0;
+        }
+        
+        de = (struct iso_dir_entry *) (trackbuf + offset);
+        
+        de_len = de->length;
+        
+        if ( de_len == 0) {
+            offset = file_pos = (file_pos+ISO_SECTOR_SIZE) & ~(ISO_SECTOR_SIZE-1);
+            continue;
+        }
+        
+        
+        offset += de_len;
+        
+        /* Make sure we have a full directory entry */
+        if ( offset >= TRACKBUF_SIZE ) {
+            int slop = TRACKBUF_SIZE - offset + de_len;
+            memcpy(&tmpde, de, slop);
+            offset &= TRACKBUF_SIZE - 1;
+            file->file_sector ++;
+            if ( offset ) {
+                if ( !have_more ) 
+                    return 0;
+                iso_getfssec(NULL, trackbuf, file, BufSafe, &have_more);
+                memcpy((void*)&tmpde + slop, trackbuf, offset);
+            }
+            de = &tmpde;
+        }
+        
+        if ( de_len < 33 ) {
+            printf("Corrutped directory entry in sector %d\n", file->file_sector);
+            return 0;
+        }
+        
+        de_name_len = de->name_len;
+        de_name = (char *)((void *)de + 0x21);
+        
+        
+        if ( (de_name_len == 1) && (*de_name == 0) ) {
+            found = iso_compare_names(".", &de_name_len, name);
+            
+        } else if ( (de_name_len == 1) && (*de_name == 1) ) {
+            de_name_len = 2;
+            found = iso_compare_names("..", &de_name_len, name);
+            
+        } else 
+            found = iso_compare_names(de_name, &de_name_len, name);
+        
+        if (found)
+            break;
+        
+        file_pos += de_len;
+    }
+    
+    if ( file_pos >= dir->dir_len ) 
+        return 0; /* not found */
+    
+
+    if ( *(name+de_name_len) && (*(name+de_name_len) != '/' ) ) {
+        printf("Something wrong happened during searching file %s\n", name);
+        
+        *res = NULL;
+        return 0;
+    }
+    
+    if ( de->flags & 0x02 ) {
+        /* it's a directory */        
+        dir = &CurrentDir;        
+        dir->dir_lba = *(uint32_t *)de->extent;
+        dir->dir_len = *(uint32_t *)de->size;
+        dir->dir_clust = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+        
+        *file_len = dir->dir_len;
+        *res = dir;
+        
+        /* we can close it now */
+        close_file(file); 
+                
+        /* Mark we got a directory */
+        return 1;        
+    } else {
+        /* it's a file */
+        file->file_sector    = *(uint32_t *)de->extent;
+        file->file_bytesleft = *(uint32_t *)de->size;
+        file->file_left = (file->file_bytesleft + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+
+        *file_len = file->file_bytesleft;
+        *res = file;
+        
+        /* Mark we got a file */
+        return 2;
+    }    
+}
+
+
+/**
+ * iso_searchdir:
+ *
+ * open a file
+ *
+ * searchdir_iso is a special entry point for ISOLINUX only. In addition
+ * to the above, searchdir_iso passes a file flag mask in AL. This is 
+ * useful for searching for directories.
+ *
+ * well, it's not like the searchidr function in EXT fs or FAT fs; it also
+ * can read a diretory.(Just thought of mine, liu)
+ *
+ */
+void iso_searchdir(char *filename, struct file *file)
+{
+    struct open_file_t *open_file = NULL;
+    struct dir_t *dir;
+    uint32_t file_len;
+    int ret;
+    void *res;
+        
+    dir = &CurrentDir;
+    if ( *filename == '/' ) {
+        dir = &RootDir;
+        filename ++;
+    }
+    
+    while ( *filename ) {
+        
+        ret = do_search_dir(dir, filename, &file_len, &res);
+        if ( ret == 1 )
+            dir = (struct dir_t *)res;
+        else if ( ret == 2 )
+            break;
+        else 
+            goto err;
+        
+        /* find the end */
+        while ( *filename && (*filename != '/') )
+            filename ++;
+        
+        /* skip the slash */
+        while ( *filename && (*filename == '/') )
+            filename++;   
+    }
+    
+    /* well , we need recheck it , becuase it can be a directory */
+    if ( ret == 2 ) {
+        open_file = (struct open_file_t *)res;
+        goto found;
+    } else {
+        open_file = allocate_file();
+        if ( !open_file )
+            goto err;
+        
+        open_file->file_sector = dir->dir_lba;
+        open_file->file_bytesleft = dir->dir_len;
+        open_file->file_left = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+        goto found;
+    }
+ err:
+    close_file(open_file);
+    file_len = 0;
+    open_file = NULL;
+ found:
+    file->file_len = file_len;
+    file->open_file = (void*)open_file;
+
+#if 0
+    if (open_file) {
+        printf("file bytesleft: %d\n", open_file->file_bytesleft);
+        printf("file sector   : %d\n", open_file->file_sector);
+        printf("file in sector: %d\n", open_file->file_in_sec);
+        printf("file offsector: %d\n", open_file->file_in_off);
+    }
+#endif
+}
+
+void iso_load_config(com32sys_t *regs)
+{
+    char *config_name = "isolinux.cfg";
+    com32sys_t out_regs;
+    
+    strcpy(ConfigName, config_name);
+    
+    regs->edi.w[0] = ConfigName;
+    memset(&out_regs, 0, sizeof out_regs);
+    call16(core_open, regs, &out_regs);
+}
+
+
+int iso_fs_init()
+{
+    char *iso_dir;
+    char *boot_dir  = "/boot/isolinux";
+    char *isolinux_dir = "/isolinux";
+   
+    struct file file;
+    struct open_file_t *open_file;
+    int len;
+    int bi_pvd = 16;
+    
+    getlinsec_cdrom(trackbuf, bi_pvd, 1);
+    
+    CurrentDir.dir_lba = RootDir.dir_lba = *(uint32_t *)(trackbuf + 156 + 2);
+    
+#ifdef DEBUG
+    printf("Root directory at LBA = 0x%x\n", RootDir.dir_lba);
+#endif
+    
+    CurrentDir.dir_len = RootDir.dir_len = *(uint32_t*)(trackbuf + 156 + 10);
+    CurrentDir.dir_clust = RootDir.dir_clust = (RootDir.dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+    
+    /*
+     * Look for an isolinux directory, and if found,
+     * make it the current directory instead of the
+     * root directory.
+     *
+     * Also copy the name of the directory to CurrrentDirName
+     */
+    *(uint16_t *)CurrentDirName = ROOT_DIR_WORD;
+    
+    iso_dir = boot_dir;
+    iso_searchdir(boot_dir, &file);         /* search for /boot/isolinux */
+    if ( !file.file_len ) {
+        iso_dir = isolinux_dir;
+        iso_searchdir(isolinux_dir, &file); /* search for /isolinux */
+        if ( !file.file_len )
+            goto no_isolinux_dir;
+    }
+    
+    strcpy(CurrentDirName, iso_dir);
+    len = strlen(CurrentDirName);
+    CurrentDirName[len]    = '/';
+    CurrentDirName[len+1]  = '\0';
+    
+    open_file = (struct open_file_t *)file.open_file;
+    CurrentDir.dir_len    = open_file->file_bytesleft;
+    CurrentDir.dir_clust  = open_file->file_left;
+    CurrentDir.dir_lba    = open_file->file_sector;
+    close_file(open_file);
+    
+#ifdef DEBUG
+    printf("isolinux directory at LBA = %0x%x\n", CurrentDir.dir_lba);
+#endif  
+      
+ no_isolinux_dir:
+    printf("No isolinux directory found\n");
+
+     /* we do not use cache for now, so we can just return 0 */
+    return 0;
+}
+
+
+const struct fs_ops iso_fs_ops = {
+    .fs_name       = "iso",
+    .fs_init       = iso_fs_init,
+    .searchdir     = iso_searchdir,
+    .getfssec      = iso_getfssec,
+    .mangle_name   = iso_mangle_name,
+    .unmangle_name = NULL,
+    .load_config   = iso_load_config
+};
index b2c9c98..1a1cae9 100644 (file)
@@ -86,6 +86,7 @@ dir_clust     resd 1                  ; Length in clusters
 ; Memory below this point is reserved for the BIOS and the MBR
 ;
                section .earlybss
+               global trackbuf
 trackbufsize   equ 8192
 trackbuf       resb trackbufsize       ; Track buffer goes here
 ;              ends at 2800h
@@ -191,6 +192,7 @@ _spec_end   equ $
 _spec_len      equ _spec_end - _spec_start
 
                section .bss16
+               global Files
                alignb open_file_t_size
 Files          resb MAX_OPEN*open_file_t_size
 
@@ -767,6 +769,7 @@ getonesec:
 ;      ES:BX   - Target buffer
 ;      BP      - Sector count
 ;
+               global getlinsec
 getlinsec:     jmp word [cs:GetlinsecPtr]
 
 %ifndef DEBUG_MESSAGES
@@ -1160,90 +1163,25 @@ all_read:
 ; (which will be at 16 only for a single-session disk!); from the PVD
 ; we should be able to find the rest of what we need to know.
 ;
-get_fs_structures:
-               mov eax,[bi_pvd]
-               mov bx,trackbuf
-               call getonesec
-
-               mov eax,[trackbuf+156+2]
-               mov [RootDir+dir_lba],eax
-               mov [CurrentDir+dir_lba],eax
-%ifdef DEBUG_MESSAGES
-               mov si,dbg_rootdir_msg
-               call writemsg
-               call writehex8
-               call crlf
-%endif
-               mov eax,[trackbuf+156+10]
-               mov [RootDir+dir_len],eax
-               mov [CurrentDir+dir_len],eax
-               add eax,SECTOR_SIZE-1
-               shr eax,SECTOR_SHIFT
-               mov [RootDir+dir_clust],eax
-               mov [CurrentDir+dir_clust],eax
-
-               ; Look for an isolinux directory, and if found,
-               ; make it the current directory instead of the root
-               ; directory.
-               ; Also copy the name of the directory to CurrentDirName
-               mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
-               mov di,boot_dir                 ; Search for /boot/isolinux
-               mov al,02h
-               push di
-               call searchdir_iso
-               pop di
-               jnz .found_dir
-               mov di,isolinux_dir
-               mov al,02h                      ; Search for /isolinux
-               push di
-               call searchdir_iso
-               pop di
-               jz .no_isolinux_dir
-.found_dir:
-               ; Copy current directory name to CurrentDirName
-               push si
-               push di
-               mov si,di
-               mov di,CurrentDirName
-               call strcpy
-               mov byte [di],0 ;done in case it's not word aligned
-               dec di
-               mov byte [di],'/'
-               pop di
-               pop si
-
-               mov [CurrentDir+dir_len],eax
-               mov eax,[si+file_left]
-               mov [CurrentDir+dir_clust],eax
-               xor eax,eax                     ; Free this file pointer entry
-               xchg eax,[si+file_sector]
-               mov [CurrentDir+dir_lba],eax
-%ifdef DEBUG_MESSAGES
-               push si
-               mov si,dbg_isodir_msg
-               call writemsg
-               pop si
-               call writehex8
-               call crlf
-%endif
-.no_isolinux_dir:
+               pushad
+             extern iso_fs_ops
+             mov eax,iso_fs_ops
+             mov dl,[DriveNumber]
+               mov dh,1                  ; it's cdrom
+             mov ecx,[bsHidden]
+             mov ebx,[bsHidden+4]
+               pm_call fs_init
+               popad
 
 ;
 ; Locate the configuration file
 ;
-load_config:
 %ifdef DEBUG_MESSAGES
                mov si,dbg_config_msg
                call writemsg
 %endif
 
-               mov si,config_name
-               mov di,ConfigName
-               call strcpy
-
-               mov di,ConfigName
-               call open
-               jz no_config_file               ; Not found or empty
+               pm_call load_config
 
 %ifdef DEBUG_MESSAGES
                mov si,dbg_configok_msg
@@ -1289,7 +1227,7 @@ is_disk_image:
 
                mov bx,trackbuf
                mov cx,1                        ; Load 1 sector
-               call getfssec
+               pm_call getfssec
 
                cmp word [trackbuf+510],0aa55h  ; Boot signature
                jne .bad_image          ; Image not bootable
@@ -1386,284 +1324,6 @@ is_disk_image:
                mov al,bl
 .done_sector:  ret
 
-;
-; 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_left
-               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_iso is a special entry point for ISOLINUX only.  In addition
-; to the above, searchdir_iso passes a file flag mask in AL.  This is useful
-; for searching for directories.
-;
-alloc_failure:
-               xor ax,ax                       ; ZF <- 1
-               ret
-
-searchdir:
-               xor al,al
-searchdir_iso:
-               mov [ISOFlags],al
-               TRACER 'S'
-               call allocate_file              ; Temporary file structure for directory
-               jnz alloc_failure
-               push es
-               push ds
-               pop es                          ; ES = DS
-               mov si,CurrentDir
-               cmp byte [di],'/'               ; If filename begins with slash
-               jne .not_rooted
-               inc di                          ; Skip leading slash
-               mov si,RootDir                  ; Reference root directory instead
-.not_rooted:
-               mov eax,[si+dir_clust]
-               mov [bx+file_left],eax
-               shl eax,SECTOR_SHIFT
-               mov [bx+file_bytesleft],eax
-               mov eax,[si+dir_lba]
-               mov [bx+file_sector],eax
-               mov edx,[si+dir_len]
-
-.look_for_slash:
-               mov ax,di
-.scan:
-               mov cl,[di]
-               inc di
-               and cl,cl
-               jz .isfile
-               cmp cl,'/'
-               jne .scan
-               mov [di-1],byte 0               ; Terminate at directory name
-               mov cl,02h                      ; Search for directory
-               xchg cl,[ISOFlags]
-
-               push di                         ; Save these...
-               push cx
-
-               ; Create recursion stack frame...
-               push word .resume               ; Where to "return" to
-               push es
-.isfile:       xchg ax,di
-
-.getsome:
-               ; Get a chunk of the directory
-               ; This relies on the fact that ISOLINUX doesn't change SI
-               mov si,trackbuf
-               TRACER 'g'
-               pushad
-               xchg bx,si
-               mov cx,[BufSafe]
-               call getfssec
-               popad
-
-.compare:
-               movzx eax,byte [si]             ; Length of directory entry
-               cmp al,33
-               jb .next_sector
-               TRACER 'c'
-               mov cl,[si+25]
-               xor cl,[ISOFlags]
-               test cl, byte 8Eh               ; Unwanted file attributes!
-               jnz .not_file
-               pusha
-               movzx cx,byte [si+32]           ; File identifier length
-               add si,byte 33                  ; File identifier offset
-               TRACER 'i'
-               call iso_compare_names
-               popa
-               je .success
-.not_file:
-               sub edx,eax                     ; Decrease bytes left
-               jbe .failure
-               add si,ax                       ; Advance pointer
-
-.check_overrun:
-               ; Did we finish the buffer?
-               cmp si,trackbuf+trackbufsize
-               jb .compare                     ; No, keep going
-
-               jmp short .getsome              ; Get some more directory
-
-.next_sector:
-               ; Advance to the beginning of next sector
-               lea ax,[si+SECTOR_SIZE-1]
-               and ax,~(SECTOR_SIZE-1)
-               sub ax,si
-               jmp short .not_file             ; We still need to do length checks
-
-.failure:      xor eax,eax                     ; ZF = 1
-               mov [bx+file_sector],eax
-               pop es
-               ret
-
-.success:
-               mov eax,[si+2]                  ; Location of extent
-               mov [bx+file_sector],eax
-               mov eax,[si+10]                 ; Data length
-               mov [bx+file_bytesleft],eax
-               push eax
-               add eax,SECTOR_SIZE-1
-               shr eax,SECTOR_SHIFT
-               mov [bx+file_left],eax
-               pop eax
-               jz .failure                     ; Empty file?
-               ; ZF = 0
-               mov si,bx
-               pop es
-               ret
-
-.resume:       ; We get here if we were only doing part of a lookup
-               ; This relies on the fact that .success returns bx == si
-               xchg edx,eax                    ; Directory length in edx
-               pop cx                          ; Old ISOFlags
-               pop di                          ; Next filename pointer
-               mov byte [di-1], '/'            ; Restore slash
-               mov [ISOFlags],cl               ; Restore the flags
-               jz .failure                     ; Did we fail?  If so fail for real!
-               jmp .look_for_slash             ; Otherwise, next level
-
-;
-; 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
-
-;
-; iso_compare_names:
-;      Compare the names DS:SI and DS:DI and report if they are
-;      equal from an ISO 9660 perspective.  SI is the name from
-;      the filesystem; CX indicates its length, and ';' terminates.
-;      DI is expected to end with a null.
-;
-;      Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
-;
-
-iso_compare_names:
-               ; First, terminate and canonicalize input filename
-               push di
-               mov di,ISOFileName
-.canon_loop:   jcxz .canon_end
-               lodsb
-               dec cx
-               cmp al,';'
-               je .canon_end
-               and al,al
-               je .canon_end
-               stosb
-               cmp di,ISOFileNameEnd-1         ; Guard against buffer overrun
-               jb .canon_loop
-.canon_end:
-               cmp di,ISOFileName
-               jbe .canon_done
-               cmp byte [di-1],'.'             ; Remove terminal dots
-               jne .canon_done
-               dec di
-               jmp short .canon_end
-.canon_done:
-               mov [di],byte 0                 ; Null-terminate string
-               pop di
-               mov si,ISOFileName
-.compare:
-               lodsb
-               mov ah,[di]
-               inc di
-               and ax,ax
-               jz .success                     ; End of string for both
-               and al,al                       ; Is either one end of string?
-               jz .failure                     ; If so, failure
-               and ah,ah
-               jz .failure
-               or ax,2020h                     ; Convert to lower case
-               cmp al,ah
-               je .compare
-.failure:      and ax,ax                       ; ZF = 0 (at least one will be nonzero)
-.success:      ret
-
-;
-; 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,
-;             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,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
@@ -1680,56 +1340,6 @@ unmangle_name:   call strcpy
                dec di                          ; Point to final null byte
                ret
 
-;
-; getfssec: Get multiple clusters from a file, given the file pointer.
-;
-;  On entry:
-;      ES:BX   -> Buffer
-;      SI      -> File pointer
-;      CX      -> Cluster count
-;  On exit:
-;      SI      -> File pointer (or 0 on EOF)
-;      CF = 1  -> Hit EOF
-;      ECX     -> Bytes actually read
-;
-getfssec:
-               TRACER 'F'
-               push ds
-               push cs
-               pop ds                          ; DS <- CS
-
-               movzx ecx,cx
-               cmp ecx,[si+file_left]
-               jna .ok_size
-               mov ecx,[si+file_left]
-.ok_size:
-
-               pushad
-               mov eax,[si+file_sector]
-               mov bp,cx
-               TRACER 'l'
-               call getlinsec
-               popad
-
-               ; ECX[31:16] == 0 here...
-               add [si+file_sector],ecx
-               sub [si+file_left],ecx
-               shl ecx,SECTOR_SHIFT            ; Convert to bytes
-               cmp ecx,[si+file_bytesleft]
-               jb .not_all
-               mov ecx,[si+file_bytesleft]
-.not_all:      sub [si+file_bytesleft],ecx
-               jnz .ret                        ; CF = 0 in this case...
-               push eax
-               xor eax,eax
-               mov [si+file_sector],eax        ; Unused
-               mov si,ax
-               pop eax
-               stc
-.ret:
-               pop ds
-               TRACER 'f'
-               ret
 
 ; -----------------------------------------------------------------------------
 ;  Common modules