This patch adds memory block devices to QEMU. It was mainly for the purpose of booting a pentium qemu without a disk, but it is also very useful for testing and debugging different types of file systems from the OS using only memory.
signed-off-by: [EMAIL PROTECTED]
Jason.
Index: qemu/Makefile =================================================================== --- qemu.orig/Makefile +++ qemu/Makefile @@ -29,7 +29,7 @@ subdir-%: dyngen$(EXESUF) recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c block-mem.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c Index: qemu/Makefile.target =================================================================== --- qemu.orig/Makefile.target +++ qemu/Makefile.target @@ -273,7 +273,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-mem.o ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o endif Index: qemu/block-mem.c =================================================================== --- /dev/null +++ qemu/block-mem.c @@ -0,0 +1,216 @@ +/* + * Block driver for volatile memory-based devices + * + * Copyright (c) 2006 Wind River Systems, Inc. + * Written by Alex deVries and Jason Wessel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "block_int.h" + +/**************************************************************/ +/* Memory scratch disk driver using host memory */ + +/* mem_segment is a linked list of segments */ + +struct mem_segment { + char name[256]; + char * data; + unsigned int size; + struct mem_segment * next; +} ; + +static struct mem_segment * segment_head = NULL; + + +struct BDRVMemState { + struct mem_segment * segment; +}; + + +/* Given a segment name, find the mem_segment (if it exists) */ + +static struct mem_segment * find_segment(char * segment_name) { + + struct mem_segment * p; + + if (!segment_name) return NULL; + + for (p = segment_head; p ; p=p->next) { + if (strcmp(p->name,segment_name)==0) return p; + } + return NULL; +} + +/* Read the block device */ + +static int mem_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + struct BDRVMemState *s; + struct mem_segment * p ; + + uint64_t len = nb_sectors * 512; + uint64_t offset = sector_num * 512; + + if (!bs) return -1; + s = bs->opaque; + + if (s && s->segment) return -1; + p = s->segment; + + /* Check if it is out of bounds */ + if (offset > p->size) return -1; + + /* Make sure we don't read off the end */ + if (len + offset > p->size) len = p->size - offset; + + memcpy(buf,p->data,len); + return len; +} + +/* Write to the block device */ + +static int mem_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + struct BDRVMemState *s; + struct mem_segment * p ; + + uint64_t len = nb_sectors * 512; + uint64_t offset = sector_num * 512; + + if (!bs) return -1; + s = bs->opaque; + + if (s && s->segment) return -1; + p = s->segment; + + /* Check if it is out of bounds */ + if (offset > p->size) return -1; + + /* Make sure we don't read off the end */ + if (len + offset > p->size) len = p->size - offset; + + memcpy(p->data,buf,len); + return len; +} + +/* Close the device */ + +static void mem_close(BlockDriverState *bs) +{ + return; +} + +static int mem_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + if (!strncmp(filename, "mem:",4)) + return 100; + + return 0; +} + +/* Create the segment. Create a segment with the segment name of + * filename, and size of image_sectors * 512 + */ +static int mem_create(const char *filename, int64_t image_sectors, + const char *image_filename, int flags) +{ + struct mem_segment* p; + + /* When image_sectors is zero, parse the sector size from + * the file name. + */ + if (!filename || filename[0] == 0) + { + return -1; + } + + if (image_sectors == 0) { + const char *s = filename; + if (strncmp(s,"mem:",4) != 0) + return -1; + s += 4; + s = strchr(s,':'); + if (!s) + return -1; + s++; + image_sectors = atoi(s); + if (image_sectors == 0) + return -1; + } + + /* Make sure the segment isn't already being used */ + + if (find_segment((char *) filename)) return -1; + + /* Create memory for the segment */ + p = qemu_malloc(sizeof(struct mem_segment)); + if (!p) return -1; + + /* Allocate the data area */ + p->data = qemu_malloc(image_sectors * 512); + if (!p->data) return -1; + + /* Setup the name */ + snprintf(p->name,256,filename); + p->size=image_sectors * 512; + + /* Tack it to the head */ + p->next = segment_head; + segment_head=p; + + return 0; + +} + +/* Open the block device */ + +static int mem_open(BlockDriverState *bs, const char *filename) +{ + + struct mem_segment * p = find_segment((char *) filename); + + + if (!p || !p->data) { + /* If the segment did not exist, try to create it on the fly */ + mem_create(filename, 0, 0, 0); + p = find_segment((char *) filename); + if (!p || !p->data) + return -1; + } + + bs->opaque = (void * ) p; + + return 0; +} + +BlockDriver bdrv_mem = { + "mem", + sizeof(struct BDRVMemState), + mem_probe, + mem_open, + mem_read, + mem_write, + mem_close, + mem_create, + 0, +}; Index: qemu/block.c =================================================================== --- qemu.orig/block.c +++ qemu/block.c @@ -784,6 +784,7 @@ BlockDriver bdrv_raw = { void bdrv_init(void) { bdrv_register(&bdrv_raw); + bdrv_register(&bdrv_mem); #ifndef _WIN32 bdrv_register(&bdrv_cow); #endif Index: qemu/qemu-doc.texi =================================================================== --- qemu.orig/qemu-doc.texi +++ qemu/qemu-doc.texi @@ -814,6 +814,7 @@ written), compressed and encrypted disk * disk_images_snapshot_mode:: Snapshot mode * qemu_img_invocation:: qemu-img Invocation * disk_images_fat_images:: Virtual FAT disk images +* disk_images_mem_images:: Memory only scratch disk @end menu @node disk_images_quickstart @@ -878,6 +879,21 @@ What you should @emph{never} do: @item write to the FAT directory on the host system while accessing it with the guest system. @end itemize [EMAIL PROTECTED] disk_images_mem_images [EMAIL PROTECTED] Memory only scratch disk + +QEMU can create an in memory scratch disk device instead of using a disk image. This is the default on a pentium system to satisfy the BIOS if you do not provide a disk image. In the default case you only have a single 512byte sector which is the MBR of the scratch disk, but you can create a large scratch disk. You can also choose to use memory scratch devices with any other target. The syntax is as follows: + [EMAIL PROTECTED] +qemu -kernel bzImage -hda mem:0:1 [EMAIL PROTECTED] example + +The scratch disks use the keyword "mem" followed by ":" then the memory device number "0", and finally the number of 512 byte sectors to allocate. The above invocation is equivalent to when the -hda and its parameter are omitted for the pentium qemu. Below is an example of creating a 1 megabyte scratch disk as the second IDE drive. + [EMAIL PROTECTED] +qemu -kernel bzImage -hda hdisk.img -hdb mem:1:524288 [EMAIL PROTECTED] example + @node pcsys_network @section Network emulation Index: qemu/vl.c =================================================================== --- qemu.orig/vl.c +++ qemu/vl.c @@ -5556,6 +5556,14 @@ int main(int argc, char **argv) bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); } +#ifdef TARGET_I386 + /* Allow a i386 target to boot with no "-hda" argument */ + if (!hd_filename[0]) { + hd_filename[0] = strdup("mem:0:1"); + boot_device = 'c'; + } +#endif /* TARGET_I386 */ + /* open the virtual block devices */ for(i = 0; i < MAX_DISKS; i++) { if (hd_filename[i]) { Index: qemu/vl.h =================================================================== --- qemu.orig/vl.h +++ qemu/vl.h @@ -468,6 +468,7 @@ int cpu_load(QEMUFile *f, void *opaque, typedef struct BlockDriverState BlockDriverState; typedef struct BlockDriver BlockDriver; +extern BlockDriver bdrv_mem; extern BlockDriver bdrv_raw; extern BlockDriver bdrv_cow; extern BlockDriver bdrv_qcow;
_______________________________________________ Qemu-devel mailing list Qemu-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/qemu-devel