Merge branch 'isolinux'
authorLiu Aleaxander <Aleaxander@gmail.com>
Tue, 23 Jun 2009 09:59:06 +0000 (17:59 +0800)
committerLiu Aleaxander <Aleaxander@gmail.com>
Tue, 23 Jun 2009 09:59:06 +0000 (17:59 +0800)
Conflicts:

core/Makefile
core/diskstart.inc
core/fs.c

1  2 
core/Makefile
core/diskio.c
core/diskstart.inc
core/fs.c
core/include/fs.h
core/iso9660.c
core/isolinux.asm

diff --cc core/Makefile
@@@ -33,8 -33,7 +33,9 @@@ CODEPAGE = cp86
  
  # The targets to build in this directory...
  BTARGET  = kwdhash.gen \
-          ldlinux.bss ldlinux.sys ldlinux.bin
 +         extlinux.bin extlinux.bss extlinux.sys \
++         ldlinux.bss ldlinux.sys ldlinux.bin \
+          isolinux.bin isolinux-debug.bin
  
  # All primary source files for the main syslinux files
  NASMSRC        := $(wildcard *.asm)
diff --cc core/diskio.c
index c85d92a,0000000..c1c8dc0
mode 100644,000000..100644
--- /dev/null
@@@ -1,299 -1,0 +1,300 @@@
 +#include <stdio.h>
 +#include <string.h>
 +#include <stdbool.h>
 +#include <klibc/compiler.h>
 +#include "core.h"
 +#include "fs.h"
 +#include "disk.h"
 +
 +#define RETRY_COUNT 6
 +
 +extern uint16_t MaxTransfer;
 +
 +static int chs_rdwr_sectors(struct disk *disk, void *buf,
 +                          sector_t lba, size_t count, bool is_write)
 +{
 +    char *ptr = buf;
 +    char *tptr;
 +    size_t chunk, freeseg;
 +    int sector_size  = disk->sector_size;
 +    int sector_shift = disk->sector_shift;
 +    uint32_t xlba = lba;      /* Truncated LBA (CHS is << 2 TB) */
 +    uint32_t t;
 +    uint16_t c, h, s;
 +    com32sys_t ireg, oreg;
 +    size_t done = 0;
 +    size_t bytes;
 +    int retry;
 +
 +    memset(&ireg, 0, sizeof ireg);
 +
 +    ireg.eax.b[1] = 0x02 + is_write;
 +    ireg.edx.b[0] = disk->disk_number;
 +
 +    while (count) {
 +      chunk = count;
 +      if (chunk > MaxTransfer)
 +          chunk = MaxTransfer;
 +
 +      freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
 +
 +      if ((size_t)buf <= 0xf0000 && freeseg) {
 +          /* Can do a direct load */
 +          tptr = ptr;
 +      } else {
 +          /* Either accessing high memory or we're crossing a 64K line */
 +          tptr = core_xfer_buf;
 +          freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
 +      }
 +      if (chunk > freeseg)
 +          chunk = freeseg;
 +
 +      bytes = chunk << sector_shift;
 +
 +      if (tptr != ptr && is_write)
 +          memcpy(tptr, ptr, bytes);
 +
 +      s = xlba % disk->s;
 +      t = xlba / disk->s;
 +      h = t % disk->h;
 +      c = t / disk->h;
 +
 +      ireg.eax.b[0] = chunk;
 +      ireg.ecx.b[1] = c;
 +      ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
 +      ireg.edx.b[1] = h;
 +      ireg.ebx.w[0] = OFFS(tptr);
 +      ireg.es       = SEG(tptr);
 +
 +      retry = RETRY_COUNT;
 +
 +      for (;;) {
 +          __intcall(0x13, &ireg, &oreg);
 +          if (!(oreg.eflags.l & EFLAGS_CF))
 +              break;
 +          if (retry--)
 +              continue;
 +          chunk >>= 1;
 +          if (chunk) {
 +              MaxTransfer = chunk;
 +              retry = RETRY_COUNT;
 +              continue;
 +          }
 +          return done;        /* Failure */
 +      }
 +
 +      bytes = chunk << sector_shift;
 +
 +      if (tptr != ptr && !is_write)
 +          memcpy(ptr, tptr, bytes);
 +
 +      ptr   += bytes;
 +      xlba  += chunk;
 +      count -= chunk;
 +      done  += chunk;
 +    }
 +    return done;
 +}
 +
 +struct edd_rdwr_packet {
 +    uint16_t size;
 +    uint16_t blocks;
 +    far_ptr_t buf;
 +    uint64_t lba;
 +};
 +
 +static int edd_rdwr_sectors(struct disk *disk, void *buf,
 +                          sector_t lba, size_t count, bool is_write)
 +{
 +    static __lowmem struct edd_rdwr_packet pkt;
 +    char *ptr = buf;
 +    char *tptr;
 +    size_t chunk, freeseg;
 +    int sector_size  = disk->sector_size;
 +    int sector_shift = disk->sector_shift;
 +    com32sys_t ireg, oreg;
 +    size_t done = 0;
 +    size_t bytes;
 +    int retry;
 +
 +    memset(&ireg, 0, sizeof ireg);
++    
 +    ireg.eax.b[1] = 0x42 + is_write;
 +    ireg.edx.b[0] = disk->disk_number;
 +    ireg.ds       = SEG(&pkt);
 +    ireg.esi.w[0] = OFFS(&pkt);
 +
 +    while (count) {
 +      chunk = count;
 +      if (chunk > MaxTransfer)
 +          chunk = MaxTransfer;
 +
 +      freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
 +
 +      if ((size_t)buf <= 0xf0000 && freeseg) {
 +          /* Can do a direct load */
 +          tptr = ptr;
 +      } else {
 +          /* Either accessing high memory or we're crossing a 64K line */
 +          tptr = core_xfer_buf;
 +          freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
 +      }
 +      if (chunk > freeseg)
 +          chunk = freeseg;
 +
 +      bytes = chunk << sector_shift;
 +
 +      if (tptr != ptr && is_write)
 +          memcpy(tptr, ptr, bytes);
 +
 +      pkt.size   = sizeof pkt;
 +      pkt.blocks = chunk;
 +      pkt.buf    = FAR_PTR(tptr);
 +      pkt.lba    = lba;
 +
 +      retry = RETRY_COUNT;
 +
 +      for (;;) {
 +          __intcall(0x13, &ireg, &oreg);
 +          if (!(oreg.eflags.l & EFLAGS_CF))
 +              break;
 +          if (retry--)
 +              continue;
 +          chunk >>= 1;
 +          if (chunk) {
 +              MaxTransfer = chunk;
 +              retry = RETRY_COUNT;
 +              continue;
 +          }
 +          /*** XXX: Consider falling back to CHS here?! ***/
++            printf("reading sectors error(EDD)\n");
 +          return done;        /* Failure */
 +      }
 +
 +      bytes = chunk << sector_shift;
 +
 +      if (tptr != ptr && !is_write)
 +          memcpy(ptr, tptr, bytes);
 +
 +      ptr   += bytes;
 +      lba   += chunk;
 +      count -= chunk;
 +      done  += chunk;
 +    }
 +    return done;
 +}
 +struct edd_disk_params {
 +    uint16_t  len;
 +    uint16_t  flags;
 +    uint32_t  phys_c;
 +    uint32_t  phys_h;
 +    uint32_t  phys_s;
 +    uint64_t  sectors;
 +    uint16_t  sector_size;
 +    far_ptr_t dpte;
 +    uint16_t  devpath_key;
 +    uint8_t   devpath_len;
 +    uint8_t   _pad1[3];
 +    char      bus_type[4];
 +    char      if_type[8];
 +    uint8_t   if_path[8];
 +    uint8_t   dev_path[8];
 +    uint8_t   _pad2;
 +    uint8_t   devpath_csum;
 +} __attribute__((packed));
 +
 +static inline bool is_power_of_2(uint32_t x)
 +{
 +    return !(x & (x-1));
 +}
 +
 +int ilog2(uint32_t num)
 +{
 +    int i = 0;
 +    
 +    if (!is_power_of_2(num)) {
 +        printf("ERROR: the num must be power of 2 when conveting to log2\n");
 +        return 0;
 +    }
 +    while (num >>= 1)
 +        i++;
 +    return i;
 +}
 +
 +void dump_disk(struct disk *disk)
 +{
 +    printf("drive number: 0x%x\n", disk->disk_number);
 +    printf("disk type: %s(%d)\n", disk->type ? "EDD" : "CHS", disk->type);
 +    printf("sector size: %d(%d)\n", disk->sector_size, disk->sector_shift);
 +    printf("h: %d\ts: %d\n", disk->h, disk->s);
 +    printf("offset: %d\n", disk->part_start);
 +    printf("%s\n", disk->rdwr_sectors == edd_rdwr_sectors ? "EDD_RDWR_SECTORS" :
 +           "CHS_RDWR_SECTORS");
 +    printf("--------------------------------\n");
 +    printf("disk->rdwr_sectors@: %p\n", disk->rdwr_sectors);
 +    printf("edd_rdwr_sectors  @: %p\n", edd_rdwr_sectors);
 +    printf("chs_rdwr_sectors  @: %p\n", chs_rdwr_sectors);
 +}
 +
 +struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
 +                       uint16_t bsHeads, uint16_t bsSecPerTrack)
 +{
 +    static struct disk disk;
 +    static __lowmem struct edd_disk_params edd_params;
 +    com32sys_t ireg, oreg;
 +    bool ebios = cdrom;
 +    int sector_size = cdrom ? 2048 : 512;
 +
 +    memset(&ireg, 0, sizeof ireg);
 +
 +    /* Get EBIOS support */
 +    ireg.eax.b[1] = 0x41;
 +    ireg.ebx.w[0] = 0x55aa;
 +    ireg.edx.b[0] = devno;
 +    ireg.eflags.b[0] = 0x3;   /* CF set */
 +
 +    __intcall(0x13, &ireg, &oreg);
 +
 +    if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) &&
 +                oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) {
 +      /* Query EBIOS parameters */
 +      ireg.eax.b[1] = 0x48;
 +      ireg.ds = SEG(&edd_params);
 +      ireg.esi.w[0] = OFFS(&edd_params);
 +      __intcall(0x13, &ireg, &oreg);
 +
 +      if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
 +          ebios = true;
 +          if (edd_params.sector_size >= 512 &&
 +              is_power_of_2(edd_params.sector_size))
 +              sector_size = edd_params.sector_size;
 +      }
 +    }
 +
 +    /* CBIOS parameters */
 +    disk.h = bsHeads;
 +    disk.s = bsSecPerTrack;
 +
 +    if ((int8_t)devno < 0) {
 +      /* Get hard disk geometry from BIOS */
 +
 +      ireg.eax.b[1] = 0x08;
 +      __intcall(0x13, &ireg, &oreg);
 +
 +      if (!(oreg.eflags.l & EFLAGS_CF)) {
 +          disk.h = oreg.edx.b[1] + 1;
 +          disk.s = oreg.ecx.b[0] & 63;
 +      }
 +    }
 +
 +    disk.disk_number   = devno;
 +    disk.type          = ebios;
 +    disk.sector_size   = sector_size;
 +    disk.sector_shift  = ilog2(sector_size);
 +    disk.part_start    = part_start;
 +    disk.rdwr_sectors  = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
 +
 +    dump_disk(&disk);
 +
 +    return &disk;
 +}
@@@ -731,11 -729,8 +731,11 @@@ expand_super
              mov eax,iso_fs_ops
   %endif
              mov dl,[DriveNumber]
-               mov dh,0               ; we are boot from disk not CDROM
 -              mov dh,0               ; it's a disk not cdrom
++              mov dh,0               ; we are boot from disk not CDROM
              mov ecx,[bsHidden]
              mov ebx,[bsHidden+4]
 +              mov si,[bsHeads]
 +              mov di,[bsSecPerTrack]
  %endif
 -             pm_call fs_init
 +              pm_call fs_init
 +              popad
diff --cc core/fs.c
+++ b/core/fs.c
@@@ -134,7 -130,8 +135,8 @@@ struct device * device_init(uint8_t dev
  /* debug function */
  void dump_dev(struct device *dev)
  {
 -    printf("drive number: 0x%x\n", dev->device_number);
 -    printf("device type:%s\n", dev->type ? "CHS" : "EDD");
 +    printf("device type:%s\n", dev->disk->type ? "EDD" : "CHS");
++    printf("drive number: 0x%x\n", dev->disk->disk_number);
      printf("cache_data: %p\n", dev->cache_data);
      printf("cache_head: %p\n", dev->cache_head);
      printf("cache_block_size: %d\n", dev->cache_block_size);
Simple merge
diff --cc core/iso9660.c
index 0000000,68885a6..09da65a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,579 +1,579 @@@
 -    getlinsec_cdrom(buf, file->file_sector, sectors);
+ #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;
+     
 -    
++    fs->fs_dev->disk->rdwr_sectors(fs->fs_dev->disk, (void *)buf, file->file_sector, sectors, 0);
+     
+     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 ++;
+     }
 -        
++#define DEBUG() printf("go there? %d\n", __LINE__)
+     while ( *filename ) {
 -        
++        DEBUG();
+         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;
 -    
++        DEBUG();
+         /* find the end */
+         while ( *filename && (*filename != '/') )
+             filename ++;
+         
+         /* skip the slash */
+         while ( *filename && (*filename == '/') )
+             filename++;   
+     }
 -int iso_fs_init()
++    DEBUG();
+     /* 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] = OFFS_WRT(ConfigName, 0);
+     memset(&out_regs, 0, sizeof out_regs);
+     call16(core_open, regs, &out_regs);
+ }
 -    getlinsec_cdrom(trackbuf, bi_pvd, 1);
++int iso_fs_init(struct fs_info *fs)
+ {
+     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;
+     
++    fs->fs_dev->disk->rdwr_sectors(fs->fs_dev->disk, (void*)trackbuf, bi_pvd, 1, 0);
+     
+     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 ) {
+             printf("No isolinux directory found!\n");
+             return 0;
+         }            
+     }
+     
+     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  
+       
+     /* 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
+ };
@@@ -1099,6 -1102,6 +1102,7 @@@ bios_ebios:     dw getlinsec_ebios, bios_eb
  %endif
  
  ; Maximum transfer size
++                global MaxTransfer          
  MaxTransfer   dw 127                          ; Hard disk modes
  MaxTransferCD dw 32                           ; CD mode
  
@@@ -1160,73 -1163,15 +1164,17 @@@ 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]
++                mov si,[bsHeads]
++              mov di,[bsSecPerTrack]
+               pm_call fs_init
+               popad
  
  ;
  ; Locate the configuration file