This is a preliminary patch that adds support for using a single partition
image as a hard disk image.

Syntax is: qemu -hdX part:file

E.g. qemu -hda part:/dev/hda1

qemu will see a hard disk with a single partition on it. Reading appears to work
ok, I haven't tested writing yet.

Writing to the MBR is allowed, but this is a bad idea as changes to the MBR
will be lost the moment qemu shuts down.

Known Issues:

booting is not supported - this will require passing a separate bootsector.
system id of the partition is always W95 FAT32 (LBA).
having multiple partition images in a single hard disk is not supported.

-- 
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.
--- vl.h        Sun May  7 23:24:35 2006
+++ vl.h        Sun May  7 23:24:47 2006
@@ -477,6 +477,7 @@
 extern BlockDriver bdrv_bochs;
 extern BlockDriver bdrv_vpc;
 extern BlockDriver bdrv_vvfat;
+extern BlockDriver bdrv_part_raw;
 
 void bdrv_init(void);
 BlockDriver *bdrv_find_format(const char *format_name);
--- Makefile.target     Sun May  7 23:25:52 2006
+++ Makefile.target     Sun May  7 23:26:04 2006
@@ -273,7 +273,7 @@
 
 # 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-part-raw.o
 ifdef CONFIG_WIN32
 VL_OBJS+=tap-win32.o
 endif
--- block.c     Sun May  7 23:22:40 2006
+++ block.c     Sun May  7 23:22:25 2006
@@ -794,4 +794,5 @@
     bdrv_register(&bdrv_bochs);
     bdrv_register(&bdrv_vpc);
     bdrv_register(&bdrv_vvfat);
+    bdrv_register(&bdrv_part_raw);
 }
--- Makefile    Sun May  7 23:38:56 2006
+++ Makefile    Sun May  7 23:16:20 2006
@@ -22,7 +22,7 @@
        $(MAKE) -C $$d $@ || exit 1 ; \
         done
 
-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-part-raw.c
        $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
 
 dyngen$(EXESUF): dyngen.c
--- /dev/null   Wed Apr 19 17:19:14 2006
+++ block-part-raw.c    Sun May  7 23:21:52 2006
@@ -0,0 +1,249 @@
+/*
+ * Block driver to use partition images instead of whole hard disk images
+ * 
+ * Copyright (c) 2006 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 "vl.h"
+#include "block_int.h"
+
+#ifdef __sun__
+#include <sys/dkio.h>
+#endif
+
+typedef struct BDRVPartRawState {
+    char mbr_data[63*512];
+    int fd;
+} BDRVPartRawState;
+
+static int part_raw_probe(const uint8_t *buf, int buf_size, const char 
*filename)
+{
+    if (strstart(filename, "part:", NULL))
+        return 100;
+    return 0;
+}
+
+static int part_raw_open(BlockDriverState *bs, const char *filename)
+{
+    BDRVPartRawState *s = bs->opaque;
+    int fd;
+    int64_t size;
+#ifdef _BSD
+    struct stat sb;
+#endif
+#ifdef __sun__
+    struct dk_minfo minfo;
+    int rv;
+#endif
+    int head, cylinder, sector;
+
+    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
+    if (fd < 0) {
+        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
+        if (fd < 0)
+            return -1;
+        bs->read_only = 1;
+    }
+#ifdef _BSD
+    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+       if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+#endif
+#ifdef CONFIG_COCOA
+        size = LONG_LONG_MAX;
+#else
+        size = lseek(fd, 0LL, SEEK_END);
+#endif
+    } else
+#endif
+#ifdef __sun__
+    /*
+     * use the DKIOCGMEDIAINFO ioctl to read the size.
+     */
+    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
+    if ( rv != -1 ) {
+        size = minfo.dki_lbsize * minfo.dki_capacity;
+    } else /* there are reports that lseek on some devices
+              fails, but irc discussion said that contingency
+              on contingency was overkill */
+#endif
+    {
+        size = lseek(fd, 0, SEEK_END);
+    }
+    bs->total_sectors = (size / 512) + 63;
+    s->fd = fd;
+
+    /* set up c/h/s */
+    size = size+(63*512);
+    cylinder = size/(63*16);
+    /* FIXME */
+    cylinder = cylinder + 1; /* add a cylinder just in case partition extends 
beyond the edge of the last cylinder/head/track */
+    head = 16;
+    sector = 63;
+    /* some bit twiddling here */
+    sector = (((cylinder >> 8) & 3) << 6) + sector;
+
+    /* set up fake MBR */
+    memset(s->mbr_data, 0, 63*512);
+    /* first partition is bootable */
+    s->mbr_data[446] = 0x80;
+    /* start head */
+    s->mbr_data[447] = 0x01;
+    /* start sector - only first 6 bits */
+    s->mbr_data[448] = 0x01;
+    /* start cylinder - this byte plus 2 bits from mbr_data[447] */
+    s->mbr_data[449] = 0x00;
+    /* system ID */
+    s->mbr_data[450] = 0x0C; /* say we're win98 fat32 */
+    /* ending head */
+    s->mbr_data[451] = head;
+    /* ending sector */
+    s->mbr_data[452] = sector;
+    /* ending cylinder */
+    s->mbr_data[453] = cylinder;
+    /* absolute start sector - 4 bytes/DWORD */
+    s->mbr_data[454] = 0x3F; // 3F = 63
+    /* absolute total number of sectors - 4 bytes/DWORD */
+    *((uint32_t*)(s->mbr_data+458)) = cpu_to_le32(bs->total_sectors - 63);
+    /* leave the other partitions blank - we only support the first one */
+
+    /* set the MBR sector signature */
+    s->mbr_data[510] = 0x55;
+    s->mbr_data[511] = 0xAA;
+
+    return 0;
+}
+
+static int part_raw_read(BlockDriverState *bs, int64_t sector_num, 
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVPartRawState *s = bs->opaque;
+    int ret,split;
+
+    if (sector_num >= 63)
+    {
+    
+    lseek(s->fd, (sector_num - 63) * 512, SEEK_SET);
+    ret = read(s->fd, buf, nb_sectors * 512);
+    if (ret != nb_sectors * 512) 
+        return -1;
+    return 0;
+
+    }
+    else
+    {
+
+    if ((nb_sectors + sector_num) > 63)
+    {
+       /* ah hell - we have to do both the fake part and the real part */
+
+       split = nb_sectors + sector_num - 63;
+       ret = part_raw_read(bs, 63, &buf[(nb_sectors-split)*512], split * 512);
+       if (ret != split * 512)
+           return -1;
+
+       /* this will always return 0 */
+       ret = part_raw_read(bs, sector_num, buf, (nb_sectors - split) * 512);
+       return 0;
+    }
+    else
+    {
+       memcpy(buf, &(s->mbr_data[sector_num*512]), nb_sectors*512);
+       return 0;
+    }
+
+    }
+}
+
+static int part_raw_write(BlockDriverState *bs, int64_t sector_num, 
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVPartRawState *s = bs->opaque;
+    int ret, split;
+
+    if (sector_num >= 63)
+    {
+    
+    lseek(s->fd, (sector_num - 63) * 512, SEEK_SET);
+    ret = write(s->fd, buf, nb_sectors * 512);
+    if (ret != nb_sectors * 512) 
+        return -1;
+    return 0;
+
+    }
+    else
+    {
+
+    if ((nb_sectors + sector_num) > 63)
+    {
+       /* ah hell - we have to do both the fake part and the real part */
+
+       split = nb_sectors + sector_num - 63;
+       ret = part_raw_write(bs, 63, &buf[(nb_sectors-split)*512], split * 512);
+       if (ret != split * 512)
+           return -1;
+
+       /* this will always return 0 */
+       ret = part_raw_write(bs, sector_num, buf, (nb_sectors - split) * 512);
+       return 0;
+    }
+    else
+    {
+       memcpy(&(s->mbr_data[sector_num*512]), buf, nb_sectors*512);
+       return 0;
+    }
+
+    }
+}
+
+static void part_raw_close(BlockDriverState *bs)
+{
+    BDRVPartRawState *s = bs->opaque;
+    close(s->fd);
+}
+
+static int part_raw_create(const char *filename, int64_t total_size,
+                      const char *backing_file, int flags)
+{
+    int fd;
+
+    if (flags || backing_file)
+        return -ENOTSUP;
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
+              0644);
+    if (fd < 0)
+        return -EIO;
+    ftruncate(fd, total_size * 512);
+    close(fd);
+    return 0;
+}
+
+BlockDriver bdrv_part_raw = {
+    "part_raw",
+    sizeof(BDRVPartRawState),
+    part_raw_probe,
+    part_raw_open,
+    part_raw_read,
+    part_raw_write,
+    part_raw_close,
+    part_raw_create,
+};
+
_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Reply via email to