iso9660: use boot_info_table and fix hybrid mode
authorH. Peter Anvin <hpa@zytor.com>
Fri, 26 Feb 2010 21:18:26 +0000 (13:18 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 26 Feb 2010 21:18:26 +0000 (13:18 -0800)
In hybrid disk mode, one block will generally *not* equal one sector.
Use the boot_info_table to find the primary volume descriptor.
Remove the now-unused cdrom_read_blocks().

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
core/fs/iso9660/iso9660.c
core/fs/iso9660/iso9660_fs.h
core/isolinux.asm

index c32c3a0..995cd21 100644 (file)
@@ -134,12 +134,6 @@ static bool iso_compare_name(const char *de_name, size_t len,
     return true;
 }
 
-static inline int cdrom_read_blocks(struct disk *disk, void *buf, 
-                                   int block, int blocks)
-{
-    return disk->rdwr_sectors(disk, buf, block, blocks, 0);
-}
-
 /*
  * Find a entry in the specified dir with name _dname_.
  */
@@ -314,25 +308,38 @@ static int iso_load_config(void)
     return 0;
 }
 
-
 static int iso_fs_init(struct fs_info *fs)
 {
     struct iso_sb_info *sbi;
-    
+    char pvd[2048];            /* Primary Volume Descriptor */
+    uint32_t pvd_lba;
+    struct disk *disk = fs->fs_dev->disk;
+    int blktosec;
+
     sbi = malloc(sizeof(*sbi));
     if (!sbi) {
        malloc_error("iso_sb_info structure");
        return 1;
     }
     fs->fs_info = sbi;
-    
-    cdrom_read_blocks(fs->fs_dev->disk, trackbuf, 16, 1);
-    memcpy(&sbi->root, trackbuf + ROOT_DIR_OFFSET, sizeof(sbi->root));
 
+    /* 
+     * XXX: handling iso9660 in hybrid mode on top of a 4K-logical disk
+     * will really, really hurt...
+     */
     fs->sector_shift = fs->fs_dev->disk->sector_shift;
-    fs->block_shift  = 11;
+    fs->block_shift  = 11;     /* A CD-ROM block is always 2K */
     fs->sector_size  = 1 << fs->sector_shift;
     fs->block_size   = 1 << fs->block_shift;
+    blktosec = fs->block_shift - fs->sector_shift;
+
+    pvd_lba = iso_boot_info.pvd;
+    if (!pvd_lba)
+       pvd_lba = 16;           /* Default if not otherwise defined */
+
+    disk->rdwr_sectors(disk, pvd, (sector_t)pvd_lba << blktosec,
+                      1 << blktosec, false);
+    memcpy(&sbi->root, pvd + ROOT_DIR_OFFSET, sizeof(sbi->root));
 
     /* Initialize the cache */
     cache_init(fs->fs_dev, fs->block_shift);
index 6e9d495..a365fa1 100644 (file)
@@ -4,6 +4,17 @@
 #include <klibc/compiler.h>
 #include <stdint.h>
 
+/* Boot info table */
+struct iso_boot_info {
+    uint32_t pvd;              /* LBA of primary volume descriptor */
+    uint32_t file;             /* LBA of boot file */
+    uint32_t length;           /* Length of boot file */
+    uint32_t csum;             /* Checksum of boot file */
+    uint32_t reserved[10];     /* Currently unused */
+};
+
+extern struct iso_boot_info iso_boot_info; /* In isolinux.asm */
+
 /* The root dir entry offset in the primary volume descriptor */
 #define ROOT_DIR_OFFSET   156
 
index 078f7ca..7329f14 100644 (file)
@@ -200,6 +200,8 @@ _start:             ; Far jump makes sure we canonicalize the address
                ; -boot-info-table option.  If not, the values in this
                ; table are default values that we can use to get us what
                ; we need, at least under a certain set of assumptions.
+               global iso_boot_info
+iso_boot_info:
 bi_pvd:                dd 16                           ; LBA of primary volume descriptor
 bi_file:       dd 0                            ; LBA of boot file
 bi_length:     dd 0xdeadbeef                   ; Length of boot file