mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'origin/master' into xbox
This commit is contained in:
commit
bc0ec04f1f
|
@ -553,6 +553,7 @@ T: git git://github.com/kvaneesh/QEMU.git
|
|||
|
||||
virtio-blk
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Supported
|
||||
F: hw/virtio-blk*
|
||||
|
||||
|
@ -583,6 +584,7 @@ F: audio/
|
|||
|
||||
Block
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Supported
|
||||
F: block*
|
||||
F: block/
|
||||
|
|
4
Makefile
4
Makefile
|
@ -127,6 +127,8 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure
|
|||
$(SRC_PATH)/pixman/configure:
|
||||
(cd $(SRC_PATH)/pixman; autoreconf -v --install)
|
||||
|
||||
$(SUBDIR_RULES): libqemustub.a
|
||||
|
||||
$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) subdir-libdis
|
||||
|
||||
$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser
|
||||
|
@ -284,7 +286,7 @@ distclean: clean
|
|||
for d in $(TARGET_DIRS) $(QEMULIBS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
test -f pixman/config.log && make -C pixman distclean
|
||||
if test -f pixman/config.log; then make -C pixman distclean; fi
|
||||
|
||||
KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
|
||||
ar de en-us fi fr-be hr it lv nl pl ru th \
|
||||
|
|
|
@ -143,6 +143,9 @@ GENERATED_HEADERS += hmp-commands.h qmp-commands-old.h
|
|||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
# Workaround for http://gcc.gnu.org/PR55489, see configure.
|
||||
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
|
||||
|
||||
nested-vars += obj-y
|
||||
|
||||
# This resolves all nested paths, so it must come last
|
||||
|
|
|
@ -173,7 +173,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||
}
|
||||
|
||||
/* wait until next event */
|
||||
for (;;) {
|
||||
while (count > 0) {
|
||||
int timeout = blocking ? INFINITE : 0;
|
||||
int ret = WaitForMultipleObjects(count, events, FALSE, timeout);
|
||||
|
||||
|
@ -209,6 +209,9 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try again, but only call each handler once. */
|
||||
events[ret - WAIT_OBJECT_0] = events[--count];
|
||||
}
|
||||
|
||||
return progress;
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
common-obj-y += rng.o rng-random.o rng-egd.o
|
||||
common-obj-y += rng.o rng-egd.o
|
||||
common-obj-$(CONFIG_POSIX) += rng-random.o
|
||||
|
|
34
block.c
34
block.c
|
@ -787,7 +787,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||
BlockDriver *drv)
|
||||
{
|
||||
int ret;
|
||||
char tmp_filename[PATH_MAX];
|
||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||
char tmp_filename[PATH_MAX + 1];
|
||||
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
BlockDriverState *bs1;
|
||||
|
@ -3521,7 +3522,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
|||
|
||||
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
|
||||
{
|
||||
acb->pool->cancel(acb);
|
||||
acb->aiocb_info->cancel(acb);
|
||||
}
|
||||
|
||||
/* block I/O throttling */
|
||||
|
@ -3711,7 +3712,7 @@ static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
|
|||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static AIOPool bdrv_em_aio_pool = {
|
||||
static const AIOCBInfo bdrv_em_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlockDriverAIOCBSync),
|
||||
.cancel = bdrv_aio_cancel_em,
|
||||
};
|
||||
|
@ -3740,7 +3741,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
|||
{
|
||||
BlockDriverAIOCBSync *acb;
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque);
|
||||
acb->is_write = is_write;
|
||||
acb->qiov = qiov;
|
||||
acb->bounce = qemu_blockalign(bs, qiov->size);
|
||||
|
@ -3785,7 +3786,7 @@ static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
|
|||
qemu_aio_flush();
|
||||
}
|
||||
|
||||
static AIOPool bdrv_em_co_aio_pool = {
|
||||
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
|
||||
.cancel = bdrv_aio_co_cancel_em,
|
||||
};
|
||||
|
@ -3828,7 +3829,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
|||
Coroutine *co;
|
||||
BlockDriverAIOCBCoroutine *acb;
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||
acb->req.sector = sector_num;
|
||||
acb->req.nb_sectors = nb_sectors;
|
||||
acb->req.qiov = qiov;
|
||||
|
@ -3858,7 +3859,7 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
|||
Coroutine *co;
|
||||
BlockDriverAIOCBCoroutine *acb;
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||
co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
|
||||
qemu_coroutine_enter(co, acb);
|
||||
|
||||
|
@ -3884,7 +3885,7 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
|
|||
|
||||
trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||
acb->req.sector = sector_num;
|
||||
acb->req.nb_sectors = nb_sectors;
|
||||
co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
|
||||
|
@ -3904,18 +3905,13 @@ void bdrv_init_with_whitelist(void)
|
|||
bdrv_init();
|
||||
}
|
||||
|
||||
void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
|
||||
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BlockDriverAIOCB *acb;
|
||||
|
||||
if (pool->free_aiocb) {
|
||||
acb = pool->free_aiocb;
|
||||
pool->free_aiocb = acb->next;
|
||||
} else {
|
||||
acb = g_malloc0(pool->aiocb_size);
|
||||
acb->pool = pool;
|
||||
}
|
||||
acb = g_slice_alloc(aiocb_info->aiocb_size);
|
||||
acb->aiocb_info = aiocb_info;
|
||||
acb->bs = bs;
|
||||
acb->cb = cb;
|
||||
acb->opaque = opaque;
|
||||
|
@ -3924,10 +3920,8 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
|
|||
|
||||
void qemu_aio_release(void *p)
|
||||
{
|
||||
BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;
|
||||
AIOPool *pool = acb->pool;
|
||||
acb->next = pool->free_aiocb;
|
||||
pool->free_aiocb = acb;
|
||||
BlockDriverAIOCB *acb = p;
|
||||
g_slice_free1(acb->aiocb_info->aiocb_size, acb);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct BlkdebugAIOCB {
|
|||
|
||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
|
||||
|
||||
static AIOPool blkdebug_aio_pool = {
|
||||
static const AIOCBInfo blkdebug_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkdebugAIOCB),
|
||||
.cancel = blkdebug_aio_cancel,
|
||||
};
|
||||
|
@ -335,7 +335,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
||||
acb->ret = -error;
|
||||
|
||||
bh = qemu_bh_new(error_callback_bh, acb);
|
||||
|
|
|
@ -48,7 +48,7 @@ static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
}
|
||||
}
|
||||
|
||||
static AIOPool blkverify_aio_pool = {
|
||||
static const AIOCBInfo blkverify_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkverifyAIOCB),
|
||||
.cancel = blkverify_aio_cancel,
|
||||
};
|
||||
|
@ -233,7 +233,7 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
|||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
|
||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->bh = NULL;
|
||||
acb->is_write = is_write;
|
||||
|
|
|
@ -438,7 +438,7 @@ static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
// Do we have to implement canceling? Seems to work without...
|
||||
}
|
||||
|
||||
static AIOPool curl_aio_pool = {
|
||||
static const AIOCBInfo curl_aiocb_info = {
|
||||
.aiocb_size = sizeof(CURLAIOCB),
|
||||
.cancel = curl_aio_cancel,
|
||||
};
|
||||
|
@ -505,7 +505,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
|||
{
|
||||
CURLAIOCB *acb;
|
||||
|
||||
acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->qiov = qiov;
|
||||
acb->sector_num = sector_num;
|
||||
|
|
|
@ -388,7 +388,7 @@ static void qemu_gluster_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
}
|
||||
}
|
||||
|
||||
static AIOPool gluster_aio_pool = {
|
||||
static const AIOCBInfo gluster_aiocb_info = {
|
||||
.aiocb_size = sizeof(GlusterAIOCB),
|
||||
.cancel = qemu_gluster_aio_cancel,
|
||||
};
|
||||
|
@ -439,7 +439,7 @@ static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs,
|
|||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||
s->qemu_aio_count++;
|
||||
|
||||
acb = qemu_aio_get(&gluster_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
|
||||
acb->size = size;
|
||||
acb->ret = 0;
|
||||
acb->finished = NULL;
|
||||
|
@ -484,7 +484,7 @@ static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs,
|
|||
GlusterAIOCB *acb;
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
|
||||
acb = qemu_aio_get(&gluster_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
|
||||
acb->size = 0;
|
||||
acb->ret = 0;
|
||||
acb->finished = NULL;
|
||||
|
|
272
block/iscsi.c
272
block/iscsi.c
|
@ -65,13 +65,6 @@ typedef struct IscsiAIOCB {
|
|||
#endif
|
||||
} IscsiAIOCB;
|
||||
|
||||
struct IscsiTask {
|
||||
IscsiLun *iscsilun;
|
||||
BlockDriverState *bs;
|
||||
int status;
|
||||
int complete;
|
||||
};
|
||||
|
||||
static void
|
||||
iscsi_bh_cb(void *p)
|
||||
{
|
||||
|
@ -133,7 +126,7 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
}
|
||||
}
|
||||
|
||||
static AIOPool iscsi_aio_pool = {
|
||||
static const AIOCBInfo iscsi_aiocb_info = {
|
||||
.aiocb_size = sizeof(IscsiAIOCB),
|
||||
.cancel = iscsi_aio_cancel,
|
||||
};
|
||||
|
@ -234,7 +227,7 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
|||
uint64_t lba;
|
||||
struct iscsi_data data;
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
|
@ -325,7 +318,7 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||
|
||||
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||
trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
|
@ -380,7 +373,7 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||
iscsi_aio_read16_cb,
|
||||
NULL,
|
||||
|
@ -430,7 +423,7 @@ iscsi_aio_flush(BlockDriverState *bs,
|
|||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
IscsiAIOCB *acb;
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
acb->canceled = 0;
|
||||
|
@ -483,7 +476,7 @@ iscsi_aio_discard(BlockDriverState *bs,
|
|||
IscsiAIOCB *acb;
|
||||
struct unmap_list list[1];
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
acb->canceled = 0;
|
||||
|
@ -558,7 +551,7 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||
|
||||
assert(req == SG_IO);
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
acb->canceled = 0;
|
||||
|
@ -665,163 +658,6 @@ iscsi_getlength(BlockDriverState *bs)
|
|||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_readcapacity16 *rc16;
|
||||
struct scsi_task *task = command_data;
|
||||
|
||||
if (status != 0) {
|
||||
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
rc16 = scsi_datain_unmarshall(task);
|
||||
if (rc16 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->block_size = rc16->block_length;
|
||||
itask->iscsilun->num_blocks = rc16->returned_lba + 1;
|
||||
itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
||||
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||||
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_readcapacity10 *rc10;
|
||||
struct scsi_task *task = command_data;
|
||||
|
||||
if (status != 0) {
|
||||
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
rc10 = scsi_datain_unmarshall(task);
|
||||
if (rc10 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->block_size = rc10->block_size;
|
||||
if (rc10->lba == 0) {
|
||||
/* blank disk loaded */
|
||||
itask->iscsilun->num_blocks = 0;
|
||||
} else {
|
||||
itask->iscsilun->num_blocks = rc10->lba + 1;
|
||||
}
|
||||
itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
||||
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||||
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_task *task = command_data;
|
||||
struct scsi_inquiry_standard *inq;
|
||||
|
||||
if (status != 0) {
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
inq = scsi_datain_unmarshall(task);
|
||||
if (inq == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->type = inq->periperal_device_type;
|
||||
|
||||
scsi_free_scsi_task(task);
|
||||
|
||||
switch (itask->iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
||||
iscsi_readcapacity16_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
|
||||
0, 0,
|
||||
iscsi_readcapacity10_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_task *task;
|
||||
|
||||
if (status != 0) {
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
|
||||
0, 0, 36,
|
||||
iscsi_inquiry_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send inquiry command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
||||
{
|
||||
QemuOptsList *list;
|
||||
|
@ -934,7 +770,10 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct iscsi_context *iscsi = NULL;
|
||||
struct iscsi_url *iscsi_url = NULL;
|
||||
struct IscsiTask task;
|
||||
struct scsi_task *task = NULL;
|
||||
struct scsi_inquiry_standard *inq = NULL;
|
||||
struct scsi_readcapacity10 *rc10 = NULL;
|
||||
struct scsi_readcapacity16 *rc16 = NULL;
|
||||
char *initiator_name = NULL;
|
||||
int ret;
|
||||
|
||||
|
@ -947,8 +786,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||
|
||||
iscsi_url = iscsi_parse_full_url(iscsi, filename);
|
||||
if (iscsi_url == NULL) {
|
||||
error_report("Failed to parse URL : %s %s", filename,
|
||||
iscsi_get_error(iscsi));
|
||||
error_report("Failed to parse URL : %s", filename);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -998,33 +836,80 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||
/* check if we got HEADER_DIGEST via the options */
|
||||
parse_header_digest(iscsi, iscsi_url->target);
|
||||
|
||||
task.iscsilun = iscsilun;
|
||||
task.status = 0;
|
||||
task.complete = 0;
|
||||
task.bs = bs;
|
||||
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
|
||||
error_report("iSCSI: Failed to connect to LUN : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iscsilun->iscsi = iscsi;
|
||||
iscsilun->lun = iscsi_url->lun;
|
||||
|
||||
if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
|
||||
iscsi_connect_cb, &task)
|
||||
!= 0) {
|
||||
error_report("iSCSI: Failed to start async connect.");
|
||||
task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
|
||||
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI: failed to send inquiry command.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!task.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
if (task.status != 0) {
|
||||
error_report("iSCSI: Failed to connect to LUN : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
inq = scsi_datain_unmarshall(task);
|
||||
if (inq == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iscsilun->type = inq->periperal_device_type;
|
||||
|
||||
scsi_free_scsi_task(task);
|
||||
|
||||
switch (iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
rc16 = scsi_datain_unmarshall(task);
|
||||
if (rc16 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
iscsilun->block_size = rc16->block_length;
|
||||
iscsilun->num_blocks = rc16->returned_lba + 1;
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI: failed to send readcapacity10 command.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
rc10 = scsi_datain_unmarshall(task);
|
||||
if (rc10 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
iscsilun->block_size = rc10->block_size;
|
||||
if (rc10->lba == 0) {
|
||||
/* blank disk loaded */
|
||||
iscsilun->num_blocks = 0;
|
||||
} else {
|
||||
iscsilun->num_blocks = rc10->lba + 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bs->total_sectors = iscsilun->num_blocks *
|
||||
iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||||
|
||||
/* Medium changer or tape. We dont have any emulation for this so this must
|
||||
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
||||
* to read from the device to guess the image format.
|
||||
|
@ -1043,6 +928,9 @@ out:
|
|||
if (iscsi_url != NULL) {
|
||||
iscsi_destroy_url(iscsi_url);
|
||||
}
|
||||
if (task != NULL) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (iscsi != NULL) {
|
||||
|
@ -1063,6 +951,11 @@ static void iscsi_close(BlockDriverState *bs)
|
|||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
}
|
||||
|
||||
static int iscsi_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_iscsi = {
|
||||
.format_name = "iscsi",
|
||||
.protocol_name = "iscsi",
|
||||
|
@ -1078,6 +971,7 @@ static BlockDriver bdrv_iscsi = {
|
|||
.bdrv_aio_flush = iscsi_aio_flush,
|
||||
|
||||
.bdrv_aio_discard = iscsi_aio_discard,
|
||||
.bdrv_has_zero_init = iscsi_has_zero_init,
|
||||
|
||||
#ifdef __linux__
|
||||
.bdrv_ioctl = iscsi_ioctl,
|
||||
|
|
|
@ -140,7 +140,7 @@ static void laio_cancel(BlockDriverAIOCB *blockacb)
|
|||
}
|
||||
}
|
||||
|
||||
static AIOPool laio_pool = {
|
||||
static const AIOCBInfo laio_aiocb_info = {
|
||||
.aiocb_size = sizeof(struct qemu_laiocb),
|
||||
.cancel = laio_cancel,
|
||||
};
|
||||
|
@ -154,7 +154,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||
struct iocb *iocbs;
|
||||
off_t offset = sector_num * 512;
|
||||
|
||||
laiocb = qemu_aio_get(&laio_pool, bs, cb, opaque);
|
||||
laiocb = qemu_aio_get(&laio_aiocb_info, bs, cb, opaque);
|
||||
laiocb->nbytes = nb_sectors * 512;
|
||||
laiocb->ctx = s;
|
||||
laiocb->ret = -EINPROGRESS;
|
||||
|
|
|
@ -301,7 +301,8 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||
uint64_t last_table_size;
|
||||
uint64_t blocks_clusters;
|
||||
do {
|
||||
uint64_t table_clusters = size_to_clusters(s, table_size);
|
||||
uint64_t table_clusters =
|
||||
size_to_clusters(s, table_size * sizeof(uint64_t));
|
||||
blocks_clusters = 1 +
|
||||
((table_clusters + refcount_block_clusters - 1)
|
||||
/ refcount_block_clusters);
|
||||
|
|
|
@ -30,7 +30,7 @@ static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
}
|
||||
}
|
||||
|
||||
static AIOPool qed_aio_pool = {
|
||||
static const AIOCBInfo qed_aiocb_info = {
|
||||
.aiocb_size = sizeof(QEDAIOCB),
|
||||
.cancel = qed_aio_cancel,
|
||||
};
|
||||
|
@ -1311,7 +1311,7 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
|
|||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque, int flags)
|
||||
{
|
||||
QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
|
||||
QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
|
||||
|
||||
trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
|
||||
opaque, flags);
|
||||
|
|
|
@ -333,6 +333,10 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (s->type == FTYPE_FD || s->type == FTYPE_CD) {
|
||||
raw_s->open_flags |= O_NONBLOCK;
|
||||
}
|
||||
|
||||
raw_parse_flags(state->flags, &raw_s->open_flags);
|
||||
|
||||
raw_s->fd = -1;
|
||||
|
@ -1409,6 +1413,9 @@ static BlockDriver bdrv_host_device = {
|
|||
.bdrv_probe_device = hdev_probe_device,
|
||||
.bdrv_file_open = hdev_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
@ -1530,6 +1537,9 @@ static BlockDriver bdrv_host_floppy = {
|
|||
.bdrv_probe_device = floppy_probe_device,
|
||||
.bdrv_file_open = floppy_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
@ -1629,6 +1639,9 @@ static BlockDriver bdrv_host_cdrom = {
|
|||
.bdrv_probe_device = cdrom_probe_device,
|
||||
.bdrv_file_open = cdrom_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
@ -1748,6 +1761,9 @@ static BlockDriver bdrv_host_cdrom = {
|
|||
.bdrv_probe_device = cdrom_probe_device,
|
||||
.bdrv_file_open = cdrom_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
|
|
@ -69,7 +69,7 @@ typedef enum {
|
|||
typedef struct RBDAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int ret;
|
||||
int64_t ret;
|
||||
QEMUIOVector *qiov;
|
||||
char *bounce;
|
||||
RBDAIOCmd cmd;
|
||||
|
@ -86,7 +86,7 @@ typedef struct RADOSCB {
|
|||
int done;
|
||||
int64_t size;
|
||||
char *buf;
|
||||
int ret;
|
||||
int64_t ret;
|
||||
} RADOSCB;
|
||||
|
||||
#define RBD_FD_READ 0
|
||||
|
@ -570,7 +570,7 @@ static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
acb->cancelled = 1;
|
||||
}
|
||||
|
||||
static AIOPool rbd_aio_pool = {
|
||||
static const AIOCBInfo rbd_aiocb_info = {
|
||||
.aiocb_size = sizeof(RBDAIOCB),
|
||||
.cancel = qemu_rbd_aio_cancel,
|
||||
};
|
||||
|
@ -672,7 +672,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
|
||||
acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
|
||||
acb->cmd = cmd;
|
||||
acb->qiov = qiov;
|
||||
if (cmd == RBD_AIO_DISCARD) {
|
||||
|
|
|
@ -420,7 +420,7 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
acb->canceled = true;
|
||||
}
|
||||
|
||||
static AIOPool sd_aio_pool = {
|
||||
static const AIOCBInfo sd_aiocb_info = {
|
||||
.aiocb_size = sizeof(SheepdogAIOCB),
|
||||
.cancel = sd_aio_cancel,
|
||||
};
|
||||
|
@ -431,7 +431,7 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
|||
{
|
||||
SheepdogAIOCB *acb;
|
||||
|
||||
acb = qemu_aio_get(&sd_aio_pool, bs, cb, opaque);
|
||||
acb = qemu_aio_get(&sd_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->qiov = qiov;
|
||||
|
||||
|
|
|
@ -60,9 +60,6 @@
|
|||
/* TODO: move uuid emulation to some central place in QEMU. */
|
||||
#include "sysemu.h" /* UUID_FMT */
|
||||
typedef unsigned char uuid_t[16];
|
||||
void uuid_generate(uuid_t out);
|
||||
int uuid_is_null(const uuid_t uu);
|
||||
void uuid_unparse(const uuid_t uu, char *out);
|
||||
#endif
|
||||
|
||||
/* Code configuration options. */
|
||||
|
@ -124,18 +121,18 @@ void uuid_unparse(const uuid_t uu, char *out);
|
|||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||
|
||||
#if !defined(CONFIG_UUID)
|
||||
void uuid_generate(uuid_t out)
|
||||
static inline void uuid_generate(uuid_t out)
|
||||
{
|
||||
memset(out, 0, sizeof(uuid_t));
|
||||
}
|
||||
|
||||
int uuid_is_null(const uuid_t uu)
|
||||
static inline int uuid_is_null(const uuid_t uu)
|
||||
{
|
||||
uuid_t null_uuid = { 0 };
|
||||
return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
|
||||
}
|
||||
|
||||
void uuid_unparse(const uuid_t uu, char *out)
|
||||
static inline void uuid_unparse(const uuid_t uu, char *out)
|
||||
{
|
||||
snprintf(out, 37, UUID_FMT,
|
||||
uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
|
||||
|
|
10
block/vmdk.c
10
block/vmdk.c
|
@ -1092,6 +1092,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
|||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret;
|
||||
uint64_t n, index_in_cluster;
|
||||
uint64_t extent_begin_sector, extent_relative_sector_num;
|
||||
VmdkExtent *extent = NULL;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
|
@ -1103,7 +1104,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
|||
ret = get_cluster_offset(
|
||||
bs, extent, NULL,
|
||||
sector_num << 9, 0, &cluster_offset);
|
||||
index_in_cluster = sector_num % extent->cluster_sectors;
|
||||
extent_begin_sector = extent->end_sector - extent->sectors;
|
||||
extent_relative_sector_num = sector_num - extent_begin_sector;
|
||||
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
|
@ -1154,6 +1157,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
|||
VmdkExtent *extent = NULL;
|
||||
int n, ret;
|
||||
int64_t index_in_cluster;
|
||||
uint64_t extent_begin_sector, extent_relative_sector_num;
|
||||
uint64_t cluster_offset;
|
||||
VmdkMetaData m_data;
|
||||
|
||||
|
@ -1196,7 +1200,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
|||
if (ret) {
|
||||
return -EINVAL;
|
||||
}
|
||||
index_in_cluster = sector_num % extent->cluster_sectors;
|
||||
extent_begin_sector = extent->end_sector - extent->sectors;
|
||||
extent_relative_sector_num = sector_num - extent_begin_sector;
|
||||
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
|
|
|
@ -131,7 +131,7 @@ static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||
}
|
||||
}
|
||||
|
||||
static AIOPool win32_aio_pool = {
|
||||
static const AIOCBInfo win32_aiocb_info = {
|
||||
.aiocb_size = sizeof(QEMUWin32AIOCB),
|
||||
.cancel = win32_aio_cancel,
|
||||
};
|
||||
|
@ -145,7 +145,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
|||
uint64_t offset = sector_num * 512;
|
||||
DWORD rc;
|
||||
|
||||
waiocb = qemu_aio_get(&win32_aio_pool, bs, cb, opaque);
|
||||
waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque);
|
||||
waiocb->nbytes = nb_sectors * 512;
|
||||
waiocb->qiov = qiov;
|
||||
waiocb->is_read = (type == QEMU_AIO_READ);
|
||||
|
@ -167,11 +167,11 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
|||
waiocb->is_linear = true;
|
||||
}
|
||||
|
||||
waiocb->ov = (OVERLAPPED) {
|
||||
.Offset = (DWORD) offset,
|
||||
.OffsetHigh = (DWORD) (offset >> 32),
|
||||
.hEvent = event_notifier_get_handle(&aio->e)
|
||||
};
|
||||
memset(&waiocb->ov, 0, sizeof(waiocb->ov));
|
||||
waiocb->ov.Offset = (DWORD)offset;
|
||||
waiocb->ov.OffsetHigh = (DWORD)(offset >> 32);
|
||||
waiocb->ov.hEvent = event_notifier_get_handle(&aio->e);
|
||||
|
||||
aio->count++;
|
||||
|
||||
if (type & QEMU_AIO_READ) {
|
||||
|
|
|
@ -99,7 +99,7 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
|||
}
|
||||
|
||||
if (!has_writable) {
|
||||
writable = true;
|
||||
writable = false;
|
||||
}
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
writable = false;
|
||||
|
|
|
@ -1183,6 +1183,21 @@ for flag in $gcc_flags; do
|
|||
fi
|
||||
done
|
||||
|
||||
# Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and
|
||||
# large functions that use global variables. The bug is in all releases of
|
||||
# GCC, but it became particularly acute in 4.6.x and 4.7.x. It is fixed in
|
||||
# 4.7.3 and 4.8.0. We should be able to delete this at the end of 2013.
|
||||
cat > $TMPC << EOF
|
||||
#if __GNUC__ == 4 && (__GNUC_MINOR__ == 6 || (__GNUC_MINOR__ == 7 && __GNUC_PATCHLEVEL__ <= 2))
|
||||
int main(void) { return 0; }
|
||||
#else
|
||||
#error No bug in this compiler.
|
||||
#endif
|
||||
EOF
|
||||
if compile_prog "-Werror -fno-gcse" "" ; then
|
||||
TRANSLATE_OPT_CFLAGS=-fno-gcse
|
||||
fi
|
||||
|
||||
if test "$static" = "yes" ; then
|
||||
if test "$pie" = "yes" ; then
|
||||
echo "static and pie are mutually incompatible"
|
||||
|
@ -3675,6 +3690,7 @@ echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
|
|||
echo "EXESUF=$EXESUF" >> $config_host_mak
|
||||
echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
|
||||
echo "POD2MAN=$POD2MAN" >> $config_host_mak
|
||||
echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak
|
||||
|
||||
# generate list of library paths for linker script
|
||||
|
||||
|
|
|
@ -171,8 +171,8 @@ static Coroutine *coroutine_new(void)
|
|||
CoroutineThreadState *coTS;
|
||||
struct sigaction sa;
|
||||
struct sigaction osa;
|
||||
struct sigaltstack ss;
|
||||
struct sigaltstack oss;
|
||||
stack_t ss;
|
||||
stack_t oss;
|
||||
sigset_t sigs;
|
||||
sigset_t osigs;
|
||||
jmp_buf old_env;
|
||||
|
|
|
@ -195,7 +195,7 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb)
|
|||
dma_complete(dbs, 0);
|
||||
}
|
||||
|
||||
static AIOPool dma_aio_pool = {
|
||||
static const AIOCBInfo dma_aiocb_info = {
|
||||
.aiocb_size = sizeof(DMAAIOCB),
|
||||
.cancel = dma_aio_cancel,
|
||||
};
|
||||
|
@ -205,7 +205,7 @@ BlockDriverAIOCB *dma_bdrv_io(
|
|||
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
|
||||
void *opaque, DMADirection dir)
|
||||
{
|
||||
DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
|
||||
DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, bs, cb, opaque);
|
||||
|
||||
trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));
|
||||
|
||||
|
|
|
@ -139,6 +139,10 @@ having a common prefix in a batch. For example, virtio-blk trace events could
|
|||
be enabled using:
|
||||
trace-event virtio_blk_* on
|
||||
|
||||
If a line in the "-trace events=<file>" file begins with a '-', the trace event
|
||||
will be disabled instead of enabled. This is useful when a wildcard was used
|
||||
to enable an entire family of events but one noisy event needs to be disabled.
|
||||
|
||||
== Trace backends ==
|
||||
|
||||
The "tracetool" script automates tedious trace event code generation and also
|
||||
|
@ -185,15 +189,6 @@ records the char* pointer value instead of the string that is pointed to.
|
|||
|
||||
==== Monitor commands ====
|
||||
|
||||
* info trace
|
||||
Display the contents of trace buffer. This command dumps the trace buffer
|
||||
with simple formatting. For full pretty-printing, use the simpletrace.py
|
||||
script on a binary trace file.
|
||||
|
||||
The trace buffer is written into until full. The full trace buffer is
|
||||
flushed and emptied. This means the 'info trace' will display few or no
|
||||
entries if the buffer has just been flushed.
|
||||
|
||||
* trace-file on|off|flush|set <path>
|
||||
Enable/disable/flush the trace file or set the trace file name.
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
e->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
e->event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
assert(e->event);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <string.h>
|
||||
#include "qemu-fsdev.h"
|
||||
#include "qemu-config.h"
|
||||
#include "module.h"
|
||||
|
||||
int qemu_fsdev_add(QemuOpts *opts)
|
||||
{
|
||||
|
|
|
@ -1573,13 +1573,6 @@ show roms
|
|||
@end table
|
||||
ETEXI
|
||||
|
||||
#ifdef CONFIG_TRACE_SIMPLE
|
||||
STEXI
|
||||
@item info trace
|
||||
show contents of trace buffer
|
||||
ETEXI
|
||||
#endif
|
||||
|
||||
STEXI
|
||||
@item info trace-events
|
||||
show available trace events and their state
|
||||
|
|
|
@ -10,6 +10,7 @@ common-obj-$(CONFIG_PCI) += shpc.o
|
|||
common-obj-$(CONFIG_PCI) += slotid_cap.o
|
||||
common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
|
||||
common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
|
||||
common-obj-$(CONFIG_PCI) += i82801b11.o
|
||||
common-obj-y += watchdog.o
|
||||
common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
|
||||
common-obj-$(CONFIG_ECC) += ecc.o
|
||||
|
@ -28,7 +29,7 @@ common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
|
|||
common-obj-$(CONFIG_PCSPK) += pcspk.o
|
||||
common-obj-$(CONFIG_PCKBD) += pckbd.o
|
||||
common-obj-$(CONFIG_FDC) += fdc.o
|
||||
common-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
|
||||
common-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o acpi_ich9.o smbus_ich9.o
|
||||
common-obj-$(CONFIG_APM) += pm_smbus.o apm.o
|
||||
common-obj-$(CONFIG_DMA) += dma.o
|
||||
common-obj-$(CONFIG_I82374) += i82374.o
|
||||
|
@ -38,6 +39,7 @@ common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o
|
|||
common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
|
||||
common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
|
||||
common-obj-y += fifo.o
|
||||
common-obj-y += pam.o
|
||||
|
||||
# PPC devices
|
||||
common-obj-$(CONFIG_PREP_PCI) += prep_pci.o
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* ACPI implementation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This is based on acpi.c.
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "pci.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "sysemu.h"
|
||||
#include "acpi.h"
|
||||
#include "kvm.h"
|
||||
|
||||
#include "ich9.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ICH9_DEBUG(fmt, ...) \
|
||||
do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define ICH9_DEBUG(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
|
||||
uint32_t val);
|
||||
static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len);
|
||||
|
||||
static void pm_update_sci(ICH9LPCPMRegs *pm)
|
||||
{
|
||||
int sci_level, pm1a_sts;
|
||||
|
||||
pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs);
|
||||
|
||||
sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) &
|
||||
(ACPI_BITMASK_RT_CLOCK_ENABLE |
|
||||
ACPI_BITMASK_POWER_BUTTON_ENABLE |
|
||||
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
|
||||
ACPI_BITMASK_TIMER_ENABLE)) != 0);
|
||||
qemu_set_irq(pm->irq, sci_level);
|
||||
|
||||
/* schedule a timer interruption if needed */
|
||||
acpi_pm_tmr_update(&pm->acpi_regs,
|
||||
(pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
|
||||
!(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
|
||||
}
|
||||
|
||||
static void ich9_pm_update_sci_fn(ACPIREGS *regs)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
|
||||
pm_update_sci(pm);
|
||||
}
|
||||
|
||||
static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
|
||||
switch (addr & ICH9_PMIO_MASK) {
|
||||
case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1):
|
||||
acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
uint32_t val = 0;
|
||||
|
||||
switch (addr & ICH9_PMIO_MASK) {
|
||||
case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1):
|
||||
val = acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
|
||||
switch (addr & ICH9_PMIO_MASK) {
|
||||
case ICH9_PMIO_PM1_STS:
|
||||
acpi_pm1_evt_write_sts(&pm->acpi_regs, val);
|
||||
pm_update_sci(pm);
|
||||
break;
|
||||
case ICH9_PMIO_PM1_EN:
|
||||
pm->acpi_regs.pm1.evt.en = val;
|
||||
pm_update_sci(pm);
|
||||
break;
|
||||
case ICH9_PMIO_PM1_CNT:
|
||||
acpi_pm1_cnt_write(&pm->acpi_regs, val, 0);
|
||||
break;
|
||||
default:
|
||||
pm_ioport_write_fallback(opaque, addr, 2, val);
|
||||
break;
|
||||
}
|
||||
ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
uint32_t val;
|
||||
|
||||
switch (addr & ICH9_PMIO_MASK) {
|
||||
case ICH9_PMIO_PM1_STS:
|
||||
val = acpi_pm1_evt_get_sts(&pm->acpi_regs);
|
||||
break;
|
||||
case ICH9_PMIO_PM1_EN:
|
||||
val = pm->acpi_regs.pm1.evt.en;
|
||||
break;
|
||||
case ICH9_PMIO_PM1_CNT:
|
||||
val = pm->acpi_regs.pm1.cnt.cnt;
|
||||
break;
|
||||
default:
|
||||
val = pm_ioport_read_fallback(opaque, addr, 2);
|
||||
break;
|
||||
}
|
||||
ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
|
||||
switch (addr & ICH9_PMIO_MASK) {
|
||||
case ICH9_PMIO_SMI_EN:
|
||||
pm->smi_en = val;
|
||||
break;
|
||||
default:
|
||||
pm_ioport_write_fallback(opaque, addr, 4, val);
|
||||
break;
|
||||
}
|
||||
ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
uint32_t val;
|
||||
|
||||
switch (addr & ICH9_PMIO_MASK) {
|
||||
case ICH9_PMIO_PM1_TMR:
|
||||
val = acpi_pm_tmr_get(&pm->acpi_regs);
|
||||
break;
|
||||
case ICH9_PMIO_SMI_EN:
|
||||
val = pm->smi_en;
|
||||
break;
|
||||
|
||||
default:
|
||||
val = pm_ioport_read_fallback(opaque, addr, 4);
|
||||
break;
|
||||
}
|
||||
ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
|
||||
uint32_t val)
|
||||
{
|
||||
int subsize = (len == 4) ? 2 : 1;
|
||||
IOPortWriteFunc *ioport_write =
|
||||
(subsize == 2) ? pm_ioport_writew : pm_ioport_writeb;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i += subsize) {
|
||||
ioport_write(opaque, addr, val);
|
||||
val >>= 8 * subsize;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len)
|
||||
{
|
||||
int subsize = (len == 4) ? 2 : 1;
|
||||
IOPortReadFunc *ioport_read =
|
||||
(subsize == 2) ? pm_ioport_readw : pm_ioport_readb;
|
||||
|
||||
uint32_t val;
|
||||
int i;
|
||||
|
||||
val = 0;
|
||||
for (i = 0; i < len; i += subsize) {
|
||||
val <<= 8 * subsize;
|
||||
val |= ioport_read(opaque, addr);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
|
||||
{
|
||||
ICH9_DEBUG("to 0x%x\n", pm_io_base);
|
||||
|
||||
assert((pm_io_base & ICH9_PMIO_MASK) == 0);
|
||||
|
||||
if (pm->pm_io_base != 0) {
|
||||
isa_unassign_ioport(pm->pm_io_base, ICH9_PMIO_SIZE);
|
||||
}
|
||||
|
||||
/* don't map at 0 */
|
||||
if (pm_io_base == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 1, pm_ioport_writeb, pm);
|
||||
register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 1, pm_ioport_readb, pm);
|
||||
register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 2, pm_ioport_writew, pm);
|
||||
register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 2, pm_ioport_readw, pm);
|
||||
register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_writel, pm);
|
||||
register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_readl, pm);
|
||||
|
||||
pm->pm_io_base = pm_io_base;
|
||||
acpi_gpe_blk(&pm->acpi_regs, pm_io_base + ICH9_PMIO_GPE0_STS);
|
||||
}
|
||||
|
||||
static int ich9_pm_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
uint32_t pm_io_base = pm->pm_io_base;
|
||||
pm->pm_io_base = 0;
|
||||
ich9_pm_iospace_update(pm, pm_io_base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define VMSTATE_GPE_ARRAY(_field, _state) \
|
||||
{ \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = 0, \
|
||||
.num = ICH9_PMIO_GPE0_LEN, \
|
||||
.info = &vmstate_info_uint8, \
|
||||
.size = sizeof(uint8_t), \
|
||||
.flags = VMS_ARRAY | VMS_POINTER, \
|
||||
.offset = vmstate_offset_pointer(_state, _field, uint8_t), \
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_ich9_pm = {
|
||||
.name = "ich9_pm",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = ich9_pm_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
|
||||
VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs),
|
||||
VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
|
||||
VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
|
||||
VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void pm_reset(void *opaque)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = opaque;
|
||||
ich9_pm_iospace_update(pm, 0);
|
||||
|
||||
acpi_pm1_evt_reset(&pm->acpi_regs);
|
||||
acpi_pm1_cnt_reset(&pm->acpi_regs);
|
||||
acpi_pm_tmr_reset(&pm->acpi_regs);
|
||||
acpi_gpe_reset(&pm->acpi_regs);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* Mark SMM as already inited to prevent SMM from running. KVM does not
|
||||
* support SMM mode. */
|
||||
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
|
||||
}
|
||||
|
||||
pm_update_sci(pm);
|
||||
}
|
||||
|
||||
static void pm_powerdown_req(Notifier *n, void *opaque)
|
||||
{
|
||||
ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
|
||||
|
||||
acpi_pm1_evt_power_down(&pm->acpi_regs);
|
||||
}
|
||||
|
||||
void ich9_pm_init(ICH9LPCPMRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3)
|
||||
{
|
||||
acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn);
|
||||
acpi_pm1_cnt_init(&pm->acpi_regs);
|
||||
acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
|
||||
|
||||
pm->irq = sci_irq;
|
||||
qemu_register_reset(pm_reset, pm);
|
||||
pm->powerdown_notifier.notify = pm_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&pm->powerdown_notifier);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* QEMU GMCH/ICH9 LPC PM Emulation
|
||||
*
|
||||
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef HW_ACPI_ICH9_H
|
||||
#define HW_ACPI_ICH9_H
|
||||
|
||||
#include "acpi.h"
|
||||
|
||||
typedef struct ICH9LPCPMRegs {
|
||||
/*
|
||||
* In ich9 spec says that pm1_cnt register is 32bit width and
|
||||
* that the upper 16bits are reserved and unused.
|
||||
* PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
|
||||
*/
|
||||
ACPIREGS acpi_regs;
|
||||
uint32_t smi_en;
|
||||
uint32_t smi_sts;
|
||||
|
||||
qemu_irq irq; /* SCI */
|
||||
|
||||
uint32_t pm_io_base;
|
||||
Notifier powerdown_notifier;
|
||||
} ICH9LPCPMRegs;
|
||||
|
||||
void ich9_pm_init(ICH9LPCPMRegs *pm,
|
||||
qemu_irq sci_irq, qemu_irq cmos_s3_resume);
|
||||
void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
|
||||
extern const VMStateDescription vmstate_ich9_pm;
|
||||
|
||||
#endif /* HW_ACPI_ICH9_H */
|
|
@ -235,10 +235,9 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
|
|||
{ \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = 0, \
|
||||
.num = GPE_LEN, \
|
||||
.info = &vmstate_info_uint16, \
|
||||
.size = sizeof(uint16_t), \
|
||||
.flags = VMS_ARRAY | VMS_POINTER, \
|
||||
.flags = VMS_SINGLE | VMS_POINTER, \
|
||||
.offset = vmstate_offset_pointer(_state, _field, uint8_t), \
|
||||
}
|
||||
|
||||
|
@ -267,11 +266,54 @@ static const VMStateDescription vmstate_pci_status = {
|
|||
}
|
||||
};
|
||||
|
||||
static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
int ret, i;
|
||||
uint16_t temp;
|
||||
|
||||
ret = pci_device_load(&s->dev, f);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
qemu_get_be16s(f, &s->ar.pm1.evt.sts);
|
||||
qemu_get_be16s(f, &s->ar.pm1.evt.en);
|
||||
qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
|
||||
|
||||
ret = vmstate_load_state(f, &vmstate_apm, opaque, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_get_timer(f, s->ar.tmr.timer);
|
||||
qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
|
||||
|
||||
qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
|
||||
for (i = 0; i < 3; i++) {
|
||||
qemu_get_be16s(f, &temp);
|
||||
}
|
||||
|
||||
qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
|
||||
for (i = 0; i < 3; i++) {
|
||||
qemu_get_be16s(f, &temp);
|
||||
}
|
||||
|
||||
ret = vmstate_load_state(f, &vmstate_pci_status, opaque, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
||||
* To support incoming qemu-kvm 1.2 migration, change version_id
|
||||
* and minimum_version_id to 2 below (which breaks migration from
|
||||
* qemu 1.2).
|
||||
*
|
||||
*/
|
||||
static const VMStateDescription vmstate_acpi = {
|
||||
.name = "piix4_pm",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.minimum_version_id_old = 1,
|
||||
.load_state_old = acpi_load_old,
|
||||
.post_load = vmstate_acpi_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define ARM_MISC_H 1
|
||||
|
||||
#include "memory.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
/* The CPU is also modeled as an interrupt controller. */
|
||||
#define ARM_PIC_CPU_IRQ 0
|
||||
|
|
2
hw/bt.h
2
hw/bt.h
|
@ -23,6 +23,8 @@
|
|||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/irq.h"
|
||||
|
||||
/* BD Address */
|
||||
typedef struct {
|
||||
uint8_t b[6];
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef QEMU_DEVICES_H
|
||||
#define QEMU_DEVICES_H
|
||||
|
||||
#include "hw/irq.h"
|
||||
|
||||
/* ??? Not all users of this file can include cpu-common.h. */
|
||||
struct MemoryRegion;
|
||||
|
||||
|
|
121
hw/fdc.c
121
hw/fdc.c
|
@ -327,7 +327,7 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
|
|||
static void fdctrl_reset_fifo(FDCtrl *fdctrl);
|
||||
static int fdctrl_transfer_handler (void *opaque, int nchan,
|
||||
int dma_pos, int dma_len);
|
||||
static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0);
|
||||
static void fdctrl_raise_irq(FDCtrl *fdctrl);
|
||||
static FDrive *get_cur_drv(FDCtrl *fdctrl);
|
||||
|
||||
static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
|
||||
|
@ -349,12 +349,12 @@ enum {
|
|||
FD_DIR_SCANE = 2,
|
||||
FD_DIR_SCANL = 3,
|
||||
FD_DIR_SCANH = 4,
|
||||
FD_DIR_VERIFY = 5,
|
||||
};
|
||||
|
||||
enum {
|
||||
FD_STATE_MULTI = 0x01, /* multi track flag */
|
||||
FD_STATE_FORMAT = 0x02, /* format flag */
|
||||
FD_STATE_SEEK = 0x04, /* seek flag */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -496,7 +496,6 @@ enum {
|
|||
};
|
||||
|
||||
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
|
||||
#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
|
||||
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
|
||||
|
||||
struct FDCtrl {
|
||||
|
@ -799,6 +798,7 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level)
|
|||
/* Change IRQ state */
|
||||
static void fdctrl_reset_irq(FDCtrl *fdctrl)
|
||||
{
|
||||
fdctrl->status0 = 0;
|
||||
if (!(fdctrl->sra & FD_SRA_INTPEND))
|
||||
return;
|
||||
FLOPPY_DPRINTF("Reset interrupt\n");
|
||||
|
@ -806,14 +806,13 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl)
|
|||
fdctrl->sra &= ~FD_SRA_INTPEND;
|
||||
}
|
||||
|
||||
static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
|
||||
static void fdctrl_raise_irq(FDCtrl *fdctrl)
|
||||
{
|
||||
/* Sparc mutation */
|
||||
if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
|
||||
/* XXX: not sure */
|
||||
fdctrl->msr &= ~FD_MSR_CMDBUSY;
|
||||
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
|
||||
fdctrl->status0 = status0;
|
||||
return;
|
||||
}
|
||||
if (!(fdctrl->sra & FD_SRA_INTPEND)) {
|
||||
|
@ -822,7 +821,6 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
|
|||
}
|
||||
|
||||
fdctrl->reset_sensei = 0;
|
||||
fdctrl->status0 = status0;
|
||||
FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
|
||||
}
|
||||
|
||||
|
@ -851,7 +849,8 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
|
|||
fd_recalibrate(&fdctrl->drives[i]);
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
if (do_irq) {
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG);
|
||||
fdctrl->status0 |= FD_SR0_RDYCHG;
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
|
||||
}
|
||||
}
|
||||
|
@ -1079,15 +1078,12 @@ static void fdctrl_reset_fifo(FDCtrl *fdctrl)
|
|||
}
|
||||
|
||||
/* Set FIFO status for the host to read */
|
||||
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, uint8_t status0)
|
||||
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len)
|
||||
{
|
||||
fdctrl->data_dir = FD_DIR_READ;
|
||||
fdctrl->data_len = fifo_len;
|
||||
fdctrl->data_pos = 0;
|
||||
fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
|
||||
if (status0) {
|
||||
fdctrl_raise_irq(fdctrl, status0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set an error: unimplemented/unknown command */
|
||||
|
@ -1096,7 +1092,7 @@ static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
|
|||
qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
|
||||
fdctrl->fifo[0]);
|
||||
fdctrl->fifo[0] = FD_SR0_INVCMD;
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
|
||||
/* Seek to next sector
|
||||
|
@ -1126,11 +1122,13 @@ static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
|
|||
} else {
|
||||
new_head = 0;
|
||||
new_track++;
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
new_track++;
|
||||
ret = 0;
|
||||
}
|
||||
|
@ -1150,10 +1148,14 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
|
|||
uint8_t status1, uint8_t status2)
|
||||
{
|
||||
FDrive *cur_drv;
|
||||
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
fdctrl->status0 = status0 | FD_SR0_SEEK | (cur_drv->head << 2) |
|
||||
GET_CUR_DRV(fdctrl);
|
||||
|
||||
fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
|
||||
fdctrl->status0 |= GET_CUR_DRV(fdctrl);
|
||||
if (cur_drv->head) {
|
||||
fdctrl->status0 |= FD_SR0_HEAD;
|
||||
}
|
||||
fdctrl->status0 |= status0;
|
||||
|
||||
FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
|
||||
status0, status1, status2, fdctrl->status0);
|
||||
|
@ -1170,7 +1172,9 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
|
|||
}
|
||||
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
|
||||
fdctrl->msr &= ~FD_MSR_NONDMA;
|
||||
fdctrl_set_fifo(fdctrl, 7, fdctrl->status0);
|
||||
|
||||
fdctrl_set_fifo(fdctrl, 7);
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
}
|
||||
|
||||
/* Prepare a data transfer (either DMA or FIFO) */
|
||||
|
@ -1178,7 +1182,6 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
|
|||
{
|
||||
FDrive *cur_drv;
|
||||
uint8_t kh, kt, ks;
|
||||
int did_seek = 0;
|
||||
|
||||
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
|
@ -1212,7 +1215,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
|
|||
fdctrl->fifo[5] = ks;
|
||||
return;
|
||||
case 1:
|
||||
did_seek = 1;
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1234,16 +1237,12 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
|
|||
/* Set the FIFO state */
|
||||
fdctrl->data_dir = direction;
|
||||
fdctrl->data_pos = 0;
|
||||
fdctrl->msr |= FD_MSR_CMDBUSY;
|
||||
assert(fdctrl->msr & FD_MSR_CMDBUSY);
|
||||
if (fdctrl->fifo[0] & 0x80)
|
||||
fdctrl->data_state |= FD_STATE_MULTI;
|
||||
else
|
||||
fdctrl->data_state &= ~FD_STATE_MULTI;
|
||||
if (did_seek)
|
||||
fdctrl->data_state |= FD_STATE_SEEK;
|
||||
else
|
||||
fdctrl->data_state &= ~FD_STATE_SEEK;
|
||||
if (fdctrl->fifo[5] == 00) {
|
||||
if (fdctrl->fifo[5] == 0) {
|
||||
fdctrl->data_len = fdctrl->fifo[8];
|
||||
} else {
|
||||
int tmp;
|
||||
|
@ -1266,14 +1265,21 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
|
|||
if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
|
||||
direction == FD_DIR_SCANH) && dma_mode == 0) ||
|
||||
(direction == FD_DIR_WRITE && dma_mode == 2) ||
|
||||
(direction == FD_DIR_READ && dma_mode == 1)) {
|
||||
(direction == FD_DIR_READ && dma_mode == 1) ||
|
||||
(direction == FD_DIR_VERIFY)) {
|
||||
/* No access is allowed until DMA transfer has completed */
|
||||
fdctrl->msr &= ~FD_MSR_RQM;
|
||||
/* Now, we just have to wait for the DMA controller to
|
||||
* recall us...
|
||||
*/
|
||||
DMA_hold_DREQ(fdctrl->dma_chann);
|
||||
DMA_schedule(fdctrl->dma_chann);
|
||||
if (direction != FD_DIR_VERIFY) {
|
||||
/* Now, we just have to wait for the DMA controller to
|
||||
* recall us...
|
||||
*/
|
||||
DMA_hold_DREQ(fdctrl->dma_chann);
|
||||
DMA_schedule(fdctrl->dma_chann);
|
||||
} else {
|
||||
/* Start transfer */
|
||||
fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
|
||||
fdctrl->data_len);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
|
||||
|
@ -1285,7 +1291,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
|
|||
if (direction != FD_DIR_WRITE)
|
||||
fdctrl->msr |= FD_MSR_DIO;
|
||||
/* IO based transfer: calculate len */
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
}
|
||||
|
||||
/* Prepare a transfer of deleted data */
|
||||
|
@ -1376,6 +1382,9 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
|
|||
goto transfer_error;
|
||||
}
|
||||
break;
|
||||
case FD_DIR_VERIFY:
|
||||
/* VERIFY commands */
|
||||
break;
|
||||
default:
|
||||
/* SCAN commands */
|
||||
{
|
||||
|
@ -1411,8 +1420,6 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
|
|||
fdctrl->data_dir == FD_DIR_SCANL ||
|
||||
fdctrl->data_dir == FD_DIR_SCANH)
|
||||
status2 = FD_SR2_SEH;
|
||||
if (FD_DID_SEEK(fdctrl->data_state))
|
||||
status0 |= FD_SR0_SEEK;
|
||||
fdctrl->data_len -= len;
|
||||
fdctrl_stop_transfer(fdctrl, status0, status1, status2);
|
||||
transfer_error:
|
||||
|
@ -1458,7 +1465,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
|
|||
* then from status mode to command mode
|
||||
*/
|
||||
if (fdctrl->msr & FD_MSR_NONDMA) {
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
|
||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||
} else {
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
fdctrl_reset_irq(fdctrl);
|
||||
|
@ -1506,7 +1513,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
|
|||
fdctrl->fifo[5] = ks;
|
||||
return;
|
||||
case 1:
|
||||
fdctrl->data_state |= FD_STATE_SEEK;
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1520,10 +1527,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
|
|||
if (cur_drv->sect == cur_drv->last_sect) {
|
||||
fdctrl->data_state &= ~FD_STATE_FORMAT;
|
||||
/* Last sector done */
|
||||
if (FD_DID_SEEK(fdctrl->data_state))
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
|
||||
else
|
||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||
} else {
|
||||
/* More to do */
|
||||
fdctrl->data_pos = 0;
|
||||
|
@ -1536,7 +1540,7 @@ static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
|
|||
{
|
||||
fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
|
||||
fdctrl->fifo[0] = fdctrl->lock << 4;
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1561,20 +1565,20 @@ static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
|
|||
(cur_drv->perpendicular << 2);
|
||||
fdctrl->fifo[8] = fdctrl->config;
|
||||
fdctrl->fifo[9] = fdctrl->precomp_trk;
|
||||
fdctrl_set_fifo(fdctrl, 10, 0);
|
||||
fdctrl_set_fifo(fdctrl, 10);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
|
||||
{
|
||||
/* Controller's version */
|
||||
fdctrl->fifo[0] = fdctrl->version;
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
|
||||
{
|
||||
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1627,7 +1631,7 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
|
|||
fdctrl->fifo[12] = fdctrl->pwrd;
|
||||
fdctrl->fifo[13] = 0;
|
||||
fdctrl->fifo[14] = 0;
|
||||
fdctrl_set_fifo(fdctrl, 15, 0);
|
||||
fdctrl_set_fifo(fdctrl, 15);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1650,7 +1654,6 @@ static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
|
|||
fdctrl->data_state |= FD_STATE_MULTI;
|
||||
else
|
||||
fdctrl->data_state &= ~FD_STATE_MULTI;
|
||||
fdctrl->data_state &= ~FD_STATE_SEEK;
|
||||
cur_drv->bps =
|
||||
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
|
||||
#if 0
|
||||
|
@ -1693,7 +1696,7 @@ static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
|
|||
(cur_drv->head << 2) |
|
||||
GET_CUR_DRV(fdctrl) |
|
||||
0x28;
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1705,7 +1708,8 @@ static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
|
|||
fd_recalibrate(cur_drv);
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
/* Raise Interrupt */
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1718,7 +1722,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
|
|||
fdctrl->reset_sensei--;
|
||||
} else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
|
||||
fdctrl->fifo[0] = FD_SR0_INVCMD;
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
return;
|
||||
} else {
|
||||
fdctrl->fifo[0] =
|
||||
|
@ -1727,7 +1731,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
|
|||
}
|
||||
|
||||
fdctrl->fifo[1] = cur_drv->track;
|
||||
fdctrl_set_fifo(fdctrl, 2, 0);
|
||||
fdctrl_set_fifo(fdctrl, 2);
|
||||
fdctrl_reset_irq(fdctrl);
|
||||
fdctrl->status0 = FD_SR0_RDYCHG;
|
||||
}
|
||||
|
@ -1744,7 +1748,8 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
|
|||
*/
|
||||
fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
|
||||
/* Raise Interrupt */
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1769,7 +1774,7 @@ static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
|
|||
{
|
||||
fdctrl->pwrd = fdctrl->fifo[1];
|
||||
fdctrl->fifo[0] = fdctrl->fifo[1];
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1788,7 +1793,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct
|
|||
fdctrl->fifo[0] = fdctrl->fifo[1];
|
||||
fdctrl->fifo[2] = 0;
|
||||
fdctrl->fifo[3] = 0;
|
||||
fdctrl_set_fifo(fdctrl, 4, 0);
|
||||
fdctrl_set_fifo(fdctrl, 4);
|
||||
} else {
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
}
|
||||
|
@ -1796,7 +1801,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct
|
|||
/* ERROR */
|
||||
fdctrl->fifo[0] = 0x80 |
|
||||
(cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
|
||||
fdctrl_set_fifo(fdctrl, 1, 0);
|
||||
fdctrl_set_fifo(fdctrl, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1815,7 +1820,8 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
|
|||
}
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
/* Raise Interrupt */
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
}
|
||||
|
||||
static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
|
||||
|
@ -1832,7 +1838,8 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
|
|||
}
|
||||
fdctrl_reset_fifo(fdctrl);
|
||||
/* Raise Interrupt */
|
||||
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
|
||||
fdctrl->status0 |= FD_SR0_SEEK;
|
||||
fdctrl_raise_irq(fdctrl);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
|
@ -1854,7 +1861,7 @@ static const struct {
|
|||
{ FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
|
||||
{ FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
|
||||
{ FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
|
||||
{ FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
|
||||
{ FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
|
||||
{ FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
|
||||
{ FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
|
||||
{ FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
|
||||
|
@ -1918,7 +1925,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
|||
* then from status mode to command mode
|
||||
*/
|
||||
if (fdctrl->data_pos == fdctrl->data_len)
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
|
||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||
return;
|
||||
}
|
||||
if (fdctrl->data_pos == 0) {
|
||||
|
|
|
@ -6,6 +6,7 @@ obj-y += pci-hotplug.o smbios.o wdt_ib700.o
|
|||
obj-y += debugcon.o multiboot.o
|
||||
obj-y += pc_piix.o
|
||||
obj-y += pc_sysfw.o
|
||||
obj-y += lpc_ich9.o q35.o pc_q35.o
|
||||
obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
|
||||
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
|
||||
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef struct PICCommonState PICCommonState;
|
|||
|
||||
#define TYPE_PIC_COMMON "pic-common"
|
||||
#define PIC_COMMON(obj) \
|
||||
OBJECT_CHECK(PICCommon, (obj), TYPE_PIC_COMMON)
|
||||
OBJECT_CHECK(PICCommonState, (obj), TYPE_PIC_COMMON)
|
||||
#define PIC_COMMON_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON)
|
||||
#define PIC_COMMON_GET_CLASS(obj) \
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2006 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.
|
||||
*/
|
||||
/*
|
||||
* QEMU i82801b11 dmi-to-pci Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011
|
||||
* Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "pci.h"
|
||||
#include "ich9.h"
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ICH9 DMI-to-PCI bridge */
|
||||
#define I82801ba_SSVID_OFFSET 0x50
|
||||
#define I82801ba_SSVID_SVID 0
|
||||
#define I82801ba_SSVID_SSID 0
|
||||
|
||||
typedef struct I82801b11Bridge {
|
||||
PCIBridge br;
|
||||
} I82801b11Bridge;
|
||||
|
||||
static int i82801b11_bridge_initfn(PCIDevice *d)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pci_bridge_initfn(d);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
|
||||
I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
|
||||
if (rc < 0) {
|
||||
goto err_bridge;
|
||||
}
|
||||
pci_config_set_prog_interface(d->config, PCI_CLASS_BRDIGE_PCI_INF_SUB);
|
||||
return 0;
|
||||
|
||||
err_bridge:
|
||||
pci_bridge_exitfn(d);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->is_bridge = 1;
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11;
|
||||
k->revision = ICH9_D2P_A2_REVISION;
|
||||
k->init = i82801b11_bridge_initfn;
|
||||
}
|
||||
|
||||
static const TypeInfo i82801b11_bridge_info = {
|
||||
.name = "i82801b11-bridge",
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(I82801b11Bridge),
|
||||
.class_init = i82801b11_bridge_class_init,
|
||||
};
|
||||
|
||||
PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus)
|
||||
{
|
||||
PCIDevice *d;
|
||||
PCIBridge *br;
|
||||
char buf[16];
|
||||
DeviceState *qdev;
|
||||
|
||||
d = pci_create_multifunction(bus, devfn, true, "i82801b11-bridge");
|
||||
if (!d) {
|
||||
return NULL;
|
||||
}
|
||||
br = DO_UPCAST(PCIBridge, dev, d);
|
||||
qdev = &br->dev.qdev;
|
||||
|
||||
snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
|
||||
pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn);
|
||||
qdev_init_nofail(qdev);
|
||||
|
||||
return pci_bridge_get_sec_bus(br);
|
||||
}
|
||||
|
||||
static void d2pbr_register(void)
|
||||
{
|
||||
type_register_static(&i82801b11_bridge_info);
|
||||
}
|
||||
|
||||
type_init(d2pbr_register);
|
|
@ -0,0 +1,207 @@
|
|||
#ifndef HW_ICH9_H
|
||||
#define HW_ICH9_H
|
||||
|
||||
#include "hw.h"
|
||||
#include "range.h"
|
||||
#include "isa.h"
|
||||
#include "sysbus.h"
|
||||
#include "pc.h"
|
||||
#include "apm.h"
|
||||
#include "ioapic.h"
|
||||
#include "pci.h"
|
||||
#include "pcie_host.h"
|
||||
#include "pci_bridge.h"
|
||||
#include "acpi.h"
|
||||
#include "acpi_ich9.h"
|
||||
#include "pam.h"
|
||||
#include "pci_internals.h"
|
||||
|
||||
void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
|
||||
int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
|
||||
void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
|
||||
PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
|
||||
i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
|
||||
|
||||
#define ICH9_CC_SIZE (16 * 1024) /* 16KB */
|
||||
|
||||
#define TYPE_ICH9_LPC_DEVICE "ICH9 LPC"
|
||||
#define ICH9_LPC_DEVICE(obj) \
|
||||
OBJECT_CHECK(ICH9LPCState, (obj), TYPE_ICH9_LPC_DEVICE)
|
||||
|
||||
typedef struct ICH9LPCState {
|
||||
/* ICH9 LPC PCI to ISA bridge */
|
||||
PCIDevice d;
|
||||
|
||||
/* (pci device, intx) -> pirq
|
||||
* In real chipset case, the unused slots are never used
|
||||
* as ICH9 supports only D25-D32 irq routing.
|
||||
* On the other hand in qemu case, any slot/function can be populated
|
||||
* via command line option.
|
||||
* So fallback interrupt routing for any devices in any slots is necessary.
|
||||
*/
|
||||
uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS];
|
||||
|
||||
APMState apm;
|
||||
ICH9LPCPMRegs pm;
|
||||
uint32_t sci_level; /* track sci level */
|
||||
|
||||
/* 10.1 Chipset Configuration registers(Memory Space)
|
||||
which is pointed by RCBA */
|
||||
uint8_t chip_config[ICH9_CC_SIZE];
|
||||
/* isa bus */
|
||||
ISABus *isa_bus;
|
||||
MemoryRegion rbca_mem;
|
||||
|
||||
qemu_irq *pic;
|
||||
qemu_irq *ioapic;
|
||||
} ICH9LPCState;
|
||||
|
||||
#define Q35_MASK(bit, ms_bit, ls_bit) \
|
||||
((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
|
||||
|
||||
/* ICH9: Chipset Configuration Registers */
|
||||
#define ICH9_CC_ADDR_MASK (ICH9_CC_SIZE - 1)
|
||||
|
||||
#define ICH9_CC
|
||||
#define ICH9_CC_D28IP 0x310C
|
||||
#define ICH9_CC_D28IP_SHIFT 4
|
||||
#define ICH9_CC_D28IP_MASK 0xf
|
||||
#define ICH9_CC_D28IP_DEFAULT 0x00214321
|
||||
#define ICH9_CC_D31IR 0x3140
|
||||
#define ICH9_CC_D30IR 0x3142
|
||||
#define ICH9_CC_D29IR 0x3144
|
||||
#define ICH9_CC_D28IR 0x3146
|
||||
#define ICH9_CC_D27IR 0x3148
|
||||
#define ICH9_CC_D26IR 0x314C
|
||||
#define ICH9_CC_D25IR 0x3150
|
||||
#define ICH9_CC_DIR_DEFAULT 0x3210
|
||||
#define ICH9_CC_D30IR_DEFAULT 0x0
|
||||
#define ICH9_CC_DIR_SHIFT 4
|
||||
#define ICH9_CC_DIR_MASK 0x7
|
||||
#define ICH9_CC_OIC 0x31FF
|
||||
#define ICH9_CC_OIC_AEN 0x1
|
||||
|
||||
/* D28:F[0-5] */
|
||||
#define ICH9_PCIE_DEV 28
|
||||
#define ICH9_PCIE_FUNC_MAX 6
|
||||
|
||||
|
||||
/* D29:F0 USB UHCI Controller #1 */
|
||||
#define ICH9_USB_UHCI1_DEV 29
|
||||
#define ICH9_USB_UHCI1_FUNC 0
|
||||
|
||||
/* D30:F0 DMI-to-PCI brdige */
|
||||
#define ICH9_D2P_BRIDGE "ICH9 D2P BRIDGE"
|
||||
#define ICH9_D2P_BRIDGE_SAVEVM_VERSION 0
|
||||
|
||||
#define ICH9_D2P_BRIDGE_DEV 30
|
||||
#define ICH9_D2P_BRIDGE_FUNC 0
|
||||
|
||||
#define ICH9_D2P_SECONDARY_DEFAULT (256 - 8)
|
||||
|
||||
#define ICH9_D2P_A2_REVISION 0x92
|
||||
|
||||
|
||||
/* D31:F1 LPC controller */
|
||||
#define ICH9_A2_LPC "ICH9 A2 LPC"
|
||||
#define ICH9_A2_LPC_SAVEVM_VERSION 0
|
||||
|
||||
#define ICH9_LPC_DEV 31
|
||||
#define ICH9_LPC_FUNC 0
|
||||
|
||||
#define ICH9_A2_LPC_REVISION 0x2
|
||||
#define ICH9_LPC_NB_PIRQS 8 /* PCI A-H */
|
||||
|
||||
#define ICH9_LPC_PMBASE 0x40
|
||||
#define ICH9_LPC_PMBASE_BASE_ADDRESS_MASK Q35_MASK(32, 15, 7)
|
||||
#define ICH9_LPC_PMBASE_RTE 0x1
|
||||
#define ICH9_LPC_PMBASE_DEFAULT 0x1
|
||||
#define ICH9_LPC_ACPI_CTRL 0x44
|
||||
#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80
|
||||
#define ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK Q35_MASK(8, 2, 0)
|
||||
#define ICH9_LPC_ACPI_CTRL_9 0x0
|
||||
#define ICH9_LPC_ACPI_CTRL_10 0x1
|
||||
#define ICH9_LPC_ACPI_CTRL_11 0x2
|
||||
#define ICH9_LPC_ACPI_CTRL_20 0x4
|
||||
#define ICH9_LPC_ACPI_CTRL_21 0x5
|
||||
#define ICH9_LPC_ACPI_CTRL_DEFAULT 0x0
|
||||
|
||||
#define ICH9_LPC_PIRQA_ROUT 0x60
|
||||
#define ICH9_LPC_PIRQB_ROUT 0x61
|
||||
#define ICH9_LPC_PIRQC_ROUT 0x62
|
||||
#define ICH9_LPC_PIRQD_ROUT 0x63
|
||||
|
||||
#define ICH9_LPC_PIRQE_ROUT 0x68
|
||||
#define ICH9_LPC_PIRQF_ROUT 0x69
|
||||
#define ICH9_LPC_PIRQG_ROUT 0x6a
|
||||
#define ICH9_LPC_PIRQH_ROUT 0x6b
|
||||
|
||||
#define ICH9_LPC_PIRQ_ROUT_IRQEN 0x80
|
||||
#define ICH9_LPC_PIRQ_ROUT_MASK Q35_MASK(8, 3, 0)
|
||||
#define ICH9_LPC_PIRQ_ROUT_DEFAULT 0x80
|
||||
|
||||
#define ICH9_LPC_RCBA 0xf0
|
||||
#define ICH9_LPC_RCBA_BA_MASK Q35_MASK(32, 31, 14)
|
||||
#define ICH9_LPC_RCBA_EN 0x1
|
||||
#define ICH9_LPC_RCBA_DEFAULT 0x0
|
||||
|
||||
#define ICH9_LPC_PIC_NUM_PINS 16
|
||||
#define ICH9_LPC_IOAPIC_NUM_PINS 24
|
||||
|
||||
/* D31:F2 SATA Controller #1 */
|
||||
#define ICH9_SATA1_DEV 31
|
||||
#define ICH9_SATA1_FUNC 2
|
||||
|
||||
/* D30:F1 power management I/O registers
|
||||
offset from the address ICH9_LPC_PMBASE */
|
||||
|
||||
/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
|
||||
#define ICH9_PMIO_SIZE 128
|
||||
#define ICH9_PMIO_MASK (ICH9_PMIO_SIZE - 1)
|
||||
|
||||
#define ICH9_PMIO_PM1_STS 0x00
|
||||
#define ICH9_PMIO_PM1_EN 0x02
|
||||
#define ICH9_PMIO_PM1_CNT 0x04
|
||||
#define ICH9_PMIO_PM1_TMR 0x08
|
||||
#define ICH9_PMIO_GPE0_STS 0x20
|
||||
#define ICH9_PMIO_GPE0_EN 0x28
|
||||
#define ICH9_PMIO_GPE0_LEN 16
|
||||
#define ICH9_PMIO_SMI_EN 0x30
|
||||
#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5)
|
||||
#define ICH9_PMIO_SMI_STS 0x34
|
||||
|
||||
/* FADT ACPI_ENABLE/ACPI_DISABLE */
|
||||
#define ICH9_APM_ACPI_ENABLE 0x2
|
||||
#define ICH9_APM_ACPI_DISABLE 0x3
|
||||
|
||||
|
||||
/* D31:F3 SMBus controller */
|
||||
#define ICH9_A2_SMB_REVISION 0x02
|
||||
#define ICH9_SMB_PI 0x00
|
||||
|
||||
#define ICH9_SMB_SMBMBAR0 0x10
|
||||
#define ICH9_SMB_SMBMBAR1 0x14
|
||||
#define ICH9_SMB_SMBM_BAR 0
|
||||
#define ICH9_SMB_SMBM_SIZE (1 << 8)
|
||||
#define ICH9_SMB_SMB_BASE 0x20
|
||||
#define ICH9_SMB_SMB_BASE_BAR 4
|
||||
#define ICH9_SMB_SMB_BASE_SIZE (1 << 5)
|
||||
#define ICH9_SMB_HOSTC 0x40
|
||||
#define ICH9_SMB_HOSTC_SSRESET ((uint8_t)(1 << 3))
|
||||
#define ICH9_SMB_HOSTC_I2C_EN ((uint8_t)(1 << 2))
|
||||
#define ICH9_SMB_HOSTC_SMB_SMI_EN ((uint8_t)(1 << 1))
|
||||
#define ICH9_SMB_HOSTC_HST_EN ((uint8_t)(1 << 0))
|
||||
|
||||
/* D31:F3 SMBus I/O and memory mapped I/O registers */
|
||||
#define ICH9_SMB_DEV 31
|
||||
#define ICH9_SMB_FUNC 3
|
||||
|
||||
#define ICH9_SMB_HST_STS 0x00
|
||||
#define ICH9_SMB_HST_CNT 0x02
|
||||
#define ICH9_SMB_HST_CMD 0x03
|
||||
#define ICH9_SMB_XMIT_SLVA 0x04
|
||||
#define ICH9_SMB_HST_D0 0x05
|
||||
#define ICH9_SMB_HST_D1 0x06
|
||||
#define ICH9_SMB_HOST_BLOCK_DB 0x07
|
||||
|
||||
#endif /* HW_ICH9_H */
|
|
@ -1124,12 +1124,17 @@ void ide_atapi_cmd(IDEState *s)
|
|||
* GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
|
||||
* states rely on this behavior.
|
||||
*/
|
||||
if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
|
||||
ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
|
||||
if (!(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA) &&
|
||||
!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
|
||||
|
||||
if (s->cdrom_changed == 1) {
|
||||
ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
|
||||
s->cdrom_changed = 2;
|
||||
} else {
|
||||
ide_atapi_cmd_error(s, UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED);
|
||||
s->cdrom_changed = 0;
|
||||
}
|
||||
|
||||
s->cdrom_changed = 0;
|
||||
s->sense_key = UNIT_ATTENTION;
|
||||
s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -345,7 +345,7 @@ static void trim_aio_cancel(BlockDriverAIOCB *acb)
|
|||
qemu_aio_release(iocb);
|
||||
}
|
||||
|
||||
static AIOPool trim_aio_pool = {
|
||||
static const AIOCBInfo trim_aiocb_info = {
|
||||
.aiocb_size = sizeof(TrimAIOCB),
|
||||
.cancel = trim_aio_cancel,
|
||||
};
|
||||
|
@ -369,7 +369,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
|
|||
TrimAIOCB *iocb;
|
||||
int i, j, ret;
|
||||
|
||||
iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque);
|
||||
iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque);
|
||||
iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
|
||||
iocb->ret = 0;
|
||||
|
||||
|
@ -588,6 +588,7 @@ void ide_dma_cb(void *opaque, int ret)
|
|||
IDEState *s = opaque;
|
||||
int n;
|
||||
int64_t sector_num;
|
||||
bool stay_active = false;
|
||||
|
||||
if (ret < 0) {
|
||||
int op = BM_STATUS_DMA_RETRY;
|
||||
|
@ -603,6 +604,14 @@ void ide_dma_cb(void *opaque, int ret)
|
|||
}
|
||||
|
||||
n = s->io_buffer_size >> 9;
|
||||
if (n > s->nsector) {
|
||||
/* The PRDs were longer than needed for this request. Shorten them so
|
||||
* we don't get a negative remainder. The Active bit must remain set
|
||||
* after the request completes. */
|
||||
n = s->nsector;
|
||||
stay_active = true;
|
||||
}
|
||||
|
||||
sector_num = ide_get_sector(s);
|
||||
if (n > 0) {
|
||||
dma_buf_commit(s);
|
||||
|
@ -625,6 +634,7 @@ void ide_dma_cb(void *opaque, int ret)
|
|||
if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
|
||||
/* The PRDs were too short. Reset the Active bit, but don't raise an
|
||||
* interrupt. */
|
||||
s->status = READY_STAT | SEEK_STAT;
|
||||
goto eot;
|
||||
}
|
||||
|
||||
|
@ -655,6 +665,9 @@ eot:
|
|||
bdrv_acct_done(s->bs, &s->acct);
|
||||
}
|
||||
ide_set_inactive(s);
|
||||
if (stay_active) {
|
||||
s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_DMAING);
|
||||
}
|
||||
}
|
||||
|
||||
static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
|
||||
|
@ -2176,12 +2189,6 @@ static int ide_drive_post_load(void *opaque, int version_id)
|
|||
{
|
||||
IDEState *s = opaque;
|
||||
|
||||
if (version_id < 3) {
|
||||
if (s->sense_key == UNIT_ATTENTION &&
|
||||
s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) {
|
||||
s->cdrom_changed = 1;
|
||||
}
|
||||
}
|
||||
if (s->identify_set) {
|
||||
bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5)));
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
|||
|
||||
s->io_buffer_size = io->len;
|
||||
|
||||
qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1, NULL);
|
||||
qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
|
||||
&dma_context_memory);
|
||||
qemu_sglist_add(&s->sg, io->addr, io->len);
|
||||
io->addr += io->len;
|
||||
io->len = 0;
|
||||
|
@ -132,7 +133,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
|||
s->io_buffer_index = 0;
|
||||
s->io_buffer_size = io->len;
|
||||
|
||||
qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1, NULL);
|
||||
qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
|
||||
&dma_context_memory);
|
||||
qemu_sglist_add(&s->sg, io->addr, io->len);
|
||||
io->addr += io->len;
|
||||
io->len = 0;
|
||||
|
|
2
hw/irq.h
2
hw/irq.h
|
@ -3,6 +3,8 @@
|
|||
|
||||
/* Generic IRQ/GPIO pin infrastructure. */
|
||||
|
||||
typedef struct IRQState *qemu_irq;
|
||||
|
||||
typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
|
||||
|
||||
void qemu_set_irq(qemu_irq irq, int level);
|
||||
|
|
|
@ -15,6 +15,46 @@
|
|||
#include "hw/apic_internal.h"
|
||||
#include "kvm.h"
|
||||
|
||||
/* PC Utility function */
|
||||
void kvm_pc_setup_irq_routing(bool pci_enabled)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
int i;
|
||||
|
||||
if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (i == 2) {
|
||||
continue;
|
||||
}
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
|
||||
}
|
||||
for (i = 8; i < 16; ++i) {
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
|
||||
}
|
||||
if (pci_enabled) {
|
||||
for (i = 0; i < 24; ++i) {
|
||||
if (i == 0) {
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
|
||||
} else if (i != 2) {
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_pc_gsi_handler(void *opaque, int n, int level)
|
||||
{
|
||||
GSIState *s = opaque;
|
||||
|
||||
if (n < ISA_NUM_IRQS) {
|
||||
/* Kernel will forward to both PIC and IOAPIC */
|
||||
qemu_set_irq(s->i8259_irq[n], level);
|
||||
} else {
|
||||
qemu_set_irq(s->ioapic_irq[n], level);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct KVMIOAPICState KVMIOAPICState;
|
||||
|
||||
struct KVMIOAPICState {
|
||||
|
|
|
@ -0,0 +1,525 @@
|
|||
/*
|
||||
* Copyright (c) 2006 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.
|
||||
*/
|
||||
/*
|
||||
* QEMU ICH9 Emulation
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011
|
||||
* Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This is based on piix_pci.c, but heavily modified.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "hw.h"
|
||||
#include "range.h"
|
||||
#include "isa.h"
|
||||
#include "sysbus.h"
|
||||
#include "pc.h"
|
||||
#include "apm.h"
|
||||
#include "ioapic.h"
|
||||
#include "pci.h"
|
||||
#include "pcie_host.h"
|
||||
#include "pci_bridge.h"
|
||||
#include "ich9.h"
|
||||
#include "acpi.h"
|
||||
#include "acpi_ich9.h"
|
||||
#include "pam.h"
|
||||
#include "pci_internals.h"
|
||||
#include "exec-memory.h"
|
||||
|
||||
static int ich9_lpc_sci_irq(ICH9LPCState *lpc);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ICH9 LPC PCI to ISA bridge */
|
||||
|
||||
static void ich9_lpc_reset(DeviceState *qdev);
|
||||
|
||||
/* chipset configuration register
|
||||
* to access chipset configuration registers, pci_[sg]et_{byte, word, long}
|
||||
* are used.
|
||||
* Although it's not pci configuration space, it's little endian as Intel.
|
||||
*/
|
||||
|
||||
static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir)
|
||||
{
|
||||
int intx;
|
||||
for (intx = 0; intx < PCI_NUM_PINS; intx++) {
|
||||
irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
static void ich9_cc_update(ICH9LPCState *lpc)
|
||||
{
|
||||
int slot;
|
||||
int pci_intx;
|
||||
|
||||
const int reg_offsets[] = {
|
||||
ICH9_CC_D25IR,
|
||||
ICH9_CC_D26IR,
|
||||
ICH9_CC_D27IR,
|
||||
ICH9_CC_D28IR,
|
||||
ICH9_CC_D29IR,
|
||||
ICH9_CC_D30IR,
|
||||
ICH9_CC_D31IR,
|
||||
};
|
||||
const int *offset;
|
||||
|
||||
/* D{25 - 31}IR, but D30IR is read only to 0. */
|
||||
for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) {
|
||||
if (slot == 30) {
|
||||
continue;
|
||||
}
|
||||
ich9_cc_update_ir(lpc->irr[slot],
|
||||
pci_get_word(lpc->chip_config + *offset));
|
||||
}
|
||||
|
||||
/*
|
||||
* D30: DMI2PCI bridge
|
||||
* It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge
|
||||
* are connected to pirq lines. Our choice is PIRQ[E-H].
|
||||
* INT[A-D] are connected to PIRQ[E-H]
|
||||
*/
|
||||
for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) {
|
||||
lpc->irr[30][pci_intx] = pci_intx + 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void ich9_cc_init(ICH9LPCState *lpc)
|
||||
{
|
||||
int slot;
|
||||
int intx;
|
||||
|
||||
/* the default irq routing is arbitrary as long as it matches with
|
||||
* acpi irq routing table.
|
||||
* The one that is incompatible with piix_pci(= bochs) one is
|
||||
* intentionally chosen to let the users know that the different
|
||||
* board is used.
|
||||
*
|
||||
* int[A-D] -> pirq[E-F]
|
||||
* avoid pirq A-D because they are used for pci express port
|
||||
*/
|
||||
for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
|
||||
for (intx = 0; intx < PCI_NUM_PINS; intx++) {
|
||||
lpc->irr[slot][intx] = (slot + intx) % 4 + 4;
|
||||
}
|
||||
}
|
||||
ich9_cc_update(lpc);
|
||||
}
|
||||
|
||||
static void ich9_cc_reset(ICH9LPCState *lpc)
|
||||
{
|
||||
uint8_t *c = lpc->chip_config;
|
||||
|
||||
memset(lpc->chip_config, 0, sizeof(lpc->chip_config));
|
||||
|
||||
pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT);
|
||||
pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT);
|
||||
pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT);
|
||||
pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT);
|
||||
pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
|
||||
pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
|
||||
pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
|
||||
|
||||
ich9_cc_update(lpc);
|
||||
}
|
||||
|
||||
static void ich9_cc_addr_len(uint64_t *addr, unsigned *len)
|
||||
{
|
||||
*addr &= ICH9_CC_ADDR_MASK;
|
||||
if (*addr + *len >= ICH9_CC_SIZE) {
|
||||
*len = ICH9_CC_SIZE - *addr;
|
||||
}
|
||||
}
|
||||
|
||||
/* val: little endian */
|
||||
static void ich9_cc_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned len)
|
||||
{
|
||||
ICH9LPCState *lpc = (ICH9LPCState *)opaque;
|
||||
|
||||
ich9_cc_addr_len(&addr, &len);
|
||||
memcpy(lpc->chip_config + addr, &val, len);
|
||||
ich9_cc_update(lpc);
|
||||
}
|
||||
|
||||
/* return value: little endian */
|
||||
static uint64_t ich9_cc_read(void *opaque, hwaddr addr,
|
||||
unsigned len)
|
||||
{
|
||||
ICH9LPCState *lpc = (ICH9LPCState *)opaque;
|
||||
|
||||
uint32_t val = 0;
|
||||
ich9_cc_addr_len(&addr, &len);
|
||||
memcpy(&val, lpc->chip_config + addr, len);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* IRQ routing */
|
||||
/* */
|
||||
static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
|
||||
{
|
||||
*pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK;
|
||||
*pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN;
|
||||
}
|
||||
|
||||
static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num,
|
||||
int *pic_irq, int *pic_dis)
|
||||
{
|
||||
switch (pirq_num) {
|
||||
case 0 ... 3: /* A-D */
|
||||
ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num],
|
||||
pic_irq, pic_dis);
|
||||
return;
|
||||
case 4 ... 7: /* E-H */
|
||||
ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)],
|
||||
pic_irq, pic_dis);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
/* pic_irq: i8254 irq 0-15 */
|
||||
static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq)
|
||||
{
|
||||
int i, pic_level;
|
||||
|
||||
/* The pic level is the logical OR of all the PCI irqs mapped to it */
|
||||
pic_level = 0;
|
||||
for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) {
|
||||
int tmp_irq;
|
||||
int tmp_dis;
|
||||
ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis);
|
||||
if (!tmp_dis && pic_irq == tmp_irq) {
|
||||
pic_level |= pci_bus_get_irq_level(lpc->d.bus, i);
|
||||
}
|
||||
}
|
||||
if (pic_irq == ich9_lpc_sci_irq(lpc)) {
|
||||
pic_level |= lpc->sci_level;
|
||||
}
|
||||
|
||||
qemu_set_irq(lpc->pic[pic_irq], pic_level);
|
||||
}
|
||||
|
||||
/* pirq: pirq[A-H] 0-7*/
|
||||
static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq)
|
||||
{
|
||||
int pic_irq;
|
||||
int pic_dis;
|
||||
|
||||
ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis);
|
||||
assert(pic_irq < ICH9_LPC_PIC_NUM_PINS);
|
||||
if (pic_dis) {
|
||||
return;
|
||||
}
|
||||
|
||||
ich9_lpc_update_pic(lpc, pic_irq);
|
||||
}
|
||||
|
||||
/* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */
|
||||
static int ich9_pirq_to_gsi(int pirq)
|
||||
{
|
||||
return pirq + ICH9_LPC_PIC_NUM_PINS;
|
||||
}
|
||||
|
||||
static int ich9_gsi_to_pirq(int gsi)
|
||||
{
|
||||
return gsi - ICH9_LPC_PIC_NUM_PINS;
|
||||
}
|
||||
|
||||
static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi)
|
||||
{
|
||||
int level = 0;
|
||||
|
||||
if (gsi >= ICH9_LPC_PIC_NUM_PINS) {
|
||||
level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi));
|
||||
}
|
||||
if (gsi == ich9_lpc_sci_irq(lpc)) {
|
||||
level |= lpc->sci_level;
|
||||
}
|
||||
|
||||
qemu_set_irq(lpc->ioapic[gsi], level);
|
||||
}
|
||||
|
||||
void ich9_lpc_set_irq(void *opaque, int pirq, int level)
|
||||
{
|
||||
ICH9LPCState *lpc = opaque;
|
||||
|
||||
assert(0 <= pirq);
|
||||
assert(pirq < ICH9_LPC_NB_PIRQS);
|
||||
|
||||
ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq));
|
||||
ich9_lpc_update_by_pirq(lpc, pirq);
|
||||
}
|
||||
|
||||
/* return the pirq number (PIRQ[A-H]:0-7) corresponding to
|
||||
* a given device irq pin.
|
||||
*/
|
||||
int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
|
||||
{
|
||||
BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
|
||||
PCIBus *pci_bus = PCI_BUS(bus);
|
||||
PCIDevice *lpc_pdev =
|
||||
pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)];
|
||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev);
|
||||
|
||||
return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
|
||||
}
|
||||
|
||||
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
|
||||
{
|
||||
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
|
||||
ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
|
||||
case ICH9_LPC_ACPI_CTRL_9:
|
||||
return 9;
|
||||
case ICH9_LPC_ACPI_CTRL_10:
|
||||
return 10;
|
||||
case ICH9_LPC_ACPI_CTRL_11:
|
||||
return 11;
|
||||
case ICH9_LPC_ACPI_CTRL_20:
|
||||
return 20;
|
||||
case ICH9_LPC_ACPI_CTRL_21:
|
||||
return 21;
|
||||
default:
|
||||
/* reserved */
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ich9_set_sci(void *opaque, int irq_num, int level)
|
||||
{
|
||||
ICH9LPCState *lpc = opaque;
|
||||
int irq;
|
||||
|
||||
assert(irq_num == 0);
|
||||
level = !!level;
|
||||
if (level == lpc->sci_level) {
|
||||
return;
|
||||
}
|
||||
lpc->sci_level = level;
|
||||
|
||||
irq = ich9_lpc_sci_irq(lpc);
|
||||
if (irq < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ich9_lpc_update_apic(lpc, irq);
|
||||
if (irq < ICH9_LPC_PIC_NUM_PINS) {
|
||||
ich9_lpc_update_pic(lpc, irq);
|
||||
}
|
||||
}
|
||||
|
||||
void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3)
|
||||
{
|
||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
|
||||
qemu_irq *sci_irq;
|
||||
|
||||
sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
|
||||
ich9_pm_init(&lpc->pm, sci_irq[0], cmos_s3);
|
||||
|
||||
ich9_lpc_reset(&lpc->d.qdev);
|
||||
}
|
||||
|
||||
/* APM */
|
||||
|
||||
static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
|
||||
{
|
||||
ICH9LPCState *lpc = arg;
|
||||
|
||||
/* ACPI specs 3.0, 4.7.2.5 */
|
||||
acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
|
||||
val == ICH9_APM_ACPI_ENABLE,
|
||||
val == ICH9_APM_ACPI_DISABLE);
|
||||
|
||||
/* SMI_EN = PMBASE + 30. SMI control and enable register */
|
||||
if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
|
||||
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
|
||||
}
|
||||
}
|
||||
|
||||
/* config:PMBASE */
|
||||
static void
|
||||
ich9_lpc_pmbase_update(ICH9LPCState *lpc)
|
||||
{
|
||||
uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
|
||||
pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
|
||||
|
||||
ich9_pm_iospace_update(&lpc->pm, pm_io_base);
|
||||
}
|
||||
|
||||
/* config:RBCA */
|
||||
static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old)
|
||||
{
|
||||
uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA);
|
||||
|
||||
if (rbca_old & ICH9_LPC_RCBA_EN) {
|
||||
memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem);
|
||||
}
|
||||
if (rbca & ICH9_LPC_RCBA_EN) {
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
rbca & ICH9_LPC_RCBA_BA_MASK,
|
||||
&lpc->rbca_mem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ich9_lpc_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ICH9LPCState *lpc = opaque;
|
||||
|
||||
ich9_lpc_pmbase_update(lpc);
|
||||
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ich9_lpc_config_write(PCIDevice *d,
|
||||
uint32_t addr, uint32_t val, int len)
|
||||
{
|
||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
|
||||
uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
|
||||
|
||||
pci_default_write_config(d, addr, val, len);
|
||||
if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) {
|
||||
ich9_lpc_pmbase_update(lpc);
|
||||
}
|
||||
if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
|
||||
ich9_lpc_rcba_update(lpc, rbca_old);
|
||||
}
|
||||
}
|
||||
|
||||
static void ich9_lpc_reset(DeviceState *qdev)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(qdev);
|
||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
|
||||
uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i,
|
||||
ICH9_LPC_PIRQ_ROUT_DEFAULT);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i,
|
||||
ICH9_LPC_PIRQ_ROUT_DEFAULT);
|
||||
}
|
||||
pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT);
|
||||
|
||||
pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
|
||||
pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT);
|
||||
|
||||
ich9_cc_reset(lpc);
|
||||
|
||||
ich9_lpc_pmbase_update(lpc);
|
||||
ich9_lpc_rcba_update(lpc, rbca_old);
|
||||
|
||||
lpc->sci_level = 0;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rbca_mmio_ops = {
|
||||
.read = ich9_cc_read,
|
||||
.write = ich9_cc_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int ich9_lpc_initfn(PCIDevice *d)
|
||||
{
|
||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
|
||||
ISABus *isa_bus;
|
||||
|
||||
isa_bus = isa_bus_new(&d->qdev, get_system_io());
|
||||
|
||||
pci_set_long(d->wmask + ICH9_LPC_PMBASE,
|
||||
ICH9_LPC_PMBASE_BASE_ADDRESS_MASK);
|
||||
|
||||
memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc,
|
||||
"lpc-rbca-mmio", ICH9_CC_SIZE);
|
||||
|
||||
lpc->isa_bus = isa_bus;
|
||||
|
||||
ich9_cc_init(lpc);
|
||||
apm_init(&lpc->apm, ich9_apm_ctrl_changed, lpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ich9_lpc = {
|
||||
.name = "ICH9LPC",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = ich9_lpc_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(d, ICH9LPCState),
|
||||
VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState),
|
||||
VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE),
|
||||
VMSTATE_UINT32(sci_level, ICH9LPCState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void ich9_lpc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = ich9_lpc_reset;
|
||||
k->init = ich9_lpc_initfn;
|
||||
dc->vmsd = &vmstate_ich9_lpc;
|
||||
dc->no_user = 1;
|
||||
k->config_write = ich9_lpc_config_write;
|
||||
dc->desc = "ICH9 LPC bridge";
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8;
|
||||
k->revision = ICH9_A2_LPC_REVISION;
|
||||
k->class_id = PCI_CLASS_BRIDGE_ISA;
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo ich9_lpc_info = {
|
||||
.name = TYPE_ICH9_LPC_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(struct ICH9LPCState),
|
||||
.class_init = ich9_lpc_class_init,
|
||||
};
|
||||
|
||||
static void ich9_lpc_register(void)
|
||||
{
|
||||
type_register_static(&ich9_lpc_info);
|
||||
}
|
||||
|
||||
type_init(ich9_lpc_register);
|
|
@ -25,6 +25,7 @@
|
|||
#include "qemu-timer.h"
|
||||
#include "sysemu.h"
|
||||
#include "mc146818rtc.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#include "apic.h"
|
||||
|
@ -569,7 +570,11 @@ static void rtc_update_time(RTCState *s)
|
|||
guest_nsec = get_guest_rtc_ns(s);
|
||||
guest_sec = guest_nsec / NSEC_PER_SEC;
|
||||
gmtime_r(&guest_sec, &ret);
|
||||
rtc_set_cmos(s, &ret);
|
||||
|
||||
/* Is SET flag of Register B disabled? */
|
||||
if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) {
|
||||
rtc_set_cmos(s, &ret);
|
||||
}
|
||||
}
|
||||
|
||||
static int update_in_progress(RTCState *s)
|
||||
|
|
|
@ -1296,7 +1296,7 @@ static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd)
|
|||
|
||||
static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd)
|
||||
{
|
||||
qemu_aio_flush();
|
||||
bdrv_drain_all();
|
||||
return MFI_STAT_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#ifndef hw_omap_h
|
||||
#include "memory.h"
|
||||
# define hw_omap_h "omap.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
# define OMAP_EMIFS_BASE 0x00000000
|
||||
# define OMAP2_Q0_BASE 0x00000000
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* QEMU i440FX/PIIX3 PCI Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
* Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* Split out from piix_pci.c
|
||||
*
|
||||
* 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 "sysemu.h"
|
||||
#include "pam.h"
|
||||
|
||||
void smram_update(MemoryRegion *smram_region, uint8_t smram,
|
||||
uint8_t smm_enabled)
|
||||
{
|
||||
bool smram_enabled;
|
||||
|
||||
smram_enabled = ((smm_enabled && (smram & SMRAM_G_SMRAME)) ||
|
||||
(smram & SMRAM_D_OPEN));
|
||||
memory_region_set_enabled(smram_region, !smram_enabled);
|
||||
}
|
||||
|
||||
void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram,
|
||||
MemoryRegion *smram_region)
|
||||
{
|
||||
uint8_t smm_enabled = (smm != 0);
|
||||
if (*host_smm_enabled != smm_enabled) {
|
||||
*host_smm_enabled = smm_enabled;
|
||||
smram_update(smram_region, smram, *host_smm_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void init_pam(MemoryRegion *ram_memory, MemoryRegion *system_memory,
|
||||
MemoryRegion *pci_address_space, PAMMemoryRegion *mem,
|
||||
uint32_t start, uint32_t size)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* RAM */
|
||||
memory_region_init_alias(&mem->alias[3], "pam-ram", ram_memory,
|
||||
start, size);
|
||||
/* ROM (XXX: not quite correct) */
|
||||
memory_region_init_alias(&mem->alias[1], "pam-rom", ram_memory,
|
||||
start, size);
|
||||
memory_region_set_readonly(&mem->alias[1], true);
|
||||
|
||||
/* XXX: should distinguish read/write cases */
|
||||
memory_region_init_alias(&mem->alias[0], "pam-pci", pci_address_space,
|
||||
start, size);
|
||||
memory_region_init_alias(&mem->alias[2], "pam-pci", pci_address_space,
|
||||
start, size);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
memory_region_set_enabled(&mem->alias[i], false);
|
||||
memory_region_add_subregion_overlap(system_memory, start,
|
||||
&mem->alias[i], 1);
|
||||
}
|
||||
mem->current = 0;
|
||||
}
|
||||
|
||||
void pam_update(PAMMemoryRegion *pam, int idx, uint8_t val)
|
||||
{
|
||||
assert(0 <= idx && idx <= 12);
|
||||
|
||||
memory_region_set_enabled(&pam->alias[pam->current], false);
|
||||
pam->current = (val >> ((!(idx & 1)) * 4)) & PAM_ATTR_MASK;
|
||||
memory_region_set_enabled(&pam->alias[pam->current], true);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef QEMU_PAM_H
|
||||
#define QEMU_PAM_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
* Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* Split out from piix_pci.c
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SMRAM memory area and PAM memory area in Legacy address range for PC.
|
||||
* PAM: Programmable Attribute Map registers
|
||||
*
|
||||
* 0xa0000 - 0xbffff compatible SMRAM
|
||||
*
|
||||
* 0xc0000 - 0xc3fff Expansion area memory segments
|
||||
* 0xc4000 - 0xc7fff
|
||||
* 0xc8000 - 0xcbfff
|
||||
* 0xcc000 - 0xcffff
|
||||
* 0xd0000 - 0xd3fff
|
||||
* 0xd4000 - 0xd7fff
|
||||
* 0xd8000 - 0xdbfff
|
||||
* 0xdc000 - 0xdffff
|
||||
* 0xe0000 - 0xe3fff Extended System BIOS Area Memory Segments
|
||||
* 0xe4000 - 0xe7fff
|
||||
* 0xe8000 - 0xebfff
|
||||
* 0xec000 - 0xeffff
|
||||
*
|
||||
* 0xf0000 - 0xfffff System BIOS Area Memory Segments
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define SMRAM_C_BASE 0xa0000
|
||||
#define SMRAM_C_END 0xc0000
|
||||
#define SMRAM_C_SIZE 0x20000
|
||||
|
||||
#define PAM_EXPAN_BASE 0xc0000
|
||||
#define PAM_EXPAN_SIZE 0x04000
|
||||
|
||||
#define PAM_EXBIOS_BASE 0xe0000
|
||||
#define PAM_EXBIOS_SIZE 0x04000
|
||||
|
||||
#define PAM_BIOS_BASE 0xf0000
|
||||
#define PAM_BIOS_END 0xfffff
|
||||
/* 64KB: Intel 3 series express chipset family p. 58*/
|
||||
#define PAM_BIOS_SIZE 0x10000
|
||||
|
||||
/* PAM registers: log nibble and high nibble*/
|
||||
#define PAM_ATTR_WE ((uint8_t)2)
|
||||
#define PAM_ATTR_RE ((uint8_t)1)
|
||||
#define PAM_ATTR_MASK ((uint8_t)3)
|
||||
|
||||
/* SMRAM register */
|
||||
#define SMRAM_D_OPEN ((uint8_t)(1 << 6))
|
||||
#define SMRAM_D_CLS ((uint8_t)(1 << 5))
|
||||
#define SMRAM_D_LCK ((uint8_t)(1 << 4))
|
||||
#define SMRAM_G_SMRAME ((uint8_t)(1 << 3))
|
||||
#define SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7)
|
||||
#define SMRAM_C_BASE_SEG ((uint8_t)0x2) /* hardwired to b010 */
|
||||
|
||||
typedef struct PAMMemoryRegion {
|
||||
MemoryRegion alias[4]; /* index = PAM value */
|
||||
unsigned current;
|
||||
} PAMMemoryRegion;
|
||||
|
||||
void smram_update(MemoryRegion *smram_region, uint8_t smram,
|
||||
uint8_t smm_enabled);
|
||||
void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram,
|
||||
MemoryRegion *smram_region);
|
||||
void init_pam(MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci,
|
||||
PAMMemoryRegion *mem, uint32_t start, uint32_t size);
|
||||
void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val);
|
||||
|
||||
#endif /* QEMU_PAM_H */
|
39
hw/pc.c
39
hw/pc.c
|
@ -1058,6 +1058,21 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
|||
*floppy = fdctrl_init_isa(isa_bus, fd);
|
||||
}
|
||||
|
||||
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
|
||||
if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
|
||||
pc_init_ne2k_isa(isa_bus, nd);
|
||||
} else {
|
||||
pci_nic_init_nofail(nd, "e1000", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pc_pci_device_init(PCIBus *pci_bus)
|
||||
{
|
||||
int max_bus;
|
||||
|
@ -1068,3 +1083,27 @@ void pc_pci_device_init(PCIBus *pci_bus)
|
|||
pci_create_simple(pci_bus, -1, "lsi53c895a");
|
||||
}
|
||||
}
|
||||
|
||||
void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *d;
|
||||
unsigned int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
dev = qdev_create(NULL, "kvm-ioapic");
|
||||
} else {
|
||||
dev = qdev_create(NULL, "ioapic");
|
||||
}
|
||||
if (parent_name) {
|
||||
object_property_add_child(object_resolve_path(parent_name, NULL),
|
||||
"ioapic", OBJECT(dev), NULL);
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
d = sysbus_from_qdev(dev);
|
||||
sysbus_mmio_map(d, 0, 0xfec00000);
|
||||
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
}
|
||||
|
|
3
hw/pc.h
3
hw/pc.h
|
@ -98,11 +98,14 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
|||
const char *boot_device,
|
||||
ISADevice *floppy, BusState *ide0, BusState *ide1,
|
||||
ISADevice *s);
|
||||
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus);
|
||||
void pc_pci_device_init(PCIBus *pci_bus);
|
||||
|
||||
typedef void (*cpu_set_smm_t)(int smm, void *arg);
|
||||
void cpu_smm_register(cpu_set_smm_t callback, void *arg);
|
||||
|
||||
void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
|
||||
|
||||
/* acpi.c */
|
||||
extern int acpi_enabled;
|
||||
extern char *acpi_tables;
|
||||
|
|
79
hw/pc_piix.c
79
hw/pc_piix.c
|
@ -54,70 +54,6 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
|
|||
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
|
||||
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||
|
||||
static void kvm_piix3_setup_irq_routing(bool pci_enabled)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
KVMState *s = kvm_state;
|
||||
int i;
|
||||
|
||||
if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (i == 2) {
|
||||
continue;
|
||||
}
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
|
||||
}
|
||||
for (i = 8; i < 16; ++i) {
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
|
||||
}
|
||||
if (pci_enabled) {
|
||||
for (i = 0; i < 24; ++i) {
|
||||
if (i == 0) {
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
|
||||
} else if (i != 2) {
|
||||
kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_KVM */
|
||||
}
|
||||
|
||||
static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
|
||||
{
|
||||
GSIState *s = opaque;
|
||||
|
||||
if (n < ISA_NUM_IRQS) {
|
||||
/* Kernel will forward to both PIC and IOAPIC */
|
||||
qemu_set_irq(s->i8259_irq[n], level);
|
||||
} else {
|
||||
qemu_set_irq(s->ioapic_irq[n], level);
|
||||
}
|
||||
}
|
||||
|
||||
static void ioapic_init(GSIState *gsi_state)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *d;
|
||||
unsigned int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
dev = qdev_create(NULL, "kvm-ioapic");
|
||||
} else {
|
||||
dev = qdev_create(NULL, "ioapic");
|
||||
}
|
||||
/* FIXME: this should be under the piix3. */
|
||||
object_property_add_child(object_resolve_path("i440fx", NULL),
|
||||
"ioapic", OBJECT(dev), NULL);
|
||||
qdev_init_nofail(dev);
|
||||
d = sysbus_from_qdev(dev);
|
||||
sysbus_mmio_map(d, 0, 0xfec00000);
|
||||
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_init1(MemoryRegion *system_memory,
|
||||
MemoryRegion *system_io,
|
||||
|
@ -183,8 +119,8 @@ static void pc_init1(MemoryRegion *system_memory,
|
|||
|
||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_piix3_setup_irq_routing(pci_enabled);
|
||||
gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
|
||||
kvm_pc_setup_irq_routing(pci_enabled);
|
||||
gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
|
||||
GSI_NUM_PINS);
|
||||
} else {
|
||||
gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
|
||||
|
@ -221,7 +157,7 @@ static void pc_init1(MemoryRegion *system_memory,
|
|||
gsi_state->i8259_irq[i] = i8259[i];
|
||||
}
|
||||
if (pci_enabled) {
|
||||
ioapic_init(gsi_state);
|
||||
ioapic_init_gsi(gsi_state, "i440fx");
|
||||
}
|
||||
|
||||
pc_register_ferr_irq(gsi[13]);
|
||||
|
@ -234,14 +170,7 @@ static void pc_init1(MemoryRegion *system_memory,
|
|||
/* init basic PC hardware */
|
||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
|
||||
if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
|
||||
pc_init_ne2k_isa(isa_bus, nd);
|
||||
else
|
||||
pci_nic_init_nofail(nd, "e1000", NULL);
|
||||
}
|
||||
pc_nic_init(isa_bus, pci_bus);
|
||||
|
||||
ide_drive_get(hd, MAX_IDE_BUS);
|
||||
if (pci_enabled) {
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Q35 chipset based pc system emulator
|
||||
*
|
||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||
* Copyright (c) 2009, 2010
|
||||
* Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This is based on pc.c, but heavily modified.
|
||||
*
|
||||
* 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 "hw.h"
|
||||
#include "arch_init.h"
|
||||
#include "smbus.h"
|
||||
#include "boards.h"
|
||||
#include "mc146818rtc.h"
|
||||
#include "xen.h"
|
||||
#include "kvm.h"
|
||||
#include "kvm/clock.h"
|
||||
#include "q35.h"
|
||||
#include "exec-memory.h"
|
||||
#include "ich9.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci.h"
|
||||
#include "hw/usb.h"
|
||||
|
||||
/* ICH9 AHCI has 6 ports */
|
||||
#define MAX_SATA_PORTS 6
|
||||
|
||||
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
|
||||
* BIOS will read it and start S3 resume at POST Entry */
|
||||
static void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
|
||||
{
|
||||
ISADevice *s = opaque;
|
||||
|
||||
if (level) {
|
||||
rtc_set_memory(s, 0xF, 0xFE);
|
||||
}
|
||||
}
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
ram_addr_t below_4g_mem_size, above_4g_mem_size;
|
||||
Q35PCIHost *q35_host;
|
||||
PCIBus *host_bus;
|
||||
PCIDevice *lpc;
|
||||
BusState *idebus[MAX_SATA_PORTS];
|
||||
ISADevice *rtc_state;
|
||||
ISADevice *floppy;
|
||||
MemoryRegion *pci_memory;
|
||||
MemoryRegion *rom_memory;
|
||||
MemoryRegion *ram_memory;
|
||||
GSIState *gsi_state;
|
||||
ISABus *isa_bus;
|
||||
int pci_enabled = 1;
|
||||
qemu_irq *cpu_irq;
|
||||
qemu_irq *gsi;
|
||||
qemu_irq *i8259;
|
||||
int i;
|
||||
ICH9LPCState *ich9_lpc;
|
||||
PCIDevice *ahci;
|
||||
qemu_irq *cmos_s3;
|
||||
|
||||
pc_cpus_init(cpu_model);
|
||||
|
||||
kvmclock_create();
|
||||
|
||||
if (ram_size >= 0xb0000000) {
|
||||
above_4g_mem_size = ram_size - 0xb0000000;
|
||||
below_4g_mem_size = 0xb0000000;
|
||||
} else {
|
||||
above_4g_mem_size = 0;
|
||||
below_4g_mem_size = ram_size;
|
||||
}
|
||||
|
||||
/* pci enabled */
|
||||
if (pci_enabled) {
|
||||
pci_memory = g_new(MemoryRegion, 1);
|
||||
memory_region_init(pci_memory, "pci", INT64_MAX);
|
||||
rom_memory = pci_memory;
|
||||
} else {
|
||||
pci_memory = NULL;
|
||||
rom_memory = get_system_memory();
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
|
||||
initrd_filename, below_4g_mem_size, above_4g_mem_size,
|
||||
rom_memory, &ram_memory);
|
||||
}
|
||||
|
||||
/* irq lines */
|
||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_pc_setup_irq_routing(pci_enabled);
|
||||
gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
|
||||
GSI_NUM_PINS);
|
||||
} else {
|
||||
gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
|
||||
}
|
||||
|
||||
/* create pci host bus */
|
||||
q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE));
|
||||
|
||||
q35_host->mch.ram_memory = ram_memory;
|
||||
q35_host->mch.pci_address_space = pci_memory;
|
||||
q35_host->mch.system_memory = get_system_memory();
|
||||
q35_host->mch.address_space_io = get_system_io();;
|
||||
q35_host->mch.below_4g_mem_size = below_4g_mem_size;
|
||||
q35_host->mch.above_4g_mem_size = above_4g_mem_size;
|
||||
/* pci */
|
||||
qdev_init_nofail(DEVICE(q35_host));
|
||||
host_bus = q35_host->host.pci.bus;
|
||||
/* create ISA bus */
|
||||
lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
|
||||
ICH9_LPC_FUNC), true,
|
||||
TYPE_ICH9_LPC_DEVICE);
|
||||
ich9_lpc = ICH9_LPC_DEVICE(lpc);
|
||||
ich9_lpc->pic = gsi;
|
||||
ich9_lpc->ioapic = gsi_state->ioapic_irq;
|
||||
pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
|
||||
ICH9_LPC_NB_PIRQS);
|
||||
isa_bus = ich9_lpc->isa_bus;
|
||||
|
||||
/*end early*/
|
||||
isa_bus_irqs(isa_bus, gsi);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
i8259 = kvm_i8259_init(isa_bus);
|
||||
} else if (xen_enabled()) {
|
||||
i8259 = xen_interrupt_controller_init();
|
||||
} else {
|
||||
cpu_irq = pc_allocate_cpu_irq();
|
||||
i8259 = i8259_init(isa_bus, cpu_irq[0]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ISA_NUM_IRQS; i++) {
|
||||
gsi_state->i8259_irq[i] = i8259[i];
|
||||
}
|
||||
if (pci_enabled) {
|
||||
ioapic_init_gsi(gsi_state, NULL);
|
||||
}
|
||||
|
||||
pc_register_ferr_irq(gsi[13]);
|
||||
|
||||
/* init basic PC hardware */
|
||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
|
||||
|
||||
/* connect pm stuff to lpc */
|
||||
cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
|
||||
ich9_lpc_pm_init(lpc, *cmos_s3);
|
||||
|
||||
/* ahci and SATA device, for q35 1 ahci controller is built-in */
|
||||
ahci = pci_create_simple_multifunction(host_bus,
|
||||
PCI_DEVFN(ICH9_SATA1_DEV,
|
||||
ICH9_SATA1_FUNC),
|
||||
true, "ich9-ahci");
|
||||
idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
|
||||
idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
|
||||
|
||||
if (usb_enabled(false)) {
|
||||
/* Should we create 6 UHCI according to ich9 spec? */
|
||||
ehci_create_ich9_with_companions(host_bus, 0x1d);
|
||||
}
|
||||
|
||||
/* TODO: Populate SPD eeprom data. */
|
||||
smbus_eeprom_init(ich9_smb_init(host_bus,
|
||||
PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
|
||||
0xb100),
|
||||
8, NULL, 0);
|
||||
|
||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
|
||||
floppy, idebus[0], idebus[1], rtc_state);
|
||||
|
||||
/* the rest devices to which pci devfn is automatically assigned */
|
||||
pc_vga_init(isa_bus, host_bus);
|
||||
audio_init(isa_bus, host_bus);
|
||||
pc_nic_init(isa_bus, host_bus);
|
||||
if (pci_enabled) {
|
||||
pc_pci_device_init(host_bus);
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUMachine pc_q35_machine = {
|
||||
.name = "q35-next",
|
||||
.alias = "q35",
|
||||
.desc = "Q35 chipset PC",
|
||||
.init = pc_q35_init,
|
||||
.max_cpus = 255,
|
||||
};
|
||||
|
||||
static void pc_q35_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_q35_machine);
|
||||
}
|
||||
|
||||
machine_init(pc_q35_machine_init);
|
|
@ -80,7 +80,13 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
|
|||
SCSIBus *scsibus;
|
||||
SCSIDevice *scsidev;
|
||||
|
||||
scsibus = SCSI_BUS(QLIST_FIRST(&adapter->child_bus));
|
||||
scsibus = (SCSIBus *)
|
||||
object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)),
|
||||
TYPE_SCSI_BUS);
|
||||
if (!scsibus) {
|
||||
error_report("Device is not a SCSI adapter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* drive_init() tries to find a default for dinfo->unit. Doesn't
|
||||
|
|
6
hw/pci.c
6
hw/pci.c
|
@ -301,9 +301,9 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,
|
|||
PCIBus *bus;
|
||||
|
||||
bus = g_malloc0(sizeof(*bus));
|
||||
bus->qbus.glib_allocated = true;
|
||||
pci_bus_new_inplace(bus, parent, name, address_space_mem,
|
||||
address_space_io, devfn_min);
|
||||
OBJECT(bus)->free = g_free;
|
||||
return bus;
|
||||
}
|
||||
|
||||
|
@ -367,6 +367,10 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
|
|||
|
||||
pci_update_mappings(s);
|
||||
|
||||
memory_region_set_enabled(&s->bus_master_enable_region,
|
||||
pci_get_word(s->config + PCI_COMMAND)
|
||||
& PCI_COMMAND_MASTER);
|
||||
|
||||
g_free(config);
|
||||
return 0;
|
||||
}
|
||||
|
|
14
hw/pci_ids.h
14
hw/pci_ids.h
|
@ -37,6 +37,7 @@
|
|||
#define PCI_CLASS_BRIDGE_HOST 0x0600
|
||||
#define PCI_CLASS_BRIDGE_ISA 0x0601
|
||||
#define PCI_CLASS_BRIDGE_PCI 0x0604
|
||||
#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01
|
||||
#define PCI_CLASS_BRIDGE_OTHER 0x0680
|
||||
|
||||
#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
|
||||
|
@ -117,6 +118,17 @@
|
|||
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
|
||||
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
|
||||
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
|
||||
#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
|
||||
|
@ -127,6 +139,8 @@
|
|||
#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
|
||||
#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0
|
||||
|
||||
#define PCI_VENDOR_ID_XEN 0x5853
|
||||
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "sysbus.h"
|
||||
#include "range.h"
|
||||
#include "xen.h"
|
||||
#include "pam.h"
|
||||
|
||||
/*
|
||||
* I440FX chipset data sheet.
|
||||
|
@ -68,11 +69,6 @@ typedef struct PIIX3State {
|
|||
int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
|
||||
} PIIX3State;
|
||||
|
||||
typedef struct PAMMemoryRegion {
|
||||
MemoryRegion alias[4]; /* index = PAM value */
|
||||
unsigned current;
|
||||
} PAMMemoryRegion;
|
||||
|
||||
struct PCII440FXState {
|
||||
PCIDevice dev;
|
||||
MemoryRegion *system_memory;
|
||||
|
@ -105,52 +101,16 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
|
|||
return (pci_intx + slot_addend) & 3;
|
||||
}
|
||||
|
||||
static void init_pam(PCII440FXState *d, PAMMemoryRegion *mem,
|
||||
uint32_t start, uint32_t size)
|
||||
static void i440fx_update_memory_mappings(PCII440FXState *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* RAM */
|
||||
memory_region_init_alias(&mem->alias[3], "pam-ram", d->ram_memory, start, size);
|
||||
/* ROM (XXX: not quite correct) */
|
||||
memory_region_init_alias(&mem->alias[1], "pam-rom", d->ram_memory, start, size);
|
||||
memory_region_set_readonly(&mem->alias[1], true);
|
||||
|
||||
/* XXX: should distinguish read/write cases */
|
||||
memory_region_init_alias(&mem->alias[0], "pam-pci", d->pci_address_space,
|
||||
start, size);
|
||||
memory_region_init_alias(&mem->alias[2], "pam-pci", d->pci_address_space,
|
||||
start, size);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
memory_region_set_enabled(&mem->alias[i], false);
|
||||
memory_region_add_subregion_overlap(d->system_memory, start, &mem->alias[i], 1);
|
||||
}
|
||||
mem->current = 0;
|
||||
}
|
||||
|
||||
static void update_pam(PAMMemoryRegion *pam, unsigned r)
|
||||
{
|
||||
memory_region_set_enabled(&pam->alias[pam->current], false);
|
||||
pam->current = r;
|
||||
memory_region_set_enabled(&pam->alias[pam->current], true);
|
||||
}
|
||||
|
||||
static void i440fx_update_memory_mappings(PCII440FXState *d)
|
||||
{
|
||||
int i, r;
|
||||
uint32_t smram;
|
||||
bool smram_enabled;
|
||||
|
||||
memory_region_transaction_begin();
|
||||
update_pam(&d->pam_regions[0], (d->dev.config[I440FX_PAM] >> 4) & 3);
|
||||
for(i = 0; i < 12; i++) {
|
||||
r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
|
||||
update_pam(&d->pam_regions[i+1], r);
|
||||
for (i = 0; i < 13; i++) {
|
||||
pam_update(&d->pam_regions[i], i,
|
||||
d->dev.config[I440FX_PAM + ((i + 1) / 2)]);
|
||||
}
|
||||
smram = d->dev.config[I440FX_SMRAM];
|
||||
smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40);
|
||||
memory_region_set_enabled(&d->smram_region, !smram_enabled);
|
||||
smram_update(&d->smram_region, d->dev.config[I440FX_SMRAM], d->smm_enabled);
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
|
@ -158,11 +118,10 @@ static void i440fx_set_smm(int val, void *arg)
|
|||
{
|
||||
PCII440FXState *d = arg;
|
||||
|
||||
val = (val != 0);
|
||||
if (d->smm_enabled != val) {
|
||||
d->smm_enabled = val;
|
||||
i440fx_update_memory_mappings(d);
|
||||
}
|
||||
memory_region_transaction_begin();
|
||||
smram_set_smm(&d->smm_enabled, val, d->dev.config[I440FX_SMRAM],
|
||||
&d->smram_region);
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
|
||||
|
@ -300,9 +259,12 @@ static PCIBus *i440fx_common_init(const char *device_name,
|
|||
memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
|
||||
&f->smram_region, 1);
|
||||
memory_region_set_enabled(&f->smram_region, false);
|
||||
init_pam(f, &f->pam_regions[0], 0xf0000, 0x10000);
|
||||
init_pam(f->ram_memory, f->system_memory, f->pci_address_space,
|
||||
&f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
|
||||
for (i = 0; i < 12; ++i) {
|
||||
init_pam(f, &f->pam_regions[i+1], 0xc0000 + i * 0x4000, 0x4000);
|
||||
init_pam(f->ram_memory, f->system_memory, f->pci_address_space,
|
||||
&f->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
|
||||
PAM_EXPAN_SIZE);
|
||||
}
|
||||
|
||||
/* Xen supports additional interrupt routes from the PCI devices to
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* QEMU MCH/ICH9 PCI Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
* Copyright (c) 2009, 2010, 2011
|
||||
* Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This is based on piix_pci.c, but heavily modified.
|
||||
*
|
||||
* 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 "hw.h"
|
||||
#include "q35.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Q35 host
|
||||
*/
|
||||
|
||||
static int q35_host_init(SysBusDevice *dev)
|
||||
{
|
||||
PCIBus *b;
|
||||
PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev);
|
||||
Q35PCIHost *s = Q35_HOST_DEVICE(&dev->qdev);
|
||||
|
||||
memory_region_init_io(&pci->conf_mem, &pci_host_conf_le_ops, pci,
|
||||
"pci-conf-idx", 4);
|
||||
sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
|
||||
sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_ADDR, 4);
|
||||
|
||||
memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci,
|
||||
"pci-conf-data", 4);
|
||||
sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
|
||||
sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
|
||||
|
||||
if (pcie_host_init(&s->host) < 0) {
|
||||
return -1;
|
||||
}
|
||||
b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0",
|
||||
s->mch.pci_address_space, s->mch.address_space_io, 0);
|
||||
s->host.pci.bus = b;
|
||||
qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
|
||||
qdev_init_nofail(DEVICE(&s->mch));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property mch_props[] = {
|
||||
DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void q35_host_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = q35_host_init;
|
||||
dc->props = mch_props;
|
||||
}
|
||||
|
||||
static void q35_host_initfn(Object *obj)
|
||||
{
|
||||
Q35PCIHost *s = Q35_HOST_DEVICE(obj);
|
||||
|
||||
object_initialize(&s->mch, TYPE_MCH_PCI_DEVICE);
|
||||
object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
|
||||
qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false);
|
||||
}
|
||||
|
||||
static const TypeInfo q35_host_info = {
|
||||
.name = TYPE_Q35_HOST_DEVICE,
|
||||
.parent = TYPE_PCIE_HOST_BRIDGE,
|
||||
.instance_size = sizeof(Q35PCIHost),
|
||||
.instance_init = q35_host_initfn,
|
||||
.class_init = q35_host_class_init,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* MCH D0:F0
|
||||
*/
|
||||
|
||||
/* PCIe MMCFG */
|
||||
static void mch_update_pciexbar(MCHPCIState *mch)
|
||||
{
|
||||
PCIDevice *pci_dev = &mch->d;
|
||||
BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
|
||||
DeviceState *qdev = bus->parent;
|
||||
Q35PCIHost *s = Q35_HOST_DEVICE(qdev);
|
||||
|
||||
uint64_t pciexbar;
|
||||
int enable;
|
||||
uint64_t addr;
|
||||
uint64_t addr_mask;
|
||||
uint32_t length;
|
||||
|
||||
pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR);
|
||||
enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN;
|
||||
addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK;
|
||||
switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) {
|
||||
case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M:
|
||||
length = 256 * 1024 * 1024;
|
||||
break;
|
||||
case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M:
|
||||
length = 128 * 1024 * 1024;
|
||||
addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK |
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
|
||||
break;
|
||||
case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M:
|
||||
length = 64 * 1024 * 1024;
|
||||
addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
|
||||
break;
|
||||
case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD:
|
||||
default:
|
||||
enable = 0;
|
||||
length = 0;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
addr = pciexbar & addr_mask;
|
||||
pcie_host_mmcfg_update(&s->host, enable, addr, length);
|
||||
}
|
||||
|
||||
/* PAM */
|
||||
static void mch_update_pam(MCHPCIState *mch)
|
||||
{
|
||||
int i;
|
||||
|
||||
memory_region_transaction_begin();
|
||||
for (i = 0; i < 13; i++) {
|
||||
pam_update(&mch->pam_regions[i], i,
|
||||
mch->d.config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]);
|
||||
}
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
/* SMRAM */
|
||||
static void mch_update_smram(MCHPCIState *mch)
|
||||
{
|
||||
memory_region_transaction_begin();
|
||||
smram_update(&mch->smram_region, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
|
||||
mch->smm_enabled);
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void mch_set_smm(int smm, void *arg)
|
||||
{
|
||||
MCHPCIState *mch = arg;
|
||||
|
||||
memory_region_transaction_begin();
|
||||
smram_set_smm(&mch->smm_enabled, smm, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
|
||||
&mch->smram_region);
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void mch_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
|
||||
/* XXX: implement SMRAM.D_LOCK */
|
||||
pci_default_write_config(d, address, val, len);
|
||||
|
||||
if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0,
|
||||
MCH_HOST_BRIDGE_PAM_SIZE)) {
|
||||
mch_update_pam(mch);
|
||||
}
|
||||
|
||||
if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR,
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) {
|
||||
mch_update_pciexbar(mch);
|
||||
}
|
||||
|
||||
if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM,
|
||||
MCH_HOST_BRDIGE_SMRAM_SIZE)) {
|
||||
mch_update_smram(mch);
|
||||
}
|
||||
}
|
||||
|
||||
static void mch_update(MCHPCIState *mch)
|
||||
{
|
||||
mch_update_pciexbar(mch);
|
||||
mch_update_pam(mch);
|
||||
mch_update_smram(mch);
|
||||
}
|
||||
|
||||
static int mch_post_load(void *opaque, int version_id)
|
||||
{
|
||||
MCHPCIState *mch = opaque;
|
||||
mch_update(mch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_mch = {
|
||||
.name = "mch",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = mch_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_PCI_DEVICE(d, MCHPCIState),
|
||||
VMSTATE_UINT8(smm_enabled, MCHPCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void mch_reset(DeviceState *qdev)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(qdev);
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
|
||||
pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
|
||||
|
||||
d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
|
||||
|
||||
mch_update(mch);
|
||||
}
|
||||
|
||||
static int mch_init(PCIDevice *d)
|
||||
{
|
||||
int i;
|
||||
hwaddr pci_hole64_size;
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
|
||||
/* setup pci memory regions */
|
||||
memory_region_init_alias(&mch->pci_hole, "pci-hole",
|
||||
mch->pci_address_space,
|
||||
mch->below_4g_mem_size,
|
||||
0x100000000ULL - mch->below_4g_mem_size);
|
||||
memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
|
||||
&mch->pci_hole);
|
||||
pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
|
||||
((uint64_t)1 << 62));
|
||||
memory_region_init_alias(&mch->pci_hole_64bit, "pci-hole64",
|
||||
mch->pci_address_space,
|
||||
0x100000000ULL + mch->above_4g_mem_size,
|
||||
pci_hole64_size);
|
||||
if (pci_hole64_size) {
|
||||
memory_region_add_subregion(mch->system_memory,
|
||||
0x100000000ULL + mch->above_4g_mem_size,
|
||||
&mch->pci_hole_64bit);
|
||||
}
|
||||
/* smram */
|
||||
cpu_smm_register(&mch_set_smm, mch);
|
||||
memory_region_init_alias(&mch->smram_region, "smram-region",
|
||||
mch->pci_address_space, 0xa0000, 0x20000);
|
||||
memory_region_add_subregion_overlap(mch->system_memory, 0xa0000,
|
||||
&mch->smram_region, 1);
|
||||
memory_region_set_enabled(&mch->smram_region, false);
|
||||
init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space,
|
||||
&mch->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
|
||||
for (i = 0; i < 12; ++i) {
|
||||
init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space,
|
||||
&mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
|
||||
PAM_EXPAN_SIZE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mch_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
k->init = mch_init;
|
||||
k->config_write = mch_write_config;
|
||||
dc->reset = mch_reset;
|
||||
dc->desc = "Host bridge";
|
||||
dc->vmsd = &vmstate_mch;
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH;
|
||||
k->revision = MCH_HOST_BRIDGE_REVISION_DEFUALT;
|
||||
k->class_id = PCI_CLASS_BRIDGE_HOST;
|
||||
}
|
||||
|
||||
static const TypeInfo mch_info = {
|
||||
.name = TYPE_MCH_PCI_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(MCHPCIState),
|
||||
.class_init = mch_class_init,
|
||||
};
|
||||
|
||||
static void q35_register(void)
|
||||
{
|
||||
type_register_static(&mch_info);
|
||||
type_register_static(&q35_host_info);
|
||||
}
|
||||
|
||||
type_init(q35_register);
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* q35.h
|
||||
*
|
||||
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef HW_Q35_H
|
||||
#define HW_Q35_H
|
||||
|
||||
#include "hw.h"
|
||||
#include "range.h"
|
||||
#include "isa.h"
|
||||
#include "sysbus.h"
|
||||
#include "pc.h"
|
||||
#include "apm.h"
|
||||
#include "apic.h"
|
||||
#include "pci.h"
|
||||
#include "pcie_host.h"
|
||||
#include "acpi.h"
|
||||
#include "acpi_ich9.h"
|
||||
#include "pam.h"
|
||||
|
||||
#define TYPE_Q35_HOST_DEVICE "q35-pcihost"
|
||||
#define Q35_HOST_DEVICE(obj) \
|
||||
OBJECT_CHECK(Q35PCIHost, (obj), TYPE_Q35_HOST_DEVICE)
|
||||
|
||||
#define TYPE_MCH_PCI_DEVICE "mch"
|
||||
#define MCH_PCI_DEVICE(obj) \
|
||||
OBJECT_CHECK(MCHPCIState, (obj), TYPE_MCH_PCI_DEVICE)
|
||||
|
||||
typedef struct MCHPCIState {
|
||||
PCIDevice d;
|
||||
MemoryRegion *ram_memory;
|
||||
MemoryRegion *pci_address_space;
|
||||
MemoryRegion *system_memory;
|
||||
MemoryRegion *address_space_io;
|
||||
PAMMemoryRegion pam_regions[13];
|
||||
MemoryRegion smram_region;
|
||||
MemoryRegion pci_hole;
|
||||
MemoryRegion pci_hole_64bit;
|
||||
uint8_t smm_enabled;
|
||||
ram_addr_t below_4g_mem_size;
|
||||
ram_addr_t above_4g_mem_size;
|
||||
} MCHPCIState;
|
||||
|
||||
typedef struct Q35PCIHost {
|
||||
PCIExpressHost host;
|
||||
MCHPCIState mch;
|
||||
} Q35PCIHost;
|
||||
|
||||
#define Q35_MASK(bit, ms_bit, ls_bit) \
|
||||
((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
|
||||
|
||||
/*
|
||||
* gmch part
|
||||
*/
|
||||
|
||||
/* PCI configuration */
|
||||
#define MCH_HOST_BRIDGE "MCH"
|
||||
|
||||
#define MCH_HOST_BRIDGE_CONFIG_ADDR 0xcf8
|
||||
#define MCH_HOST_BRIDGE_CONFIG_DATA 0xcfc
|
||||
|
||||
/* D0:F0 configuration space */
|
||||
#define MCH_HOST_BRIDGE_REVISION_DEFUALT 0x0
|
||||
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE 8 /* 64bit register */
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT 0xb0000000
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_ADMSK Q35_MASK(64, 35, 28)
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK ((uint64_t)(1 << 26))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK ((uint64_t)(1 << 25))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK ((uint64_t)(0x3 << 1))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M ((uint64_t)(0x0 << 1))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M ((uint64_t)(0x1 << 1))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M ((uint64_t)(0x2 << 1))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD ((uint64_t)(0x3 << 1))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAREN ((uint64_t)1)
|
||||
|
||||
#define MCH_HOST_BRIDGE_PAM_NB 7
|
||||
#define MCH_HOST_BRIDGE_PAM_SIZE 7
|
||||
#define MCH_HOST_BRIDGE_PAM0 0x90
|
||||
#define MCH_HOST_BRIDGE_PAM_BIOS_AREA 0xf0000
|
||||
#define MCH_HOST_BRIDGE_PAM_AREA_SIZE 0x10000 /* 16KB */
|
||||
#define MCH_HOST_BRIDGE_PAM1 0x91
|
||||
#define MCH_HOST_BRIDGE_PAM_EXPAN_AREA 0xc0000
|
||||
#define MCH_HOST_BRIDGE_PAM_EXPAN_SIZE 0x04000
|
||||
#define MCH_HOST_BRIDGE_PAM2 0x92
|
||||
#define MCH_HOST_BRIDGE_PAM3 0x93
|
||||
#define MCH_HOST_BRIDGE_PAM4 0x94
|
||||
#define MCH_HOST_BRIDGE_PAM_EXBIOS_AREA 0xe0000
|
||||
#define MCH_HOST_BRIDGE_PAM_EXBIOS_SIZE 0x04000
|
||||
#define MCH_HOST_BRIDGE_PAM5 0x95
|
||||
#define MCH_HOST_BRIDGE_PAM6 0x96
|
||||
#define MCH_HOST_BRIDGE_PAM_WE_HI ((uint8_t)(0x2 << 4))
|
||||
#define MCH_HOST_BRIDGE_PAM_RE_HI ((uint8_t)(0x1 << 4))
|
||||
#define MCH_HOST_BRIDGE_PAM_HI_MASK ((uint8_t)(0x3 << 4))
|
||||
#define MCH_HOST_BRIDGE_PAM_WE_LO ((uint8_t)0x2)
|
||||
#define MCH_HOST_BRIDGE_PAM_RE_LO ((uint8_t)0x1)
|
||||
#define MCH_HOST_BRIDGE_PAM_LO_MASK ((uint8_t)0x3)
|
||||
#define MCH_HOST_BRIDGE_PAM_WE ((uint8_t)0x2)
|
||||
#define MCH_HOST_BRIDGE_PAM_RE ((uint8_t)0x1)
|
||||
#define MCH_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3)
|
||||
|
||||
#define MCH_HOST_BRDIGE_SMRAM 0x9d
|
||||
#define MCH_HOST_BRDIGE_SMRAM_SIZE 1
|
||||
#define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2)
|
||||
#define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6))
|
||||
#define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5))
|
||||
#define MCH_HOST_BRIDGE_SMRAM_D_LCK ((uint8_t)(1 << 4))
|
||||
#define MCH_HOST_BRIDGE_SMRAM_G_SMRAME ((uint8_t)(1 << 3))
|
||||
#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7)
|
||||
#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG ((uint8_t)0x2) /* hardwired to b010 */
|
||||
#define MCH_HOST_BRIDGE_SMRAM_C_BASE 0xa0000
|
||||
#define MCH_HOST_BRIDGE_SMRAM_C_END 0xc0000
|
||||
#define MCH_HOST_BRIDGE_SMRAM_C_SIZE 0x20000
|
||||
#define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000
|
||||
|
||||
#define MCH_HOST_BRIDGE_ESMRAMC 0x9e
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1))
|
||||
#define MCH_HOST_BRDIGE_ESMRAMC_T_EN ((uint8_t)1)
|
||||
|
||||
/* D1:F0 PCIE* port*/
|
||||
#define MCH_PCIE_DEV 1
|
||||
#define MCH_PCIE_FUNC 0
|
||||
|
||||
#endif /* HW_Q35_H */
|
|
@ -1,6 +1,7 @@
|
|||
#include "qdev.h"
|
||||
#include "qdev-addr.h"
|
||||
#include "hwaddr.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
|
||||
/* --- target physical address --- */
|
||||
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
#ifndef QDEV_CORE_H
|
||||
#define QDEV_CORE_H
|
||||
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qemu/object.h"
|
||||
#include "hw/irq.h"
|
||||
#include "error.h"
|
||||
|
||||
typedef struct Property Property;
|
||||
|
||||
typedef struct PropertyInfo PropertyInfo;
|
||||
|
||||
typedef struct CompatProperty CompatProperty;
|
||||
|
||||
typedef struct BusState BusState;
|
||||
|
||||
typedef struct BusClass BusClass;
|
||||
|
||||
enum DevState {
|
||||
DEV_STATE_CREATED = 1,
|
||||
DEV_STATE_INITIALIZED,
|
||||
};
|
||||
|
||||
enum {
|
||||
DEV_NVECTORS_UNSPECIFIED = -1,
|
||||
};
|
||||
|
||||
#define TYPE_DEVICE "device"
|
||||
#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
|
||||
#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
|
||||
#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
|
||||
|
||||
typedef int (*qdev_initfn)(DeviceState *dev);
|
||||
typedef int (*qdev_event)(DeviceState *dev);
|
||||
typedef void (*qdev_resetfn)(DeviceState *dev);
|
||||
|
||||
struct VMStateDescription;
|
||||
|
||||
typedef struct DeviceClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
const char *fw_name;
|
||||
const char *desc;
|
||||
Property *props;
|
||||
int no_user;
|
||||
|
||||
/* callbacks */
|
||||
void (*reset)(DeviceState *dev);
|
||||
|
||||
/* device state */
|
||||
const struct VMStateDescription *vmsd;
|
||||
|
||||
/* Private to qdev / bus. */
|
||||
qdev_initfn init;
|
||||
qdev_event unplug;
|
||||
qdev_event exit;
|
||||
const char *bus_type;
|
||||
} DeviceClass;
|
||||
|
||||
/* This structure should not be accessed directly. We declare it here
|
||||
so that it can be embedded in individual device state structures. */
|
||||
struct DeviceState {
|
||||
Object parent_obj;
|
||||
|
||||
const char *id;
|
||||
enum DevState state;
|
||||
QemuOpts *opts;
|
||||
int hotplugged;
|
||||
BusState *parent_bus;
|
||||
int num_gpio_out;
|
||||
qemu_irq *gpio_out;
|
||||
int num_gpio_in;
|
||||
qemu_irq *gpio_in;
|
||||
QLIST_HEAD(, BusState) child_bus;
|
||||
int num_child_bus;
|
||||
int instance_id_alias;
|
||||
int alias_required_for_version;
|
||||
};
|
||||
|
||||
#define TYPE_BUS "bus"
|
||||
#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
|
||||
#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
|
||||
#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS)
|
||||
|
||||
struct BusClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
/* FIXME first arg should be BusState */
|
||||
void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
|
||||
char *(*get_dev_path)(DeviceState *dev);
|
||||
/*
|
||||
* This callback is used to create Open Firmware device path in accordance
|
||||
* with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus
|
||||
* bindings can be found at http://playground.sun.com/1275/bindings/.
|
||||
*/
|
||||
char *(*get_fw_dev_path)(DeviceState *dev);
|
||||
int (*reset)(BusState *bus);
|
||||
};
|
||||
|
||||
typedef struct BusChild {
|
||||
DeviceState *child;
|
||||
int index;
|
||||
QTAILQ_ENTRY(BusChild) sibling;
|
||||
} BusChild;
|
||||
|
||||
/**
|
||||
* BusState:
|
||||
*/
|
||||
struct BusState {
|
||||
Object obj;
|
||||
DeviceState *parent;
|
||||
const char *name;
|
||||
int allow_hotplug;
|
||||
int max_index;
|
||||
QTAILQ_HEAD(ChildrenHead, BusChild) children;
|
||||
QLIST_ENTRY(BusState) sibling;
|
||||
};
|
||||
|
||||
struct Property {
|
||||
const char *name;
|
||||
PropertyInfo *info;
|
||||
int offset;
|
||||
uint8_t bitnr;
|
||||
uint8_t qtype;
|
||||
int64_t defval;
|
||||
};
|
||||
|
||||
struct PropertyInfo {
|
||||
const char *name;
|
||||
const char *legacy_name;
|
||||
const char **enum_table;
|
||||
int (*parse)(DeviceState *dev, Property *prop, const char *str);
|
||||
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
||||
ObjectPropertyAccessor *get;
|
||||
ObjectPropertyAccessor *set;
|
||||
ObjectPropertyRelease *release;
|
||||
};
|
||||
|
||||
typedef struct GlobalProperty {
|
||||
const char *driver;
|
||||
const char *property;
|
||||
const char *value;
|
||||
QTAILQ_ENTRY(GlobalProperty) next;
|
||||
} GlobalProperty;
|
||||
|
||||
/*** Board API. This should go away once we have a machine config file. ***/
|
||||
|
||||
DeviceState *qdev_create(BusState *bus, const char *name);
|
||||
DeviceState *qdev_try_create(BusState *bus, const char *name);
|
||||
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_init_nofail(DeviceState *dev);
|
||||
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
int required_for_version);
|
||||
void qdev_unplug(DeviceState *dev, Error **errp);
|
||||
void qdev_free(DeviceState *dev);
|
||||
int qdev_simple_unplug_cb(DeviceState *dev);
|
||||
void qdev_machine_creation_done(void);
|
||||
bool qdev_machine_modified(void);
|
||||
|
||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
||||
|
||||
BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
|
||||
|
||||
/*** Device API. ***/
|
||||
|
||||
/* Register device properties. */
|
||||
/* GPIO inputs also double as IRQ sinks. */
|
||||
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
||||
|
||||
BusState *qdev_get_parent_bus(DeviceState *dev);
|
||||
|
||||
/*** BUS API. ***/
|
||||
|
||||
DeviceState *qdev_find_recursive(BusState *bus, const char *id);
|
||||
|
||||
/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */
|
||||
typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
|
||||
typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
|
||||
|
||||
void qbus_create_inplace(BusState *bus, const char *typename,
|
||||
DeviceState *parent, const char *name);
|
||||
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
|
||||
/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
|
||||
* < 0 if either devfn or busfn terminate walk somewhere in cursion,
|
||||
* 0 otherwise. */
|
||||
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
|
||||
qbus_walkerfn *busfn, void *opaque);
|
||||
int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
|
||||
qbus_walkerfn *busfn, void *opaque);
|
||||
void qdev_reset_all(DeviceState *dev);
|
||||
void qbus_reset_all_fn(void *opaque);
|
||||
|
||||
void qbus_free(BusState *bus);
|
||||
|
||||
#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
|
||||
|
||||
/* This should go away once we get rid of the NULL bus hack */
|
||||
BusState *sysbus_get_default(void);
|
||||
|
||||
char *qdev_get_fw_dev_path(DeviceState *dev);
|
||||
|
||||
/**
|
||||
* @qdev_machine_init
|
||||
*
|
||||
* Initialize platform devices before machine init. This is a hack until full
|
||||
* support for composition is added.
|
||||
*/
|
||||
void qdev_machine_init(void);
|
||||
|
||||
/**
|
||||
* @device_reset
|
||||
*
|
||||
* Reset a single device (by calling the reset method).
|
||||
*/
|
||||
void device_reset(DeviceState *dev);
|
||||
|
||||
const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev);
|
||||
|
||||
const char *qdev_fw_name(DeviceState *dev);
|
||||
|
||||
Object *qdev_get_machine(void);
|
||||
|
||||
/* FIXME: make this a link<> */
|
||||
void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
|
||||
|
||||
extern int qdev_hotplug;
|
||||
|
||||
char *qdev_get_dev_path(DeviceState *dev);
|
||||
|
||||
#endif
|
|
@ -289,8 +289,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
|
|||
if (name && (strcmp(bus->name, name) != 0)) {
|
||||
match = 0;
|
||||
}
|
||||
if (bus_typename &&
|
||||
(strcmp(object_get_typename(OBJECT(bus)), bus_typename) != 0)) {
|
||||
if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) {
|
||||
match = 0;
|
||||
}
|
||||
if (match) {
|
||||
|
@ -435,7 +434,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
|
|||
if (!bus) {
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(object_get_typename(OBJECT(bus)), k->bus_type) != 0) {
|
||||
if (!object_dynamic_cast(OBJECT(bus), k->bus_type)) {
|
||||
qerror_report(QERR_BAD_BUS_FOR_DEVICE,
|
||||
driver, object_get_typename(OBJECT(bus)));
|
||||
return NULL;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef QEMU_QDEV_MONITOR_H
|
||||
#define QEMU_QDEV_MONITOR_H
|
||||
|
||||
#include "qdev-core.h"
|
||||
#include "monitor.h"
|
||||
|
||||
/*** monitor commands ***/
|
||||
|
||||
void do_info_qtree(Monitor *mon);
|
||||
void do_info_qdm(Monitor *mon);
|
||||
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
int qdev_device_help(QemuOpts *opts);
|
||||
DeviceState *qdev_device_add(QemuOpts *opts);
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "blockdev.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "net/hub.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
|
||||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
#ifndef QEMU_QDEV_PROPERTIES_H
|
||||
#define QEMU_QDEV_PROPERTIES_H
|
||||
|
||||
#include "qdev-core.h"
|
||||
|
||||
/*** qdev-properties.c ***/
|
||||
|
||||
extern PropertyInfo qdev_prop_bit;
|
||||
extern PropertyInfo qdev_prop_uint8;
|
||||
extern PropertyInfo qdev_prop_uint16;
|
||||
extern PropertyInfo qdev_prop_uint32;
|
||||
extern PropertyInfo qdev_prop_int32;
|
||||
extern PropertyInfo qdev_prop_uint64;
|
||||
extern PropertyInfo qdev_prop_hex8;
|
||||
extern PropertyInfo qdev_prop_hex32;
|
||||
extern PropertyInfo qdev_prop_hex64;
|
||||
extern PropertyInfo qdev_prop_string;
|
||||
extern PropertyInfo qdev_prop_chr;
|
||||
extern PropertyInfo qdev_prop_ptr;
|
||||
extern PropertyInfo qdev_prop_macaddr;
|
||||
extern PropertyInfo qdev_prop_losttickpolicy;
|
||||
extern PropertyInfo qdev_prop_bios_chs_trans;
|
||||
extern PropertyInfo qdev_prop_drive;
|
||||
extern PropertyInfo qdev_prop_netdev;
|
||||
extern PropertyInfo qdev_prop_vlan;
|
||||
extern PropertyInfo qdev_prop_pci_devfn;
|
||||
extern PropertyInfo qdev_prop_blocksize;
|
||||
extern PropertyInfo qdev_prop_pci_host_devaddr;
|
||||
|
||||
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
|
||||
.name = (_name), \
|
||||
.info = &(_prop), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(_type,typeof_field(_state, _field)), \
|
||||
}
|
||||
#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
|
||||
.name = (_name), \
|
||||
.info = &(_prop), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(_type,typeof_field(_state, _field)), \
|
||||
.qtype = QTYPE_QINT, \
|
||||
.defval = (_type)_defval, \
|
||||
}
|
||||
#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \
|
||||
.name = (_name), \
|
||||
.info = &(qdev_prop_bit), \
|
||||
.bitnr = (_bit), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(uint32_t,typeof_field(_state, _field)), \
|
||||
.qtype = QTYPE_QBOOL, \
|
||||
.defval = (bool)_defval, \
|
||||
}
|
||||
|
||||
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
|
||||
#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
|
||||
#define DEFINE_PROP_UINT32(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
|
||||
#define DEFINE_PROP_INT32(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
|
||||
#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
|
||||
#define DEFINE_PROP_HEX8(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
|
||||
#define DEFINE_PROP_HEX32(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
|
||||
#define DEFINE_PROP_HEX64(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
|
||||
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
|
||||
|
||||
#define DEFINE_PROP_PTR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
|
||||
#define DEFINE_PROP_CHR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
|
||||
#define DEFINE_PROP_STRING(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
|
||||
#define DEFINE_PROP_NETDEV(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*)
|
||||
#define DEFINE_PROP_VLAN(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*)
|
||||
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
|
||||
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
|
||||
#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
|
||||
LostTickPolicy)
|
||||
#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
|
||||
#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
|
||||
#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
|
||||
|
||||
#define DEFINE_PROP_END_OF_LIST() \
|
||||
{}
|
||||
|
||||
/* Set properties between creation and init. */
|
||||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
|
||||
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
|
||||
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
|
||||
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
|
||||
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
|
||||
void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
|
||||
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
|
||||
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
|
||||
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value);
|
||||
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
|
||||
void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value);
|
||||
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
|
||||
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
|
||||
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
|
||||
/* FIXME: Remove opaque pointer properties. */
|
||||
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
||||
|
||||
void qdev_prop_register_global_list(GlobalProperty *props);
|
||||
void qdev_prop_set_globals(DeviceState *dev);
|
||||
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
||||
Property *prop, const char *value);
|
||||
|
||||
/**
|
||||
* @qdev_property_add_static - add a @Property to a device referencing a
|
||||
* field in a struct.
|
||||
*/
|
||||
void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
|
||||
|
||||
#endif
|
27
hw/qdev.c
27
hw/qdev.c
|
@ -29,6 +29,7 @@
|
|||
#include "qdev.h"
|
||||
#include "sysemu.h"
|
||||
#include "error.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
|
||||
int qdev_hotplug = 0;
|
||||
static bool qdev_hot_added = false;
|
||||
|
@ -453,7 +454,6 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
|
|||
BusState *bus;
|
||||
|
||||
bus = BUS(object_new(typename));
|
||||
bus->qom_allocated = true;
|
||||
|
||||
bus->parent = parent;
|
||||
bus->name = name ? g_strdup(name) : NULL;
|
||||
|
@ -464,14 +464,7 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
|
|||
|
||||
void qbus_free(BusState *bus)
|
||||
{
|
||||
if (bus->qom_allocated) {
|
||||
object_delete(OBJECT(bus));
|
||||
} else {
|
||||
object_finalize(OBJECT(bus));
|
||||
if (bus->glib_allocated) {
|
||||
g_free(bus);
|
||||
}
|
||||
}
|
||||
object_delete(OBJECT(bus));
|
||||
}
|
||||
|
||||
static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
|
||||
|
@ -704,9 +697,6 @@ static void device_finalize(Object *obj)
|
|||
qemu_opts_del(dev->opts);
|
||||
}
|
||||
}
|
||||
if (dev->parent_bus) {
|
||||
bus_remove_child(dev->parent_bus, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void device_class_base_init(ObjectClass *class, void *data)
|
||||
|
@ -719,6 +709,18 @@ static void device_class_base_init(ObjectClass *class, void *data)
|
|||
klass->props = NULL;
|
||||
}
|
||||
|
||||
static void qdev_remove_from_bus(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
bus_remove_child(dev->parent_bus, dev);
|
||||
}
|
||||
|
||||
static void device_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
class->unparent = qdev_remove_from_bus;
|
||||
}
|
||||
|
||||
void device_reset(DeviceState *dev)
|
||||
{
|
||||
DeviceClass *klass = DEVICE_GET_CLASS(dev);
|
||||
|
@ -746,6 +748,7 @@ static TypeInfo device_type_info = {
|
|||
.instance_init = device_initfn,
|
||||
.instance_finalize = device_finalize,
|
||||
.class_base_init = device_class_base_init,
|
||||
.class_init = device_class_init,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(DeviceClass),
|
||||
};
|
||||
|
|
370
hw/qdev.h
370
hw/qdev.h
|
@ -1,371 +1,9 @@
|
|||
#ifndef QDEV_H
|
||||
#define QDEV_H
|
||||
|
||||
#include "hw.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-char.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qemu/object.h"
|
||||
#include "error.h"
|
||||
|
||||
typedef struct Property Property;
|
||||
|
||||
typedef struct PropertyInfo PropertyInfo;
|
||||
|
||||
typedef struct CompatProperty CompatProperty;
|
||||
|
||||
typedef struct BusState BusState;
|
||||
|
||||
typedef struct BusClass BusClass;
|
||||
|
||||
enum DevState {
|
||||
DEV_STATE_CREATED = 1,
|
||||
DEV_STATE_INITIALIZED,
|
||||
};
|
||||
|
||||
enum {
|
||||
DEV_NVECTORS_UNSPECIFIED = -1,
|
||||
};
|
||||
|
||||
#define TYPE_DEVICE "device"
|
||||
#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
|
||||
#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
|
||||
#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
|
||||
|
||||
typedef int (*qdev_initfn)(DeviceState *dev);
|
||||
typedef int (*qdev_event)(DeviceState *dev);
|
||||
typedef void (*qdev_resetfn)(DeviceState *dev);
|
||||
|
||||
typedef struct DeviceClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
const char *fw_name;
|
||||
const char *desc;
|
||||
Property *props;
|
||||
int no_user;
|
||||
|
||||
/* callbacks */
|
||||
void (*reset)(DeviceState *dev);
|
||||
|
||||
/* device state */
|
||||
const VMStateDescription *vmsd;
|
||||
|
||||
/* Private to qdev / bus. */
|
||||
qdev_initfn init;
|
||||
qdev_event unplug;
|
||||
qdev_event exit;
|
||||
const char *bus_type;
|
||||
} DeviceClass;
|
||||
|
||||
/* This structure should not be accessed directly. We declare it here
|
||||
so that it can be embedded in individual device state structures. */
|
||||
struct DeviceState {
|
||||
Object parent_obj;
|
||||
|
||||
const char *id;
|
||||
enum DevState state;
|
||||
QemuOpts *opts;
|
||||
int hotplugged;
|
||||
BusState *parent_bus;
|
||||
int num_gpio_out;
|
||||
qemu_irq *gpio_out;
|
||||
int num_gpio_in;
|
||||
qemu_irq *gpio_in;
|
||||
QLIST_HEAD(, BusState) child_bus;
|
||||
int num_child_bus;
|
||||
int instance_id_alias;
|
||||
int alias_required_for_version;
|
||||
};
|
||||
|
||||
#define TYPE_BUS "bus"
|
||||
#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
|
||||
#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
|
||||
#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS)
|
||||
|
||||
struct BusClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
/* FIXME first arg should be BusState */
|
||||
void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
|
||||
char *(*get_dev_path)(DeviceState *dev);
|
||||
/*
|
||||
* This callback is used to create Open Firmware device path in accordance
|
||||
* with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus
|
||||
* bindings can be found at http://playground.sun.com/1275/bindings/.
|
||||
*/
|
||||
char *(*get_fw_dev_path)(DeviceState *dev);
|
||||
int (*reset)(BusState *bus);
|
||||
};
|
||||
|
||||
typedef struct BusChild {
|
||||
DeviceState *child;
|
||||
int index;
|
||||
QTAILQ_ENTRY(BusChild) sibling;
|
||||
} BusChild;
|
||||
|
||||
/**
|
||||
* BusState:
|
||||
* @qom_allocated: Indicates whether the object was allocated by QOM.
|
||||
* @glib_allocated: Indicates whether the object was initialized in-place
|
||||
* yet is expected to be freed with g_free().
|
||||
*/
|
||||
struct BusState {
|
||||
Object obj;
|
||||
DeviceState *parent;
|
||||
const char *name;
|
||||
int allow_hotplug;
|
||||
bool qom_allocated;
|
||||
bool glib_allocated;
|
||||
int max_index;
|
||||
QTAILQ_HEAD(ChildrenHead, BusChild) children;
|
||||
QLIST_ENTRY(BusState) sibling;
|
||||
};
|
||||
|
||||
struct Property {
|
||||
const char *name;
|
||||
PropertyInfo *info;
|
||||
int offset;
|
||||
uint8_t bitnr;
|
||||
uint8_t qtype;
|
||||
int64_t defval;
|
||||
};
|
||||
|
||||
struct PropertyInfo {
|
||||
const char *name;
|
||||
const char *legacy_name;
|
||||
const char **enum_table;
|
||||
int (*parse)(DeviceState *dev, Property *prop, const char *str);
|
||||
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
||||
ObjectPropertyAccessor *get;
|
||||
ObjectPropertyAccessor *set;
|
||||
ObjectPropertyRelease *release;
|
||||
};
|
||||
|
||||
typedef struct GlobalProperty {
|
||||
const char *driver;
|
||||
const char *property;
|
||||
const char *value;
|
||||
QTAILQ_ENTRY(GlobalProperty) next;
|
||||
} GlobalProperty;
|
||||
|
||||
/*** Board API. This should go away once we have a machine config file. ***/
|
||||
|
||||
DeviceState *qdev_create(BusState *bus, const char *name);
|
||||
DeviceState *qdev_try_create(BusState *bus, const char *name);
|
||||
int qdev_device_help(QemuOpts *opts);
|
||||
DeviceState *qdev_device_add(QemuOpts *opts);
|
||||
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_init_nofail(DeviceState *dev);
|
||||
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
int required_for_version);
|
||||
void qdev_unplug(DeviceState *dev, Error **errp);
|
||||
void qdev_free(DeviceState *dev);
|
||||
int qdev_simple_unplug_cb(DeviceState *dev);
|
||||
void qdev_machine_creation_done(void);
|
||||
bool qdev_machine_modified(void);
|
||||
|
||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
||||
|
||||
BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
|
||||
|
||||
/*** Device API. ***/
|
||||
|
||||
/* Register device properties. */
|
||||
/* GPIO inputs also double as IRQ sinks. */
|
||||
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
||||
|
||||
BusState *qdev_get_parent_bus(DeviceState *dev);
|
||||
|
||||
/*** BUS API. ***/
|
||||
|
||||
DeviceState *qdev_find_recursive(BusState *bus, const char *id);
|
||||
|
||||
/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */
|
||||
typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
|
||||
typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
|
||||
|
||||
void qbus_create_inplace(BusState *bus, const char *typename,
|
||||
DeviceState *parent, const char *name);
|
||||
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
|
||||
/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
|
||||
* < 0 if either devfn or busfn terminate walk somewhere in cursion,
|
||||
* 0 otherwise. */
|
||||
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
|
||||
qbus_walkerfn *busfn, void *opaque);
|
||||
int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
|
||||
qbus_walkerfn *busfn, void *opaque);
|
||||
void qdev_reset_all(DeviceState *dev);
|
||||
void qbus_reset_all_fn(void *opaque);
|
||||
|
||||
void qbus_free(BusState *bus);
|
||||
|
||||
#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
|
||||
|
||||
/* This should go away once we get rid of the NULL bus hack */
|
||||
BusState *sysbus_get_default(void);
|
||||
|
||||
/*** monitor commands ***/
|
||||
|
||||
void do_info_qtree(Monitor *mon);
|
||||
void do_info_qdm(Monitor *mon);
|
||||
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
|
||||
/*** qdev-properties.c ***/
|
||||
|
||||
extern PropertyInfo qdev_prop_bit;
|
||||
extern PropertyInfo qdev_prop_uint8;
|
||||
extern PropertyInfo qdev_prop_uint16;
|
||||
extern PropertyInfo qdev_prop_uint32;
|
||||
extern PropertyInfo qdev_prop_int32;
|
||||
extern PropertyInfo qdev_prop_uint64;
|
||||
extern PropertyInfo qdev_prop_hex8;
|
||||
extern PropertyInfo qdev_prop_hex32;
|
||||
extern PropertyInfo qdev_prop_hex64;
|
||||
extern PropertyInfo qdev_prop_string;
|
||||
extern PropertyInfo qdev_prop_chr;
|
||||
extern PropertyInfo qdev_prop_ptr;
|
||||
extern PropertyInfo qdev_prop_macaddr;
|
||||
extern PropertyInfo qdev_prop_losttickpolicy;
|
||||
extern PropertyInfo qdev_prop_bios_chs_trans;
|
||||
extern PropertyInfo qdev_prop_drive;
|
||||
extern PropertyInfo qdev_prop_netdev;
|
||||
extern PropertyInfo qdev_prop_vlan;
|
||||
extern PropertyInfo qdev_prop_pci_devfn;
|
||||
extern PropertyInfo qdev_prop_blocksize;
|
||||
extern PropertyInfo qdev_prop_pci_host_devaddr;
|
||||
|
||||
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
|
||||
.name = (_name), \
|
||||
.info = &(_prop), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(_type,typeof_field(_state, _field)), \
|
||||
}
|
||||
#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
|
||||
.name = (_name), \
|
||||
.info = &(_prop), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(_type,typeof_field(_state, _field)), \
|
||||
.qtype = QTYPE_QINT, \
|
||||
.defval = (_type)_defval, \
|
||||
}
|
||||
#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \
|
||||
.name = (_name), \
|
||||
.info = &(qdev_prop_bit), \
|
||||
.bitnr = (_bit), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(uint32_t,typeof_field(_state, _field)), \
|
||||
.qtype = QTYPE_QBOOL, \
|
||||
.defval = (bool)_defval, \
|
||||
}
|
||||
|
||||
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
|
||||
#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
|
||||
#define DEFINE_PROP_UINT32(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
|
||||
#define DEFINE_PROP_INT32(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
|
||||
#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
|
||||
#define DEFINE_PROP_HEX8(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
|
||||
#define DEFINE_PROP_HEX32(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
|
||||
#define DEFINE_PROP_HEX64(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
|
||||
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
|
||||
|
||||
#define DEFINE_PROP_PTR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
|
||||
#define DEFINE_PROP_CHR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
|
||||
#define DEFINE_PROP_STRING(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
|
||||
#define DEFINE_PROP_NETDEV(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*)
|
||||
#define DEFINE_PROP_VLAN(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*)
|
||||
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
|
||||
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
|
||||
#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
|
||||
LostTickPolicy)
|
||||
#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
|
||||
#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
|
||||
#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
|
||||
|
||||
#define DEFINE_PROP_END_OF_LIST() \
|
||||
{}
|
||||
|
||||
/* Set properties between creation and init. */
|
||||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
|
||||
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
|
||||
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
|
||||
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
|
||||
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
|
||||
void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
|
||||
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
|
||||
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
|
||||
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value);
|
||||
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
|
||||
void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value);
|
||||
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
|
||||
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
|
||||
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
|
||||
/* FIXME: Remove opaque pointer properties. */
|
||||
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
||||
|
||||
void qdev_prop_register_global_list(GlobalProperty *props);
|
||||
void qdev_prop_set_globals(DeviceState *dev);
|
||||
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
||||
Property *prop, const char *value);
|
||||
|
||||
char *qdev_get_fw_dev_path(DeviceState *dev);
|
||||
|
||||
/**
|
||||
* @qdev_property_add_static - add a @Property to a device referencing a
|
||||
* field in a struct.
|
||||
*/
|
||||
void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
|
||||
|
||||
/**
|
||||
* @qdev_machine_init
|
||||
*
|
||||
* Initialize platform devices before machine init. This is a hack until full
|
||||
* support for composition is added.
|
||||
*/
|
||||
void qdev_machine_init(void);
|
||||
|
||||
/**
|
||||
* @device_reset
|
||||
*
|
||||
* Reset a single device (by calling the reset method).
|
||||
*/
|
||||
void device_reset(DeviceState *dev);
|
||||
|
||||
const VMStateDescription *qdev_get_vmsd(DeviceState *dev);
|
||||
|
||||
const char *qdev_fw_name(DeviceState *dev);
|
||||
|
||||
Object *qdev_get_machine(void);
|
||||
|
||||
/* FIXME: make this a link<> */
|
||||
void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
|
||||
|
||||
extern int qdev_hotplug;
|
||||
|
||||
char *qdev_get_dev_path(DeviceState *dev);
|
||||
#include "hw/hw.h"
|
||||
#include "qdev-core.h"
|
||||
#include "qdev-properties.h"
|
||||
#include "qdev-monitor.h"
|
||||
|
||||
#endif
|
||||
|
|
1
hw/qxl.c
1
hw/qxl.c
|
@ -2146,6 +2146,7 @@ static int qxl_post_load(void *opaque, int version)
|
|||
|
||||
switch (newmode) {
|
||||
case QXL_MODE_UNDEFINED:
|
||||
qxl_create_memslots(d);
|
||||
break;
|
||||
case QXL_MODE_VGA:
|
||||
qxl_create_memslots(d);
|
||||
|
|
|
@ -155,7 +155,6 @@ unsigned s390_del_running_cpu(CPUS390XState *env)
|
|||
static void s390_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t my_ram_size = args->ram_size;
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
|
|
|
@ -112,12 +112,13 @@ static uint16_t handle_write_event_buf(SCLPEventFacility *ef,
|
|||
SCLPEvent *event;
|
||||
SCLPEventClass *ec;
|
||||
|
||||
rc = SCLP_RC_INVALID_FUNCTION;
|
||||
|
||||
QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
|
||||
DeviceState *qdev = kid->child;
|
||||
event = (SCLPEvent *) qdev;
|
||||
ec = SCLP_EVENT_GET_CLASS(event);
|
||||
|
||||
rc = SCLP_RC_INVALID_FUNCTION;
|
||||
if (ec->write_event_data &&
|
||||
ec->event_type() == event_buf->type) {
|
||||
rc = ec->write_event_data(event, event_buf);
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* ACPI implementation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
|
||||
* VA Linux Systems Japan K.K.
|
||||
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
* This is based on acpi.c, but heavily rewritten.
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "pm_smbus.h"
|
||||
#include "pci.h"
|
||||
#include "sysemu.h"
|
||||
#include "i2c.h"
|
||||
#include "smbus.h"
|
||||
|
||||
#include "ich9.h"
|
||||
|
||||
#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB"
|
||||
#define ICH9_SMB_DEVICE(obj) \
|
||||
OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE)
|
||||
|
||||
typedef struct ICH9SMBState {
|
||||
PCIDevice dev;
|
||||
|
||||
PMSMBus smb;
|
||||
MemoryRegion mem_bar;
|
||||
} ICH9SMBState;
|
||||
|
||||
static const VMStateDescription vmstate_ich9_smbus = {
|
||||
.name = "ich9_smb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void ich9_smb_ioport_writeb(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
ICH9SMBState *s = opaque;
|
||||
uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
|
||||
|
||||
if ((hostc & ICH9_SMB_HOSTC_HST_EN) && !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
|
||||
uint64_t offset = addr - s->dev.io_regions[ICH9_SMB_SMB_BASE_BAR].addr;
|
||||
smb_ioport_writeb(&s->smb, offset, val);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t ich9_smb_ioport_readb(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
ICH9SMBState *s = opaque;
|
||||
uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
|
||||
|
||||
if ((hostc & ICH9_SMB_HOSTC_HST_EN) && !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
|
||||
uint64_t offset = addr - s->dev.io_regions[ICH9_SMB_SMB_BASE_BAR].addr;
|
||||
return smb_ioport_readb(&s->smb, offset);
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps lpc_smb_mmio_ops = {
|
||||
.read = ich9_smb_ioport_readb,
|
||||
.write = ich9_smb_ioport_writeb,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int ich9_smbus_initfn(PCIDevice *d)
|
||||
{
|
||||
ICH9SMBState *s = ICH9_SMB_DEVICE(d);
|
||||
|
||||
/* TODO? D31IP.SMIP in chipset configuration space */
|
||||
pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
|
||||
|
||||
pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
|
||||
|
||||
/*
|
||||
* update parameters based on
|
||||
* paralell_hds[0]
|
||||
* serial_hds[0]
|
||||
* serial_hds[0]
|
||||
* fdc
|
||||
*
|
||||
* Is there any OS that depends on them?
|
||||
*/
|
||||
|
||||
/* TODO smb_io_base */
|
||||
pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
|
||||
/* TODO bar0, bar1: 64bit BAR support*/
|
||||
|
||||
memory_region_init_io(&s->mem_bar, &lpc_smb_mmio_ops, s, "ich9-smbus-bar",
|
||||
ICH9_SMB_SMB_BASE_SIZE);
|
||||
pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
|
||||
&s->mem_bar);
|
||||
pm_smbus_init(&d->qdev, &s->smb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ich9_smb_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
|
||||
k->revision = ICH9_A2_SMB_REVISION;
|
||||
k->class_id = PCI_CLASS_SERIAL_SMBUS;
|
||||
dc->no_user = 1;
|
||||
dc->vmsd = &vmstate_ich9_smbus;
|
||||
dc->desc = "ICH9 SMBUS Bridge";
|
||||
k->init = ich9_smbus_initfn;
|
||||
}
|
||||
|
||||
i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
|
||||
{
|
||||
PCIDevice *d =
|
||||
pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE);
|
||||
ICH9SMBState *s = ICH9_SMB_DEVICE(d);
|
||||
return s->smb.smbus;
|
||||
}
|
||||
|
||||
static const TypeInfo ich9_smb_info = {
|
||||
.name = TYPE_ICH9_SMB_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(ICH9SMBState),
|
||||
.class_init = ich9_smb_class_init,
|
||||
};
|
||||
|
||||
static void ich9_smb_register(void)
|
||||
{
|
||||
type_register_static(&ich9_smb_info);
|
||||
}
|
||||
|
||||
type_init(ich9_smb_register);
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "memory.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
struct soc_dma_s;
|
||||
struct soc_dma_ch_s;
|
||||
|
|
|
@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
|
|||
|
||||
/* There is no cached config, allocate MSIs */
|
||||
if (!phb->msi_table[ndev].nvec) {
|
||||
irq = spapr_allocate_irq_block(req_num, true);
|
||||
irq = spapr_allocate_irq_block(req_num, false);
|
||||
if (irq < 0) {
|
||||
fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
|
|
|
@ -274,7 +274,7 @@ static void main_system_bus_create(void)
|
|||
main_system_bus = g_malloc0(system_bus_info.instance_size);
|
||||
qbus_create_inplace(main_system_bus, TYPE_SYSTEM_BUS, NULL,
|
||||
"main-system-bus");
|
||||
main_system_bus->glib_allocated = true;
|
||||
OBJECT(main_system_bus)->free = g_free;
|
||||
object_property_add_child(container_get(qdev_get_machine(),
|
||||
"/unattached"),
|
||||
"sysbus", OBJECT(main_system_bus), NULL);
|
||||
|
|
|
@ -590,6 +590,13 @@ USBDevice *usbdevice_create(const char *cmdline)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!bus) {
|
||||
error_report("Error: no usb bus to attach usbdevice %s, "
|
||||
"please try -machine usb=on and check that "
|
||||
"the machine model supports USB", driver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!f->usbdevice_init) {
|
||||
if (*params) {
|
||||
error_report("usbdevice %s accepts no params", driver);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
struct USBBtState {
|
||||
USBDevice dev;
|
||||
struct HCIInfo *hci;
|
||||
USBEndpoint *intr;
|
||||
|
||||
int config;
|
||||
|
||||
|
@ -290,10 +291,7 @@ static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
|
|||
{
|
||||
int len;
|
||||
|
||||
if (likely(!fifo->len)) {
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
assert(fifo->len != 0);
|
||||
|
||||
len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
|
||||
usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
|
||||
|
@ -422,14 +420,26 @@ static void usb_bt_handle_data(USBDevice *dev, USBPacket *p)
|
|||
case USB_TOKEN_IN:
|
||||
switch (p->ep->nr) {
|
||||
case USB_EVT_EP:
|
||||
if (s->evt.len == 0) {
|
||||
p->status = USB_RET_NAK;
|
||||
break;
|
||||
}
|
||||
usb_bt_fifo_dequeue(&s->evt, p);
|
||||
break;
|
||||
|
||||
case USB_ACL_EP:
|
||||
if (s->evt.len == 0) {
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
usb_bt_fifo_dequeue(&s->acl, p);
|
||||
break;
|
||||
|
||||
case USB_SCO_EP:
|
||||
if (s->evt.len == 0) {
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
usb_bt_fifo_dequeue(&s->sco, p);
|
||||
break;
|
||||
|
||||
|
@ -467,6 +477,9 @@ static void usb_bt_out_hci_packet_event(void *opaque,
|
|||
{
|
||||
struct USBBtState *s = (struct USBBtState *) opaque;
|
||||
|
||||
if (s->evt.len == 0) {
|
||||
usb_wakeup(s->intr);
|
||||
}
|
||||
usb_bt_fifo_enqueue(&s->evt, data, len);
|
||||
}
|
||||
|
||||
|
@ -489,8 +502,12 @@ static void usb_bt_handle_destroy(USBDevice *dev)
|
|||
|
||||
static int usb_bt_initfn(USBDevice *dev)
|
||||
{
|
||||
struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev);
|
||||
|
||||
usb_desc_create_serial(dev);
|
||||
usb_desc_init(dev);
|
||||
s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1002,6 +1002,8 @@ static void ccid_handle_data(USBDevice *dev, USBPacket *p)
|
|||
"handle_data: int_in: notify_slot_change %X, "
|
||||
"requested len %zd\n",
|
||||
s->bmSlotICCState, p->iov.size);
|
||||
} else {
|
||||
p->status = USB_RET_NAK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
#include "hw/pci.h"
|
||||
#include "range.h"
|
||||
|
||||
typedef struct EHCIPCIState {
|
||||
PCIDevice pcidev;
|
||||
|
@ -79,6 +80,21 @@ static int usb_ehci_pci_initfn(PCIDevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
|
||||
uint32_t val, int l)
|
||||
{
|
||||
EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
|
||||
bool busmaster;
|
||||
|
||||
pci_default_write_config(dev, addr, val, l);
|
||||
|
||||
if (!range_covers_byte(addr, l, PCI_COMMAND)) {
|
||||
return;
|
||||
}
|
||||
busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER;
|
||||
i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL;
|
||||
}
|
||||
|
||||
static Property ehci_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@ -106,6 +122,8 @@ static void ehci_class_init(ObjectClass *klass, void *data)
|
|||
k->device_id = i->device_id;
|
||||
k->revision = i->revision;
|
||||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
k->config_write = usb_ehci_pci_write_config;
|
||||
k->no_hotplug = 1;
|
||||
dc->vmsd = &vmstate_ehci_pci;
|
||||
dc->props = ehci_pci_properties;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ static int usb_ehci_sysbus_initfn(SysBusDevice *dev)
|
|||
|
||||
s->capsbase = 0x100;
|
||||
s->opregbase = 0x140;
|
||||
s->dma = &dma_context_memory;
|
||||
|
||||
usb_ehci_initfn(s, DEVICE(dev));
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
|
|
@ -189,6 +189,7 @@ static const char *ehci_mmio_names[] = {
|
|||
|
||||
static int ehci_state_executing(EHCIQueue *q);
|
||||
static int ehci_state_writeback(EHCIQueue *q);
|
||||
static int ehci_state_advqueue(EHCIQueue *q);
|
||||
static int ehci_fill_queue(EHCIPacket *p);
|
||||
|
||||
static const char *nr2str(const char **n, size_t len, uint32_t nr)
|
||||
|
@ -453,12 +454,16 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
|
|||
static void ehci_free_packet(EHCIPacket *p)
|
||||
{
|
||||
if (p->async == EHCI_ASYNC_FINISHED) {
|
||||
int state = ehci_get_state(p->queue->ehci, p->queue->async);
|
||||
EHCIQueue *q = p->queue;
|
||||
int state = ehci_get_state(q->ehci, q->async);
|
||||
/* This is a normal, but rare condition (cancel racing completion) */
|
||||
fprintf(stderr, "EHCI: Warning packet completed but not processed\n");
|
||||
ehci_state_executing(p->queue);
|
||||
ehci_state_writeback(p->queue);
|
||||
ehci_set_state(p->queue->ehci, p->queue->async, state);
|
||||
ehci_state_executing(q);
|
||||
ehci_state_writeback(q);
|
||||
if (!(q->qh.token & QTD_TOKEN_HALT)) {
|
||||
ehci_state_advqueue(q);
|
||||
}
|
||||
ehci_set_state(q->ehci, q->async, state);
|
||||
/* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
|
||||
return;
|
||||
}
|
||||
|
@ -959,6 +964,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
|
|||
|
||||
case USBINTR:
|
||||
val &= USBINTR_MASK;
|
||||
if (ehci_enabled(s) && (USBSTS_FLR & val)) {
|
||||
qemu_bh_schedule(s->async_bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case FRINDEX:
|
||||
|
@ -995,21 +1003,25 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
|
|||
*mmio, old);
|
||||
}
|
||||
|
||||
|
||||
// TODO : Put in common header file, duplication from usb-ohci.c
|
||||
|
||||
/* Get an array of dwords from main memory */
|
||||
static inline int get_dwords(EHCIState *ehci, uint32_t addr,
|
||||
uint32_t *buf, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ehci->dma) {
|
||||
ehci_raise_irq(ehci, USBSTS_HSE);
|
||||
ehci->usbcmd &= ~USBCMD_RUNSTOP;
|
||||
trace_usb_ehci_dma_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
|
||||
dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
|
||||
*buf = le32_to_cpu(*buf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Put an array of dwords in to main memory */
|
||||
|
@ -1018,12 +1030,19 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr,
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!ehci->dma) {
|
||||
ehci_raise_irq(ehci, USBSTS_HSE);
|
||||
ehci->usbcmd &= ~USBCMD_RUNSTOP;
|
||||
trace_usb_ehci_dma_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
|
||||
uint32_t tmp = cpu_to_le32(*buf);
|
||||
dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
return 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1435,8 +1454,10 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
|
|||
|
||||
/* Find the head of the list (4.9.1.1) */
|
||||
for(i = 0; i < MAX_QH; i++) {
|
||||
get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
|
||||
sizeof(EHCIqh) >> 2);
|
||||
if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
|
||||
sizeof(EHCIqh) >> 2) < 0) {
|
||||
return 0;
|
||||
}
|
||||
ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
|
||||
|
||||
if (qh.epchar & QH_EPCHAR_H) {
|
||||
|
@ -1533,8 +1554,11 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|||
goto out;
|
||||
}
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||
(uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
||||
if (get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||
(uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) {
|
||||
q = NULL;
|
||||
goto out;
|
||||
}
|
||||
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
|
||||
|
||||
/*
|
||||
|
@ -1545,8 +1569,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|||
endp = get_field(qh.epchar, QH_EPCHAR_EP);
|
||||
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
|
||||
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
|
||||
(memcmp(&qh.current_qtd, &q->qh.current_qtd,
|
||||
9 * sizeof(uint32_t)) != 0) ||
|
||||
(qh.current_qtd != q->qh.current_qtd) ||
|
||||
(q->async && qh.next_qtd != q->qh.next_qtd) ||
|
||||
(memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd,
|
||||
7 * sizeof(uint32_t)) != 0) ||
|
||||
(q->dev != NULL && q->dev->addr != devaddr)) {
|
||||
if (ehci_reset_queue(q) > 0) {
|
||||
ehci_trace_guest_bug(ehci, "guest updated active QH");
|
||||
|
@ -1621,8 +1647,10 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
|
|||
assert(!async);
|
||||
entry = ehci_get_fetch_addr(ehci, async);
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
|
||||
sizeof(EHCIitd) >> 2);
|
||||
if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
|
||||
sizeof(EHCIitd) >> 2) < 0) {
|
||||
return -1;
|
||||
}
|
||||
ehci_trace_itd(ehci, entry, &itd);
|
||||
|
||||
if (ehci_process_itd(ehci, &itd, entry) != 0) {
|
||||
|
@ -1645,8 +1673,10 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
|
|||
assert(!async);
|
||||
entry = ehci_get_fetch_addr(ehci, async);
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
|
||||
sizeof(EHCIsitd) >> 2);
|
||||
if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
|
||||
sizeof(EHCIsitd) >> 2) < 0) {
|
||||
return 0;
|
||||
}
|
||||
ehci_trace_sitd(ehci, entry, &sitd);
|
||||
|
||||
if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
|
||||
|
@ -1707,14 +1737,17 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
|||
EHCIPacket *p;
|
||||
int again = 1;
|
||||
|
||||
get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
|
||||
sizeof(EHCIqtd) >> 2);
|
||||
if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
|
||||
sizeof(EHCIqtd) >> 2) < 0) {
|
||||
return 0;
|
||||
}
|
||||
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
|
||||
|
||||
p = QTAILQ_FIRST(&q->packets);
|
||||
if (p != NULL) {
|
||||
if (p->qtdaddr != q->qtdaddr ||
|
||||
(!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
|
||||
(q->async && !NLPTR_TBIT(p->qtd.next) &&
|
||||
(p->qtd.next != qtd.next)) ||
|
||||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
|
||||
p->qtd.bufptr[0] != qtd.bufptr[0]) {
|
||||
ehci_cancel_queue(q);
|
||||
|
@ -1785,7 +1818,7 @@ static int ehci_fill_queue(EHCIPacket *p)
|
|||
USBEndpoint *ep = p->packet.ep;
|
||||
EHCIQueue *q = p->queue;
|
||||
EHCIqtd qtd = p->qtd;
|
||||
uint32_t qtdaddr, start_addr = p->qtdaddr;
|
||||
uint32_t qtdaddr;
|
||||
|
||||
for (;;) {
|
||||
if (NLPTR_TBIT(qtd.next) != 0) {
|
||||
|
@ -1796,11 +1829,15 @@ static int ehci_fill_queue(EHCIPacket *p)
|
|||
* Detect circular td lists, Windows creates these, counting on the
|
||||
* active bit going low after execution to make the queue stop.
|
||||
*/
|
||||
if (qtdaddr == start_addr) {
|
||||
break;
|
||||
QTAILQ_FOREACH(p, &q->packets, next) {
|
||||
if (p->qtdaddr == qtdaddr) {
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (get_dwords(q->ehci, NLPTR_GET(qtdaddr),
|
||||
(uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) {
|
||||
return -1;
|
||||
}
|
||||
get_dwords(q->ehci, NLPTR_GET(qtdaddr),
|
||||
(uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
|
||||
ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
|
||||
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
|
||||
break;
|
||||
|
@ -1814,6 +1851,7 @@ static int ehci_fill_queue(EHCIPacket *p)
|
|||
assert(p->packet.status == USB_RET_ASYNC);
|
||||
p->async = EHCI_ASYNC_INFLIGHT;
|
||||
}
|
||||
leave:
|
||||
usb_device_flush_ep_queue(ep->dev, ep);
|
||||
return 1;
|
||||
}
|
||||
|
@ -2098,8 +2136,9 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
|
|||
}
|
||||
list |= ((ehci->frindex & 0x1ff8) >> 1);
|
||||
|
||||
dma_memory_read(ehci->dma, list, &entry, sizeof entry);
|
||||
entry = le32_to_cpu(entry);
|
||||
if (get_dwords(ehci, list, &entry, 1) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
|
||||
ehci->frindex / 8, list, entry);
|
||||
|
@ -2209,6 +2248,10 @@ static void ehci_frame_timer(void *opaque)
|
|||
ehci->async_stepdown = 0;
|
||||
}
|
||||
|
||||
if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) {
|
||||
need_timer++;
|
||||
}
|
||||
|
||||
if (need_timer) {
|
||||
/* If we've raised int, we speed up the timer, so that we quickly
|
||||
* notice any new packets queued up in response */
|
||||
|
|
|
@ -1882,6 +1882,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
|
|||
k->vendor_id = PCI_VENDOR_ID_APPLE;
|
||||
k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
|
||||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
k->no_hotplug = 1;
|
||||
dc->desc = "Apple USB Controller";
|
||||
dc->props = ohci_pci_properties;
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ struct UHCIState {
|
|||
QEMUBH *bh;
|
||||
uint32_t frame_bytes;
|
||||
uint32_t frame_bandwidth;
|
||||
bool completions_only;
|
||||
UHCIPort ports[NB_PORTS];
|
||||
|
||||
/* Interrupts that should be raised at the end of the current frame. */
|
||||
|
@ -555,6 +556,10 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
port->ctrl &= UHCI_PORT_READ_ONLY;
|
||||
/* enabled may only be set if a device is connected */
|
||||
if (!(port->ctrl & UHCI_PORT_CCS)) {
|
||||
val &= ~UHCI_PORT_EN;
|
||||
}
|
||||
port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
|
||||
/* some bits are reset when a '1' is written to them */
|
||||
port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
|
||||
|
@ -891,6 +896,10 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (s->completions_only) {
|
||||
return TD_RESULT_ASYNC_CONT;
|
||||
}
|
||||
|
||||
/* Allocate new packet */
|
||||
if (q == NULL) {
|
||||
USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
|
||||
|
@ -954,15 +963,14 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet)
|
|||
UHCIState *s = async->queue->uhci;
|
||||
|
||||
if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
|
||||
uhci_async_unlink(async);
|
||||
uhci_async_cancel(async);
|
||||
return;
|
||||
}
|
||||
|
||||
async->done = 1;
|
||||
if (s->frame_bytes < s->frame_bandwidth) {
|
||||
qemu_bh_schedule(s->bh);
|
||||
}
|
||||
/* Force processing of this packet *now*, needed for migration */
|
||||
s->completions_only = true;
|
||||
qemu_bh_schedule(s->bh);
|
||||
}
|
||||
|
||||
static int is_valid(uint32_t link)
|
||||
|
@ -1054,7 +1062,7 @@ static void uhci_process_frame(UHCIState *s)
|
|||
qhdb_reset(&qhdb);
|
||||
|
||||
for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
|
||||
if (s->frame_bytes >= s->frame_bandwidth) {
|
||||
if (!s->completions_only && s->frame_bytes >= s->frame_bandwidth) {
|
||||
/* We've reached the usb 1.1 bandwidth, which is
|
||||
1280 bytes/frame, stop processing */
|
||||
trace_usb_uhci_frame_stop_bandwidth();
|
||||
|
@ -1170,6 +1178,7 @@ static void uhci_frame_timer(void *opaque)
|
|||
/* prepare the timer for the next frame */
|
||||
s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
|
||||
s->frame_bytes = 0;
|
||||
s->completions_only = false;
|
||||
qemu_bh_cancel(s->bh);
|
||||
|
||||
if (!(s->cmd & UHCI_CMD_RS)) {
|
||||
|
@ -1318,6 +1327,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
|
|||
k->device_id = info->device_id;
|
||||
k->revision = info->revision;
|
||||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
k->no_hotplug = 1;
|
||||
dc->vmsd = &vmstate_uhci;
|
||||
dc->props = uhci_properties;
|
||||
u->info = *info;
|
||||
|
|
|
@ -3167,6 +3167,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
|
|||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
k->revision = 0x03;
|
||||
k->is_express = 1;
|
||||
k->no_hotplug = 1;
|
||||
}
|
||||
|
||||
static TypeInfo xhci_info = {
|
||||
|
|
|
@ -135,7 +135,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f);
|
|||
static void usb_host_auto_check(void *unused);
|
||||
static int usb_host_read_file(char *line, size_t line_size,
|
||||
const char *device_file, const char *device_name);
|
||||
static int usb_linux_update_endp_table(USBHostDevice *s);
|
||||
static void usb_linux_update_endp_table(USBHostDevice *s);
|
||||
|
||||
static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
|
||||
{
|
||||
|
@ -366,8 +366,11 @@ static void async_complete(void *opaque)
|
|||
if (p) {
|
||||
switch (aurb->urb.status) {
|
||||
case 0:
|
||||
p->actual_length = aurb->urb.actual_length;
|
||||
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
||||
p->actual_length += aurb->urb.actual_length;
|
||||
if (!aurb->more) {
|
||||
/* Clear previous ASYNC status */
|
||||
p->status = USB_RET_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case -EPIPE:
|
||||
|
@ -385,10 +388,12 @@ static void async_complete(void *opaque)
|
|||
}
|
||||
|
||||
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status);
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
p->status, aurb->urb.actual_length);
|
||||
usb_generic_async_ctrl_complete(&s->dev, p);
|
||||
} else if (!aurb->more) {
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status);
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
p->status, aurb->urb.actual_length);
|
||||
usb_packet_complete(&s->dev, p);
|
||||
}
|
||||
}
|
||||
|
@ -863,8 +868,9 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
|
|||
p->ep->nr, p->iov.size);
|
||||
|
||||
if (!is_valid(s, p->pid, p->ep->nr)) {
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
|
||||
p->status = USB_RET_NAK;
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
p->status, p->actual_length);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -879,8 +885,9 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
|
|||
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
|
||||
if (ret < 0) {
|
||||
perror("USBDEVFS_CLEAR_HALT");
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
|
||||
p->status = USB_RET_NAK;
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
p->status, p->actual_length);
|
||||
return;
|
||||
}
|
||||
clear_halt(s, p->pid, p->ep->nr);
|
||||
|
@ -936,15 +943,15 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
|
|||
|
||||
switch(errno) {
|
||||
case ETIMEDOUT:
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
USB_RET_NAK);
|
||||
p->status = USB_RET_NAK;
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
p->status, p->actual_length);
|
||||
break;
|
||||
case EPIPE:
|
||||
default:
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
USB_RET_STALL);
|
||||
p->status = USB_RET_STALL;
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, p,
|
||||
p->status, p->actual_length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1132,8 +1139,7 @@ static void usb_host_handle_control(USBDevice *dev, USBPacket *p,
|
|||
p->status = USB_RET_ASYNC;
|
||||
}
|
||||
|
||||
/* returns 1 on problem encountered or 0 for success */
|
||||
static int usb_linux_update_endp_table(USBHostDevice *s)
|
||||
static void usb_linux_update_endp_table(USBHostDevice *s)
|
||||
{
|
||||
static const char *tname[] = {
|
||||
[USB_ENDPOINT_XFER_CONTROL] = "control",
|
||||
|
@ -1159,23 +1165,23 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||
if (d->bLength < 2) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"descriptor too short");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
if (i + d->bLength > s->descr_len) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"descriptor too long");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
switch (d->bDescriptorType) {
|
||||
case 0:
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"invalid descriptor type");
|
||||
goto error;
|
||||
return;
|
||||
case USB_DT_DEVICE:
|
||||
if (d->bLength < 0x12) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"device descriptor too short");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
|
||||
p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
|
||||
|
@ -1185,7 +1191,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||
if (d->bLength < 0x09) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"config descriptor too short");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
configuration = d->u.config.bConfigurationValue;
|
||||
active = (configuration == s->dev.configuration);
|
||||
|
@ -1196,7 +1202,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||
if (d->bLength < 0x09) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"interface descriptor too short");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
interface = d->u.interface.bInterfaceNumber;
|
||||
altsetting = d->u.interface.bAlternateSetting;
|
||||
|
@ -1209,7 +1215,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||
if (d->bLength < 0x07) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"endpoint descriptor too short");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
devep = d->u.endpoint.bEndpointAddress;
|
||||
pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
|
@ -1217,7 +1223,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||
if (ep == 0) {
|
||||
trace_usb_host_parse_error(s->bus_num, s->addr,
|
||||
"invalid endpoint address");
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
|
||||
type = d->u.endpoint.bmAttributes & 0x3;
|
||||
|
@ -1250,11 +1256,6 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
|||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
usb_ep_reset(&s->dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1341,10 +1342,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
|
|||
}
|
||||
|
||||
usb_ep_init(&dev->dev);
|
||||
ret = usb_linux_update_endp_table(dev);
|
||||
if (ret) {
|
||||
goto fail;
|
||||
}
|
||||
usb_linux_update_endp_table(dev);
|
||||
|
||||
if (speed == -1) {
|
||||
struct usbdevfs_connectinfo ci;
|
||||
|
@ -1738,6 +1736,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
|
|||
}
|
||||
|
||||
static QEMUTimer *usb_auto_timer;
|
||||
static VMChangeStateEntry *usb_vmstate;
|
||||
|
||||
static int usb_host_auto_scan(void *opaque, int bus_num,
|
||||
int addr, const char *port,
|
||||
|
@ -1792,6 +1791,13 @@ static int usb_host_auto_scan(void *opaque, int bus_num,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void usb_host_vm_state(void *unused, int running, RunState state)
|
||||
{
|
||||
if (running) {
|
||||
usb_host_auto_check(unused);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_host_auto_check(void *unused)
|
||||
{
|
||||
struct USBHostDevice *s;
|
||||
|
@ -1820,6 +1826,9 @@ static void usb_host_auto_check(void *unused)
|
|||
}
|
||||
}
|
||||
|
||||
if (!usb_vmstate) {
|
||||
usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL);
|
||||
}
|
||||
if (!usb_auto_timer) {
|
||||
usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
|
||||
if (!usb_auto_timer) {
|
||||
|
|
|
@ -37,7 +37,7 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
|
|||
|
||||
while (len) {
|
||||
dma_addr_t xlen = len;
|
||||
mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &xlen, dir);
|
||||
mem = dma_memory_map(sgl->dma, base, &xlen, dir);
|
||||
if (!mem) {
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -342,7 +342,9 @@ static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev,
|
|||
if (p->combined && p != p->combined->first) {
|
||||
continue;
|
||||
}
|
||||
packet_id_queue_add(&dev->already_in_flight, p->id);
|
||||
if (p->state == USB_PACKET_ASYNC) {
|
||||
packet_id_queue_add(&dev->already_in_flight, p->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,80 +610,82 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
|||
p->status = USB_RET_ASYNC;
|
||||
}
|
||||
|
||||
static void usbredir_handle_interrupt_data(USBRedirDevice *dev,
|
||||
USBPacket *p, uint8_t ep)
|
||||
static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
|
||||
USBPacket *p, uint8_t ep)
|
||||
{
|
||||
if (ep & USB_DIR_IN) {
|
||||
/* Input interrupt endpoint, buffered packet input */
|
||||
struct buf_packet *intp;
|
||||
int status, len;
|
||||
/* Input interrupt endpoint, buffered packet input */
|
||||
struct buf_packet *intp;
|
||||
int status, len;
|
||||
|
||||
if (!dev->endpoint[EP2I(ep)].interrupt_started &&
|
||||
!dev->endpoint[EP2I(ep)].interrupt_error) {
|
||||
struct usb_redir_start_interrupt_receiving_header start_int = {
|
||||
.endpoint = ep,
|
||||
};
|
||||
/* No id, we look at the ep when receiving a status back */
|
||||
usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
|
||||
&start_int);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
DPRINTF("interrupt recv started ep %02X\n", ep);
|
||||
dev->endpoint[EP2I(ep)].interrupt_started = 1;
|
||||
/* We don't really want to drop interrupt packets ever, but
|
||||
having some upper limit to how much we buffer is good. */
|
||||
dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
|
||||
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
|
||||
}
|
||||
|
||||
intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
|
||||
if (intp == NULL) {
|
||||
DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
|
||||
/* Check interrupt_error for stream errors */
|
||||
status = dev->endpoint[EP2I(ep)].interrupt_error;
|
||||
dev->endpoint[EP2I(ep)].interrupt_error = 0;
|
||||
if (status) {
|
||||
usbredir_handle_status(dev, p, status);
|
||||
} else {
|
||||
p->status = USB_RET_NAK;
|
||||
}
|
||||
return;
|
||||
}
|
||||
DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
|
||||
intp->status, intp->len);
|
||||
|
||||
status = intp->status;
|
||||
len = intp->len;
|
||||
if (len > p->iov.size) {
|
||||
ERROR("received int data is larger then packet ep %02X\n", ep);
|
||||
len = p->iov.size;
|
||||
status = usb_redir_babble;
|
||||
}
|
||||
usb_packet_copy(p, intp->data, len);
|
||||
bufp_free(dev, intp, ep);
|
||||
usbredir_handle_status(dev, p, status);
|
||||
} else {
|
||||
/* Output interrupt endpoint, normal async operation */
|
||||
struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||
uint8_t buf[p->iov.size];
|
||||
|
||||
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
|
||||
p->iov.size, p->id);
|
||||
|
||||
if (usbredir_already_in_flight(dev, p->id)) {
|
||||
p->status = USB_RET_ASYNC;
|
||||
return;
|
||||
}
|
||||
|
||||
interrupt_packet.endpoint = ep;
|
||||
interrupt_packet.length = p->iov.size;
|
||||
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
|
||||
usbredirparser_send_interrupt_packet(dev->parser, p->id,
|
||||
&interrupt_packet, buf, p->iov.size);
|
||||
if (!dev->endpoint[EP2I(ep)].interrupt_started &&
|
||||
!dev->endpoint[EP2I(ep)].interrupt_error) {
|
||||
struct usb_redir_start_interrupt_receiving_header start_int = {
|
||||
.endpoint = ep,
|
||||
};
|
||||
/* No id, we look at the ep when receiving a status back */
|
||||
usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
|
||||
&start_int);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
p->status = USB_RET_ASYNC;
|
||||
DPRINTF("interrupt recv started ep %02X\n", ep);
|
||||
dev->endpoint[EP2I(ep)].interrupt_started = 1;
|
||||
/* We don't really want to drop interrupt packets ever, but
|
||||
having some upper limit to how much we buffer is good. */
|
||||
dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
|
||||
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
|
||||
}
|
||||
|
||||
intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
|
||||
if (intp == NULL) {
|
||||
DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
|
||||
/* Check interrupt_error for stream errors */
|
||||
status = dev->endpoint[EP2I(ep)].interrupt_error;
|
||||
dev->endpoint[EP2I(ep)].interrupt_error = 0;
|
||||
if (status) {
|
||||
usbredir_handle_status(dev, p, status);
|
||||
} else {
|
||||
p->status = USB_RET_NAK;
|
||||
}
|
||||
return;
|
||||
}
|
||||
DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
|
||||
intp->status, intp->len);
|
||||
|
||||
status = intp->status;
|
||||
len = intp->len;
|
||||
if (len > p->iov.size) {
|
||||
ERROR("received int data is larger then packet ep %02X\n", ep);
|
||||
len = p->iov.size;
|
||||
status = usb_redir_babble;
|
||||
}
|
||||
usb_packet_copy(p, intp->data, len);
|
||||
bufp_free(dev, intp, ep);
|
||||
usbredir_handle_status(dev, p, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle interrupt out data, the usbredir protocol expects us to do this
|
||||
* async, so that it can report back a completion status. But guests will
|
||||
* expect immediate completion for an interrupt endpoint, and handling this
|
||||
* async causes migration issues. So we report success directly, counting
|
||||
* on the fact that output interrupt packets normally always succeed.
|
||||
*/
|
||||
static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev,
|
||||
USBPacket *p, uint8_t ep)
|
||||
{
|
||||
struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||
uint8_t buf[p->iov.size];
|
||||
|
||||
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
|
||||
p->iov.size, p->id);
|
||||
|
||||
interrupt_packet.endpoint = ep;
|
||||
interrupt_packet.length = p->iov.size;
|
||||
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
|
||||
usbredirparser_send_interrupt_packet(dev->parser, p->id,
|
||||
&interrupt_packet, buf, p->iov.size);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
|
||||
static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
|
||||
|
@ -727,7 +731,11 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p)
|
|||
usbredir_handle_bulk_data(dev, p, ep);
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
usbredir_handle_interrupt_data(dev, p, ep);
|
||||
if (ep & USB_DIR_IN) {
|
||||
usbredir_handle_interrupt_in_data(dev, p, ep);
|
||||
} else {
|
||||
usbredir_handle_interrupt_out_data(dev, p, ep);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("handle_data ep %02X has unknown type %d\n", ep,
|
||||
|
@ -1639,11 +1647,13 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
|
|||
/* bufp_alloc also adds the packet to the ep queue */
|
||||
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
|
||||
} else {
|
||||
USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
|
||||
if (p) {
|
||||
usbredir_handle_status(dev, p, interrupt_packet->status);
|
||||
p->actual_length = interrupt_packet->length;
|
||||
usb_packet_complete(&dev->dev, p);
|
||||
/*
|
||||
* We report output interrupt packets as completed directly upon
|
||||
* submission, so all we can do here if one failed is warn.
|
||||
*/
|
||||
if (interrupt_packet->status) {
|
||||
WARNING("interrupt output failed status %d ep %02X id %"PRIu64"\n",
|
||||
interrupt_packet->status, ep, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1960,7 +1970,7 @@ static const VMStateDescription usbredir_vmstate = {
|
|||
|
||||
static Property usbredir_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
|
||||
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
|
||||
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning),
|
||||
DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
|
||||
DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
|
101
hw/virtio-rng.c
101
hw/virtio-rng.c
|
@ -22,14 +22,9 @@ typedef struct VirtIORNG {
|
|||
|
||||
/* Only one vq - guest puts buffer(s) on it when it needs entropy */
|
||||
VirtQueue *vq;
|
||||
VirtQueueElement elem;
|
||||
|
||||
/* Config data for the device -- currently only chardev */
|
||||
VirtIORNGConf *conf;
|
||||
|
||||
/* Whether we've popped a vq element into 'elem' above */
|
||||
bool popped;
|
||||
|
||||
RngBackend *rng;
|
||||
|
||||
/* We purposefully don't migrate this state. The quota will reset on the
|
||||
|
@ -48,17 +43,12 @@ static bool is_guest_ready(VirtIORNG *vrng)
|
|||
return false;
|
||||
}
|
||||
|
||||
static size_t pop_an_elem(VirtIORNG *vrng)
|
||||
static size_t get_request_size(VirtQueue *vq, unsigned quota)
|
||||
{
|
||||
size_t size;
|
||||
unsigned int in, out;
|
||||
|
||||
if (!vrng->popped && !virtqueue_pop(vrng->vq, &vrng->elem)) {
|
||||
return 0;
|
||||
}
|
||||
vrng->popped = true;
|
||||
|
||||
size = iov_size(vrng->elem.in_sg, vrng->elem.in_num);
|
||||
return size;
|
||||
virtqueue_get_avail_bytes(vq, &in, &out, quota, 0);
|
||||
return in;
|
||||
}
|
||||
|
||||
static void virtio_rng_process(VirtIORNG *vrng);
|
||||
|
@ -67,6 +57,7 @@ static void virtio_rng_process(VirtIORNG *vrng);
|
|||
static void chr_read(void *opaque, const void *buf, size_t size)
|
||||
{
|
||||
VirtIORNG *vrng = opaque;
|
||||
VirtQueueElement elem;
|
||||
size_t len;
|
||||
int offset;
|
||||
|
||||
|
@ -78,43 +69,39 @@ static void chr_read(void *opaque, const void *buf, size_t size)
|
|||
|
||||
offset = 0;
|
||||
while (offset < size) {
|
||||
if (!pop_an_elem(vrng)) {
|
||||
if (!virtqueue_pop(vrng->vq, &elem)) {
|
||||
break;
|
||||
}
|
||||
len = iov_from_buf(vrng->elem.in_sg, vrng->elem.in_num,
|
||||
len = iov_from_buf(elem.in_sg, elem.in_num,
|
||||
0, buf + offset, size - offset);
|
||||
offset += len;
|
||||
|
||||
virtqueue_push(vrng->vq, &vrng->elem, len);
|
||||
vrng->popped = false;
|
||||
virtqueue_push(vrng->vq, &elem, len);
|
||||
}
|
||||
virtio_notify(&vrng->vdev, vrng->vq);
|
||||
|
||||
/*
|
||||
* Lastly, if we had multiple elems queued by the guest, and we
|
||||
* didn't have enough data to fill them all, indicate we want more
|
||||
* data.
|
||||
*/
|
||||
virtio_rng_process(vrng);
|
||||
}
|
||||
|
||||
static void virtio_rng_process(VirtIORNG *vrng)
|
||||
{
|
||||
ssize_t size;
|
||||
size_t size;
|
||||
unsigned quota;
|
||||
|
||||
if (!is_guest_ready(vrng)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = pop_an_elem(vrng);
|
||||
if (vrng->quota_remaining < 0) {
|
||||
quota = 0;
|
||||
} else {
|
||||
quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX);
|
||||
}
|
||||
size = get_request_size(vrng->vq, quota);
|
||||
size = MIN(vrng->quota_remaining, size);
|
||||
|
||||
if (size > 0) {
|
||||
if (size) {
|
||||
rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
|
||||
|
@ -131,23 +118,6 @@ static void virtio_rng_save(QEMUFile *f, void *opaque)
|
|||
VirtIORNG *vrng = opaque;
|
||||
|
||||
virtio_save(&vrng->vdev, f);
|
||||
|
||||
qemu_put_byte(f, vrng->popped);
|
||||
if (vrng->popped) {
|
||||
int i;
|
||||
|
||||
qemu_put_be32(f, vrng->elem.index);
|
||||
|
||||
qemu_put_be32(f, vrng->elem.in_num);
|
||||
for (i = 0; i < vrng->elem.in_num; i++) {
|
||||
qemu_put_be64(f, vrng->elem.in_addr[i]);
|
||||
}
|
||||
|
||||
qemu_put_be32(f, vrng->elem.out_num);
|
||||
for (i = 0; i < vrng->elem.out_num; i++) {
|
||||
qemu_put_be64(f, vrng->elem.out_addr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
|
||||
|
@ -159,34 +129,10 @@ static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
|
|||
}
|
||||
virtio_load(&vrng->vdev, f);
|
||||
|
||||
vrng->popped = qemu_get_byte(f);
|
||||
if (vrng->popped) {
|
||||
int i;
|
||||
|
||||
vrng->elem.index = qemu_get_be32(f);
|
||||
|
||||
vrng->elem.in_num = qemu_get_be32(f);
|
||||
g_assert(vrng->elem.in_num < VIRTQUEUE_MAX_SIZE);
|
||||
for (i = 0; i < vrng->elem.in_num; i++) {
|
||||
vrng->elem.in_addr[i] = qemu_get_be64(f);
|
||||
}
|
||||
|
||||
vrng->elem.out_num = qemu_get_be32(f);
|
||||
g_assert(vrng->elem.out_num < VIRTQUEUE_MAX_SIZE);
|
||||
for (i = 0; i < vrng->elem.out_num; i++) {
|
||||
vrng->elem.out_addr[i] = qemu_get_be64(f);
|
||||
}
|
||||
|
||||
virtqueue_map_sg(vrng->elem.in_sg, vrng->elem.in_addr,
|
||||
vrng->elem.in_num, 1);
|
||||
virtqueue_map_sg(vrng->elem.out_sg, vrng->elem.out_addr,
|
||||
vrng->elem.out_num, 0);
|
||||
}
|
||||
|
||||
/* We may have an element ready but couldn't process it due to a quota
|
||||
limit. Make sure to try again after live migration when the quota may
|
||||
have been reset.
|
||||
*/
|
||||
* limit. Make sure to try again after live migration when the quota may
|
||||
* have been reset.
|
||||
*/
|
||||
virtio_rng_process(vrng);
|
||||
|
||||
return 0;
|
||||
|
@ -232,10 +178,9 @@ VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
|
|||
|
||||
vrng->qdev = dev;
|
||||
vrng->conf = conf;
|
||||
vrng->popped = false;
|
||||
vrng->quota_remaining = vrng->conf->max_bytes;
|
||||
|
||||
g_assert_cmpint(vrng->conf->max_bytes, <=, INT64_MAX);
|
||||
assert(vrng->conf->max_bytes <= INT64_MAX);
|
||||
vrng->quota_remaining = vrng->conf->max_bytes;
|
||||
|
||||
vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock,
|
||||
check_rate_limit, vrng);
|
||||
|
@ -253,6 +198,8 @@ void virtio_rng_exit(VirtIODevice *vdev)
|
|||
{
|
||||
VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
|
||||
|
||||
qemu_del_timer(vrng->rate_limit_timer);
|
||||
qemu_free_timer(vrng->rate_limit_timer);
|
||||
unregister_savevm(vrng->qdev, "virtio-rng", vrng);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
|
|
@ -424,15 +424,17 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
|||
size_t resid)
|
||||
{
|
||||
VirtIOSCSIReq *req = r->hba_private;
|
||||
uint32_t sense_len;
|
||||
|
||||
req->resp.cmd->response = VIRTIO_SCSI_S_OK;
|
||||
req->resp.cmd->status = status;
|
||||
if (req->resp.cmd->status == GOOD) {
|
||||
req->resp.cmd->resid = resid;
|
||||
req->resp.cmd->resid = tswap32(resid);
|
||||
} else {
|
||||
req->resp.cmd->resid = 0;
|
||||
req->resp.cmd->sense_len =
|
||||
scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
|
||||
sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
|
||||
VIRTIO_SCSI_SENSE_SIZE);
|
||||
req->resp.cmd->sense_len = tswap32(sense_len);
|
||||
}
|
||||
virtio_scsi_complete_req(req);
|
||||
}
|
||||
|
@ -532,8 +534,8 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
|
|||
stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
||||
stl_raw(&scsiconf->sense_size, s->sense_size);
|
||||
stl_raw(&scsiconf->cdb_size, s->cdb_size);
|
||||
stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
|
||||
stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
|
||||
stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
|
||||
stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
|
||||
stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,15 @@ struct VirtIOSerial {
|
|||
uint32_t *ports_map;
|
||||
|
||||
struct virtio_console_config config;
|
||||
|
||||
struct {
|
||||
QEMUTimer *timer;
|
||||
int nr_active_ports;
|
||||
struct {
|
||||
VirtIOSerialPort *port;
|
||||
uint8_t host_connected;
|
||||
} *connected;
|
||||
} post_load;
|
||||
};
|
||||
|
||||
static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
|
||||
|
@ -297,7 +306,7 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
|
|||
if (use_multiport(port->vser) && !port->guest_connected) {
|
||||
return 0;
|
||||
}
|
||||
virtqueue_get_avail_bytes(vq, &bytes, NULL);
|
||||
virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
@ -626,6 +635,29 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
|
|||
}
|
||||
}
|
||||
|
||||
static void virtio_serial_post_load_timer_cb(void *opaque)
|
||||
{
|
||||
int i;
|
||||
VirtIOSerial *s = opaque;
|
||||
VirtIOSerialPort *port;
|
||||
uint8_t host_connected;
|
||||
|
||||
for (i = 0 ; i < s->post_load.nr_active_ports; ++i) {
|
||||
port = s->post_load.connected[i].port;
|
||||
host_connected = s->post_load.connected[i].host_connected;
|
||||
if (host_connected != port->host_connected) {
|
||||
/*
|
||||
* We have to let the guest know of the host connection
|
||||
* status change
|
||||
*/
|
||||
send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
|
||||
port->host_connected);
|
||||
}
|
||||
}
|
||||
g_free(s->post_load.connected);
|
||||
s->post_load.connected = NULL;
|
||||
}
|
||||
|
||||
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOSerial *s = opaque;
|
||||
|
@ -673,10 +705,13 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
|||
|
||||
qemu_get_be32s(f, &nr_active_ports);
|
||||
|
||||
s->post_load.nr_active_ports = nr_active_ports;
|
||||
s->post_load.connected =
|
||||
g_malloc0(sizeof(*s->post_load.connected) * nr_active_ports);
|
||||
|
||||
/* Items in struct VirtIOSerialPort */
|
||||
for (i = 0; i < nr_active_ports; i++) {
|
||||
uint32_t id;
|
||||
bool host_connected;
|
||||
|
||||
id = qemu_get_be32(f);
|
||||
port = find_port_by_id(s, id);
|
||||
|
@ -685,15 +720,8 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
|||
}
|
||||
|
||||
port->guest_connected = qemu_get_byte(f);
|
||||
host_connected = qemu_get_byte(f);
|
||||
if (host_connected != port->host_connected) {
|
||||
/*
|
||||
* We have to let the guest know of the host connection
|
||||
* status change
|
||||
*/
|
||||
send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
|
||||
port->host_connected);
|
||||
}
|
||||
s->post_load.connected[i].port = port;
|
||||
s->post_load.connected[i].host_connected = qemu_get_byte(f);
|
||||
|
||||
if (version_id > 2) {
|
||||
uint32_t elem_popped;
|
||||
|
@ -718,6 +746,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
|||
}
|
||||
}
|
||||
}
|
||||
qemu_mod_timer(s->post_load.timer, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -967,6 +996,9 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
|
|||
register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
|
||||
virtio_serial_load, vser);
|
||||
|
||||
vser->post_load.timer = qemu_new_timer_ns(vm_clock,
|
||||
virtio_serial_post_load_timer_cb, vser);
|
||||
|
||||
return vdev;
|
||||
}
|
||||
|
||||
|
@ -979,6 +1011,8 @@ void virtio_serial_exit(VirtIODevice *vdev)
|
|||
g_free(vser->ivqs);
|
||||
g_free(vser->ovqs);
|
||||
g_free(vser->ports_map);
|
||||
g_free(vser->post_load.connected);
|
||||
qemu_free_timer(vser->post_load.timer);
|
||||
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
|
15
hw/virtio.c
15
hw/virtio.c
|
@ -336,7 +336,8 @@ static unsigned virtqueue_next_desc(hwaddr desc_pa,
|
|||
}
|
||||
|
||||
void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
|
||||
unsigned int *out_bytes)
|
||||
unsigned int *out_bytes,
|
||||
unsigned max_in_bytes, unsigned max_out_bytes)
|
||||
{
|
||||
unsigned int idx;
|
||||
unsigned int total_bufs, in_total, out_total;
|
||||
|
@ -385,6 +386,9 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
|
|||
} else {
|
||||
out_total += vring_desc_len(desc_pa, i);
|
||||
}
|
||||
if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
|
||||
goto done;
|
||||
}
|
||||
} while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
|
||||
|
||||
if (!indirect)
|
||||
|
@ -392,6 +396,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
|
|||
else
|
||||
total_bufs++;
|
||||
}
|
||||
done:
|
||||
if (in_bytes) {
|
||||
*in_bytes = in_total;
|
||||
}
|
||||
|
@ -405,12 +410,8 @@ int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
|
|||
{
|
||||
unsigned int in_total, out_total;
|
||||
|
||||
virtqueue_get_avail_bytes(vq, &in_total, &out_total);
|
||||
if ((in_bytes && in_bytes < in_total)
|
||||
|| (out_bytes && out_bytes < out_total)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes);
|
||||
return in_bytes <= in_total && out_bytes <= out_total;
|
||||
}
|
||||
|
||||
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
|
||||
|
|
|
@ -150,7 +150,8 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
|
|||
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
|
||||
unsigned int out_bytes);
|
||||
void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
|
||||
unsigned int *out_bytes);
|
||||
unsigned int *out_bytes,
|
||||
unsigned max_in_bytes, unsigned max_out_bytes);
|
||||
|
||||
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
|
||||
|
||||
|
|
1
hw/xen.h
1
hw/xen.h
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "hw/irq.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
/* xen-machine.c */
|
||||
|
|
|
@ -229,6 +229,23 @@ typedef struct ObjectProperty
|
|||
QTAILQ_ENTRY(ObjectProperty) node;
|
||||
} ObjectProperty;
|
||||
|
||||
/**
|
||||
* ObjectUnparent:
|
||||
* @obj: the object that is being removed from the composition tree
|
||||
*
|
||||
* Called when an object is being removed from the QOM composition tree.
|
||||
* The function should remove any backlinks from children objects to @obj.
|
||||
*/
|
||||
typedef void (ObjectUnparent)(Object *obj);
|
||||
|
||||
/**
|
||||
* ObjectFree:
|
||||
* @obj: the object being freed
|
||||
*
|
||||
* Called when an object's last reference is removed.
|
||||
*/
|
||||
typedef void (ObjectFree)(void *obj);
|
||||
|
||||
/**
|
||||
* ObjectClass:
|
||||
*
|
||||
|
@ -240,6 +257,8 @@ struct ObjectClass
|
|||
/*< private >*/
|
||||
Type type;
|
||||
GSList *interfaces;
|
||||
|
||||
ObjectUnparent *unparent;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -261,6 +280,7 @@ struct Object
|
|||
{
|
||||
/*< private >*/
|
||||
ObjectClass *class;
|
||||
ObjectFree *free;
|
||||
QTAILQ_HEAD(, ObjectProperty) properties;
|
||||
uint32_t ref;
|
||||
Object *parent;
|
||||
|
@ -484,15 +504,6 @@ void object_initialize_with_type(void *data, Type type);
|
|||
*/
|
||||
void object_initialize(void *obj, const char *typename);
|
||||
|
||||
/**
|
||||
* object_finalize:
|
||||
* @obj: The object to finalize.
|
||||
*
|
||||
* This function destroys and object without freeing the memory associated with
|
||||
* it.
|
||||
*/
|
||||
void object_finalize(void *obj);
|
||||
|
||||
/**
|
||||
* object_dynamic_cast:
|
||||
* @obj: The object to cast.
|
||||
|
|
|
@ -42,7 +42,7 @@ static inline void ratelimit_set_speed(RateLimit *limit, uint64_t speed,
|
|||
uint64_t slice_ns)
|
||||
{
|
||||
limit->slice_ns = slice_ns;
|
||||
limit->slice_quota = ((double)speed * 1000000000ULL) / slice_ns;
|
||||
limit->slice_quota = ((double)speed * slice_ns)/1000000000ULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -61,10 +61,10 @@ struct RngBackend
|
|||
* This function is used by the front-end to request entropy from an entropy
|
||||
* source. This function can be called multiple times before @receive_entropy
|
||||
* is invoked with different values of @receive_entropy and @opaque. The
|
||||
* backend will queue each request and handle appropriate.
|
||||
* backend will queue each request and handle appropriately.
|
||||
*
|
||||
* The backend does not need to pass the full amount of data to @receive_entropy
|
||||
* but will pass at a value greater than 0.
|
||||
* but will pass a value greater than 0.
|
||||
*/
|
||||
void rng_backend_request_entropy(RngBackend *s, size_t size,
|
||||
EntropyReceiveFunc *receive_entropy,
|
||||
|
@ -87,7 +87,7 @@ void rng_backend_cancel_requests(RngBackend *s);
|
|||
*
|
||||
* This function will open the backend if it is not already open. Calling this
|
||||
* function on an already opened backend will not result in an error.
|
||||
*/
|
||||
*/
|
||||
void rng_backend_open(RngBackend *s, Error **errp);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -364,7 +364,7 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
|
|||
unsigned int i, j;
|
||||
unsigned long page_number, c;
|
||||
hwaddr addr, addr1;
|
||||
unsigned int len = ((section->size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
|
||||
unsigned int len = ((section->size / getpagesize()) + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
|
||||
unsigned long hpratio = getpagesize() / TARGET_PAGE_SIZE;
|
||||
|
||||
/*
|
||||
|
@ -1905,6 +1905,8 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env)
|
|||
}
|
||||
}
|
||||
}
|
||||
QTAILQ_REMOVE(&s->kvm_sw_breakpoints, bp, entry);
|
||||
g_free(bp);
|
||||
}
|
||||
kvm_arch_remove_all_hw_breakpoints();
|
||||
|
||||
|
|
2
kvm.h
2
kvm.h
|
@ -275,4 +275,6 @@ void kvm_irqchip_release_virq(KVMState *s, int virq);
|
|||
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
void kvm_pc_gsi_handler(void *opaque, int n, int level);
|
||||
void kvm_pc_setup_irq_routing(bool pci_enabled);
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue