Add support for using floppy images in CBFS.
authorKevin O'Connor <kevin@koconnor.net>
Mon, 17 Aug 2009 01:59:40 +0000 (21:59 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Mon, 17 Aug 2009 01:59:40 +0000 (21:59 -0400)
Add new "ramdisk" type for disk accesses.
Extract out high-mem finding code from pmm into find_high_area().
Fix bug in GDB_BASE and GDT_LIMIT macros (wrong bit shifts).

12 files changed:
Makefile
src/block.c
src/config.h
src/coreboot.c
src/disk.h
src/floppy.c
src/memmap.c
src/memmap.h
src/pmm.c
src/post.c
src/ramdisk.c [new file with mode: 0644]
src/util.h

index 2b8d0d23ac97f89f02d782faa08156a3ea7f8202..d697fcac1fae1aeb809e4dbe3deb83b03bcb61dc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ OUT=out/
 # Source files
 SRCBOTH=output.c util.c block.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \
         serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
-        pnpbios.c pirtable.c vgahooks.c pmm.c
+        pnpbios.c pirtable.c vgahooks.c pmm.c ramdisk.c
 SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c font.c
 SRC32=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
index 3345db7154ade50c7e73958b626263ae03ef6cd6..aa341a23d0c53cc5e7ddd9382d195070cf7744d3 100644 (file)
@@ -235,12 +235,14 @@ process_op(struct disk_op_s *op)
 {
     u8 type = GET_GLOBAL(Drives.drives[op->driveid].type);
     switch (type) {
+    case DTYPE_FLOPPY:
+        return process_floppy_op(op);
     case DTYPE_ATA:
         return process_ata_op(op);
     case DTYPE_ATAPI:
         return process_atapi_op(op);
-    case DTYPE_FLOPPY:
-        return process_floppy_op(op);
+    case DTYPE_RAMDISK:
+        return process_ramdisk_op(op);
     default:
         op->count = 0;
         return DISK_RET_EPARAM;
index 72c7d71217aee031e0ee36fa961d289da4983d45..494fe8d5408b2846c60f3bf447fa1cdefa3fc111 100644 (file)
@@ -68,6 +68,8 @@
 #define CONFIG_PCI_ROOT2 0x00
 // Support searching coreboot flash format.
 #define CONFIG_COREBOOT_FLASH 0
+// Support floppy images in the coreboot flash.
+#define CONFIG_FLASH_FLOPPY 1
 // Support the lzma decompression algorighm.
 #define CONFIG_LZMA 1
 // Support finding and running option roms during post.
index 16f906a6df981c5de76990b29253d848bc91ccfc..4596ffdd2b79cbcd0f432ab19ef1dd881d4cb1e4 100644 (file)
@@ -503,7 +503,7 @@ cbfs_filename(struct cbfs_file *file)
 }
 
 // Determine the uncompressed size of a datafile.
-int
+u32
 cbfs_datasize(struct cbfs_file *file, int iscomp)
 {
     void *src = (void*)file + ntohl(file->offset);
index 89e4a2af81106f092611306f09fad25adbe8e61c..dbaa1b70a3e4cb9fd959ab3aee92af07a9747631 100644 (file)
@@ -188,6 +188,7 @@ struct drive_s {
 #define DTYPE_FLOPPY   0x01
 #define DTYPE_ATA      0x02
 #define DTYPE_ATAPI    0x03
+#define DTYPE_RAMDISK  0x04
 
 #define TRANSLATION_NONE  0
 #define TRANSLATION_LBA   1
@@ -226,6 +227,8 @@ void drive_setup();
 // floppy.c
 extern struct floppy_ext_dbt_s diskette_param_table2;
 void floppy_setup();
+void addFloppy(int floppyid, int ftype, int driver);
+int find_floppy_type(u32 size);
 int process_floppy_op(struct disk_op_s *op);
 void floppy_tick();
 
@@ -240,4 +243,8 @@ void cdemu_13(struct bregs *regs);
 void cdemu_134b(struct bregs *regs);
 int cdrom_boot(int cdid);
 
+// ramdisk.c
+void ramdisk_setup();
+int process_ramdisk_op(struct disk_op_s *op);
+
 #endif // disk.h
index 3bf63b24acd2fbad16ccbee38332ce2f5c7cace6..90a7fce36bef795c9ae2ece26dfe0eed2c4410ff 100644 (file)
@@ -85,8 +85,8 @@ struct floppyinfo_s FloppyInfo[] VAR16_32 = {
     { {2, 40, 8}, 0x00, 0x27},
 };
 
-static void
-addFloppy(int floppyid, int ftype)
+void
+addFloppy(int floppyid, int ftype, int driver)
 {
     if (ftype <= 0 || ftype >= ARRAY_SIZE(FloppyInfo)) {
         dprintf(1, "Bad floppy type %d\n", ftype);
@@ -99,7 +99,7 @@ addFloppy(int floppyid, int ftype)
     Drives.drivecount++;
     memset(&Drives.drives[driveid], 0, sizeof(Drives.drives[0]));
     Drives.drives[driveid].cntl_id = floppyid;
-    Drives.drives[driveid].type = DTYPE_FLOPPY;
+    Drives.drives[driveid].type = driver;
     Drives.drives[driveid].blksize = FLOPPY_SECTOR_SIZE;
     Drives.drives[driveid].floppy_type = ftype;
     Drives.drives[driveid].sectors = (u16)-1;
@@ -122,9 +122,9 @@ floppy_setup()
     } else {
         u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
         if (type & 0xf0)
-            addFloppy(0, type >> 4);
+            addFloppy(0, type >> 4, DTYPE_FLOPPY);
         if (type & 0x0f)
-            addFloppy(1, type & 0x0f);
+            addFloppy(1, type & 0x0f, DTYPE_FLOPPY);
     }
 
     outb(0x02, PORT_DMA1_MASK_REG);
@@ -132,6 +132,19 @@ floppy_setup()
     enable_hwirq(6, entry_0e);
 }
 
+// Find a floppy type that matches a given image size.
+int
+find_floppy_type(u32 size)
+{
+    int i;
+    for (i=1; i<ARRAY_SIZE(FloppyInfo); i++) {
+        struct chs_s *c = &FloppyInfo[i].chs;
+        if (c->cylinders * c->heads * c->spt * FLOPPY_SECTOR_SIZE == size)
+            return i;
+    }
+    return -1;
+}
+
 
 /****************************************************************
  * Low-level floppy IO
index 005c474cc7b660a10f57f0dacacbe43698b974db..45f5012c7e6804599bcf80481d437536218c4a61 100644 (file)
@@ -119,6 +119,23 @@ add_e820(u64 start, u64 size, u32 type)
     //dump_map();
 }
 
+// Find highest area of 32bit memory that can hold the given size.
+struct e820entry *
+find_high_area(u32 size)
+{
+    int i;
+    for (i=e820_count-1; i>=0; i--) {
+        struct e820entry *e = &e820_list[i];
+        u64 end = e->start + e->size;
+        if (e->type != E820_RAM || end > 0xffffffff || e->size < size)
+            continue;
+        if (end < 1024*1024 + size)
+            break;
+        return e;
+    }
+    return NULL;
+}
+
 // Prep for memmap stuff - init bios table locations.
 void
 memmap_setup()
index 51471d6927a648f0c94b6ed63d839c7b4cb25fb8..4494538d9161c05a3685e667b2bdc4cee89ee92a 100644 (file)
@@ -19,6 +19,7 @@ struct e820entry {
 void add_e820(u64 start, u64 size, u32 type);
 void memmap_setup();
 void memmap_finalize();
+struct e820entry *find_high_area(u32 size);
 
 // e820 map storage (defined in system.c)
 extern struct e820entry e820_list[];
index b3eef4bc314a725661f0094651c20dadd4c43321..da462fdf272ea5cdd63bac239452a2b43c589da5 100644 (file)
--- a/src/pmm.c
+++ b/src/pmm.c
@@ -6,7 +6,7 @@
 
 #include "util.h" // checksum
 #include "config.h" // BUILD_BIOS_ADDR
-#include "memmap.h" // e820_list
+#include "memmap.h" // find_high_area
 #include "farptr.h" // GET_FARVAR
 #include "biosvar.h" // EBDA_SEGMENT_MINIMUM
 
@@ -117,24 +117,14 @@ malloc_setup()
     ZoneTmpLow.top = ZoneTmpLow.cur = (u32)MAKE_FLATPTR(EBDA_SEGMENT_MINIMUM, 0);
 
     // Find memory at the top of ram.
-    u32 top = 0, bottom = 0;
-    int i;
-    for (i=e820_count-1; i>=0; i--) {
-        struct e820entry *e = &e820_list[i];
-        u64 end = e->start + e->size;
-        if (e->type != E820_RAM || end > 0xffffffff
-            || e->size < CONFIG_MAX_HIGHTABLE + MALLOC_MIN_ALIGN)
-            continue;
-        top = end;
-        bottom = e->start;
-        break;
-    }
-    if (top < 1024*1024 + CONFIG_MAX_HIGHTABLE) {
+    struct e820entry *e = find_high_area(CONFIG_MAX_HIGHTABLE+MALLOC_MIN_ALIGN);
+    if (!e) {
         // No memory above 1Meg
         memset(&ZoneHigh, 0, sizeof(ZoneHigh));
-        memset(&ZoneTmpHigh, 0, sizeof(ZoneHigh));
+        memset(&ZoneTmpHigh, 0, sizeof(ZoneTmpHigh));
         return;
     }
+    u32 top = e->start + e->size, bottom = e->start;
 
     // Memory at top of ram.
     ZoneHigh.bottom = ALIGN(top - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
index 9bb51326c814009ae050b83fcac1e0f566d5eee4..69aeb93cd721a42228cf2ef6cc3baac01a1f38eb 100644 (file)
@@ -189,6 +189,7 @@ post()
     drive_setup();
     floppy_setup();
     ata_setup();
+    ramdisk_setup();
 
     optionrom_setup();
 
diff --git a/src/ramdisk.c b/src/ramdisk.c
new file mode 100644 (file)
index 0000000..cb78f45
--- /dev/null
@@ -0,0 +1,99 @@
+// Code for emulating a drive via high-memory accesses.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // process_ramdisk_op
+#include "util.h" // dprintf
+#include "memmap.h" // add_e820
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+
+#define RAMDISK_SECTOR_SIZE 512
+
+void
+ramdisk_setup()
+{
+    if (!CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+        return;
+
+    // Find image.
+    int iscomp;
+    struct cbfs_file *file = cbfs_finddataprefix("floppyimg/", NULL, &iscomp);
+    if (!file)
+        return;
+    u32 size = cbfs_datasize(file, iscomp);
+    dprintf(3, "Found floppy file %s of size %d\n", cbfs_filename(file), size);
+    int ftype = find_floppy_type(size);
+    if (ftype < 0) {
+        dprintf(3, "No floppy type found for ramdisk size\n");
+        return;
+    }
+
+    // Allocate ram for image.
+    struct e820entry *e = find_high_area(size);
+    if (!e) {
+        dprintf(3, "No ram for ramdisk\n");
+        return;
+    }
+    u32 loc = e->start + e->size - size;
+    add_e820(loc, size, E820_RESERVED);
+
+    // Copy image into ram.
+    cbfs_copyfile(file, (void*)loc, size, iscomp);
+
+    // Setup driver.
+    dprintf(1, "Mapping CBFS floppy %s to addr %x\n", cbfs_filename(file), loc);
+    addFloppy(loc, ftype, DTYPE_RAMDISK);
+}
+
+static int
+ramdisk_op(struct disk_op_s *op, int iswrite)
+{
+    u32 offset = GET_GLOBAL(Drives.drives[op->driveid].cntl_id);
+    offset += (u32)op->lba * RAMDISK_SECTOR_SIZE;
+    u64 opd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)op->buf_fl);
+    u64 ramd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE(offset);
+
+    u64 gdt[6];
+    if (iswrite) {
+        gdt[2] = opd;
+        gdt[3] = ramd;
+    } else {
+        gdt[2] = ramd;
+        gdt[3] = opd;
+    }
+
+    // Call 0x1587 to copy data.
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.ah = 0x87;
+    br.es = GET_SEG(SS);
+    br.si = (u32)gdt;
+    br.cx = op->count * RAMDISK_SECTOR_SIZE / 2;
+    call16_int(0x15, &br);
+
+    return DISK_RET_SUCCESS;
+}
+
+int
+process_ramdisk_op(struct disk_op_s *op)
+{
+    if (!CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+        return 0;
+
+    switch (op->command) {
+    case CMD_READ:
+        return ramdisk_op(op, 0);
+    case CMD_WRITE:
+        return ramdisk_op(op, 1);
+    case CMD_VERIFY:
+    case CMD_FORMAT:
+    case CMD_RESET:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
index dc3dfc158c95c8d619ffd843cd14ef47d8cc4bda..0e4f84b3ae9534887c84ec4063250a75b8430466 100644 (file)
@@ -89,10 +89,10 @@ static inline u32 __ffs(u32 word)
 }
 
 // GDT bit manipulation
-#define GDT_BASE(v)  (((u64)((v) & 0xff000000) << 56)           \
-                      | ((u64)((v) & 0x00ffffff) << 16))
-#define GDT_LIMIT(v) (((u64)((v) & 0x000f0000) << 48)   \
-                      | ((u64)((v) & 0x0000ffff) << 0))
+#define GDT_BASE(v)  ((((u64)(v) & 0xff000000) << 32)           \
+                      | (((u64)(v) & 0x00ffffff) << 16))
+#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32)   \
+                      | (((u64)(v) & 0x0000ffff) << 0))
 #define GDT_CODE     (0x9bULL << 40) // Code segment - P,R,A bits also set
 #define GDT_DATA     (0x93ULL << 40) // Data segment - W,A bits also set
 #define GDT_B        (0x1ULL << 54)  // Big flag
@@ -224,7 +224,7 @@ struct cbfs_file;
 struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last);
 struct cbfs_file *cbfs_finddataprefix(const char *prefix, struct cbfs_file *last
                                       , int *iscomp);
-int cbfs_datasize(struct cbfs_file *file, int iscomp);
+u32 cbfs_datasize(struct cbfs_file *file, int iscomp);
 const char *cbfs_filename(struct cbfs_file *file);
 int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen, int iscomp);
 int cbfs_copy_optionrom(void *dst, u32 maxlen, u32 vendev);