[Top][All Lists]
[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",
};
- [Qemu-devel] block composite driver and partition driver,
jma5 <=