mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'kwolf/for-anthony' into staging
* kwolf/for-anthony: (41 commits) fdc-test: Clean up a bit fdc-test: introduce test_relative_seek fdc: fix relative seek qemu-iotests: Valgrind support coroutine-ucontext: Help valgrind understand coroutines qemu-io: Fix memory leaks hw/block-common: Factor out fall back to legacy -drive cyls=... blockdev: Don't limit DriveInfo serial to 20 characters hw/block-common: Factor out fall back to legacy -drive serial=... hw/block-common: Move BlockConf & friends from block.h Relax IDE CHS limits from 16383,16,63 to 65535,16,255 blockdev: Drop redundant CHS validation for if=ide hd-geometry: Compute BIOS CHS translation in one place qtest: Test we don't put hard disk info into CMOS for a CD-ROM ide pc: Put hard disk info into CMOS only for hard disks block: Geometry and translation hints are now useless, purge them qtest: Cover qdev property for BIOS CHS translation ide: qdev property for BIOS CHS translation qdev: New property type chs-translation qdev: Collect private helpers in one place ...
This commit is contained in:
@@ -996,12 +996,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
bs_dest->block_timer = bs_src->block_timer;
|
||||
bs_dest->io_limits_enabled = bs_src->io_limits_enabled;
|
||||
|
||||
/* geometry */
|
||||
bs_dest->cyls = bs_src->cyls;
|
||||
bs_dest->heads = bs_src->heads;
|
||||
bs_dest->secs = bs_src->secs;
|
||||
bs_dest->translation = bs_src->translation;
|
||||
|
||||
/* r/w error */
|
||||
bs_dest->on_read_error = bs_src->on_read_error;
|
||||
bs_dest->on_write_error = bs_src->on_write_error;
|
||||
@@ -2132,148 +2126,6 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
|
||||
*nb_sectors_ptr = length;
|
||||
}
|
||||
|
||||
struct partition {
|
||||
uint8_t boot_ind; /* 0x80 - active */
|
||||
uint8_t head; /* starting head */
|
||||
uint8_t sector; /* starting sector */
|
||||
uint8_t cyl; /* starting cylinder */
|
||||
uint8_t sys_ind; /* What partition type */
|
||||
uint8_t end_head; /* end head */
|
||||
uint8_t end_sector; /* end sector */
|
||||
uint8_t end_cyl; /* end cylinder */
|
||||
uint32_t start_sect; /* starting sector counting from 0 */
|
||||
uint32_t nr_sects; /* nr of sectors in partition */
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
|
||||
static int guess_disk_lchs(BlockDriverState *bs,
|
||||
int *pcylinders, int *pheads, int *psectors)
|
||||
{
|
||||
uint8_t buf[BDRV_SECTOR_SIZE];
|
||||
int i, heads, sectors, cylinders;
|
||||
struct partition *p;
|
||||
uint32_t nr_sects;
|
||||
uint64_t nb_sectors;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
|
||||
/**
|
||||
* The function will be invoked during startup not only in sync I/O mode,
|
||||
* but also in async I/O mode. So the I/O throttling function has to
|
||||
* be disabled temporarily here, not permanently.
|
||||
*/
|
||||
if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* test msdos magic */
|
||||
if (buf[510] != 0x55 || buf[511] != 0xaa)
|
||||
return -1;
|
||||
for(i = 0; i < 4; i++) {
|
||||
p = ((struct partition *)(buf + 0x1be)) + i;
|
||||
nr_sects = le32_to_cpu(p->nr_sects);
|
||||
if (nr_sects && p->end_head) {
|
||||
/* We make the assumption that the partition terminates on
|
||||
a cylinder boundary */
|
||||
heads = p->end_head + 1;
|
||||
sectors = p->end_sector & 63;
|
||||
if (sectors == 0)
|
||||
continue;
|
||||
cylinders = nb_sectors / (heads * sectors);
|
||||
if (cylinders < 1 || cylinders > 16383)
|
||||
continue;
|
||||
*pheads = heads;
|
||||
*psectors = sectors;
|
||||
*pcylinders = cylinders;
|
||||
#if 0
|
||||
printf("guessed geometry: LCHS=%d %d %d\n",
|
||||
cylinders, heads, sectors);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs)
|
||||
{
|
||||
int translation, lba_detected = 0;
|
||||
int cylinders, heads, secs;
|
||||
uint64_t nb_sectors;
|
||||
|
||||
/* if a geometry hint is available, use it */
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs);
|
||||
translation = bdrv_get_translation_hint(bs);
|
||||
if (cylinders != 0) {
|
||||
*pcyls = cylinders;
|
||||
*pheads = heads;
|
||||
*psecs = secs;
|
||||
} else {
|
||||
if (guess_disk_lchs(bs, &cylinders, &heads, &secs) == 0) {
|
||||
if (heads > 16) {
|
||||
/* if heads > 16, it means that a BIOS LBA
|
||||
translation was active, so the default
|
||||
hardware geometry is OK */
|
||||
lba_detected = 1;
|
||||
goto default_geometry;
|
||||
} else {
|
||||
*pcyls = cylinders;
|
||||
*pheads = heads;
|
||||
*psecs = secs;
|
||||
/* disable any translation to be in sync with
|
||||
the logical geometry */
|
||||
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
bdrv_set_translation_hint(bs,
|
||||
BIOS_ATA_TRANSLATION_NONE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
default_geometry:
|
||||
/* if no geometry, use a standard physical disk geometry */
|
||||
cylinders = nb_sectors / (16 * 63);
|
||||
|
||||
if (cylinders > 16383)
|
||||
cylinders = 16383;
|
||||
else if (cylinders < 2)
|
||||
cylinders = 2;
|
||||
*pcyls = cylinders;
|
||||
*pheads = 16;
|
||||
*psecs = 63;
|
||||
if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) {
|
||||
if ((*pcyls * *pheads) <= 131072) {
|
||||
bdrv_set_translation_hint(bs,
|
||||
BIOS_ATA_TRANSLATION_LARGE);
|
||||
} else {
|
||||
bdrv_set_translation_hint(bs,
|
||||
BIOS_ATA_TRANSLATION_LBA);
|
||||
}
|
||||
}
|
||||
}
|
||||
bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_set_geometry_hint(BlockDriverState *bs,
|
||||
int cyls, int heads, int secs)
|
||||
{
|
||||
bs->cyls = cyls;
|
||||
bs->heads = heads;
|
||||
bs->secs = secs;
|
||||
}
|
||||
|
||||
void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
|
||||
{
|
||||
bs->translation = translation;
|
||||
}
|
||||
|
||||
void bdrv_get_geometry_hint(BlockDriverState *bs,
|
||||
int *pcyls, int *pheads, int *psecs)
|
||||
{
|
||||
*pcyls = bs->cyls;
|
||||
*pheads = bs->heads;
|
||||
*psecs = bs->secs;
|
||||
}
|
||||
|
||||
/* throttling disk io limits */
|
||||
void bdrv_set_io_limits(BlockDriverState *bs,
|
||||
BlockIOLimit *io_limits)
|
||||
@@ -2282,112 +2134,6 @@ void bdrv_set_io_limits(BlockDriverState *bs,
|
||||
bs->io_limits_enabled = bdrv_io_limits_enabled(bs);
|
||||
}
|
||||
|
||||
/* Recognize floppy formats */
|
||||
typedef struct FDFormat {
|
||||
FDriveType drive;
|
||||
uint8_t last_sect;
|
||||
uint8_t max_track;
|
||||
uint8_t max_head;
|
||||
FDriveRate rate;
|
||||
} FDFormat;
|
||||
|
||||
static const FDFormat fd_formats[] = {
|
||||
/* First entry is default format */
|
||||
/* 1.44 MB 3"1/2 floppy disks */
|
||||
{ FDRIVE_DRV_144, 18, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 20, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 21, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 21, 82, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 21, 83, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 22, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 23, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 24, 80, 1, FDRIVE_RATE_500K, },
|
||||
/* 2.88 MB 3"1/2 floppy disks */
|
||||
{ FDRIVE_DRV_288, 36, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 39, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 40, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 44, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 48, 80, 1, FDRIVE_RATE_1M, },
|
||||
/* 720 kB 3"1/2 floppy disks */
|
||||
{ FDRIVE_DRV_144, 9, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 10, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 10, 82, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 10, 83, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 13, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 14, 80, 1, FDRIVE_RATE_250K, },
|
||||
/* 1.2 MB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 15, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 18, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 18, 82, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 18, 83, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 20, 80, 1, FDRIVE_RATE_500K, },
|
||||
/* 720 kB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 9, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_120, 11, 80, 1, FDRIVE_RATE_250K, },
|
||||
/* 360 kB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 9, 40, 1, FDRIVE_RATE_300K, },
|
||||
{ FDRIVE_DRV_120, 9, 40, 0, FDRIVE_RATE_300K, },
|
||||
{ FDRIVE_DRV_120, 10, 41, 1, FDRIVE_RATE_300K, },
|
||||
{ FDRIVE_DRV_120, 10, 42, 1, FDRIVE_RATE_300K, },
|
||||
/* 320 kB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 8, 40, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_120, 8, 40, 0, FDRIVE_RATE_250K, },
|
||||
/* 360 kB must match 5"1/4 better than 3"1/2... */
|
||||
{ FDRIVE_DRV_144, 9, 80, 0, FDRIVE_RATE_250K, },
|
||||
/* end */
|
||||
{ FDRIVE_DRV_NONE, -1, -1, 0, 0, },
|
||||
};
|
||||
|
||||
void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
|
||||
int *max_track, int *last_sect,
|
||||
FDriveType drive_in, FDriveType *drive,
|
||||
FDriveRate *rate)
|
||||
{
|
||||
const FDFormat *parse;
|
||||
uint64_t nb_sectors, size;
|
||||
int i, first_match, match;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
match = -1;
|
||||
first_match = -1;
|
||||
for (i = 0; ; i++) {
|
||||
parse = &fd_formats[i];
|
||||
if (parse->drive == FDRIVE_DRV_NONE) {
|
||||
break;
|
||||
}
|
||||
if (drive_in == parse->drive ||
|
||||
drive_in == FDRIVE_DRV_NONE) {
|
||||
size = (parse->max_head + 1) * parse->max_track *
|
||||
parse->last_sect;
|
||||
if (nb_sectors == size) {
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
if (first_match == -1) {
|
||||
first_match = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match == -1) {
|
||||
if (first_match == -1) {
|
||||
match = 1;
|
||||
} else {
|
||||
match = first_match;
|
||||
}
|
||||
parse = &fd_formats[match];
|
||||
}
|
||||
*nb_heads = parse->max_head + 1;
|
||||
*max_track = parse->max_track;
|
||||
*last_sect = parse->last_sect;
|
||||
*drive = parse->drive;
|
||||
*rate = parse->rate;
|
||||
}
|
||||
|
||||
int bdrv_get_translation_hint(BlockDriverState *bs)
|
||||
{
|
||||
return bs->translation;
|
||||
}
|
||||
|
||||
void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
|
||||
BlockErrorAction on_write_error)
|
||||
{
|
||||
|
||||
@@ -178,7 +178,6 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset);
|
||||
int64_t bdrv_getlength(BlockDriverState *bs);
|
||||
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
||||
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
int bdrv_commit_all(void);
|
||||
int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
@@ -258,36 +257,6 @@ int bdrv_has_zero_init(BlockDriverState *bs);
|
||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
int *pnum);
|
||||
|
||||
#define BIOS_ATA_TRANSLATION_AUTO 0
|
||||
#define BIOS_ATA_TRANSLATION_NONE 1
|
||||
#define BIOS_ATA_TRANSLATION_LBA 2
|
||||
#define BIOS_ATA_TRANSLATION_LARGE 3
|
||||
#define BIOS_ATA_TRANSLATION_RECHS 4
|
||||
|
||||
void bdrv_set_geometry_hint(BlockDriverState *bs,
|
||||
int cyls, int heads, int secs);
|
||||
void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
|
||||
void bdrv_get_geometry_hint(BlockDriverState *bs,
|
||||
int *pcyls, int *pheads, int *psecs);
|
||||
typedef enum FDriveType {
|
||||
FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */
|
||||
FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */
|
||||
FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */
|
||||
FDRIVE_DRV_NONE = 0x03, /* No drive connected */
|
||||
} FDriveType;
|
||||
|
||||
typedef enum FDriveRate {
|
||||
FDRIVE_RATE_500K = 0x00, /* 500 Kbps */
|
||||
FDRIVE_RATE_300K = 0x01, /* 300 Kbps */
|
||||
FDRIVE_RATE_250K = 0x02, /* 250 Kbps */
|
||||
FDRIVE_RATE_1M = 0x03, /* 1 Mbps */
|
||||
} FDriveRate;
|
||||
|
||||
void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
|
||||
int *max_track, int *last_sect,
|
||||
FDriveType drive_in, FDriveType *drive,
|
||||
FDriveRate *rate);
|
||||
int bdrv_get_translation_hint(BlockDriverState *bs);
|
||||
void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
|
||||
BlockErrorAction on_write_error);
|
||||
BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
|
||||
@@ -434,43 +403,4 @@ typedef enum {
|
||||
#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
|
||||
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
|
||||
|
||||
|
||||
/* Convenience for block device models */
|
||||
|
||||
typedef struct BlockConf {
|
||||
BlockDriverState *bs;
|
||||
uint16_t physical_block_size;
|
||||
uint16_t logical_block_size;
|
||||
uint16_t min_io_size;
|
||||
uint32_t opt_io_size;
|
||||
int32_t bootindex;
|
||||
uint32_t discard_granularity;
|
||||
} BlockConf;
|
||||
|
||||
static inline unsigned int get_physical_block_exp(BlockConf *conf)
|
||||
{
|
||||
unsigned int exp = 0, size;
|
||||
|
||||
for (size = conf->physical_block_size;
|
||||
size > conf->logical_block_size;
|
||||
size >>= 1) {
|
||||
exp++;
|
||||
}
|
||||
|
||||
return exp;
|
||||
}
|
||||
|
||||
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
|
||||
DEFINE_PROP_DRIVE("drive", _state, _conf.bs), \
|
||||
DEFINE_PROP_BLOCKSIZE("logical_block_size", _state, \
|
||||
_conf.logical_block_size, 512), \
|
||||
DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \
|
||||
_conf.physical_block_size, 512), \
|
||||
DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \
|
||||
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \
|
||||
DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \
|
||||
DEFINE_PROP_UINT32("discard_granularity", _state, \
|
||||
_conf.discard_granularity, 0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+65
-85
@@ -498,26 +498,6 @@ success:
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int send_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = qemu_send_full(sockfd, hdr, sizeof(*hdr), 0);
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ret = qemu_send_full(sockfd, data, *wlen, 0);
|
||||
if (ret < *wlen) {
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen)
|
||||
{
|
||||
@@ -537,49 +517,6 @@ static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen, unsigned int *rlen);
|
||||
|
||||
static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen, unsigned int *rlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
return do_co_req(sockfd, hdr, data, wlen, rlen);
|
||||
}
|
||||
|
||||
socket_set_block(sockfd);
|
||||
ret = send_req(sockfd, hdr, data, wlen);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qemu_recv_full(sockfd, hdr, sizeof(*hdr), 0);
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to get a rsp, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*rlen > hdr->data_length) {
|
||||
*rlen = hdr->data_length;
|
||||
}
|
||||
|
||||
if (*rlen) {
|
||||
ret = qemu_recv_full(sockfd, data, *rlen, 0);
|
||||
if (ret < *rlen) {
|
||||
error_report("failed to get the data, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
socket_set_nonblock(sockfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void restart_co_req(void *opaque)
|
||||
{
|
||||
Coroutine *co = opaque;
|
||||
@@ -587,11 +524,26 @@ static void restart_co_req(void *opaque)
|
||||
qemu_coroutine_enter(co, NULL);
|
||||
}
|
||||
|
||||
static coroutine_fn int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen, unsigned int *rlen)
|
||||
typedef struct SheepdogReqCo {
|
||||
int sockfd;
|
||||
SheepdogReq *hdr;
|
||||
void *data;
|
||||
unsigned int *wlen;
|
||||
unsigned int *rlen;
|
||||
int ret;
|
||||
bool finished;
|
||||
} SheepdogReqCo;
|
||||
|
||||
static coroutine_fn void do_co_req(void *opaque)
|
||||
{
|
||||
int ret;
|
||||
Coroutine *co;
|
||||
SheepdogReqCo *srco = opaque;
|
||||
int sockfd = srco->sockfd;
|
||||
SheepdogReq *hdr = srco->hdr;
|
||||
void *data = srco->data;
|
||||
unsigned int *wlen = srco->wlen;
|
||||
unsigned int *rlen = srco->rlen;
|
||||
|
||||
co = qemu_coroutine_self();
|
||||
qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, NULL, co);
|
||||
@@ -627,7 +579,36 @@ static coroutine_fn int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
out:
|
||||
qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL);
|
||||
socket_set_nonblock(sockfd);
|
||||
return ret;
|
||||
|
||||
srco->ret = ret;
|
||||
srco->finished = true;
|
||||
}
|
||||
|
||||
static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen, unsigned int *rlen)
|
||||
{
|
||||
Coroutine *co;
|
||||
SheepdogReqCo srco = {
|
||||
.sockfd = sockfd,
|
||||
.hdr = hdr,
|
||||
.data = data,
|
||||
.wlen = wlen,
|
||||
.rlen = rlen,
|
||||
.ret = 0,
|
||||
.finished = false,
|
||||
};
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
do_co_req(&srco);
|
||||
} else {
|
||||
co = qemu_coroutine_create(do_co_req);
|
||||
qemu_coroutine_enter(co, &srco);
|
||||
while (!srco.finished) {
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
return srco.ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
@@ -1590,18 +1571,25 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
|
||||
len = MIN(total - done, SD_DATA_OBJ_SIZE - offset);
|
||||
|
||||
if (!inode->data_vdi_id[idx]) {
|
||||
if (acb->aiocb_type == AIOCB_READ_UDATA) {
|
||||
switch (acb->aiocb_type) {
|
||||
case AIOCB_READ_UDATA:
|
||||
if (!inode->data_vdi_id[idx]) {
|
||||
qemu_iovec_memset(acb->qiov, done, 0, len);
|
||||
goto done;
|
||||
}
|
||||
|
||||
create = 1;
|
||||
} else if (acb->aiocb_type == AIOCB_WRITE_UDATA
|
||||
&& !is_data_obj_writable(inode, idx)) {
|
||||
/* Copy-On-Write */
|
||||
create = 1;
|
||||
old_oid = oid;
|
||||
flags = SD_FLAG_CMD_COW;
|
||||
break;
|
||||
case AIOCB_WRITE_UDATA:
|
||||
if (!inode->data_vdi_id[idx]) {
|
||||
create = 1;
|
||||
} else if (!is_data_obj_writable(inode, idx)) {
|
||||
/* Copy-On-Write */
|
||||
create = 1;
|
||||
old_oid = oid;
|
||||
flags = SD_FLAG_CMD_COW;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (create) {
|
||||
@@ -1687,20 +1675,12 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
SheepdogAIOCB *acb;
|
||||
int i, ret;
|
||||
int ret;
|
||||
|
||||
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
|
||||
acb->aiocb_type = AIOCB_READ_UDATA;
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
|
||||
/*
|
||||
* TODO: we can do better; we don't need to initialize
|
||||
* blindly.
|
||||
*/
|
||||
for (i = 0; i < qiov->niov; i++) {
|
||||
memset(qiov->iov[i].iov_base, 0, qiov->iov[i].iov_len);
|
||||
}
|
||||
|
||||
ret = sd_co_rw_vector(acb);
|
||||
if (ret <= 0) {
|
||||
qemu_aio_release(acb);
|
||||
|
||||
+32
-26
@@ -359,11 +359,12 @@ typedef struct BDRVVVFATState {
|
||||
* if the position is outside the specified geometry, fill maximum value for CHS
|
||||
* and return 1 to signal overflow.
|
||||
*/
|
||||
static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
|
||||
static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
|
||||
{
|
||||
int head,sector;
|
||||
sector = spos % (bs->secs); spos/= bs->secs;
|
||||
head = spos % (bs->heads); spos/= bs->heads;
|
||||
if(spos >= bs->cyls){
|
||||
sector = spos % secs; spos /= secs;
|
||||
head = spos % heads; spos /= heads;
|
||||
if (spos >= cyls) {
|
||||
/* Overflow,
|
||||
it happens if 32bit sector positions are used, while CHS is only 24bit.
|
||||
Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
|
||||
@@ -378,7 +379,7 @@ static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_mbr(BDRVVVFATState* s)
|
||||
static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
|
||||
{
|
||||
/* TODO: if the files mbr.img and bootsect.img exist, use them */
|
||||
mbr_t* real_mbr=(mbr_t*)s->first_sectors;
|
||||
@@ -393,12 +394,15 @@ static void init_mbr(BDRVVVFATState* s)
|
||||
partition->attributes=0x80; /* bootable */
|
||||
|
||||
/* LBA is used when partition is outside the CHS geometry */
|
||||
lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
|
||||
lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
|
||||
lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
|
||||
cyls, heads, secs);
|
||||
lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
|
||||
cyls, heads, secs);
|
||||
|
||||
/*LBA partitions are identified only by start/length_sector_long not by CHS*/
|
||||
partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
|
||||
partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
|
||||
partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1);
|
||||
partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
|
||||
- s->first_sectors_number + 1);
|
||||
|
||||
/* FAT12/FAT16/FAT32 */
|
||||
/* DOS uses different types when partition is LBA,
|
||||
@@ -830,7 +834,7 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
|
||||
}
|
||||
|
||||
static int init_directories(BDRVVVFATState* s,
|
||||
const char* dirname)
|
||||
const char *dirname, int heads, int secs)
|
||||
{
|
||||
bootsector_t* bootsector;
|
||||
mapping_t* mapping;
|
||||
@@ -957,8 +961,8 @@ static int init_directories(BDRVVVFATState* s,
|
||||
bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
|
||||
s->fat.pointer[0] = bootsector->media_type;
|
||||
bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
|
||||
bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
|
||||
bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
|
||||
bootsector->sectors_per_track = cpu_to_le16(secs);
|
||||
bootsector->number_of_heads = cpu_to_le16(heads);
|
||||
bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
|
||||
bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
|
||||
|
||||
@@ -991,7 +995,7 @@ static void vvfat_rebind(BlockDriverState *bs)
|
||||
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int i;
|
||||
int i, cyls, heads, secs;
|
||||
|
||||
#ifdef DEBUG
|
||||
vvv = s;
|
||||
@@ -1033,24 +1037,28 @@ DLOG(if (stderr == NULL) {
|
||||
/* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
|
||||
if (!s->fat_type) {
|
||||
s->fat_type = 12;
|
||||
bs->secs = 36;
|
||||
secs = 36;
|
||||
s->sectors_per_cluster=2;
|
||||
} else {
|
||||
bs->secs=(s->fat_type == 12 ? 18 : 36);
|
||||
secs = s->fat_type == 12 ? 18 : 36;
|
||||
s->sectors_per_cluster=1;
|
||||
}
|
||||
s->first_sectors_number = 1;
|
||||
bs->cyls=80; bs->heads=2;
|
||||
cyls = 80;
|
||||
heads = 2;
|
||||
} else {
|
||||
/* 32MB or 504MB disk*/
|
||||
if (!s->fat_type) {
|
||||
s->fat_type = 16;
|
||||
}
|
||||
bs->cyls=(s->fat_type == 12 ? 64 : 1024);
|
||||
bs->heads=16; bs->secs=63;
|
||||
cyls = s->fat_type == 12 ? 64 : 1024;
|
||||
heads = 16;
|
||||
secs = 63;
|
||||
}
|
||||
fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
|
||||
dirname, cyls, heads, secs);
|
||||
|
||||
s->sector_count=bs->cyls*bs->heads*bs->secs-(s->first_sectors_number-1);
|
||||
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
|
||||
|
||||
if (strstr(dirname, ":rw:")) {
|
||||
if (enable_write_target(s))
|
||||
@@ -1066,18 +1074,16 @@ DLOG(if (stderr == NULL) {
|
||||
else
|
||||
dirname += i+1;
|
||||
|
||||
bs->total_sectors=bs->cyls*bs->heads*bs->secs;
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
if(init_directories(s, dirname))
|
||||
if (init_directories(s, dirname, heads, secs)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
|
||||
|
||||
if(s->first_sectors_number==0x40)
|
||||
init_mbr(s);
|
||||
else {
|
||||
/* MS-DOS does not like to know about CHS (?). */
|
||||
bs->heads = bs->cyls = bs->secs = 0;
|
||||
if (s->first_sectors_number == 0x40) {
|
||||
init_mbr(s, cyls, heads, secs);
|
||||
}
|
||||
|
||||
// assert(is_consistent(s));
|
||||
|
||||
@@ -320,7 +320,6 @@ struct BlockDriverState {
|
||||
|
||||
/* NOTE: the following infos are only hints for real hardware
|
||||
drivers. They are not used by the block driver */
|
||||
int cyls, heads, secs, translation;
|
||||
BlockErrorAction on_read_error, on_write_error;
|
||||
bool iostatus_enabled;
|
||||
BlockDeviceIoStatus iostatus;
|
||||
|
||||
+10
-18
@@ -7,8 +7,8 @@
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "block.h"
|
||||
#include "blockdev.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "monitor.h"
|
||||
#include "qerror.h"
|
||||
#include "qemu-option.h"
|
||||
@@ -330,15 +330,15 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
||||
max_devs = if_max_devs[type];
|
||||
|
||||
if (cyls || heads || secs) {
|
||||
if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
|
||||
if (cyls < 1) {
|
||||
error_report("invalid physical cyls number");
|
||||
return NULL;
|
||||
}
|
||||
if (heads < 1 || (type == IF_IDE && heads > 16)) {
|
||||
if (heads < 1) {
|
||||
error_report("invalid physical heads number");
|
||||
return NULL;
|
||||
}
|
||||
if (secs < 1 || (type == IF_IDE && secs > 63)) {
|
||||
if (secs < 1) {
|
||||
error_report("invalid physical secs number");
|
||||
return NULL;
|
||||
}
|
||||
@@ -530,11 +530,13 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
||||
dinfo->type = type;
|
||||
dinfo->bus = bus_id;
|
||||
dinfo->unit = unit_id;
|
||||
dinfo->cyls = cyls;
|
||||
dinfo->heads = heads;
|
||||
dinfo->secs = secs;
|
||||
dinfo->trans = translation;
|
||||
dinfo->opts = opts;
|
||||
dinfo->refcount = 1;
|
||||
if (serial) {
|
||||
pstrcpy(dinfo->serial, sizeof(dinfo->serial), serial);
|
||||
}
|
||||
dinfo->serial = serial;
|
||||
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
|
||||
|
||||
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
|
||||
@@ -547,17 +549,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
||||
case IF_SCSI:
|
||||
case IF_XEN:
|
||||
case IF_NONE:
|
||||
switch(media) {
|
||||
case MEDIA_DISK:
|
||||
if (cyls != 0) {
|
||||
bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
|
||||
bdrv_set_translation_hint(dinfo->bdrv, translation);
|
||||
}
|
||||
break;
|
||||
case MEDIA_CDROM:
|
||||
dinfo->media_cd = 1;
|
||||
break;
|
||||
}
|
||||
dinfo->media_cd = media == MEDIA_CDROM;
|
||||
break;
|
||||
case IF_SD:
|
||||
case IF_FLOPPY:
|
||||
|
||||
+2
-3
@@ -17,8 +17,6 @@
|
||||
void blockdev_mark_auto_del(BlockDriverState *bs);
|
||||
void blockdev_auto_del(BlockDriverState *bs);
|
||||
|
||||
#define BLOCK_SERIAL_STRLEN 20
|
||||
|
||||
typedef enum {
|
||||
IF_DEFAULT = -1, /* for use with drive_add() only */
|
||||
IF_NONE,
|
||||
@@ -35,8 +33,9 @@ struct DriveInfo {
|
||||
int unit;
|
||||
int auto_del; /* see blockdev_mark_auto_del() */
|
||||
int media_cd;
|
||||
int cyls, heads, secs, trans;
|
||||
QemuOpts *opts;
|
||||
char serial[BLOCK_SERIAL_STRLEN + 1];
|
||||
const char *serial;
|
||||
QTAILQ_ENTRY(DriveInfo) next;
|
||||
int refcount;
|
||||
};
|
||||
|
||||
@@ -2870,6 +2870,22 @@ if compile_prog "" "" ; then
|
||||
linux_magic_h=yes
|
||||
fi
|
||||
|
||||
########################################
|
||||
# check if we have valgrind/valgrind.h
|
||||
|
||||
valgrind_h=no
|
||||
cat > $TMPC << EOF
|
||||
#include <valgrind/valgrind.h>
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
int main(void) {
|
||||
VALGRIND_STACK_DEREGISTER(0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
valgrind_h=yes
|
||||
fi
|
||||
|
||||
########################################
|
||||
# check if environ is declared
|
||||
|
||||
@@ -3379,6 +3395,10 @@ if test "$linux_magic_h" = "yes" ; then
|
||||
echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$valgrind_h" = "yes" ; then
|
||||
echo "CONFIG_VALGRIND_H=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$has_environ" = "yes" ; then
|
||||
echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-coroutine-int.h"
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
#include <valgrind/valgrind.h>
|
||||
#endif
|
||||
|
||||
enum {
|
||||
/* Maximum free pool size prevents holding too many freed coroutines */
|
||||
POOL_MAX_SIZE = 64,
|
||||
@@ -43,6 +47,11 @@ typedef struct {
|
||||
Coroutine base;
|
||||
void *stack;
|
||||
jmp_buf env;
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
unsigned int valgrind_stack_id;
|
||||
#endif
|
||||
|
||||
} CoroutineUContext;
|
||||
|
||||
/**
|
||||
@@ -159,6 +168,11 @@ static Coroutine *coroutine_new(void)
|
||||
uc.uc_stack.ss_size = stack_size;
|
||||
uc.uc_stack.ss_flags = 0;
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
co->valgrind_stack_id =
|
||||
VALGRIND_STACK_REGISTER(co->stack, co->stack + stack_size);
|
||||
#endif
|
||||
|
||||
arg.p = co;
|
||||
|
||||
makecontext(&uc, (void (*)(void))coroutine_trampoline,
|
||||
@@ -185,6 +199,16 @@ Coroutine *qemu_coroutine_new(void)
|
||||
return co;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
/* Work around an unused variable in the valgrind.h macro... */
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
static inline void valgrind_stack_deregister(CoroutineUContext *co)
|
||||
{
|
||||
VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
|
||||
}
|
||||
#pragma GCC diagnostic error "-Wunused-but-set-variable"
|
||||
#endif
|
||||
|
||||
void qemu_coroutine_delete(Coroutine *co_)
|
||||
{
|
||||
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
|
||||
@@ -196,6 +220,10 @@ void qemu_coroutine_delete(Coroutine *co_)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
valgrind_stack_deregister(co);
|
||||
#endif
|
||||
|
||||
g_free(co->stack);
|
||||
g_free(co);
|
||||
}
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ common-obj-$(CONFIG_MAX111X) += max111x.o
|
||||
common-obj-$(CONFIG_DS1338) += ds1338.o
|
||||
common-obj-y += i2c.o smbus.o smbus_eeprom.o
|
||||
common-obj-y += eeprom93xx.o
|
||||
common-obj-y += scsi-disk.o cdrom.o
|
||||
common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o
|
||||
common-obj-y += scsi-generic.o scsi-bus.o
|
||||
common-obj-y += hid.o
|
||||
common-obj-$(CONFIG_SSI) += ssi.o
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Common code for block device models
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "blockdev.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "qemu-error.h"
|
||||
|
||||
void blkconf_serial(BlockConf *conf, char **serial)
|
||||
{
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (!*serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
if (dinfo->serial) {
|
||||
*serial = g_strdup(dinfo->serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int blkconf_geometry(BlockConf *conf, int *ptrans,
|
||||
unsigned cyls_max, unsigned heads_max, unsigned secs_max)
|
||||
{
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (!conf->cyls && !conf->heads && !conf->secs) {
|
||||
/* try to fall back to value set with legacy -drive cyls=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
conf->cyls = dinfo->cyls;
|
||||
conf->heads = dinfo->heads;
|
||||
conf->secs = dinfo->secs;
|
||||
if (ptrans) {
|
||||
*ptrans = dinfo->trans;
|
||||
}
|
||||
}
|
||||
if (!conf->cyls && !conf->heads && !conf->secs) {
|
||||
hd_geometry_guess(conf->bs,
|
||||
&conf->cyls, &conf->heads, &conf->secs,
|
||||
ptrans);
|
||||
} else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
*ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs);
|
||||
}
|
||||
if (conf->cyls || conf->heads || conf->secs) {
|
||||
if (conf->cyls < 1 || conf->cyls > cyls_max) {
|
||||
error_report("cyls must be between 1 and %u", cyls_max);
|
||||
return -1;
|
||||
}
|
||||
if (conf->heads < 1 || conf->heads > heads_max) {
|
||||
error_report("heads must be between 1 and %u", heads_max);
|
||||
return -1;
|
||||
}
|
||||
if (conf->secs < 1 || conf->secs > secs_max) {
|
||||
error_report("secs must be between 1 and %u", secs_max);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Common code for block device models
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_BLOCK_COMMON_H
|
||||
#define HW_BLOCK_COMMON_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
||||
/* Configuration */
|
||||
|
||||
typedef struct BlockConf {
|
||||
BlockDriverState *bs;
|
||||
uint16_t physical_block_size;
|
||||
uint16_t logical_block_size;
|
||||
uint16_t min_io_size;
|
||||
uint32_t opt_io_size;
|
||||
int32_t bootindex;
|
||||
uint32_t discard_granularity;
|
||||
/* geometry, not all devices use this */
|
||||
uint32_t cyls, heads, secs;
|
||||
} BlockConf;
|
||||
|
||||
static inline unsigned int get_physical_block_exp(BlockConf *conf)
|
||||
{
|
||||
unsigned int exp = 0, size;
|
||||
|
||||
for (size = conf->physical_block_size;
|
||||
size > conf->logical_block_size;
|
||||
size >>= 1) {
|
||||
exp++;
|
||||
}
|
||||
|
||||
return exp;
|
||||
}
|
||||
|
||||
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
|
||||
DEFINE_PROP_DRIVE("drive", _state, _conf.bs), \
|
||||
DEFINE_PROP_BLOCKSIZE("logical_block_size", _state, \
|
||||
_conf.logical_block_size, 512), \
|
||||
DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \
|
||||
_conf.physical_block_size, 512), \
|
||||
DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \
|
||||
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \
|
||||
DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \
|
||||
DEFINE_PROP_UINT32("discard_granularity", _state, \
|
||||
_conf.discard_granularity, 0)
|
||||
|
||||
#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf) \
|
||||
DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0), \
|
||||
DEFINE_PROP_UINT32("heads", _state, _conf.heads, 0), \
|
||||
DEFINE_PROP_UINT32("secs", _state, _conf.secs, 0)
|
||||
|
||||
/* Configuration helpers */
|
||||
|
||||
void blkconf_serial(BlockConf *conf, char **serial);
|
||||
int blkconf_geometry(BlockConf *conf, int *trans,
|
||||
unsigned cyls_max, unsigned heads_max, unsigned secs_max);
|
||||
|
||||
/* Hard disk geometry */
|
||||
|
||||
#define BIOS_ATA_TRANSLATION_AUTO 0
|
||||
#define BIOS_ATA_TRANSLATION_NONE 1
|
||||
#define BIOS_ATA_TRANSLATION_LBA 2
|
||||
#define BIOS_ATA_TRANSLATION_LARGE 3
|
||||
#define BIOS_ATA_TRANSLATION_RECHS 4
|
||||
|
||||
void hd_geometry_guess(BlockDriverState *bs,
|
||||
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
|
||||
int *ptrans);
|
||||
int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs);
|
||||
|
||||
#endif
|
||||
@@ -52,6 +52,113 @@
|
||||
/********************************************************/
|
||||
/* Floppy drive emulation */
|
||||
|
||||
typedef enum FDriveRate {
|
||||
FDRIVE_RATE_500K = 0x00, /* 500 Kbps */
|
||||
FDRIVE_RATE_300K = 0x01, /* 300 Kbps */
|
||||
FDRIVE_RATE_250K = 0x02, /* 250 Kbps */
|
||||
FDRIVE_RATE_1M = 0x03, /* 1 Mbps */
|
||||
} FDriveRate;
|
||||
|
||||
typedef struct FDFormat {
|
||||
FDriveType drive;
|
||||
uint8_t last_sect;
|
||||
uint8_t max_track;
|
||||
uint8_t max_head;
|
||||
FDriveRate rate;
|
||||
} FDFormat;
|
||||
|
||||
static const FDFormat fd_formats[] = {
|
||||
/* First entry is default format */
|
||||
/* 1.44 MB 3"1/2 floppy disks */
|
||||
{ FDRIVE_DRV_144, 18, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 20, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 21, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 21, 82, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 21, 83, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 22, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 23, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_144, 24, 80, 1, FDRIVE_RATE_500K, },
|
||||
/* 2.88 MB 3"1/2 floppy disks */
|
||||
{ FDRIVE_DRV_288, 36, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 39, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 40, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 44, 80, 1, FDRIVE_RATE_1M, },
|
||||
{ FDRIVE_DRV_288, 48, 80, 1, FDRIVE_RATE_1M, },
|
||||
/* 720 kB 3"1/2 floppy disks */
|
||||
{ FDRIVE_DRV_144, 9, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 10, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 10, 82, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 10, 83, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 13, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_144, 14, 80, 1, FDRIVE_RATE_250K, },
|
||||
/* 1.2 MB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 15, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 18, 80, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 18, 82, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 18, 83, 1, FDRIVE_RATE_500K, },
|
||||
{ FDRIVE_DRV_120, 20, 80, 1, FDRIVE_RATE_500K, },
|
||||
/* 720 kB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 9, 80, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_120, 11, 80, 1, FDRIVE_RATE_250K, },
|
||||
/* 360 kB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 9, 40, 1, FDRIVE_RATE_300K, },
|
||||
{ FDRIVE_DRV_120, 9, 40, 0, FDRIVE_RATE_300K, },
|
||||
{ FDRIVE_DRV_120, 10, 41, 1, FDRIVE_RATE_300K, },
|
||||
{ FDRIVE_DRV_120, 10, 42, 1, FDRIVE_RATE_300K, },
|
||||
/* 320 kB 5"1/4 floppy disks */
|
||||
{ FDRIVE_DRV_120, 8, 40, 1, FDRIVE_RATE_250K, },
|
||||
{ FDRIVE_DRV_120, 8, 40, 0, FDRIVE_RATE_250K, },
|
||||
/* 360 kB must match 5"1/4 better than 3"1/2... */
|
||||
{ FDRIVE_DRV_144, 9, 80, 0, FDRIVE_RATE_250K, },
|
||||
/* end */
|
||||
{ FDRIVE_DRV_NONE, -1, -1, 0, 0, },
|
||||
};
|
||||
|
||||
static void pick_geometry(BlockDriverState *bs, int *nb_heads,
|
||||
int *max_track, int *last_sect,
|
||||
FDriveType drive_in, FDriveType *drive,
|
||||
FDriveRate *rate)
|
||||
{
|
||||
const FDFormat *parse;
|
||||
uint64_t nb_sectors, size;
|
||||
int i, first_match, match;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
match = -1;
|
||||
first_match = -1;
|
||||
for (i = 0; ; i++) {
|
||||
parse = &fd_formats[i];
|
||||
if (parse->drive == FDRIVE_DRV_NONE) {
|
||||
break;
|
||||
}
|
||||
if (drive_in == parse->drive ||
|
||||
drive_in == FDRIVE_DRV_NONE) {
|
||||
size = (parse->max_head + 1) * parse->max_track *
|
||||
parse->last_sect;
|
||||
if (nb_sectors == size) {
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
if (first_match == -1) {
|
||||
first_match = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match == -1) {
|
||||
if (first_match == -1) {
|
||||
match = 1;
|
||||
} else {
|
||||
match = first_match;
|
||||
}
|
||||
parse = &fd_formats[match];
|
||||
}
|
||||
*nb_heads = parse->max_head + 1;
|
||||
*max_track = parse->max_track;
|
||||
*last_sect = parse->last_sect;
|
||||
*drive = parse->drive;
|
||||
*rate = parse->rate;
|
||||
}
|
||||
|
||||
#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
|
||||
#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
|
||||
|
||||
@@ -187,8 +294,8 @@ static void fd_revalidate(FDrive *drv)
|
||||
FLOPPY_DPRINTF("revalidate\n");
|
||||
if (drv->bs != NULL) {
|
||||
ro = bdrv_is_read_only(drv->bs);
|
||||
bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
|
||||
&last_sect, drv->drive, &drive, &rate);
|
||||
pick_geometry(drv->bs, &nb_heads, &max_track,
|
||||
&last_sect, drv->drive, &drive, &rate);
|
||||
if (!bdrv_is_inserted(drv->bs)) {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
} else {
|
||||
@@ -1695,7 +1802,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct
|
||||
}
|
||||
}
|
||||
|
||||
static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
|
||||
static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
|
||||
{
|
||||
FDrive *cur_drv;
|
||||
|
||||
@@ -1705,14 +1812,15 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
|
||||
fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
|
||||
cur_drv->sect, 1);
|
||||
} else {
|
||||
fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
|
||||
fd_seek(cur_drv, cur_drv->head,
|
||||
cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
|
||||
}
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
/* Raise Interrupt */
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
|
||||
static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
|
||||
{
|
||||
FDrive *cur_drv;
|
||||
|
||||
@@ -1721,7 +1829,8 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
|
||||
if (fdctrl->fifo[2] > cur_drv->track) {
|
||||
fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
|
||||
} else {
|
||||
fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
|
||||
fd_seek(cur_drv, cur_drv->head,
|
||||
cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
|
||||
}
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
/* Raise Interrupt */
|
||||
@@ -2054,18 +2163,13 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
|
||||
return fdctrl_init_common(fdctrl);
|
||||
}
|
||||
|
||||
void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev)
|
||||
FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
|
||||
{
|
||||
FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
|
||||
FDCtrl *fdctrl = &isa->state;
|
||||
int i;
|
||||
FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, fdc);
|
||||
|
||||
for (i = 0; i < MAX_FD; i++) {
|
||||
bs[i] = fdctrl->drives[i].bs;
|
||||
}
|
||||
return isa->state.drives[i].drive;
|
||||
}
|
||||
|
||||
|
||||
static const VMStateDescription vmstate_isa_fdc ={
|
||||
.name = "fdc",
|
||||
.version_id = 2,
|
||||
|
||||
@@ -6,11 +6,19 @@
|
||||
/* fdc.c */
|
||||
#define MAX_FD 2
|
||||
|
||||
typedef enum FDriveType {
|
||||
FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */
|
||||
FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */
|
||||
FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */
|
||||
FDRIVE_DRV_NONE = 0x03, /* No drive connected */
|
||||
} FDriveType;
|
||||
|
||||
ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds);
|
||||
void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
|
||||
target_phys_addr_t mmio_base, DriveInfo **fds);
|
||||
void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
|
||||
DriveInfo **fds, qemu_irq *fdc_tc);
|
||||
void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev);
|
||||
|
||||
FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Hard disk geometry utilities
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* 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.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "trace.h"
|
||||
|
||||
struct partition {
|
||||
uint8_t boot_ind; /* 0x80 - active */
|
||||
uint8_t head; /* starting head */
|
||||
uint8_t sector; /* starting sector */
|
||||
uint8_t cyl; /* starting cylinder */
|
||||
uint8_t sys_ind; /* What partition type */
|
||||
uint8_t end_head; /* end head */
|
||||
uint8_t end_sector; /* end sector */
|
||||
uint8_t end_cyl; /* end cylinder */
|
||||
uint32_t start_sect; /* starting sector counting from 0 */
|
||||
uint32_t nr_sects; /* nr of sectors in partition */
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* try to guess the disk logical geometry from the MSDOS partition table.
|
||||
Return 0 if OK, -1 if could not guess */
|
||||
static int guess_disk_lchs(BlockDriverState *bs,
|
||||
int *pcylinders, int *pheads, int *psectors)
|
||||
{
|
||||
uint8_t buf[BDRV_SECTOR_SIZE];
|
||||
int i, heads, sectors, cylinders;
|
||||
struct partition *p;
|
||||
uint32_t nr_sects;
|
||||
uint64_t nb_sectors;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
|
||||
/**
|
||||
* The function will be invoked during startup not only in sync I/O mode,
|
||||
* but also in async I/O mode. So the I/O throttling function has to
|
||||
* be disabled temporarily here, not permanently.
|
||||
*/
|
||||
if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* test msdos magic */
|
||||
if (buf[510] != 0x55 || buf[511] != 0xaa) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
p = ((struct partition *)(buf + 0x1be)) + i;
|
||||
nr_sects = le32_to_cpu(p->nr_sects);
|
||||
if (nr_sects && p->end_head) {
|
||||
/* We make the assumption that the partition terminates on
|
||||
a cylinder boundary */
|
||||
heads = p->end_head + 1;
|
||||
sectors = p->end_sector & 63;
|
||||
if (sectors == 0) {
|
||||
continue;
|
||||
}
|
||||
cylinders = nb_sectors / (heads * sectors);
|
||||
if (cylinders < 1 || cylinders > 16383) {
|
||||
continue;
|
||||
}
|
||||
*pheads = heads;
|
||||
*psectors = sectors;
|
||||
*pcylinders = cylinders;
|
||||
trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void guess_chs_for_size(BlockDriverState *bs,
|
||||
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
|
||||
{
|
||||
uint64_t nb_sectors;
|
||||
int cylinders;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
|
||||
cylinders = nb_sectors / (16 * 63);
|
||||
if (cylinders > 16383) {
|
||||
cylinders = 16383;
|
||||
} else if (cylinders < 2) {
|
||||
cylinders = 2;
|
||||
}
|
||||
*pcyls = cylinders;
|
||||
*pheads = 16;
|
||||
*psecs = 63;
|
||||
}
|
||||
|
||||
void hd_geometry_guess(BlockDriverState *bs,
|
||||
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
|
||||
int *ptrans)
|
||||
{
|
||||
int cylinders, heads, secs, translation;
|
||||
|
||||
if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
|
||||
/* no LCHS guess: use a standard physical disk geometry */
|
||||
guess_chs_for_size(bs, pcyls, pheads, psecs);
|
||||
translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
|
||||
} else if (heads > 16) {
|
||||
/* LCHS guess with heads > 16 means that a BIOS LBA
|
||||
translation was active, so a standard physical disk
|
||||
geometry is OK */
|
||||
guess_chs_for_size(bs, pcyls, pheads, psecs);
|
||||
translation = *pcyls * *pheads <= 131072
|
||||
? BIOS_ATA_TRANSLATION_LARGE
|
||||
: BIOS_ATA_TRANSLATION_LBA;
|
||||
} else {
|
||||
/* LCHS guess with heads <= 16: use as physical geometry */
|
||||
*pcyls = cylinders;
|
||||
*pheads = heads;
|
||||
*psecs = secs;
|
||||
/* disable any translation to be in sync with
|
||||
the logical geometry */
|
||||
translation = BIOS_ATA_TRANSLATION_NONE;
|
||||
}
|
||||
if (ptrans) {
|
||||
*ptrans = translation;
|
||||
}
|
||||
trace_hd_geometry_guess(bs, *pcyls, *pheads, *psecs, translation);
|
||||
}
|
||||
|
||||
int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
|
||||
{
|
||||
return cyls <= 1024 && heads <= 16 && secs <= 63
|
||||
? BIOS_ATA_TRANSLATION_NONE
|
||||
: BIOS_ATA_TRANSLATION_LBA;
|
||||
}
|
||||
@@ -29,7 +29,9 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
|
||||
qemu_irq irq, int shift,
|
||||
DriveInfo *hd0, DriveInfo *hd1);
|
||||
|
||||
void ide_get_bs(BlockDriverState *bs[], BusState *qbus);
|
||||
int ide_get_geometry(BusState *bus, int unit,
|
||||
int16_t *cyls, int8_t *heads, int8_t *secs);
|
||||
int ide_get_bios_chs_trans(BusState *bus, int unit);
|
||||
|
||||
/* ide/core.c */
|
||||
void ide_drive_get(DriveInfo **hd, int max_bus);
|
||||
|
||||
+31
-19
@@ -30,6 +30,7 @@
|
||||
#include "qemu-timer.h"
|
||||
#include "sysemu.h"
|
||||
#include "dma.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "blockdev.h"
|
||||
|
||||
#include <hw/ide/internal.h>
|
||||
@@ -1924,31 +1925,20 @@ static const BlockDevOps ide_cd_block_ops = {
|
||||
|
||||
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
||||
const char *version, const char *serial, const char *model,
|
||||
uint64_t wwn)
|
||||
uint64_t wwn,
|
||||
uint32_t cylinders, uint32_t heads, uint32_t secs,
|
||||
int chs_trans)
|
||||
{
|
||||
int cylinders, heads, secs;
|
||||
uint64_t nb_sectors;
|
||||
|
||||
s->bs = bs;
|
||||
s->drive_kind = kind;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
bdrv_guess_geometry(bs, &cylinders, &heads, &secs);
|
||||
if (cylinders < 1 || cylinders > 16383) {
|
||||
error_report("cyls must be between 1 and 16383");
|
||||
return -1;
|
||||
}
|
||||
if (heads < 1 || heads > 16) {
|
||||
error_report("heads must be between 1 and 16");
|
||||
return -1;
|
||||
}
|
||||
if (secs < 1 || secs > 63) {
|
||||
error_report("secs must be between 1 and 63");
|
||||
return -1;
|
||||
}
|
||||
s->cylinders = cylinders;
|
||||
s->heads = heads;
|
||||
s->sectors = secs;
|
||||
s->chs_trans = chs_trans;
|
||||
s->nb_sectors = nb_sectors;
|
||||
s->wwn = wwn;
|
||||
/* The SMART values should be preserved across power cycles
|
||||
@@ -2075,17 +2065,39 @@ void ide_init2(IDEBus *bus, qemu_irq irq)
|
||||
void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
|
||||
DriveInfo *hd1, qemu_irq irq)
|
||||
{
|
||||
int i;
|
||||
int i, trans;
|
||||
DriveInfo *dinfo;
|
||||
uint32_t cyls, heads, secs;
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
dinfo = i == 0 ? hd0 : hd1;
|
||||
ide_init1(bus, i);
|
||||
if (dinfo) {
|
||||
cyls = dinfo->cyls;
|
||||
heads = dinfo->heads;
|
||||
secs = dinfo->secs;
|
||||
trans = dinfo->trans;
|
||||
if (!cyls && !heads && !secs) {
|
||||
hd_geometry_guess(dinfo->bdrv, &cyls, &heads, &secs, &trans);
|
||||
} else if (trans == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
trans = hd_bios_chs_auto_trans(cyls, heads, secs);
|
||||
}
|
||||
if (cyls < 1 || cyls > 65535) {
|
||||
error_report("cyls must be between 1 and 65535");
|
||||
exit(1);
|
||||
}
|
||||
if (heads < 1 || heads > 16) {
|
||||
error_report("heads must be between 1 and 16");
|
||||
exit(1);
|
||||
}
|
||||
if (secs < 1 || secs > 255) {
|
||||
error_report("secs must be between 1 and 255");
|
||||
exit(1);
|
||||
}
|
||||
if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
|
||||
dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
|
||||
*dinfo->serial ? dinfo->serial : NULL,
|
||||
NULL, 0) < 0) {
|
||||
dinfo->media_cd ? IDE_CD : IDE_HD,
|
||||
NULL, dinfo->serial, NULL, 0,
|
||||
cyls, heads, secs, trans) < 0) {
|
||||
error_report("Can't set up IDE drive %s", dinfo->id);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+6
-2
@@ -11,6 +11,7 @@
|
||||
#include "iorange.h"
|
||||
#include "dma.h"
|
||||
#include "sysemu.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "hw/scsi-defs.h"
|
||||
|
||||
/* debug IDE devices */
|
||||
@@ -344,7 +345,7 @@ struct IDEState {
|
||||
uint8_t unit;
|
||||
/* ide config */
|
||||
IDEDriveKind drive_kind;
|
||||
int cylinders, heads, sectors;
|
||||
int cylinders, heads, sectors, chs_trans;
|
||||
int64_t nb_sectors;
|
||||
int mult_sectors;
|
||||
int identify_set;
|
||||
@@ -474,6 +475,7 @@ struct IDEDevice {
|
||||
DeviceState qdev;
|
||||
uint32_t unit;
|
||||
BlockConf conf;
|
||||
int chs_trans;
|
||||
char *version;
|
||||
char *serial;
|
||||
char *model;
|
||||
@@ -545,7 +547,9 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr);
|
||||
|
||||
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
||||
const char *version, const char *serial, const char *model,
|
||||
uint64_t wwn);
|
||||
uint64_t wwn,
|
||||
uint32_t cylinders, uint32_t heads, uint32_t secs,
|
||||
int chs_trans);
|
||||
void ide_init2(IDEBus *bus, qemu_irq irq);
|
||||
void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
|
||||
DriveInfo *hd1, qemu_irq irq);
|
||||
|
||||
+27
-14
@@ -21,6 +21,7 @@
|
||||
#include "qemu-error.h"
|
||||
#include <hw/ide/internal.h>
|
||||
#include "blockdev.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
/* --------------------------------- */
|
||||
@@ -111,11 +112,24 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
|
||||
return DO_UPCAST(IDEDevice, qdev, dev);
|
||||
}
|
||||
|
||||
void ide_get_bs(BlockDriverState *bs[], BusState *qbus)
|
||||
int ide_get_geometry(BusState *bus, int unit,
|
||||
int16_t *cyls, int8_t *heads, int8_t *secs)
|
||||
{
|
||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, qbus);
|
||||
bs[0] = bus->master ? bus->master->conf.bs : NULL;
|
||||
bs[1] = bus->slave ? bus->slave->conf.bs : NULL;
|
||||
IDEState *s = &DO_UPCAST(IDEBus, qbus, bus)->ifs[unit];
|
||||
|
||||
if (s->drive_kind != IDE_HD || !s->bs) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*cyls = s->cylinders;
|
||||
*heads = s->heads;
|
||||
*secs = s->sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ide_get_bios_chs_trans(BusState *bus, int unit)
|
||||
{
|
||||
return DO_UPCAST(IDEBus, qbus, bus)->ifs[unit].chs_trans;
|
||||
}
|
||||
|
||||
/* --------------------------------- */
|
||||
@@ -128,25 +142,21 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
|
||||
{
|
||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
|
||||
IDEState *s = bus->ifs + dev->unit;
|
||||
const char *serial;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
|
||||
error_report("discard_granularity must be 512 for ide");
|
||||
return -1;
|
||||
}
|
||||
|
||||
serial = dev->serial;
|
||||
if (!serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(dev->conf.bs);
|
||||
if (*dinfo->serial) {
|
||||
serial = dinfo->serial;
|
||||
}
|
||||
blkconf_serial(&dev->conf, &dev->serial);
|
||||
if (blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ide_init_drive(s, dev->conf.bs, kind,
|
||||
dev->version, serial, dev->model, dev->wwn) < 0) {
|
||||
dev->version, dev->serial, dev->model, dev->wwn,
|
||||
dev->conf.cyls, dev->conf.heads, dev->conf.secs,
|
||||
dev->chs_trans) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -189,6 +199,9 @@ static int ide_drive_initfn(IDEDevice *dev)
|
||||
|
||||
static Property ide_hd_properties[] = {
|
||||
DEFINE_IDE_DEV_PROPERTIES(),
|
||||
DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
|
||||
DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
|
||||
IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "kvm.h"
|
||||
#include "xen.h"
|
||||
#include "blockdev.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "memory.h"
|
||||
#include "exec-memory.h"
|
||||
@@ -216,11 +217,9 @@ static int cmos_get_fd_drive_type(FDriveType fd0)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd,
|
||||
ISADevice *s)
|
||||
static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs,
|
||||
int16_t cylinders, int8_t heads, int8_t sectors)
|
||||
{
|
||||
int cylinders, heads, sectors;
|
||||
bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors);
|
||||
rtc_set_memory(s, type_ofs, 47);
|
||||
rtc_set_memory(s, info_ofs, cylinders);
|
||||
rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
|
||||
@@ -281,48 +280,42 @@ static int pc_boot_set(void *opaque, const char *boot_device)
|
||||
|
||||
typedef struct pc_cmos_init_late_arg {
|
||||
ISADevice *rtc_state;
|
||||
BusState *idebus0, *idebus1;
|
||||
BusState *idebus[2];
|
||||
} pc_cmos_init_late_arg;
|
||||
|
||||
static void pc_cmos_init_late(void *opaque)
|
||||
{
|
||||
pc_cmos_init_late_arg *arg = opaque;
|
||||
ISADevice *s = arg->rtc_state;
|
||||
int16_t cylinders;
|
||||
int8_t heads, sectors;
|
||||
int val;
|
||||
BlockDriverState *hd_table[4];
|
||||
int i;
|
||||
int i, trans;
|
||||
|
||||
ide_get_bs(hd_table, arg->idebus0);
|
||||
ide_get_bs(hd_table + 2, arg->idebus1);
|
||||
|
||||
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
|
||||
if (hd_table[0])
|
||||
cmos_init_hd(0x19, 0x1b, hd_table[0], s);
|
||||
if (hd_table[1])
|
||||
cmos_init_hd(0x1a, 0x24, hd_table[1], s);
|
||||
val = 0;
|
||||
if (ide_get_geometry(arg->idebus[0], 0,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
|
||||
val |= 0xf0;
|
||||
}
|
||||
if (ide_get_geometry(arg->idebus[0], 1,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
|
||||
val |= 0x0f;
|
||||
}
|
||||
rtc_set_memory(s, 0x12, val);
|
||||
|
||||
val = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (hd_table[i]) {
|
||||
int cylinders, heads, sectors, translation;
|
||||
/* NOTE: bdrv_get_geometry_hint() returns the physical
|
||||
geometry. It is always such that: 1 <= sects <= 63, 1
|
||||
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
|
||||
geometry can be different if a translation is done. */
|
||||
translation = bdrv_get_translation_hint(hd_table[i]);
|
||||
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors);
|
||||
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
|
||||
/* No translation. */
|
||||
translation = 0;
|
||||
} else {
|
||||
/* LBA translation. */
|
||||
translation = 1;
|
||||
}
|
||||
} else {
|
||||
translation--;
|
||||
}
|
||||
val |= translation << (i * 2);
|
||||
/* NOTE: ide_get_geometry() returns the physical
|
||||
geometry. It is always such that: 1 <= sects <= 63, 1
|
||||
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
|
||||
geometry can be different if a translation is done. */
|
||||
if (ide_get_geometry(arg->idebus[i / 2], i % 2,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1;
|
||||
assert((trans & ~3) == 0);
|
||||
val |= trans << (i * 2);
|
||||
}
|
||||
}
|
||||
rtc_set_memory(s, 0x39, val);
|
||||
@@ -335,10 +328,8 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
ISADevice *floppy, BusState *idebus0, BusState *idebus1,
|
||||
ISADevice *s)
|
||||
{
|
||||
int val, nb, nb_heads, max_track, last_sect, i;
|
||||
int val, nb, i;
|
||||
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
|
||||
FDriveRate rate;
|
||||
BlockDriverState *fd[MAX_FD];
|
||||
static pc_cmos_init_late_arg arg;
|
||||
|
||||
/* various important CMOS locations needed by PC/Bochs bios */
|
||||
@@ -381,13 +372,8 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
|
||||
/* floppy type */
|
||||
if (floppy) {
|
||||
fdc_get_bs(fd, floppy);
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (fd[i]) {
|
||||
bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
|
||||
&last_sect, FDRIVE_DRV_NONE,
|
||||
&fd_type[i], &rate);
|
||||
}
|
||||
fd_type[i] = isa_fdc_get_drive_type(floppy, i);
|
||||
}
|
||||
}
|
||||
val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
|
||||
@@ -418,8 +404,8 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
|
||||
/* hard drives */
|
||||
arg.rtc_state = s;
|
||||
arg.idebus0 = idebus0;
|
||||
arg.idebus1 = idebus1;
|
||||
arg.idebus[0] = idebus0;
|
||||
arg.idebus[1] = idebus1;
|
||||
qemu_register_reset(pc_cmos_init_late, &arg);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user