diff options
Diffstat (limited to 'roms/seabios/src/hw/ramdisk.c')
-rw-r--r-- | roms/seabios/src/hw/ramdisk.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/roms/seabios/src/hw/ramdisk.c b/roms/seabios/src/hw/ramdisk.c new file mode 100644 index 000000000..b9e9baabc --- /dev/null +++ b/roms/seabios/src/hw/ramdisk.c @@ -0,0 +1,108 @@ +// 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 "biosvar.h" // GET_GLOBALFLAT +#include "block.h" // struct drive_s +#include "bregs.h" // struct bregs +#include "e820map.h" // e820_add +#include "malloc.h" // memalign_tmphigh +#include "memmap.h" // PAGE_SIZE +#include "output.h" // dprintf +#include "romfile.h" // romfile_findprefix +#include "stacks.h" // call16_int +#include "std/disk.h" // DISK_RET_SUCCESS +#include "string.h" // memset +#include "util.h" // process_ramdisk_op + +void +ramdisk_setup(void) +{ + if (!CONFIG_FLASH_FLOPPY) + return; + + // Find image. + struct romfile_s *file = romfile_findprefix("floppyimg/", NULL); + if (!file) + return; + const char *filename = file->name; + u32 size = file->size; + dprintf(3, "Found floppy file %s of size %d\n", filename, 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. + void *pos = memalign_tmphigh(PAGE_SIZE, size); + if (!pos) { + warn_noalloc(); + return; + } + e820_add((u32)pos, size, E820_RESERVED); + + // Copy image into ram. + int ret = file->copy(file, pos, size); + if (ret < 0) + return; + + // Setup driver. + struct drive_s *drive = init_floppy((u32)pos, ftype); + if (!drive) + return; + drive->type = DTYPE_RAMDISK; + dprintf(1, "Mapping floppy %s to addr %p\n", filename, pos); + char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]); + boot_add_floppy(drive, desc, bootprio_find_named_rom(filename, 0)); +} + +static int +ramdisk_copy(struct disk_op_s *op, int iswrite) +{ + u32 offset = GET_GLOBALFLAT(op->drive_fl->cntl_id); + offset += (u32)op->lba * DISK_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 int 1587 to copy data. + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_CF|F_IF; + br.ah = 0x87; + br.es = GET_SEG(SS); + br.si = (u32)gdt; + br.cx = op->count * DISK_SECTOR_SIZE / 2; + call16_int(0x15, &br); + + if (br.flags & F_CF) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; +} + +int +ramdisk_process_op(struct disk_op_s *op) +{ + if (!CONFIG_FLASH_FLOPPY) + return 0; + + switch (op->command) { + case CMD_READ: + return ramdisk_copy(op, 0); + case CMD_WRITE: + return ramdisk_copy(op, 1); + default: + return default_process_op(op); + } +} |