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",
};

Reply via email to