This edition is finally able to construct a real partition table. Still buggy (linux fdisk complains about it) but partitions are mountable inside the VM.
The full syntax is: qemu -hda partition:boot=1,bootloader=bootmbr.bin,/dev/hda1,sysid=0xC,partition.raw,sysid=ox82,/dev/sda2,sysid=0x83 You can simplify it though (assuming /dev/hda1 holds a FAT32 filesystem): qemu -hda partition:/dev/hda1 Good luck. -- [EMAIL PROTECTED] -- http://www.fastmail.fm - Send your email first class
/* * Block driver to use composite images * * Copyright (c) 2007 Jim Brown * * 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. */ #ifndef BLOCK_COMPOSITE_H #define BLOCK_COMPOSITE_H #include "vl.h" #include "block_int.h" typedef struct SlaveDriverState { BlockDriverState * bs; int start_sector; int end_sector; } SlaveDriverState; typedef struct BDRVPartState { SlaveDriverState * slave_bs; int slave_count; } BDRVPartState; #endif /*BLOCK_COMPOSITE_H*/
/* * Block driver to use composite images * * Copyright (c) 2007 Jim Brown * * 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 "block_composite.h" static int composite_probe(const uint8_t *buf, int buf_size, const char *filename) { if (strstart(filename, "composite:", NULL)) return 100; return 0; } static int composite_open(BlockDriverState *bs, const char *nfilename, int flags) { BDRVPartState *s = bs->opaque; BlockDriverState * slave_bs; int previous_start, file_count = 1, i; const char * zfilename = &(nfilename[10]), * nptr = zfilename; char * filename; bs->read_only = 0; s->slave_count = 0; previous_start = 0; while (nptr != NULL) { nptr = strchr(nptr, ',')+1; if ((nptr-1) != NULL) { file_count++; } else { nptr = NULL; } } s->slave_bs = qemu_mallocz(sizeof(SlaveDriverState)*file_count); if (s->slave_bs == NULL) return -1; nptr = zfilename; while (nptr != NULL) { nptr = strchr(zfilename, ',')+1; if ((nptr-1) != NULL) { filename = strndup(zfilename, (size_t)((nptr-1)-zfilename)); zfilename = nptr; } else { filename = strdup(zfilename); nptr = NULL; } slave_bs = qemu_mallocz(sizeof(BlockDriverState)); if ((slave_bs == NULL) || (bdrv_open2(slave_bs, filename, 0, NULL) != 0)) { for (i = 0; i < s->slave_count; i++) { bdrv_close(s->slave_bs[i].bs); qemu_free(s->slave_bs[i].bs); } qemu_free(s->slave_bs); return -1; } free(filename); s->slave_bs[s->slave_count].bs = slave_bs; s->slave_bs[s->slave_count].start_sector = previous_start; previous_start = previous_start + s->slave_bs[s->slave_count].bs->total_sectors; s->slave_count++; if (slave_bs->read_only) { bs->read_only = 1; } } bs->total_sectors = previous_start; return 0; } static int composite_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVPartState *s = bs->opaque; int ret,sstart,send,i; sstart = -1; for (i = 0; i < s->slave_count; i++) { if ((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num) && (s->slave_bs[i].start_sector <= sector_num)) { sstart = i; break; } } if (sstart == -1) return -1; send = -1; for (i = 0; i < s->slave_count; i++) { if((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num+nb_sectors) && (s->slave_bs[i].start_sector <= sector_num+nb_sectors)) { send = i; break; } } if (send == -1) return -1; if (sstart > send) return -2; //wtf??? int a = 0, b = 0, bufpos = 0; i = sstart; while (i < send) { a = s->slave_bs[i].bs->total_sectors; ret = bdrv_read(s->slave_bs[i].bs, sector_num+b, &(buf[bufpos]), a); if (ret != 0) return ret; b = b+a; bufpos = bufpos + (a * 512); i++; } return bdrv_read(s->slave_bs[send].bs, sector_num+b, &(buf[bufpos]), nb_sectors-b); } static int composite_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVPartState *s = bs->opaque; int ret,sstart,send,i; sstart = -1; for (i = 0; i < s->slave_count; i++) { if ((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num) && (s->slave_bs[i].start_sector <= sector_num)) { sstart = i; break; } } if (sstart == -1) return -1; send = -1; for (i = 0; i < s->slave_count; i++) { if((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num+nb_sectors) && (s->slave_bs[i].start_sector <= sector_num+nb_sectors)) { send = i; break; } } if (send == -1) return -1; if (sstart > send) return -2; //wtf??? int a = 0, b = 0, bufpos = 0; i = sstart; while (i < send) { a = s->slave_bs[i].bs->total_sectors; ret = bdrv_write(s->slave_bs[i].bs, sector_num+b, &(buf[bufpos]), a); if (ret != 0) return ret; b = b+a; bufpos = bufpos + (a * 512); i++; } i= bdrv_write(s->slave_bs[send].bs, sector_num+b, &(buf[bufpos]), nb_sectors-b); return i; } static void composite_close(BlockDriverState *bs) { BDRVPartState *s = bs->opaque; int i; for (i = 0; i < s->slave_count; i++) { bdrv_close(s->slave_bs[i].bs); qemu_free(s->slave_bs[i].bs); } qemu_free(s->slave_bs); s->slave_bs = NULL; } static int composite_create(const char *filename, int64_t total_size, const char *backing_file, int flags) { /* what would be the point... just make a raw or qcow */ return -ENOTSUP; } BlockDriver bdrv_composite = { "composite", sizeof(BDRVPartState), composite_probe, composite_open, composite_read, composite_write, composite_close, composite_create, .protocol_name = "composite", };
/* * Block driver in RAM * * Copyright (c) 2007 Jim Boown * * 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" #include <assert.h> #ifndef QEMU_TOOL #include "exec-all.h" #endif typedef struct BDRVRamState { char * ram_data; } BDRVRamState; static int ram_probe(const uint8_t *buf, int buf_size, const char *filename) { if (strstart(filename, "ram:", NULL)) return 100; return 0; } static int ram_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRamState *s = bs->opaque; if (!strstart(filename, "ram:", NULL)) return -1; int sectnum = atoi(filename+4); if (sectnum == 0) return -2; s->ram_data = qemu_mallocz(sectnum*512); if (s->ram_data == NULL) return -2; memset(s->ram_data, ' ', sectnum*512); bs->total_sectors = sectnum; return 0; } static int ram_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVRamState *s = bs->opaque; if (sector_num+nb_sectors > bs->total_sectors) return -1; memcpy(buf, &(s->ram_data[sector_num*512]), nb_sectors*512); return 0; } static int ram_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVRamState *s = bs->opaque; if (sector_num+nb_sectors > bs->total_sectors) return -1; memcpy(&(s->ram_data[sector_num*512]), buf, nb_sectors*512); return 0; } static void ram_close(BlockDriverState *bs) { BDRVRamState *s = bs->opaque; qemu_free(s->ram_data); } static int ram_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int* n) { *n = bs->total_sectors - sector_num; if (*n > nb_sectors) *n = nb_sectors; else if (*n < 0) return 0; return 1; } BlockDriver bdrv_ram = { "ram", sizeof(BDRVRamState), ram_probe, ram_open, ram_read, ram_write, ram_close, NULL, NULL, ram_is_allocated, .protocol_name = "ram", };
/* * Block driver to use partitions as hard disks * * Copyright (c) 2007 Jim Brown * * 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. */ /* we need this in order to be able to figure out the sizes of the individual partitions */ #include "block_composite.h" /* in sectors */ #define MBR_SIZE 63 /* ideally this would be dynamically allocated */ #define MAX_PART_STRING 4096 typedef struct CompositeDriverState { BlockDriverState * bs; } CompositeDriverState; static int partition_probe(const uint8_t *buf, int buf_size, const char *filename) { if (strstart(filename, "partition:", NULL)) return 100; return 0; } static int partition_open(BlockDriverState *bs, const char *nfilename, int flags) { CompositeDriverState *s = bs->opaque; BlockDriverState * bbs; int64_t size, totalsectors; int boot_fd, i, bootid = 1, partition_count = 0; int head, cylinder, sector, oldstart; int oldhead, oldcylinder, oldsector; int sysid[10]; /* probably only need 4 */ const char * zfilename = &(nfilename[10]), * nptr = zfilename; char * filename, * strerr = NULL, * bootloader; char mbr_data[MBR_SIZE*512], partition_string[MAX_PART_STRING]; partition_string[0] = '\0'; strcat(partition_string, "composite:ram:63,"); /*63 == MBR_SIZE */ bootloader = strdup("bootmbr.bin"); bs->read_only = 0; int n = 0; while (nptr != NULL) { nptr = strchr(zfilename, ',')+1; if ((nptr-1) != NULL) { filename = strndup(zfilename, (size_t)((nptr-1)-zfilename)); zfilename = nptr; } else { filename = strdup(zfilename); nptr = NULL; } if (strncmp(filename, "sysid=", 6) == 0) { /* just pass in any sysid, e.g. 0x82 or 0x0C */ char ffd[strlen(filename)]; ffd[0] = ' '; ffd[1] = '\0'; strcat(ffd, filename+6); sysid[partition_count] = (int)strtol(ffd, &strerr, 0); if (*strerr != '\0') /* detect error in conversion */ sysid[partition_count-1] = 0x0C; /* default to win98 FAT32 */ } else if (strncmp(filename, "boot=", 5) == 0) { /* between 1 and 4, 1 selects the first partition, 4 selects the last partition (if you are making a hard disk with 4 partitions in it) */ char ffd[strlen(filename)]; int bootidf; ffd[0] = ' '; ffd[1] = '\0'; strcat(ffd, filename+5); bootidf = (int)strtol(ffd, &strerr, 0); if (*strerr == '\0') /* no detect error in conversion */ bootid = bootidf; } else if (strncmp(filename, "bootloader=", 11) == 0) { free(bootloader); bootloader = strdup(filename+11); } else { /* the string shouldn't start with a ',' */ if (n) strcat(partition_string, ","); else n = 1; strcat(partition_string, filename); partition_count ++; sysid[partition_count-1] = 0x0C; /* default to win98 FAT32 */ } free(filename); } s->bs = qemu_mallocz(sizeof(BlockDriverState)); if ((s->bs == NULL) || (bdrv_open2(s->bs, partition_string, 0, NULL) != 0)) { free(bootloader); return -1; } bs->total_sectors = s->bs->total_sectors; bs->read_only = s->bs->read_only; /* get the fake MBR */ memset(mbr_data, 0, MBR_SIZE*512); boot_fd = open(bootloader, O_RDONLY); if (boot_fd == -1) { printf("Warning: failed to open bootmbr.bin - MBR will not be bootable\n"); } else { if (read(boot_fd, mbr_data, MBR_SIZE*512) == -1) { printf("Warning: failed to read bootmbr.bin - MBR will not be bootable\n"); } close(boot_fd); } oldstart = 0x3F; //3F == 63 oldhead = 0x01; oldsector = 0x01; oldcylinder = 0x00; /* remember that the very first slave in the composite is the ram image ** * that we're using to store the MBR, so the second slave in the composite * is the first partition */ for (i = 1; i <= partition_count; i++) { /* set up c/h/s */ if (i == partition_count) { totalsectors = bs->total_sectors; } else { bbs = ((BDRVPartState*)s->bs->opaque)->slave_bs[i+1].bs; totalsectors = bbs->total_sectors; } size = totalsectors * 512; cylinder = size/(63*16); head = 16; sector = 63; /* some bit twiddling here */ sector = (((cylinder >> 8) & 3) << 6) + sector; /* set up fake MBR - each partition entry is 16 bytes long */ /* start 446 */ /* set which partition is meant to be bootable (that we'll boot from) */ if (i == bootid) mbr_data[446+((i-1)*16)] = 0x80; else mbr_data[446+((i-1)*16)] = 0x00; /* start head */ mbr_data[447+((i-1)*16)] = oldhead; /* start sector - only first 6 bits */ mbr_data[448+((i-1)*16)] = oldsector; /* start cylinder - this byte plus 2 bits from mbr_data[447] */ mbr_data[449+((i-1)*16)] = oldcylinder; /* system ID */ mbr_data[450+((i-1)*16)] = sysid[i-1]; /* ending head */ mbr_data[451+((i-1)*16)] = head; /* ending sector */ mbr_data[452+((i-1)*16)] = sector; /* ending cylinder */ mbr_data[453+((i-1)*16)] = cylinder; /* absolute start sector - 4 bytes/DWORD */ //mbr_data[454+(i*16)] = 0x3F; // 3F = 63 *((uint32_t*)(mbr_data+454+((i-1)*16))) = cpu_to_le32(oldstart); /* absolute total number of sectors - 4 bytes/DWORD */ *((uint32_t*)(mbr_data+458+((i-1)*16))) = cpu_to_le32(totalsectors); /* end 462 */ oldstart = oldstart + totalsectors; oldhead = head; oldcylinder = cylinder; oldsector = sector; oldsector++; if (oldsector > 63) { oldhead++; oldsector = 0x01; if (oldhead > 16) { oldcylinder++; oldhead = 0x01; } } } /* set the MBR sector signature */ mbr_data[510] = 0x55; mbr_data[511] = 0xAA; /* now write it to the ram image */ /* bs->boot_sector_enabled = 0; s->bs->boot_sector_enabled = 0; bbs = ((BDRVPartState*)s->bs->opaque)->slave_bs[0].bs; the ram image bbs->boot_sector_enabled = 0; */ if (bdrv_write(s->bs, 0, mbr_data, MBR_SIZE) != 0) printf("Warning: failed to commit MBR and partition table to fake hard disk\n"); return 0; } static int partition_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { CompositeDriverState *s = bs->opaque; return bdrv_read(s->bs, sector_num, buf, nb_sectors); } static int partition_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { CompositeDriverState *s = bs->opaque; return bdrv_write(s->bs, sector_num, buf, nb_sectors); } static void partition_close(BlockDriverState *bs) { CompositeDriverState *s = bs->opaque; bdrv_close(s->bs); qemu_free(s->bs); s->bs = NULL; } static int partition_create(const char *filename, int64_t total_size, const char *backing_file, int flags) { /* what would be the point... just make a raw or qcow */ return -ENOTSUP; } BlockDriver bdrv_partition = { "partition", sizeof(CompositeDriverState), partition_probe, partition_open, partition_read, partition_write, partition_close, partition_create, .protocol_name = "partition", };