qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] block composite driver and partition driver


From: jma5
Subject: [Qemu-devel] block composite driver and partition driver
Date: Tue, 30 Jan 2007 11:24:42 -0500 (EST)

I've finally gotten around to working on my multipart driver again.

block-composite.c is the basic low level composite image format, which lets you
use a bunch of disk images as a single image.

block-ram.c is a ram block device, with the size of the "image" given in the
number of disk sectors.

block-partition.c is a partition block device that uses the composite driver
to combine partitions together along with a fake mbr that it generates and
stores inside of a ram block device. (It doesn't work yet - for some reason the
number of cylinders being reported to the guest OS is 0.)

--
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.
/*
 * 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 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 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, 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 = (char*)0xF001F001;
    char mbr_data[MBR_SIZE*512], partition_string[MAX_PART_STRING];
    partition_string[0] = '\0';

    strcat(partition_string, "composite:ram:63"); /*63 == MBR_SIZE */
    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)
        {
                sysid[partition_count] = (int)strtol(filename+6, 
(char**)&stderr, 16);

                if (filename+6 == strerr) /* detect error in conversion */
                        sysid[partition_count] = 0x0C; /* default to win98 
FAT32 */
        }
        else
        {
                /* the string shouldn't start with a ',' */
                if (n)
                        strcat(partition_string, ",");
                else
                        n = 1;

                strcat(partition_string, filename);
                partition_count ++;
        }
        free(filename);
    }

    s->bs = qemu_mallocz(sizeof(BlockDriverState));
    if (bdrv_open2(s->bs, partition_string, 0, NULL) != 0)
            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("bootmbr.bin", 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, 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++)
    {

    bbs = ((BDRVPartState*)s->bs->opaque)->slave_bs[i+1].bs;
    /* set up c/h/s */
    if (i == partition_count)
    totalsectors = bs->total_sectors;
    else
    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 */
    /* first partition is bootable */
    if (i == 0)
    mbr_data[446+(i*16)] = 0x80;
    else
    mbr_data[446+(i*16)] = 0x00;
    /* start head */
    mbr_data[447+(i*16)] = oldhead;
    /* start sector - only first 6 bits */
    mbr_data[448+(i*16)] = oldsector;
    /* start cylinder - this byte plus 2 bits from mbr_data[447] */
    mbr_data[449+(i*16)] = oldcylinder;
    /* system ID */
    mbr_data[450+(i*16)] = 0x0C; /* say we're win98 fat32 */
    /* ending head */
    mbr_data[451+(i*16)] = head;
    /* ending sector */
    mbr_data[452+(i*16)] = sector;
    /* ending cylinder */
    mbr_data[453+(i*16)] = cylinder;
    /* absolute start sector - 4 bytes/DWORD */
    //mbr_data[454+(i*16)] = 0x3F; // 3F = 63
    *((uint32_t*)(mbr_data+454+(i*16))) = cpu_to_le32(oldstart);
    /* absolute total number of sectors - 4 bytes/DWORD */
    *((uint32_t*)(mbr_data+458+(i*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 */
    bdrv_write(s->bs, 0, mbr_data, MBR_SIZE);

    bs->cyls = cylinder;
    bs->heads = head;
    bs->secs = sector;
    bs->translation = BIOS_ATA_TRANSLATION_NONE;

    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

[Prev in Thread] Current Thread [Next in Thread]