aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2009-08-16 21:59:40 -0400
committerKevin O'Connor <kevin@koconnor.net>2009-08-16 21:59:40 -0400
commita3855adbde97f3bb71e2d5f153be7304ac700a89 (patch)
treee13407187d715c8dc546affcf8bf5bdef9d3bf29
parent1f83625f4861b1118e3392adb1da96a0d24a94cb (diff)
downloadseabios-a3855adbde97f3bb71e2d5f153be7304ac700a89.tar.gz
Add support for using floppy images in CBFS.
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).
-rw-r--r--Makefile2
-rw-r--r--src/block.c6
-rw-r--r--src/config.h2
-rw-r--r--src/coreboot.c2
-rw-r--r--src/disk.h7
-rw-r--r--src/floppy.c23
-rw-r--r--src/memmap.c17
-rw-r--r--src/memmap.h1
-rw-r--r--src/pmm.c20
-rw-r--r--src/post.c1
-rw-r--r--src/ramdisk.c99
-rw-r--r--src/util.h10
12 files changed, 161 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index 2b8d0d2..d697fca 100644
--- 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 \
diff --git a/src/block.c b/src/block.c
index 3345db7..aa341a2 100644
--- a/src/block.c
+++ b/src/block.c
@@ -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;
diff --git a/src/config.h b/src/config.h
index 72c7d71..494fe8d 100644
--- a/src/config.h
+++ b/src/config.h
@@ -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.
diff --git a/src/coreboot.c b/src/coreboot.c
index 16f906a..4596ffd 100644
--- a/src/coreboot.c
+++ b/src/coreboot.c
@@ -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);
diff --git a/src/disk.h b/src/disk.h
index 89e4a2a..dbaa1b7 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -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
diff --git a/src/floppy.c b/src/floppy.c
index 3bf63b2..90a7fce 100644
--- a/src/floppy.c
+++ b/src/floppy.c
@@ -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
diff --git a/src/memmap.c b/src/memmap.c
index 005c474..45f5012 100644
--- a/src/memmap.c
+++ b/src/memmap.c
@@ -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()
diff --git a/src/memmap.h b/src/memmap.h
index 51471d6..4494538 100644
--- a/src/memmap.h
+++ b/src/memmap.h
@@ -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[];
diff --git a/src/pmm.c b/src/pmm.c
index b3eef4b..da462fd 100644
--- 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);
diff --git a/src/post.c b/src/post.c
index 9bb5132..69aeb93 100644
--- a/src/post.c
+++ b/src/post.c
@@ -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
index 0000000..cb78f45
--- /dev/null
+++ b/src/ramdisk.c
@@ -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;
+ }
+}
diff --git a/src/util.h b/src/util.h
index dc3dfc1..0e4f84b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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);