diff options
138 files changed, 10685 insertions, 9993 deletions
diff --git a/Makefile.objs b/Makefile.objs index 44d9bb9043..01587c8f8f 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -81,7 +81,7 @@ common-obj-y += $(oslib-obj-y) common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o -common-obj-y += tcg-runtime.o host-utils.o +common-obj-y += tcg-runtime.o host-utils.o main-loop.o common-obj-y += irq.o input.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_MAX7310) += max7310.o @@ -305,7 +305,7 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) -9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o +9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o diff --git a/Makefile.target b/Makefile.target index 417f23e00e..fe5f6f70af 100644 --- a/Makefile.target +++ b/Makefile.target @@ -74,8 +74,15 @@ libobj-y += op_helper.o helper.o ifeq ($(TARGET_BASE_ARCH), i386) libobj-y += cpuid.o endif +libobj-$(TARGET_SPARC64) += vis_helper.o libobj-$(CONFIG_NEED_MMU) += mmu.o libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o +ifeq ($(TARGET_BASE_ARCH), sparc) +libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o +libobj-y += cpu_init.o +endif +libobj-$(TARGET_SPARC) += int32_helper.o +libobj-$(TARGET_SPARC64) += int64_helper.o libobj-y += disas.o @@ -91,7 +98,7 @@ tcg/tcg.o: cpu.h # HELPER_CFLAGS is used for all the code compiled with static register # variables -op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +op_helper.o ldst_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling # cpu_signal_handler() in user-exec.c. diff --git a/arch_init.c b/arch_init.c index a6c69c75a9..a411fdf263 100644 --- a/arch_init.c +++ b/arch_init.c @@ -256,6 +256,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) uint64_t bytes_transferred_last; double bwidth = 0; uint64_t expected_time = 0; + int ret; if (stage < 0) { cpu_physical_memory_set_dirty_tracking(0); @@ -263,8 +264,8 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) } if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { - qemu_file_set_error(f); - return 0; + qemu_file_set_error(f, -EINVAL); + return -EINVAL; } if (stage == 1) { @@ -300,7 +301,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) bytes_transferred_last = bytes_transferred; bwidth = qemu_get_clock_ns(rt_clock); - while (!qemu_file_rate_limit(f)) { + while ((ret = qemu_file_rate_limit(f)) == 0) { int bytes_sent; bytes_sent = ram_save_block(f); @@ -310,6 +311,10 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) } } + if (ret < 0) { + return ret; + } + bwidth = qemu_get_clock_ns(rt_clock) - bwidth; bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; @@ -371,6 +376,7 @@ int ram_load(QEMUFile *f, void *opaque, int version_id) { ram_addr_t addr; int flags; + int error; if (version_id < 3 || version_id > 4) { return -EINVAL; @@ -451,8 +457,9 @@ int ram_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, host, TARGET_PAGE_SIZE); } - if (qemu_file_has_error(f)) { - return -EIO; + error = qemu_file_get_error(f); + if (error) { + return error; } } while (!(flags & RAM_SAVE_FLAG_EOS)); @@ -24,6 +24,7 @@ #include "qemu-common.h" #include "qemu-aio.h" +#include "main-loop.h" /* Anchor of the list of Bottom Halves belonging to the context */ static struct QEMUBH *first_bh; diff --git a/block-migration.c b/block-migration.c index e2775ee50b..0bff07538b 100644 --- a/block-migration.c +++ b/block-migration.c @@ -263,7 +263,7 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f, error: monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector); - qemu_file_set_error(f); + qemu_file_set_error(f, -EIO); g_free(blk->buf); g_free(blk); return 0; @@ -383,6 +383,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, int64_t total_sectors = bmds->total_sectors; int64_t sector; int nr_sectors; + int ret = -EIO; for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) { if (bmds_aio_inflight(bmds, sector)) { @@ -418,8 +419,8 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, block_mig_state.submitted++; bmds_set_aio_inflight(bmds, sector, nr_sectors, 1); } else { - if (bdrv_read(bmds->bs, sector, blk->buf, - nr_sectors) < 0) { + ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors); + if (ret < 0) { goto error; } blk_send(f, blk); @@ -439,7 +440,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, error: monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector); - qemu_file_set_error(f); + qemu_file_set_error(f, ret); g_free(blk->buf); g_free(blk); return 0; @@ -473,7 +474,7 @@ static void flush_blks(QEMUFile* f) break; } if (blk->ret < 0) { - qemu_file_set_error(f); + qemu_file_set_error(f, blk->ret); break; } blk_send(f, blk); @@ -556,6 +557,8 @@ static void blk_mig_cleanup(Monitor *mon) static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { + int ret; + DPRINTF("Enter save live stage %d submitted %d transferred %d\n", stage, block_mig_state.submitted, block_mig_state.transferred); @@ -579,9 +582,10 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) flush_blks(f); - if (qemu_file_has_error(f)) { + ret = qemu_file_get_error(f); + if (ret) { blk_mig_cleanup(mon); - return 0; + return ret; } blk_mig_reset_dirty_cursor(); @@ -607,9 +611,10 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) flush_blks(f); - if (qemu_file_has_error(f)) { + ret = qemu_file_get_error(f); + if (ret) { blk_mig_cleanup(mon); - return 0; + return ret; } } @@ -624,8 +629,9 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) /* report completion */ qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); - if (qemu_file_has_error(f)) { - return 0; + ret = qemu_file_get_error(f); + if (ret) { + return ret; } monitor_printf(mon, "Block migration completed\n"); @@ -646,6 +652,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) uint8_t *buf; int64_t total_sectors = 0; int nr_sectors; + int ret; do { addr = qemu_get_be64(f); @@ -654,7 +661,6 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) addr >>= BDRV_SECTOR_BITS; if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) { - int ret; /* get device name */ len = qemu_get_byte(f); qemu_get_buffer(f, (uint8_t *)device_name, len); @@ -704,8 +710,9 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) fprintf(stderr, "Unknown flags\n"); return -EINVAL; } - if (qemu_file_has_error(f)) { - return -EIO; + ret = qemu_file_get_error(f); + if (ret != 0) { + return ret; } } while (!(flags & BLK_MIG_FLAG_EOS)); @@ -53,17 +53,12 @@ static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); -static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque); -static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque); static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *iov); static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *iov); -static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs); static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, @@ -203,9 +198,6 @@ void bdrv_register(BlockDriver *bdrv) } } - if (!bdrv->bdrv_aio_flush) - bdrv->bdrv_aio_flush = bdrv_aio_flush_em; - QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list); } @@ -1027,11 +1019,6 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num, nb_sectors * BDRV_SECTOR_SIZE); } -static inline bool bdrv_has_async_flush(BlockDriver *drv) -{ - return drv->bdrv_aio_flush != bdrv_aio_flush_em; -} - typedef struct RwCo { BlockDriverState *bs; int64_t sector_num; @@ -1759,33 +1746,6 @@ const char *bdrv_get_device_name(BlockDriverState *bs) return bs->device_name; } -int bdrv_flush(BlockDriverState *bs) -{ - if (bs->open_flags & BDRV_O_NO_FLUSH) { - return 0; - } - - if (bs->drv && bdrv_has_async_flush(bs->drv) && qemu_in_coroutine()) { - return bdrv_co_flush_em(bs); - } - - if (bs->drv && bs->drv->bdrv_flush) { - return bs->drv->bdrv_flush(bs); - } - - /* - * Some block drivers always operate in either writethrough or unsafe mode - * and don't support bdrv_flush therefore. Usually qemu doesn't know how - * the server works (because the behaviour is hardcoded or depends on - * server-side configuration), so we can't ensure that everything is safe - * on disk. Returning an error doesn't work because that would break guests - * even if the server operates in writethrough mode. - * - * Let's hope the user knows what he's doing. - */ - return 0; -} - void bdrv_flush_all(void) { BlockDriverState *bs; @@ -1808,17 +1768,6 @@ int bdrv_has_zero_init(BlockDriverState *bs) return 1; } -int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) -{ - if (!bs->drv) { - return -ENOMEDIUM; - } - if (!bs->drv->bdrv_discard) { - return 0; - } - return bs->drv->bdrv_discard(bs, sector_num, nb_sectors); -} - /* * Returns true iff the specified sector is present in the disk image. Drivers * not implementing the functionality are assumed to not support backing files, @@ -2610,22 +2559,6 @@ fail: return -1; } -BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque) -{ - BlockDriver *drv = bs->drv; - - trace_bdrv_aio_flush(bs, opaque); - - if (bs->open_flags & BDRV_O_NO_FLUSH) { - return bdrv_aio_noop_em(bs, cb, opaque); - } - - if (!drv) - return NULL; - return drv->bdrv_aio_flush(bs, cb, opaque); -} - void bdrv_aio_cancel(BlockDriverAIOCB *acb) { acb->pool->cancel(acb); @@ -2735,7 +2668,7 @@ static AIOPool bdrv_em_co_aio_pool = { .cancel = bdrv_aio_co_cancel_em, }; -static void bdrv_co_rw_bh(void *opaque) +static void bdrv_co_em_bh(void *opaque) { BlockDriverAIOCBCoroutine *acb = opaque; @@ -2758,7 +2691,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) acb->req.nb_sectors, acb->req.qiov); } - acb->bh = qemu_bh_new(bdrv_co_rw_bh, acb); + acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); qemu_bh_schedule(acb->bh); } @@ -2785,41 +2718,56 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, return &acb->common; } -static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs, +static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque) +{ + BlockDriverAIOCBCoroutine *acb = opaque; + BlockDriverState *bs = acb->common.bs; + + acb->req.error = bdrv_co_flush(bs); + acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); + qemu_bh_schedule(acb->bh); +} + +BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverAIOCBSync *acb; + trace_bdrv_aio_flush(bs, opaque); - acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque); - acb->is_write = 1; /* don't bounce in the completion hadler */ - acb->qiov = NULL; - acb->bounce = NULL; - acb->ret = 0; + Coroutine *co; + BlockDriverAIOCBCoroutine *acb; - if (!acb->bh) - acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); + acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque); + co = qemu_coroutine_create(bdrv_aio_flush_co_entry); + qemu_coroutine_enter(co, acb); - bdrv_flush(bs); - qemu_bh_schedule(acb->bh); return &acb->common; } -static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs, +static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque) +{ + BlockDriverAIOCBCoroutine *acb = opaque; + BlockDriverState *bs = acb->common.bs; + + acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors); + acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); + qemu_bh_schedule(acb->bh); +} + +BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverAIOCBSync *acb; + Coroutine *co; + BlockDriverAIOCBCoroutine *acb; - acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque); - acb->is_write = 1; /* don't bounce in the completion handler */ - acb->qiov = NULL; - acb->bounce = NULL; - acb->ret = 0; + trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque); - if (!acb->bh) { - acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); - } + acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque); + acb->req.sector = sector_num; + acb->req.nb_sectors = nb_sectors; + co = qemu_coroutine_create(bdrv_aio_discard_co_entry); + qemu_coroutine_enter(co, acb); - qemu_bh_schedule(acb->bh); return &acb->common; } @@ -2916,19 +2864,131 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs, return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true); } -static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs) +static void coroutine_fn bdrv_flush_co_entry(void *opaque) { - CoroutineIOCompletion co = { - .coroutine = qemu_coroutine_self(), + RwCo *rwco = opaque; + + rwco->ret = bdrv_co_flush(rwco->bs); +} + +int coroutine_fn bdrv_co_flush(BlockDriverState *bs) +{ + if (bs->open_flags & BDRV_O_NO_FLUSH) { + return 0; + } else if (!bs->drv) { + return 0; + } else if (bs->drv->bdrv_co_flush) { + return bs->drv->bdrv_co_flush(bs); + } else if (bs->drv->bdrv_aio_flush) { + BlockDriverAIOCB *acb; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + acb = bs->drv->bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co); + if (acb == NULL) { + return -EIO; + } else { + qemu_coroutine_yield(); + return co.ret; + } + } else { + /* + * Some block drivers always operate in either writethrough or unsafe + * mode and don't support bdrv_flush therefore. Usually qemu doesn't + * know how the server works (because the behaviour is hardcoded or + * depends on server-side configuration), so we can't ensure that + * everything is safe on disk. Returning an error doesn't work because + * that would break guests even if the server operates in writethrough + * mode. + * + * Let's hope the user knows what he's doing. + */ + return 0; + } +} + +int bdrv_flush(BlockDriverState *bs) +{ + Coroutine *co; + RwCo rwco = { + .bs = bs, + .ret = NOT_DONE, }; - BlockDriverAIOCB *acb; - acb = bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co); - if (!acb) { + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_flush_co_entry(&rwco); + } else { + co = qemu_coroutine_create(bdrv_flush_co_entry); + qemu_coroutine_enter(co, &rwco); + while (rwco.ret == NOT_DONE) { + qemu_aio_wait(); + } + } + + return rwco.ret; +} + +static void coroutine_fn bdrv_discard_co_entry(void *opaque) +{ + RwCo *rwco = opaque; + + rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors); +} + +int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, + int nb_sectors) +{ + if (!bs->drv) { + return -ENOMEDIUM; + } else if (bdrv_check_request(bs, sector_num, nb_sectors)) { return -EIO; + } else if (bs->read_only) { + return -EROFS; + } else if (bs->drv->bdrv_co_discard) { + return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors); + } else if (bs->drv->bdrv_aio_discard) { + BlockDriverAIOCB *acb; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors, + bdrv_co_io_em_complete, &co); + if (acb == NULL) { + return -EIO; + } else { + qemu_coroutine_yield(); + return co.ret; + } + } else { + return 0; } - qemu_coroutine_yield(); - return co.ret; +} + +int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) +{ + Coroutine *co; + RwCo rwco = { + .bs = bs, + .sector_num = sector_num, + .nb_sectors = nb_sectors, + .ret = NOT_DONE, + }; + + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_discard_co_entry(&rwco); + } else { + co = qemu_coroutine_create(bdrv_discard_co_entry); + qemu_coroutine_enter(co, &rwco); + while (rwco.ret == NOT_DONE) { + qemu_aio_wait(); + } + } + + return rwco.ret; } /**************************************************************/ @@ -166,6 +166,9 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, BlockDriverCompletionFunc *cb, void *opaque); BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); void bdrv_aio_cancel(BlockDriverAIOCB *acb); typedef struct BlockRequest { @@ -191,10 +194,12 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, /* Ensure contents are flushed to disk. */ int bdrv_flush(BlockDriverState *bs); +int coroutine_fn bdrv_co_flush(BlockDriverState *bs); void bdrv_flush_all(void); void bdrv_close_all(void); int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); +int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); int bdrv_has_zero_init(BlockDriverState *bs); int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); diff --git a/block/blkdebug.c b/block/blkdebug.c index b3c5d42cef..9b885359e4 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -397,11 +397,6 @@ static void blkdebug_close(BlockDriverState *bs) } } -static int blkdebug_flush(BlockDriverState *bs) -{ - return bdrv_flush(bs->file); -} - static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { @@ -454,7 +449,6 @@ static BlockDriver bdrv_blkdebug = { .bdrv_file_open = blkdebug_open, .bdrv_close = blkdebug_close, - .bdrv_flush = blkdebug_flush, .bdrv_aio_readv = blkdebug_aio_readv, .bdrv_aio_writev = blkdebug_aio_writev, diff --git a/block/blkverify.c b/block/blkverify.c index c7522b4093..483f3b3cfe 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -116,14 +116,6 @@ static void blkverify_close(BlockDriverState *bs) s->test_file = NULL; } -static int blkverify_flush(BlockDriverState *bs) -{ - BDRVBlkverifyState *s = bs->opaque; - - /* Only flush test file, the raw file is not important */ - return bdrv_flush(s->test_file); -} - static int64_t blkverify_getlength(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; @@ -368,7 +360,6 @@ static BlockDriver bdrv_blkverify = { .bdrv_file_open = blkverify_open, .bdrv_close = blkverify_close, - .bdrv_flush = blkverify_flush, .bdrv_aio_readv = blkverify_aio_readv, .bdrv_aio_writev = blkverify_aio_writev, diff --git a/block/bochs.c b/block/bochs.c index 3c2f8d1b12..ab7944dc43 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -80,6 +80,7 @@ struct bochs_header { }; typedef struct BDRVBochsState { + CoMutex lock; uint32_t *catalog_bitmap; int catalog_size; @@ -150,6 +151,7 @@ static int bochs_open(BlockDriverState *bs, int flags) s->extent_size = le32_to_cpu(bochs.extra.redolog.extent); + qemu_co_mutex_init(&s->lock); return 0; fail: return -1; @@ -207,6 +209,17 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVBochsState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = bochs_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static void bochs_close(BlockDriverState *bs) { BDRVBochsState *s = bs->opaque; @@ -218,7 +231,7 @@ static BlockDriver bdrv_bochs = { .instance_size = sizeof(BDRVBochsState), .bdrv_probe = bochs_probe, .bdrv_open = bochs_open, - .bdrv_read = bochs_read, + .bdrv_read = bochs_co_read, .bdrv_close = bochs_close, }; diff --git a/block/cloop.c b/block/cloop.c index 8cff9f2cac..775f8a98e1 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -27,6 +27,7 @@ #include <zlib.h> typedef struct BDRVCloopState { + CoMutex lock; uint32_t block_size; uint32_t n_blocks; uint64_t* offsets; @@ -93,6 +94,7 @@ static int cloop_open(BlockDriverState *bs, int flags) s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks*s->sectors_per_block; + qemu_co_mutex_init(&s->lock); return 0; cloop_close: @@ -144,6 +146,17 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVCloopState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = cloop_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static void cloop_close(BlockDriverState *bs) { BDRVCloopState *s = bs->opaque; @@ -159,7 +172,7 @@ static BlockDriver bdrv_cloop = { .instance_size = sizeof(BDRVCloopState), .bdrv_probe = cloop_probe, .bdrv_open = cloop_open, - .bdrv_read = cloop_read, + .bdrv_read = cloop_co_read, .bdrv_close = cloop_close, }; diff --git a/block/cow.c b/block/cow.c index 4cf543c832..707c0aad88 100644 --- a/block/cow.c +++ b/block/cow.c @@ -42,6 +42,7 @@ struct cow_header_v2 { }; typedef struct BDRVCowState { + CoMutex lock; int64_t cow_sectors_offset; } BDRVCowState; @@ -84,6 +85,7 @@ static int cow_open(BlockDriverState *bs, int flags) bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); s->cow_sectors_offset = (bitmap_size + 511) & ~511; + qemu_co_mutex_init(&s->lock); return 0; fail: return -1; @@ -199,6 +201,17 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVCowState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = cow_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static int cow_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { @@ -213,6 +226,17 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num, return cow_update_bitmap(bs, sector_num, nb_sectors); } +static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVCowState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = cow_write(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static void cow_close(BlockDriverState *bs) { } @@ -282,9 +306,9 @@ exit: return ret; } -static int cow_flush(BlockDriverState *bs) +static coroutine_fn int cow_co_flush(BlockDriverState *bs) { - return bdrv_flush(bs->file); + return bdrv_co_flush(bs->file); } static QEMUOptionParameter cow_create_options[] = { @@ -306,11 +330,11 @@ static BlockDriver bdrv_cow = { .instance_size = sizeof(BDRVCowState), .bdrv_probe = cow_probe, .bdrv_open = cow_open, - .bdrv_read = cow_read, - .bdrv_write = cow_write, + .bdrv_read = cow_co_read, + .bdrv_write = cow_co_write, .bdrv_close = cow_close, .bdrv_create = cow_create, - .bdrv_flush = cow_flush, + .bdrv_co_flush = cow_co_flush, .bdrv_is_allocated = cow_is_allocated, .create_options = cow_create_options, diff --git a/block/dmg.c b/block/dmg.c index 64c3cce46a..37902a4347 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -28,6 +28,7 @@ #include <zlib.h> typedef struct BDRVDMGState { + CoMutex lock; /* each chunk contains a certain number of sectors, * offsets[i] is the offset in the .dmg file, * lengths[i] is the length of the compressed chunk, @@ -177,6 +178,7 @@ static int dmg_open(BlockDriverState *bs, int flags) s->current_chunk = s->n_chunks; + qemu_co_mutex_init(&s->lock); return 0; fail: return -1; @@ -280,6 +282,17 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVDMGState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = dmg_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static void dmg_close(BlockDriverState *bs) { BDRVDMGState *s = bs->opaque; @@ -300,7 +313,7 @@ static BlockDriver bdrv_dmg = { .instance_size = sizeof(BDRVDMGState), .bdrv_probe = dmg_probe, .bdrv_open = dmg_open, - .bdrv_read = dmg_read, + .bdrv_read = dmg_co_read, .bdrv_close = dmg_close, }; diff --git a/block/nbd.c b/block/nbd.c index 76f04d863c..882b2dc84a 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -47,6 +47,7 @@ #endif typedef struct BDRVNBDState { + CoMutex lock; int sock; uint32_t nbdflags; off_t size; @@ -175,6 +176,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags) */ result = nbd_establish_connection(bs); + qemu_co_mutex_init(&s->lock); return result; } @@ -238,6 +240,28 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int nbd_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVNBDState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = nbd_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + +static coroutine_fn int nbd_co_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVNBDState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = nbd_write(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static void nbd_close(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; @@ -258,8 +282,8 @@ static BlockDriver bdrv_nbd = { .format_name = "nbd", .instance_size = sizeof(BDRVNBDState), .bdrv_file_open = nbd_open, - .bdrv_read = nbd_read, - .bdrv_write = nbd_write, + .bdrv_read = nbd_co_read, + .bdrv_write = nbd_co_write, .bdrv_close = nbd_close, .bdrv_getlength = nbd_getlength, .protocol_name = "nbd", diff --git a/block/parallels.c b/block/parallels.c index c64103ddbb..d30f0ecf77 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -46,6 +46,7 @@ struct parallels_header { } QEMU_PACKED; typedef struct BDRVParallelsState { + CoMutex lock; uint32_t *catalog_bitmap; int catalog_size; @@ -95,6 +96,7 @@ static int parallels_open(BlockDriverState *bs, int flags) for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); + qemu_co_mutex_init(&s->lock); return 0; fail: if (s->catalog_bitmap) @@ -134,6 +136,17 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int parallels_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVParallelsState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = parallels_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static void parallels_close(BlockDriverState *bs) { BDRVParallelsState *s = bs->opaque; @@ -145,7 +158,7 @@ static BlockDriver bdrv_parallels = { .instance_size = sizeof(BDRVParallelsState), .bdrv_probe = parallels_probe, .bdrv_open = parallels_open, - .bdrv_read = parallels_read, + .bdrv_read = parallels_co_read, .bdrv_close = parallels_close, }; diff --git a/block/qcow.c b/block/qcow.c index eba5a04c44..ab36b2995c 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -781,15 +781,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return 0; } -static int qcow_flush(BlockDriverState *bs) +static coroutine_fn int qcow_co_flush(BlockDriverState *bs) { - return bdrv_flush(bs->file); -} - -static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque) -{ - return bdrv_aio_flush(bs->file, cb, opaque); + return bdrv_co_flush(bs->file); } static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) @@ -826,13 +820,12 @@ static BlockDriver bdrv_qcow = { .bdrv_open = qcow_open, .bdrv_close = qcow_close, .bdrv_create = qcow_create, - .bdrv_flush = qcow_flush, .bdrv_is_allocated = qcow_is_allocated, .bdrv_set_key = qcow_set_key, .bdrv_make_empty = qcow_make_empty, - .bdrv_co_readv = qcow_co_readv, - .bdrv_co_writev = qcow_co_writev, - .bdrv_aio_flush = qcow_aio_flush, + .bdrv_co_readv = qcow_co_readv, + .bdrv_co_writev = qcow_co_writev, + .bdrv_co_flush = qcow_co_flush, .bdrv_write_compressed = qcow_write_compressed, .bdrv_get_info = qcow_get_info, diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 2f76311354..f4e049fa90 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -568,8 +568,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, } cluster_offset = be64_to_cpu(l2_table[l2_index]); - if (cluster_offset & QCOW_OFLAG_COPIED) - return cluster_offset & ~QCOW_OFLAG_COPIED; + if (cluster_offset & QCOW_OFLAG_COPIED) { + qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); + return 0; + } if (cluster_offset) qcow2_free_any_clusters(bs, cluster_offset, 1); diff --git a/block/qcow2.c b/block/qcow2.c index 510ff6897f..a181932b67 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -978,11 +978,17 @@ static int qcow2_make_empty(BlockDriverState *bs) return 0; } -static int qcow2_discard(BlockDriverState *bs, int64_t sector_num, - int nb_sectors) +static coroutine_fn int qcow2_co_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors) { - return qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS, + int ret; + BDRVQcowState *s = bs->opaque; + + qemu_co_mutex_lock(&s->lock); + ret = qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; } static int qcow2_truncate(BlockDriverState *bs, int64_t offset) @@ -1053,8 +1059,8 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY); if (ret != 0) { - g_free(out_buf); - return -1; + ret = -EINVAL; + goto fail; } strm.avail_in = s->cluster_size; @@ -1064,9 +1070,9 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, ret = deflate(&strm, Z_FINISH); if (ret != Z_STREAM_END && ret != Z_OK) { - g_free(out_buf); deflateEnd(&strm); - return -1; + ret = -EINVAL; + goto fail; } out_len = strm.next_out - out_buf; @@ -1074,29 +1080,37 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, if (ret != Z_STREAM_END || out_len >= s->cluster_size) { /* could not compress: write normal cluster */ - bdrv_write(bs, sector_num, buf, s->cluster_sectors); + ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors); + if (ret < 0) { + goto fail; + } } else { cluster_offset = qcow2_alloc_compressed_cluster_offset(bs, sector_num << 9, out_len); - if (!cluster_offset) - return -1; + if (!cluster_offset) { + ret = -EIO; + goto fail; + } cluster_offset &= s->cluster_offset_mask; BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); - if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) { - g_free(out_buf); - return -1; + ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len); + if (ret < 0) { + goto fail; } } + ret = 0; +fail: g_free(out_buf); - return 0; + return ret; } -static int qcow2_flush(BlockDriverState *bs) +static int qcow2_co_flush(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; int ret; + qemu_co_mutex_lock(&s->lock); ret = qcow2_cache_flush(bs, s->l2_table_cache); if (ret < 0) { return ret; @@ -1106,28 +1120,9 @@ static int qcow2_flush(BlockDriverState *bs) if (ret < 0) { return ret; } + qemu_co_mutex_unlock(&s->lock); - return bdrv_flush(bs->file); -} - -static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, - void *opaque) -{ - BDRVQcowState *s = bs->opaque; - int ret; - - ret = qcow2_cache_flush(bs, s->l2_table_cache); - if (ret < 0) { - return NULL; - } - - ret = qcow2_cache_flush(bs, s->refcount_block_cache); - if (ret < 0) { - return NULL; - } - - return bdrv_aio_flush(bs->file, cb, opaque); + return bdrv_co_flush(bs->file); } static int64_t qcow2_vm_state_offset(BDRVQcowState *s) @@ -1242,16 +1237,15 @@ static BlockDriver bdrv_qcow2 = { .bdrv_open = qcow2_open, .bdrv_close = qcow2_close, .bdrv_create = qcow2_create, - .bdrv_flush = qcow2_flush, .bdrv_is_allocated = qcow2_is_allocated, .bdrv_set_key = qcow2_set_key, .bdrv_make_empty = qcow2_make_empty, .bdrv_co_readv = qcow2_co_readv, .bdrv_co_writev = qcow2_co_writev, - .bdrv_aio_flush = qcow2_aio_flush, + .bdrv_co_flush = qcow2_co_flush, - .bdrv_discard = qcow2_discard, + .bdrv_co_discard = qcow2_co_discard, .bdrv_truncate = qcow2_truncate, .bdrv_write_compressed = qcow2_write_compressed, diff --git a/block/qed.c b/block/qed.c index e87dc4decf..2e06992784 100644 --- a/block/qed.c +++ b/block/qed.c @@ -533,11 +533,6 @@ static void bdrv_qed_close(BlockDriverState *bs) qemu_vfree(s->l1_table); } -static int bdrv_qed_flush(BlockDriverState *bs) -{ - return bdrv_flush(bs->file); -} - static int qed_create(const char *filename, uint32_t cluster_size, uint64_t image_size, uint32_t table_size, const char *backing_file, const char *backing_fmt) @@ -1479,7 +1474,6 @@ static BlockDriver bdrv_qed = { .bdrv_open = bdrv_qed_open, .bdrv_close = bdrv_qed_close, .bdrv_create = bdrv_qed_create, - .bdrv_flush = bdrv_qed_flush, .bdrv_is_allocated = bdrv_qed_is_allocated, .bdrv_make_empty = bdrv_qed_make_empty, .bdrv_aio_readv = bdrv_qed_aio_readv, diff --git a/block/raw-posix.c b/block/raw-posix.c index c7f5544edd..a3de373586 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -583,19 +583,6 @@ static int raw_create(const char *filename, QEMUOptionParameter *options) return result; } -static int raw_flush(BlockDriverState *bs) -{ - BDRVRawState *s = bs->opaque; - int ret; - - ret = qemu_fdatasync(s->fd); - if (ret < 0) { - return -errno; - } - - return 0; -} - #ifdef CONFIG_XFS static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors) { @@ -615,7 +602,8 @@ static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors) } #endif -static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) +static coroutine_fn int raw_co_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors) { #ifdef CONFIG_XFS BDRVRawState *s = bs->opaque; @@ -645,8 +633,7 @@ static BlockDriver bdrv_file = { .bdrv_file_open = raw_open, .bdrv_close = raw_close, .bdrv_create = raw_create, - .bdrv_flush = raw_flush, - .bdrv_discard = raw_discard, + .bdrv_co_discard = raw_co_discard, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -915,7 +902,6 @@ static BlockDriver bdrv_host_device = { .bdrv_create = hdev_create, .create_options = raw_create_options, .bdrv_has_zero_init = hdev_has_zero_init, - .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -1035,7 +1021,6 @@ static BlockDriver bdrv_host_floppy = { .bdrv_create = hdev_create, .create_options = raw_create_options, .bdrv_has_zero_init = hdev_has_zero_init, - .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -1135,7 +1120,6 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_create = hdev_create, .create_options = raw_create_options, .bdrv_has_zero_init = hdev_has_zero_init, - .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -1255,7 +1239,6 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_create = hdev_create, .create_options = raw_create_options, .bdrv_has_zero_init = hdev_has_zero_init, - .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, diff --git a/block/raw-win32.c b/block/raw-win32.c index b7dd357c6d..f5f73bcd64 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -281,7 +281,7 @@ static BlockDriver bdrv_file = { .bdrv_file_open = raw_open, .bdrv_close = raw_close, .bdrv_create = raw_create, - .bdrv_flush = raw_flush, + .bdrv_co_flush = raw_flush, .bdrv_read = raw_read, .bdrv_write = raw_write, .bdrv_truncate = raw_truncate, @@ -409,7 +409,7 @@ static BlockDriver bdrv_host_device = { .bdrv_probe_device = hdev_probe_device, .bdrv_file_open = hdev_open, .bdrv_close = raw_close, - .bdrv_flush = raw_flush, + .bdrv_co_flush = raw_flush, .bdrv_has_zero_init = hdev_has_zero_init, .bdrv_read = raw_read, diff --git a/block/raw.c b/block/raw.c index 5ca606b68a..33cc4716d3 100644 --- a/block/raw.c +++ b/block/raw.c @@ -25,15 +25,9 @@ static void raw_close(BlockDriverState *bs) { } -static int raw_flush(BlockDriverState *bs) +static int coroutine_fn raw_co_flush(BlockDriverState *bs) { - return bdrv_flush(bs->file); -} - -static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque) -{ - return bdrv_aio_flush(bs->file, cb, opaque); + return bdrv_co_flush(bs->file); } static int64_t raw_getlength(BlockDriverState *bs) @@ -51,9 +45,10 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) return 1; /* everything can be opened as raw image */ } -static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) +static int coroutine_fn raw_co_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors) { - return bdrv_discard(bs->file, sector_num, nb_sectors); + return bdrv_co_discard(bs->file, sector_num, nb_sectors); } static int raw_is_inserted(BlockDriverState *bs) @@ -115,16 +110,16 @@ static BlockDriver bdrv_raw = { .bdrv_open = raw_open, .bdrv_close = raw_close, + .bdrv_co_readv = raw_co_readv, .bdrv_co_writev = raw_co_writev, - .bdrv_flush = raw_flush, + .bdrv_co_flush = raw_co_flush, + .bdrv_co_discard = raw_co_discard, + .bdrv_probe = raw_probe, .bdrv_getlength = raw_getlength, .bdrv_truncate = raw_truncate, - .bdrv_aio_flush = raw_aio_flush, - .bdrv_discard = raw_discard, - .bdrv_is_inserted = raw_is_inserted, .bdrv_media_changed = raw_media_changed, .bdrv_eject = raw_eject, diff --git a/block/rbd.c b/block/rbd.c index 3068c829fe..c684e0cb0b 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -705,7 +705,7 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs, return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1); } -static int qemu_rbd_flush(BlockDriverState *bs) +static int qemu_rbd_co_flush(BlockDriverState *bs) { #if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1) /* rbd_flush added in 0.1.1 */ @@ -851,7 +851,7 @@ static BlockDriver bdrv_rbd = { .bdrv_file_open = qemu_rbd_open, .bdrv_close = qemu_rbd_close, .bdrv_create = qemu_rbd_create, - .bdrv_flush = qemu_rbd_flush, + .bdrv_co_flush = qemu_rbd_co_flush, .bdrv_get_info = qemu_rbd_getinfo, .create_options = qemu_rbd_create_options, .bdrv_getlength = qemu_rbd_getlength, diff --git a/block/sheepdog.c b/block/sheepdog.c index ae857e294c..9f8060960f 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -396,7 +396,7 @@ static inline int free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req) return !QLIST_EMPTY(&acb->aioreq_head); } -static void sd_finish_aiocb(SheepdogAIOCB *acb) +static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb) { if (!acb->canceled) { qemu_coroutine_enter(acb->coroutine, NULL); @@ -735,7 +735,7 @@ out: return ret; } -static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, +static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, struct iovec *iov, int niov, int create, enum AIOCBState aiocb_type); @@ -743,7 +743,7 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, * This function searchs pending requests to the object `oid', and * sends them. */ -static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id) +static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id) { AIOReq *aio_req, *next; SheepdogAIOCB *acb; @@ -777,7 +777,7 @@ static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id) * This function is registered as a fd handler, and called from the * main loop when s->fd is ready for reading responses. */ -static void aio_read_response(void *opaque) +static void coroutine_fn aio_read_response(void *opaque) { SheepdogObjRsp rsp; BDRVSheepdogState *s = opaque; @@ -1064,7 +1064,7 @@ out: return ret; } -static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, +static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, struct iovec *iov, int niov, int create, enum AIOCBState aiocb_type) { @@ -1517,7 +1517,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) * update metadata, this sends a write request to the vdi object. * Otherwise, this switches back to sd_co_readv/writev. */ -static void sd_write_done(SheepdogAIOCB *acb) +static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) { int ret; BDRVSheepdogState *s = acb->common.bs->opaque; @@ -1615,7 +1615,7 @@ out: * Returns 1 when we need to wait a response, 0 when there is no sent * request and -errno in error cases. */ -static int sd_co_rw_vector(void *p) +static int coroutine_fn sd_co_rw_vector(void *p) { SheepdogAIOCB *acb = p; int ret = 0; diff --git a/block/vdi.c b/block/vdi.c index 1d5ad2bf49..883046d5a2 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -936,10 +936,10 @@ static void vdi_close(BlockDriverState *bs) { } -static int vdi_flush(BlockDriverState *bs) +static coroutine_fn int vdi_co_flush(BlockDriverState *bs) { logout("\n"); - return bdrv_flush(bs->file); + return bdrv_co_flush(bs->file); } @@ -975,7 +975,7 @@ static BlockDriver bdrv_vdi = { .bdrv_open = vdi_open, .bdrv_close = vdi_close, .bdrv_create = vdi_create, - .bdrv_flush = vdi_flush, + .bdrv_co_flush = vdi_co_flush, .bdrv_is_allocated = vdi_is_allocated, .bdrv_make_empty = vdi_make_empty, diff --git a/block/vmdk.c b/block/vmdk.c index 5d16ec49bc..6be592ffd6 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -90,6 +90,7 @@ typedef struct VmdkExtent { } VmdkExtent; typedef struct BDRVVmdkState { + CoMutex lock; int desc_offset; bool cid_updated; uint32_t parent_cid; @@ -283,10 +284,12 @@ static int vmdk_parent_open(BlockDriverState *bs) char *p_name; char desc[DESC_SIZE + 1]; BDRVVmdkState *s = bs->opaque; + int ret; desc[DESC_SIZE] = '\0'; - if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) { - return -1; + ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + if (ret < 0) { + return ret; } p_name = strstr(desc, "parentFileNameHint"); @@ -296,10 +299,10 @@ static int vmdk_parent_open(BlockDriverState *bs) p_name += sizeof("parentFileNameHint") + 1; end_name = strchr(p_name, '\"'); if (end_name == NULL) { - return -1; + return -EINVAL; } if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { - return -1; + return -EINVAL; } pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); @@ -622,19 +625,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, return -ENOTSUP; } s->desc_offset = 0; - ret = vmdk_parse_extents(buf, bs, bs->file->filename); - if (ret) { - vmdk_free_extents(bs); - return ret; - } - - /* try to open parent images, if exist */ - if (vmdk_parent_open(bs)) { - vmdk_free_extents(bs); - return -EINVAL; - } - s->parent_cid = vmdk_read_cid(bs, 1); - return 0; + return vmdk_parse_extents(buf, bs, bs->file->filename); } static int vmdk_open(BlockDriverState *bs, int flags) @@ -644,17 +635,24 @@ static int vmdk_open(BlockDriverState *bs, int flags) if (vmdk_open_sparse(bs, bs->file, flags) == 0) { s->desc_offset = 0x200; - /* try to open parent images, if exist */ - ret = vmdk_parent_open(bs); + } else { + ret = vmdk_open_desc_file(bs, flags, 0); if (ret) { - vmdk_free_extents(bs); - return ret; + goto fail; } - s->parent_cid = vmdk_read_cid(bs, 1); - return 0; - } else { - return vmdk_open_desc_file(bs, flags, 0); } + /* try to open parent images, if exist */ + ret = vmdk_parent_open(bs); + if (ret) { + goto fail; + } + s->parent_cid = vmdk_read_cid(bs, 1); + qemu_co_mutex_init(&s->lock); + return ret; + +fail: + vmdk_free_extents(bs); + return ret; } static int get_whole_cluster(BlockDriverState *bs, @@ -1026,6 +1024,17 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVVmdkState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vmdk_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static int vmdk_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { @@ -1107,6 +1116,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVVmdkState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vmdk_write(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat, bool compress) @@ -1474,14 +1494,14 @@ static void vmdk_close(BlockDriverState *bs) vmdk_free_extents(bs); } -static int vmdk_flush(BlockDriverState *bs) +static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) { int i, ret, err; BDRVVmdkState *s = bs->opaque; - ret = bdrv_flush(bs->file); + ret = bdrv_co_flush(bs->file); for (i = 0; i < s->num_extents; i++) { - err = bdrv_flush(s->extents[i].file); + err = bdrv_co_flush(s->extents[i].file); if (err < 0) { ret = err; } @@ -1544,11 +1564,11 @@ static BlockDriver bdrv_vmdk = { .instance_size = sizeof(BDRVVmdkState), .bdrv_probe = vmdk_probe, .bdrv_open = vmdk_open, - .bdrv_read = vmdk_read, - .bdrv_write = vmdk_write, + .bdrv_read = vmdk_co_read, + .bdrv_write = vmdk_co_write, .bdrv_close = vmdk_close, .bdrv_create = vmdk_create, - .bdrv_flush = vmdk_flush, + .bdrv_co_flush = vmdk_co_flush, .bdrv_is_allocated = vmdk_is_allocated, .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, diff --git a/block/vpc.c b/block/vpc.c index cb6c570f44..79be7d051b 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -110,6 +110,7 @@ struct vhd_dyndisk_header { }; typedef struct BDRVVPCState { + CoMutex lock; uint8_t footer_buf[HEADER_SIZE]; uint64_t free_data_block_offset; int max_table_entries; @@ -226,6 +227,7 @@ static int vpc_open(BlockDriverState *bs, int flags) s->last_pagetable = -1; #endif + qemu_co_mutex_init(&s->lock); return 0; fail: return err; @@ -407,6 +409,17 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num, return 0; } +static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVVPCState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vpc_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static int vpc_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { @@ -443,9 +456,20 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, return 0; } -static int vpc_flush(BlockDriverState *bs) +static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVVPCState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vpc_write(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + +static coroutine_fn int vpc_co_flush(BlockDriverState *bs) { - return bdrv_flush(bs->file); + return bdrv_co_flush(bs->file); } /* @@ -639,9 +663,9 @@ static BlockDriver bdrv_vpc = { .instance_size = sizeof(BDRVVPCState), .bdrv_probe = vpc_probe, .bdrv_open = vpc_open, - .bdrv_read = vpc_read, - .bdrv_write = vpc_write, - .bdrv_flush = vpc_flush, + .bdrv_read = vpc_co_read, + .bdrv_write = vpc_co_write, + .bdrv_co_flush = vpc_co_flush, .bdrv_close = vpc_close, .bdrv_create = vpc_create, diff --git a/block/vvfat.c b/block/vvfat.c index 7e9e35a3a3..e1fcdbc45b 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -317,6 +317,7 @@ static void print_mapping(const struct mapping_t* mapping); /* here begins the real VVFAT driver */ typedef struct BDRVVVFATState { + CoMutex lock; BlockDriverState* bs; /* pointer to parent */ unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */ unsigned char first_sectors[0x40*0x200]; @@ -1065,6 +1066,7 @@ DLOG(if (stderr == NULL) { bs->heads = bs->cyls = bs->secs = 0; // assert(is_consistent(s)); + qemu_co_mutex_init(&s->lock); return 0; } @@ -1279,6 +1281,17 @@ DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num)); return 0; } +static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVVVFATState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vvfat_read(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + /* LATER TODO: statify all functions */ /* @@ -2714,6 +2727,17 @@ DLOG(checkpoint()); return 0; } +static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int ret; + BDRVVVFATState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vvfat_write(bs, sector_num, buf, nb_sectors); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + static int vvfat_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int* n) { @@ -2803,8 +2827,8 @@ static BlockDriver bdrv_vvfat = { .format_name = "vvfat", .instance_size = sizeof(BDRVVVFATState), .bdrv_file_open = vvfat_open, - .bdrv_read = vvfat_read, - .bdrv_write = vvfat_write, + .bdrv_read = vvfat_co_read, + .bdrv_write = vvfat_co_write, .bdrv_close = vvfat_close, .bdrv_is_allocated = vvfat_is_allocated, .protocol_name = "fat", diff --git a/block_int.h b/block_int.h index f2f4f2db38..dac00f504f 100644 --- a/block_int.h +++ b/block_int.h @@ -62,7 +62,6 @@ struct BlockDriver { const uint8_t *buf, int nb_sectors); void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); - int (*bdrv_flush)(BlockDriverState *bs); int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); @@ -76,13 +75,17 @@ struct BlockDriver { BlockDriverCompletionFunc *cb, void *opaque); BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); - int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num, - int nb_sectors); + BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); + int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs); + int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors); int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs, int num_reqs); diff --git a/buffered_file.c b/buffered_file.c index 486af575d5..fed9a227bb 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -27,7 +27,6 @@ typedef struct QEMUFileBuffered BufferedCloseFunc *close; void *opaque; QEMUFile *file; - int has_error; int freeze_output; size_t bytes_xfer; size_t xfer_limit; @@ -72,9 +71,11 @@ static void buffered_append(QEMUFileBuffered *s, static void buffered_flush(QEMUFileBuffered *s) { size_t offset = 0; + int error; - if (s->has_error) { - DPRINTF("flush when error, bailing\n"); + error = qemu_file_get_error(s->file); + if (error != 0) { + DPRINTF("flush when error, bailing: %s\n", strerror(-error)); return; } @@ -93,7 +94,7 @@ static void buffered_flush(QEMUFileBuffered *s) if (ret <= 0) { DPRINTF("error flushing data, %zd\n", ret); - s->has_error = 1; + qemu_file_set_error(s->file, ret); break; } else { DPRINTF("flushed %zd byte(s)\n", ret); @@ -109,14 +110,15 @@ static void buffered_flush(QEMUFileBuffered *s) static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBuffered *s = opaque; - int offset = 0; + int offset = 0, error; ssize_t ret; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); - if (s->has_error) { - DPRINTF("flush when error, bailing\n"); - return -EINVAL; + error = qemu_file_get_error(s->file); + if (error) { + DPRINTF("flush when error, bailing: %s\n", strerror(-error)); + return error; } DPRINTF("unfreezing output\n"); @@ -139,7 +141,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in if (ret <= 0) { DPRINTF("error putting\n"); - s->has_error = 1; + qemu_file_set_error(s->file, ret); offset = -EINVAL; break; } @@ -173,10 +175,10 @@ static int buffered_close(void *opaque) DPRINTF("closing\n"); - while (!s->has_error && s->buffer_size) { + while (!qemu_file_get_error(s->file) && s->buffer_size) { buffered_flush(s); if (s->freeze_output) - s->wait_for_unfreeze(s); + s->wait_for_unfreeze(s->opaque); } ret = s->close(s->opaque); @@ -189,13 +191,21 @@ static int buffered_close(void *opaque) return ret; } +/* + * The meaning of the return values is: + * 0: We can continue sending + * 1: Time to stop + * negative: There has been an error + */ static int buffered_rate_limit(void *opaque) { QEMUFileBuffered *s = opaque; + int ret; - if (s->has_error) - return 0; - + ret = qemu_file_get_error(s->file); + if (ret) { + return ret; + } if (s->freeze_output) return 1; @@ -208,9 +218,9 @@ static int buffered_rate_limit(void *opaque) static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate) { QEMUFileBuffered *s = opaque; - if (s->has_error) + if (qemu_file_get_error(s->file)) { goto out; - + } if (new_rate > SIZE_MAX) { new_rate = SIZE_MAX; } @@ -232,7 +242,7 @@ static void buffered_rate_tick(void *opaque) { QEMUFileBuffered *s = opaque; - if (s->has_error) { + if (qemu_file_get_error(s->file)) { buffered_close(s); return; } diff --git a/compatfd.c b/compatfd.c index 31654c62a6..02306a4f71 100644 --- a/compatfd.c +++ b/compatfd.c @@ -119,9 +119,17 @@ int qemu_signalfd(const sigset_t *mask) bool qemu_signalfd_available(void) { #ifdef CONFIG_SIGNALFD + sigset_t mask; + int fd; + bool ok; + sigemptyset(&mask); errno = 0; - syscall(SYS_signalfd, -1, NULL, _NSIG / 8); - return errno != ENOSYS; + fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8); + ok = (errno != ENOSYS); + if (fd >= 0) { + close(fd); + } + return ok; #else return false; #endif @@ -2557,6 +2557,31 @@ EOF fi ########################################## +# check if we have open_by_handle_at + +open_by_hande_at=no +cat > $TMPC << EOF +#include <fcntl.h> +int main(void) { struct file_handle *fh; open_by_handle_at(0, fh, 0); } +EOF +if compile_prog "" "" ; then + open_by_handle_at=yes +fi + +######################################## +# check if we have linux/magic.h + +linux_magic_h=no +cat > $TMPC << EOF +#include <linux/magic.h> +int main(void) { +} +EOF +if compile_prog "" "" ; then + linux_magic_h=yes +fi + +########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -3035,6 +3060,14 @@ if test "$ucontext_coroutine" = "yes" ; then echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak fi +if test "$open_by_handle_at" = "yes" ; then + echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak +fi + +if test "$linux_magic_h" = "yes" ; then + echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak +fi + # USB host support case "$usb" in linux) @@ -33,17 +33,12 @@ #include "qemu-thread.h" #include "cpus.h" +#include "main-loop.h" #ifndef _WIN32 #include "compatfd.h" #endif -#ifdef SIGRTMIN -#define SIG_IPI (SIGRTMIN+4) -#else -#define SIG_IPI SIGUSR1 -#endif - #ifdef CONFIG_LINUX #include <sys/prctl.h> @@ -65,6 +60,281 @@ static CPUState *next_cpu; /***********************************************************/ +/* guest cycle counter */ + +/* Conversion factor from emulated instructions to virtual clock ticks. */ +static int icount_time_shift; +/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ +#define MAX_ICOUNT_SHIFT 10 +/* Compensate for varying guest execution speed. */ +static int64_t qemu_icount_bias; +static QEMUTimer *icount_rt_timer; +static QEMUTimer *icount_vm_timer; +static QEMUTimer *icount_warp_timer; +static int64_t vm_clock_warp_start; +static int64_t qemu_icount; + +typedef struct TimersState { + int64_t cpu_ticks_prev; + int64_t cpu_ticks_offset; + int64_t cpu_clock_offset; + int32_t cpu_ticks_enabled; + int64_t dummy; +} TimersState; + +TimersState timers_state; + +/* Return the virtual CPU time, based on the instruction counter. */ +int64_t cpu_get_icount(void) +{ + int64_t icount; + CPUState *env = cpu_single_env;; + + icount = qemu_icount; + if (env) { + if (!can_do_io(env)) { + fprintf(stderr, "Bad clock read\n"); + } + icount -= (env->icount_decr.u16.low + env->icount_extra); + } + return qemu_icount_bias + (icount << icount_time_shift); +} + +/* return the host CPU cycle counter and handle stop/restart */ +int64_t cpu_get_ticks(void) +{ + if (use_icount) { + return cpu_get_icount(); + } + if (!timers_state.cpu_ticks_enabled) { + return timers_state.cpu_ticks_offset; + } else { + int64_t ticks; + ticks = cpu_get_real_ticks(); + if (timers_state.cpu_ticks_prev > ticks) { + /* Note: non increasing ticks may happen if the host uses + software suspend */ + timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; + } + timers_state.cpu_ticks_prev = ticks; + return ticks + timers_state.cpu_ticks_offset; + } +} + +/* return the host CPU monotonic timer and handle stop/restart */ +int64_t cpu_get_clock(void) +{ + int64_t ti; + if (!timers_state.cpu_ticks_enabled) { + return timers_state.cpu_clock_offset; + } else { + ti = get_clock(); + return ti + timers_state.cpu_clock_offset; + } +} + +/* enable cpu_get_ticks() */ +void cpu_enable_ticks(void) +{ + if (!timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset -= cpu_get_real_ticks(); + timers_state.cpu_clock_offset -= get_clock(); + timers_state.cpu_ticks_enabled = 1; + } +} + +/* disable cpu_get_ticks() : the clock is stopped. You must not call + cpu_get_ticks() after that. */ +void cpu_disable_ticks(void) +{ + if (timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset = cpu_get_ticks(); + timers_state.cpu_clock_offset = cpu_get_clock(); + timers_state.cpu_ticks_enabled = 0; + } +} + +/* Correlation between real and virtual time is always going to be + fairly approximate, so ignore small variation. + When the guest is idle real and virtual time will be aligned in + the IO wait loop. */ +#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10) + +static void icount_adjust(void) +{ + int64_t cur_time; + int64_t cur_icount; + int64_t delta; + static int64_t last_delta; + /* If the VM is not running, then do nothing. */ + if (!runstate_is_running()) { + return; + } + cur_time = cpu_get_clock(); + cur_icount = qemu_get_clock_ns(vm_clock); + delta = cur_icount - cur_time; + /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ + if (delta > 0 + && last_delta + ICOUNT_WOBBLE < delta * 2 + && icount_time_shift > 0) { + /* The guest is getting too far ahead. Slow time down. */ + icount_time_shift--; + } + if (delta < 0 + && last_delta - ICOUNT_WOBBLE > delta * 2 + && icount_time_shift < MAX_ICOUNT_SHIFT) { + /* The guest is getting too far behind. Speed time up. */ + icount_time_shift++; + } + last_delta = delta; + qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); +} + +static void icount_adjust_rt(void *opaque) +{ + qemu_mod_timer(icount_rt_timer, + qemu_get_clock_ms(rt_clock) + 1000); + icount_adjust(); +} + +static void icount_adjust_vm(void *opaque) +{ + qemu_mod_timer(icount_vm_timer, + qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); + icount_adjust(); +} + +static int64_t qemu_icount_round(int64_t count) +{ + return (count + (1 << icount_time_shift) - 1) >> icount_time_shift; +} + +static void icount_warp_rt(void *opaque) +{ + if (vm_clock_warp_start == -1) { + return; + } + + if (runstate_is_running()) { + int64_t clock = qemu_get_clock_ns(rt_clock); + int64_t warp_delta = clock - vm_clock_warp_start; + if (use_icount == 1) { + qemu_icount_bias += warp_delta; + } else { + /* + * In adaptive mode, do not let the vm_clock run too + * far ahead of real time. + */ + int64_t cur_time = cpu_get_clock(); + int64_t cur_icount = qemu_get_clock_ns(vm_clock); + int64_t delta = cur_time - cur_icount; + qemu_icount_bias += MIN(warp_delta, delta); + } + if (qemu_clock_expired(vm_clock)) { + qemu_notify_event(); + } + } + vm_clock_warp_start = -1; +} + +void qemu_clock_warp(QEMUClock *clock) +{ + int64_t deadline; + + /* + * There are too many global variables to make the "warp" behavior + * applicable to other clocks. But a clock argument removes the + * need for if statements all over the place. + */ + if (clock != vm_clock || !use_icount) { + return; + } + + /* + * If the CPUs have been sleeping, advance the vm_clock timer now. This + * ensures that the deadline for the timer is computed correctly below. + * This also makes sure that the insn counter is synchronized before the + * CPU starts running, in case the CPU is woken by an event other than + * the earliest vm_clock timer. + */ + icount_warp_rt(NULL); + if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) { + qemu_del_timer(icount_warp_timer); + return; + } + + vm_clock_warp_start = qemu_get_clock_ns(rt_clock); + deadline = qemu_clock_deadline(vm_clock); + if (deadline > 0) { + /* + * Ensure the vm_clock proceeds even when the virtual CPU goes to + * sleep. Otherwise, the CPU might be waiting for a future timer + * interrupt to wake it up, but the interrupt never comes because + * the vCPU isn't running any insns and thus doesn't advance the + * vm_clock. + * + * An extreme solution for this problem would be to never let VCPUs + * sleep in icount mode if there is a pending vm_clock timer; rather + * time could just advance to the next vm_clock event. Instead, we + * do stop VCPUs and only advance vm_clock after some "real" time, + * (related to the time left until the next event) has passed. This + * rt_clock timer will do this. This avoids that the warps are too + * visible externally---for example, you will not be sending network + * packets continously instead of every 100ms. + */ + qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline); + } else { + qemu_notify_event(); + } +} + +static const VMStateDescription vmstate_timers = { + .name = "timer", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(cpu_ticks_offset, TimersState), + VMSTATE_INT64(dummy, TimersState), + VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), + VMSTATE_END_OF_LIST() + } +}; + +void configure_icount(const char *option) +{ + vmstate_register(NULL, 0, &vmstate_timers, &timers_state); + if (!option) { + return; + } + + icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL); + if (strcmp(option, "auto") != 0) { + icount_time_shift = strtol(option, NULL, 0); + use_icount = 1; + return; + } + + use_icount = 2; + + /* 125MIPS seems a reasonable initial guess at the guest speed. + It will be corrected fairly quickly anyway. */ + icount_time_shift = 3; + + /* Have both realtime and virtual time triggers for speed adjustment. + The realtime trigger catches emulated time passing too slowly, + the virtual time trigger catches emulated time passing too fast. + Realtime triggers occur even when idle, so use them less frequently + than VM triggers. */ + icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL); + qemu_mod_timer(icount_rt_timer, + qemu_get_clock_ms(rt_clock) + 1000); + icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL); + qemu_mod_timer(icount_vm_timer, + qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); +} + +/***********************************************************/ void hw_error(const char *fmt, ...) { va_list ap; @@ -272,143 +542,10 @@ static void qemu_kvm_eat_signals(CPUState *env) #endif /* !CONFIG_LINUX */ #ifndef _WIN32 -static int io_thread_fd = -1; - -static void qemu_event_increment(void) -{ - /* Write 8 bytes to be compatible with eventfd. */ - static const uint64_t val = 1; - ssize_t ret; - - if (io_thread_fd == -1) { - return; - } - do { - ret = write(io_thread_fd, &val, sizeof(val)); - } while (ret < 0 && errno == EINTR); - - /* EAGAIN is fine, a read must be pending. */ - if (ret < 0 && errno != EAGAIN) { - fprintf(stderr, "qemu_event_increment: write() failed: %s\n", - strerror(errno)); - exit (1); - } -} - -static void qemu_event_read(void *opaque) -{ - int fd = (intptr_t)opaque; - ssize_t len; - char buffer[512]; - - /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */ - do { - len = read(fd, buffer, sizeof(buffer)); - } while ((len == -1 && errno == EINTR) || len == sizeof(buffer)); -} - -static int qemu_event_init(void) -{ - int err; - int fds[2]; - - err = qemu_eventfd(fds); - if (err == -1) { - return -errno; - } - err = fcntl_setfl(fds[0], O_NONBLOCK); - if (err < 0) { - goto fail; - } - err = fcntl_setfl(fds[1], O_NONBLOCK); - if (err < 0) { - goto fail; - } - qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, - (void *)(intptr_t)fds[0]); - - io_thread_fd = fds[1]; - return 0; - -fail: - close(fds[0]); - close(fds[1]); - return err; -} - static void dummy_signal(int sig) { } -/* If we have signalfd, we mask out the signals we want to handle and then - * use signalfd to listen for them. We rely on whatever the current signal - * handler is to dispatch the signals when we receive them. - */ -static void sigfd_handler(void *opaque) -{ - int fd = (intptr_t)opaque; - struct qemu_signalfd_siginfo info; - struct sigaction action; - ssize_t len; - - while (1) { - do { - len = read(fd, &info, sizeof(info)); - } while (len == -1 && errno == EINTR); - - if (len == -1 && errno == EAGAIN) { - break; - } - - if (len != sizeof(info)) { - printf("read from sigfd returned %zd: %m\n", len); - return; - } - - sigaction(info.ssi_signo, NULL, &action); - if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) { - action.sa_sigaction(info.ssi_signo, - (siginfo_t *)&info, NULL); - } else if (action.sa_handler) { - action.sa_handler(info.ssi_signo); - } - } -} - -static int qemu_signal_init(void) -{ - int sigfd; - sigset_t set; - - /* - * SIG_IPI must be blocked in the main thread and must not be caught - * by sigwait() in the signal thread. Otherwise, the cpu thread will - * not catch it reliably. - */ - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - sigemptyset(&set); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIGBUS); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - sigfd = qemu_signalfd(&set); - if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); - return -errno; - } - - fcntl_setfl(sigfd, O_NONBLOCK); - - qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, - (void *)(intptr_t)sigfd); - - return 0; -} - static void qemu_kvm_init_cpu_signals(CPUState *env) { int r; @@ -452,38 +589,6 @@ static void qemu_tcg_init_cpu_signals(void) } #else /* _WIN32 */ - -HANDLE qemu_event_handle; - -static void dummy_event_handler(void *opaque) -{ -} - -static int qemu_event_init(void) -{ - qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!qemu_event_handle) { - fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError()); - return -1; - } - qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL); - return 0; -} - -static void qemu_event_increment(void) -{ - if (!SetEvent(qemu_event_handle)) { - fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n", - GetLastError()); - exit (1); - } -} - -static int qemu_signal_init(void) -{ - return 0; -} - static void qemu_kvm_init_cpu_signals(CPUState *env) { abort(); @@ -509,38 +614,16 @@ static QemuCond qemu_cpu_cond; static QemuCond qemu_pause_cond; static QemuCond qemu_work_cond; -int qemu_init_main_loop(void) +void qemu_init_cpu_loop(void) { - int ret; - qemu_init_sigbus(); - - ret = qemu_signal_init(); - if (ret) { - return ret; - } - - /* Note eventfd must be drained before signalfd handlers run */ - ret = qemu_event_init(); - if (ret) { - return ret; - } - qemu_cond_init(&qemu_cpu_cond); qemu_cond_init(&qemu_pause_cond); qemu_cond_init(&qemu_work_cond); qemu_cond_init(&qemu_io_proceeded_cond); qemu_mutex_init(&qemu_global_mutex); - qemu_mutex_lock(&qemu_global_mutex); qemu_thread_get_self(&io_thread); - - return 0; -} - -void qemu_main_loop_start(void) -{ - resume_all_vcpus(); } void run_on_cpu(CPUState *env, void (*func)(void *data), void *data) @@ -686,7 +769,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { cpu_exec_all(); - if (use_icount && qemu_next_icount_deadline() <= 0) { + if (use_icount && qemu_clock_deadline(vm_clock) <= 0) { qemu_notify_event(); } qemu_tcg_wait_io_event(); @@ -784,6 +867,7 @@ void pause_all_vcpus(void) { CPUState *penv = first_cpu; + qemu_clock_enable(vm_clock, false); while (penv) { penv->stop = 1; qemu_cpu_kick(penv); @@ -858,11 +942,6 @@ void qemu_init_vcpu(void *_env) } } -void qemu_notify_event(void) -{ - qemu_event_increment(); -} - void cpu_stop_current(void) { if (cpu_single_env) { @@ -887,6 +966,17 @@ void vm_stop(RunState state) do_vm_stop(state); } +/* does a state transition even if the VM is already stopped, + current state is forgotten forever */ +void vm_stop_force_state(RunState state) +{ + if (runstate_is_running()) { + vm_stop(state); + } else { + runstate_set(state); + } +} + static int tcg_cpu_exec(CPUState *env) { int ret; @@ -903,7 +993,7 @@ static int tcg_cpu_exec(CPUState *env) qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 0; env->icount_extra = 0; - count = qemu_icount_round(qemu_next_icount_deadline()); + count = qemu_icount_round(qemu_clock_deadline(vm_clock)); qemu_icount += count; decr = (count > 0xffff) ? 0xffff : count; count -= decr; @@ -995,22 +1085,6 @@ void set_cpu_log_filename(const char *optarg) cpu_set_log_filename(optarg); } -/* Return the virtual CPU time, based on the instruction counter. */ -int64_t cpu_get_icount(void) -{ - int64_t icount; - CPUState *env = cpu_single_env;; - - icount = qemu_icount; - if (env) { - if (!can_do_io(env)) { - fprintf(stderr, "Bad clock read\n"); - } - icount -= (env->icount_decr.u16.low + env->icount_extra); - } - return qemu_icount_bias + (icount << icount_time_shift); -} - void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) { /* XXX: implement xxx_cpu_list for targets that still miss it */ @@ -2,8 +2,7 @@ #define QEMU_CPUS_H /* cpus.c */ -int qemu_init_main_loop(void); -void qemu_main_loop_start(void); +void qemu_init_cpu_loop(void); void resume_all_vcpus(void); void pause_all_vcpus(void); void cpu_stop_current(void); diff --git a/exec-all.h b/exec-all.h index 1120f84661..72ef246793 100644 --- a/exec-all.h +++ b/exec-all.h @@ -356,4 +356,18 @@ extern int singlestep; /* cpu-exec.c */ extern volatile sig_atomic_t exit_request; +/* Deterministic execution requires that IO only be performed on the last + instruction of a TB so that interrupts take effect immediately. */ +static inline int can_do_io(CPUState *env) +{ + if (!use_icount) { + return 1; + } + /* If not executing code then assume we are ok. */ + if (!env->current_tb) { + return 1; + } + return env->can_do_io != 0; +} + #endif @@ -125,9 +125,6 @@ CPUState *cpu_single_env; 1 = Precise instruction counting. 2 = Adaptive rate instruction counting. */ int use_icount = 0; -/* Current instruction counter. While executing translated code this may - include some instructions that have not yet been executed. */ -int64_t qemu_icount; typedef struct PageDesc { /* list of TBs intersecting this ram page */ diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 8de8abfd5b..908e2a5edc 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -23,23 +23,6 @@ #define SM_LOCAL_MODE_BITS 0600 #define SM_LOCAL_DIR_MODE_BITS 0700 -typedef enum -{ - /* - * Server will try to set uid/gid. - * On failure ignore the error. - */ - SM_NONE = 0, - /* - * uid/gid set on fileserver files - */ - SM_PASSTHROUGH = 1, - /* - * uid/gid part of xattr - */ - SM_MAPPED, -} SecModel; - typedef struct FsCred { uid_t fc_uid; @@ -49,17 +32,41 @@ typedef struct FsCred } FsCred; struct xattr_operations; +struct FsContext; +struct V9fsPath; -/* FsContext flag values */ -#define PATHNAME_FSCONTEXT 0x1 +typedef struct extended_ops { + int (*get_st_gen)(struct FsContext *, struct V9fsPath *, + mode_t, uint64_t *); +} extended_ops; + +/* export flags */ +#define V9FS_IMMEDIATE_WRITEOUT 0x00000001 +#define V9FS_PATHNAME_FSCONTEXT 0x00000002 +/* + * uid/gid set on fileserver files + */ +#define V9FS_SM_PASSTHROUGH 0x00000004 +/* + * uid/gid part of xattr + */ +#define V9FS_SM_MAPPED 0x00000008 +/* + * Server will try to set uid/gid. + * On failure ignore the error. + */ +#define V9FS_SM_NONE 0x00000010 + + +#define V9FS_SEC_MASK 0x0000001C typedef struct FsContext { - int flags; - char *fs_root; - SecModel fs_sm; uid_t uid; + char *fs_root; + int export_flags; struct xattr_operations **xops; + struct extended_ops exops; /* fs driver specific data */ void *private; } FsContext; diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index 768819f575..5977bcca4c 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -18,46 +18,55 @@ #include "qemu-common.h" #include "qemu-config.h" -static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries = - QTAILQ_HEAD_INITIALIZER(fstype_entries); +static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries = + QTAILQ_HEAD_INITIALIZER(fsdriver_entries); -static FsTypeTable FsTypes[] = { +static FsDriverTable FsDrivers[] = { { .name = "local", .ops = &local_ops}, { .name = "handle", .ops = &handle_ops}, }; int qemu_fsdev_add(QemuOpts *opts) { - struct FsTypeListEntry *fsle; + struct FsDriverListEntry *fsle; int i; const char *fsdev_id = qemu_opts_id(opts); - const char *fstype = qemu_opt_get(opts, "fstype"); + const char *fsdriver = qemu_opt_get(opts, "fsdriver"); const char *path = qemu_opt_get(opts, "path"); const char *sec_model = qemu_opt_get(opts, "security_model"); + const char *writeout = qemu_opt_get(opts, "writeout"); + if (!fsdev_id) { fprintf(stderr, "fsdev: No id specified\n"); return -1; } - if (fstype) { - for (i = 0; i < ARRAY_SIZE(FsTypes); i++) { - if (strcmp(FsTypes[i].name, fstype) == 0) { + if (fsdriver) { + for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) { + if (strcmp(FsDrivers[i].name, fsdriver) == 0) { break; } } - if (i == ARRAY_SIZE(FsTypes)) { - fprintf(stderr, "fsdev: fstype %s not found\n", fstype); + if (i == ARRAY_SIZE(FsDrivers)) { + fprintf(stderr, "fsdev: fsdriver %s not found\n", fsdriver); return -1; } } else { - fprintf(stderr, "fsdev: No fstype specified\n"); + fprintf(stderr, "fsdev: No fsdriver specified\n"); + return -1; + } + + if (!strcmp(fsdriver, "local") && !sec_model) { + fprintf(stderr, "security model not specified, " + "local fs needs security model\nvalid options are:" + "\tsecurity_model=[passthrough|mapped|none]\n"); return -1; } - if (!sec_model) { - fprintf(stderr, "fsdev: No security_model specified.\n"); + if (strcmp(fsdriver, "local") && sec_model) { + fprintf(stderr, "only local fs driver needs security model\n"); return -1; } @@ -70,20 +79,40 @@ int qemu_fsdev_add(QemuOpts *opts) fsle->fse.fsdev_id = g_strdup(fsdev_id); fsle->fse.path = g_strdup(path); - fsle->fse.security_model = g_strdup(sec_model); - fsle->fse.ops = FsTypes[i].ops; + fsle->fse.ops = FsDrivers[i].ops; + fsle->fse.export_flags = 0; + if (writeout) { + if (!strcmp(writeout, "immediate")) { + fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT; + } + } - QTAILQ_INSERT_TAIL(&fstype_entries, fsle, next); - return 0; + if (strcmp(fsdriver, "local")) { + goto done; + } + if (!strcmp(sec_model, "passthrough")) { + fsle->fse.export_flags |= V9FS_SM_PASSTHROUGH; + } else if (!strcmp(sec_model, "mapped")) { + fsle->fse.export_flags |= V9FS_SM_MAPPED; + } else if (!strcmp(sec_model, "none")) { + fsle->fse.export_flags |= V9FS_SM_NONE; + } else { + fprintf(stderr, "Invalid security model %s specified, valid options are" + "\n\t [passthrough|mapped|none]\n", sec_model); + return -1; + } +done: + QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next); + return 0; } -FsTypeEntry *get_fsdev_fsentry(char *id) +FsDriverEntry *get_fsdev_fsentry(char *id) { if (id) { - struct FsTypeListEntry *fsle; + struct FsDriverListEntry *fsle; - QTAILQ_FOREACH(fsle, &fstype_entries, next) { + QTAILQ_FOREACH(fsle, &fsdriver_entries, next) { if (strcmp(fsle->fse.fsdev_id, id) == 0) { return &fsle->fse; } diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h index e04931a58d..5099085720 100644 --- a/fsdev/qemu-fsdev.h +++ b/fsdev/qemu-fsdev.h @@ -29,28 +29,28 @@ * ----------------- * etc */ -typedef struct FsTypeTable { +typedef struct FsDriverTable { const char *name; FileOperations *ops; -} FsTypeTable; +} FsDriverTable; /* * Structure to store the various fsdev's passed through command line. */ -typedef struct FsTypeEntry { +typedef struct FsDriverEntry { char *fsdev_id; char *path; - char *security_model; + int export_flags; FileOperations *ops; -} FsTypeEntry; +} FsDriverEntry; -typedef struct FsTypeListEntry { - FsTypeEntry fse; - QTAILQ_ENTRY(FsTypeListEntry) next; -} FsTypeListEntry; +typedef struct FsDriverListEntry { + FsDriverEntry fse; + QTAILQ_ENTRY(FsDriverListEntry) next; +} FsDriverListEntry; int qemu_fsdev_add(QemuOpts *opts); -FsTypeEntry *get_fsdev_fsentry(char *id); +FsDriverEntry *get_fsdev_fsentry(char *id); extern FileOperations local_ops; extern FileOperations handle_ops; #endif diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 7ad4bec005..692811e5ab 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -17,6 +17,30 @@ #include "qemu-coroutine.h" #include "virtio-9p-coth.h" +int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, + V9fsStatDotl *v9stat) +{ + int err = 0; + V9fsState *s = pdu->s; + + if (v9fs_request_cancelled(pdu)) { + return -EINTR; + } + if (s->ctx.exops.get_st_gen) { + v9fs_path_read_lock(s); + v9fs_co_run_in_worker( + { + err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode, + &v9stat->st_gen); + if (err < 0) { + err = -errno; + } + }); + v9fs_path_unlock(s); + } + return err; +} + int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf) { int err; diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 68745add1e..83f125bd47 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -323,7 +323,7 @@ int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, int err; V9fsState *s = pdu->s; - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { err = s->ops->name_to_path(&s->ctx, dirpath, name, path); if (err < 0) { err = -errno; diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index 4630080e53..ca96b9cf2f 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -101,4 +101,7 @@ extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *, struct iovec *, int, int64_t); extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, const char *, V9fsPath *); +extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, + V9fsStatDotl *v9stat); + #endif diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c deleted file mode 100644 index 96925f04a4..0000000000 --- a/hw/9pfs/virtio-9p-debug.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Virtio 9p PDU debug - * - * Copyright IBM, Corp. 2010 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "hw/virtio.h" -#include "hw/pc.h" -#include "virtio-9p.h" -#include "virtio-9p-debug.h" - -#define BUG_ON(cond) assert(!(cond)) - -static FILE *llogfile; - -static struct iovec *get_sg(V9fsPDU *pdu, int rx) -{ - if (rx) { - return pdu->elem.in_sg; - } - return pdu->elem.out_sg; -} - -static int get_sg_count(V9fsPDU *pdu, int rx) -{ - if (rx) { - return pdu->elem.in_num; - } - return pdu->elem.out_num; - -} - -static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - size_t offset = *offsetp; - struct iovec *sg = get_sg(pdu, rx); - int8_t value; - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%x", name, value); - *offsetp = offset; -} - -static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - int16_t value; - - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%x", name, value); - *offsetp = offset; -} - -static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - int32_t value; - - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%x", name, value); - *offsetp = offset; -} - -static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - int64_t value; - - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%" PRIx64, name, value); - *offsetp = offset; -} - -static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - int sg_count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - uint16_t tmp_size, size; - size_t result; - size_t copied = 0; - int i = 0; - - /* get the size */ - copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size)); - BUG_ON(copied != sizeof(tmp_size)); - size = le16_to_cpupu(&tmp_size); - offset += copied; - - fprintf(llogfile, "%s=", name); - for (i = 0; size && i < sg_count; i++) { - size_t len; - if (offset >= sg[i].iov_len) { - /* skip this sg */ - offset -= sg[i].iov_len; - continue; - } else { - len = MIN(sg[i].iov_len - offset, size); - result = fwrite(sg[i].iov_base + offset, 1, len, llogfile); - BUG_ON(result != len); - size -= len; - copied += len; - if (size) { - offset = 0; - continue; - } - } - } - *offsetp += copied; -} - -static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - fprintf(llogfile, "%s={", name); - pprint_int8(pdu, rx, offsetp, "type"); - pprint_int32(pdu, rx, offsetp, ", version"); - pprint_int64(pdu, rx, offsetp, ", path"); - fprintf(llogfile, "}"); -} - -static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - fprintf(llogfile, "%s={", name); - pprint_int16(pdu, rx, offsetp, "size"); - pprint_int16(pdu, rx, offsetp, ", type"); - pprint_int32(pdu, rx, offsetp, ", dev"); - pprint_qid(pdu, rx, offsetp, ", qid"); - pprint_int32(pdu, rx, offsetp, ", mode"); - pprint_int32(pdu, rx, offsetp, ", atime"); - pprint_int32(pdu, rx, offsetp, ", mtime"); - pprint_int64(pdu, rx, offsetp, ", length"); - pprint_str(pdu, rx, offsetp, ", name"); - pprint_str(pdu, rx, offsetp, ", uid"); - pprint_str(pdu, rx, offsetp, ", gid"); - pprint_str(pdu, rx, offsetp, ", muid"); - pprint_str(pdu, rx, offsetp, ", extension"); - pprint_int32(pdu, rx, offsetp, ", uid"); - pprint_int32(pdu, rx, offsetp, ", gid"); - pprint_int32(pdu, rx, offsetp, ", muid"); - fprintf(llogfile, "}"); -} - -static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - fprintf(llogfile, "%s={", name); - pprint_qid(pdu, rx, offsetp, "qid"); - pprint_int32(pdu, rx, offsetp, ", st_mode"); - pprint_int64(pdu, rx, offsetp, ", st_nlink"); - pprint_int32(pdu, rx, offsetp, ", st_uid"); - pprint_int32(pdu, rx, offsetp, ", st_gid"); - pprint_int64(pdu, rx, offsetp, ", st_rdev"); - pprint_int64(pdu, rx, offsetp, ", st_size"); - pprint_int64(pdu, rx, offsetp, ", st_blksize"); - pprint_int64(pdu, rx, offsetp, ", st_blocks"); - pprint_int64(pdu, rx, offsetp, ", atime"); - pprint_int64(pdu, rx, offsetp, ", atime_nsec"); - pprint_int64(pdu, rx, offsetp, ", mtime"); - pprint_int64(pdu, rx, offsetp, ", mtime_nsec"); - pprint_int64(pdu, rx, offsetp, ", ctime"); - pprint_int64(pdu, rx, offsetp, ", ctime_nsec"); - fprintf(llogfile, "}"); -} - - - -static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - int sg_count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - uint16_t tmp_count, count, i; - size_t copied = 0; - - fprintf(llogfile, "%s={", name); - - /* Get the count */ - copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); - BUG_ON(copied != sizeof(tmp_count)); - count = le16_to_cpupu(&tmp_count); - offset += copied; - - for (i = 0; i < count; i++) { - char str[512]; - if (i) { - fprintf(llogfile, ", "); - } - snprintf(str, sizeof(str), "[%d]", i); - pprint_str(pdu, rx, &offset, str); - } - - fprintf(llogfile, "}"); - - *offsetp = offset; -} - -static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - int sg_count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - uint16_t tmp_count, count, i; - size_t copied = 0; - - fprintf(llogfile, "%s={", name); - - copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); - BUG_ON(copied != sizeof(tmp_count)); - count = le16_to_cpupu(&tmp_count); - offset += copied; - - for (i = 0; i < count; i++) { - char str[512]; - if (i) { - fprintf(llogfile, ", "); - } - snprintf(str, sizeof(str), "[%d]", i); - pprint_qid(pdu, rx, &offset, str); - } - - fprintf(llogfile, "}"); - - *offsetp = offset; -} - -static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - struct iovec *sg = get_sg(pdu, rx); - unsigned int count; - int i; - - if (rx) { - count = pdu->elem.in_num; - } else { - count = pdu->elem.out_num; - } - - fprintf(llogfile, "%s={", name); - for (i = 0; i < count; i++) { - if (i) { - fprintf(llogfile, ", "); - } - fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len); - } - fprintf(llogfile, "}"); -} - -/* FIXME: read from a directory fid returns serialized stat_t's */ -#ifdef DEBUG_DATA -static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - unsigned int count; - int32_t size; - int total, i, j; - ssize_t len; - - if (rx) { - count = pdu->elem.in_num; - } else { - count = pdu->elem.out_num; - } - - BUG_ON((offset + sizeof(size)) > sg[0].iov_len); - - memcpy(&size, sg[0].iov_base + offset, sizeof(size)); - offset += sizeof(size); - - fprintf(llogfile, "size: %x\n", size); - - sg[0].iov_base += 11; /* skip header */ - sg[0].iov_len -= 11; - - total = 0; - for (i = 0; i < count; i++) { - total += sg[i].iov_len; - if (total >= size) { - /* trim sg list so writev does the right thing */ - sg[i].iov_len -= (total - size); - i++; - break; - } - } - - fprintf(llogfile, "%s={\"", name); - fflush(llogfile); - for (j = 0; j < i; j++) { - if (j) { - fprintf(llogfile, "\", \""); - fflush(llogfile); - } - - do { - len = writev(fileno(llogfile), &sg[j], 1); - } while (len == -1 && errno == EINTR); - fprintf(llogfile, "len == %ld: %m\n", len); - BUG_ON(len != sg[j].iov_len); - } - fprintf(llogfile, "\"}"); - - sg[0].iov_base -= 11; - sg[0].iov_len += 11; - -} -#endif - -void pprint_pdu(V9fsPDU *pdu) -{ - size_t offset = 7; - - if (llogfile == NULL) { - llogfile = fopen("/tmp/pdu.log", "w"); - } - - BUG_ON(!llogfile); - - switch (pdu->id) { - case P9_TREADDIR: - fprintf(llogfile, "TREADDIR: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int64(pdu, 0, &offset, ", initial offset"); - pprint_int32(pdu, 0, &offset, ", max count"); - break; - case P9_RREADDIR: - fprintf(llogfile, "RREADDIR: ("); - pprint_int32(pdu, 1, &offset, "count"); -#ifdef DEBUG_DATA - pprint_data(pdu, 1, &offset, ", data"); -#endif - break; - case P9_TMKDIR: - fprintf(llogfile, "TMKDIR: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, "name"); - pprint_int32(pdu, 0, &offset, "mode"); - pprint_int32(pdu, 0, &offset, "gid"); - break; - case P9_RMKDIR: - fprintf(llogfile, "RMKDIR: ("); - pprint_qid(pdu, 0, &offset, "qid"); - break; - case P9_TVERSION: - fprintf(llogfile, "TVERSION: ("); - pprint_int32(pdu, 0, &offset, "msize"); - pprint_str(pdu, 0, &offset, ", version"); - break; - case P9_RVERSION: - fprintf(llogfile, "RVERSION: ("); - pprint_int32(pdu, 1, &offset, "msize"); - pprint_str(pdu, 1, &offset, ", version"); - break; - case P9_TGETATTR: - fprintf(llogfile, "TGETATTR: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RGETATTR: - fprintf(llogfile, "RGETATTR: ("); - pprint_stat_dotl(pdu, 1, &offset, "getattr"); - break; - case P9_TAUTH: - fprintf(llogfile, "TAUTH: ("); - pprint_int32(pdu, 0, &offset, "afid"); - pprint_str(pdu, 0, &offset, ", uname"); - pprint_str(pdu, 0, &offset, ", aname"); - pprint_int32(pdu, 0, &offset, ", n_uname"); - break; - case P9_RAUTH: - fprintf(llogfile, "RAUTH: ("); - pprint_qid(pdu, 1, &offset, "qid"); - break; - case P9_TATTACH: - fprintf(llogfile, "TATTACH: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int32(pdu, 0, &offset, ", afid"); - pprint_str(pdu, 0, &offset, ", uname"); - pprint_str(pdu, 0, &offset, ", aname"); - pprint_int32(pdu, 0, &offset, ", n_uname"); - break; - case P9_RATTACH: - fprintf(llogfile, "RATTACH: ("); - pprint_qid(pdu, 1, &offset, "qid"); - break; - case P9_TERROR: - fprintf(llogfile, "TERROR: ("); - break; - case P9_RERROR: - fprintf(llogfile, "RERROR: ("); - pprint_str(pdu, 1, &offset, "ename"); - pprint_int32(pdu, 1, &offset, ", ecode"); - break; - case P9_TFLUSH: - fprintf(llogfile, "TFLUSH: ("); - pprint_int16(pdu, 0, &offset, "oldtag"); - break; - case P9_RFLUSH: - fprintf(llogfile, "RFLUSH: ("); - break; - case P9_TWALK: - fprintf(llogfile, "TWALK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int32(pdu, 0, &offset, ", newfid"); - pprint_strs(pdu, 0, &offset, ", wnames"); - break; - case P9_RWALK: - fprintf(llogfile, "RWALK: ("); - pprint_qids(pdu, 1, &offset, "wqids"); - break; - case P9_TOPEN: - fprintf(llogfile, "TOPEN: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int8(pdu, 0, &offset, ", mode"); - break; - case P9_ROPEN: - fprintf(llogfile, "ROPEN: ("); - pprint_qid(pdu, 1, &offset, "qid"); - pprint_int32(pdu, 1, &offset, ", iounit"); - break; - case P9_TCREATE: - fprintf(llogfile, "TCREATE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_int32(pdu, 0, &offset, ", perm"); - pprint_int8(pdu, 0, &offset, ", mode"); - pprint_str(pdu, 0, &offset, ", extension"); - break; - case P9_RCREATE: - fprintf(llogfile, "RCREATE: ("); - pprint_qid(pdu, 1, &offset, "qid"); - pprint_int32(pdu, 1, &offset, ", iounit"); - break; - case P9_TSYMLINK: - fprintf(llogfile, "TSYMLINK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_str(pdu, 0, &offset, ", symname"); - pprint_int32(pdu, 0, &offset, ", gid"); - break; - case P9_RSYMLINK: - fprintf(llogfile, "RSYMLINK: ("); - pprint_qid(pdu, 1, &offset, "qid"); - break; - case P9_TLCREATE: - fprintf(llogfile, "TLCREATE: ("); - pprint_int32(pdu, 0, &offset, "dfid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_int32(pdu, 0, &offset, ", flags"); - pprint_int32(pdu, 0, &offset, ", mode"); - pprint_int32(pdu, 0, &offset, ", gid"); - break; - case P9_RLCREATE: - fprintf(llogfile, "RLCREATE: ("); - pprint_qid(pdu, 1, &offset, "qid"); - pprint_int32(pdu, 1, &offset, ", iounit"); - break; - case P9_TMKNOD: - fprintf(llogfile, "TMKNOD: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, "name"); - pprint_int32(pdu, 0, &offset, "mode"); - pprint_int32(pdu, 0, &offset, "major"); - pprint_int32(pdu, 0, &offset, "minor"); - pprint_int32(pdu, 0, &offset, "gid"); - break; - case P9_RMKNOD: - fprintf(llogfile, "RMKNOD: )"); - pprint_qid(pdu, 0, &offset, "qid"); - break; - case P9_TREADLINK: - fprintf(llogfile, "TREADLINK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RREADLINK: - fprintf(llogfile, "RREADLINK: ("); - pprint_str(pdu, 0, &offset, "target"); - break; - case P9_TREAD: - fprintf(llogfile, "TREAD: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int64(pdu, 0, &offset, ", offset"); - pprint_int32(pdu, 0, &offset, ", count"); - pprint_sg(pdu, 0, &offset, ", sg"); - break; - case P9_RREAD: - fprintf(llogfile, "RREAD: ("); - pprint_int32(pdu, 1, &offset, "count"); - pprint_sg(pdu, 1, &offset, ", sg"); - offset = 7; -#ifdef DEBUG_DATA - pprint_data(pdu, 1, &offset, ", data"); -#endif - break; - case P9_TWRITE: - fprintf(llogfile, "TWRITE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int64(pdu, 0, &offset, ", offset"); - pprint_int32(pdu, 0, &offset, ", count"); - break; - case P9_RWRITE: - fprintf(llogfile, "RWRITE: ("); - pprint_int32(pdu, 1, &offset, "count"); - break; - case P9_TCLUNK: - fprintf(llogfile, "TCLUNK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RCLUNK: - fprintf(llogfile, "RCLUNK: ("); - break; - case P9_TFSYNC: - fprintf(llogfile, "TFSYNC: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RFSYNC: - fprintf(llogfile, "RFSYNC: ("); - break; - case P9_TLINK: - fprintf(llogfile, "TLINK: ("); - pprint_int32(pdu, 0, &offset, "dfid"); - pprint_int32(pdu, 0, &offset, ", fid"); - pprint_str(pdu, 0, &offset, ", newpath"); - break; - case P9_RLINK: - fprintf(llogfile, "RLINK: ("); - break; - case P9_TREMOVE: - fprintf(llogfile, "TREMOVE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RREMOVE: - fprintf(llogfile, "RREMOVE: ("); - break; - case P9_TSTAT: - fprintf(llogfile, "TSTAT: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RSTAT: - fprintf(llogfile, "RSTAT: ("); - offset += 2; /* ignored */ - pprint_stat(pdu, 1, &offset, "stat"); - break; - case P9_TWSTAT: - fprintf(llogfile, "TWSTAT: ("); - pprint_int32(pdu, 0, &offset, "fid"); - offset += 2; /* ignored */ - pprint_stat(pdu, 0, &offset, ", stat"); - break; - case P9_RWSTAT: - fprintf(llogfile, "RWSTAT: ("); - break; - case P9_TXATTRWALK: - fprintf(llogfile, "TXATTRWALK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int32(pdu, 0, &offset, ", newfid"); - pprint_str(pdu, 0, &offset, ", xattr name"); - break; - case P9_RXATTRWALK: - fprintf(llogfile, "RXATTRWALK: ("); - pprint_int64(pdu, 1, &offset, "xattrsize"); - case P9_TXATTRCREATE: - fprintf(llogfile, "TXATTRCREATE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_int64(pdu, 0, &offset, ", xattrsize"); - pprint_int32(pdu, 0, &offset, ", flags"); - break; - case P9_RXATTRCREATE: - fprintf(llogfile, "RXATTRCREATE: ("); - break; - case P9_TLOCK: - fprintf(llogfile, "TLOCK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int8(pdu, 0, &offset, ", type"); - pprint_int32(pdu, 0, &offset, ", flags"); - pprint_int64(pdu, 0, &offset, ", start"); - pprint_int64(pdu, 0, &offset, ", length"); - pprint_int32(pdu, 0, &offset, ", proc_id"); - pprint_str(pdu, 0, &offset, ", client_id"); - break; - case P9_RLOCK: - fprintf(llogfile, "RLOCK: ("); - pprint_int8(pdu, 0, &offset, "status"); - break; - case P9_TGETLOCK: - fprintf(llogfile, "TGETLOCK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int8(pdu, 0, &offset, ", type"); - pprint_int64(pdu, 0, &offset, ", start"); - pprint_int64(pdu, 0, &offset, ", length"); - pprint_int32(pdu, 0, &offset, ", proc_id"); - pprint_str(pdu, 0, &offset, ", client_id"); - break; - case P9_RGETLOCK: - fprintf(llogfile, "RGETLOCK: ("); - pprint_int8(pdu, 0, &offset, "type"); - pprint_int64(pdu, 0, &offset, ", start"); - pprint_int64(pdu, 0, &offset, ", length"); - pprint_int32(pdu, 0, &offset, ", proc_id"); - pprint_str(pdu, 0, &offset, ", client_id"); - break; - default: - fprintf(llogfile, "unknown(%d): (", pdu->id); - break; - } - - fprintf(llogfile, ")\n"); - /* Flush the log message out */ - fflush(llogfile); -} diff --git a/hw/9pfs/virtio-9p-debug.h b/hw/9pfs/virtio-9p-debug.h deleted file mode 100644 index d9a249118d..0000000000 --- a/hw/9pfs/virtio-9p-debug.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _QEMU_VIRTIO_9P_DEBUG_H -#define _QEMU_VIRTIO_9P_DEBUG_H - -void pprint_pdu(V9fsPDU *pdu); - -#endif diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 513e181c82..bba4c54762 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -49,7 +49,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) V9fsState *s; int i, len; struct stat stat; - FsTypeEntry *fse; + FsDriverEntry *fse; + V9fsPath path; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P, @@ -82,55 +83,33 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) exit(1); } - if (!strcmp(fse->security_model, "passthrough")) { - /* Files on the Fileserver set to client user credentials */ - s->ctx.fs_sm = SM_PASSTHROUGH; + s->ctx.export_flags = fse->export_flags; + s->ctx.fs_root = g_strdup(fse->path); + s->ctx.exops.get_st_gen = NULL; + + if (fse->export_flags & V9FS_SM_PASSTHROUGH) { s->ctx.xops = passthrough_xattr_ops; - } else if (!strcmp(fse->security_model, "mapped")) { - /* Files on the fileserver are set to QEMU credentials. - * Client user credentials are saved in extended attributes. - */ - s->ctx.fs_sm = SM_MAPPED; + } else if (fse->export_flags & V9FS_SM_MAPPED) { s->ctx.xops = mapped_xattr_ops; - } else if (!strcmp(fse->security_model, "none")) { - /* - * Files on the fileserver are set to QEMU credentials. - */ - s->ctx.fs_sm = SM_NONE; - s->ctx.xops = none_xattr_ops; - } else { - fprintf(stderr, "Default to security_model=none. You may want" - " enable advanced security model using " - "security option:\n\t security_model=passthrough\n\t " - "security_model=mapped\n"); - s->ctx.fs_sm = SM_NONE; + } else if (fse->export_flags & V9FS_SM_NONE) { s->ctx.xops = none_xattr_ops; } - if (lstat(fse->path, &stat)) { - fprintf(stderr, "share path %s does not exist\n", fse->path); - exit(1); - } else if (!S_ISDIR(stat.st_mode)) { - fprintf(stderr, "share path %s is not a directory\n", fse->path); - exit(1); - } - - s->ctx.fs_root = g_strdup(fse->path); len = strlen(conf->tag); if (len > MAX_TAG_LEN) { - len = MAX_TAG_LEN; + fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " + "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN); + exit(1); } /* s->tag is non-NULL terminated string */ s->tag = g_malloc(len); memcpy(s->tag, conf->tag, len); s->tag_len = len; s->ctx.uid = -1; - s->ctx.flags = 0; s->ops = fse->ops; s->vdev.get_features = virtio_9p_get_features; - s->config_size = sizeof(struct virtio_9p_config) + - s->tag_len; + s->config_size = sizeof(struct virtio_9p_config) + s->tag_len; s->vdev.get_config = virtio_9p_get_config; s->fid_list = NULL; qemu_co_rwlock_init(&s->rename_lock); @@ -144,6 +123,27 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) fprintf(stderr, "worker thread initialization failed\n"); exit(1); } + + /* + * Check details of export path, We need to use fs driver + * call back to do that. Since we are in the init path, we don't + * use co-routines here. + */ + v9fs_path_init(&path); + if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { + fprintf(stderr, + "error in converting name to path %s", strerror(errno)); + exit(1); + } + if (s->ops->lstat(&s->ctx, &path, &stat)) { + fprintf(stderr, "share path %s does not exist\n", fse->path); + exit(1); + } else if (!S_ISDIR(stat.st_mode)) { + fprintf(stderr, "share path %s is not a directory\n", fse->path); + exit(1); + } + v9fs_path_free(&path); + return &s->vdev; } @@ -169,6 +169,8 @@ static PCIDeviceInfo virtio_9p_info = { .revision = VIRTIO_PCI_ABI_VERSION, .class_id = 0x2, .qdev.props = (Property[]) { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c index 5c8b5ed471..98809f1642 100644 --- a/hw/9pfs/virtio-9p-handle.c +++ b/hw/9pfs/virtio-9p-handle.c @@ -21,49 +21,56 @@ #include <sys/un.h> #include <attr/xattr.h> #include <unistd.h> - -struct handle_data { - int mountfd; - int handle_bytes; -}; - -#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14 -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char handle[0]; -}; +#include <linux/fs.h> +#ifdef CONFIG_LINUX_MAGIC_H +#include <linux/magic.h> #endif +#include <sys/ioctl.h> -#ifndef AT_EMPTY_PATH -#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ +#ifndef XFS_SUPER_MAGIC +#define XFS_SUPER_MAGIC 0x58465342 #endif -#ifndef O_PATH -#define O_PATH 010000000 +#ifndef EXT2_SUPER_MAGIC +#define EXT2_SUPER_MAGIC 0xEF53 #endif - -#ifndef __NR_name_to_handle_at -#if defined(__i386__) -#define __NR_name_to_handle_at 341 -#define __NR_open_by_handle_at 342 -#elif defined(__x86_64__) -#define __NR_name_to_handle_at 303 -#define __NR_open_by_handle_at 304 +#ifndef REISERFS_SUPER_MAGIC +#define REISERFS_SUPER_MAGIC 0x52654973 #endif +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E #endif -#ifdef __NR_name_to_handle_at +struct handle_data { + int mountfd; + int handle_bytes; +}; + +#ifdef CONFIG_OPEN_BY_HANDLE static inline int name_to_handle(int dirfd, const char *name, struct file_handle *fh, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags); + return name_to_handle_at(dirfd, name, fh, mnt_id, flags); } static inline int open_by_handle(int mountfd, const char *fh, int flags) { - return syscall(__NR_open_by_handle_at, mountfd, fh, flags); + return open_by_handle_at(mountfd, (struct file_handle *)fh, flags); } #else + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char handle[0]; +}; + +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ +#endif +#ifndef O_PATH +#define O_PATH 010000000 +#endif + static inline int name_to_handle(int dirfd, const char *name, struct file_handle *fh, int *mnt_id, int flags) { @@ -192,16 +199,29 @@ static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov, static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov, int iovcnt, off_t offset) { + ssize_t ret; #ifdef CONFIG_PREADV - return pwritev(fd, iov, iovcnt, offset); + ret = pwritev(fd, iov, iovcnt, offset); #else int err = lseek(fd, offset, SEEK_SET); if (err == -1) { return err; } else { - return writev(fd, iov, iovcnt); + ret = writev(fd, iov, iovcnt); } #endif +#ifdef CONFIG_SYNC_FILE_RANGE + if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { + /* + * Initiate a writeback. This is not a data integrity sync. + * We want to ensure that we don't leave dirty pages in the cache + * after write when writeout=immediate is sepcified. + */ + sync_file_range(fd, offset, ret, + SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); + } +#endif + return ret; } static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) @@ -367,7 +387,9 @@ static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, const struct timespec *buf) { - int fd, ret; + int ret; +#ifdef CONFIG_UTIMENSAT + int fd; struct handle_data *data = (struct handle_data *)ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); @@ -376,6 +398,10 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, } ret = futimens(fd, buf); close(fd); +#else + ret = -1; + errno = ENOSYS; +#endif return ret; } @@ -546,16 +572,50 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir, return ret; } +static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path, + mode_t st_mode, uint64_t *st_gen) +{ + int err, fd; + + /* + * Do not try to open special files like device nodes, fifos etc + * We can get fd for regular files and directories only + */ + if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { + return 0; + } + fd = handle_open(ctx, path, O_RDONLY); + if (fd < 0) { + return fd; + } + err = ioctl(fd, FS_IOC_GETVERSION, st_gen); + handle_close(ctx, fd); + return err; +} + static int handle_init(FsContext *ctx) { int ret, mnt_id; + struct statfs stbuf; struct file_handle fh; struct handle_data *data = g_malloc(sizeof(struct handle_data)); + data->mountfd = open(ctx->fs_root, O_DIRECTORY); if (data->mountfd < 0) { ret = data->mountfd; goto err_out; } + ret = statfs(ctx->fs_root, &stbuf); + if (!ret) { + switch (stbuf.f_type) { + case EXT2_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + ctx->exops.get_st_gen = handle_ioc_getversion; + break; + } + } memset(&fh, 0, sizeof(struct file_handle)); ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0); if (ret && errno == EOVERFLOW) { diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 9559ff6550..d561de88f0 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -20,6 +20,24 @@ #include <sys/socket.h> #include <sys/un.h> #include <attr/xattr.h> +#include <linux/fs.h> +#ifdef CONFIG_LINUX_MAGIC_H +#include <linux/magic.h> +#endif +#include <sys/ioctl.h> + +#ifndef XFS_SUPER_MAGIC +#define XFS_SUPER_MAGIC 0x58465342 +#endif +#ifndef EXT2_SUPER_MAGIC +#define EXT2_SUPER_MAGIC 0xEF53 +#endif +#ifndef REISERFS_SUPER_MAGIC +#define REISERFS_SUPER_MAGIC 0x52654973 +#endif +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E +#endif static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { @@ -31,7 +49,7 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) if (err) { return err; } - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { /* Actual credentials are part of extended attrs */ uid_t tmp_uid; gid_t tmp_gid; @@ -106,7 +124,7 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, * If we fail to change ownership and if we are * using security model none. Ignore the error */ - if (fs_ctx->fs_sm != SM_NONE) { + if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { return -1; } } @@ -120,7 +138,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char buffer[PATH_MAX]; char *path = fs_path->data; - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { int fd; fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); if (fd == -1) { @@ -131,8 +149,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, } while (tsize == -1 && errno == EINTR); close(fd); return tsize; - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz); } return tsize; @@ -203,16 +221,30 @@ static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov, static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, int iovcnt, off_t offset) { + ssize_t ret +; #ifdef CONFIG_PREADV - return pwritev(fd, iov, iovcnt, offset); + ret = pwritev(fd, iov, iovcnt, offset); #else int err = lseek(fd, offset, SEEK_SET); if (err == -1) { return err; } else { - return writev(fd, iov, iovcnt); + ret = writev(fd, iov, iovcnt); } #endif +#ifdef CONFIG_SYNC_FILE_RANGE + if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { + /* + * Initiate a writeback. This is not a data integrity sync. + * We want to ensure that we don't leave dirty pages in the cache + * after write when writeout=immediate is sepcified. + */ + sync_file_range(fd, offset, ret, + SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); + } +#endif + return ret; } static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) @@ -220,10 +252,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) char buffer[PATH_MAX]; char *path = fs_path->data; - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); } return -1; @@ -243,7 +275,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, path = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { err = mknod(rpath(fs_ctx, path, buffer), SM_LOCAL_MODE_BITS|S_IFREG, 0); if (err == -1) { @@ -254,8 +286,8 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, credp->fc_rdev); if (err == -1) { @@ -291,7 +323,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, path = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); if (err == -1) { goto out; @@ -302,8 +334,8 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); if (err == -1) { goto out; @@ -331,7 +363,7 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) if (err) { return err; } - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { /* Actual credentials are part of extended attrs */ uid_t tmp_uid; gid_t tmp_gid; @@ -369,7 +401,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, path = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); if (fd == -1) { err = fd; @@ -382,8 +414,8 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); if (fd == -1) { err = fd; @@ -422,7 +454,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, newpath = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { int fd; ssize_t oldpath_size, write_size; fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, @@ -451,8 +483,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); if (err) { goto out; @@ -464,7 +496,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, * If we fail to change ownership and if we are * using security model none. Ignore the error */ - if (fs_ctx->fs_sm != SM_NONE) { + if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { serrno = errno; goto err_end; } else @@ -519,13 +551,13 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) char *path = fs_path->data; if ((credp->fc_uid == -1 && credp->fc_gid == -1) || - (fs_ctx->fs_sm == SM_PASSTHROUGH)) { + (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH)) { return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, credp->fc_gid); - } else if (fs_ctx->fs_sm == SM_MAPPED) { + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, credp->fc_gid); } @@ -645,10 +677,44 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, return ret; } +static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, + mode_t st_mode, uint64_t *st_gen) +{ + int err, fd; + /* + * Do not try to open special files like device nodes, fifos etc + * We can get fd for regular files and directories only + */ + if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { + return 0; + } + fd = local_open(ctx, path, O_RDONLY); + if (fd < 0) { + return fd; + } + err = ioctl(fd, FS_IOC_GETVERSION, st_gen); + local_close(ctx, fd); + return err; +} + static int local_init(FsContext *ctx) { - ctx->flags |= PATHNAME_FSCONTEXT; - return 0; + int err; + struct statfs stbuf; + + ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; + err = statfs(ctx->fs_root, &stbuf); + if (!err) { + switch (stbuf.f_type) { + case EXT2_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + ctx->exops.get_st_gen = local_ioc_getversion; + break; + } + } + return err; } FileOperations local_ops = { diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index c01c31aa25..aab3bebcc7 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -17,11 +17,10 @@ #include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" -#include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" +#include "trace.h" -int debug_9p_pdu; int open_fd_hw; int total_open_fd; static int open_fd_rc; @@ -72,6 +71,55 @@ static int omode_to_uflags(int8_t mode) return ret; } +static int dotl_to_at_flags(int flags) +{ + int rflags = 0; + if (flags & P9_DOTL_AT_REMOVEDIR) { + rflags |= AT_REMOVEDIR; + } + return rflags; +} + +struct dotl_openflag_map { + int dotl_flag; + int open_flag; +}; + +static int dotl_to_open_flags(int flags) +{ + int i; + /* + * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY + * and P9_DOTL_NOACCESS + */ + int oflags = flags & O_ACCMODE; + + struct dotl_openflag_map dotl_oflag_map[] = { + { P9_DOTL_CREATE, O_CREAT }, + { P9_DOTL_EXCL, O_EXCL }, + { P9_DOTL_NOCTTY , O_NOCTTY }, + { P9_DOTL_TRUNC, O_TRUNC }, + { P9_DOTL_APPEND, O_APPEND }, + { P9_DOTL_NONBLOCK, O_NONBLOCK } , + { P9_DOTL_DSYNC, O_DSYNC }, + { P9_DOTL_FASYNC, FASYNC }, + { P9_DOTL_DIRECT, O_DIRECT }, + { P9_DOTL_LARGEFILE, O_LARGEFILE }, + { P9_DOTL_DIRECTORY, O_DIRECTORY }, + { P9_DOTL_NOFOLLOW, O_NOFOLLOW }, + { P9_DOTL_NOATIME, O_NOATIME }, + { P9_DOTL_SYNC, O_SYNC }, + }; + + for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) { + if (flags & dotl_oflag_map[i].dotl_flag) { + oflags |= dotl_oflag_map[i].open_flag; + } + } + + return oflags; +} + void cred_init(FsCred *credp) { credp->fc_uid = -1; @@ -80,6 +128,21 @@ void cred_init(FsCred *credp) credp->fc_rdev = -1; } +static int get_dotl_openflags(V9fsState *s, int oflags) +{ + int flags; + /* + * Filter the client open flags + */ + flags = dotl_to_open_flags(oflags); + flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); + /* + * Ignore direct disk access hint until the server supports it. + */ + flags &= ~O_DIRECT; + return flags; +} + void v9fs_string_init(V9fsString *str) { str->data = NULL; @@ -621,9 +684,6 @@ static V9fsPDU *alloc_pdu(V9fsState *s) static void free_pdu(V9fsState *s, V9fsPDU *pdu) { if (pdu) { - if (debug_9p_pdu) { - pprint_pdu(pdu); - } /* * Cancelled pdu are added back to the freelist * by flush request . @@ -909,6 +969,7 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len) if (s->proto_version == V9FS_PROTO_2000L) { id = P9_RLERROR; } + trace_complete_pdu(pdu->tag, pdu->id, err); /* Trace ERROR */ } /* fill out the header */ @@ -1218,6 +1279,7 @@ static void v9fs_version(void *opaque) size_t offset = 7; pdu_unmarshal(pdu, offset, "ds", &s->msize, &version); + trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data); if (!strcmp(version.data, "9P2000.u")) { s->proto_version = V9FS_PROTO_2000U; @@ -1228,6 +1290,8 @@ static void v9fs_version(void *opaque) } offset += pdu_marshal(pdu, offset, "ds", s->msize, &version); + trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data); + complete_pdu(s, pdu, offset); v9fs_string_free(&version); @@ -1246,6 +1310,7 @@ static void v9fs_attach(void *opaque) ssize_t err; pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname); + trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data); fidp = alloc_fid(s, fid); if (fidp == NULL) { @@ -1270,6 +1335,8 @@ static void v9fs_attach(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_attach_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path); complete_pdu(s, pdu, err); v9fs_string_free(&uname); v9fs_string_free(&aname); @@ -1287,6 +1354,7 @@ static void v9fs_stat(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_stat(pdu->tag, pdu->id, fid); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -1307,6 +1375,9 @@ static void v9fs_stat(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode, + v9stat.atime, v9stat.mtime, v9stat.length); + complete_pdu(s, pdu, err); } @@ -1323,6 +1394,7 @@ static void v9fs_getattr(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask); + trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -1338,11 +1410,24 @@ static void v9fs_getattr(void *opaque) goto out; } stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl); + + /* fill st_gen if requested and supported by underlying fs */ + if (request_mask & P9_STATS_GEN) { + retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl); + if (retval < 0) { + goto out; + } + v9stat_dotl.st_result_mask |= P9_STATS_GEN; + } retval = offset; retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl); out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask, + v9stat_dotl.st_mode, v9stat_dotl.st_uid, + v9stat_dotl.st_gid); + complete_pdu(s, pdu, retval); } @@ -1470,6 +1555,8 @@ static void v9fs_walk(void *opaque) offset += pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); + trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames); + if (nwnames && nwnames <= P9_MAXWELEM) { wnames = g_malloc0(sizeof(wnames[0]) * nwnames); qids = g_malloc0(sizeof(qids[0]) * nwnames); @@ -1526,6 +1613,7 @@ out: v9fs_path_free(&dpath); v9fs_path_free(&path); out_nofid: + trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids); complete_pdu(s, pdu, err); if (nwnames && nwnames <= P9_MAXWELEM) { for (name_idx = 0; name_idx < nwnames; name_idx++) { @@ -1576,6 +1664,8 @@ static void v9fs_open(void *opaque) } else { pdu_unmarshal(pdu, offset, "db", &fid, &mode); } + trace_v9fs_open(pdu->tag, pdu->id, fid, mode); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -1598,10 +1688,7 @@ static void v9fs_open(void *opaque) err = offset; } else { if (s->proto_version == V9FS_PROTO_2000L) { - flags = mode; - flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); - /* Ignore direct disk access hint until the server supports it. */ - flags &= ~O_DIRECT; + flags = get_dotl_openflags(s, mode); } else { flags = omode_to_uflags(mode); } @@ -1625,6 +1712,8 @@ static void v9fs_open(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_open_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, iounit); complete_pdu(s, pdu, err); } @@ -1643,6 +1732,7 @@ static void v9fs_lcreate(void *opaque) pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags, &mode, &gid); + trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid); fidp = get_fid(pdu, dfid); if (fidp == NULL) { @@ -1650,8 +1740,7 @@ static void v9fs_lcreate(void *opaque) goto out_nofid; } - /* Ignore direct disk access hint until the server supports it. */ - flags &= ~O_DIRECT; + flags = get_dotl_openflags(pdu->s, flags); err = v9fs_co_open2(pdu, fidp, &name, gid, flags | O_CREAT, mode, &stbuf); if (err < 0) { @@ -1673,6 +1762,8 @@ static void v9fs_lcreate(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_lcreate_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, iounit); complete_pdu(pdu->s, pdu, err); v9fs_string_free(&name); } @@ -1688,6 +1779,8 @@ static void v9fs_fsync(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dd", &fid, &datasync); + trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -1712,6 +1805,7 @@ static void v9fs_clunk(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_clunk(pdu->tag, pdu->id, fid); fidp = clunk_fid(s, fid); if (fidp == NULL) { @@ -1828,6 +1922,7 @@ static void v9fs_read(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count); + trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -1886,6 +1981,7 @@ static void v9fs_read(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_read_return(pdu->tag, pdu->id, count, err); complete_pdu(s, pdu, err); } @@ -1970,6 +2066,8 @@ static void v9fs_readdir(void *opaque) pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count); + trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count); + fidp = get_fid(pdu, fid); if (fidp == NULL) { retval = -EINVAL; @@ -1995,6 +2093,7 @@ static void v9fs_readdir(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval); complete_pdu(s, pdu, retval); } @@ -2059,6 +2158,7 @@ static void v9fs_write(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt); + trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2105,6 +2205,7 @@ static void v9fs_write(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_write_return(pdu->tag, pdu->id, total, err); complete_pdu(s, pdu, err); } @@ -2129,6 +2230,8 @@ static void v9fs_create(void *opaque) pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name, &perm, &mode, &extension); + trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -EINVAL; @@ -2262,6 +2365,8 @@ static void v9fs_create(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_create_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, iounit); complete_pdu(pdu->s, pdu, err); v9fs_string_free(&name); v9fs_string_free(&extension); @@ -2282,6 +2387,7 @@ static void v9fs_symlink(void *opaque) size_t offset = 7; pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid); + trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid); dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { @@ -2298,6 +2404,8 @@ static void v9fs_symlink(void *opaque) out: put_fid(pdu, dfidp); out_nofid: + trace_v9fs_symlink_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path); complete_pdu(pdu->s, pdu, err); v9fs_string_free(&name); v9fs_string_free(&symname); @@ -2312,6 +2420,7 @@ static void v9fs_flush(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "w", &tag); + trace_v9fs_flush(pdu->tag, pdu->id, tag); QLIST_FOREACH(cancel_pdu, &s->active_list, next) { if (cancel_pdu->tag == tag) { @@ -2342,6 +2451,7 @@ static void v9fs_link(void *opaque) int err = 0; pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name); + trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data); dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { @@ -2375,6 +2485,7 @@ static void v9fs_remove(void *opaque) V9fsPDU *pdu = opaque; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_remove(pdu->tag, pdu->id, fid); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2382,7 +2493,7 @@ static void v9fs_remove(void *opaque) goto out_nofid; } /* if fs driver is not path based, return EOPNOTSUPP */ - if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) { + if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) { err = -EOPNOTSUPP; goto out_err; } @@ -2417,6 +2528,7 @@ static void v9fs_unlinkat(void *opaque) V9fsPDU *pdu = opaque; pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags); + flags = dotl_to_at_flags(flags); dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { @@ -2528,7 +2640,7 @@ static void v9fs_rename(void *opaque) } BUG_ON(fidp->fid_type != P9_FID_NONE); /* if fs driver is not path based, return EOPNOTSUPP */ - if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) { + if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) { err = -EOPNOTSUPP; goto out; } @@ -2601,7 +2713,7 @@ static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid, if (err < 0) { goto out; } - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { /* Only for path based fid we need to do the below fixup */ v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name, &newdirfidp->path, new_name); @@ -2653,6 +2765,8 @@ static void v9fs_wstat(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat); + trace_v9fs_wstat(pdu->tag, pdu->id, fid, + v9stat.mode, v9stat.atime, v9stat.mtime); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2821,6 +2935,7 @@ static void v9fs_mknod(void *opaque) pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode, &major, &minor, &gid); + trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2838,6 +2953,7 @@ static void v9fs_mknod(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_mknod_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path); complete_pdu(s, pdu, err); v9fs_string_free(&name); } @@ -2865,6 +2981,10 @@ static void v9fs_lock(void *opaque) pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type, &flock->flags, &flock->start, &flock->length, &flock->proc_id, &flock->client_id); + + trace_v9fs_lock(pdu->tag, pdu->id, fid, + flock->type, flock->start, flock->length); + status = P9_LOCK_ERROR; /* We support only block flag now (that too ignored currently) */ @@ -2887,6 +3007,7 @@ out: out_nofid: err = offset; err += pdu_marshal(pdu, offset, "b", status); + trace_v9fs_lock_return(pdu->tag, pdu->id, status); complete_pdu(s, pdu, err); v9fs_string_free(&flock->client_id); g_free(flock); @@ -2911,6 +3032,9 @@ static void v9fs_getlock(void *opaque) &glock->start, &glock->length, &glock->proc_id, &glock->client_id); + trace_v9fs_getlock(pdu->tag, pdu->id, fid, + glock->type, glock->start, glock->length); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -2920,7 +3044,7 @@ static void v9fs_getlock(void *opaque) if (err < 0) { goto out; } - glock->type = F_UNLCK; + glock->type = P9_LOCK_TYPE_UNLCK; offset += pdu_marshal(pdu, offset, "bqqds", glock->type, glock->start, glock->length, glock->proc_id, &glock->client_id); @@ -2928,6 +3052,9 @@ static void v9fs_getlock(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start, + glock->length, glock->proc_id); + complete_pdu(s, pdu, err); v9fs_string_free(&glock->client_id); g_free(glock); @@ -2948,6 +3075,8 @@ static void v9fs_mkdir(void *opaque) pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid); + trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -2963,6 +3092,8 @@ static void v9fs_mkdir(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_mkdir_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, err); complete_pdu(pdu->s, pdu, err); v9fs_string_free(&name); } @@ -2980,6 +3111,8 @@ static void v9fs_xattrwalk(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name); + trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data); + file_fidp = get_fid(pdu, fid); if (file_fidp == NULL) { err = -ENOENT; @@ -3056,6 +3189,7 @@ out: put_fid(pdu, xattr_fidp); } out_nofid: + trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size); complete_pdu(s, pdu, err); v9fs_string_free(&name); } @@ -3075,6 +3209,7 @@ static void v9fs_xattrcreate(void *opaque) pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags); + trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags); file_fidp = get_fid(pdu, fid); if (file_fidp == NULL) { @@ -3111,6 +3246,7 @@ static void v9fs_readlink(void *opaque) V9fsFidState *fidp; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_readlink(pdu->tag, pdu->id, fid); fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -3128,6 +3264,7 @@ static void v9fs_readlink(void *opaque) out: put_fid(pdu, fidp); out_nofid: + trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data); complete_pdu(pdu->s, pdu, err); } @@ -3179,9 +3316,6 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu) Coroutine *co; CoroutineEntry *handler; - if (debug_9p_pdu) { - pprint_pdu(pdu); - } if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) || (pdu_co_handlers[pdu->id] == NULL)) { handler = v9fs_op_not_supp; diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 60b8a56e57..802f5809d1 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -352,6 +352,35 @@ typedef struct V9fsMkState { V9fsString fullname; } V9fsMkState; +/* 9p2000.L open flags */ +#define P9_DOTL_RDONLY 00000000 +#define P9_DOTL_WRONLY 00000001 +#define P9_DOTL_RDWR 00000002 +#define P9_DOTL_NOACCESS 00000003 +#define P9_DOTL_CREATE 00000100 +#define P9_DOTL_EXCL 00000200 +#define P9_DOTL_NOCTTY 00000400 +#define P9_DOTL_TRUNC 00001000 +#define P9_DOTL_APPEND 00002000 +#define P9_DOTL_NONBLOCK 00004000 +#define P9_DOTL_DSYNC 00010000 +#define P9_DOTL_FASYNC 00020000 +#define P9_DOTL_DIRECT 00040000 +#define P9_DOTL_LARGEFILE 00100000 +#define P9_DOTL_DIRECTORY 00200000 +#define P9_DOTL_NOFOLLOW 00400000 +#define P9_DOTL_NOATIME 01000000 +#define P9_DOTL_CLOEXEC 02000000 +#define P9_DOTL_SYNC 04000000 + +/* 9p2000.L at flags */ +#define P9_DOTL_AT_REMOVEDIR 0x200 + +/* 9P2000.L lock type */ +#define P9_LOCK_TYPE_RDLCK 0 +#define P9_LOCK_TYPE_WRLCK 1 +#define P9_LOCK_TYPE_UNLCK 2 + #define P9_LOCK_SUCCESS 0 #define P9_LOCK_BLOCKED 1 #define P9_LOCK_ERROR 2 @@ -393,21 +422,21 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count, static inline void v9fs_path_write_lock(V9fsState *s) { - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_wrlock(&s->rename_lock); } } static inline void v9fs_path_read_lock(V9fsState *s) { - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_rdlock(&s->rename_lock); } } static inline void v9fs_path_unlock(V9fsState *s) { - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_unlock(&s->rename_lock); } } diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 83213dd406..8dd8742f70 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -658,9 +658,6 @@ static void gic_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->enabled); for (i = 0; i < NUM_CPU(s); i++) { qemu_put_be32(f, s->cpu_enabled[i]); -#ifndef NVIC - qemu_put_be32(f, s->irq_target[i]); -#endif for (j = 0; j < 32; j++) qemu_put_be32(f, s->priority1[j][i]); for (j = 0; j < GIC_NIRQ; j++) @@ -674,6 +671,9 @@ static void gic_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->priority2[i]); } for (i = 0; i < GIC_NIRQ; i++) { +#ifndef NVIC + qemu_put_be32(f, s->irq_target[i]); +#endif qemu_put_byte(f, s->irq_state[i].enabled); qemu_put_byte(f, s->irq_state[i].pending); qemu_put_byte(f, s->irq_state[i].active); @@ -689,15 +689,12 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) int i; int j; - if (version_id != 1) + if (version_id != 2) return -EINVAL; s->enabled = qemu_get_be32(f); for (i = 0; i < NUM_CPU(s); i++) { s->cpu_enabled[i] = qemu_get_be32(f); -#ifndef NVIC - s->irq_target[i] = qemu_get_be32(f); -#endif for (j = 0; j < 32; j++) s->priority1[j][i] = qemu_get_be32(f); for (j = 0; j < GIC_NIRQ; j++) @@ -711,6 +708,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) s->priority2[i] = qemu_get_be32(f); } for (i = 0; i < GIC_NIRQ; i++) { +#ifndef NVIC + s->irq_target[i] = qemu_get_be32(f); +#endif s->irq_state[i].enabled = qemu_get_byte(f); s->irq_state[i].pending = qemu_get_byte(f); s->irq_state[i].active = qemu_get_byte(f); @@ -739,5 +739,5 @@ static void gic_init(gic_state *s) } memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000); gic_reset(s); - register_savevm(NULL, "arm_gic", -1, 1, gic_save, gic_load, s); + register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s); } diff --git a/hw/collie.c b/hw/collie.c index a10cc1b90c..8dd6e4ec7e 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -13,6 +13,7 @@ #include "arm-misc.h" #include "flash.h" #include "blockdev.h" +#include "exec-memory.h" static struct arm_boot_info collie_binfo = { .loader_start = SA_SDCS0, @@ -26,12 +27,13 @@ static void collie_init(ram_addr_t ram_size, { StrongARMState *s; DriveInfo *dinfo; + MemoryRegion *sysmem = get_system_memory(); if (!cpu_model) { cpu_model = "sa1110"; } - s = sa1110_init(collie_binfo.ram_size, cpu_model); + s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model); dinfo = drive_get(IF_PFLASH, 0, 0); pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000, diff --git a/hw/devices.h b/hw/devices.h index 8ac384ff20..1a55c1e905 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -53,7 +53,8 @@ void retu_key_event(void *retu, int state); /* tc6393xb.c */ typedef struct TC6393xbState TC6393xbState; #define TC6393XB_RAM 0x110000 /* amount of ram for Video and USB */ -TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq); +TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem, + uint32_t base, qemu_irq irq); void tc6393xb_gpio_out_set(TC6393xbState *s, int line, qemu_irq handler); qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s); diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 9875c445f8..6852a61d08 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -29,7 +29,7 @@ typedef struct { DeviceState qdev; uint32_t chip_size; char *filename; - QEMUFile *file; + FILE *file; uint8_t *contents; } NvRamState; @@ -70,9 +70,9 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) s->contents[addr] = val; if (s->file) { - qemu_fseek(s->file, addr, SEEK_SET); - qemu_put_byte(s->file, (int)val); - qemu_fflush(s->file); + fseek(s->file, addr, SEEK_SET); + fputc(val, s->file); + fflush(s->file); } } @@ -108,15 +108,17 @@ static int nvram_post_load(void *opaque, int version_id) /* Close file, as filename may has changed in load/store process */ if (s->file) { - qemu_fclose(s->file); + fclose(s->file); } /* Write back nvram contents */ - s->file = qemu_fopen(s->filename, "wb"); + s->file = fopen(s->filename, "wb"); if (s->file) { /* Write back contents, as 'wb' mode cleaned the file */ - qemu_put_buffer(s->file, s->contents, s->chip_size); - qemu_fflush(s->file); + if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) { + printf("nvram_post_load: short write\n"); + } + fflush(s->file); } return 0; @@ -143,7 +145,7 @@ typedef struct { static int nvram_sysbus_initfn(SysBusDevice *dev) { NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram; - QEMUFile *file; + FILE *file; int s_io; s->contents = g_malloc0(s->chip_size); @@ -153,11 +155,13 @@ static int nvram_sysbus_initfn(SysBusDevice *dev) sysbus_init_mmio(dev, s->chip_size, s_io); /* Read current file */ - file = qemu_fopen(s->filename, "rb"); + file = fopen(s->filename, "rb"); if (file) { /* Read nvram contents */ - qemu_get_buffer(file, s->contents, s->chip_size); - qemu_fclose(file); + if (fread(s->contents, s->chip_size, 1, file) != 1) { + printf("nvram_sysbus_initfn: short read\n"); + } + fclose(file); } nvram_post_load(s, 0); @@ -434,6 +434,7 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) FDCtrl *fdctrl = opaque; uint32_t retval; + reg &= 7; switch (reg) { case FD_REG_SRA: retval = fdctrl_read_statusA(fdctrl); @@ -471,6 +472,7 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value); + reg &= 7; switch (reg) { case FD_REG_DOR: fdctrl_write_dor(fdctrl, value); @@ -1945,6 +1947,18 @@ static int sun4m_fdc_init1(SysBusDevice *dev) return fdctrl_init_common(fdctrl); } +void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev) +{ + FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev); + FDCtrl *fdctrl = &isa->state; + int i; + + for (i = 0; i < MAX_FD; i++) { + bs[i] = fdctrl->drives[i].bs; + } +} + + static const VMStateDescription vmstate_isa_fdc ={ .name = "fdc", .version_id = 2, @@ -7,14 +7,15 @@ /* fdc.c */ #define MAX_FD 2 -static inline void fdctrl_init_isa(DriveInfo **fds) +static inline ISADevice *fdctrl_init_isa(DriveInfo **fds) { ISADevice *dev; dev = isa_try_create("isa-fdc"); if (!dev) { - return; + return NULL; } + if (fds[0]) { qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv); } @@ -22,10 +23,14 @@ static inline void fdctrl_init_isa(DriveInfo **fds) qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv); } qdev_init_nofail(&dev->qdev); + + return dev; } void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, target_phys_addr_t mmio_base, DriveInfo **fds); void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base, DriveInfo **fds, qemu_irq *fdc_tc); +void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev); + #endif diff --git a/hw/hda-audio.c b/hw/hda-audio.c index c699d6fd8b..9b089e65b4 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -466,7 +466,8 @@ struct HDAAudioState { QEMUSoundCard card; const desc_codec *desc; HDAAudioStream st[4]; - bool running[16]; + bool running_compat[16]; + bool running_real[2 * 16]; /* properties */ uint32_t debug; @@ -663,7 +664,7 @@ static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data) st->channel = payload & 0x0f; dprint(a, 2, "%s: stream %d, channel %d\n", st->node->name, st->stream, st->channel); - hda_audio_set_running(st, a->running[st->stream]); + hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]); hda_codec_response(hda, true, 0); break; case AC_VERB_GET_CONV: @@ -746,16 +747,20 @@ fail: hda_codec_response(hda, true, 0); } -static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running) +static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output) { HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); int s; - a->running[stnr] = running; + a->running_compat[stnr] = running; + a->running_real[output * 16 + stnr] = running; for (s = 0; s < ARRAY_SIZE(a->st); s++) { if (a->st[s].node == NULL) { continue; } + if (a->st[s].output != output) { + continue; + } if (a->st[s].stream != stnr) { continue; } @@ -837,6 +842,12 @@ static int hda_audio_post_load(void *opaque, int version) int i; dprint(a, 1, "%s\n", __FUNCTION__); + if (version == 1) { + /* assume running_compat[] is for output streams */ + for (i = 0; i < ARRAY_SIZE(a->running_compat); i++) + a->running_real[16 + i] = a->running_compat[i]; + } + for (i = 0; i < ARRAY_SIZE(a->st); i++) { st = a->st + i; if (st->node == NULL) @@ -844,7 +855,7 @@ static int hda_audio_post_load(void *opaque, int version) hda_codec_parse_fmt(st->format, &st->as); hda_audio_setup(st); hda_audio_set_amp(st); - hda_audio_set_running(st, a->running[st->stream]); + hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]); } return 0; } @@ -868,13 +879,14 @@ static const VMStateDescription vmstate_hda_audio_stream = { static const VMStateDescription vmstate_hda_audio = { .name = "hda-audio", - .version_id = 1, + .version_id = 2, .post_load = hda_audio_post_load, .fields = (VMStateField []) { VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0, vmstate_hda_audio_stream, HDAAudioStream), - VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16), + VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16), + VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2), VMSTATE_END_OF_LIST() } }; @@ -85,8 +85,8 @@ uint64_t qemu_get_be64(QEMUFile *f); int qemu_file_rate_limit(QEMUFile *f); int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); -int qemu_file_has_error(QEMUFile *f); -void qemu_file_set_error(QEMUFile *f); +int qemu_file_get_error(QEMUFile *f); +void qemu_file_set_error(QEMUFile *f, int error); /* Try to send any outstanding data. This function is useful when output is * halted due to rate limiting or EAGAIN errors occur as it can be used to diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 4272204e03..f97775c235 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -389,14 +389,15 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, { HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); IntelHDAState *d = container_of(bus, IntelHDAState, codecs); - IntelHDAStream *st = NULL; target_phys_addr_t addr; uint32_t s, copy, left; + IntelHDAStream *st; bool irq = false; - for (s = 0; s < ARRAY_SIZE(d->st); s++) { - if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) { - st = d->st + s; + st = output ? d->st + 4 : d->st; + for (s = 0; s < 4; s++) { + if (stnr == ((st[s].ctl >> 20) & 0x0f)) { + st = st + s; break; } } @@ -484,7 +485,7 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st) st->bp = 0; } -static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running) +static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output) { DeviceState *qdev; HDACodecDevice *cdev; @@ -492,7 +493,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) { cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); if (cdev->info->stream) { - cdev->info->stream(cdev, stream, running); + cdev->info->stream(cdev, stream, running, output); } } } @@ -566,6 +567,7 @@ static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) { + bool output = reg->stream >= 4; IntelHDAStream *st = d->st + reg->stream; if (st->ctl & 0x01) { @@ -581,11 +583,11 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3 dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n", reg->stream, stnr, st->cbl); intel_hda_parse_bdl(d, st); - intel_hda_notify_codecs(d, stnr, true); + intel_hda_notify_codecs(d, stnr, true, output); } else { /* stop */ dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr); - intel_hda_notify_codecs(d, stnr, false); + intel_hda_notify_codecs(d, stnr, false, output); } } intel_hda_update_irq(d); diff --git a/hw/intel-hda.h b/hw/intel-hda.h index 4e44e3894f..65fd2a85bb 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -34,7 +34,7 @@ struct HDACodecDeviceInfo { int (*init)(HDACodecDevice *dev); int (*exit)(HDACodecDevice *dev); void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); - void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running); + void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output); }; void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, diff --git a/hw/m48t59.c b/hw/m48t59.c index f318e67919..a77937ef68 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -480,7 +480,6 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) { M48t59State *NVRAM = opaque; - addr -= NVRAM->io_base; NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); switch (addr) { case 0: @@ -492,7 +491,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) NVRAM->addr |= val << 8; break; case 3: - m48t59_write(NVRAM, val, NVRAM->addr); + m48t59_write(NVRAM, NVRAM->addr, val); NVRAM->addr = 0x0000; break; default: @@ -505,7 +504,6 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) M48t59State *NVRAM = opaque; uint32_t retval; - addr -= NVRAM->io_base; switch (addr) { case 3: retval = m48t59_read(NVRAM, NVRAM->addr); diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 5affdd18a5..1791ec12e1 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -661,11 +661,6 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, ch->io.channel = ch; } -void DBDMA_schedule(void) -{ - qemu_notify_event(); -} - static void dbdma_control_write(DBDMA_channel *ch) { diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h index 933e17c5b9..6d1abe6aae 100644 --- a/hw/mac_dbdma.h +++ b/hw/mac_dbdma.h @@ -41,5 +41,4 @@ struct DBDMA_io { void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMA_rw rw, DBDMA_flush flush, void *opaque); -void DBDMA_schedule(void); void* DBDMA_init (MemoryRegion **dbdma_mem); diff --git a/hw/omap2.c b/hw/omap2.c index 838c32f371..5197fef2d8 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -2409,6 +2409,11 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3)); sysbus_connect_irq(busdev, 9, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4)); + if (s->mpu_model == omap2430) { + sysbus_connect_irq(busdev, 12, + qdev_get_gpio_in(s->ih[0], + OMAP_INT_243X_GPIO_BANK5)); + } ta = omap_l4ta(s->l4, 3); sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1)); sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0)); @@ -331,12 +331,12 @@ static void pc_cmos_init_late(void *opaque) void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, - BusState *idebus0, BusState *idebus1, + ISADevice *floppy, BusState *idebus0, BusState *idebus1, ISADevice *s) { int val, nb, nb_heads, max_track, last_sect, i; FDriveType fd_type[2]; - DriveInfo *fd[2]; + BlockDriverState *fd[MAX_FD]; static pc_cmos_init_late_arg arg; /* various important CMOS locations needed by PC/Bochs bios */ @@ -378,14 +378,16 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, } /* floppy type */ - for (i = 0; i < 2; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - if (fd[i] && bdrv_is_inserted(fd[i]->bdrv)) { - bdrv_get_floppy_geometry_hint(fd[i]->bdrv, &nb_heads, &max_track, - &last_sect, FDRIVE_DRV_NONE, - &fd_type[i]); - } else { - fd_type[i] = FDRIVE_DRV_NONE; + if (floppy) { + fdc_get_bs(fd, floppy); + for (i = 0; i < 2; i++) { + if (fd[i] && bdrv_is_inserted(fd[i])) { + bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track, + &last_sect, FDRIVE_DRV_NONE, + &fd_type[i]); + } else { + fd_type[i] = FDRIVE_DRV_NONE; + } } } val = (cmos_get_fd_drive_type(fd_type[0]) << 4) | @@ -1124,6 +1126,7 @@ static void cpu_request_exit(void *opaque, int irq, int level) void pc_basic_device_init(qemu_irq *gsi, ISADevice **rtc_state, + ISADevice **floppy, bool no_vmport) { int i; @@ -1188,7 +1191,7 @@ void pc_basic_device_init(qemu_irq *gsi, for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } - fdctrl_init_isa(fd); + *floppy = fdctrl_init_isa(fd); } void pc_pci_device_init(PCIBus *pci_bus) @@ -142,11 +142,12 @@ qemu_irq *pc_allocate_cpu_irq(void); void pc_vga_init(PCIBus *pci_bus); void pc_basic_device_init(qemu_irq *gsi, ISADevice **rtc_state, + ISADevice **floppy, bool no_vmport); void pc_init_ne2k_isa(NICInfo *nd); void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, - BusState *ide0, BusState *ide1, + ISADevice *floppy, BusState *ide0, BusState *ide1, ISADevice *s); void pc_pci_device_init(PCIBus *pci_bus); diff --git a/hw/pc_piix.c b/hw/pc_piix.c index c89042f1ce..8c7f2b7337 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -95,6 +95,7 @@ static void pc_init1(MemoryRegion *system_memory, DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; BusState *idebus[MAX_IDE_BUS]; ISADevice *rtc_state; + ISADevice *floppy; MemoryRegion *ram_memory; MemoryRegion *pci_memory; MemoryRegion *rom_memory; @@ -174,7 +175,7 @@ static void pc_init1(MemoryRegion *system_memory, } /* init basic PC hardware */ - pc_basic_device_init(gsi, &rtc_state, xen_enabled()); + pc_basic_device_init(gsi, &rtc_state, &floppy, xen_enabled()); for(i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -207,7 +208,7 @@ static void pc_init1(MemoryRegion *system_memory, audio_init(gsi, pci_enabled ? pci_bus : NULL); pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, - idebus[0], idebus[1], rtc_state); + floppy, idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled) { usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); @@ -998,17 +998,8 @@ static void pci_update_mappings(PCIDevice *d) } r->addr = new_addr; if (r->addr != PCI_BAR_UNMAPPED) { - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - memory_region_add_subregion_overlap(r->address_space, - r->addr, - r->memory, - 1); - } else { - memory_region_add_subregion_overlap(r->address_space, - r->addr, - r->memory, - 1); - } + memory_region_add_subregion_overlap(r->address_space, + r->addr, r->memory, 1); } } } diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index b6287cdc6d..650d1650c5 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -319,7 +319,7 @@ int pci_bridge_initfn(PCIDevice *dev) sec_bus->parent_dev = dev; sec_bus->map_irq = br->map_irq; sec_bus->address_space_mem = &br->address_space_mem; - memory_region_init(&br->address_space_mem, "pci_pridge_pci", INT64_MAX); + memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); sec_bus->address_space_io = &br->address_space_io; memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); pci_bridge_region_init(br); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index ebcaafa641..aac3526f55 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -73,11 +73,13 @@ static void ppc_heathrow_init (ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + MemoryRegion *sysmem = get_system_memory(); CPUState *env = NULL; char *filename; qemu_irq *pic, **heathrow_irqs; int linux_boot, i; - ram_addr_t ram_offset, bios_offset; + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; @@ -114,15 +116,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size, exit(1); } - ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size); - cpu_register_physical_memory(0, ram_size, ram_offset); + memory_region_init_ram(ram, NULL, "ppc_heathrow.ram", ram_size); + memory_region_add_subregion(sysmem, 0, ram); /* allocate and load BIOS */ - bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE); + memory_region_init_ram(bios, NULL, "ppc_heathrow.bios", BIOS_SIZE); if (bios_name == NULL) bios_name = PROM_FILENAME; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM); + memory_region_set_readonly(bios, true); + memory_region_add_subregion(sysmem, PROM_ADDR, bios); /* Load OpenBIOS (ELF) */ if (filename) { diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 6427baa562..f22d5b98c5 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -116,16 +116,17 @@ static uint32_t speaker_ioport_read (void *opaque, uint32_t addr) /* PCI intack register */ /* Read-only register (?) */ -static void _PPC_intack_write (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void PPC_intack_write (void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { #if 0 - printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr, + printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx64 "\n", __func__, addr, value); #endif } -static inline uint32_t _PPC_intack_read(target_phys_addr_t addr) +static uint64_t PPC_intack_read(void *opaque, target_phys_addr_t addr, + unsigned size) { uint32_t retval = 0; @@ -139,31 +140,10 @@ static inline uint32_t _PPC_intack_read(target_phys_addr_t addr) return retval; } -static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr) -{ - return _PPC_intack_read(addr); -} - -static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr) -{ - return _PPC_intack_read(addr); -} - -static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr) -{ - return _PPC_intack_read(addr); -} - -static CPUWriteMemoryFunc * const PPC_intack_write[] = { - &_PPC_intack_write, - &_PPC_intack_write, - &_PPC_intack_write, -}; - -static CPUReadMemoryFunc * const PPC_intack_read[] = { - &PPC_intack_readb, - &PPC_intack_readw, - &PPC_intack_readl, +static const MemoryRegionOps PPC_intack_ops = { + .read = PPC_intack_read, + .write = PPC_intack_write, + .endianness = DEVICE_LITTLE_ENDIAN, }; /* PowerPC control and status registers */ @@ -244,17 +224,14 @@ static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr) return retval; } -static CPUWriteMemoryFunc * const PPC_XCSR_write[] = { - &PPC_XCSR_writeb, - &PPC_XCSR_writew, - &PPC_XCSR_writel, +static const MemoryRegionOps PPC_XCSR_ops = { + .old_mmio = { + .read = { PPC_XCSR_readb, PPC_XCSR_readw, PPC_XCSR_readl, }, + .write = { PPC_XCSR_writeb, PPC_XCSR_writew, PPC_XCSR_writel, }, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; -static CPUReadMemoryFunc * const PPC_XCSR_read[] = { - &PPC_XCSR_readb, - &PPC_XCSR_readw, - &PPC_XCSR_readl, -}; #endif /* Fake super-io ports for PREP platform (Intel 82378ZB) */ @@ -503,16 +480,12 @@ static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr) return ret; } -static CPUWriteMemoryFunc * const PPC_prep_io_write[] = { - &PPC_prep_io_writeb, - &PPC_prep_io_writew, - &PPC_prep_io_writel, -}; - -static CPUReadMemoryFunc * const PPC_prep_io_read[] = { - &PPC_prep_io_readb, - &PPC_prep_io_readw, - &PPC_prep_io_readl, +static const MemoryRegionOps PPC_prep_io_ops = { + .old_mmio = { + .read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl }, + .write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel }, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; #define NVRAM_SIZE 0x2000 @@ -534,13 +507,19 @@ static void ppc_prep_init (ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + MemoryRegion *sysmem = get_system_memory(); CPUState *env = NULL; char *filename; nvram_t nvram; M48t59State *m48t59; - int PPC_io_memory; + MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1); + MemoryRegion *intack = g_new(MemoryRegion, 1); +#if 0 + MemoryRegion *xcsr = g_new(MemoryRegion, 1); +#endif int linux_boot, i, nb_nics1, bios_size; - ram_addr_t ram_offset, bios_offset; + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); uint32_t kernel_base, initrd_base; long kernel_size, initrd_size; PCIBus *pci_bus; @@ -574,11 +553,11 @@ static void ppc_prep_init (ram_addr_t ram_size, } /* allocate RAM */ - ram_offset = qemu_ram_alloc(NULL, "ppc_prep.ram", ram_size); - cpu_register_physical_memory(0, ram_size, ram_offset); + memory_region_init_ram(ram, NULL, "ppc_prep.ram", ram_size); + memory_region_add_subregion(sysmem, 0, ram); /* allocate and load BIOS */ - bios_offset = qemu_ram_alloc(NULL, "ppc_prep.bios", BIOS_SIZE); + memory_region_init_ram(bios, NULL, "ppc_prep.bios", BIOS_SIZE); if (bios_name == NULL) bios_name = BIOS_FILENAME; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); @@ -591,8 +570,8 @@ static void ppc_prep_init (ram_addr_t ram_size, target_phys_addr_t bios_addr; bios_size = (bios_size + 0xfff) & ~0xfff; bios_addr = (uint32_t)(-bios_size); - cpu_register_physical_memory(bios_addr, bios_size, - bios_offset | IO_MEM_ROM); + memory_region_set_readonly(bios, true); + memory_region_add_subregion(sysmem, bios_addr, bios); bios_size = load_image_targphys(filename, bios_addr, bios_size); } if (bios_size < 0 || bios_size > BIOS_SIZE) { @@ -655,10 +634,9 @@ static void ppc_prep_init (ram_addr_t ram_size, isa_bus_irqs(i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ - PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read, - PPC_prep_io_write, sysctrl, - DEVICE_LITTLE_ENDIAN); - cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); + memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl, + "ppc-io", 0x00800000); + memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory); /* init basic PC hardware */ pci_vga_init(pci_bus); @@ -713,15 +691,12 @@ static void ppc_prep_init (ram_addr_t ram_size, register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl); register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); /* PCI intack location */ - PPC_io_memory = cpu_register_io_memory(PPC_intack_read, - PPC_intack_write, NULL, - DEVICE_LITTLE_ENDIAN); - cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); + memory_region_init_io(intack, &PPC_intack_ops, NULL, "ppc-intack", 4); + memory_region_add_subregion(sysmem, 0xBFFFFFF0, intack); /* PowerPC control and status register group */ #if 0 - PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write, - NULL, DEVICE_LITTLE_ENDIAN); - cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); + memory_region_init_io(xcsr, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000); + memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr); #endif if (usb_enabled) { diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 5bf8eab897..51b6abddd3 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -229,6 +229,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, const char *cpu_model) { MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); PCIBus *pci_bus; CPUState *env = NULL; uint64_t elf_entry; @@ -291,8 +292,8 @@ static void mpc8544ds_init(ram_addr_t ram_size, ram_size &= ~(RAM_SIZES_ALIGN - 1); /* Register Memory */ - cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(NULL, - "mpc8544ds.ram", ram_size)); + memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size); + memory_region_add_subregion(address_space_mem, 0, ram); /* MPIC */ mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, @@ -122,6 +122,11 @@ typedef struct { CPUState *env; DeviceState *pic; qemu_irq reset; + MemoryRegion sdram; + MemoryRegion internal; + MemoryRegion cm_iomem; + MemoryRegion mm_iomem; + MemoryRegion pm_iomem; DeviceState *dma; DeviceState *gpio; PXA2xxLCDState *lcd; @@ -151,6 +156,7 @@ typedef struct { } PXA2xxState; struct PXA2xxI2SState { + MemoryRegion iomem; qemu_irq irq; qemu_irq rx_dma; qemu_irq tx_dma; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 70d7c8a06d..bfc28a999b 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -88,7 +88,8 @@ static PXASSPDef pxa27x_ssp[] = { #define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ #define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ -static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -107,7 +108,7 @@ static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -134,16 +135,10 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_pm_readfn[] = { - pxa2xx_pm_read, - pxa2xx_pm_read, - pxa2xx_pm_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = { - pxa2xx_pm_write, - pxa2xx_pm_write, - pxa2xx_pm_write, +static const MemoryRegionOps pxa2xx_pm_ops = { + .read = pxa2xx_pm_read, + .write = pxa2xx_pm_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_pxa2xx_pm = { @@ -162,7 +157,8 @@ static const VMStateDescription vmstate_pxa2xx_pm = { #define OSCC 0x08 /* Oscillator Configuration register */ #define CCSR 0x0c /* Core Clock Status register */ -static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -183,7 +179,7 @@ static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -206,16 +202,10 @@ static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_cm_readfn[] = { - pxa2xx_cm_read, - pxa2xx_cm_read, - pxa2xx_cm_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = { - pxa2xx_cm_write, - pxa2xx_cm_write, - pxa2xx_cm_write, +static const MemoryRegionOps pxa2xx_cm_ops = { + .read = pxa2xx_cm_read, + .write = pxa2xx_cm_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_pxa2xx_cm = { @@ -461,7 +451,8 @@ static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm, #define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */ #define SA1110 0x64 /* SA-1110 Memory Compatibility register */ -static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -478,7 +469,7 @@ static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -495,16 +486,10 @@ static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_mm_readfn[] = { - pxa2xx_mm_read, - pxa2xx_mm_read, - pxa2xx_mm_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = { - pxa2xx_mm_write, - pxa2xx_mm_write, - pxa2xx_mm_write, +static const MemoryRegionOps pxa2xx_mm_ops = { + .read = pxa2xx_mm_read, + .write = pxa2xx_mm_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_pxa2xx_mm = { @@ -521,6 +506,7 @@ static const VMStateDescription vmstate_pxa2xx_mm = { /* Synchronous Serial Ports */ typedef struct { SysBusDevice busdev; + MemoryRegion iomem; qemu_irq irq; int enable; SSIBus *bus; @@ -627,7 +613,8 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s) pxa2xx_ssp_int_update(s); } -static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; uint32_t retval; @@ -673,9 +660,10 @@ static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value64, unsigned size) { PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; + uint32_t value = value64; switch (addr) { case SSCR0: @@ -762,16 +750,10 @@ static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_ssp_readfn[] = { - pxa2xx_ssp_read, - pxa2xx_ssp_read, - pxa2xx_ssp_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_ssp_writefn[] = { - pxa2xx_ssp_write, - pxa2xx_ssp_write, - pxa2xx_ssp_write, +static const MemoryRegionOps pxa2xx_ssp_ops = { + .read = pxa2xx_ssp_read, + .write = pxa2xx_ssp_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) @@ -823,15 +805,12 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) static int pxa2xx_ssp_init(SysBusDevice *dev) { - int iomemtype; PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev); sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn, - pxa2xx_ssp_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x1000, iomemtype); + memory_region_init_io(&s->iomem, &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000); + sysbus_init_mmio_region(dev, &s->iomem); register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0, pxa2xx_ssp_save, pxa2xx_ssp_load, s); @@ -858,6 +837,7 @@ static int pxa2xx_ssp_init(SysBusDevice *dev) typedef struct { SysBusDevice busdev; + MemoryRegion iomem; uint32_t rttr; uint32_t rtsr; uint32_t rtar; @@ -1009,7 +989,8 @@ static inline void pxa2xx_rtc_pi_tick(void *opaque) pxa2xx_rtc_int_update(s); } -static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; @@ -1055,9 +1036,10 @@ static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value64, unsigned size) { PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + uint32_t value = value64; switch (addr) { case RTTR: @@ -1157,16 +1139,10 @@ static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_rtc_readfn[] = { - pxa2xx_rtc_read, - pxa2xx_rtc_read, - pxa2xx_rtc_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_rtc_writefn[] = { - pxa2xx_rtc_write, - pxa2xx_rtc_write, - pxa2xx_rtc_write, +static const MemoryRegionOps pxa2xx_rtc_ops = { + .read = pxa2xx_rtc_read, + .write = pxa2xx_rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int pxa2xx_rtc_init(SysBusDevice *dev) @@ -1174,7 +1150,6 @@ static int pxa2xx_rtc_init(SysBusDevice *dev) PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev); struct tm tm; int wom; - int iomemtype; s->rttr = 0x7fff; s->rtsr = 0; @@ -1201,9 +1176,8 @@ static int pxa2xx_rtc_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->rtc_irq); - iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn, - pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x10000, iomemtype); + memory_region_init_io(&s->iomem, &pxa2xx_rtc_ops, s, "pxa2xx-rtc", 0x10000); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -1272,6 +1246,7 @@ typedef struct { struct PXA2xxI2CState { SysBusDevice busdev; + MemoryRegion iomem; PXA2xxI2CSlaveState *slave; i2c_bus *bus; qemu_irq irq; @@ -1356,7 +1331,8 @@ static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data) return 1; } -static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; @@ -1384,9 +1360,10 @@ static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value64, unsigned size) { PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; + uint32_t value = value64; int ack; addr -= s->offset; @@ -1453,16 +1430,10 @@ static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_i2c_readfn[] = { - pxa2xx_i2c_read, - pxa2xx_i2c_read, - pxa2xx_i2c_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_i2c_writefn[] = { - pxa2xx_i2c_write, - pxa2xx_i2c_write, - pxa2xx_i2c_write, +static const MemoryRegionOps pxa2xx_i2c_ops = { + .read = pxa2xx_i2c_read, + .write = pxa2xx_i2c_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_pxa2xx_i2c_slave = { @@ -1536,13 +1507,12 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, static int pxa2xx_i2c_initfn(SysBusDevice *dev) { PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev); - int iomemtype; s->bus = i2c_init_bus(&dev->qdev, "i2c"); - iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn, - pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, s->region_size, iomemtype); + memory_region_init_io(&s->iomem, &pxa2xx_i2c_ops, s, + "pxa2xx-i2x", s->region_size); + sysbus_init_mmio_region(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); return 0; @@ -1621,7 +1591,8 @@ static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s) #define SADIV 0x60 /* Serial Audio Clock Divider register */ #define SADR 0x80 /* Serial Audio Data register */ -static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; @@ -1653,7 +1624,7 @@ static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; uint32_t *sample; @@ -1707,16 +1678,10 @@ static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_i2s_readfn[] = { - pxa2xx_i2s_read, - pxa2xx_i2s_read, - pxa2xx_i2s_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = { - pxa2xx_i2s_write, - pxa2xx_i2s_write, - pxa2xx_i2s_write, +static const MemoryRegionOps pxa2xx_i2s_ops = { + .read = pxa2xx_i2s_read, + .write = pxa2xx_i2s_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_pxa2xx_i2s = { @@ -1759,10 +1724,10 @@ static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) pxa2xx_i2s_update(s); } -static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base, +static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, + target_phys_addr_t base, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) { - int iomemtype; PXA2xxI2SState *s = (PXA2xxI2SState *) g_malloc0(sizeof(PXA2xxI2SState)); @@ -1773,9 +1738,9 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base, pxa2xx_i2s_reset(s); - iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn, - pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x100000, iomemtype); + memory_region_init_io(&s->iomem, &pxa2xx_i2s_ops, s, + "pxa2xx-i2s", 0x100000); + memory_region_add_subregion(sysmem, base, &s->iomem); vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s); @@ -1784,6 +1749,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base, /* PXA Fast Infra-red Communications Port */ struct PXA2xxFIrState { + MemoryRegion iomem; qemu_irq irq; qemu_irq rx_dma; qemu_irq tx_dma; @@ -1854,7 +1820,8 @@ static inline void pxa2xx_fir_update(PXA2xxFIrState *s) #define ICSR1 0x18 /* FICP Status register 1 */ #define ICFOR 0x1c /* FICP FIFO Occupancy Status register */ -static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr) +static uint64_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr, + unsigned size) { PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; uint8_t ret; @@ -1892,9 +1859,10 @@ static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr) } static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value64, unsigned size) { PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + uint32_t value = value64; uint8_t ch; switch (addr) { @@ -1936,16 +1904,10 @@ static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const pxa2xx_fir_readfn[] = { - pxa2xx_fir_read, - pxa2xx_fir_read, - pxa2xx_fir_read, -}; - -static CPUWriteMemoryFunc * const pxa2xx_fir_writefn[] = { - pxa2xx_fir_write, - pxa2xx_fir_write, - pxa2xx_fir_write, +static const MemoryRegionOps pxa2xx_fir_ops = { + .read = pxa2xx_fir_read, + .write = pxa2xx_fir_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int pxa2xx_fir_is_empty(void *opaque) @@ -2019,11 +1981,11 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base, +static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + target_phys_addr_t base, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, CharDriverState *chr) { - int iomemtype; PXA2xxFIrState *s = (PXA2xxFIrState *) g_malloc0(sizeof(PXA2xxFIrState)); @@ -2034,9 +1996,8 @@ static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base, pxa2xx_fir_reset(s); - iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn, - pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x1000, iomemtype); + memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); + memory_region_add_subregion(sysmem, base, &s->iomem); if (chr) qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, @@ -2063,7 +2024,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size, const char *revision) { PXA2xxState *s; - int iomemtype, i; + int i; DriveInfo *dinfo; s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); @@ -2082,12 +2043,11 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; /* SDRAM & Internal Memory Storage */ - cpu_register_physical_memory(PXA2XX_SDRAM_BASE, - sdram_size, qemu_ram_alloc(NULL, "pxa270.sdram", - sdram_size) | IO_MEM_RAM); - cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, - 0x40000, qemu_ram_alloc(NULL, "pxa270.internal", - 0x40000) | IO_MEM_RAM); + memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size); + memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); + memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000); + memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, + &s->internal); s->pic = pxa2xx_pic_init(0x40d00000, s->env); @@ -2125,7 +2085,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, } } if (serial_hds[i]) - s->fir = pxa2xx_fir_init(0x40800000, + s->fir = pxa2xx_fir_init(address_space, 0x40800000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), @@ -2137,9 +2097,8 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->cm_base = 0x41300000; s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ - iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, - pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); + memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); + memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2148,15 +2107,13 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->mm_regs[MDMRS >> 2] = 0x00020002; s->mm_regs[MDREFR >> 2] = 0x03ca4000; s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, - pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); + memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); + memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); s->pm_base = 0x40f00000; - iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, - pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); + memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); + memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa27x_ssp[i].io_base; i ++); @@ -2184,7 +2141,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->i2c[1] = pxa2xx_i2c_init(0x40f00100, qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); - s->i2s = pxa2xx_i2s_init(0x40400000, + s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); @@ -2202,7 +2159,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) { PXA2xxState *s; - int iomemtype, i; + int i; DriveInfo *dinfo; s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); @@ -2215,12 +2172,12 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; /* SDRAM & Internal Memory Storage */ - cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size, - qemu_ram_alloc(NULL, "pxa255.sdram", - sdram_size) | IO_MEM_RAM); - cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE, - qemu_ram_alloc(NULL, "pxa255.internal", - PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM); + memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size); + memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); + memory_region_init_ram(&s->internal, NULL, "pxa255.internal", + PXA2XX_INTERNAL_SIZE); + memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, + &s->internal); s->pic = pxa2xx_pic_init(0x40d00000, s->env); @@ -2257,7 +2214,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) } } if (serial_hds[i]) - s->fir = pxa2xx_fir_init(0x40800000, + s->fir = pxa2xx_fir_init(address_space, 0x40800000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), @@ -2269,9 +2226,8 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->cm_base = 0x41300000; s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ - iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, - pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); + memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); + memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2280,15 +2236,13 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->mm_regs[MDMRS >> 2] = 0x00020002; s->mm_regs[MDREFR >> 2] = 0x03ca4000; s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, - pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); + memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); + memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); s->pm_base = 0x40f00000; - iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, - pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); + memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); + memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa255_ssp[i].io_base; i ++); @@ -2316,7 +2270,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->i2c[1] = pxa2xx_i2c_init(0x40f00100, qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); - s->i2s = pxa2xx_i2s_init(0x40400000, + s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); @@ -82,6 +82,7 @@ typedef struct { /* output pin */ qemu_irq irl; + MemoryRegion iomem; } r2d_fpga_t; enum r2d_fpga_irq { @@ -168,31 +169,25 @@ r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value) } } -static CPUReadMemoryFunc * const r2d_fpga_readfn[] = { - r2d_fpga_read, - r2d_fpga_read, - NULL, +static const MemoryRegionOps r2d_fpga_ops = { + .old_mmio = { + .read = { r2d_fpga_read, r2d_fpga_read, NULL, }, + .write = { r2d_fpga_write, r2d_fpga_write, NULL, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static CPUWriteMemoryFunc * const r2d_fpga_writefn[] = { - r2d_fpga_write, - r2d_fpga_write, - NULL, -}; - -static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl) +static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem, + target_phys_addr_t base, qemu_irq irl) { - int iomemtype; r2d_fpga_t *s; s = g_malloc0(sizeof(r2d_fpga_t)); s->irl = irl; - iomemtype = cpu_register_io_memory(r2d_fpga_readfn, - r2d_fpga_writefn, s, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x40, iomemtype); + memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40); + memory_region_add_subregion(sysmem, base, &s->iomem); return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS); } @@ -232,7 +227,7 @@ static void r2d_init(ram_addr_t ram_size, CPUState *env; ResetData *reset_info; struct SH7750State *s; - ram_addr_t sdram_addr; + MemoryRegion *sdram = g_new(MemoryRegion, 1); qemu_irq *irq; DriveInfo *dinfo; int i; @@ -252,11 +247,11 @@ static void r2d_init(ram_addr_t ram_size, qemu_register_reset(main_cpu_reset, reset_info); /* Allocate memory space */ - sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE); - cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr); + memory_region_init_ram(sdram, NULL, "r2d.sdram", SDRAM_SIZE); + memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram); /* Register peripherals */ s = sh7750_init(env); - irq = r2d_fpga_init(0x04000000, sh7750_irl(s)); + irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s)); sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB], irq[PCI_INTC], irq[PCI_INTD], NULL); diff --git a/hw/realview.c b/hw/realview.c index 11ffb8a824..14281b0f06 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -18,17 +18,20 @@ #include "boards.h" #include "bitbang_i2c.h" #include "blockdev.h" +#include "exec-memory.h" #define SMP_BOOT_ADDR 0xe0000000 typedef struct { SysBusDevice busdev; + MemoryRegion iomem; bitbang_i2c_interface *bitbang; int out; int in; } RealViewI2CState; -static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset) +static uint64_t realview_i2c_read(void *opaque, target_phys_addr_t offset, + unsigned size) { RealViewI2CState *s = (RealViewI2CState *)opaque; @@ -41,7 +44,7 @@ static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset) } static void realview_i2c_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { RealViewI2CState *s = (RealViewI2CState *)opaque; @@ -59,30 +62,22 @@ static void realview_i2c_write(void *opaque, target_phys_addr_t offset, s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0); } -static CPUReadMemoryFunc * const realview_i2c_readfn[] = { - realview_i2c_read, - realview_i2c_read, - realview_i2c_read -}; - -static CPUWriteMemoryFunc * const realview_i2c_writefn[] = { - realview_i2c_write, - realview_i2c_write, - realview_i2c_write +static const MemoryRegionOps realview_i2c_ops = { + .read = realview_i2c_read, + .write = realview_i2c_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int realview_i2c_init(SysBusDevice *dev) { RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev); i2c_bus *bus; - int iomemtype; bus = i2c_init_bus(&dev->qdev, "i2c"); s->bitbang = bitbang_i2c_init(bus); - iomemtype = cpu_register_io_memory(realview_i2c_readfn, - realview_i2c_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x1000, iomemtype); + memory_region_init_io(&s->iomem, &realview_i2c_ops, s, + "realview-i2c", 0x1000); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -125,7 +120,11 @@ static void realview_init(ram_addr_t ram_size, enum realview_board_type board_type) { CPUState *env = NULL; - ram_addr_t ram_offset; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram_lo = g_new(MemoryRegion, 1); + MemoryRegion *ram_hi = g_new(MemoryRegion, 1); + MemoryRegion *ram_alias = g_new(MemoryRegion, 1); + MemoryRegion *ram_hack = g_new(MemoryRegion, 1); DeviceState *dev, *sysctl, *gpio2; SysBusDevice *busdev; qemu_irq *irqp; @@ -184,21 +183,21 @@ static void realview_init(ram_addr_t ram_size, /* Core tile RAM. */ low_ram_size = ram_size - 0x20000000; ram_size = 0x20000000; - ram_offset = qemu_ram_alloc(NULL, "realview.lowmem", low_ram_size); - cpu_register_physical_memory(0x20000000, low_ram_size, - ram_offset | IO_MEM_RAM); + memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size); + memory_region_add_subregion(sysmem, 0x20000000, ram_lo); } - ram_offset = qemu_ram_alloc(NULL, "realview.highmem", ram_size); + memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size); low_ram_size = ram_size; if (low_ram_size > 0x10000000) low_ram_size = 0x10000000; /* SDRAM at address zero. */ - cpu_register_physical_memory(0, low_ram_size, ram_offset | IO_MEM_RAM); + memory_region_init_alias(ram_alias, "realview.alias", + ram_hi, 0, low_ram_size); + memory_region_add_subregion(sysmem, 0, ram_alias); if (is_pb) { /* And again at a high address. */ - cpu_register_physical_memory(0x70000000, ram_size, - ram_offset | IO_MEM_RAM); + memory_region_add_subregion(sysmem, 0x70000000, ram_hi); } else { ram_size = low_ram_size; } @@ -372,9 +371,8 @@ static void realview_init(ram_addr_t ram_size, startup code. I guess this works on real hardware because the BootROM happens to be in ROM/flash or in memory that isn't clobbered until after Linux boots the secondary CPUs. */ - ram_offset = qemu_ram_alloc(NULL, "realview.hack", 0x1000); - cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000, - ram_offset | IO_MEM_RAM); + memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000); + memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); realview_binfo.ram_size = ram_size; realview_binfo.kernel_filename = kernel_filename; diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 778cffe39c..60c66e92c4 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -29,6 +29,7 @@ #include "hw/virtio.h" #include "hw/sysbus.h" #include "kvm.h" +#include "exec-memory.h" #include "hw/s390-virtio-bus.h" @@ -128,7 +129,8 @@ static void s390_init(ram_addr_t my_ram_size, const char *cpu_model) { CPUState *env = NULL; - ram_addr_t ram_addr; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); ram_addr_t kernel_size = 0; ram_addr_t initrd_offset; ram_addr_t initrd_size = 0; @@ -150,8 +152,8 @@ static void s390_init(ram_addr_t my_ram_size, s390_bus = s390_virtio_bus_init(&my_ram_size); /* allocate RAM */ - ram_addr = qemu_ram_alloc(NULL, "s390.ram", my_ram_size); - cpu_register_physical_memory(0, my_ram_size, ram_addr); + memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size); + memory_region_add_subregion(sysmem, 0, ram); /* allocate storage keys */ storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE); diff --git a/hw/sm501.c b/hw/sm501.c index a7ed6fadf1..297bc9c318 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -459,7 +459,7 @@ typedef struct SM501State { target_phys_addr_t base; uint32_t local_mem_size_index; uint8_t * local_mem; - ram_addr_t local_mem_offset; + MemoryRegion local_mem_region; uint32_t last_width; uint32_t last_height; @@ -726,7 +726,8 @@ static void sm501_2d_operation(SM501State * s) } } -static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr) +static uint64_t sm501_system_config_read(void *opaque, target_phys_addr_t addr, + unsigned size) { SM501State * s = (SM501State *)opaque; uint32_t ret = 0; @@ -778,12 +779,12 @@ static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr) return ret; } -static void sm501_system_config_write(void *opaque, - target_phys_addr_t addr, uint32_t value) +static void sm501_system_config_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { SM501State * s = (SM501State *)opaque; SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n", - addr, value); + (uint32_t)addr, (uint32_t)value); switch(addr) { case SM501_SYSTEM_CONTROL: @@ -821,21 +822,19 @@ static void sm501_system_config_write(void *opaque, default: printf("sm501 system config : not implemented register write." - " addr=%x, val=%x\n", (int)addr, value); + " addr=%x, val=%x\n", (int)addr, (uint32_t)value); abort(); } } -static CPUReadMemoryFunc * const sm501_system_config_readfn[] = { - NULL, - NULL, - &sm501_system_config_read, -}; - -static CPUWriteMemoryFunc * const sm501_system_config_writefn[] = { - NULL, - NULL, - &sm501_system_config_write, +static const MemoryRegionOps sm501_system_config_ops = { + .read = sm501_system_config_read, + .write = sm501_system_config_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, }; static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr) @@ -864,7 +863,8 @@ static void sm501_palette_write(void *opaque, *(uint32_t*)&s->dc_palette[addr] = value; } -static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr) +static uint64_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr, + unsigned size) { SM501State * s = (SM501State *)opaque; uint32_t ret = 0; @@ -958,13 +958,12 @@ static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr) return ret; } -static void sm501_disp_ctrl_write(void *opaque, - target_phys_addr_t addr, - uint32_t value) +static void sm501_disp_ctrl_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { SM501State * s = (SM501State *)opaque; SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n", - addr, value); + (unsigned)addr, (unsigned)value); switch(addr) { case SM501_DC_PANEL_CONTROL: @@ -1059,24 +1058,23 @@ static void sm501_disp_ctrl_write(void *opaque, default: printf("sm501 disp ctrl : not implemented register write." - " addr=%x, val=%x\n", (int)addr, value); + " addr=%x, val=%x\n", (int)addr, (unsigned)value); abort(); } } -static CPUReadMemoryFunc * const sm501_disp_ctrl_readfn[] = { - NULL, - NULL, - &sm501_disp_ctrl_read, -}; - -static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = { - NULL, - NULL, - &sm501_disp_ctrl_write, +static const MemoryRegionOps sm501_disp_ctrl_ops = { + .read = sm501_disp_ctrl_read, + .write = sm501_disp_ctrl_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr) +static uint64_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr, + unsigned size) { SM501State * s = (SM501State *)opaque; uint32_t ret = 0; @@ -1095,12 +1093,12 @@ static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr) return ret; } -static void sm501_2d_engine_write(void *opaque, - target_phys_addr_t addr, uint32_t value) +static void sm501_2d_engine_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { SM501State * s = (SM501State *)opaque; SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n", - addr, value); + (unsigned)addr, (unsigned)value); switch(addr) { case SM501_2D_SOURCE: @@ -1148,21 +1146,19 @@ static void sm501_2d_engine_write(void *opaque, break; default: printf("sm501 2d engine : not implemented register write." - " addr=%x, val=%x\n", (int)addr, value); + " addr=%x, val=%x\n", (int)addr, (unsigned)value); abort(); } } -static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = { - NULL, - NULL, - &sm501_2d_engine_read, -}; - -static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = { - NULL, - NULL, - &sm501_2d_engine_write, +static const MemoryRegionOps sm501_2d_engine_ops = { + .read = sm501_2d_engine_read, + .write = sm501_2d_engine_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, }; /* draw line functions for all console modes */ @@ -1276,7 +1272,7 @@ static void sm501_draw_crt(SM501State * s) int y_start = -1; ram_addr_t page_min = ~0l; ram_addr_t page_max = 0l; - ram_addr_t offset = s->local_mem_offset; + ram_addr_t offset = 0; /* choose draw_line function */ switch (s->dc_crt_control & 3) { @@ -1333,7 +1329,8 @@ static void sm501_draw_crt(SM501State * s) /* check dirty flags for each line */ for (page = page0; page <= page1; page += TARGET_PAGE_SIZE) - if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) + if (memory_region_get_dirty(&s->local_mem_region, page, + DIRTY_MEMORY_VGA)) update = 1; /* draw line and change status */ @@ -1372,8 +1369,9 @@ static void sm501_draw_crt(SM501State * s) /* clear dirty flags */ if (page_min != ~0l) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); + memory_region_reset_dirty(&s->local_mem_region, + page_min, page_max + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); } } @@ -1390,9 +1388,9 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, { SM501State * s; DeviceState *dev; - int sm501_system_config_index; - int sm501_disp_ctrl_index; - int sm501_2d_engine_index; + MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1); + MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1); + MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1); /* allocate management data region */ s = (SM501State *)g_malloc0(sizeof(SM501State)); @@ -1407,27 +1405,26 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, s->dc_crt_control = 0x00010000; /* allocate local memory */ - s->local_mem_offset = qemu_ram_alloc(NULL, "sm501.local", local_mem_bytes); - s->local_mem = qemu_get_ram_ptr(s->local_mem_offset); - cpu_register_physical_memory(base, local_mem_bytes, s->local_mem_offset); + memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", + local_mem_bytes); + s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); + memory_region_add_subregion(address_space_mem, base, &s->local_mem_region); /* map mmio */ - sm501_system_config_index - = cpu_register_io_memory(sm501_system_config_readfn, - sm501_system_config_writefn, s, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base + MMIO_BASE_OFFSET, - 0x6c, sm501_system_config_index); - sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn, - sm501_disp_ctrl_writefn, s, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC, - 0x1000, sm501_disp_ctrl_index); - sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn, - sm501_2d_engine_writefn, s, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE, - 0x54, sm501_2d_engine_index); + memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s, + "sm501-system-config", 0x6c); + memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET, + sm501_system_config); + memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s, + "sm501-disp-ctrl", 0x1000); + memory_region_add_subregion(address_space_mem, + base + MMIO_BASE_OFFSET + SM501_DC, + sm501_disp_ctrl); + memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s, + "sm501-2d-engine", 0x54); + memory_region_add_subregion(address_space_mem, + base + MMIO_BASE_OFFSET + SM501_2D_ENGINE, + sm501_2d_engine); /* bridge to usb host emulation module */ dev = qdev_create(NULL, "sysbus-ohci"); diff --git a/hw/spapr.c b/hw/spapr.c index b1189755d3..63e5d336ea 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -41,6 +41,8 @@ #include "kvm.h" #include "kvm_ppc.h" +#include "exec-memory.h" + #include <libfdt.h> #define KERNEL_LOAD_ADDR 0x00000000 @@ -324,7 +326,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, { CPUState *env; int i; - ram_addr_t ram_offset; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); uint32_t initrd_base; long kernel_size, initrd_size, fw_size; long pteg_shift = 17; @@ -361,8 +364,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* allocate RAM */ spapr->ram_limit = ram_size; - ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", spapr->ram_limit); - cpu_register_physical_memory(0, ram_size, ram_offset); + memory_region_init_ram(ram, NULL, "ppc_spapr.ram", spapr->ram_limit); + memory_region_add_subregion(sysmem, 0, ram); /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest diff --git a/hw/spitz.c b/hw/spitz.c index 6f8a94ceb3..23f9d41ff7 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -49,6 +49,7 @@ typedef struct { SysBusDevice busdev; + MemoryRegion iomem; DeviceState *nand; uint8_t ctl; uint8_t manf_id; @@ -56,7 +57,7 @@ typedef struct { ECCState ecc; } SLNANDState; -static uint32_t sl_readb(void *opaque, target_phys_addr_t addr) +static uint64_t sl_read(void *opaque, target_phys_addr_t addr, unsigned size) { SLNANDState *s = (SLNANDState *) opaque; int ryby; @@ -86,6 +87,10 @@ static uint32_t sl_readb(void *opaque, target_phys_addr_t addr) return s->ctl; case FLASH_FLASHIO: + if (size == 4) { + return ecc_digest(&s->ecc, nand_getio(s->nand)) | + (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); + } return ecc_digest(&s->ecc, nand_getio(s->nand)); default: @@ -94,19 +99,8 @@ static uint32_t sl_readb(void *opaque, target_phys_addr_t addr) return 0; } -static uint32_t sl_readl(void *opaque, target_phys_addr_t addr) -{ - SLNANDState *s = (SLNANDState *) opaque; - - if (addr == FLASH_FLASHIO) - return ecc_digest(&s->ecc, nand_getio(s->nand)) | - (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); - - return sl_readb(opaque, addr); -} - -static void sl_writeb(void *opaque, target_phys_addr_t addr, - uint32_t value) +static void sl_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { SLNANDState *s = (SLNANDState *) opaque; @@ -140,15 +134,10 @@ enum { FLASH_1024M, }; -static CPUReadMemoryFunc * const sl_readfn[] = { - sl_readb, - sl_readb, - sl_readl, -}; -static CPUWriteMemoryFunc * const sl_writefn[] = { - sl_writeb, - sl_writeb, - sl_writeb, +static const MemoryRegionOps sl_ops = { + .read = sl_read, + .write = sl_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void sl_flash_register(PXA2xxState *cpu, int size) @@ -168,7 +157,6 @@ static void sl_flash_register(PXA2xxState *cpu, int size) } static int sl_nand_init(SysBusDevice *dev) { - int iomemtype; SLNANDState *s; DriveInfo *nand; @@ -178,10 +166,8 @@ static int sl_nand_init(SysBusDevice *dev) { nand = drive_get(IF_MTD, 0, 0); s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id); - iomemtype = cpu_register_io_memory(sl_readfn, - sl_writefn, s, DEVICE_NATIVE_ENDIAN); - - sysbus_init_mmio(dev, 0x40, iomemtype); + memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -898,6 +884,7 @@ static void spitz_common_init(ram_addr_t ram_size, PXA2xxState *cpu; DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *rom = g_new(MemoryRegion, 1); if (!cpu_model) cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; @@ -907,8 +894,9 @@ static void spitz_common_init(ram_addr_t ram_size, sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M); - cpu_register_physical_memory(0, SPITZ_ROM, - qemu_ram_alloc(NULL, "spitz.rom", SPITZ_ROM) | IO_MEM_ROM); + memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM); + memory_region_set_readonly(rom, true); + memory_region_add_subregion(address_space_mem, 0, rom); /* Setup peripherals */ spitz_keyboard_register(cpu); diff --git a/hw/strongarm.c b/hw/strongarm.c index 6097ea2c18..a3d908051f 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -68,6 +68,7 @@ static struct { /* Interrupt Controller */ typedef struct { SysBusDevice busdev; + MemoryRegion iomem; qemu_irq irq; qemu_irq fiq; @@ -109,7 +110,8 @@ static void strongarm_pic_set_irq(void *opaque, int irq, int level) strongarm_pic_update(s); } -static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset) +static uint64_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset, + unsigned size) { StrongARMPICState *s = opaque; @@ -134,7 +136,7 @@ static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset) } static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { StrongARMPICState *s = opaque; @@ -156,27 +158,19 @@ static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset, strongarm_pic_update(s); } -static CPUReadMemoryFunc * const strongarm_pic_readfn[] = { - strongarm_pic_mem_read, - strongarm_pic_mem_read, - strongarm_pic_mem_read, -}; - -static CPUWriteMemoryFunc * const strongarm_pic_writefn[] = { - strongarm_pic_mem_write, - strongarm_pic_mem_write, - strongarm_pic_mem_write, +static const MemoryRegionOps strongarm_pic_ops = { + .read = strongarm_pic_mem_read, + .write = strongarm_pic_mem_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int strongarm_pic_initfn(SysBusDevice *dev) { StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev); - int iomemtype; qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS); - iomemtype = cpu_register_io_memory(strongarm_pic_readfn, - strongarm_pic_writefn, s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x1000, iomemtype); + memory_region_init_io(&s->iomem, &strongarm_pic_ops, s, "pic", 0x1000); + sysbus_init_mmio_region(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); sysbus_init_irq(dev, &s->fiq); @@ -229,6 +223,7 @@ static SysBusDeviceInfo strongarm_pic_info = { typedef struct { SysBusDevice busdev; + MemoryRegion iomem; uint32_t rttr; uint32_t rtsr; uint32_t rtar; @@ -287,7 +282,8 @@ static inline void strongarm_rtc_hz_tick(void *opaque) strongarm_rtc_int_update(s); } -static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr) +static uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr, + unsigned size) { StrongARMRTCState *s = opaque; @@ -309,7 +305,7 @@ static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr) } static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { StrongARMRTCState *s = opaque; uint32_t old_rtsr; @@ -349,23 +345,16 @@ static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const strongarm_rtc_readfn[] = { - strongarm_rtc_read, - strongarm_rtc_read, - strongarm_rtc_read, -}; - -static CPUWriteMemoryFunc * const strongarm_rtc_writefn[] = { - strongarm_rtc_write, - strongarm_rtc_write, - strongarm_rtc_write, +static const MemoryRegionOps strongarm_rtc_ops = { + .read = strongarm_rtc_read, + .write = strongarm_rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int strongarm_rtc_init(SysBusDevice *dev) { StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev); struct tm tm; - int iomemtype; s->rttr = 0x0; s->rtsr = 0; @@ -381,9 +370,8 @@ static int strongarm_rtc_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->rtc_irq); sysbus_init_irq(dev, &s->rtc_hz_irq); - iomemtype = cpu_register_io_memory(strongarm_rtc_readfn, - strongarm_rtc_writefn, s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x10000, iomemtype); + memory_region_init_io(&s->iomem, &strongarm_rtc_ops, s, "rtc", 0x10000); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -443,6 +431,7 @@ static SysBusDeviceInfo strongarm_rtc_sysbus_info = { typedef struct StrongARMGPIOInfo StrongARMGPIOInfo; struct StrongARMGPIOInfo { SysBusDevice busdev; + MemoryRegion iomem; qemu_irq handler[28]; qemu_irq irqs[11]; qemu_irq irqX; @@ -507,7 +496,8 @@ static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s) s->prev_level = level; } -static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset) +static uint64_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset, + unsigned size) { StrongARMGPIOInfo *s = opaque; @@ -548,8 +538,8 @@ static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset) return 0; } -static void strongarm_gpio_write(void *opaque, - target_phys_addr_t offset, uint32_t value) +static void strongarm_gpio_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) { StrongARMGPIOInfo *s = opaque; @@ -592,16 +582,10 @@ static void strongarm_gpio_write(void *opaque, } } -static CPUReadMemoryFunc * const strongarm_gpio_readfn[] = { - strongarm_gpio_read, - strongarm_gpio_read, - strongarm_gpio_read -}; - -static CPUWriteMemoryFunc * const strongarm_gpio_writefn[] = { - strongarm_gpio_write, - strongarm_gpio_write, - strongarm_gpio_write +static const MemoryRegionOps strongarm_gpio_ops = { + .read = strongarm_gpio_read, + .write = strongarm_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static DeviceState *strongarm_gpio_init(target_phys_addr_t base, @@ -623,7 +607,6 @@ static DeviceState *strongarm_gpio_init(target_phys_addr_t base, static int strongarm_gpio_initfn(SysBusDevice *dev) { - int iomemtype; StrongARMGPIOInfo *s; int i; @@ -632,10 +615,9 @@ static int strongarm_gpio_initfn(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28); qdev_init_gpio_out(&dev->qdev, s->handler, 28); - iomemtype = cpu_register_io_memory(strongarm_gpio_readfn, - strongarm_gpio_writefn, s, DEVICE_NATIVE_ENDIAN); + memory_region_init_io(&s->iomem, &strongarm_gpio_ops, s, "gpio", 0x1000); - sysbus_init_mmio(dev, 0x1000, iomemtype); + sysbus_init_mmio_region(dev, &s->iomem); for (i = 0; i < 11; i++) { sysbus_init_irq(dev, &s->irqs[i]); } @@ -678,6 +660,7 @@ static SysBusDeviceInfo strongarm_gpio_info = { typedef struct StrongARMPPCInfo StrongARMPPCInfo; struct StrongARMPPCInfo { SysBusDevice busdev; + MemoryRegion iomem; qemu_irq handler[28]; uint32_t ilevel; @@ -716,7 +699,8 @@ static void strongarm_ppc_handler_update(StrongARMPPCInfo *s) s->prev_level = level; } -static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset) +static uint64_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset, + unsigned size) { StrongARMPPCInfo *s = opaque; @@ -745,8 +729,8 @@ static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset) return 0; } -static void strongarm_ppc_write(void *opaque, - target_phys_addr_t offset, uint32_t value) +static void strongarm_ppc_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) { StrongARMPPCInfo *s = opaque; @@ -778,21 +762,14 @@ static void strongarm_ppc_write(void *opaque, } } -static CPUReadMemoryFunc * const strongarm_ppc_readfn[] = { - strongarm_ppc_read, - strongarm_ppc_read, - strongarm_ppc_read -}; - -static CPUWriteMemoryFunc * const strongarm_ppc_writefn[] = { - strongarm_ppc_write, - strongarm_ppc_write, - strongarm_ppc_write +static const MemoryRegionOps strongarm_ppc_ops = { + .read = strongarm_ppc_read, + .write = strongarm_ppc_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int strongarm_ppc_init(SysBusDevice *dev) { - int iomemtype; StrongARMPPCInfo *s; s = FROM_SYSBUS(StrongARMPPCInfo, dev); @@ -800,10 +777,9 @@ static int strongarm_ppc_init(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22); qdev_init_gpio_out(&dev->qdev, s->handler, 22); - iomemtype = cpu_register_io_memory(strongarm_ppc_readfn, - strongarm_ppc_writefn, s, DEVICE_NATIVE_ENDIAN); + memory_region_init_io(&s->iomem, &strongarm_ppc_ops, s, "ppc", 0x1000); - sysbus_init_mmio(dev, 0x1000, iomemtype); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -871,6 +847,7 @@ static SysBusDeviceInfo strongarm_ppc_info = { typedef struct { SysBusDevice busdev; + MemoryRegion iomem; CharDriverState *chr; qemu_irq irq; @@ -1079,7 +1056,8 @@ static void strongarm_uart_tx(void *opaque) strongarm_uart_update_int_status(s); } -static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr) +static uint64_t strongarm_uart_read(void *opaque, target_phys_addr_t addr, + unsigned size) { StrongARMUARTState *s = opaque; uint16_t ret; @@ -1121,7 +1099,7 @@ static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr) } static void strongarm_uart_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { StrongARMUARTState *s = opaque; @@ -1176,26 +1154,18 @@ static void strongarm_uart_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const strongarm_uart_readfn[] = { - strongarm_uart_read, - strongarm_uart_read, - strongarm_uart_read, -}; - -static CPUWriteMemoryFunc * const strongarm_uart_writefn[] = { - strongarm_uart_write, - strongarm_uart_write, - strongarm_uart_write, +static const MemoryRegionOps strongarm_uart_ops = { + .read = strongarm_uart_read, + .write = strongarm_uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int strongarm_uart_init(SysBusDevice *dev) { StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); - int iomemtype; - iomemtype = cpu_register_io_memory(strongarm_uart_readfn, - strongarm_uart_writefn, s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x10000, iomemtype); + memory_region_init_io(&s->iomem, &strongarm_uart_ops, s, "uart", 0x10000); + sysbus_init_mmio_region(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s); @@ -1288,6 +1258,7 @@ static SysBusDeviceInfo strongarm_uart_info = { /* Synchronous Serial Ports */ typedef struct { SysBusDevice busdev; + MemoryRegion iomem; qemu_irq irq; SSIBus *bus; @@ -1355,7 +1326,8 @@ static void strongarm_ssp_fifo_update(StrongARMSSPState *s) strongarm_ssp_int_update(s); } -static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr) +static uint64_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr, + unsigned size) { StrongARMSSPState *s = opaque; uint32_t retval; @@ -1388,7 +1360,7 @@ static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr) } static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { StrongARMSSPState *s = opaque; @@ -1397,7 +1369,7 @@ static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr, s->sscr[0] = value & 0xffbf; if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) { printf("%s: Wrong data size: %i bits\n", __func__, - SSCR0_DSS(value)); + (int)SSCR0_DSS(value)); } if (!(value & SSCR0_SSE)) { s->sssr = 0; @@ -1452,16 +1424,10 @@ static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const strongarm_ssp_readfn[] = { - strongarm_ssp_read, - strongarm_ssp_read, - strongarm_ssp_read, -}; - -static CPUWriteMemoryFunc * const strongarm_ssp_writefn[] = { - strongarm_ssp_write, - strongarm_ssp_write, - strongarm_ssp_write, +static const MemoryRegionOps strongarm_ssp_ops = { + .read = strongarm_ssp_read, + .write = strongarm_ssp_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int strongarm_ssp_post_load(void *opaque, int version_id) @@ -1475,15 +1441,12 @@ static int strongarm_ssp_post_load(void *opaque, int version_id) static int strongarm_ssp_init(SysBusDevice *dev) { - int iomemtype; StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev); sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(strongarm_ssp_readfn, - strongarm_ssp_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, 0x1000, iomemtype); + memory_region_init_io(&s->iomem, &strongarm_ssp_ops, s, "ssp", 0x1000); + sysbus_init_mmio_region(dev, &s->iomem); s->bus = ssi_create_bus(&dev->qdev, "ssi"); return 0; @@ -1523,7 +1486,8 @@ static SysBusDeviceInfo strongarm_ssp_info = { }; /* Main CPU functions */ -StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev) +StrongARMState *sa1110_init(MemoryRegion *sysmem, + unsigned int sdram_size, const char *rev) { StrongARMState *s; qemu_irq *pic; @@ -1547,9 +1511,8 @@ StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev) exit(1); } - cpu_register_physical_memory(SA_SDCS0, - sdram_size, qemu_ram_alloc(NULL, "strongarm.sdram", - sdram_size) | IO_MEM_RAM); + memory_region_init_ram(&s->sdram, NULL, "strongarm.sdram", sdram_size); + memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram); pic = arm_pic_init_cpu(s->env); s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, diff --git a/hw/strongarm.h b/hw/strongarm.h index a81b110e23..684f61bee3 100644 --- a/hw/strongarm.h +++ b/hw/strongarm.h @@ -1,6 +1,8 @@ #ifndef _STRONGARM_H #define _STRONGARM_H +#include "memory.h" + #define SA_CS0 0x00000000 #define SA_CS1 0x08000000 #define SA_CS2 0x10000000 @@ -52,6 +54,7 @@ enum { typedef struct { CPUState *env; + MemoryRegion sdram; DeviceState *pic; DeviceState *gpio; DeviceState *ppc; @@ -59,6 +62,7 @@ typedef struct { SSIBus *ssp_bus; } StrongARMState; -StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev); +StrongARMState *sa1110_init(MemoryRegion *sysmem, + unsigned int sdram_size, const char *rev); #endif diff --git a/hw/sun4m.c b/hw/sun4m.c index 71bf648e69..314edc4d87 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -593,19 +593,25 @@ static void idreg_init(target_phys_addr_t addr) cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data)); } +typedef struct IDRegState { + SysBusDevice busdev; + MemoryRegion mem; +} IDRegState; + static int idreg_init1(SysBusDevice *dev) { - ram_addr_t idreg_offset; + IDRegState *s = FROM_SYSBUS(IDRegState, dev); - idreg_offset = qemu_ram_alloc(NULL, "sun4m.idreg", sizeof(idreg_data)); - sysbus_init_mmio(dev, sizeof(idreg_data), idreg_offset | IO_MEM_ROM); + memory_region_init_ram(&s->mem, NULL, "sun4m.idreg", sizeof(idreg_data)); + memory_region_set_readonly(&s->mem, true); + sysbus_init_mmio_region(dev, &s->mem); return 0; } static SysBusDeviceInfo idreg_info = { .init = idreg_init1, .qdev.name = "macio_idreg", - .qdev.size = sizeof(SysBusDevice), + .qdev.size = sizeof(IDRegState), }; static void idreg_register_devices(void) @@ -615,6 +621,11 @@ static void idreg_register_devices(void) device_init(idreg_register_devices); +typedef struct AFXState { + SysBusDevice busdev; + MemoryRegion mem; +} AFXState; + /* SS-5 TCX AFX register */ static void afx_init(target_phys_addr_t addr) { @@ -630,17 +641,17 @@ static void afx_init(target_phys_addr_t addr) static int afx_init1(SysBusDevice *dev) { - ram_addr_t afx_offset; + AFXState *s = FROM_SYSBUS(AFXState, dev); - afx_offset = qemu_ram_alloc(NULL, "sun4m.afx", 4); - sysbus_init_mmio(dev, 4, afx_offset | IO_MEM_RAM); + memory_region_init_ram(&s->mem, NULL, "sun4m.afx", 4); + sysbus_init_mmio_region(dev, &s->mem); return 0; } static SysBusDeviceInfo afx_info = { .init = afx_init1, .qdev.name = "tcx_afx", - .qdev.size = sizeof(SysBusDevice), + .qdev.size = sizeof(AFXState), }; static void afx_register_devices(void) @@ -650,6 +661,11 @@ static void afx_register_devices(void) device_init(afx_register_devices); +typedef struct PROMState { + SysBusDevice busdev; + MemoryRegion prom; +} PROMState; + /* Boot PROM (OpenBIOS) */ static uint64_t translate_prom_address(void *opaque, uint64_t addr) { @@ -693,17 +709,18 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name) static int prom_init1(SysBusDevice *dev) { - ram_addr_t prom_offset; + PROMState *s = FROM_SYSBUS(PROMState, dev); - prom_offset = qemu_ram_alloc(NULL, "sun4m.prom", PROM_SIZE_MAX); - sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM); + memory_region_init_ram(&s->prom, NULL, "sun4m.prom", PROM_SIZE_MAX); + memory_region_set_readonly(&s->prom, true); + sysbus_init_mmio_region(dev, &s->prom); return 0; } static SysBusDeviceInfo prom_info = { .init = prom_init1, .qdev.name = "openprom", - .qdev.size = sizeof(SysBusDevice), + .qdev.size = sizeof(PROMState), .qdev.props = (Property[]) { {/* end of property list */} } @@ -719,19 +736,17 @@ device_init(prom_register_devices); typedef struct RamDevice { SysBusDevice busdev; + MemoryRegion ram; uint64_t size; } RamDevice; /* System RAM */ static int ram_init1(SysBusDevice *dev) { - ram_addr_t RAM_size, ram_offset; RamDevice *d = FROM_SYSBUS(RamDevice, dev); - RAM_size = d->size; - - ram_offset = qemu_ram_alloc(NULL, "sun4m.ram", RAM_size); - sysbus_init_mmio(dev, RAM_size, ram_offset); + memory_region_init_ram(&d->ram, NULL, "sun4m.ram", d->size); + sysbus_init_mmio_region(dev, &d->ram); return 0; } diff --git a/hw/sun4u.c b/hw/sun4u.c index 96fc3d0488..eaaefe3c94 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -574,6 +574,11 @@ static void pci_ebus_register(void) device_init(pci_ebus_register); +typedef struct PROMState { + SysBusDevice busdev; + MemoryRegion prom; +} PROMState; + static uint64_t translate_prom_address(void *opaque, uint64_t addr) { target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque; @@ -617,17 +622,18 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name) static int prom_init1(SysBusDevice *dev) { - ram_addr_t prom_offset; + PROMState *s = FROM_SYSBUS(PROMState, dev); - prom_offset = qemu_ram_alloc(NULL, "sun4u.prom", PROM_SIZE_MAX); - sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM); + memory_region_init_ram(&s->prom, NULL, "sun4u.prom", PROM_SIZE_MAX); + memory_region_set_readonly(&s->prom, true); + sysbus_init_mmio_region(dev, &s->prom); return 0; } static SysBusDeviceInfo prom_info = { .init = prom_init1, .qdev.name = "openprom", - .qdev.size = sizeof(SysBusDevice), + .qdev.size = sizeof(PROMState), .qdev.props = (Property[]) { {/* end of property list */} } @@ -644,19 +650,17 @@ device_init(prom_register_devices); typedef struct RamDevice { SysBusDevice busdev; + MemoryRegion ram; uint64_t size; } RamDevice; /* System RAM */ static int ram_init1(SysBusDevice *dev) { - ram_addr_t RAM_size, ram_offset; RamDevice *d = FROM_SYSBUS(RamDevice, dev); - RAM_size = d->size; - - ram_offset = qemu_ram_alloc(NULL, "sun4u.ram", RAM_size); - sysbus_init_mmio(dev, RAM_size, ram_offset); + memory_region_init_ram(&d->ram, NULL, "sun4u.ram", d->size); + sysbus_init_mmio_region(dev, &d->ram); return 0; } diff --git a/hw/syborg.c b/hw/syborg.c index bc200e48aa..248de54c4e 100644 --- a/hw/syborg.c +++ b/hw/syborg.c @@ -26,6 +26,7 @@ #include "boards.h" #include "arm-misc.h" #include "net.h" +#include "exec-memory.h" static struct arm_boot_info syborg_binfo; @@ -35,9 +36,10 @@ static void syborg_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { CPUState *env; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); qemu_irq *cpu_pic; qemu_irq pic[64]; - ram_addr_t ram_addr; DeviceState *dev; int i; @@ -50,8 +52,8 @@ static void syborg_init(ram_addr_t ram_size, } /* RAM at address zero. */ - ram_addr = qemu_ram_alloc(NULL, "syborg.ram", ram_size); - cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM); + memory_region_init_ram(ram, NULL, "syborg.ram", ram_size); + memory_region_add_subregion(sysmem, 0, ram); cpu_pic = arm_pic_init_cpu(env); dev = sysbus_create_simple("syborg,interrupt", 0xC0000000, diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index c28005a86b..c144dcf5ff 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -79,6 +79,7 @@ #define NAND_MODE_ECC_RST 0x60 struct TC6393xbState { + MemoryRegion iomem; qemu_irq irq; qemu_irq *sub_irqs; struct { @@ -122,7 +123,7 @@ struct TC6393xbState { ECCState ecc; DisplayState *ds; - ram_addr_t vram_addr; + MemoryRegion vram; uint16_t *vram_ptr; uint32_t scr_width, scr_height; /* in pixels */ qemu_irq l3v; @@ -495,7 +496,9 @@ static void tc6393xb_update_display(void *opaque) } -static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) { +static uint64_t tc6393xb_readb(void *opaque, target_phys_addr_t addr, + unsigned size) +{ TC6393xbState *s = opaque; switch (addr >> 8) { @@ -516,7 +519,8 @@ static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) { return 0; } -static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { +static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { TC6393xbState *s = opaque; switch (addr >> 8) { @@ -532,51 +536,21 @@ static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t valu tc6393xb_nand_writeb(s, addr & 0xff, value); else fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n", - (uint32_t) addr, value & 0xff); -} - -static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr) -{ - return (tc6393xb_readb(opaque, addr) & 0xff) | - (tc6393xb_readb(opaque, addr + 1) << 8); -} - -static uint32_t tc6393xb_readl(void *opaque, target_phys_addr_t addr) -{ - return (tc6393xb_readb(opaque, addr) & 0xff) | - ((tc6393xb_readb(opaque, addr + 1) & 0xff) << 8) | - ((tc6393xb_readb(opaque, addr + 2) & 0xff) << 16) | - ((tc6393xb_readb(opaque, addr + 3) & 0xff) << 24); + (uint32_t) addr, (int)value & 0xff); } -static void tc6393xb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) +TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) { - tc6393xb_writeb(opaque, addr, value); - tc6393xb_writeb(opaque, addr + 1, value >> 8); -} - -static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t value) -{ - tc6393xb_writeb(opaque, addr, value); - tc6393xb_writeb(opaque, addr + 1, value >> 8); - tc6393xb_writeb(opaque, addr + 2, value >> 16); - tc6393xb_writeb(opaque, addr + 3, value >> 24); -} - -TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq) -{ - int iomemtype; TC6393xbState *s; DriveInfo *nand; - CPUReadMemoryFunc * const tc6393xb_readfn[] = { - tc6393xb_readb, - tc6393xb_readw, - tc6393xb_readl, - }; - CPUWriteMemoryFunc * const tc6393xb_writefn[] = { - tc6393xb_writeb, - tc6393xb_writew, - tc6393xb_writel, + static const MemoryRegionOps tc6393xb_ops = { + .read = tc6393xb_readb, + .write = tc6393xb_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, }; s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState)); @@ -591,13 +565,12 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq) nand = drive_get(IF_MTD, 0, 0); s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76); - iomemtype = cpu_register_io_memory(tc6393xb_readfn, - tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x10000, iomemtype); + memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000); + memory_region_add_subregion(sysmem, base, &s->iomem); - s->vram_addr = qemu_ram_alloc(NULL, "tc6393xb.vram", 0x100000); - s->vram_ptr = qemu_get_ram_ptr(s->vram_addr); - cpu_register_physical_memory(base + 0x100000, 0x100000, s->vram_addr); + memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000); + s->vram_ptr = memory_region_get_ram_ptr(&s->vram); + memory_region_add_subregion(sysmem, base + 0x100000, &s->vram); s->scr_width = 480; s->scr_height = 640; s->ds = graphic_console_init(tc6393xb_update_display, @@ -40,7 +40,15 @@ typedef struct TCXState { DisplayState *ds; uint8_t *vram; uint32_t *vram24, *cplane; - ram_addr_t vram_offset, vram24_offset, cplane_offset; + MemoryRegion vram_mem; + MemoryRegion vram_8bit; + MemoryRegion vram_24bit; + MemoryRegion vram_cplane; + MemoryRegion dac; + MemoryRegion tec; + MemoryRegion thc24; + MemoryRegion thc8; + ram_addr_t vram24_offset, cplane_offset; uint32_t vram_size; uint32_t palette[256]; uint8_t r[256], g[256], b[256]; @@ -56,7 +64,7 @@ static void tcx_set_dirty(TCXState *s) unsigned int i; for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) { - cpu_physical_memory_set_dirty(s->vram_offset + i); + memory_region_set_dirty(&s->vram_mem, i); } } @@ -65,8 +73,8 @@ static void tcx24_set_dirty(TCXState *s) unsigned int i; for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) { - cpu_physical_memory_set_dirty(s->vram24_offset + i); - cpu_physical_memory_set_dirty(s->cplane_offset + i); + memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i); + memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i); } } @@ -174,16 +182,18 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, } } -static inline int check_dirty(ram_addr_t page, ram_addr_t page24, +static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24, ram_addr_t cpage) { int ret; unsigned int off; - ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG); + ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA); for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) { - ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG); - ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG); + ret |= memory_region_get_dirty(&s->vram_mem, page24 + off, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, cpage + off, + DIRTY_MEMORY_VGA); } return ret; } @@ -192,16 +202,17 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, ram_addr_t page_max, ram_addr_t page24, ram_addr_t cpage) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); - page_min -= ts->vram_offset; - page_max -= ts->vram_offset; - cpu_physical_memory_reset_dirty(page24 + page_min * 4, - page24 + page_max * 4 + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); - cpu_physical_memory_reset_dirty(cpage + page_min * 4, - cpage + page_max * 4 + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); + memory_region_reset_dirty(&ts->vram_mem, + page_min, page_max + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + memory_region_reset_dirty(&ts->vram_mem, + page24 + page_min * 4, + page24 + page_max * 4 + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + memory_region_reset_dirty(&ts->vram_mem, + cpage + page_min * 4, + cpage + page_max * 4 + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); } /* Fixed line length 1024 allows us to do nice tricks not possible on @@ -216,7 +227,7 @@ static void tcx_update_display(void *opaque) if (ds_get_bits_per_pixel(ts->ds) == 0) return; - page = ts->vram_offset; + page = 0; y_start = -1; page_min = -1; page_max = 0; @@ -242,7 +253,7 @@ static void tcx_update_display(void *opaque) } for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { + if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -279,8 +290,9 @@ static void tcx_update_display(void *opaque) } /* reset modified pages */ if (page_max >= page_min) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); + memory_region_reset_dirty(&ts->vram_mem, + page_min, page_max + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); } } @@ -294,7 +306,7 @@ static void tcx24_update_display(void *opaque) if (ds_get_bits_per_pixel(ts->ds) != 32) return; - page = ts->vram_offset; + page = 0; page24 = ts->vram24_offset; cpage = ts->cplane_offset; y_start = -1; @@ -309,7 +321,7 @@ static void tcx24_update_display(void *opaque) for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { - if (check_dirty(page, page24, cpage)) { + if (check_dirty(ts, page, page24, cpage)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -421,18 +433,20 @@ static void tcx_reset(DeviceState *d) s->r[255] = s->g[255] = s->b[255] = 255; update_palette_entries(s, 0, 256); memset(s->vram, 0, MAXX*MAXY); - cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + - MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG); + memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), + DIRTY_MEMORY_VGA); s->dac_index = 0; s->dac_state = 0; } -static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr) +static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr, + unsigned size) { return 0; } -static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val, + unsigned size) { TCXState *s = opaque; @@ -468,77 +482,77 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) return; } -static CPUReadMemoryFunc * const tcx_dac_read[3] = { - NULL, - NULL, - tcx_dac_readl, +static const MemoryRegionOps tcx_dac_ops = { + .read = tcx_dac_readl, + .write = tcx_dac_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, }; -static CPUWriteMemoryFunc * const tcx_dac_write[3] = { - NULL, - NULL, - tcx_dac_writel, -}; - -static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr) +static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr, + unsigned size) { return 0; } -static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) +static void dummy_writel(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) { } -static CPUReadMemoryFunc * const tcx_dummy_read[3] = { - NULL, - NULL, - tcx_dummy_readl, -}; - -static CPUWriteMemoryFunc * const tcx_dummy_write[3] = { - NULL, - NULL, - tcx_dummy_writel, +static const MemoryRegionOps dummy_ops = { + .read = dummy_readl, + .write = dummy_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static int tcx_init1(SysBusDevice *dev) { TCXState *s = FROM_SYSBUS(TCXState, dev); - int io_memory, dummy_memory; - ram_addr_t vram_offset; + ram_addr_t vram_offset = 0; int size; uint8_t *vram_base; - vram_offset = qemu_ram_alloc(NULL, "tcx.vram", s->vram_size * (1 + 4 + 4)); - vram_base = qemu_get_ram_ptr(vram_offset); - s->vram_offset = vram_offset; + memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram", + s->vram_size * (1 + 4 + 4)); + vram_base = memory_region_get_ram_ptr(&s->vram_mem); /* 8-bit plane */ s->vram = vram_base; size = s->vram_size; - sysbus_init_mmio(dev, size, s->vram_offset); + memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio_region(dev, &s->vram_8bit); vram_offset += size; vram_base += size; /* DAC */ - io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory); + memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS); + sysbus_init_mmio_region(dev, &s->dac); /* TEC (dummy) */ - dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write, - s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory); + memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS); + sysbus_init_mmio_region(dev, &s->tec); /* THC: NetBSD writes here even with 8-bit display: dummy */ - sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory); + memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24", + TCX_THC_NREGS_24); + sysbus_init_mmio_region(dev, &s->thc24); if (s->depth == 24) { /* 24-bit plane */ size = s->vram_size * 4; s->vram24 = (uint32_t *)vram_base; s->vram24_offset = vram_offset; - sysbus_init_mmio(dev, size, vram_offset); + memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio_region(dev, &s->vram_24bit); vram_offset += size; vram_base += size; @@ -546,14 +560,18 @@ static int tcx_init1(SysBusDevice *dev) size = s->vram_size * 4; s->cplane = (uint32_t *)vram_base; s->cplane_offset = vram_offset; - sysbus_init_mmio(dev, size, vram_offset); + memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio_region(dev, &s->vram_cplane); s->ds = graphic_console_init(tcx24_update_display, tcx24_invalidate_display, tcx24_screen_dump, NULL, s); } else { /* THC 8 bit (dummy) */ - sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory); + memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8", + TCX_THC_NREGS_8); + sysbus_init_mmio_region(dev, &s->thc8); s->ds = graphic_console_init(tcx_update_display, tcx_invalidate_display, @@ -220,7 +220,7 @@ static void tosa_init(ram_addr_t ram_size, cpu_register_physical_memory(0, TOSA_ROM, qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM); - tmio = tc6393xb_init(0x10000000, + tmio = tc6393xb_init(address_space_mem, 0x10000000, qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT)); scp0 = sysbus_create_simple("scoop", 0x08800000, NULL); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index df27c198b0..ca5923c495 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -83,11 +83,6 @@ /* Flags track per-device state like workarounds for quirks in older guests. */ #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) -/* Performance improves when virtqueue kick processing is decoupled from the - * vcpu thread using ioeventfd for some devices. */ -#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1 -#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT) - /* QEMU doesn't strictly need write barriers since everything runs in * lock-step. We'll leave the calls to wmb() in though to make it obvious for * KVM or if kqemu gets SMP support. diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index 14c10f7d67..f8404de92b 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -18,6 +18,11 @@ #include "virtio-net.h" #include "virtio-serial.h" +/* Performance improves when virtqueue kick processing is decoupled from the + * vcpu thread using ioeventfd for some devices. */ +#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1 +#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT) + typedef struct { PCIDevice pci_dev; VirtIODevice *vdev; diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 8a9fac499b..286bbac54a 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -620,7 +620,7 @@ static void blk_alloc(struct XenDevice *xendev) static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int index, qflags, have_barriers, info = 0; + int index, qflags, info = 0; /* read xenstore entries */ if (blkdev->params == NULL) { @@ -706,7 +706,6 @@ static int blk_init(struct XenDevice *xendev) blkdev->bs->drv ? blkdev->bs->drv->format_name : "-"); blkdev->file_size = 0; } - have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0; xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\"," " size %" PRId64 " (%" PRId64 " MB)\n", @@ -714,7 +713,7 @@ static int blk_init(struct XenDevice *xendev) blkdev->file_size, blkdev->file_size >> 20); /* fill info */ - xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers); + xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1); xenstore_write_be_int(&blkdev->xendev, "info", info); xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk); xenstore_write_be_int(&blkdev->xendev, "sectors", diff --git a/iohandler.c b/iohandler.c index 4cc1c5ade6..5640d49388 100644 --- a/iohandler.c +++ b/iohandler.c @@ -26,6 +26,7 @@ #include "qemu-common.h" #include "qemu-char.h" #include "qemu-queue.h" +#include "main-loop.h" #ifndef _WIN32 #include <sys/wait.h> @@ -80,64 +81,12 @@ int qemu_set_fd_handler2(int fd, return 0; } -typedef struct IOTrampoline -{ - GIOChannel *chan; - IOHandler *fd_read; - IOHandler *fd_write; - void *opaque; - guint tag; -} IOTrampoline; - -static gboolean fd_trampoline(GIOChannel *chan, GIOCondition cond, gpointer opaque) -{ - IOTrampoline *tramp = opaque; - - if ((cond & G_IO_IN) && tramp->fd_read) { - tramp->fd_read(tramp->opaque); - } - - if ((cond & G_IO_OUT) && tramp->fd_write) { - tramp->fd_write(tramp->opaque); - } - - return TRUE; -} - int qemu_set_fd_handler(int fd, IOHandler *fd_read, IOHandler *fd_write, void *opaque) { - static IOTrampoline fd_trampolines[FD_SETSIZE]; - IOTrampoline *tramp = &fd_trampolines[fd]; - - if (tramp->tag != 0) { - g_io_channel_unref(tramp->chan); - g_source_remove(tramp->tag); - tramp->tag = 0; - } - - if (fd_read || fd_write || opaque) { - GIOCondition cond = 0; - - tramp->fd_read = fd_read; - tramp->fd_write = fd_write; - tramp->opaque = opaque; - - if (fd_read) { - cond |= G_IO_IN | G_IO_ERR; - } - - if (fd_write) { - cond |= G_IO_OUT | G_IO_ERR; - } - - tramp->chan = g_io_channel_unix_new(fd); - tramp->tag = g_io_add_watch(tramp->chan, cond, fd_trampoline, tramp); - } - - return 0; + return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); } void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) diff --git a/linux-user/main.c b/linux-user/main.c index 186358bd63..e7dad547b8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3084,6 +3084,7 @@ static void handle_arg_version(const char *arg) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"); + exit(0); } struct qemu_argument { @@ -3129,7 +3130,7 @@ struct qemu_argument arg_table[] = { {"strace", "QEMU_STRACE", false, handle_arg_strace, "", "log system calls"}, {"version", "QEMU_VERSION", false, handle_arg_version, - "", "log system calls"}, + "", "display version information and exit"}, {NULL, NULL, false, NULL, NULL, NULL} }; @@ -3231,16 +3232,15 @@ static int parse_args(int argc, char **argv) for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { if (!strcmp(r, arginfo->argv)) { - if (optind >= argc) { - usage(); - } - - arginfo->handle_opt(argv[optind]); - if (arginfo->has_arg) { + if (optind >= argc) { + usage(); + } + arginfo->handle_opt(argv[optind]); optind++; + } else { + arginfo->handle_opt(NULL); } - break; } } @@ -3276,9 +3276,6 @@ int main(int argc, char **argv, char **envp) int i; int ret; - if (argc <= 1) - usage(); - qemu_cache_utils_init(envp); if ((envlist = envlist_create()) == NULL) { diff --git a/main-loop.c b/main-loop.c new file mode 100644 index 0000000000..60e9748324 --- /dev/null +++ b/main-loop.c @@ -0,0 +1,475 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "slirp/slirp.h" +#include "main-loop.h" + +#ifndef _WIN32 + +#include "compatfd.h" + +static int io_thread_fd = -1; + +void qemu_notify_event(void) +{ + /* Write 8 bytes to be compatible with eventfd. */ + static const uint64_t val = 1; + ssize_t ret; + + if (io_thread_fd == -1) { + return; + } + do { + ret = write(io_thread_fd, &val, sizeof(val)); + } while (ret < 0 && errno == EINTR); + + /* EAGAIN is fine, a read must be pending. */ + if (ret < 0 && errno != EAGAIN) { + fprintf(stderr, "qemu_notify_event: write() failed: %s\n", + strerror(errno)); + exit(1); + } +} + +static void qemu_event_read(void *opaque) +{ + int fd = (intptr_t)opaque; + ssize_t len; + char buffer[512]; + + /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */ + do { + len = read(fd, buffer, sizeof(buffer)); + } while ((len == -1 && errno == EINTR) || len == sizeof(buffer)); +} + +static int qemu_event_init(void) +{ + int err; + int fds[2]; + + err = qemu_eventfd(fds); + if (err == -1) { + return -errno; + } + err = fcntl_setfl(fds[0], O_NONBLOCK); + if (err < 0) { + goto fail; + } + err = fcntl_setfl(fds[1], O_NONBLOCK); + if (err < 0) { + goto fail; + } + qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, + (void *)(intptr_t)fds[0]); + + io_thread_fd = fds[1]; + return 0; + +fail: + close(fds[0]); + close(fds[1]); + return err; +} + +/* If we have signalfd, we mask out the signals we want to handle and then + * use signalfd to listen for them. We rely on whatever the current signal + * handler is to dispatch the signals when we receive them. + */ +static void sigfd_handler(void *opaque) +{ + int fd = (intptr_t)opaque; + struct qemu_signalfd_siginfo info; + struct sigaction action; + ssize_t len; + + while (1) { + do { + len = read(fd, &info, sizeof(info)); + } while (len == -1 && errno == EINTR); + + if (len == -1 && errno == EAGAIN) { + break; + } + + if (len != sizeof(info)) { + printf("read from sigfd returned %zd: %m\n", len); + return; + } + + sigaction(info.ssi_signo, NULL, &action); + if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) { + action.sa_sigaction(info.ssi_signo, + (siginfo_t *)&info, NULL); + } else if (action.sa_handler) { + action.sa_handler(info.ssi_signo); + } + } +} + +static int qemu_signal_init(void) +{ + int sigfd; + sigset_t set; + + /* + * SIG_IPI must be blocked in the main thread and must not be caught + * by sigwait() in the signal thread. Otherwise, the cpu thread will + * not catch it reliably. + */ + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + sigemptyset(&set); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIGBUS); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + sigfd = qemu_signalfd(&set); + if (sigfd == -1) { + fprintf(stderr, "failed to create signalfd\n"); + return -errno; + } + + fcntl_setfl(sigfd, O_NONBLOCK); + + qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, + (void *)(intptr_t)sigfd); + + return 0; +} + +#else /* _WIN32 */ + +HANDLE qemu_event_handle; + +static void dummy_event_handler(void *opaque) +{ +} + +static int qemu_event_init(void) +{ + qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!qemu_event_handle) { + fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError()); + return -1; + } + qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL); + return 0; +} + +void qemu_notify_event(void) +{ + if (!SetEvent(qemu_event_handle)) { + fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n", + GetLastError()); + exit(1); + } +} + +static int qemu_signal_init(void) +{ + return 0; +} +#endif + +int qemu_init_main_loop(void) +{ + int ret; + + qemu_mutex_lock_iothread(); + ret = qemu_signal_init(); + if (ret) { + return ret; + } + + /* Note eventfd must be drained before signalfd handlers run */ + ret = qemu_event_init(); + if (ret) { + return ret; + } + + return 0; +} + + +static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ +static int n_poll_fds; +static int max_priority; + +static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds, + fd_set *xfds, struct timeval *tv) +{ + GMainContext *context = g_main_context_default(); + int i; + int timeout = 0, cur_timeout; + + g_main_context_prepare(context, &max_priority); + + n_poll_fds = g_main_context_query(context, max_priority, &timeout, + poll_fds, ARRAY_SIZE(poll_fds)); + g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds)); + + for (i = 0; i < n_poll_fds; i++) { + GPollFD *p = &poll_fds[i]; + + if ((p->events & G_IO_IN)) { + FD_SET(p->fd, rfds); + *max_fd = MAX(*max_fd, p->fd); + } + if ((p->events & G_IO_OUT)) { + FD_SET(p->fd, wfds); + *max_fd = MAX(*max_fd, p->fd); + } + if ((p->events & G_IO_ERR)) { + FD_SET(p->fd, xfds); + *max_fd = MAX(*max_fd, p->fd); + } + } + + cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000); + if (timeout >= 0 && timeout < cur_timeout) { + tv->tv_sec = timeout / 1000; + tv->tv_usec = (timeout % 1000) * 1000; + } +} + +static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds, + bool err) +{ + GMainContext *context = g_main_context_default(); + + if (!err) { + int i; + + for (i = 0; i < n_poll_fds; i++) { + GPollFD *p = &poll_fds[i]; + + if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) { + p->revents |= G_IO_IN; + } + if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) { + p->revents |= G_IO_OUT; + } + if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) { + p->revents |= G_IO_ERR; + } + } + } + + if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) { + g_main_context_dispatch(context); + } +} + +#ifdef _WIN32 +/***********************************************************/ +/* Polling handling */ + +typedef struct PollingEntry { + PollingFunc *func; + void *opaque; + struct PollingEntry *next; +} PollingEntry; + +static PollingEntry *first_polling_entry; + +int qemu_add_polling_cb(PollingFunc *func, void *opaque) +{ + PollingEntry **ppe, *pe; + pe = g_malloc0(sizeof(PollingEntry)); + pe->func = func; + pe->opaque = opaque; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); + *ppe = pe; + return 0; +} + +void qemu_del_polling_cb(PollingFunc *func, void *opaque) +{ + PollingEntry **ppe, *pe; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { + pe = *ppe; + if (pe->func == func && pe->opaque == opaque) { + *ppe = pe->next; + g_free(pe); + break; + } + } +} + +/***********************************************************/ +/* Wait objects support */ +typedef struct WaitObjects { + int num; + HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; + WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; + void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; +} WaitObjects; + +static WaitObjects wait_objects = {0}; + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + WaitObjects *w = &wait_objects; + if (w->num >= MAXIMUM_WAIT_OBJECTS) { + return -1; + } + w->events[w->num] = handle; + w->func[w->num] = func; + w->opaque[w->num] = opaque; + w->num++; + return 0; +} + +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + int i, found; + WaitObjects *w = &wait_objects; + + found = 0; + for (i = 0; i < w->num; i++) { + if (w->events[i] == handle) { + found = 1; + } + if (found) { + w->events[i] = w->events[i + 1]; + w->func[i] = w->func[i + 1]; + w->opaque[i] = w->opaque[i + 1]; + } + } + if (found) { + w->num--; + } +} + +static void os_host_main_loop_wait(int *timeout) +{ + int ret, ret2, i; + PollingEntry *pe; + + /* XXX: need to suppress polling by better using win32 events */ + ret = 0; + for (pe = first_polling_entry; pe != NULL; pe = pe->next) { + ret |= pe->func(pe->opaque); + } + if (ret == 0) { + int err; + WaitObjects *w = &wait_objects; + + qemu_mutex_unlock_iothread(); + ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout); + qemu_mutex_lock_iothread(); + if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { + if (w->func[ret - WAIT_OBJECT_0]) { + w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); + } + + /* Check for additional signaled events */ + for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { + /* Check if event is signaled */ + ret2 = WaitForSingleObject(w->events[i], 0); + if (ret2 == WAIT_OBJECT_0) { + if (w->func[i]) { + w->func[i](w->opaque[i]); + } + } else if (ret2 != WAIT_TIMEOUT) { + err = GetLastError(); + fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); + } + } + } else if (ret != WAIT_TIMEOUT) { + err = GetLastError(); + fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); + } + } + + *timeout = 0; +} +#else +static inline void os_host_main_loop_wait(int *timeout) +{ +} +#endif + +int main_loop_wait(int nonblocking) +{ + fd_set rfds, wfds, xfds; + int ret, nfds; + struct timeval tv; + int timeout; + + if (nonblocking) { + timeout = 0; + } else { + timeout = qemu_calculate_timeout(); + qemu_bh_update_timeout(&timeout); + } + + os_host_main_loop_wait(&timeout); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + /* poll any events */ + /* XXX: separate device handlers from system ones */ + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + +#ifdef CONFIG_SLIRP + slirp_select_fill(&nfds, &rfds, &wfds, &xfds); +#endif + qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds); + glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv); + + if (timeout > 0) { + qemu_mutex_unlock_iothread(); + } + + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + + if (timeout > 0) { + qemu_mutex_lock_iothread(); + } + + glib_select_poll(&rfds, &wfds, &xfds, (ret < 0)); + qemu_iohandler_poll(&rfds, &wfds, &xfds, ret); +#ifdef CONFIG_SLIRP + slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0)); +#endif + + qemu_run_all_timers(); + + /* Check bottom-halves last in case any of the earlier events triggered + them. */ + qemu_bh_poll(); + + return ret; +} diff --git a/main-loop.h b/main-loop.h new file mode 100644 index 0000000000..8a716b133f --- /dev/null +++ b/main-loop.h @@ -0,0 +1,351 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 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. + */ + +#ifndef QEMU_MAIN_LOOP_H +#define QEMU_MAIN_LOOP_H 1 + +#ifdef SIGRTMIN +#define SIG_IPI (SIGRTMIN+4) +#else +#define SIG_IPI SIGUSR1 +#endif + +/** + * qemu_init_main_loop: Set up the process so that it can run the main loop. + * + * This includes setting up signal handlers. It should be called before + * any other threads are created. In addition, threads other than the + * main one should block signals that are trapped by the main loop. + * For simplicity, you can consider these signals to be safe: SIGUSR1, + * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time + * signals if available. Remember that Windows in practice does not have + * signals, though. + */ +int qemu_init_main_loop(void); + +/** + * main_loop_wait: Run one iteration of the main loop. + * + * If @nonblocking is true, poll for events, otherwise suspend until + * one actually occurs. The main loop usually consists of a loop that + * repeatedly calls main_loop_wait(false). + * + * Main loop services include file descriptor callbacks, bottom halves + * and timers (defined in qemu-timer.h). Bottom halves are similar to timers + * that execute immediately, but have a lower overhead and scheduling them + * is wait-free, thread-safe and signal-safe. + * + * It is sometimes useful to put a whole program in a coroutine. In this + * case, the coroutine actually should be started from within the main loop, + * so that the main loop can run whenever the coroutine yields. To do this, + * you can use a bottom half to enter the coroutine as soon as the main loop + * starts: + * + * void enter_co_bh(void *opaque) { + * QEMUCoroutine *co = opaque; + * qemu_coroutine_enter(co, NULL); + * } + * + * ... + * QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry); + * QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co); + * qemu_bh_schedule(start_bh); + * while (...) { + * main_loop_wait(false); + * } + * + * (In the future we may provide a wrapper for this). + * + * @nonblocking: Whether the caller should block until an event occurs. + */ +int main_loop_wait(int nonblocking); + +/** + * qemu_notify_event: Force processing of pending events. + * + * Similar to signaling a condition variable, qemu_notify_event forces + * main_loop_wait to look at pending events and exit. The caller of + * main_loop_wait will usually call it again very soon, so qemu_notify_event + * also has the side effect of recalculating the sets of file descriptors + * that the main loop waits for. + * + * Calling qemu_notify_event is rarely necessary, because main loop + * services (bottom halves and timers) call it themselves. One notable + * exception occurs when using qemu_set_fd_handler2 (see below). + */ +void qemu_notify_event(void); + +#ifdef _WIN32 +/* return TRUE if no sleep should be done afterwards */ +typedef int PollingFunc(void *opaque); + +/** + * qemu_add_polling_cb: Register a Windows-specific polling callback + * + * Currently, under Windows some events are polled rather than waited for. + * Polling callbacks do not ensure that @func is called timely, because + * the main loop might wait for an arbitrarily long time. If possible, + * you should instead create a separate thread that does a blocking poll + * and set a Win32 event object. The event can then be passed to + * qemu_add_wait_object. + * + * Polling callbacks really have nothing Windows specific in them, but + * as they are a hack and are currenly not necessary under POSIX systems, + * they are only available when QEMU is running under Windows. + * + * @func: The function that does the polling, and returns 1 to force + * immediate completion of main_loop_wait. + * @opaque: A pointer-size value that is passed to @func. + */ +int qemu_add_polling_cb(PollingFunc *func, void *opaque); + +/** + * qemu_del_polling_cb: Unregister a Windows-specific polling callback + * + * This function removes a callback that was registered with + * qemu_add_polling_cb. + * + * @func: The function that was passed to qemu_add_polling_cb. + * @opaque: A pointer-size value that was passed to qemu_add_polling_cb. + */ +void qemu_del_polling_cb(PollingFunc *func, void *opaque); + +/* Wait objects handling */ +typedef void WaitObjectFunc(void *opaque); + +/** + * qemu_add_wait_object: Register a callback for a Windows handle + * + * Under Windows, the iohandler mechanism can only be used with sockets. + * QEMU must use the WaitForMultipleObjects API to wait on other handles. + * This function registers a #HANDLE with QEMU, so that it will be included + * in the main loop's calls to WaitForMultipleObjects. When the handle + * is in a signaled state, QEMU will call @func. + * + * @handle: The Windows handle to be observed. + * @func: A function to be called when @handle is in a signaled state. + * @opaque: A pointer-size value that is passed to @func. + */ +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); + +/** + * qemu_del_wait_object: Unregister a callback for a Windows handle + * + * This function removes a callback that was registered with + * qemu_add_wait_object. + * + * @func: The function that was passed to qemu_add_wait_object. + * @opaque: A pointer-size value that was passed to qemu_add_wait_object. + */ +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +#endif + +/* async I/O support */ + +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanReadHandler(void *opaque); +typedef void IOHandler(void *opaque); + +/** + * qemu_set_fd_handler2: Register a file descriptor with the main loop + * + * This function tells the main loop to wake up whenever one of the + * following conditions is true: + * + * 1) if @fd_write is not %NULL, when the file descriptor is writable; + * + * 2) if @fd_read is not %NULL, when the file descriptor is readable. + * + * @fd_read_poll can be used to disable the @fd_read callback temporarily. + * This is useful to avoid calling qemu_set_fd_handler2 every time the + * client becomes interested in reading (or dually, stops being interested). + * A typical example is when @fd is a listening socket and you want to bound + * the number of active clients. Remember to call qemu_notify_event whenever + * the condition may change from %false to %true. + * + * The callbacks that are set up by qemu_set_fd_handler2 are level-triggered. + * If @fd_read does not read from @fd, or @fd_write does not write to @fd + * until its buffers are full, they will be called again on the next + * iteration. + * + * @fd: The file descriptor to be observed. Under Windows it must be + * a #SOCKET. + * + * @fd_read_poll: A function that returns 1 if the @fd_read callback + * should be fired. If the function returns 0, the main loop will not + * end its iteration even if @fd becomes readable. + * + * @fd_read: A level-triggered callback that is fired if @fd is readable + * at the beginning of a main loop iteration, or if it becomes readable + * during one. + * + * @fd_write: A level-triggered callback that is fired when @fd is writable + * at the beginning of a main loop iteration, or if it becomes writable + * during one. + * + * @opaque: A pointer-sized value that is passed to @fd_read_poll, + * @fd_read and @fd_write. + */ +int qemu_set_fd_handler2(int fd, + IOCanReadHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); + +/** + * qemu_set_fd_handler: Register a file descriptor with the main loop + * + * This function tells the main loop to wake up whenever one of the + * following conditions is true: + * + * 1) if @fd_write is not %NULL, when the file descriptor is writable; + * + * 2) if @fd_read is not %NULL, when the file descriptor is readable. + * + * The callbacks that are set up by qemu_set_fd_handler are level-triggered. + * If @fd_read does not read from @fd, or @fd_write does not write to @fd + * until its buffers are full, they will be called again on the next + * iteration. + * + * @fd: The file descriptor to be observed. Under Windows it must be + * a #SOCKET. + * + * @fd_read: A level-triggered callback that is fired if @fd is readable + * at the beginning of a main loop iteration, or if it becomes readable + * during one. + * + * @fd_write: A level-triggered callback that is fired when @fd is writable + * at the beginning of a main loop iteration, or if it becomes writable + * during one. + * + * @opaque: A pointer-sized value that is passed to @fd_read and @fd_write. + */ +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); + +typedef struct QEMUBH QEMUBH; +typedef void QEMUBHFunc(void *opaque); + +/** + * qemu_bh_new: Allocate a new bottom half structure. + * + * Bottom halves are lightweight callbacks whose invocation is guaranteed + * to be wait-free, thread-safe and signal-safe. The #QEMUBH structure + * is opaque and must be allocated prior to its use. + */ +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); + +/** + * qemu_bh_schedule: Schedule a bottom half. + * + * Scheduling a bottom half interrupts the main loop and causes the + * execution of the callback that was passed to qemu_bh_new. + * + * Bottom halves that are scheduled from a bottom half handler are instantly + * invoked. This can create an infinite loop if a bottom half handler + * schedules itself. + * + * @bh: The bottom half to be scheduled. + */ +void qemu_bh_schedule(QEMUBH *bh); + +/** + * qemu_bh_cancel: Cancel execution of a bottom half. + * + * Canceling execution of a bottom half undoes the effect of calls to + * qemu_bh_schedule without freeing its resources yet. While cancellation + * itself is also wait-free and thread-safe, it can of course race with the + * loop that executes bottom halves unless you are holding the iothread + * mutex. This makes it mostly useless if you are not holding the mutex. + * + * @bh: The bottom half to be canceled. + */ +void qemu_bh_cancel(QEMUBH *bh); + +/** + *qemu_bh_delete: Cancel execution of a bottom half and free its resources. + * + * Deleting a bottom half frees the memory that was allocated for it by + * qemu_bh_new. It also implies canceling the bottom half if it was + * scheduled. + * + * @bh: The bottom half to be deleted. + */ +void qemu_bh_delete(QEMUBH *bh); + +#ifdef CONFIG_POSIX +/** + * qemu_add_child_watch: Register a child process for reaping. + * + * Under POSIX systems, a parent process must read the exit status of + * its child processes using waitpid, or the operating system will not + * free some of the resources attached to that process. + * + * This function directs the QEMU main loop to observe a child process + * and call waitpid as soon as it exits; the watch is then removed + * automatically. It is useful whenever QEMU forks a child process + * but will find out about its termination by other means such as a + * "broken pipe". + * + * @pid: The pid that QEMU should observe. + */ +int qemu_add_child_watch(pid_t pid); +#endif + +/** + * qemu_mutex_lock_iothread: Lock the main loop mutex. + * + * This function locks the main loop mutex. The mutex is taken by + * qemu_init_main_loop and always taken except while waiting on + * external events (such as with select). The mutex should be taken + * by threads other than the main loop thread when calling + * qemu_bh_new(), qemu_set_fd_handler() and basically all other + * functions documented in this file. + */ +void qemu_mutex_lock_iothread(void); + +/** + * qemu_mutex_unlock_iothread: Unlock the main loop mutex. + * + * This function unlocks the main loop mutex. The mutex is taken by + * qemu_init_main_loop and always taken except while waiting on + * external events (such as with select). The mutex should be unlocked + * as soon as possible by threads other than the main loop thread, + * because it prevents the main loop from processing callbacks, + * including timers and bottom halves. + */ +void qemu_mutex_unlock_iothread(void); + +/* internal interfaces */ + +void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); +void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc); + +void qemu_bh_schedule_idle(QEMUBH *bh); +int qemu_bh_poll(void); +void qemu_bh_update_timeout(int *timeout); + +#endif diff --git a/migration-exec.c b/migration-exec.c index 2cfb6f232c..b7b1055e88 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -32,17 +32,17 @@ do { } while (0) #endif -static int file_errno(FdMigrationState *s) +static int file_errno(MigrationState *s) { return errno; } -static int file_write(FdMigrationState *s, const void * buf, size_t size) +static int file_write(MigrationState *s, const void * buf, size_t size) { return write(s->fd, buf, size); } -static int exec_close(FdMigrationState *s) +static int exec_close(MigrationState *s) { int ret = 0; DPRINTF("exec_close\n"); @@ -61,22 +61,14 @@ static int exec_close(FdMigrationState *s) return ret; } -MigrationState *exec_start_outgoing_migration(Monitor *mon, - const char *command, - int64_t bandwidth_limit, - int detach, - int blk, - int inc) +int exec_start_outgoing_migration(MigrationState *s, const char *command) { - FdMigrationState *s; FILE *f; - s = g_malloc0(sizeof(*s)); - f = popen(command, "w"); if (f == NULL) { DPRINTF("Unable to popen exec target\n"); - goto err_after_alloc; + goto err_after_popen; } s->fd = fileno(f); @@ -92,29 +84,14 @@ MigrationState *exec_start_outgoing_migration(Monitor *mon, s->close = exec_close; s->get_error = file_errno; s->write = file_write; - s->mig_state.cancel = migrate_fd_cancel; - s->mig_state.get_status = migrate_fd_get_status; - s->mig_state.release = migrate_fd_release; - - s->mig_state.blk = blk; - s->mig_state.shared = inc; - - s->state = MIG_STATE_ACTIVE; - s->mon = NULL; - s->bandwidth_limit = bandwidth_limit; - - if (!detach) { - migrate_fd_monitor_suspend(s, mon); - } migrate_fd_connect(s); - return &s->mig_state; + return 0; err_after_open: pclose(f); -err_after_alloc: - g_free(s); - return NULL; +err_after_popen: + return -1; } static void exec_accept_incoming_migration(void *opaque) diff --git a/migration-fd.c b/migration-fd.c index aee690aaed..d0aec89e8d 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -30,17 +30,17 @@ do { } while (0) #endif -static int fd_errno(FdMigrationState *s) +static int fd_errno(MigrationState *s) { return errno; } -static int fd_write(FdMigrationState *s, const void * buf, size_t size) +static int fd_write(MigrationState *s, const void * buf, size_t size) { return write(s->fd, buf, size); } -static int fd_close(FdMigrationState *s) +static int fd_close(MigrationState *s) { DPRINTF("fd_close\n"); if (s->fd != -1) { @@ -50,21 +50,12 @@ static int fd_close(FdMigrationState *s) return 0; } -MigrationState *fd_start_outgoing_migration(Monitor *mon, - const char *fdname, - int64_t bandwidth_limit, - int detach, - int blk, - int inc) +int fd_start_outgoing_migration(MigrationState *s, const char *fdname) { - FdMigrationState *s; - - s = g_malloc0(sizeof(*s)); - - s->fd = monitor_get_fd(mon, fdname); + s->fd = monitor_get_fd(s->mon, fdname); if (s->fd == -1) { DPRINTF("fd_migration: invalid file descriptor identifier\n"); - goto err_after_alloc; + goto err_after_get_fd; } if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) { @@ -75,29 +66,14 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon, s->get_error = fd_errno; s->write = fd_write; s->close = fd_close; - s->mig_state.cancel = migrate_fd_cancel; - s->mig_state.get_status = migrate_fd_get_status; - s->mig_state.release = migrate_fd_release; - - s->mig_state.blk = blk; - s->mig_state.shared = inc; - - s->state = MIG_STATE_ACTIVE; - s->mon = NULL; - s->bandwidth_limit = bandwidth_limit; - - if (!detach) { - migrate_fd_monitor_suspend(s, mon); - } migrate_fd_connect(s); - return &s->mig_state; + return 0; err_after_open: close(s->fd); -err_after_alloc: - g_free(s); - return NULL; +err_after_get_fd: + return -1; } static void fd_accept_incoming_migration(void *opaque) diff --git a/migration-tcp.c b/migration-tcp.c index c431e03a48..5aa742c34b 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -28,17 +28,17 @@ do { } while (0) #endif -static int socket_errno(FdMigrationState *s) +static int socket_errno(MigrationState *s) { return socket_error(); } -static int socket_write(FdMigrationState *s, const void * buf, size_t size) +static int socket_write(MigrationState *s, const void * buf, size_t size) { return send(s->fd, buf, size, 0); } -static int tcp_close(FdMigrationState *s) +static int tcp_close(MigrationState *s) { DPRINTF("tcp_close\n"); if (s->fd != -1) { @@ -48,17 +48,16 @@ static int tcp_close(FdMigrationState *s) return 0; } - static void tcp_wait_for_connect(void *opaque) { - FdMigrationState *s = opaque; + MigrationState *s = opaque; int val, ret; socklen_t valsize = sizeof(val); DPRINTF("connect completed\n"); do { ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); - } while (ret == -1 && (s->get_error(s)) == EINTR); + } while (ret == -1 && (socket_error()) == EINTR); if (ret < 0) { migrate_fd_error(s); @@ -75,63 +74,46 @@ static void tcp_wait_for_connect(void *opaque) } } -MigrationState *tcp_start_outgoing_migration(Monitor *mon, - const char *host_port, - int64_t bandwidth_limit, - int detach, - int blk, - int inc) +int tcp_start_outgoing_migration(MigrationState *s, const char *host_port) { struct sockaddr_in addr; - FdMigrationState *s; int ret; - if (parse_host_port(&addr, host_port) < 0) - return NULL; - - s = g_malloc0(sizeof(*s)); + ret = parse_host_port(&addr, host_port); + if (ret < 0) { + return ret; + } s->get_error = socket_errno; s->write = socket_write; s->close = tcp_close; - s->mig_state.cancel = migrate_fd_cancel; - s->mig_state.get_status = migrate_fd_get_status; - s->mig_state.release = migrate_fd_release; - - s->mig_state.blk = blk; - s->mig_state.shared = inc; - s->state = MIG_STATE_ACTIVE; - s->mon = NULL; - s->bandwidth_limit = bandwidth_limit; s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (s->fd == -1) { - g_free(s); - return NULL; + DPRINTF("Unable to open socket"); + return -socket_error(); } socket_set_nonblock(s->fd); - if (!detach) { - migrate_fd_monitor_suspend(s, mon); - } - do { ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret == -1) - ret = -(s->get_error(s)); - - if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) + if (ret == -1) { + ret = -socket_error(); + } + if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) { qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); + return 0; + } } while (ret == -EINTR); - if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) { + if (ret < 0) { DPRINTF("connect failed\n"); migrate_fd_error(s); - } else if (ret >= 0) - migrate_fd_connect(s); - - return &s->mig_state; + return ret; + } + migrate_fd_connect(s); + return 0; } static void tcp_accept_incoming_migration(void *opaque) @@ -174,23 +156,27 @@ int tcp_start_incoming_migration(const char *host_port) int val; int s; + DPRINTF("Attempting to start an incoming migration\n"); + if (parse_host_port(&addr, host_port) < 0) { fprintf(stderr, "invalid host/port combination: %s\n", host_port); return -EINVAL; } s = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) + if (s == -1) { return -socket_error(); + } val = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { goto err; - - if (listen(s, 1) == -1) + } + if (listen(s, 1) == -1) { goto err; + } qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL, (void *)(intptr_t)s); diff --git a/migration-unix.c b/migration-unix.c index 6dc985d423..8596353d7d 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -28,17 +28,17 @@ do { } while (0) #endif -static int unix_errno(FdMigrationState *s) +static int unix_errno(MigrationState *s) { return errno; } -static int unix_write(FdMigrationState *s, const void * buf, size_t size) +static int unix_write(MigrationState *s, const void * buf, size_t size) { return write(s->fd, buf, size); } -static int unix_close(FdMigrationState *s) +static int unix_close(MigrationState *s) { DPRINTF("unix_close\n"); if (s->fd != -1) { @@ -50,14 +50,14 @@ static int unix_close(FdMigrationState *s) static void unix_wait_for_connect(void *opaque) { - FdMigrationState *s = opaque; + MigrationState *s = opaque; int val, ret; socklen_t valsize = sizeof(val); DPRINTF("connect completed\n"); do { ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); - } while (ret == -1 && (s->get_error(s)) == EINTR); + } while (ret == -1 && errno == EINTR); if (ret < 0) { migrate_fd_error(s); @@ -74,72 +74,43 @@ static void unix_wait_for_connect(void *opaque) } } -MigrationState *unix_start_outgoing_migration(Monitor *mon, - const char *path, - int64_t bandwidth_limit, - int detach, - int blk, - int inc) +int unix_start_outgoing_migration(MigrationState *s, const char *path) { - FdMigrationState *s; struct sockaddr_un addr; int ret; addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); - - s = g_malloc0(sizeof(*s)); - s->get_error = unix_errno; s->write = unix_write; s->close = unix_close; - s->mig_state.cancel = migrate_fd_cancel; - s->mig_state.get_status = migrate_fd_get_status; - s->mig_state.release = migrate_fd_release; - - s->mig_state.blk = blk; - s->mig_state.shared = inc; - s->state = MIG_STATE_ACTIVE; - s->mon = NULL; - s->bandwidth_limit = bandwidth_limit; s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); - if (s->fd < 0) { + if (s->fd == -1) { DPRINTF("Unable to open socket"); - goto err_after_alloc; + return -errno; } socket_set_nonblock(s->fd); do { ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret == -1) - ret = -(s->get_error(s)); - - if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) + if (ret == -1) { + ret = -errno; + } + if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) { qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s); + return 0; + } } while (ret == -EINTR); - if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) { + if (ret < 0) { DPRINTF("connect failed\n"); - goto err_after_open; - } - - if (!detach) { - migrate_fd_monitor_suspend(s, mon); + migrate_fd_error(s); + return ret; } - - if (ret >= 0) - migrate_fd_connect(s); - - return &s->mig_state; - -err_after_open: - close(s->fd); - -err_after_alloc: - g_free(s); - return NULL; + migrate_fd_connect(s); + return 0; } static void unix_accept_incoming_migration(void *opaque) @@ -152,13 +123,13 @@ static void unix_accept_incoming_migration(void *opaque) do { c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); - } while (c == -1 && socket_error() == EINTR); + } while (c == -1 && errno == EINTR); DPRINTF("accepted migration\n"); if (c == -1) { fprintf(stderr, "could not accept migration connection\n"); - return; + goto out2; } f = qemu_fopen_socket(c); @@ -170,45 +141,49 @@ static void unix_accept_incoming_migration(void *opaque) process_incoming_migration(f); qemu_fclose(f); out: + close(c); +out2: qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); close(s); - close(c); } int unix_start_incoming_migration(const char *path) { - struct sockaddr_un un; - int sock; + struct sockaddr_un addr; + int s; + int ret; DPRINTF("Attempting to start an incoming migration\n"); - sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { + s = qemu_socket(PF_UNIX, SOCK_STREAM, 0); + if (s == -1) { fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno)); - return -EINVAL; + return -errno; } - memset(&un, 0, sizeof(un)); - un.sun_family = AF_UNIX; - snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); - unlink(un.sun_path); - if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { - fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); + unlink(addr.sun_path); + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + ret = -errno; + fprintf(stderr, "bind(unix:%s): %s\n", addr.sun_path, strerror(errno)); goto err; } - if (listen(sock, 1) < 0) { - fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); + if (listen(s, 1) == -1) { + fprintf(stderr, "listen(unix:%s): %s\n", addr.sun_path, + strerror(errno)); + ret = -errno; goto err; } - qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL, - (void *)(intptr_t)sock); + qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL, + (void *)(intptr_t)s); return 0; err: - close(sock); - - return -EINVAL; + close(s); + return ret; } diff --git a/migration.c b/migration.c index 77a51adc5b..bdca72e008 100644 --- a/migration.c +++ b/migration.c @@ -31,14 +31,33 @@ do { } while (0) #endif -/* Migration speed throttling */ -static int64_t max_throttle = (32 << 20); +enum { + MIG_STATE_ERROR, + MIG_STATE_SETUP, + MIG_STATE_CANCELLED, + MIG_STATE_ACTIVE, + MIG_STATE_COMPLETED, +}; -static MigrationState *current_migration; +#define MAX_THROTTLE (32 << 20) /* Migration speed throttling */ static NotifierList migration_state_notifiers = NOTIFIER_LIST_INITIALIZER(migration_state_notifiers); +/* When we add fault tolerance, we could have several + migrations at once. For now we don't need to add + dynamic creation of migration */ + +static MigrationState *migrate_get_current(void) +{ + static MigrationState current_migration = { + .state = MIG_STATE_SETUP, + .bandwidth_limit = MAX_THROTTLE, + }; + + return ¤t_migration; +} + int qemu_start_incoming_migration(const char *uri) { const char *p; @@ -77,87 +96,6 @@ void process_incoming_migration(QEMUFile *f) } } -int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - MigrationState *s = NULL; - const char *p; - int detach = qdict_get_try_bool(qdict, "detach", 0); - int blk = qdict_get_try_bool(qdict, "blk", 0); - int inc = qdict_get_try_bool(qdict, "inc", 0); - const char *uri = qdict_get_str(qdict, "uri"); - - if (current_migration && - current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) { - monitor_printf(mon, "migration already in progress\n"); - return -1; - } - - if (qemu_savevm_state_blocked(mon)) { - return -1; - } - - if (strstart(uri, "tcp:", &p)) { - s = tcp_start_outgoing_migration(mon, p, max_throttle, detach, - blk, inc); -#if !defined(WIN32) - } else if (strstart(uri, "exec:", &p)) { - s = exec_start_outgoing_migration(mon, p, max_throttle, detach, - blk, inc); - } else if (strstart(uri, "unix:", &p)) { - s = unix_start_outgoing_migration(mon, p, max_throttle, detach, - blk, inc); - } else if (strstart(uri, "fd:", &p)) { - s = fd_start_outgoing_migration(mon, p, max_throttle, detach, - blk, inc); -#endif - } else { - monitor_printf(mon, "unknown migration protocol: %s\n", uri); - return -1; - } - - if (s == NULL) { - monitor_printf(mon, "migration failed\n"); - return -1; - } - - if (current_migration) { - current_migration->release(current_migration); - } - - current_migration = s; - notifier_list_notify(&migration_state_notifiers, NULL); - return 0; -} - -int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - MigrationState *s = current_migration; - - if (s) - s->cancel(s); - - return 0; -} - -int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - int64_t d; - FdMigrationState *s; - - d = qdict_get_int(qdict, "value"); - if (d < 0) { - d = 0; - } - max_throttle = d; - - s = migrate_to_fms(current_migration); - if (s && s->file) { - qemu_file_set_rate_limit(s->file, max_throttle); - } - - return 0; -} - /* amount of nanoseconds we are willing to wait for migration to be down. * the choice of nanoseconds is because it is the maximum resolution that * get_clock() can achieve. It is an internal measure. All user-visible @@ -169,18 +107,6 @@ uint64_t migrate_max_downtime(void) return max_downtime; } -int do_migrate_set_downtime(Monitor *mon, const QDict *qdict, - QObject **ret_data) -{ - double d; - - d = qdict_get_double(qdict, "value") * 1e9; - d = MAX(0, MIN(UINT64_MAX, d)); - max_downtime = (uint64_t)d; - - return 0; -} - static void migrate_print_status(Monitor *mon, const char *name, const QDict *status_dict) { @@ -228,41 +154,42 @@ static void migrate_put_status(QDict *qdict, const char *name, void do_info_migrate(Monitor *mon, QObject **ret_data) { QDict *qdict; - MigrationState *s = current_migration; - - if (s) { - switch (s->get_status(s)) { - case MIG_STATE_ACTIVE: - qdict = qdict_new(); - qdict_put(qdict, "status", qstring_from_str("active")); - - migrate_put_status(qdict, "ram", ram_bytes_transferred(), - ram_bytes_remaining(), ram_bytes_total()); - - if (blk_mig_active()) { - migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(), - blk_mig_bytes_remaining(), - blk_mig_bytes_total()); - } - - *ret_data = QOBJECT(qdict); - break; - case MIG_STATE_COMPLETED: - *ret_data = qobject_from_jsonf("{ 'status': 'completed' }"); - break; - case MIG_STATE_ERROR: - *ret_data = qobject_from_jsonf("{ 'status': 'failed' }"); - break; - case MIG_STATE_CANCELLED: - *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }"); - break; + MigrationState *s = migrate_get_current(); + + switch (s->state) { + case MIG_STATE_SETUP: + /* no migration has happened ever */ + break; + case MIG_STATE_ACTIVE: + qdict = qdict_new(); + qdict_put(qdict, "status", qstring_from_str("active")); + + migrate_put_status(qdict, "ram", ram_bytes_transferred(), + ram_bytes_remaining(), ram_bytes_total()); + + if (blk_mig_active()) { + migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(), + blk_mig_bytes_remaining(), + blk_mig_bytes_total()); } + + *ret_data = QOBJECT(qdict); + break; + case MIG_STATE_COMPLETED: + *ret_data = qobject_from_jsonf("{ 'status': 'completed' }"); + break; + case MIG_STATE_ERROR: + *ret_data = qobject_from_jsonf("{ 'status': 'failed' }"); + break; + case MIG_STATE_CANCELLED: + *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }"); + break; } } /* shared migration helpers */ -void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon) +static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon) { s->mon = mon; if (monitor_suspend(mon) == 0) { @@ -273,15 +200,7 @@ void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon) } } -void migrate_fd_error(FdMigrationState *s) -{ - DPRINTF("setting error state\n"); - s->state = MIG_STATE_ERROR; - notifier_list_notify(&migration_state_notifiers, NULL); - migrate_fd_cleanup(s); -} - -int migrate_fd_cleanup(FdMigrationState *s) +static int migrate_fd_cleanup(MigrationState *s) { int ret = 0; @@ -307,19 +226,47 @@ int migrate_fd_cleanup(FdMigrationState *s) return ret; } -void migrate_fd_put_notify(void *opaque) +void migrate_fd_error(MigrationState *s) { - FdMigrationState *s = opaque; + DPRINTF("setting error state\n"); + s->state = MIG_STATE_ERROR; + notifier_list_notify(&migration_state_notifiers, s); + migrate_fd_cleanup(s); +} + +static void migrate_fd_completed(MigrationState *s) +{ + DPRINTF("setting completed state\n"); + if (migrate_fd_cleanup(s) < 0) { + s->state = MIG_STATE_ERROR; + } else { + s->state = MIG_STATE_COMPLETED; + runstate_set(RUN_STATE_POSTMIGRATE); + } + notifier_list_notify(&migration_state_notifiers, s); +} + +static void migrate_fd_put_notify(void *opaque) +{ + MigrationState *s = opaque; qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); qemu_file_put_notify(s->file); + if (qemu_file_get_error(s->file)) { + migrate_fd_error(s); + } } -ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size) +static ssize_t migrate_fd_put_buffer(void *opaque, const void *data, + size_t size) { - FdMigrationState *s = opaque; + MigrationState *s = opaque; ssize_t ret; + if (s->state != MIG_STATE_ACTIVE) { + return -EIO; + } + do { ret = s->write(s, data, size); } while (ret == -1 && ((s->get_error(s)) == EINTR)); @@ -329,115 +276,61 @@ ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size) if (ret == -EAGAIN) { qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s); - } else if (ret < 0) { - s->state = MIG_STATE_ERROR; - notifier_list_notify(&migration_state_notifiers, NULL); } return ret; } -void migrate_fd_connect(FdMigrationState *s) +static void migrate_fd_put_ready(void *opaque) { + MigrationState *s = opaque; int ret; - s->file = qemu_fopen_ops_buffered(s, - s->bandwidth_limit, - migrate_fd_put_buffer, - migrate_fd_put_ready, - migrate_fd_wait_for_unfreeze, - migrate_fd_close); - - DPRINTF("beginning savevm\n"); - ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk, - s->mig_state.shared); - if (ret < 0) { - DPRINTF("failed, %d\n", ret); - migrate_fd_error(s); - return; - } - - migrate_fd_put_ready(s); -} - -void migrate_fd_put_ready(void *opaque) -{ - FdMigrationState *s = opaque; - if (s->state != MIG_STATE_ACTIVE) { DPRINTF("put_ready returning because of non-active state\n"); return; } DPRINTF("iterate\n"); - if (qemu_savevm_state_iterate(s->mon, s->file) == 1) { - int state; + ret = qemu_savevm_state_iterate(s->mon, s->file); + if (ret < 0) { + migrate_fd_error(s); + } else if (ret == 1) { int old_vm_running = runstate_is_running(); DPRINTF("done iterating\n"); - vm_stop(RUN_STATE_FINISH_MIGRATE); + vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { - if (old_vm_running) { - vm_start(); - } - state = MIG_STATE_ERROR; + if (qemu_savevm_state_complete(s->mon, s->file) < 0) { + migrate_fd_error(s); } else { - state = MIG_STATE_COMPLETED; + migrate_fd_completed(s); } - if (migrate_fd_cleanup(s) < 0) { + if (s->state != MIG_STATE_COMPLETED) { if (old_vm_running) { vm_start(); } - state = MIG_STATE_ERROR; - } - if (state == MIG_STATE_COMPLETED) { - runstate_set(RUN_STATE_POSTMIGRATE); } - s->state = state; - notifier_list_notify(&migration_state_notifiers, NULL); } } -int migrate_fd_get_status(MigrationState *mig_state) +static void migrate_fd_cancel(MigrationState *s) { - FdMigrationState *s = migrate_to_fms(mig_state); - return s->state; -} - -void migrate_fd_cancel(MigrationState *mig_state) -{ - FdMigrationState *s = migrate_to_fms(mig_state); - if (s->state != MIG_STATE_ACTIVE) return; DPRINTF("cancelling migration\n"); s->state = MIG_STATE_CANCELLED; - notifier_list_notify(&migration_state_notifiers, NULL); + notifier_list_notify(&migration_state_notifiers, s); qemu_savevm_state_cancel(s->mon, s->file); migrate_fd_cleanup(s); } -void migrate_fd_release(MigrationState *mig_state) -{ - FdMigrationState *s = migrate_to_fms(mig_state); - - DPRINTF("releasing state\n"); - - if (s->state == MIG_STATE_ACTIVE) { - s->state = MIG_STATE_CANCELLED; - notifier_list_notify(&migration_state_notifiers, NULL); - migrate_fd_cleanup(s); - } - g_free(s); -} - -void migrate_fd_wait_for_unfreeze(void *opaque) +static void migrate_fd_wait_for_unfreeze(void *opaque) { - FdMigrationState *s = opaque; + MigrationState *s = opaque; int ret; DPRINTF("wait for unfreeze\n"); @@ -452,11 +345,15 @@ void migrate_fd_wait_for_unfreeze(void *opaque) ret = select(s->fd + 1, NULL, &wfds, NULL, NULL); } while (ret == -1 && (s->get_error(s)) == EINTR); + + if (ret == -1) { + qemu_file_set_error(s->file, -s->get_error(s)); + } } -int migrate_fd_close(void *opaque) +static int migrate_fd_close(void *opaque) { - FdMigrationState *s = opaque; + MigrationState *s = opaque; if (s->mon) { monitor_resume(s->mon); @@ -475,11 +372,129 @@ void remove_migration_state_change_notifier(Notifier *notify) notifier_list_remove(&migration_state_notifiers, notify); } -int get_migration_state(void) +bool migration_has_finished(MigrationState *s) +{ + return s->state == MIG_STATE_COMPLETED; +} + +void migrate_fd_connect(MigrationState *s) { - if (current_migration) { - return migrate_fd_get_status(current_migration); + int ret; + + s->state = MIG_STATE_ACTIVE; + s->file = qemu_fopen_ops_buffered(s, + s->bandwidth_limit, + migrate_fd_put_buffer, + migrate_fd_put_ready, + migrate_fd_wait_for_unfreeze, + migrate_fd_close); + + DPRINTF("beginning savevm\n"); + ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared); + if (ret < 0) { + DPRINTF("failed, %d\n", ret); + migrate_fd_error(s); + return; + } + migrate_fd_put_ready(s); +} + +static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc) +{ + MigrationState *s = migrate_get_current(); + int64_t bandwidth_limit = s->bandwidth_limit; + + memset(s, 0, sizeof(*s)); + s->bandwidth_limit = bandwidth_limit; + s->blk = blk; + s->shared = inc; + s->mon = NULL; + s->bandwidth_limit = bandwidth_limit; + s->state = MIG_STATE_SETUP; + + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } + + return s; +} + +int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + MigrationState *s = migrate_get_current(); + const char *p; + int detach = qdict_get_try_bool(qdict, "detach", 0); + int blk = qdict_get_try_bool(qdict, "blk", 0); + int inc = qdict_get_try_bool(qdict, "inc", 0); + const char *uri = qdict_get_str(qdict, "uri"); + int ret; + + if (s->state == MIG_STATE_ACTIVE) { + monitor_printf(mon, "migration already in progress\n"); + return -1; + } + + if (qemu_savevm_state_blocked(mon)) { + return -1; + } + + s = migrate_init(mon, detach, blk, inc); + + if (strstart(uri, "tcp:", &p)) { + ret = tcp_start_outgoing_migration(s, p); +#if !defined(WIN32) + } else if (strstart(uri, "exec:", &p)) { + ret = exec_start_outgoing_migration(s, p); + } else if (strstart(uri, "unix:", &p)) { + ret = unix_start_outgoing_migration(s, p); + } else if (strstart(uri, "fd:", &p)) { + ret = fd_start_outgoing_migration(s, p); +#endif } else { - return MIG_STATE_ERROR; + monitor_printf(mon, "unknown migration protocol: %s\n", uri); + ret = -EINVAL; + } + + if (ret < 0) { + monitor_printf(mon, "migration failed: %s\n", strerror(-ret)); + return ret; + } + + notifier_list_notify(&migration_state_notifiers, s); + return 0; +} + +int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + migrate_fd_cancel(migrate_get_current()); + return 0; +} + +int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + int64_t d; + MigrationState *s; + + d = qdict_get_int(qdict, "value"); + if (d < 0) { + d = 0; } + + s = migrate_get_current(); + s->bandwidth_limit = d; + qemu_file_set_rate_limit(s->file, s->bandwidth_limit); + + return 0; +} + +int do_migrate_set_downtime(Monitor *mon, const QDict *qdict, + QObject **ret_data) +{ + double d; + + d = qdict_get_double(qdict, "value") * 1e9; + d = MAX(0, MIN(UINT64_MAX, d)); + max_downtime = (uint64_t)d; + + return 0; } diff --git a/migration.h b/migration.h index 050c56c5a4..a1f80d0728 100644 --- a/migration.h +++ b/migration.h @@ -18,37 +18,21 @@ #include "qemu-common.h" #include "notify.h" -#define MIG_STATE_ERROR -1 -#define MIG_STATE_COMPLETED 0 -#define MIG_STATE_CANCELLED 1 -#define MIG_STATE_ACTIVE 2 - typedef struct MigrationState MigrationState; struct MigrationState { - /* FIXME: add more accessors to print migration info */ - void (*cancel)(MigrationState *s); - int (*get_status)(MigrationState *s); - void (*release)(MigrationState *s); - int blk; - int shared; -}; - -typedef struct FdMigrationState FdMigrationState; - -struct FdMigrationState -{ - MigrationState mig_state; int64_t bandwidth_limit; QEMUFile *file; int fd; Monitor *mon; int state; - int (*get_error)(struct FdMigrationState*); - int (*close)(struct FdMigrationState*); - int (*write)(struct FdMigrationState*, const void *, size_t); + int (*get_error)(MigrationState *s); + int (*close)(MigrationState *s); + int (*write)(MigrationState *s, const void *buff, size_t size); void *opaque; + int blk; + int shared; }; void process_incoming_migration(QEMUFile *f); @@ -72,72 +56,27 @@ void do_info_migrate(Monitor *mon, QObject **ret_data); int exec_start_incoming_migration(const char *host_port); -MigrationState *exec_start_outgoing_migration(Monitor *mon, - const char *host_port, - int64_t bandwidth_limit, - int detach, - int blk, - int inc); +int exec_start_outgoing_migration(MigrationState *s, const char *host_port); int tcp_start_incoming_migration(const char *host_port); -MigrationState *tcp_start_outgoing_migration(Monitor *mon, - const char *host_port, - int64_t bandwidth_limit, - int detach, - int blk, - int inc); +int tcp_start_outgoing_migration(MigrationState *s, const char *host_port); int unix_start_incoming_migration(const char *path); -MigrationState *unix_start_outgoing_migration(Monitor *mon, - const char *path, - int64_t bandwidth_limit, - int detach, - int blk, - int inc); +int unix_start_outgoing_migration(MigrationState *s, const char *path); int fd_start_incoming_migration(const char *path); -MigrationState *fd_start_outgoing_migration(Monitor *mon, - const char *fdname, - int64_t bandwidth_limit, - int detach, - int blk, - int inc); - -void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon); - -void migrate_fd_error(FdMigrationState *s); +int fd_start_outgoing_migration(MigrationState *s, const char *fdname); -int migrate_fd_cleanup(FdMigrationState *s); +void migrate_fd_error(MigrationState *s); -void migrate_fd_put_notify(void *opaque); - -ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size); - -void migrate_fd_connect(FdMigrationState *s); - -void migrate_fd_put_ready(void *opaque); - -int migrate_fd_get_status(MigrationState *mig_state); - -void migrate_fd_cancel(MigrationState *mig_state); - -void migrate_fd_release(MigrationState *mig_state); - -void migrate_fd_wait_for_unfreeze(void *opaque); - -int migrate_fd_close(void *opaque); - -static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state) -{ - return container_of(mig_state, FdMigrationState, mig_state); -} +void migrate_fd_connect(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); -int get_migration_state(void); +bool migration_has_finished(MigrationState *); uint64_t ram_bytes_remaining(void); uint64_t ram_bytes_transferred(void); diff --git a/os-win32.c b/os-win32.c index f09f01fc49..79094016f1 100644 --- a/os-win32.c +++ b/os-win32.c @@ -48,129 +48,6 @@ int setenv(const char *name, const char *value, int overwrite) return result; } -/***********************************************************/ -/* Polling handling */ - -typedef struct PollingEntry { - PollingFunc *func; - void *opaque; - struct PollingEntry *next; -} PollingEntry; - -static PollingEntry *first_polling_entry; - -int qemu_add_polling_cb(PollingFunc *func, void *opaque) -{ - PollingEntry **ppe, *pe; - pe = g_malloc0(sizeof(PollingEntry)); - pe->func = func; - pe->opaque = opaque; - for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); - *ppe = pe; - return 0; -} - -void qemu_del_polling_cb(PollingFunc *func, void *opaque) -{ - PollingEntry **ppe, *pe; - for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { - pe = *ppe; - if (pe->func == func && pe->opaque == opaque) { - *ppe = pe->next; - g_free(pe); - break; - } - } -} - -/***********************************************************/ -/* Wait objects support */ -typedef struct WaitObjects { - int num; - HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; - WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; - void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; -} WaitObjects; - -static WaitObjects wait_objects = {0}; - -int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) -{ - WaitObjects *w = &wait_objects; - - if (w->num >= MAXIMUM_WAIT_OBJECTS) - return -1; - w->events[w->num] = handle; - w->func[w->num] = func; - w->opaque[w->num] = opaque; - w->num++; - return 0; -} - -void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) -{ - int i, found; - WaitObjects *w = &wait_objects; - - found = 0; - for (i = 0; i < w->num; i++) { - if (w->events[i] == handle) - found = 1; - if (found) { - w->events[i] = w->events[i + 1]; - w->func[i] = w->func[i + 1]; - w->opaque[i] = w->opaque[i + 1]; - } - } - if (found) - w->num--; -} - -void os_host_main_loop_wait(int *timeout) -{ - int ret, ret2, i; - PollingEntry *pe; - - /* XXX: need to suppress polling by better using win32 events */ - ret = 0; - for(pe = first_polling_entry; pe != NULL; pe = pe->next) { - ret |= pe->func(pe->opaque); - } - if (ret == 0) { - int err; - WaitObjects *w = &wait_objects; - - qemu_mutex_unlock_iothread(); - ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout); - qemu_mutex_lock_iothread(); - if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { - if (w->func[ret - WAIT_OBJECT_0]) - w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); - - /* Check for additional signaled events */ - for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { - - /* Check if event is signaled */ - ret2 = WaitForSingleObject(w->events[i], 0); - if(ret2 == WAIT_OBJECT_0) { - if (w->func[i]) - w->func[i](w->opaque[i]); - } else if (ret2 == WAIT_TIMEOUT) { - } else { - err = GetLastError(); - fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); - } - } - } else if (ret == WAIT_TIMEOUT) { - } else { - err = GetLastError(); - fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); - } - } - - *timeout = 0; -} - static BOOL WINAPI qemu_ctrl_handler(DWORD type) { exit(STATUS_CONTROL_C_EXIT); diff --git a/oslib-posix.c b/oslib-posix.c index a304fb0f53..dbc8ee8960 100644 --- a/oslib-posix.c +++ b/oslib-posix.c @@ -103,6 +103,13 @@ void qemu_vfree(void *ptr) free(ptr); } +void socket_set_block(int fd) +{ + int f; + f = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, f & ~O_NONBLOCK); +} + void socket_set_nonblock(int fd) { int f; diff --git a/oslib-win32.c b/oslib-win32.c index 5f0759ffc4..5e3de7dc8a 100644 --- a/oslib-win32.c +++ b/oslib-win32.c @@ -73,6 +73,12 @@ void qemu_vfree(void *ptr) VirtualFree(ptr, 0, MEM_RELEASE); } +void socket_set_block(int fd) +{ + unsigned long opt = 0; + ioctlsocket(fd, FIONBIO, &opt); +} + void socket_set_nonblock(int fd) { unsigned long opt = 1; diff --git a/qemu-char.c b/qemu-char.c index fb9e058961..9fd94d1bb4 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -538,6 +538,9 @@ int send_all(int fd, const void *_buf, int len1) } #endif /* !_WIN32 */ +#define STDIO_MAX_CLIENTS 1 +static int stdio_nb_clients; + #ifndef _WIN32 typedef struct { @@ -545,8 +548,6 @@ typedef struct { int max_size; } FDCharDriver; -#define STDIO_MAX_CLIENTS 1 -static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { @@ -1451,6 +1452,8 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) #else /* _WIN32 */ +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; + typedef struct { int max_size; HANDLE hcom, hrecv, hsend; @@ -1459,6 +1462,14 @@ typedef struct { DWORD len; } WinCharState; +typedef struct { + HANDLE hStdIn; + HANDLE hInputReadyEvent; + HANDLE hInputDoneEvent; + HANDLE hInputThread; + uint8_t win_stdio_buf; +} WinStdioCharState; + #define NSENDBUF 2048 #define NRECVBUF 2048 #define MAXCONNECT 1 @@ -1809,6 +1820,217 @@ static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr) return qemu_chr_open_win_file(fd_out, _chr); } + +static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwSize; + int len1; + + len1 = len; + + while (len1 > 0) { + if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) { + break; + } + buf += dwSize; + len1 -= dwSize; + } + + return len - len1; +} + +static void win_stdio_wait_func(void *opaque) +{ + CharDriverState *chr = opaque; + WinStdioCharState *stdio = chr->opaque; + INPUT_RECORD buf[4]; + int ret; + DWORD dwSize; + int i; + + ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf), + &dwSize); + + if (!ret) { + /* Avoid error storm */ + qemu_del_wait_object(stdio->hStdIn, NULL, NULL); + return; + } + + for (i = 0; i < dwSize; i++) { + KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; + + if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { + int j; + if (kev->uChar.AsciiChar != 0) { + for (j = 0; j < kev->wRepeatCount; j++) { + if (qemu_chr_be_can_write(chr)) { + uint8_t c = kev->uChar.AsciiChar; + qemu_chr_be_write(chr, &c, 1); + } + } + } + } + } +} + +static DWORD WINAPI win_stdio_thread(LPVOID param) +{ + CharDriverState *chr = param; + WinStdioCharState *stdio = chr->opaque; + int ret; + DWORD dwSize; + + while (1) { + + /* Wait for one byte */ + ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL); + + /* Exit in case of error, continue if nothing read */ + if (!ret) { + break; + } + if (!dwSize) { + continue; + } + + /* Some terminal emulator returns \r\n for Enter, just pass \n */ + if (stdio->win_stdio_buf == '\r') { + continue; + } + + /* Signal the main thread and wait until the byte was eaten */ + if (!SetEvent(stdio->hInputReadyEvent)) { + break; + } + if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE) + != WAIT_OBJECT_0) { + break; + } + } + + qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); + return 0; +} + +static void win_stdio_thread_wait_func(void *opaque) +{ + CharDriverState *chr = opaque; + WinStdioCharState *stdio = chr->opaque; + + if (qemu_chr_be_can_write(chr)) { + qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1); + } + + SetEvent(stdio->hInputDoneEvent); +} + +static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo) +{ + WinStdioCharState *stdio = chr->opaque; + DWORD dwMode = 0; + + GetConsoleMode(stdio->hStdIn, &dwMode); + + if (echo) { + SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT); + } else { + SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT); + } +} + +static void win_stdio_close(CharDriverState *chr) +{ + WinStdioCharState *stdio = chr->opaque; + + if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) { + CloseHandle(stdio->hInputReadyEvent); + } + if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) { + CloseHandle(stdio->hInputDoneEvent); + } + if (stdio->hInputThread != INVALID_HANDLE_VALUE) { + TerminateThread(stdio->hInputThread, 0); + } + + g_free(chr->opaque); + g_free(chr); + stdio_nb_clients--; +} + +static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) +{ + CharDriverState *chr; + WinStdioCharState *stdio; + DWORD dwMode; + int is_console = 0; + + if (stdio_nb_clients >= STDIO_MAX_CLIENTS + || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { + return -EIO; + } + + chr = g_malloc0(sizeof(CharDriverState)); + stdio = g_malloc0(sizeof(WinStdioCharState)); + + stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); + if (stdio->hStdIn == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot open stdio: invalid handle\n"); + exit(1); + } + + is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; + + chr->opaque = stdio; + chr->chr_write = win_stdio_write; + chr->chr_close = win_stdio_close; + + if (stdio_nb_clients == 0) { + if (is_console) { + if (qemu_add_wait_object(stdio->hStdIn, + win_stdio_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } else { + DWORD dwId; + + stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, + chr, 0, &dwId); + + if (stdio->hInputThread == INVALID_HANDLE_VALUE + || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE + || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot create stdio thread or event\n"); + exit(1); + } + if (qemu_add_wait_object(stdio->hInputReadyEvent, + win_stdio_thread_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } + } + + dwMode |= ENABLE_LINE_INPUT; + + stdio_clients[stdio_nb_clients++] = chr; + if (stdio_nb_clients == 1 && is_console) { + /* set the terminal in raw mode */ + /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ + dwMode |= ENABLE_PROCESSED_INPUT; + } + + SetConsoleMode(stdio->hStdIn, dwMode); + + chr->chr_set_echo = qemu_chr_set_echo_win_stdio; + qemu_chr_fe_set_echo(chr, false); + + *_chr = chr; + + return 0; +} #endif /* !_WIN32 */ /***********************************************************/ @@ -2519,6 +2741,7 @@ static const struct { { .name = "pipe", .open = qemu_chr_open_win_pipe }, { .name = "console", .open = qemu_chr_open_win_con }, { .name = "serial", .open = qemu_chr_open_win }, + { .name = "stdio", .open = qemu_chr_open_win_stdio }, #else { .name = "file", .open = qemu_chr_open_file_out }, { .name = "pipe", .open = qemu_chr_open_pipe }, diff --git a/qemu-char.h b/qemu-char.h index eebbdd8f01..7efcf99f53 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -7,6 +7,7 @@ #include "qemu-config.h" #include "qobject.h" #include "qstring.h" +#include "main-loop.h" /* character device */ @@ -237,15 +238,4 @@ void qemu_chr_close_mem(CharDriverState *chr); QString *qemu_chr_mem_to_qs(CharDriverState *chr); size_t qemu_chr_mem_osize(const CharDriverState *chr); -/* async I/O support */ - -int qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque); -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque); #endif diff --git a/qemu-common.h b/qemu-common.h index 5e87bdf2f2..1c15cb17a7 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -13,7 +13,6 @@ typedef struct QEMUTimer QEMUTimer; typedef struct QEMUFile QEMUFile; -typedef struct QEMUBH QEMUBH; typedef struct DeviceState DeviceState; struct Monitor; @@ -96,6 +95,10 @@ static inline char *realpath(const char *path, char *resolved_path) } #endif +/* icount */ +void configure_icount(const char *option); +extern int use_icount; + /* FIXME: Remove NEED_CPU_H. */ #ifndef NEED_CPU_H @@ -113,23 +116,6 @@ static inline char *realpath(const char *path, char *resolved_path) int qemu_main(int argc, char **argv, char **envp); #endif -/* bottom halves */ -typedef void QEMUBHFunc(void *opaque); - -QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); -void qemu_bh_schedule(QEMUBH *bh); -/* Bottom halfs that are scheduled from a bottom half handler are instantly - * invoked. This can create an infinite loop if a bottom half handler - * schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by - * ensuring that the bottom half isn't executed until the next main loop - * iteration. - */ -void qemu_bh_schedule_idle(QEMUBH *bh); -void qemu_bh_cancel(QEMUBH *bh); -void qemu_bh_delete(QEMUBH *bh); -int qemu_bh_poll(void); -void qemu_bh_update_timeout(int *timeout); - void qemu_get_timedate(struct tm *tm, int offset); int qemu_timedate_diff(struct tm *tm); @@ -183,16 +169,12 @@ const char *path(const char *pathname); void *qemu_oom_check(void *ptr); -void qemu_mutex_lock_iothread(void); -void qemu_mutex_unlock_iothread(void); - int qemu_open(const char *name, int flags, ...); ssize_t qemu_write_full(int fd, const void *buf, size_t count) QEMU_WARN_UNUSED_RESULT; void qemu_set_cloexec(int fd); #ifndef _WIN32 -int qemu_add_child_watch(pid_t pid); int qemu_eventfd(int pipefd[2]); int qemu_pipe(int pipefd[2]); #endif @@ -207,14 +189,6 @@ int qemu_pipe(int pipefd[2]); void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2); -/* IO callbacks. */ -typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); -typedef int IOCanReadHandler(void *opaque); -typedef void IOHandler(void *opaque); - -void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); -void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc); - struct ParallelIOArg { void *buffer; int count; @@ -276,9 +250,6 @@ void cpu_exec_init_all(void); void cpu_save(QEMUFile *f, void *opaque); int cpu_load(QEMUFile *f, void *opaque, int version_id); -/* Force QEMU to process pending events */ -void qemu_notify_event(void); - /* Unblock cpu */ void qemu_cpu_kick(void *env); void qemu_cpu_kick_self(void); diff --git a/qemu-config.c b/qemu-config.c index 7a7854fd06..90b6b3e85b 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -165,11 +165,11 @@ static QemuOptsList qemu_chardev_opts = { QemuOptsList qemu_fsdev_opts = { .name = "fsdev", - .implied_opt_name = "fstype", + .implied_opt_name = "fsdriver", .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head), .desc = { { - .name = "fstype", + .name = "fsdriver", .type = QEMU_OPT_STRING, }, { .name = "path", @@ -177,6 +177,9 @@ QemuOptsList qemu_fsdev_opts = { }, { .name = "security_model", .type = QEMU_OPT_STRING, + }, { + .name = "writeout", + .type = QEMU_OPT_STRING, }, { /*End of list */ } }, @@ -184,11 +187,11 @@ QemuOptsList qemu_fsdev_opts = { QemuOptsList qemu_virtfs_opts = { .name = "virtfs", - .implied_opt_name = "fstype", + .implied_opt_name = "fsdriver", .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head), .desc = { { - .name = "fstype", + .name = "fsdriver", .type = QEMU_OPT_STRING, }, { .name = "path", @@ -199,6 +202,9 @@ QemuOptsList qemu_virtfs_opts = { }, { .name = "security_model", .type = QEMU_OPT_STRING, + }, { + .name = "writeout", + .type = QEMU_OPT_STRING, }, { /*End of list */ } diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c index 2a385a3bb8..6b58160058 100644 --- a/qemu-coroutine-lock.c +++ b/qemu-coroutine-lock.c @@ -26,6 +26,7 @@ #include "qemu-coroutine.h" #include "qemu-coroutine-int.h" #include "qemu-queue.h" +#include "main-loop.h" #include "trace.h" static QTAILQ_HEAD(, Coroutine) unlock_bh_queue = diff --git a/qemu-img.c b/qemu-img.c index 6a3973163f..86127f0b11 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -824,6 +824,8 @@ static int img_convert(int argc, char **argv) if (compress) { QEMUOptionParameter *encryption = get_option_parameter(param, BLOCK_OPT_ENCRYPT); + QEMUOptionParameter *preallocation = + get_option_parameter(param, BLOCK_OPT_PREALLOC); if (!drv->bdrv_write_compressed) { error_report("Compression not supported for this file format"); @@ -837,6 +839,15 @@ static int img_convert(int argc, char **argv) ret = -1; goto out; } + + if (preallocation && preallocation->value.s + && strcmp(preallocation->value.s, "off")) + { + error_report("Compression and preallocation not supported at " + "the same time"); + ret = -1; + goto out; + } } /* Create the new image */ @@ -1248,6 +1248,7 @@ static int aio_write_f(int argc, char **argv) case 'P': pattern = parse_pattern(optarg); if (pattern < 0) { + free(ctx); return 0; } break; diff --git a/qemu-options.hx b/qemu-options.hx index d4fe990e27..5d2a7765e8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -522,73 +522,103 @@ possible drivers and properties, use @code{-device ?} and @code{-device @var{driver},?}. ETEXI +DEFHEADING() + DEFHEADING(File system options:) DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, - "-fsdev local,id=id,path=path,security_model=[mapped|passthrough|none]\n", + "-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n" + " [,writeout=immediate]\n", QEMU_ARCH_ALL) STEXI -The general form of a File system device option is: -@table @option - -@item -fsdev @var{fstype} ,id=@var{id} [,@var{options}] +@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}] @findex -fsdev -Fstype is one of: -@option{local}, -The specific Fstype will determine the applicable options. - -Options to each backend are described below. - -@item -fsdev local ,id=@var{id} ,path=@var{path} ,security_model=@var{security_model} - -Create a file-system-"device" for local-filesystem. - -@option{local} is only available on Linux. - -@option{path} specifies the path to be exported. @option{path} is required. - -@option{security_model} specifies the security model to be followed. -@option{security_model} is required. +Define a new file system device. Valid options are: +@table @option +@item @var{fsdriver} +This option specifies the fs driver backend to use. +Currently "local" and "handle" file system drivers are supported. +@item id=@var{id} +Specifies identifier for this device +@item path=@var{path} +Specifies the export path for the file system device. Files under +this path will be available to the 9p client on the guest. +@item security_model=@var{security_model} +Specifies the security model to be used for this export path. +Supported security models are "passthrough", "mapped" and "none". +In "passthrough" security model, files are stored using the same +credentials as they are created on the guest. This requires qemu +to run as root. In "mapped" security model, some of the file +attributes like uid, gid, mode bits and link target are stored as +file attributes. Directories exported by this security model cannot +interact with other unix tools. "none" security model is same as +passthrough except the sever won't report failures if it fails to +set file attributes like ownership. Security model is mandatory +only for local fsdriver. Other fsdrivers (like handle) don't take +security model as a parameter. +@item writeout=@var{writeout} +This is an optional argument. The only supported value is "immediate". +This means that host page cache will be used to read and write data but +write notification will be sent to the guest only when the data has been +reported as written by the storage subsystem. +@end table +-fsdev option is used along with -device driver "virtio-9p-pci". +@item -device virtio-9p-pci,fsdev=@var{id},mount_tag=@var{mount_tag} +Options for virtio-9p-pci driver are: +@table @option +@item fsdev=@var{id} +Specifies the id value specified along with -fsdev option +@item mount_tag=@var{mount_tag} +Specifies the tag name to be used by the guest to mount this export point @end table + ETEXI +DEFHEADING() + DEFHEADING(Virtual File system pass-through options:) DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs, - "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n", + "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n" + " [,writeout=immediate]\n", QEMU_ARCH_ALL) STEXI -The general form of a Virtual File system pass-through option is: -@table @option - -@item -virtfs @var{fstype} [,@var{options}] +@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}] @findex -virtfs -Fstype is one of: -@option{local}, -The specific Fstype will determine the applicable options. - -Options to each backend are described below. - -@item -virtfs local ,path=@var{path} ,mount_tag=@var{mount_tag} ,security_model=@var{security_model} - -Create a Virtual file-system-pass through for local-filesystem. - -@option{local} is only available on Linux. - -@option{path} specifies the path to be exported. @option{path} is required. - -@option{security_model} specifies the security model to be followed. -@option{security_model} is required. - - -@option{mount_tag} specifies the tag with which the exported file is mounted. -@option{mount_tag} is required. +The general form of a Virtual File system pass-through options are: +@table @option +@item @var{fsdriver} +This option specifies the fs driver backend to use. +Currently "local" and "handle" file system drivers are supported. +@item id=@var{id} +Specifies identifier for this device +@item path=@var{path} +Specifies the export path for the file system device. Files under +this path will be available to the 9p client on the guest. +@item security_model=@var{security_model} +Specifies the security model to be used for this export path. +Supported security models are "passthrough", "mapped" and "none". +In "passthrough" security model, files are stored using the same +credentials as they are created on the guest. This requires qemu +to run as root. In "mapped" security model, some of the file +attributes like uid, gid, mode bits and link target are stored as +file attributes. Directories exported by this security model cannot +interact with other unix tools. "none" security model is same as +passthrough except the sever won't report failures if it fails to +set file attributes like ownership. Security model is mandatory only +for local fsdriver. Other fsdrivers (like handle) don't take security +model as a parameter. +@item writeout=@var{writeout} +This is an optional argument. The only supported value is "immediate". +This means that host page cache will be used to read and write data but +write notification will be sent to the guest only when the data has been +reported as written by the storage subsystem. @end table ETEXI diff --git a/qemu-os-posix.h b/qemu-os-posix.h index 81fd9ab389..920499d836 100644 --- a/qemu-os-posix.h +++ b/qemu-os-posix.h @@ -26,10 +26,6 @@ #ifndef QEMU_OS_POSIX_H #define QEMU_OS_POSIX_H -static inline void os_host_main_loop_wait(int *timeout) -{ -} - void os_set_line_buffering(void); void os_set_proc_name(const char *s); void os_setup_signal_handling(void); diff --git a/qemu-os-win32.h b/qemu-os-win32.h index 8a069d7fb6..8eda4bdc20 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -28,26 +28,11 @@ #include <windows.h> #include <winsock2.h> +#include "main-loop.h" /* Declaration of ffs() is missing in MinGW's strings.h. */ int ffs(int i); -/* Polling handling */ - -/* return TRUE if no sleep should be done afterwards */ -typedef int PollingFunc(void *opaque); - -int qemu_add_polling_cb(PollingFunc *func, void *opaque); -void qemu_del_polling_cb(PollingFunc *func, void *opaque); - -/* Wait objects handling */ -typedef void WaitObjectFunc(void *opaque); - -int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); -void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); - -void os_host_main_loop_wait(int *timeout); - static inline void os_setup_signal_handling(void) {} static inline void os_daemonize(void) {} static inline void os_setup_post(void) {} diff --git a/qemu-timer.c b/qemu-timer.c index ad1fc8b871..f11a28dd03 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -46,82 +46,6 @@ #include "qemu-timer.h" -/* Conversion factor from emulated instructions to virtual clock ticks. */ -int icount_time_shift; -/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ -#define MAX_ICOUNT_SHIFT 10 -/* Compensate for varying guest execution speed. */ -int64_t qemu_icount_bias; -static QEMUTimer *icount_rt_timer; -static QEMUTimer *icount_vm_timer; - -/***********************************************************/ -/* guest cycle counter */ - -typedef struct TimersState { - int64_t cpu_ticks_prev; - int64_t cpu_ticks_offset; - int64_t cpu_clock_offset; - int32_t cpu_ticks_enabled; - int64_t dummy; -} TimersState; - -TimersState timers_state; - -/* return the host CPU cycle counter and handle stop/restart */ -int64_t cpu_get_ticks(void) -{ - if (use_icount) { - return cpu_get_icount(); - } - if (!timers_state.cpu_ticks_enabled) { - return timers_state.cpu_ticks_offset; - } else { - int64_t ticks; - ticks = cpu_get_real_ticks(); - if (timers_state.cpu_ticks_prev > ticks) { - /* Note: non increasing ticks may happen if the host uses - software suspend */ - timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; - } - timers_state.cpu_ticks_prev = ticks; - return ticks + timers_state.cpu_ticks_offset; - } -} - -/* return the host CPU monotonic timer and handle stop/restart */ -static int64_t cpu_get_clock(void) -{ - int64_t ti; - if (!timers_state.cpu_ticks_enabled) { - return timers_state.cpu_clock_offset; - } else { - ti = get_clock(); - return ti + timers_state.cpu_clock_offset; - } -} - -/* enable cpu_get_ticks() */ -void cpu_enable_ticks(void) -{ - if (!timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset -= cpu_get_real_ticks(); - timers_state.cpu_clock_offset -= get_clock(); - timers_state.cpu_ticks_enabled = 1; - } -} - -/* disable cpu_get_ticks() : the clock is stopped. You must not call - cpu_get_ticks() after that. */ -void cpu_disable_ticks(void) -{ - if (timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset = cpu_get_ticks(); - timers_state.cpu_clock_offset = cpu_get_clock(); - timers_state.cpu_ticks_enabled = 0; - } -} - /***********************************************************/ /* timers */ @@ -133,7 +57,7 @@ struct QEMUClock { int type; int enabled; - QEMUTimer *warp_timer; + QEMUTimer *active_timers; NotifierList reset_notifiers; int64_t last; @@ -152,7 +76,7 @@ struct qemu_alarm_timer { char const *name; int (*start)(struct qemu_alarm_timer *t); void (*stop)(struct qemu_alarm_timer *t); - void (*rearm)(struct qemu_alarm_timer *t); + void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns); #if defined(__linux__) int fd; timer_t timer; @@ -180,12 +104,46 @@ static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) return !!t->rearm; } +static int64_t qemu_next_alarm_deadline(void) +{ + int64_t delta; + int64_t rtdelta; + + if (!use_icount && vm_clock->active_timers) { + delta = vm_clock->active_timers->expire_time - + qemu_get_clock_ns(vm_clock); + } else { + delta = INT32_MAX; + } + if (host_clock->active_timers) { + int64_t hdelta = host_clock->active_timers->expire_time - + qemu_get_clock_ns(host_clock); + if (hdelta < delta) { + delta = hdelta; + } + } + if (rt_clock->active_timers) { + rtdelta = (rt_clock->active_timers->expire_time - + qemu_get_clock_ns(rt_clock)); + if (rtdelta < delta) { + delta = rtdelta; + } + } + + return delta; +} + static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) { - if (!alarm_has_dynticks(t)) + int64_t nearest_delta_ns; + assert(alarm_has_dynticks(t)); + if (!rt_clock->active_timers && + !vm_clock->active_timers && + !host_clock->active_timers) { return; - - t->rearm(t); + } + nearest_delta_ns = qemu_next_alarm_deadline(); + t->rearm(t, nearest_delta_ns); } /* TODO: MIN_TIMER_REARM_NS should be optimized */ @@ -195,83 +153,28 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) static int mm_start_timer(struct qemu_alarm_timer *t); static void mm_stop_timer(struct qemu_alarm_timer *t); -static void mm_rearm_timer(struct qemu_alarm_timer *t); +static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); static int win32_start_timer(struct qemu_alarm_timer *t); static void win32_stop_timer(struct qemu_alarm_timer *t); -static void win32_rearm_timer(struct qemu_alarm_timer *t); +static void win32_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); #else static int unix_start_timer(struct qemu_alarm_timer *t); static void unix_stop_timer(struct qemu_alarm_timer *t); -static void unix_rearm_timer(struct qemu_alarm_timer *t); +static void unix_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); #ifdef __linux__ static int dynticks_start_timer(struct qemu_alarm_timer *t); static void dynticks_stop_timer(struct qemu_alarm_timer *t); -static void dynticks_rearm_timer(struct qemu_alarm_timer *t); +static void dynticks_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); #endif /* __linux__ */ #endif /* _WIN32 */ -/* Correlation between real and virtual time is always going to be - fairly approximate, so ignore small variation. - When the guest is idle real and virtual time will be aligned in - the IO wait loop. */ -#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10) - -static void icount_adjust(void) -{ - int64_t cur_time; - int64_t cur_icount; - int64_t delta; - static int64_t last_delta; - /* If the VM is not running, then do nothing. */ - if (!runstate_is_running()) - return; - - cur_time = cpu_get_clock(); - cur_icount = qemu_get_clock_ns(vm_clock); - delta = cur_icount - cur_time; - /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ - if (delta > 0 - && last_delta + ICOUNT_WOBBLE < delta * 2 - && icount_time_shift > 0) { - /* The guest is getting too far ahead. Slow time down. */ - icount_time_shift--; - } - if (delta < 0 - && last_delta - ICOUNT_WOBBLE > delta * 2 - && icount_time_shift < MAX_ICOUNT_SHIFT) { - /* The guest is getting too far behind. Speed time up. */ - icount_time_shift++; - } - last_delta = delta; - qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); -} - -static void icount_adjust_rt(void * opaque) -{ - qemu_mod_timer(icount_rt_timer, - qemu_get_clock_ms(rt_clock) + 1000); - icount_adjust(); -} - -static void icount_adjust_vm(void * opaque) -{ - qemu_mod_timer(icount_vm_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); - icount_adjust(); -} - -int64_t qemu_icount_round(int64_t count) -{ - return (count + (1 << icount_time_shift) - 1) >> icount_time_shift; -} - static struct qemu_alarm_timer alarm_timers[] = { #ifndef _WIN32 #ifdef __linux__ @@ -352,14 +255,10 @@ next: } } -#define QEMU_NUM_CLOCKS 3 - QEMUClock *rt_clock; QEMUClock *vm_clock; QEMUClock *host_clock; -static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; - static QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; @@ -367,101 +266,43 @@ static QEMUClock *qemu_new_clock(int type) clock = g_malloc0(sizeof(QEMUClock)); clock->type = type; clock->enabled = 1; + clock->last = INT64_MIN; notifier_list_init(&clock->reset_notifiers); - /* required to detect & report backward jumps */ - if (type == QEMU_CLOCK_HOST) { - clock->last = get_clock_realtime(); - } return clock; } void qemu_clock_enable(QEMUClock *clock, int enabled) { + bool old = clock->enabled; clock->enabled = enabled; + if (enabled && !old) { + qemu_rearm_alarm_timer(alarm_timer); + } } -static int64_t vm_clock_warp_start; - -static void icount_warp_rt(void *opaque) +int64_t qemu_clock_has_timers(QEMUClock *clock) { - if (vm_clock_warp_start == -1) { - return; - } - - if (runstate_is_running()) { - int64_t clock = qemu_get_clock_ns(rt_clock); - int64_t warp_delta = clock - vm_clock_warp_start; - if (use_icount == 1) { - qemu_icount_bias += warp_delta; - } else { - /* - * In adaptive mode, do not let the vm_clock run too - * far ahead of real time. - */ - int64_t cur_time = cpu_get_clock(); - int64_t cur_icount = qemu_get_clock_ns(vm_clock); - int64_t delta = cur_time - cur_icount; - qemu_icount_bias += MIN(warp_delta, delta); - } - if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], - qemu_get_clock_ns(vm_clock))) { - qemu_notify_event(); - } - } - vm_clock_warp_start = -1; + return !!clock->active_timers; } -void qemu_clock_warp(QEMUClock *clock) +int64_t qemu_clock_expired(QEMUClock *clock) { - int64_t deadline; + return (clock->active_timers && + clock->active_timers->expire_time < qemu_get_clock_ns(clock)); +} - if (!clock->warp_timer) { - return; - } +int64_t qemu_clock_deadline(QEMUClock *clock) +{ + /* To avoid problems with overflow limit this to 2^32. */ + int64_t delta = INT32_MAX; - /* - * There are too many global variables to make the "warp" behavior - * applicable to other clocks. But a clock argument removes the - * need for if statements all over the place. - */ - assert(clock == vm_clock); - - /* - * If the CPUs have been sleeping, advance the vm_clock timer now. This - * ensures that the deadline for the timer is computed correctly below. - * This also makes sure that the insn counter is synchronized before the - * CPU starts running, in case the CPU is woken by an event other than - * the earliest vm_clock timer. - */ - icount_warp_rt(NULL); - if (!all_cpu_threads_idle() || !active_timers[clock->type]) { - qemu_del_timer(clock->warp_timer); - return; + if (clock->active_timers) { + delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock); } - - vm_clock_warp_start = qemu_get_clock_ns(rt_clock); - deadline = qemu_next_icount_deadline(); - if (deadline > 0) { - /* - * Ensure the vm_clock proceeds even when the virtual CPU goes to - * sleep. Otherwise, the CPU might be waiting for a future timer - * interrupt to wake it up, but the interrupt never comes because - * the vCPU isn't running any insns and thus doesn't advance the - * vm_clock. - * - * An extreme solution for this problem would be to never let VCPUs - * sleep in icount mode if there is a pending vm_clock timer; rather - * time could just advance to the next vm_clock event. Instead, we - * do stop VCPUs and only advance vm_clock after some "real" time, - * (related to the time left until the next event) has passed. This - * rt_clock timer will do this. This avoids that the warps are too - * visible externally---for example, you will not be sending network - * packets continously instead of every 100ms. - */ - qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline); - } else { - qemu_notify_event(); + if (delta < 0) { + delta = 0; } + return delta; } QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, @@ -489,7 +330,7 @@ void qemu_del_timer(QEMUTimer *ts) /* NOTE: this code must be signal safe because qemu_timer_expired() can be called from a signal. */ - pt = &active_timers[ts->clock->type]; + pt = &ts->clock->active_timers; for(;;) { t = *pt; if (!t) @@ -504,7 +345,7 @@ void qemu_del_timer(QEMUTimer *ts) /* modify the current timer so that it will be fired when current_time >= expire_time. The corresponding callback will be called. */ -static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) +void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) { QEMUTimer **pt, *t; @@ -513,7 +354,7 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) /* add the timer in the sorted list */ /* NOTE: this code must be signal safe because qemu_timer_expired() can be called from a signal. */ - pt = &active_timers[ts->clock->type]; + pt = &ts->clock->active_timers; for(;;) { t = *pt; if (!qemu_timer_expired_ns(t, expire_time)) { @@ -526,7 +367,7 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) *pt = ts; /* Rearm if necessary */ - if (pt == &active_timers[ts->clock->type]) { + if (pt == &ts->clock->active_timers) { if (!alarm_timer->pending) { qemu_rearm_alarm_timer(alarm_timer); } @@ -538,8 +379,6 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) } } -/* modify the current timer so that it will be fired when current_time - >= expire_time. The corresponding callback will be called. */ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) { qemu_mod_timer_ns(ts, expire_time * ts->scale); @@ -548,7 +387,7 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) int qemu_timer_pending(QEMUTimer *ts) { QEMUTimer *t; - for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) { + for (t = ts->clock->active_timers; t != NULL; t = t->next) { if (t == ts) return 1; } @@ -569,7 +408,7 @@ static void qemu_run_timers(QEMUClock *clock) return; current_time = qemu_get_clock_ns(clock); - ptimer_head = &active_timers[clock->type]; + ptimer_head = &clock->active_timers; for(;;) { ts = *ptimer_head; if (!qemu_timer_expired_ns(ts, current_time)) { @@ -624,79 +463,11 @@ void init_clocks(void) rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); host_clock = qemu_new_clock(QEMU_CLOCK_HOST); - - rtc_clock = host_clock; } -/* save a timer */ -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts) { - uint64_t expire_time; - - if (qemu_timer_pending(ts)) { - expire_time = ts->expire_time; - } else { - expire_time = -1; - } - qemu_put_be64(f, expire_time); -} - -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) -{ - uint64_t expire_time; - - expire_time = qemu_get_be64(f); - if (expire_time != -1) { - qemu_mod_timer_ns(ts, expire_time); - } else { - qemu_del_timer(ts); - } -} - -static const VMStateDescription vmstate_timers = { - .name = "timer", - .version_id = 2, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT64(cpu_ticks_offset, TimersState), - VMSTATE_INT64(dummy, TimersState), - VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), - VMSTATE_END_OF_LIST() - } -}; - -void configure_icount(const char *option) -{ - vmstate_register(NULL, 0, &vmstate_timers, &timers_state); - if (!option) - return; - - vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL); - - if (strcmp(option, "auto") != 0) { - icount_time_shift = strtol(option, NULL, 0); - use_icount = 1; - return; - } - - use_icount = 2; - - /* 125MIPS seems a reasonable initial guess at the guest speed. - It will be corrected fairly quickly anyway. */ - icount_time_shift = 3; - - /* Have both realtime and virtual time triggers for speed adjustment. - The realtime trigger catches emulated time passing too slowly, - the virtual time trigger catches emulated time passing too fast. - Realtime triggers occur even when idle, so use them less frequently - than VM triggers. */ - icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL); - qemu_mod_timer(icount_rt_timer, - qemu_get_clock_ms(rt_clock) + 1000); - icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL); - qemu_mod_timer(icount_vm_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); + return qemu_timer_pending(ts) ? ts->expire_time : -1; } void qemu_run_all_timers(void) @@ -710,16 +481,11 @@ void qemu_run_all_timers(void) } /* vm time timers */ - if (runstate_is_running()) { - qemu_run_timers(vm_clock); - } - + qemu_run_timers(vm_clock); qemu_run_timers(rt_clock); qemu_run_timers(host_clock); } -static int64_t qemu_next_alarm_deadline(void); - #ifdef _WIN32 static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused) #else @@ -767,50 +533,6 @@ static void host_alarm_handler(int host_signum) } } -int64_t qemu_next_icount_deadline(void) -{ - /* To avoid problems with overflow limit this to 2^32. */ - int64_t delta = INT32_MAX; - - assert(use_icount); - if (active_timers[QEMU_CLOCK_VIRTUAL]) { - delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - - qemu_get_clock_ns(vm_clock); - } - - if (delta < 0) - delta = 0; - - return delta; -} - -static int64_t qemu_next_alarm_deadline(void) -{ - int64_t delta; - int64_t rtdelta; - - if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) { - delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - - qemu_get_clock_ns(vm_clock); - } else { - delta = INT32_MAX; - } - if (active_timers[QEMU_CLOCK_HOST]) { - int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - - qemu_get_clock_ns(host_clock); - if (hdelta < delta) - delta = hdelta; - } - if (active_timers[QEMU_CLOCK_REALTIME]) { - rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - - qemu_get_clock_ns(rt_clock)); - if (rtdelta < delta) - delta = rtdelta; - } - - return delta; -} - #if defined(__linux__) #include "compatfd.h" @@ -863,20 +585,13 @@ static void dynticks_stop_timer(struct qemu_alarm_timer *t) timer_delete(host_timer); } -static void dynticks_rearm_timer(struct qemu_alarm_timer *t) +static void dynticks_rearm_timer(struct qemu_alarm_timer *t, + int64_t nearest_delta_ns) { timer_t host_timer = t->timer; struct itimerspec timeout; - int64_t nearest_delta_ns = INT64_MAX; int64_t current_ns; - assert(alarm_has_dynticks(t)); - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - nearest_delta_ns = qemu_next_alarm_deadline(); if (nearest_delta_ns < MIN_TIMER_REARM_NS) nearest_delta_ns = MIN_TIMER_REARM_NS; @@ -918,19 +633,12 @@ static int unix_start_timer(struct qemu_alarm_timer *t) return 0; } -static void unix_rearm_timer(struct qemu_alarm_timer *t) +static void unix_rearm_timer(struct qemu_alarm_timer *t, + int64_t nearest_delta_ns) { struct itimerval itv; - int64_t nearest_delta_ns = INT64_MAX; int err; - assert(alarm_has_dynticks(t)); - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - nearest_delta_ns = qemu_next_alarm_deadline(); if (nearest_delta_ns < MIN_TIMER_REARM_NS) nearest_delta_ns = MIN_TIMER_REARM_NS; @@ -1017,23 +725,14 @@ static void mm_stop_timer(struct qemu_alarm_timer *t) timeEndPeriod(mm_period); } -static void mm_rearm_timer(struct qemu_alarm_timer *t) +static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta) { - int nearest_delta_ms; - - assert(alarm_has_dynticks(t)); - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) { - return; - } - - timeKillEvent(mm_timer); - - nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000; + int nearest_delta_ms = (delta + 999999) / 1000000; if (nearest_delta_ms < 1) { nearest_delta_ms = 1; } + + timeKillEvent(mm_timer); mm_timer = timeSetEvent(nearest_delta_ms, mm_period, mm_alarm_handler, @@ -1085,19 +784,14 @@ static void win32_stop_timer(struct qemu_alarm_timer *t) } } -static void win32_rearm_timer(struct qemu_alarm_timer *t) +static void win32_rearm_timer(struct qemu_alarm_timer *t, + int64_t nearest_delta_ns) { HANDLE hTimer = t->timer; int nearest_delta_ms; BOOLEAN success; - assert(alarm_has_dynticks(t)); - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000; + nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000; if (nearest_delta_ms < 1) { nearest_delta_ms = 1; } @@ -1116,11 +810,11 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t) #endif /* _WIN32 */ -static void alarm_timer_on_change_state_rearm(void *opaque, int running, - RunState state) +static void quit_timers(void) { - if (running) - qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque); + struct qemu_alarm_timer *t = alarm_timer; + alarm_timer = NULL; + t->stop(t); } int init_timer_alarm(void) @@ -1142,9 +836,9 @@ int init_timer_alarm(void) } /* first event is at time 0 */ + atexit(quit_timers); t->pending = 1; alarm_timer = t; - qemu_add_vm_change_state_handler(alarm_timer_on_change_state_rearm, t); return 0; @@ -1152,13 +846,6 @@ fail: return err; } -void quit_timers(void) -{ - struct qemu_alarm_timer *t = alarm_timer; - alarm_timer = NULL; - t->stop(t); -} - int qemu_calculate_timeout(void) { return 1000; diff --git a/qemu-timer.h b/qemu-timer.h index 0a43469847..67ca72e045 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -2,6 +2,7 @@ #define QEMU_TIMER_H #include "qemu-common.h" +#include "main-loop.h" #include "notify.h" #include <time.h> #include <sys/time.h> @@ -38,6 +39,9 @@ extern QEMUClock *vm_clock; extern QEMUClock *host_clock; int64_t qemu_get_clock_ns(QEMUClock *clock); +int64_t qemu_clock_has_timers(QEMUClock *clock); +int64_t qemu_clock_expired(QEMUClock *clock); +int64_t qemu_clock_deadline(QEMUClock *clock); void qemu_clock_enable(QEMUClock *clock, int enabled); void qemu_clock_warp(QEMUClock *clock); @@ -49,19 +53,18 @@ QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimerCB *cb, void *opaque); void qemu_free_timer(QEMUTimer *ts); void qemu_del_timer(QEMUTimer *ts); +void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time); void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); int qemu_timer_pending(QEMUTimer *ts); int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); +uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts); void qemu_run_all_timers(void); int qemu_alarm_pending(void); -int64_t qemu_next_icount_deadline(void); void configure_alarms(char const *opt); -void configure_icount(const char *option); int qemu_calculate_timeout(void); void init_clocks(void); int init_timer_alarm(void); -void quit_timers(void); int64_t cpu_get_ticks(void); void cpu_enable_ticks(void); @@ -150,12 +153,8 @@ void ptimer_run(ptimer_state *s, int oneshot); void ptimer_stop(ptimer_state *s); /* icount */ -int64_t qemu_icount_round(int64_t count); -extern int64_t qemu_icount; -extern int use_icount; -extern int icount_time_shift; -extern int64_t qemu_icount_bias; int64_t cpu_get_icount(void); +int64_t cpu_get_clock(void); /*******************************************/ /* host CPU ticks (if available) */ @@ -311,22 +310,6 @@ static inline int64_t cpu_get_real_ticks (void) } #endif -#ifdef NEED_CPU_H -/* Deterministic execution requires that IO only be performed on the last - instruction of a TB so that interrupts take effect immediately. */ -static inline int can_do_io(CPUState *env) -{ - if (!use_icount) - return 1; - - /* If not executing code then assume we are ok. */ - if (!env->current_tb) - return 1; - - return env->can_do_io != 0; -} -#endif - #ifdef CONFIG_PROFILER static inline int64_t profile_getclock(void) { diff --git a/qemu_socket.h b/qemu_socket.h index 180e4dbd9b..9e32fac651 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -35,6 +35,7 @@ int inet_aton(const char *cp, struct in_addr *ia); /* misc helpers */ int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +void socket_set_block(int fd); void socket_set_nonblock(int fd); int send_all(int fd, const void *buf, int len1); diff --git a/qmp-commands.hx b/qmp-commands.hx index 9c11e87ddb..4328e8b86c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -710,10 +710,10 @@ Arguments: Example: --> { "execute": "blockdev-snapshot", "arguments": { "device": "ide-hd0", - "snapshot-file": - "/some/place/my-image", - "format": "qcow2" } } +-> { "execute": "blockdev-snapshot-sync", "arguments": { "device": "ide-hd0", + "snapshot-file": + "/some/place/my-image", + "format": "qcow2" } } <- { "return": {} } EQMP @@ -81,6 +81,7 @@ #include "migration.h" #include "qemu_socket.h" #include "qemu-queue.h" +#include "qemu-timer.h" #include "cpus.h" #define SELF_ANNOUNCE_ROUNDS 5 @@ -173,7 +174,7 @@ struct QEMUFile { int buf_size; /* 0 when writing */ uint8_t buf[IO_BUF_SIZE]; - int has_error; + int last_error; }; typedef struct QEMUFileStdio @@ -425,14 +426,14 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, return f; } -int qemu_file_has_error(QEMUFile *f) +int qemu_file_get_error(QEMUFile *f) { - return f->has_error; + return f->last_error; } -void qemu_file_set_error(QEMUFile *f) +void qemu_file_set_error(QEMUFile *f, int ret) { - f->has_error = 1; + f->last_error = ret; } void qemu_fflush(QEMUFile *f) @@ -447,7 +448,7 @@ void qemu_fflush(QEMUFile *f) if (len > 0) f->buf_offset += f->buf_index; else - f->has_error = 1; + f->last_error = -EINVAL; f->buf_index = 0; } } @@ -455,6 +456,7 @@ void qemu_fflush(QEMUFile *f) static void qemu_fill_buffer(QEMUFile *f) { int len; + int pending; if (!f->get_buffer) return; @@ -462,13 +464,20 @@ static void qemu_fill_buffer(QEMUFile *f) if (f->is_write) abort(); - len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); + pending = f->buf_size - f->buf_index; + if (pending > 0) { + memmove(f->buf, f->buf + f->buf_index, pending); + } + f->buf_index = 0; + f->buf_size = pending; + + len = f->get_buffer(f->opaque, f->buf + pending, f->buf_offset, + IO_BUF_SIZE - pending); if (len > 0) { - f->buf_index = 0; - f->buf_size = len; + f->buf_size += len; f->buf_offset += len; } else if (len != -EAGAIN) - f->has_error = 1; + f->last_error = len; } int qemu_fclose(QEMUFile *f) @@ -490,13 +499,13 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) { int l; - if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { + if (!f->last_error && f->is_write == 0 && f->buf_index > 0) { fprintf(stderr, "Attempted to write to buffer while read buffer is not empty\n"); abort(); } - while (!f->has_error && size > 0) { + while (!f->last_error && size > 0) { l = IO_BUF_SIZE - f->buf_index; if (l > size) l = size; @@ -512,7 +521,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) void qemu_put_byte(QEMUFile *f, int v) { - if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { + if (!f->last_error && f->is_write == 0 && f->buf_index > 0) { fprintf(stderr, "Attempted to write to buffer while read buffer is not empty\n"); abort(); @@ -524,56 +533,86 @@ void qemu_put_byte(QEMUFile *f, int v) qemu_fflush(f); } -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) +static void qemu_file_skip(QEMUFile *f, int size) { - int size, l; + if (f->buf_index + size <= f->buf_size) { + f->buf_index += size; + } +} - if (f->is_write) +static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) +{ + int pending; + int index; + + if (f->is_write) { abort(); + } - size = size1; - while (size > 0) { - l = f->buf_size - f->buf_index; - if (l == 0) { - qemu_fill_buffer(f); - l = f->buf_size - f->buf_index; - if (l == 0) - break; + index = f->buf_index + offset; + pending = f->buf_size - index; + if (pending < size) { + qemu_fill_buffer(f); + index = f->buf_index + offset; + pending = f->buf_size - index; + } + + if (pending <= 0) { + return 0; + } + if (size > pending) { + size = pending; + } + + memcpy(buf, f->buf + index, size); + return size; +} + +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) +{ + int pending = size; + int done = 0; + + while (pending > 0) { + int res; + + res = qemu_peek_buffer(f, buf, pending, 0); + if (res == 0) { + return done; } - if (l > size) - l = size; - memcpy(buf, f->buf + f->buf_index, l); - f->buf_index += l; - buf += l; - size -= l; + qemu_file_skip(f, res); + buf += res; + pending -= res; + done += res; } - return size1 - size; + return done; } -static int qemu_peek_byte(QEMUFile *f) +static int qemu_peek_byte(QEMUFile *f, int offset) { - if (f->is_write) + int index = f->buf_index + offset; + + if (f->is_write) { abort(); + } - if (f->buf_index >= f->buf_size) { + if (index >= f->buf_size) { qemu_fill_buffer(f); - if (f->buf_index >= f->buf_size) + index = f->buf_index + offset; + if (index >= f->buf_size) { return 0; + } } - return f->buf[f->buf_index]; + return f->buf[index]; } int qemu_get_byte(QEMUFile *f) { - if (f->is_write) - abort(); + int result; - if (f->buf_index >= f->buf_size) { - qemu_fill_buffer(f); - if (f->buf_index >= f->buf_size) - return 0; - } - return f->buf[f->buf_index++]; + result = qemu_peek_byte(f, 0); + qemu_file_skip(f, 1); + return result; } int64_t qemu_ftell(QEMUFile *f) @@ -674,6 +713,30 @@ uint64_t qemu_get_be64(QEMUFile *f) return v; } + +/* timer */ + +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +{ + uint64_t expire_time; + + expire_time = qemu_timer_expire_time_ns(ts); + qemu_put_be64(f, expire_time); +} + +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) +{ + uint64_t expire_time; + + expire_time = qemu_get_be64(f); + if (expire_time != -1) { + qemu_mod_timer_ns(ts, expire_time); + } else { + qemu_del_timer(ts); + } +} + + /* bool */ static int get_bool(QEMUFile *f, void *pv, size_t size) @@ -1466,6 +1529,7 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, int shared) { SaveStateEntry *se; + int ret; QTAILQ_FOREACH(se, &savevm_handlers, entry) { if(se->set_params == NULL) { @@ -1495,17 +1559,27 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, qemu_put_be32(f, se->instance_id); qemu_put_be32(f, se->version_id); - se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque); + ret = se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque); + if (ret < 0) { + qemu_savevm_state_cancel(mon, f); + return ret; + } } - - if (qemu_file_has_error(f)) { + ret = qemu_file_get_error(f); + if (ret != 0) { qemu_savevm_state_cancel(mon, f); - return -EIO; } - return 0; + return ret; + } +/* + * this funtion has three return values: + * negative: there was one error, and we have -errno. + * 0 : We haven't finished, caller have to go again + * 1 : We have finished, we can go to complete phase + */ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; @@ -1520,7 +1594,7 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f) qemu_put_be32(f, se->section_id); ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque); - if (!ret) { + if (ret <= 0) { /* Do not proceed to the next vmstate before this one reported completion of the current stage. This serializes the migration and reduces the probability that a faster changing state is @@ -1528,21 +1602,20 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f) break; } } - - if (ret) - return 1; - - if (qemu_file_has_error(f)) { + if (ret != 0) { + return ret; + } + ret = qemu_file_get_error(f); + if (ret != 0) { qemu_savevm_state_cancel(mon, f); - return -EIO; } - - return 0; + return ret; } int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; + int ret; cpu_synchronize_all_states(); @@ -1554,7 +1627,10 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_END); qemu_put_be32(f, se->section_id); - se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque); + ret = se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque); + if (ret < 0) { + return ret; + } } QTAILQ_FOREACH(se, &savevm_handlers, entry) { @@ -1580,10 +1656,7 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f) qemu_put_byte(f, QEMU_VM_EOF); - if (qemu_file_has_error(f)) - return -EIO; - - return 0; + return qemu_file_get_error(f); } void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f) @@ -1599,12 +1672,8 @@ void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f) static int qemu_savevm_state(Monitor *mon, QEMUFile *f) { - int saved_vm_running; int ret; - saved_vm_running = runstate_is_running(); - vm_stop(RUN_STATE_SAVE_VM); - if (qemu_savevm_state_blocked(mon)) { ret = -EINVAL; goto out; @@ -1623,11 +1692,9 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f) ret = qemu_savevm_state_complete(mon, f); out: - if (qemu_file_has_error(f)) - ret = -EIO; - - if (!ret && saved_vm_running) - vm_start(); + if (ret == 0) { + ret = qemu_file_get_error(f); + } return ret; } @@ -1666,29 +1733,36 @@ static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { - const VMStateSubsection *sub = vmsd->subsections; - - if (!sub || !sub->needed) { - return 0; - } - - while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) { + while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) { char idstr[256]; int ret; - uint8_t version_id, len; + uint8_t version_id, len, size; const VMStateDescription *sub_vmsd; - qemu_get_byte(f); /* subsection */ - len = qemu_get_byte(f); - qemu_get_buffer(f, (uint8_t *)idstr, len); - idstr[len] = 0; - version_id = qemu_get_be32(f); + len = qemu_peek_byte(f, 1); + if (len < strlen(vmsd->name) + 1) { + /* subsection name has be be "section_name/a" */ + return 0; + } + size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2); + if (size != len) { + return 0; + } + idstr[size] = 0; - sub_vmsd = vmstate_get_subsection(sub, idstr); + if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) { + /* it don't have a valid subsection name */ + return 0; + } + sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr); if (sub_vmsd == NULL) { return -ENOENT; } - assert(!sub_vmsd->subsections); + qemu_file_skip(f, 1); /* subsection */ + qemu_file_skip(f, 1); /* len */ + qemu_file_skip(f, len); /* idstr */ + version_id = qemu_get_be32(f); + ret = vmstate_load_state(f, sub_vmsd, opaque, version_id); if (ret) { return ret; @@ -1712,7 +1786,6 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)vmsd->name, len); qemu_put_be32(f, vmsd->version_id); - assert(!vmsd->subsections); vmstate_save_state(f, vmsd, opaque); } sub++; @@ -1838,8 +1911,9 @@ out: g_free(le); } - if (qemu_file_has_error(f)) - ret = -EIO; + if (ret == 0) { + ret = qemu_file_get_error(f); + } return ret; } diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py new file mode 100755 index 0000000000..4358d6b594 --- /dev/null +++ b/scripts/analyse-9p-simpletrace.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# Pretty print 9p simpletrace log +# Usage: ./analyse-9p-simpletrace <trace-events> <trace-pid> +# +# Author: Harsh Prateek Bora + +import simpletrace + +class VirtFSRequestTracker(simpletrace.Analyzer): + def begin(self): + print "Pretty printing 9p simpletrace log ..." + + def complete_pdu(self, tag, id, err): + print "ERROR (tag =", tag, ", id =", id, ",err =", err, ")" + + def v9fs_version(self, tag, id, msize, version): + print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")" + + def v9fs_version_return(self, tag, id, msize, version): + print "RVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")" + + def v9fs_attach(self, tag, id, fid, afid, uname, aname): + print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")" + + def v9fs_attach_return(self, tag, id, type, verison, path): + print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})" + + def v9fs_stat(self, tag, id, fid): + print "TSTAT (tag =", tag, ", fid =", fid, ")" + + def v9fs_stat_return(self, tag, id, mode, atime, mtime, length): + print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")" + + def v9fs_getattr(self, tag, id, fid, request_mask): + print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")" + + def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid): + print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")" + + def v9fs_walk(self, tag, id, fid, newfid, nwnames): + print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")" + + def v9fs_walk_return(self, tag, id, nwnames, qids): + print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")" + + def v9fs_open(self, tag, id, fid, mode): + print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")" + + def v9fs_open_return(self, tag, id, type, version, path, iounit): + print "ROPEN (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")" + + def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid): + print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")" + + def v9fs_lcreate_return(self, id, type, version, path, iounit): + print "RLCREATE (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")" + + def v9fs_fsync(self, tag, id, fid, datasync): + print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")" + + def v9fs_clunk(self, tag, id, fid): + print "TCLUNK (tag =", tag, ", fid =", fid, ")" + + def v9fs_read(self, tag, id, fid, off, max_count): + print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")" + + def v9fs_read_return(self, tag, id, count, err): + print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")" + + def v9fs_readdir(self, tag, id, fid, offset, max_count): + print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")" + + def v9fs_readdir_return(self, tag, id, count, retval): + print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")" + + def v9fs_write(self, tag, id, fid, off, count, cnt): + print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")" + + def v9fs_write_return(self, tag, id, total, err): + print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")" + + def v9fs_create(self, tag, id, fid, perm, name, mode): + print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")" + + def v9fs_create_return(self, tag, id, type, verison, path, iounit): + print "RCREATE (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")" + + def v9fs_symlink(self, tag, id, fid, name, symname, gid): + print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")" + + def v9fs_symlink_return(self, tag, id, type, version, path): + print "RSYMLINK (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})" + + def v9fs_flush(self, tag, id, flush_tag): + print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")" + + def v9fs_link(self, tag, id, dfid, oldfid, name): + print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")" + + def v9fs_remove(self, tag, id, fid): + print "TREMOVE (tag =", tag, ", fid =", fid, ")" + + def v9fs_wstat(self, tag, id, fid, mode, atime, mtime): + print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")" + + def v9fs_mknod(self, tag, id, fid, mode, major, minor): + print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")" + + def v9fs_lock(self, tag, id, fid, type, start, length): + print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")" + + def v9fs_lock_return(self, tag, id, status): + print "RLOCK (tag =", tag, ", status =", status, ")" + + def v9fs_getlock(self, tag, id, fid, type, start, length): + print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")" + + def v9fs_getlock_return(self, tag, id, type, start, length, proc_id): + print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id, ")" + + def v9fs_mkdir(self, tag, id, fid, name, mode, gid): + print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")" + + def v9fs_mkdir_return(self, tag, id, type, version, path, err): + print "RMKDIR (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")" + + def v9fs_xattrwalk(self, tag, id, fid, newfid, name): + print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")" + + def v9fs_xattrwalk_return(self, tag, id, size): + print "RXATTRWALK (tag =", tag, ", xattrsize =", size, ")" + + def v9fs_xattrcreate(self, tag, id, fid, name, size, flags): + print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")" + + def v9fs_readlink(self, tag, id, fid): + print "TREADLINK (tag =", tag, ", fid =", fid, ")" + + def v9fs_readlink_return(self, tag, id, target): + print "RREADLINK (tag =", tag, ", target =", target, ")" + +simpletrace.run(VirtFSRequestTracker()) diff --git a/slirp/libslirp.h b/slirp/libslirp.h index a7551235e2..890fd86c3c 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -3,8 +3,6 @@ #include "qemu-common.h" -#ifdef CONFIG_SLIRP - struct Slirp; typedef struct Slirp Slirp; @@ -44,13 +42,4 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port); -#else /* !CONFIG_SLIRP */ - -static inline void slirp_select_fill(int *pnfds, fd_set *readfds, - fd_set *writefds, fd_set *xfds) { } - -static inline void slirp_select_poll(fd_set *readfds, fd_set *writefds, - fd_set *xfds, int select_error) { } -#endif /* !CONFIG_SLIRP */ - #endif @@ -8,6 +8,7 @@ #include "qemu-timer.h" #include "qapi-types.h" #include "notify.h" +#include "main-loop.h" /* vl.c */ @@ -35,6 +36,7 @@ void vm_state_notify(int running, RunState state); void vm_start(void); void vm_stop(RunState state); +void vm_stop_force_state(RunState state); void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); @@ -63,8 +65,6 @@ void do_info_snapshots(Monitor *mon); void qemu_announce_self(void); -int main_loop_wait(int nonblocking); - bool qemu_savevm_state_blocked(Monitor *mon); int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, int shared); diff --git a/target-sparc/cc_helper.c b/target-sparc/cc_helper.c new file mode 100644 index 0000000000..04bd2cf9c7 --- /dev/null +++ b/target-sparc/cc_helper.c @@ -0,0 +1,485 @@ +/* + * Helpers for lazy condition code handling + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "helper.h" + +static uint32_t compute_all_flags(CPUState *env) +{ + return env->psr & PSR_ICC; +} + +static uint32_t compute_C_flags(CPUState *env) +{ + return env->psr & PSR_CARRY; +} + +static inline uint32_t get_NZ_icc(int32_t dst) +{ + uint32_t ret = 0; + + if (dst == 0) { + ret = PSR_ZERO; + } else if (dst < 0) { + ret = PSR_NEG; + } + return ret; +} + +#ifdef TARGET_SPARC64 +static uint32_t compute_all_flags_xcc(CPUState *env) +{ + return env->xcc & PSR_ICC; +} + +static uint32_t compute_C_flags_xcc(CPUState *env) +{ + return env->xcc & PSR_CARRY; +} + +static inline uint32_t get_NZ_xcc(target_long dst) +{ + uint32_t ret = 0; + + if (!dst) { + ret = PSR_ZERO; + } else if (dst < 0) { + ret = PSR_NEG; + } + return ret; +} +#endif + +static inline uint32_t get_V_div_icc(target_ulong src2) +{ + uint32_t ret = 0; + + if (src2 != 0) { + ret = PSR_OVF; + } + return ret; +} + +static uint32_t compute_all_div(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_V_div_icc(CC_SRC2); + return ret; +} + +static uint32_t compute_C_div(CPUState *env) +{ + return 0; +} + +static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1) +{ + uint32_t ret = 0; + + if (dst < src1) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1, + uint32_t src2) +{ + uint32_t ret = 0; + + if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1, + uint32_t src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) { + ret = PSR_OVF; + } + return ret; +} + +#ifdef TARGET_SPARC64 +static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1) +{ + uint32_t ret = 0; + + if (dst < src1) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) { + ret = PSR_OVF; + } + return ret; +} + +static uint32_t compute_all_add_xcc(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_xcc(CC_DST); + ret |= get_C_add_xcc(CC_DST, CC_SRC); + ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_add_xcc(CPUState *env) +{ + return get_C_add_xcc(CC_DST, CC_SRC); +} +#endif + +static uint32_t compute_all_add(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_add_icc(CC_DST, CC_SRC); + ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_add(CPUState *env) +{ + return get_C_add_icc(CC_DST, CC_SRC); +} + +#ifdef TARGET_SPARC64 +static uint32_t compute_all_addx_xcc(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_xcc(CC_DST); + ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_addx_xcc(CPUState *env) +{ + uint32_t ret; + + ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} +#endif + +static uint32_t compute_all_addx(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_addx(CPUState *env) +{ + uint32_t ret; + + ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2) +{ + uint32_t ret = 0; + + if ((src1 | src2) & 0x3) { + ret = PSR_OVF; + } + return ret; +} + +static uint32_t compute_all_tadd(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_add_icc(CC_DST, CC_SRC); + ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_tag_icc(CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_all_taddtv(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_add_icc(CC_DST, CC_SRC); + return ret; +} + +static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2) +{ + uint32_t ret = 0; + + if (src1 < src2) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1, + uint32_t src2) +{ + uint32_t ret = 0; + + if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1, + uint32_t src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) { + ret = PSR_OVF; + } + return ret; +} + + +#ifdef TARGET_SPARC64 +static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2) +{ + uint32_t ret = 0; + + if (src1 < src2) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) { + ret = PSR_OVF; + } + return ret; +} + +static uint32_t compute_all_sub_xcc(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_xcc(CC_DST); + ret |= get_C_sub_xcc(CC_SRC, CC_SRC2); + ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_sub_xcc(CPUState *env) +{ + return get_C_sub_xcc(CC_SRC, CC_SRC2); +} +#endif + +static uint32_t compute_all_sub(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_sub_icc(CC_SRC, CC_SRC2); + ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_sub(CPUState *env) +{ + return get_C_sub_icc(CC_SRC, CC_SRC2); +} + +#ifdef TARGET_SPARC64 +static uint32_t compute_all_subx_xcc(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_xcc(CC_DST); + ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_subx_xcc(CPUState *env) +{ + uint32_t ret; + + ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} +#endif + +static uint32_t compute_all_subx(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_subx(CPUState *env) +{ + uint32_t ret; + + ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_all_tsub(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_sub_icc(CC_SRC, CC_SRC2); + ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_tag_icc(CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_all_tsubtv(CPUState *env) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_sub_icc(CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_all_logic(CPUState *env) +{ + return get_NZ_icc(CC_DST); +} + +static uint32_t compute_C_logic(CPUState *env) +{ + return 0; +} + +#ifdef TARGET_SPARC64 +static uint32_t compute_all_logic_xcc(CPUState *env) +{ + return get_NZ_xcc(CC_DST); +} +#endif + +typedef struct CCTable { + uint32_t (*compute_all)(CPUState *env); /* return all the flags */ + uint32_t (*compute_c)(CPUState *env); /* return the C flag */ +} CCTable; + +static const CCTable icc_table[CC_OP_NB] = { + /* CC_OP_DYNAMIC should never happen */ + [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags }, + [CC_OP_DIV] = { compute_all_div, compute_C_div }, + [CC_OP_ADD] = { compute_all_add, compute_C_add }, + [CC_OP_ADDX] = { compute_all_addx, compute_C_addx }, + [CC_OP_TADD] = { compute_all_tadd, compute_C_add }, + [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add }, + [CC_OP_SUB] = { compute_all_sub, compute_C_sub }, + [CC_OP_SUBX] = { compute_all_subx, compute_C_subx }, + [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub }, + [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub }, + [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic }, +}; + +#ifdef TARGET_SPARC64 +static const CCTable xcc_table[CC_OP_NB] = { + /* CC_OP_DYNAMIC should never happen */ + [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc }, + [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic }, + [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc }, + [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc }, + [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc }, + [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc }, + [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, + [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc }, + [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, + [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc }, + [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic }, +}; +#endif + +void helper_compute_psr(CPUState *env) +{ + uint32_t new_psr; + + new_psr = icc_table[CC_OP].compute_all(env); + env->psr = new_psr; +#ifdef TARGET_SPARC64 + new_psr = xcc_table[CC_OP].compute_all(env); + env->xcc = new_psr; +#endif + CC_OP = CC_OP_FLAGS; +} + +uint32_t helper_compute_C_icc(CPUState *env) +{ + uint32_t ret; + + ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT; + return ret; +} diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 19de5ba334..25b4f1a1dc 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -335,6 +335,27 @@ enum { #define SFSR_CT_NOTRANS (3ULL << 4) #define SFSR_CT_MASK (3ULL << 4) +/* Leon3 cache control */ + +/* Cache control: emulate the behavior of cache control registers but without + any effect on the emulated */ + +#define CACHE_STATE_MASK 0x3 +#define CACHE_DISABLED 0x0 +#define CACHE_FROZEN 0x1 +#define CACHE_ENABLED 0x3 + +/* Cache Control register fields */ + +#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */ +#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */ +#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */ +#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */ +#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */ +#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */ +#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */ +#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */ + typedef struct SparcTLBEntry { uint64_t tag; uint64_t tte; @@ -478,17 +499,18 @@ typedef struct CPUSPARCState { sparc_def_t *def; void *irq_manager; - void (*qemu_irq_ack) (void *irq_manager, int intno); + void (*qemu_irq_ack)(CPUState *env, void *irq_manager, int intno); /* Leon3 cache control */ uint32_t cache_control; } CPUSPARCState; #ifndef NO_CPU_IO_DEFS -/* helper.c */ +/* cpu_init.c */ CPUSPARCState *cpu_sparc_init(const char *cpu_model); void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu); void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf); +/* mmu_helper.c */ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw, int mmu_idx); #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault @@ -508,7 +530,7 @@ void gen_intermediate_code_init(CPUSPARCState *env); /* cpu-exec.c */ int cpu_sparc_exec(CPUSPARCState *s); -/* op_helper.c */ +/* win_helper.c */ target_ulong cpu_get_psr(CPUState *env1); void cpu_put_psr(CPUState *env1, target_ulong val); #ifdef TARGET_SPARC64 @@ -521,7 +543,10 @@ void cpu_change_pstate(CPUState *env1, uint32_t new_pstate); int cpu_cwp_inc(CPUState *env1, int cwp); int cpu_cwp_dec(CPUState *env1, int cwp); void cpu_set_cwp(CPUState *env1, int new_cwp); -void leon3_irq_manager(void *irq_manager, int intno); + +/* int_helper.c */ +void do_interrupt(CPUState *env); +void leon3_irq_manager(CPUState *env, void *irq_manager, int intno); /* sun4m.c, sun4u.c */ void cpu_check_irqs(CPUSPARCState *env); @@ -718,9 +743,6 @@ static inline bool tb_am_enabled(int tb_flags) #endif } -/* helper.c */ -void do_interrupt(CPUState *env); - static inline bool cpu_has_work(CPUState *env1) { return (env1->interrupt_request & CPU_INTERRUPT_HARD) && diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c new file mode 100644 index 0000000000..6954800af0 --- /dev/null +++ b/target-sparc/cpu_init.c @@ -0,0 +1,848 @@ +/* + * Sparc CPU init helpers + * + * Copyright (c) 2003-2005 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 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 "cpu.h" + +//#define DEBUG_FEATURES + +static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model); + +void cpu_reset(CPUSPARCState *env) +{ + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + + tlb_flush(env, 1); + env->cwp = 0; +#ifndef TARGET_SPARC64 + env->wim = 1; +#endif + env->regwptr = env->regbase + (env->cwp * 16); + CC_OP = CC_OP_FLAGS; +#if defined(CONFIG_USER_ONLY) +#ifdef TARGET_SPARC64 + env->cleanwin = env->nwindows - 2; + env->cansave = env->nwindows - 2; + env->pstate = PS_RMO | PS_PEF | PS_IE; + env->asi = 0x82; /* Primary no-fault */ +#endif +#else +#if !defined(TARGET_SPARC64) + env->psret = 0; + env->psrs = 1; + env->psrps = 1; +#endif +#ifdef TARGET_SPARC64 + env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG; + env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0; + env->tl = env->maxtl; + cpu_tsptr(env)->tt = TT_POWER_ON_RESET; + env->lsu = 0; +#else + env->mmuregs[0] &= ~(MMU_E | MMU_NF); + env->mmuregs[0] |= env->def->mmu_bm; +#endif + env->pc = 0; + env->npc = env->pc + 4; +#endif + env->cache_control = 0; +} + +static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model) +{ + sparc_def_t def1, *def = &def1; + + if (cpu_sparc_find_by_name(def, cpu_model) < 0) { + return -1; + } + + env->def = g_new0(sparc_def_t, 1); + memcpy(env->def, def, sizeof(*def)); +#if defined(CONFIG_USER_ONLY) + if ((env->def->features & CPU_FEATURE_FLOAT)) { + env->def->features |= CPU_FEATURE_FLOAT128; + } +#endif + env->cpu_model_str = cpu_model; + env->version = def->iu_version; + env->fsr = def->fpu_version; + env->nwindows = def->nwindows; +#if !defined(TARGET_SPARC64) + env->mmuregs[0] |= def->mmu_version; + cpu_sparc_set_id(env, 0); + env->mxccregs[7] |= def->mxcc_version; +#else + env->mmu_version = def->mmu_version; + env->maxtl = def->maxtl; + env->version |= def->maxtl << 8; + env->version |= def->nwindows - 1; +#endif + return 0; +} + +static void cpu_sparc_close(CPUSPARCState *env) +{ + g_free(env->def); + g_free(env); +} + +CPUSPARCState *cpu_sparc_init(const char *cpu_model) +{ + CPUSPARCState *env; + + env = g_new0(CPUSPARCState, 1); + cpu_exec_init(env); + + gen_intermediate_code_init(env); + + if (cpu_sparc_register(env, cpu_model) < 0) { + cpu_sparc_close(env); + return NULL; + } + qemu_init_vcpu(env); + + return env; +} + +void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu) +{ +#if !defined(TARGET_SPARC64) + env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; +#endif +} + +static const sparc_def_t sparc_defs[] = { +#ifdef TARGET_SPARC64 + { + .name = "Fujitsu Sparc64", + .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 4, + .maxtl = 4, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu Sparc64 III", + .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 5, + .maxtl = 4, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu Sparc64 IV", + .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu Sparc64 V", + .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc I", + .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc II", + .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc IIi", + .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc IIe", + .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc III", + .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc III Cu", + .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_3, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc IIIi", + .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc IV", + .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_4, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc IV+", + .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT, + }, + { + .name = "Sun UltraSparc IIIi+", + .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_3, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc T1", + /* defined in sparc_ifu_fdp.v and ctu.h */ + .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_sun4v, + .nwindows = 8, + .maxtl = 6, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT + | CPU_FEATURE_GL, + }, + { + .name = "Sun UltraSparc T2", + /* defined in tlu_asi_ctl.v and n2_revid_cust.v */ + .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_sun4v, + .nwindows = 8, + .maxtl = 6, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT + | CPU_FEATURE_GL, + }, + { + .name = "NEC UltraSparc I", + .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, +#else + { + .name = "Fujitsu MB86900", + .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 7, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD, + }, + { + .name = "Fujitsu MB86904", + .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x00ffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0x00ffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu MB86907", + .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "LSI L64811", + .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ + .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Cypress CY7C601", + .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Cypress CY7C611", + .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "TI MicroSparc I", + .iu_version = 0x41000000, + .fpu_version = 4 << 17, + .mmu_version = 0x41000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0x0000003f, + .nwindows = 7, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL | + CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | + CPU_FEATURE_FMUL, + }, + { + .name = "TI MicroSparc II", + .iu_version = 0x42000000, + .fpu_version = 4 << 17, + .mmu_version = 0x02000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x00ffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0x00ffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI MicroSparc IIep", + .iu_version = 0x42000000, + .fpu_version = 4 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x00ffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016bff, + .mmu_trcr_mask = 0x00ffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 40", /* STP1020NPGA */ + .iu_version = 0x41000000, /* SuperSPARC 2.x */ + .fpu_version = 0 << 17, + .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */ + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 50", /* STP1020PGA */ + .iu_version = 0x40000000, /* SuperSPARC 3.x */ + .fpu_version = 0 << 17, + .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */ + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 51", + .iu_version = 0x40000000, /* SuperSPARC 3.x */ + .fpu_version = 0 << 17, + .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */ + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .mxcc_version = 0x00000104, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 60", /* STP1020APGA */ + .iu_version = 0x40000000, /* SuperSPARC 3.x */ + .fpu_version = 0 << 17, + .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */ + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 61", + .iu_version = 0x44000000, /* SuperSPARC 3.x */ + .fpu_version = 0 << 17, + .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */ + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .mxcc_version = 0x00000104, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc II", + .iu_version = 0x40000000, /* SuperSPARC II 1.x */ + .fpu_version = 0 << 17, + .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */ + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .mxcc_version = 0x00000104, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Ross RT625", + .iu_version = 0x1e000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1e000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Ross RT620", + .iu_version = 0x1f000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1f000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "BIT B5010", + .iu_version = 0x20000000, + .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */ + .mmu_version = 0x20000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Matsushita MN10501", + .iu_version = 0x50000000, + .fpu_version = 0 << 17, + .mmu_version = 0x50000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Weitek W8601", + .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ + .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "LEON2", + .iu_version = 0xf2000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf2000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN, + }, + { + .name = "LEON3", + .iu_version = 0xf3000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf3000000, + .mmu_bm = 0x00000000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN | + CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL, + }, +#endif +}; + +static const char * const feature_name[] = { + "float", + "float128", + "swap", + "mul", + "div", + "flush", + "fsqrt", + "fmul", + "vis1", + "vis2", + "fsmuld", + "hypv", + "cmt", + "gl", +}; + +static void print_features(FILE *f, fprintf_function cpu_fprintf, + uint32_t features, const char *prefix) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(feature_name); i++) { + if (feature_name[i] && (features & (1 << i))) { + if (prefix) { + (*cpu_fprintf)(f, "%s", prefix); + } + (*cpu_fprintf)(f, "%s ", feature_name[i]); + } + } +} + +static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(feature_name); i++) { + if (feature_name[i] && !strcmp(flagname, feature_name[i])) { + *features |= 1 << i; + return; + } + } + fprintf(stderr, "CPU feature %s not found\n", flagname); +} + +static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) +{ + unsigned int i; + const sparc_def_t *def = NULL; + char *s = strdup(cpu_model); + char *featurestr, *name = strtok(s, ","); + uint32_t plus_features = 0; + uint32_t minus_features = 0; + uint64_t iu_version; + uint32_t fpu_version, mmu_version, nwindows; + + for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) { + if (strcasecmp(name, sparc_defs[i].name) == 0) { + def = &sparc_defs[i]; + } + } + if (!def) { + goto error; + } + memcpy(cpu_def, def, sizeof(*def)); + + featurestr = strtok(NULL, ","); + while (featurestr) { + char *val; + + if (featurestr[0] == '+') { + add_flagname_to_bitmaps(featurestr + 1, &plus_features); + } else if (featurestr[0] == '-') { + add_flagname_to_bitmaps(featurestr + 1, &minus_features); + } else if ((val = strchr(featurestr, '='))) { + *val = 0; val++; + if (!strcmp(featurestr, "iu_version")) { + char *err; + + iu_version = strtoll(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->iu_version = iu_version; +#ifdef DEBUG_FEATURES + fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version); +#endif + } else if (!strcmp(featurestr, "fpu_version")) { + char *err; + + fpu_version = strtol(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->fpu_version = fpu_version; +#ifdef DEBUG_FEATURES + fprintf(stderr, "fpu_version %x\n", fpu_version); +#endif + } else if (!strcmp(featurestr, "mmu_version")) { + char *err; + + mmu_version = strtol(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->mmu_version = mmu_version; +#ifdef DEBUG_FEATURES + fprintf(stderr, "mmu_version %x\n", mmu_version); +#endif + } else if (!strcmp(featurestr, "nwindows")) { + char *err; + + nwindows = strtol(val, &err, 0); + if (!*val || *err || nwindows > MAX_NWINDOWS || + nwindows < MIN_NWINDOWS) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->nwindows = nwindows; +#ifdef DEBUG_FEATURES + fprintf(stderr, "nwindows %d\n", nwindows); +#endif + } else { + fprintf(stderr, "unrecognized feature %s\n", featurestr); + goto error; + } + } else { + fprintf(stderr, "feature string `%s' not in format " + "(+feature|-feature|feature=xyz)\n", featurestr); + goto error; + } + featurestr = strtok(NULL, ","); + } + cpu_def->features |= plus_features; + cpu_def->features &= ~minus_features; +#ifdef DEBUG_FEATURES + print_features(stderr, fprintf, cpu_def->features, NULL); +#endif + free(s); + return 0; + + error: + free(s); + return -1; +} + +void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) { + (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx + " FPU %08x MMU %08x NWINS %d ", + sparc_defs[i].name, + sparc_defs[i].iu_version, + sparc_defs[i].fpu_version, + sparc_defs[i].mmu_version, + sparc_defs[i].nwindows); + print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES & + ~sparc_defs[i].features, "-"); + print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES & + sparc_defs[i].features, "+"); + (*cpu_fprintf)(f, "\n"); + } + (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): "); + print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL); + (*cpu_fprintf)(f, "\n"); + (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): "); + print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL); + (*cpu_fprintf)(f, "\n"); + (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version " + "fpu_version mmu_version nwindows\n"); +} + +static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf, + uint32_t cc) +{ + cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-', + cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-', + cc & PSR_CARRY ? 'C' : '-'); +} + +#ifdef TARGET_SPARC64 +#define REGS_PER_LINE 4 +#else +#define REGS_PER_LINE 8 +#endif + +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + int i, x; + + cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, + env->npc); + cpu_fprintf(f, "General Registers:\n"); + + for (i = 0; i < 8; i++) { + if (i % REGS_PER_LINE == 0) { + cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1); + } + cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]); + if (i % REGS_PER_LINE == REGS_PER_LINE - 1) { + cpu_fprintf(f, "\n"); + } + } + cpu_fprintf(f, "\nCurrent Register Window:\n"); + for (x = 0; x < 3; x++) { + for (i = 0; i < 8; i++) { + if (i % REGS_PER_LINE == 0) { + cpu_fprintf(f, "%%%c%d-%d: ", + x == 0 ? 'o' : (x == 1 ? 'l' : 'i'), + i, i + REGS_PER_LINE - 1); + } + cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]); + if (i % REGS_PER_LINE == REGS_PER_LINE - 1) { + cpu_fprintf(f, "\n"); + } + } + } + cpu_fprintf(f, "\nFloating Point Registers:\n"); + for (i = 0; i < TARGET_FPREGS; i++) { + if ((i & 3) == 0) { + cpu_fprintf(f, "%%f%02d:", i); + } + cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]); + if ((i & 3) == 3) { + cpu_fprintf(f, "\n"); + } + } +#ifdef TARGET_SPARC64 + cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate, + (unsigned)cpu_get_ccr(env)); + cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT); + cpu_fprintf(f, " xcc: "); + cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4)); + cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl, + env->psrpil); + cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d " + "cleanwin: %d cwp: %d\n", + env->cansave, env->canrestore, env->otherwin, env->wstate, + env->cleanwin, env->nwindows - 1 - env->cwp); + cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: " + TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs); +#else + cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env)); + cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env)); + cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-', + env->psrps ? 'P' : '-', env->psret ? 'E' : '-', + env->wim); + cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n", + env->fsr, env->y); +#endif +} diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c new file mode 100644 index 0000000000..23502f3020 --- /dev/null +++ b/target-sparc/fop_helper.c @@ -0,0 +1,394 @@ +/* + * FPU op helpers + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "helper.h" + +#define DT0 (env->dt0) +#define DT1 (env->dt1) +#define QT0 (env->qt0) +#define QT1 (env->qt1) + +#define F_HELPER(name, p) void helper_f##name##p(CPUState *env) + +#define F_BINOP(name) \ + float32 helper_f ## name ## s (CPUState * env, float32 src1,\ + float32 src2) \ + { \ + return float32_ ## name (src1, src2, &env->fp_status); \ + } \ + F_HELPER(name, d) \ + { \ + DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ + } \ + F_HELPER(name, q) \ + { \ + QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ + } + +F_BINOP(add); +F_BINOP(sub); +F_BINOP(mul); +F_BINOP(div); +#undef F_BINOP + +void helper_fsmuld(CPUState *env, float32 src1, float32 src2) +{ + DT0 = float64_mul(float32_to_float64(src1, &env->fp_status), + float32_to_float64(src2, &env->fp_status), + &env->fp_status); +} + +void helper_fdmulq(CPUState *env) +{ + QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), + float64_to_float128(DT1, &env->fp_status), + &env->fp_status); +} + +float32 helper_fnegs(float32 src) +{ + return float32_chs(src); +} + +#ifdef TARGET_SPARC64 +F_HELPER(neg, d) +{ + DT0 = float64_chs(DT1); +} + +F_HELPER(neg, q) +{ + QT0 = float128_chs(QT1); +} +#endif + +/* Integer to float conversion. */ +float32 helper_fitos(CPUState *env, int32_t src) +{ + return int32_to_float32(src, &env->fp_status); +} + +void helper_fitod(CPUState *env, int32_t src) +{ + DT0 = int32_to_float64(src, &env->fp_status); +} + +void helper_fitoq(CPUState *env, int32_t src) +{ + QT0 = int32_to_float128(src, &env->fp_status); +} + +#ifdef TARGET_SPARC64 +float32 helper_fxtos(CPUState *env) +{ + return int64_to_float32(*((int64_t *)&DT1), &env->fp_status); +} + +F_HELPER(xto, d) +{ + DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); +} + +F_HELPER(xto, q) +{ + QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); +} +#endif +#undef F_HELPER + +/* floating point conversion */ +float32 helper_fdtos(CPUState *env) +{ + return float64_to_float32(DT1, &env->fp_status); +} + +void helper_fstod(CPUState *env, float32 src) +{ + DT0 = float32_to_float64(src, &env->fp_status); +} + +float32 helper_fqtos(CPUState *env) +{ + return float128_to_float32(QT1, &env->fp_status); +} + +void helper_fstoq(CPUState *env, float32 src) +{ + QT0 = float32_to_float128(src, &env->fp_status); +} + +void helper_fqtod(CPUState *env) +{ + DT0 = float128_to_float64(QT1, &env->fp_status); +} + +void helper_fdtoq(CPUState *env) +{ + QT0 = float64_to_float128(DT1, &env->fp_status); +} + +/* Float to integer conversion. */ +int32_t helper_fstoi(CPUState *env, float32 src) +{ + return float32_to_int32_round_to_zero(src, &env->fp_status); +} + +int32_t helper_fdtoi(CPUState *env) +{ + return float64_to_int32_round_to_zero(DT1, &env->fp_status); +} + +int32_t helper_fqtoi(CPUState *env) +{ + return float128_to_int32_round_to_zero(QT1, &env->fp_status); +} + +#ifdef TARGET_SPARC64 +void helper_fstox(CPUState *env, float32 src) +{ + *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status); +} + +void helper_fdtox(CPUState *env) +{ + *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); +} + +void helper_fqtox(CPUState *env) +{ + *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); +} +#endif + +float32 helper_fabss(float32 src) +{ + return float32_abs(src); +} + +#ifdef TARGET_SPARC64 +void helper_fabsd(CPUState *env) +{ + DT0 = float64_abs(DT1); +} + +void helper_fabsq(CPUState *env) +{ + QT0 = float128_abs(QT1); +} +#endif + +float32 helper_fsqrts(CPUState *env, float32 src) +{ + return float32_sqrt(src, &env->fp_status); +} + +void helper_fsqrtd(CPUState *env) +{ + DT0 = float64_sqrt(DT1, &env->fp_status); +} + +void helper_fsqrtq(CPUState *env) +{ + QT0 = float128_sqrt(QT1, &env->fp_status); +} + +#define GEN_FCMP(name, size, reg1, reg2, FS, E) \ + void glue(helper_, name) (CPUState *env) \ + { \ + env->fsr &= FSR_FTT_NMASK; \ + if (E && (glue(size, _is_any_nan)(reg1) || \ + glue(size, _is_any_nan)(reg2)) && \ + (env->fsr & FSR_NVM)) { \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + helper_raise_exception(env, TT_FP_EXCP); \ + } \ + switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ + case float_relation_unordered: \ + if ((env->fsr & FSR_NVM)) { \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + helper_raise_exception(env, TT_FP_EXCP); \ + } else { \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ + env->fsr |= FSR_NVA; \ + } \ + break; \ + case float_relation_less: \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC0 << FS; \ + break; \ + case float_relation_greater: \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC1 << FS; \ + break; \ + default: \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + break; \ + } \ + } +#define GEN_FCMPS(name, size, FS, E) \ + void glue(helper_, name)(CPUState *env, float32 src1, float32 src2) \ + { \ + env->fsr &= FSR_FTT_NMASK; \ + if (E && (glue(size, _is_any_nan)(src1) || \ + glue(size, _is_any_nan)(src2)) && \ + (env->fsr & FSR_NVM)) { \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + helper_raise_exception(env, TT_FP_EXCP); \ + } \ + switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ + case float_relation_unordered: \ + if ((env->fsr & FSR_NVM)) { \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + helper_raise_exception(env, TT_FP_EXCP); \ + } else { \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ + env->fsr |= FSR_NVA; \ + } \ + break; \ + case float_relation_less: \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC0 << FS; \ + break; \ + case float_relation_greater: \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC1 << FS; \ + break; \ + default: \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + break; \ + } \ + } + +GEN_FCMPS(fcmps, float32, 0, 0); +GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); + +GEN_FCMPS(fcmpes, float32, 0, 1); +GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); + +GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); +GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); + +#ifdef TARGET_SPARC64 +GEN_FCMPS(fcmps_fcc1, float32, 22, 0); +GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); +GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); + +GEN_FCMPS(fcmps_fcc2, float32, 24, 0); +GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); +GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); + +GEN_FCMPS(fcmps_fcc3, float32, 26, 0); +GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); +GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); + +GEN_FCMPS(fcmpes_fcc1, float32, 22, 1); +GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); +GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); + +GEN_FCMPS(fcmpes_fcc2, float32, 24, 1); +GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); +GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); + +GEN_FCMPS(fcmpes_fcc3, float32, 26, 1); +GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); +GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); +#endif +#undef GEN_FCMPS + +void helper_check_ieee_exceptions(CPUState *env) +{ + target_ulong status; + + status = get_float_exception_flags(&env->fp_status); + if (status) { + /* Copy IEEE 754 flags into FSR */ + if (status & float_flag_invalid) { + env->fsr |= FSR_NVC; + } + if (status & float_flag_overflow) { + env->fsr |= FSR_OFC; + } + if (status & float_flag_underflow) { + env->fsr |= FSR_UFC; + } + if (status & float_flag_divbyzero) { + env->fsr |= FSR_DZC; + } + if (status & float_flag_inexact) { + env->fsr |= FSR_NXC; + } + + if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { + /* Unmasked exception, generate a trap */ + env->fsr |= FSR_FTT_IEEE_EXCP; + helper_raise_exception(env, TT_FP_EXCP); + } else { + /* Accumulate exceptions */ + env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; + } + } +} + +void helper_clear_float_exceptions(CPUState *env) +{ + set_float_exception_flags(0, &env->fp_status); +} + +static inline void set_fsr(CPUState *env) +{ + int rnd_mode; + + switch (env->fsr & FSR_RD_MASK) { + case FSR_RD_NEAREST: + rnd_mode = float_round_nearest_even; + break; + default: + case FSR_RD_ZERO: + rnd_mode = float_round_to_zero; + break; + case FSR_RD_POS: + rnd_mode = float_round_up; + break; + case FSR_RD_NEG: + rnd_mode = float_round_down; + break; + } + set_float_rounding_mode(rnd_mode, &env->fp_status); +} + +void helper_ldfsr(CPUState *env, uint32_t new_fsr) +{ + env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK); + set_fsr(env); +} + +#ifdef TARGET_SPARC64 +void helper_ldxfsr(CPUState *env, uint64_t new_fsr) +{ + env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK); + set_fsr(env); +} +#endif diff --git a/target-sparc/helper.c b/target-sparc/helper.c index c80531a16c..18609c449c 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -1,5 +1,5 @@ /* - * sparc helpers + * Misc Sparc helpers * * Copyright (c) 2003-2005 Fabrice Bellard * @@ -16,1926 +16,133 @@ * 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 <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <inttypes.h> #include "cpu.h" -#include "qemu-common.h" +#include "host-utils.h" +#include "helper.h" +#include "sysemu.h" -//#define DEBUG_MMU -//#define DEBUG_FEATURES - -#ifdef DEBUG_MMU -#define DPRINTF_MMU(fmt, ...) \ - do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_MMU(fmt, ...) do {} while (0) -#endif - -static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model); - -/* Sparc MMU emulation */ - -#if defined(CONFIG_USER_ONLY) - -int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw, - int mmu_idx) +void helper_raise_exception(CPUState *env, int tt) { - if (rw & 2) - env1->exception_index = TT_TFAULT; - else - env1->exception_index = TT_DFAULT; - return 1; + env->exception_index = tt; + cpu_loop_exit(env); } -#else - -#ifndef TARGET_SPARC64 -/* - * Sparc V8 Reference MMU (SRMMU) - */ -static const int access_table[8][8] = { - { 0, 0, 0, 0, 8, 0, 12, 12 }, - { 0, 0, 0, 0, 8, 0, 0, 0 }, - { 8, 8, 0, 0, 0, 8, 12, 12 }, - { 8, 8, 0, 0, 0, 8, 0, 0 }, - { 8, 0, 8, 0, 8, 8, 12, 12 }, - { 8, 0, 8, 0, 8, 0, 8, 0 }, - { 8, 8, 8, 0, 8, 8, 12, 12 }, - { 8, 8, 8, 0, 8, 8, 8, 0 } -}; - -static const int perm_table[2][8] = { - { - PAGE_READ, - PAGE_READ | PAGE_WRITE, - PAGE_READ | PAGE_EXEC, - PAGE_READ | PAGE_WRITE | PAGE_EXEC, - PAGE_EXEC, - PAGE_READ | PAGE_WRITE, - PAGE_READ | PAGE_EXEC, - PAGE_READ | PAGE_WRITE | PAGE_EXEC - }, - { - PAGE_READ, - PAGE_READ | PAGE_WRITE, - PAGE_READ | PAGE_EXEC, - PAGE_READ | PAGE_WRITE | PAGE_EXEC, - PAGE_EXEC, - PAGE_READ, - 0, - 0, - } -}; - -static int get_physical_address(CPUState *env, target_phys_addr_t *physical, - int *prot, int *access_index, - target_ulong address, int rw, int mmu_idx, - target_ulong *page_size) +void helper_debug(CPUState *env) { - int access_perms = 0; - target_phys_addr_t pde_ptr; - uint32_t pde; - int error_code = 0, is_dirty, is_user; - unsigned long page_offset; - - is_user = mmu_idx == MMU_USER_IDX; - - if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ - *page_size = TARGET_PAGE_SIZE; - // Boot mode: instruction fetches are taken from PROM - if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { - *physical = env->prom_addr | (address & 0x7ffffULL); - *prot = PAGE_READ | PAGE_EXEC; - return 0; - } - *physical = address; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return 0; - } - - *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); - *physical = 0xffffffffffff0000ULL; - - /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ - /* Context base + context number */ - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(pde_ptr); - - /* Ctx pde */ - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return 1 << 2; - case 2: /* L0 PTE, maybe should not happen? */ - case 3: /* Reserved */ - return 4 << 2; - case 1: /* L0 PDE */ - pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return (1 << 8) | (1 << 2); - case 3: /* Reserved */ - return (1 << 8) | (4 << 2); - case 1: /* L1 PDE */ - pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return (2 << 8) | (1 << 2); - case 3: /* Reserved */ - return (2 << 8) | (4 << 2); - case 1: /* L2 PDE */ - pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return (3 << 8) | (1 << 2); - case 1: /* PDE, should not happen */ - case 3: /* Reserved */ - return (3 << 8) | (4 << 2); - case 2: /* L3 PTE */ - page_offset = (address & TARGET_PAGE_MASK) & - (TARGET_PAGE_SIZE - 1); - } - *page_size = TARGET_PAGE_SIZE; - break; - case 2: /* L2 PTE */ - page_offset = address & 0x3ffff; - *page_size = 0x40000; - } - break; - case 2: /* L1 PTE */ - page_offset = address & 0xffffff; - *page_size = 0x1000000; - } - } - - /* check access */ - access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; - error_code = access_table[*access_index][access_perms]; - if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) - return error_code; - - /* update page modified and dirty bits */ - is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); - if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_MODIFIED_MASK; - stl_phys_notdirty(pde_ptr, pde); - } - - /* the page can be put in the TLB */ - *prot = perm_table[is_user][access_perms]; - if (!(pde & PG_MODIFIED_MASK)) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - *prot &= ~PAGE_WRITE; - } - - /* Even if large ptes, we map only one 4KB page in the cache to - avoid filling it too fast */ - *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset; - return error_code; + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(env); } -/* Perform address translation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int mmu_idx) +void helper_shutdown(void) { - target_phys_addr_t paddr; - target_ulong vaddr; - target_ulong page_size; - int error_code = 0, prot, access_index; - - error_code = get_physical_address(env, &paddr, &prot, &access_index, - address, rw, mmu_idx, &page_size); - if (error_code == 0) { - vaddr = address & TARGET_PAGE_MASK; - paddr &= TARGET_PAGE_MASK; -#ifdef DEBUG_MMU - printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " - TARGET_FMT_lx "\n", address, paddr, vaddr); +#if !defined(CONFIG_USER_ONLY) + qemu_system_shutdown_request(); #endif - tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); - return 0; - } - - if (env->mmuregs[3]) /* Fault status register */ - env->mmuregs[3] = 1; /* overflow (not read before another fault) */ - env->mmuregs[3] |= (access_index << 5) | error_code | 2; - env->mmuregs[4] = address; /* Fault address register */ - - if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { - // No fault mode: if a mapping is available, just override - // permissions. If no mapping is available, redirect accesses to - // neverland. Fake/overridden mappings will be flushed when - // switching to normal mode. - vaddr = address & TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); - return 0; - } else { - if (rw & 2) - env->exception_index = TT_TFAULT; - else - env->exception_index = TT_DFAULT; - return 1; - } } -target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) +#ifdef TARGET_SPARC64 +target_ulong helper_popc(target_ulong val) { - target_phys_addr_t pde_ptr; - uint32_t pde; - - /* Context base + context number */ - pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) + - (env->mmuregs[2] << 2); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 2: /* PTE, maybe should not happen? */ - case 3: /* Reserved */ - return 0; - case 1: /* L1 PDE */ - if (mmulev == 3) - return pde; - pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 3: /* Reserved */ - return 0; - case 2: /* L1 PTE */ - return pde; - case 1: /* L2 PDE */ - if (mmulev == 2) - return pde; - pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 3: /* Reserved */ - return 0; - case 2: /* L2 PTE */ - return pde; - case 1: /* L3 PDE */ - if (mmulev == 1) - return pde; - pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 1: /* PDE, should not happen */ - case 3: /* Reserved */ - return 0; - case 2: /* L3 PTE */ - return pde; - } - } - } - } - return 0; + return ctpop64(val); } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) +void helper_tick_set_count(void *opaque, uint64_t count) { - target_ulong va, va1, va2; - unsigned int n, m, o; - target_phys_addr_t pde_ptr, pa; - uint32_t pde; - - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(pde_ptr); - (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", - (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); - for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { - pde = mmu_probe(env, va, 2); - if (pde) { - pa = cpu_get_phys_page_debug(env, va); - (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx - " PDE: " TARGET_FMT_lx "\n", va, pa, pde); - for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { - pde = mmu_probe(env, va1, 1); - if (pde) { - pa = cpu_get_phys_page_debug(env, va1); - (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", - va1, pa, pde); - for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { - pde = mmu_probe(env, va2, 0); - if (pde) { - pa = cpu_get_phys_page_debug(env, va2); - (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PTE: " - TARGET_FMT_lx "\n", - va2, pa, pde); - } - } - } - } - } - } -} - #if !defined(CONFIG_USER_ONLY) - -/* Gdb expects all registers windows to be flushed in ram. This function handles - * reads (and only reads) in stack frames as if windows were flushed. We assume - * that the sparc ABI is followed. - */ -int target_memory_rw_debug(CPUState *env, target_ulong addr, - uint8_t *buf, int len, int is_write) -{ - int i; - int len1; - int cwp = env->cwp; - - if (!is_write) { - for (i = 0; i < env->nwindows; i++) { - int off; - target_ulong fp = env->regbase[cwp * 16 + 22]; - - /* Assume fp == 0 means end of frame. */ - if (fp == 0) { - break; - } - - cwp = cpu_cwp_inc(env, cwp + 1); - - /* Invalid window ? */ - if (env->wim & (1 << cwp)) { - break; - } - - /* According to the ABI, the stack is growing downward. */ - if (addr + len < fp) { - break; - } - - /* Not in this frame. */ - if (addr > fp + 64) { - continue; - } - - /* Handle access before this window. */ - if (addr < fp) { - len1 = fp - addr; - if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { - return -1; - } - addr += len1; - len -= len1; - buf += len1; - } - - /* Access byte per byte to registers. Not very efficient but speed - * is not critical. - */ - off = addr - fp; - len1 = 64 - off; - - if (len1 > len) { - len1 = len; - } - - for (; len1; len1--) { - int reg = cwp * 16 + 8 + (off >> 2); - union { - uint32_t v; - uint8_t c[4]; - } u; - u.v = cpu_to_be32(env->regbase[reg]); - *buf++ = u.c[off & 3]; - addr++; - len--; - off++; - } - - if (len == 0) { - return 0; - } - } - } - return cpu_memory_rw_debug(env, addr, buf, len, is_write); -} - -#endif /* !defined(CONFIG_USER_ONLY) */ - -#else /* !TARGET_SPARC64 */ - -// 41 bit physical address space -static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x) -{ - return x & 0x1ffffffffffULL; -} - -/* - * UltraSparc IIi I/DMMUs - */ - -// Returns true if TTE tag is valid and matches virtual address value in context -// requires virtual address mask value calculated from TTE entry size -static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, - uint64_t address, uint64_t context, - target_phys_addr_t *physical) -{ - uint64_t mask; - - switch (TTE_PGSIZE(tlb->tte)) { - default: - case 0x0: // 8k - mask = 0xffffffffffffe000ULL; - break; - case 0x1: // 64k - mask = 0xffffffffffff0000ULL; - break; - case 0x2: // 512k - mask = 0xfffffffffff80000ULL; - break; - case 0x3: // 4M - mask = 0xffffffffffc00000ULL; - break; - } - - // valid, context match, virtual address match? - if (TTE_IS_VALID(tlb->tte) && - (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) - && compare_masked(address, tlb->tag, mask)) - { - // decode physical address - *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; - return 1; - } - - return 0; -} - -static int get_physical_address_data(CPUState *env, - target_phys_addr_t *physical, int *prot, - target_ulong address, int rw, int mmu_idx) -{ - unsigned int i; - uint64_t context; - uint64_t sfsr = 0; - - int is_user = (mmu_idx == MMU_USER_IDX || - mmu_idx == MMU_USER_SECONDARY_IDX); - - if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ - *physical = ultrasparc_truncate_physical(address); - *prot = PAGE_READ | PAGE_WRITE; - return 0; - } - - switch(mmu_idx) { - case MMU_USER_IDX: - case MMU_KERNEL_IDX: - context = env->dmmu.mmu_primary_context & 0x1fff; - sfsr |= SFSR_CT_PRIMARY; - break; - case MMU_USER_SECONDARY_IDX: - case MMU_KERNEL_SECONDARY_IDX: - context = env->dmmu.mmu_secondary_context & 0x1fff; - sfsr |= SFSR_CT_SECONDARY; - break; - case MMU_NUCLEUS_IDX: - sfsr |= SFSR_CT_NUCLEUS; - /* FALLTHRU */ - default: - context = 0; - break; - } - - if (rw == 1) { - sfsr |= SFSR_WRITE_BIT; - } else if (rw == 4) { - sfsr |= SFSR_NF_BIT; - } - - for (i = 0; i < 64; i++) { - // ctx match, vaddr match, valid? - if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { - int do_fault = 0; - - // access ok? - /* multiple bits in SFSR.FT may be set on TT_DFAULT */ - if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { - do_fault = 1; - sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ - - DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64 - " mmu_idx=%d tl=%d\n", - address, context, mmu_idx, env->tl); - } - if (rw == 4) { - if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { - do_fault = 1; - sfsr |= SFSR_FT_NF_E_BIT; - } - } else { - if (TTE_IS_NFO(env->dtlb[i].tte)) { - do_fault = 1; - sfsr |= SFSR_FT_NFO_BIT; - } - } - - if (do_fault) { - /* faults above are reported with TT_DFAULT. */ - env->exception_index = TT_DFAULT; - } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { - do_fault = 1; - env->exception_index = TT_DPROT; - - DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64 - " mmu_idx=%d tl=%d\n", - address, context, mmu_idx, env->tl); - } - - if (!do_fault) { - *prot = PAGE_READ; - if (TTE_IS_W_OK(env->dtlb[i].tte)) { - *prot |= PAGE_WRITE; - } - - TTE_SET_USED(env->dtlb[i].tte); - - return 0; - } - - if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ - sfsr |= SFSR_OW_BIT; /* overflow (not read before - another fault) */ - } - - if (env->pstate & PS_PRIV) { - sfsr |= SFSR_PR_BIT; - } - - /* FIXME: ASI field in SFSR must be set */ - env->dmmu.sfsr = sfsr | SFSR_VALID_BIT; - - env->dmmu.sfar = address; /* Fault address register */ - - env->dmmu.tag_access = (address & ~0x1fffULL) | context; - - return 1; - } - } - - DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n", - address, context); - - /* - * On MMU misses: - * - UltraSPARC IIi: SFSR and SFAR unmodified - * - JPS1: SFAR updated and some fields of SFSR updated - */ - env->dmmu.tag_access = (address & ~0x1fffULL) | context; - env->exception_index = TT_DMISS; - return 1; -} - -static int get_physical_address_code(CPUState *env, - target_phys_addr_t *physical, int *prot, - target_ulong address, int mmu_idx) -{ - unsigned int i; - uint64_t context; - - int is_user = (mmu_idx == MMU_USER_IDX || - mmu_idx == MMU_USER_SECONDARY_IDX); - - if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { - /* IMMU disabled */ - *physical = ultrasparc_truncate_physical(address); - *prot = PAGE_EXEC; - return 0; - } - - if (env->tl == 0) { - /* PRIMARY context */ - context = env->dmmu.mmu_primary_context & 0x1fff; - } else { - /* NUCLEUS context */ - context = 0; - } - - for (i = 0; i < 64; i++) { - // ctx match, vaddr match, valid? - if (ultrasparc_tag_match(&env->itlb[i], - address, context, physical)) { - // access ok? - if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { - /* Fault status register */ - if (env->immu.sfsr & SFSR_VALID_BIT) { - env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before - another fault) */ - } else { - env->immu.sfsr = 0; - } - if (env->pstate & PS_PRIV) { - env->immu.sfsr |= SFSR_PR_BIT; - } - if (env->tl > 0) { - env->immu.sfsr |= SFSR_CT_NUCLEUS; - } - - /* FIXME: ASI field in SFSR must be set */ - env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; - env->exception_index = TT_TFAULT; - - env->immu.tag_access = (address & ~0x1fffULL) | context; - - DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n", - address, context); - - return 1; - } - *prot = PAGE_EXEC; - TTE_SET_USED(env->itlb[i].tte); - return 0; - } - } - - DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n", - address, context); - - /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ - env->immu.tag_access = (address & ~0x1fffULL) | context; - env->exception_index = TT_TMISS; - return 1; -} - -static int get_physical_address(CPUState *env, target_phys_addr_t *physical, - int *prot, int *access_index, - target_ulong address, int rw, int mmu_idx, - target_ulong *page_size) -{ - /* ??? We treat everything as a small page, then explicitly flush - everything when an entry is evicted. */ - *page_size = TARGET_PAGE_SIZE; - -#if defined (DEBUG_MMU) - /* safety net to catch wrong softmmu index use from dynamic code */ - if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { - DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d" - " primary context=%" PRIx64 - " secondary context=%" PRIx64 - " address=%" PRIx64 - "\n", - (rw == 2 ? "CODE" : "DATA"), - env->tl, mmu_idx, - env->dmmu.mmu_primary_context, - env->dmmu.mmu_secondary_context, - address); - } + cpu_tick_set_count(opaque, count); #endif - - if (rw == 2) - return get_physical_address_code(env, physical, prot, address, - mmu_idx); - else - return get_physical_address_data(env, physical, prot, address, rw, - mmu_idx); -} - -/* Perform address translation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int mmu_idx) -{ - target_ulong virt_addr, vaddr; - target_phys_addr_t paddr; - target_ulong page_size; - int error_code = 0, prot, access_index; - - error_code = get_physical_address(env, &paddr, &prot, &access_index, - address, rw, mmu_idx, &page_size); - if (error_code == 0) { - virt_addr = address & TARGET_PAGE_MASK; - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & - (TARGET_PAGE_SIZE - 1)); - - DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 "," - " vaddr %" PRIx64 - " mmu_idx=%d" - " tl=%d" - " primary context=%" PRIx64 - " secondary context=%" PRIx64 - "\n", - address, paddr, vaddr, mmu_idx, env->tl, - env->dmmu.mmu_primary_context, - env->dmmu.mmu_secondary_context); - - tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); - return 0; - } - // XXX - return 1; } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) +uint64_t helper_tick_get_count(void *opaque) { - unsigned int i; - const char *mask; - - (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" - PRId64 "\n", - env->dmmu.mmu_primary_context, - env->dmmu.mmu_secondary_context); - if ((env->lsu & DMMU_E) == 0) { - (*cpu_fprintf)(f, "DMMU disabled\n"); - } else { - (*cpu_fprintf)(f, "DMMU dump\n"); - for (i = 0; i < 64; i++) { - switch (TTE_PGSIZE(env->dtlb[i].tte)) { - default: - case 0x0: - mask = " 8k"; - break; - case 0x1: - mask = " 64k"; - break; - case 0x2: - mask = "512k"; - break; - case 0x3: - mask = " 4M"; - break; - } - if (TTE_IS_VALID(env->dtlb[i].tte)) { - (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" - ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", - i, - env->dtlb[i].tag & (uint64_t)~0x1fffULL, - TTE_PA(env->dtlb[i].tte), - mask, - TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", - TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", - TTE_IS_LOCKED(env->dtlb[i].tte) ? - "locked" : "unlocked", - env->dtlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->dtlb[i].tte)? - "global" : "local"); - } - } - } - if ((env->lsu & IMMU_E) == 0) { - (*cpu_fprintf)(f, "IMMU disabled\n"); - } else { - (*cpu_fprintf)(f, "IMMU dump\n"); - for (i = 0; i < 64; i++) { - switch (TTE_PGSIZE(env->itlb[i].tte)) { - default: - case 0x0: - mask = " 8k"; - break; - case 0x1: - mask = " 64k"; - break; - case 0x2: - mask = "512k"; - break; - case 0x3: - mask = " 4M"; - break; - } - if (TTE_IS_VALID(env->itlb[i].tte)) { - (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" - ", %s, %s, %s, ctx %" PRId64 " %s\n", - i, - env->itlb[i].tag & (uint64_t)~0x1fffULL, - TTE_PA(env->itlb[i].tte), - mask, - TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", - TTE_IS_LOCKED(env->itlb[i].tte) ? - "locked" : "unlocked", - env->itlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->itlb[i].tte)? - "global" : "local"); - } - } - } -} - -#endif /* TARGET_SPARC64 */ -#endif /* !CONFIG_USER_ONLY */ - - #if !defined(CONFIG_USER_ONLY) -static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys, - target_ulong addr, int rw, int mmu_idx) -{ - target_ulong page_size; - int prot, access_index; - - return get_physical_address(env, phys, &prot, &access_index, addr, rw, - mmu_idx, &page_size); -} - -#if defined(TARGET_SPARC64) -target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, - int mmu_idx) -{ - target_phys_addr_t phys_addr; - - if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { - return -1; - } - return phys_addr; -} + return cpu_tick_get_count(opaque); +#else + return 0; #endif - -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - target_phys_addr_t phys_addr; - int mmu_idx = cpu_mmu_index(env); - - if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { - if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { - return -1; - } - } - if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) { - return -1; - } - return phys_addr; } -#endif - -#ifdef TARGET_SPARC64 -#ifdef DEBUG_PCALL -static const char * const excp_names[0x80] = { - [TT_TFAULT] = "Instruction Access Fault", - [TT_TMISS] = "Instruction Access MMU Miss", - [TT_CODE_ACCESS] = "Instruction Access Error", - [TT_ILL_INSN] = "Illegal Instruction", - [TT_PRIV_INSN] = "Privileged Instruction", - [TT_NFPU_INSN] = "FPU Disabled", - [TT_FP_EXCP] = "FPU Exception", - [TT_TOVF] = "Tag Overflow", - [TT_CLRWIN] = "Clean Windows", - [TT_DIV_ZERO] = "Division By Zero", - [TT_DFAULT] = "Data Access Fault", - [TT_DMISS] = "Data Access MMU Miss", - [TT_DATA_ACCESS] = "Data Access Error", - [TT_DPROT] = "Data Protection Error", - [TT_UNALIGNED] = "Unaligned Memory Access", - [TT_PRIV_ACT] = "Privileged Action", - [TT_EXTINT | 0x1] = "External Interrupt 1", - [TT_EXTINT | 0x2] = "External Interrupt 2", - [TT_EXTINT | 0x3] = "External Interrupt 3", - [TT_EXTINT | 0x4] = "External Interrupt 4", - [TT_EXTINT | 0x5] = "External Interrupt 5", - [TT_EXTINT | 0x6] = "External Interrupt 6", - [TT_EXTINT | 0x7] = "External Interrupt 7", - [TT_EXTINT | 0x8] = "External Interrupt 8", - [TT_EXTINT | 0x9] = "External Interrupt 9", - [TT_EXTINT | 0xa] = "External Interrupt 10", - [TT_EXTINT | 0xb] = "External Interrupt 11", - [TT_EXTINT | 0xc] = "External Interrupt 12", - [TT_EXTINT | 0xd] = "External Interrupt 13", - [TT_EXTINT | 0xe] = "External Interrupt 14", - [TT_EXTINT | 0xf] = "External Interrupt 15", -}; -#endif -void do_interrupt(CPUState *env) +void helper_tick_set_limit(void *opaque, uint64_t limit) { - int intno = env->exception_index; - trap_state *tsptr; - -#ifdef DEBUG_PCALL - if (qemu_loglevel_mask(CPU_LOG_INT)) { - static int count; - const char *name; - - if (intno < 0 || intno >= 0x180) { - name = "Unknown"; - } else if (intno >= 0x100) { - name = "Trap Instruction"; - } else if (intno >= 0xc0) { - name = "Window Fill"; - } else if (intno >= 0x80) { - name = "Window Spill"; - } else { - name = excp_names[intno]; - if (!name) { - name = "Unknown"; - } - } - - qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 - " SP=%016" PRIx64 "\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); - log_cpu_state(env, 0); -#if 0 - { - int i; - uint8_t *ptr; - - qemu_log(" code="); - ptr = (uint8_t *)env->pc; - for (i = 0; i < 16; i++) { - qemu_log(" %02x", ldub(ptr + i)); - } - qemu_log("\n"); - } -#endif - count++; - } -#endif #if !defined(CONFIG_USER_ONLY) - if (env->tl >= env->maxtl) { - cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d)," - " Error state", env->exception_index, env->tl, env->maxtl); - return; - } + cpu_tick_set_limit(opaque, limit); #endif - if (env->tl < env->maxtl - 1) { - env->tl++; - } else { - env->pstate |= PS_RED; - if (env->tl < env->maxtl) { - env->tl++; - } - } - tsptr = cpu_tsptr(env); - - tsptr->tstate = (cpu_get_ccr(env) << 32) | - ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | - cpu_get_cwp64(env); - tsptr->tpc = env->pc; - tsptr->tnpc = env->npc; - tsptr->tt = intno; - - switch (intno) { - case TT_IVEC: - cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG); - break; - case TT_TFAULT: - case TT_DFAULT: - case TT_TMISS ... TT_TMISS + 3: - case TT_DMISS ... TT_DMISS + 3: - case TT_DPROT ... TT_DPROT + 3: - cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG); - break; - default: - cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG); - break; - } - - if (intno == TT_CLRWIN) { - cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1)); - } else if ((intno & 0x1c0) == TT_SPILL) { - cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); - } else if ((intno & 0x1c0) == TT_FILL) { - cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1)); - } - env->tbr &= ~0x7fffULL; - env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); - env->pc = env->tbr; - env->npc = env->pc + 4; - env->exception_index = -1; } -#else -#ifdef DEBUG_PCALL -static const char * const excp_names[0x80] = { - [TT_TFAULT] = "Instruction Access Fault", - [TT_ILL_INSN] = "Illegal Instruction", - [TT_PRIV_INSN] = "Privileged Instruction", - [TT_NFPU_INSN] = "FPU Disabled", - [TT_WIN_OVF] = "Window Overflow", - [TT_WIN_UNF] = "Window Underflow", - [TT_UNALIGNED] = "Unaligned Memory Access", - [TT_FP_EXCP] = "FPU Exception", - [TT_DFAULT] = "Data Access Fault", - [TT_TOVF] = "Tag Overflow", - [TT_EXTINT | 0x1] = "External Interrupt 1", - [TT_EXTINT | 0x2] = "External Interrupt 2", - [TT_EXTINT | 0x3] = "External Interrupt 3", - [TT_EXTINT | 0x4] = "External Interrupt 4", - [TT_EXTINT | 0x5] = "External Interrupt 5", - [TT_EXTINT | 0x6] = "External Interrupt 6", - [TT_EXTINT | 0x7] = "External Interrupt 7", - [TT_EXTINT | 0x8] = "External Interrupt 8", - [TT_EXTINT | 0x9] = "External Interrupt 9", - [TT_EXTINT | 0xa] = "External Interrupt 10", - [TT_EXTINT | 0xb] = "External Interrupt 11", - [TT_EXTINT | 0xc] = "External Interrupt 12", - [TT_EXTINT | 0xd] = "External Interrupt 13", - [TT_EXTINT | 0xe] = "External Interrupt 14", - [TT_EXTINT | 0xf] = "External Interrupt 15", - [TT_TOVF] = "Tag Overflow", - [TT_CODE_ACCESS] = "Instruction Access Error", - [TT_DATA_ACCESS] = "Data Access Error", - [TT_DIV_ZERO] = "Division By Zero", - [TT_NCP_INSN] = "Coprocessor Disabled", -}; #endif -void do_interrupt(CPUState *env) +static target_ulong helper_udiv_common(CPUState *env, target_ulong a, + target_ulong b, int cc) { - int cwp, intno = env->exception_index; - -#ifdef DEBUG_PCALL - if (qemu_loglevel_mask(CPU_LOG_INT)) { - static int count; - const char *name; - - if (intno < 0 || intno >= 0x100) { - name = "Unknown"; - } else if (intno >= 0x80) { - name = "Trap Instruction"; - } else { - name = excp_names[intno]; - if (!name) { - name = "Unknown"; - } - } - - qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); - log_cpu_state(env, 0); -#if 0 - { - int i; - uint8_t *ptr; + int overflow = 0; + uint64_t x0; + uint32_t x1; - qemu_log(" code="); - ptr = (uint8_t *)env->pc; - for (i = 0; i < 16; i++) { - qemu_log(" %02x", ldub(ptr + i)); - } - qemu_log("\n"); - } -#endif - count++; - } -#endif -#if !defined(CONFIG_USER_ONLY) - if (env->psret == 0) { - cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", - env->exception_index); - return; - } -#endif - env->psret = 0; - cwp = cpu_cwp_dec(env, env->cwp - 1); - cpu_set_cwp(env, cwp); - env->regwptr[9] = env->pc; - env->regwptr[10] = env->npc; - env->psrps = env->psrs; - env->psrs = 1; - env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); - env->pc = env->tbr; - env->npc = env->pc + 4; - env->exception_index = -1; + x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); + x1 = (b & 0xffffffff); -#if !defined(CONFIG_USER_ONLY) - /* IRQ acknowledgment */ - if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) { - env->qemu_irq_ack(env->irq_manager, intno); + if (x1 == 0) { + helper_raise_exception(env, TT_DIV_ZERO); } -#endif -} -#endif -void cpu_reset(CPUSPARCState *env) -{ - if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); - log_cpu_state(env, 0); + x0 = x0 / x1; + if (x0 > 0xffffffff) { + x0 = 0xffffffff; + overflow = 1; } - tlb_flush(env, 1); - env->cwp = 0; -#ifndef TARGET_SPARC64 - env->wim = 1; -#endif - env->regwptr = env->regbase + (env->cwp * 16); - CC_OP = CC_OP_FLAGS; -#if defined(CONFIG_USER_ONLY) -#ifdef TARGET_SPARC64 - env->cleanwin = env->nwindows - 2; - env->cansave = env->nwindows - 2; - env->pstate = PS_RMO | PS_PEF | PS_IE; - env->asi = 0x82; // Primary no-fault -#endif -#else -#if !defined(TARGET_SPARC64) - env->psret = 0; - env->psrs = 1; - env->psrps = 1; -#endif -#ifdef TARGET_SPARC64 - env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG; - env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0; - env->tl = env->maxtl; - cpu_tsptr(env)->tt = TT_POWER_ON_RESET; - env->lsu = 0; -#else - env->mmuregs[0] &= ~(MMU_E | MMU_NF); - env->mmuregs[0] |= env->def->mmu_bm; -#endif - env->pc = 0; - env->npc = env->pc + 4; -#endif - env->cache_control = 0; -} - -static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model) -{ - sparc_def_t def1, *def = &def1; - - if (cpu_sparc_find_by_name(def, cpu_model) < 0) - return -1; - - env->def = g_malloc0(sizeof(*def)); - memcpy(env->def, def, sizeof(*def)); -#if defined(CONFIG_USER_ONLY) - if ((env->def->features & CPU_FEATURE_FLOAT)) - env->def->features |= CPU_FEATURE_FLOAT128; -#endif - env->cpu_model_str = cpu_model; - env->version = def->iu_version; - env->fsr = def->fpu_version; - env->nwindows = def->nwindows; -#if !defined(TARGET_SPARC64) - env->mmuregs[0] |= def->mmu_version; - cpu_sparc_set_id(env, 0); - env->mxccregs[7] |= def->mxcc_version; -#else - env->mmu_version = def->mmu_version; - env->maxtl = def->maxtl; - env->version |= def->maxtl << 8; - env->version |= def->nwindows - 1; -#endif - return 0; -} - -static void cpu_sparc_close(CPUSPARCState *env) -{ - free(env->def); - free(env); -} - -CPUSPARCState *cpu_sparc_init(const char *cpu_model) -{ - CPUSPARCState *env; - - env = g_malloc0(sizeof(CPUSPARCState)); - cpu_exec_init(env); - - gen_intermediate_code_init(env); - - if (cpu_sparc_register(env, cpu_model) < 0) { - cpu_sparc_close(env); - return NULL; + if (cc) { + env->cc_dst = x0; + env->cc_src2 = overflow; + env->cc_op = CC_OP_DIV; } - qemu_init_vcpu(env); - - return env; + return x0; } -void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu) +target_ulong helper_udiv(CPUState *env, target_ulong a, target_ulong b) { -#if !defined(TARGET_SPARC64) - env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; -#endif + return helper_udiv_common(env, a, b, 0); } -static const sparc_def_t sparc_defs[] = { -#ifdef TARGET_SPARC64 - { - .name = "Fujitsu Sparc64", - .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 4, - .maxtl = 4, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Fujitsu Sparc64 III", - .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 5, - .maxtl = 4, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Fujitsu Sparc64 IV", - .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Fujitsu Sparc64 V", - .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI UltraSparc I", - .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI UltraSparc II", - .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI UltraSparc IIi", - .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI UltraSparc IIe", - .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Sun UltraSparc III", - .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Sun UltraSparc III Cu", - .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_3, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Sun UltraSparc IIIi", - .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Sun UltraSparc IV", - .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_4, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Sun UltraSparc IV+", - .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT, - }, - { - .name = "Sun UltraSparc IIIi+", - .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_3, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Sun UltraSparc T1", - // defined in sparc_ifu_fdp.v and ctu.h - .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_sun4v, - .nwindows = 8, - .maxtl = 6, - .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT - | CPU_FEATURE_GL, - }, - { - .name = "Sun UltraSparc T2", - // defined in tlu_asi_ctl.v and n2_revid_cust.v - .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_sun4v, - .nwindows = 8, - .maxtl = 6, - .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT - | CPU_FEATURE_GL, - }, - { - .name = "NEC UltraSparc I", - .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)), - .fpu_version = 0x00000000, - .mmu_version = mmu_us_12, - .nwindows = 8, - .maxtl = 5, - .features = CPU_DEFAULT_FEATURES, - }, -#else - { - .name = "Fujitsu MB86900", - .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */ - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 7, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD, - }, - { - .name = "Fujitsu MB86904", - .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x00ffffc0, - .mmu_cxr_mask = 0x000000ff, - .mmu_sfsr_mask = 0x00016fff, - .mmu_trcr_mask = 0x00ffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Fujitsu MB86907", - .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x000000ff, - .mmu_sfsr_mask = 0x00016fff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "LSI L64811", - .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ - .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | - CPU_FEATURE_FSMULD, - }, - { - .name = "Cypress CY7C601", - .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ - .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | - CPU_FEATURE_FSMULD, - }, - { - .name = "Cypress CY7C611", - .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ - .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | - CPU_FEATURE_FSMULD, - }, - { - .name = "TI MicroSparc I", - .iu_version = 0x41000000, - .fpu_version = 4 << 17, - .mmu_version = 0x41000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0x00016fff, - .mmu_trcr_mask = 0x0000003f, - .nwindows = 7, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL | - CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | - CPU_FEATURE_FMUL, - }, - { - .name = "TI MicroSparc II", - .iu_version = 0x42000000, - .fpu_version = 4 << 17, - .mmu_version = 0x02000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x00ffffc0, - .mmu_cxr_mask = 0x000000ff, - .mmu_sfsr_mask = 0x00016fff, - .mmu_trcr_mask = 0x00ffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI MicroSparc IIep", - .iu_version = 0x42000000, - .fpu_version = 4 << 17, - .mmu_version = 0x04000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x00ffffc0, - .mmu_cxr_mask = 0x000000ff, - .mmu_sfsr_mask = 0x00016bff, - .mmu_trcr_mask = 0x00ffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI SuperSparc 40", // STP1020NPGA - .iu_version = 0x41000000, // SuperSPARC 2.x - .fpu_version = 0 << 17, - .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC - .mmu_bm = 0x00002000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x0000ffff, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI SuperSparc 50", // STP1020PGA - .iu_version = 0x40000000, // SuperSPARC 3.x - .fpu_version = 0 << 17, - .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC - .mmu_bm = 0x00002000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x0000ffff, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI SuperSparc 51", - .iu_version = 0x40000000, // SuperSPARC 3.x - .fpu_version = 0 << 17, - .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC - .mmu_bm = 0x00002000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x0000ffff, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .mxcc_version = 0x00000104, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI SuperSparc 60", // STP1020APGA - .iu_version = 0x40000000, // SuperSPARC 3.x - .fpu_version = 0 << 17, - .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC - .mmu_bm = 0x00002000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x0000ffff, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI SuperSparc 61", - .iu_version = 0x44000000, // SuperSPARC 3.x - .fpu_version = 0 << 17, - .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC - .mmu_bm = 0x00002000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x0000ffff, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .mxcc_version = 0x00000104, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "TI SuperSparc II", - .iu_version = 0x40000000, // SuperSPARC II 1.x - .fpu_version = 0 << 17, - .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC - .mmu_bm = 0x00002000, - .mmu_ctpr_mask = 0xffffffc0, - .mmu_cxr_mask = 0x0000ffff, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .mxcc_version = 0x00000104, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Ross RT625", - .iu_version = 0x1e000000, - .fpu_version = 1 << 17, - .mmu_version = 0x1e000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "Ross RT620", - .iu_version = 0x1f000000, - .fpu_version = 1 << 17, - .mmu_version = 0x1f000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "BIT B5010", - .iu_version = 0x20000000, - .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */ - .mmu_version = 0x20000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | - CPU_FEATURE_FSMULD, - }, - { - .name = "Matsushita MN10501", - .iu_version = 0x50000000, - .fpu_version = 0 << 17, - .mmu_version = 0x50000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT | - CPU_FEATURE_FSMULD, - }, - { - .name = "Weitek W8601", - .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ - .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES, - }, - { - .name = "LEON2", - .iu_version = 0xf2000000, - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0xf2000000, - .mmu_bm = 0x00004000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN, - }, - { - .name = "LEON3", - .iu_version = 0xf3000000, - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0xf3000000, - .mmu_bm = 0x00000000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, - .mmu_sfsr_mask = 0xffffffff, - .mmu_trcr_mask = 0xffffffff, - .nwindows = 8, - .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN | - CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL, - }, -#endif -}; - -static const char * const feature_name[] = { - "float", - "float128", - "swap", - "mul", - "div", - "flush", - "fsqrt", - "fmul", - "vis1", - "vis2", - "fsmuld", - "hypv", - "cmt", - "gl", -}; - -static void print_features(FILE *f, fprintf_function cpu_fprintf, - uint32_t features, const char *prefix) +target_ulong helper_udiv_cc(CPUState *env, target_ulong a, target_ulong b) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(feature_name); i++) - if (feature_name[i] && (features & (1 << i))) { - if (prefix) - (*cpu_fprintf)(f, "%s", prefix); - (*cpu_fprintf)(f, "%s ", feature_name[i]); - } + return helper_udiv_common(env, a, b, 1); } -static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features) +static target_ulong helper_sdiv_common(CPUState *env, target_ulong a, + target_ulong b, int cc) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(feature_name); i++) - if (feature_name[i] && !strcmp(flagname, feature_name[i])) { - *features |= 1 << i; - return; - } - fprintf(stderr, "CPU feature %s not found\n", flagname); -} + int overflow = 0; + int64_t x0; + int32_t x1; -static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) -{ - unsigned int i; - const sparc_def_t *def = NULL; - char *s = strdup(cpu_model); - char *featurestr, *name = strtok(s, ","); - uint32_t plus_features = 0; - uint32_t minus_features = 0; - uint64_t iu_version; - uint32_t fpu_version, mmu_version, nwindows; + x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); + x1 = (b & 0xffffffff); - for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) { - if (strcasecmp(name, sparc_defs[i].name) == 0) { - def = &sparc_defs[i]; - } + if (x1 == 0) { + helper_raise_exception(env, TT_DIV_ZERO); } - if (!def) - goto error; - memcpy(cpu_def, def, sizeof(*def)); - - featurestr = strtok(NULL, ","); - while (featurestr) { - char *val; - - if (featurestr[0] == '+') { - add_flagname_to_bitmaps(featurestr + 1, &plus_features); - } else if (featurestr[0] == '-') { - add_flagname_to_bitmaps(featurestr + 1, &minus_features); - } else if ((val = strchr(featurestr, '='))) { - *val = 0; val++; - if (!strcmp(featurestr, "iu_version")) { - char *err; - - iu_version = strtoll(val, &err, 0); - if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - cpu_def->iu_version = iu_version; -#ifdef DEBUG_FEATURES - fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version); -#endif - } else if (!strcmp(featurestr, "fpu_version")) { - char *err; - - fpu_version = strtol(val, &err, 0); - if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - cpu_def->fpu_version = fpu_version; -#ifdef DEBUG_FEATURES - fprintf(stderr, "fpu_version %x\n", fpu_version); -#endif - } else if (!strcmp(featurestr, "mmu_version")) { - char *err; - - mmu_version = strtol(val, &err, 0); - if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - cpu_def->mmu_version = mmu_version; -#ifdef DEBUG_FEATURES - fprintf(stderr, "mmu_version %x\n", mmu_version); -#endif - } else if (!strcmp(featurestr, "nwindows")) { - char *err; - nwindows = strtol(val, &err, 0); - if (!*val || *err || nwindows > MAX_NWINDOWS || - nwindows < MIN_NWINDOWS) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - cpu_def->nwindows = nwindows; -#ifdef DEBUG_FEATURES - fprintf(stderr, "nwindows %d\n", nwindows); -#endif - } else { - fprintf(stderr, "unrecognized feature %s\n", featurestr); - goto error; - } - } else { - fprintf(stderr, "feature string `%s' not in format " - "(+feature|-feature|feature=xyz)\n", featurestr); - goto error; - } - featurestr = strtok(NULL, ","); + x0 = x0 / x1; + if ((int32_t) x0 != x0) { + x0 = x0 < 0 ? 0x80000000 : 0x7fffffff; + overflow = 1; } - cpu_def->features |= plus_features; - cpu_def->features &= ~minus_features; -#ifdef DEBUG_FEATURES - print_features(stderr, fprintf, cpu_def->features, NULL); -#endif - free(s); - return 0; - error: - free(s); - return -1; -} - -void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) { - (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ", - sparc_defs[i].name, - sparc_defs[i].iu_version, - sparc_defs[i].fpu_version, - sparc_defs[i].mmu_version, - sparc_defs[i].nwindows); - print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES & - ~sparc_defs[i].features, "-"); - print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES & - sparc_defs[i].features, "+"); - (*cpu_fprintf)(f, "\n"); + if (cc) { + env->cc_dst = x0; + env->cc_src2 = overflow; + env->cc_op = CC_OP_DIV; } - (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): "); - print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL); - (*cpu_fprintf)(f, "\n"); - (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): "); - print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL); - (*cpu_fprintf)(f, "\n"); - (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version " - "fpu_version mmu_version nwindows\n"); + return x0; } -static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf, - uint32_t cc) +target_ulong helper_sdiv(CPUState *env, target_ulong a, target_ulong b) { - cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-', - cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-', - cc & PSR_CARRY? 'C' : '-'); + return helper_sdiv_common(env, a, b, 0); } -#ifdef TARGET_SPARC64 -#define REGS_PER_LINE 4 -#else -#define REGS_PER_LINE 8 -#endif - -void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, - int flags) +target_ulong helper_sdiv_cc(CPUState *env, target_ulong a, target_ulong b) { - int i, x; - - cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, - env->npc); - cpu_fprintf(f, "General Registers:\n"); - - for (i = 0; i < 8; i++) { - if (i % REGS_PER_LINE == 0) { - cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1); - } - cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]); - if (i % REGS_PER_LINE == REGS_PER_LINE - 1) { - cpu_fprintf(f, "\n"); - } - } - cpu_fprintf(f, "\nCurrent Register Window:\n"); - for (x = 0; x < 3; x++) { - for (i = 0; i < 8; i++) { - if (i % REGS_PER_LINE == 0) { - cpu_fprintf(f, "%%%c%d-%d: ", - x == 0 ? 'o' : (x == 1 ? 'l' : 'i'), - i, i + REGS_PER_LINE - 1); - } - cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]); - if (i % REGS_PER_LINE == REGS_PER_LINE - 1) { - cpu_fprintf(f, "\n"); - } - } - } - cpu_fprintf(f, "\nFloating Point Registers:\n"); - for (i = 0; i < TARGET_FPREGS; i++) { - if ((i & 3) == 0) - cpu_fprintf(f, "%%f%02d:", i); - cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]); - if ((i & 3) == 3) - cpu_fprintf(f, "\n"); - } -#ifdef TARGET_SPARC64 - cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate, - (unsigned)cpu_get_ccr(env)); - cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT); - cpu_fprintf(f, " xcc: "); - cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4)); - cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl, - env->psrpil); - cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d " - "cleanwin: %d cwp: %d\n", - env->cansave, env->canrestore, env->otherwin, env->wstate, - env->cleanwin, env->nwindows - 1 - env->cwp); - cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: " - TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs); -#else - cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env)); - cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env)); - cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-', - env->psrps? 'P' : '-', env->psret? 'E' : '-', - env->wim); - cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n", - env->fsr, env->y); -#endif + return helper_sdiv_common(env, a, b, 1); } diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 2d36af3a31..615ddefa92 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -1,44 +1,44 @@ #include "def-helper.h" #ifndef TARGET_SPARC64 -DEF_HELPER_0(rett, void) -DEF_HELPER_1(wrpsr, void, tl) -DEF_HELPER_0(rdpsr, tl) +DEF_HELPER_1(rett, void, env) +DEF_HELPER_2(wrpsr, void, env, tl) +DEF_HELPER_1(rdpsr, tl, env) #else -DEF_HELPER_1(wrpil, void, tl) -DEF_HELPER_1(wrpstate, void, tl) -DEF_HELPER_0(done, void) -DEF_HELPER_0(retry, void) -DEF_HELPER_0(flushw, void) -DEF_HELPER_0(saved, void) -DEF_HELPER_0(restored, void) -DEF_HELPER_0(rdccr, tl) -DEF_HELPER_1(wrccr, void, tl) -DEF_HELPER_0(rdcwp, tl) -DEF_HELPER_1(wrcwp, void, tl) -DEF_HELPER_2(array8, tl, tl, tl) -DEF_HELPER_2(alignaddr, tl, tl, tl) +DEF_HELPER_2(wrpil, void, env, tl) +DEF_HELPER_2(wrpstate, void, env, tl) +DEF_HELPER_1(done, void, env) +DEF_HELPER_1(retry, void, env) +DEF_HELPER_1(flushw, void, env) +DEF_HELPER_1(saved, void, env) +DEF_HELPER_1(restored, void, env) +DEF_HELPER_1(rdccr, tl, env) +DEF_HELPER_2(wrccr, void, env, tl) +DEF_HELPER_1(rdcwp, tl, env) +DEF_HELPER_2(wrcwp, void, env, tl) +DEF_HELPER_3(array8, tl, env, tl, tl) +DEF_HELPER_3(alignaddr, tl, env, tl, tl) DEF_HELPER_1(popc, tl, tl) DEF_HELPER_3(ldda_asi, void, tl, int, int) DEF_HELPER_4(ldf_asi, void, tl, int, int, int) DEF_HELPER_4(stf_asi, void, tl, int, int, int) DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32) DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32) -DEF_HELPER_1(set_softint, void, i64) -DEF_HELPER_1(clear_softint, void, i64) -DEF_HELPER_1(write_softint, void, i64) +DEF_HELPER_2(set_softint, void, env, i64) +DEF_HELPER_2(clear_softint, void, env, i64) +DEF_HELPER_2(write_softint, void, env, i64) DEF_HELPER_2(tick_set_count, void, ptr, i64) DEF_HELPER_1(tick_get_count, i64, ptr) DEF_HELPER_2(tick_set_limit, void, ptr, i64) #endif DEF_HELPER_2(check_align, void, tl, i32) -DEF_HELPER_0(debug, void) -DEF_HELPER_0(save, void) -DEF_HELPER_0(restore, void) -DEF_HELPER_2(udiv, tl, tl, tl) -DEF_HELPER_2(udiv_cc, tl, tl, tl) -DEF_HELPER_2(sdiv, tl, tl, tl) -DEF_HELPER_2(sdiv_cc, tl, tl, tl) +DEF_HELPER_1(debug, void, env) +DEF_HELPER_1(save, void, env) +DEF_HELPER_1(restore, void, env) +DEF_HELPER_3(udiv, tl, env, tl, tl) +DEF_HELPER_3(udiv_cc, tl, env, tl, tl) +DEF_HELPER_3(sdiv, tl, env, tl, tl) +DEF_HELPER_3(sdiv_cc, tl, env, tl, tl) DEF_HELPER_2(stdf, void, tl, int) DEF_HELPER_2(lddf, void, tl, int) DEF_HELPER_2(ldqf, void, tl, int) @@ -47,119 +47,119 @@ DEF_HELPER_2(stqf, void, tl, int) DEF_HELPER_4(ld_asi, i64, tl, int, int, int) DEF_HELPER_4(st_asi, void, tl, i64, int, int) #endif -DEF_HELPER_1(ldfsr, void, i32) -DEF_HELPER_0(check_ieee_exceptions, void) -DEF_HELPER_0(clear_float_exceptions, void) +DEF_HELPER_2(ldfsr, void, env, i32) +DEF_HELPER_1(check_ieee_exceptions, void, env) +DEF_HELPER_1(clear_float_exceptions, void, env) DEF_HELPER_1(fabss, f32, f32) -DEF_HELPER_1(fsqrts, f32, f32) -DEF_HELPER_0(fsqrtd, void) -DEF_HELPER_2(fcmps, void, f32, f32) -DEF_HELPER_0(fcmpd, void) -DEF_HELPER_2(fcmpes, void, f32, f32) -DEF_HELPER_0(fcmped, void) -DEF_HELPER_0(fsqrtq, void) -DEF_HELPER_0(fcmpq, void) -DEF_HELPER_0(fcmpeq, void) +DEF_HELPER_2(fsqrts, f32, env, f32) +DEF_HELPER_1(fsqrtd, void, env) +DEF_HELPER_3(fcmps, void, env, f32, f32) +DEF_HELPER_1(fcmpd, void, env) +DEF_HELPER_3(fcmpes, void, env, f32, f32) +DEF_HELPER_1(fcmped, void, env) +DEF_HELPER_1(fsqrtq, void, env) +DEF_HELPER_1(fcmpq, void, env) +DEF_HELPER_1(fcmpeq, void, env) #ifdef TARGET_SPARC64 -DEF_HELPER_1(ldxfsr, void, i64) -DEF_HELPER_0(fabsd, void) -DEF_HELPER_2(fcmps_fcc1, void, f32, f32) -DEF_HELPER_2(fcmps_fcc2, void, f32, f32) -DEF_HELPER_2(fcmps_fcc3, void, f32, f32) -DEF_HELPER_0(fcmpd_fcc1, void) -DEF_HELPER_0(fcmpd_fcc2, void) -DEF_HELPER_0(fcmpd_fcc3, void) -DEF_HELPER_2(fcmpes_fcc1, void, f32, f32) -DEF_HELPER_2(fcmpes_fcc2, void, f32, f32) -DEF_HELPER_2(fcmpes_fcc3, void, f32, f32) -DEF_HELPER_0(fcmped_fcc1, void) -DEF_HELPER_0(fcmped_fcc2, void) -DEF_HELPER_0(fcmped_fcc3, void) -DEF_HELPER_0(fabsq, void) -DEF_HELPER_0(fcmpq_fcc1, void) -DEF_HELPER_0(fcmpq_fcc2, void) -DEF_HELPER_0(fcmpq_fcc3, void) -DEF_HELPER_0(fcmpeq_fcc1, void) -DEF_HELPER_0(fcmpeq_fcc2, void) -DEF_HELPER_0(fcmpeq_fcc3, void) +DEF_HELPER_2(ldxfsr, void, env, i64) +DEF_HELPER_1(fabsd, void, env) +DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32) +DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32) +DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32) +DEF_HELPER_1(fcmpd_fcc1, void, env) +DEF_HELPER_1(fcmpd_fcc2, void, env) +DEF_HELPER_1(fcmpd_fcc3, void, env) +DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32) +DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32) +DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32) +DEF_HELPER_1(fcmped_fcc1, void, env) +DEF_HELPER_1(fcmped_fcc2, void, env) +DEF_HELPER_1(fcmped_fcc3, void, env) +DEF_HELPER_1(fabsq, void, env) +DEF_HELPER_1(fcmpq_fcc1, void, env) +DEF_HELPER_1(fcmpq_fcc2, void, env) +DEF_HELPER_1(fcmpq_fcc3, void, env) +DEF_HELPER_1(fcmpeq_fcc1, void, env) +DEF_HELPER_1(fcmpeq_fcc2, void, env) +DEF_HELPER_1(fcmpeq_fcc3, void, env) #endif -DEF_HELPER_1(raise_exception, void, int) +DEF_HELPER_2(raise_exception, void, env, int) DEF_HELPER_0(shutdown, void) -#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void) -#define F_HELPER_DQ_0_0(name) \ - F_HELPER_0_0(name ## d); \ - F_HELPER_0_0(name ## q) +#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env) +#define F_HELPER_DQ_0_1(name) \ + F_HELPER_0_1(name ## d); \ + F_HELPER_0_1(name ## q) -F_HELPER_DQ_0_0(add); -F_HELPER_DQ_0_0(sub); -F_HELPER_DQ_0_0(mul); -F_HELPER_DQ_0_0(div); +F_HELPER_DQ_0_1(add); +F_HELPER_DQ_0_1(sub); +F_HELPER_DQ_0_1(mul); +F_HELPER_DQ_0_1(div); -DEF_HELPER_2(fadds, f32, f32, f32) -DEF_HELPER_2(fsubs, f32, f32, f32) -DEF_HELPER_2(fmuls, f32, f32, f32) -DEF_HELPER_2(fdivs, f32, f32, f32) +DEF_HELPER_3(fadds, f32, env, f32, f32) +DEF_HELPER_3(fsubs, f32, env, f32, f32) +DEF_HELPER_3(fmuls, f32, env, f32, f32) +DEF_HELPER_3(fdivs, f32, env, f32, f32) -DEF_HELPER_2(fsmuld, void, f32, f32) -F_HELPER_0_0(dmulq); +DEF_HELPER_3(fsmuld, void, env, f32, f32) +F_HELPER_0_1(dmulq); DEF_HELPER_1(fnegs, f32, f32) -DEF_HELPER_1(fitod, void, s32) -DEF_HELPER_1(fitoq, void, s32) +DEF_HELPER_2(fitod, void, env, s32) +DEF_HELPER_2(fitoq, void, env, s32) -DEF_HELPER_1(fitos, f32, s32) +DEF_HELPER_2(fitos, f32, env, s32) #ifdef TARGET_SPARC64 -DEF_HELPER_0(fnegd, void) -DEF_HELPER_0(fnegq, void) -DEF_HELPER_0(fxtos, i32) -F_HELPER_DQ_0_0(xto); +DEF_HELPER_1(fnegd, void, env) +DEF_HELPER_1(fnegq, void, env) +DEF_HELPER_1(fxtos, i32, env) +F_HELPER_DQ_0_1(xto); #endif -DEF_HELPER_0(fdtos, f32) -DEF_HELPER_1(fstod, void, f32) -DEF_HELPER_0(fqtos, f32) -DEF_HELPER_1(fstoq, void, f32) -F_HELPER_0_0(qtod); -F_HELPER_0_0(dtoq); -DEF_HELPER_1(fstoi, s32, f32) -DEF_HELPER_0(fdtoi, s32) -DEF_HELPER_0(fqtoi, s32) +DEF_HELPER_1(fdtos, f32, env) +DEF_HELPER_2(fstod, void, env, f32) +DEF_HELPER_1(fqtos, f32, env) +DEF_HELPER_2(fstoq, void, env, f32) +F_HELPER_0_1(qtod); +F_HELPER_0_1(dtoq); +DEF_HELPER_2(fstoi, s32, env, f32) +DEF_HELPER_1(fdtoi, s32, env) +DEF_HELPER_1(fqtoi, s32, env) #ifdef TARGET_SPARC64 -DEF_HELPER_1(fstox, void, i32) -F_HELPER_0_0(dtox); -F_HELPER_0_0(qtox); -F_HELPER_0_0(aligndata); +DEF_HELPER_2(fstox, void, env, i32) +F_HELPER_0_1(dtox); +F_HELPER_0_1(qtox); +F_HELPER_0_1(aligndata); -F_HELPER_0_0(pmerge); -F_HELPER_0_0(mul8x16); -F_HELPER_0_0(mul8x16al); -F_HELPER_0_0(mul8x16au); -F_HELPER_0_0(mul8sux16); -F_HELPER_0_0(mul8ulx16); -F_HELPER_0_0(muld8sux16); -F_HELPER_0_0(muld8ulx16); -F_HELPER_0_0(expand); +F_HELPER_0_1(pmerge); +F_HELPER_0_1(mul8x16); +F_HELPER_0_1(mul8x16al); +F_HELPER_0_1(mul8x16au); +F_HELPER_0_1(mul8sux16); +F_HELPER_0_1(mul8ulx16); +F_HELPER_0_1(muld8sux16); +F_HELPER_0_1(muld8ulx16); +F_HELPER_0_1(expand); #define VIS_HELPER(name) \ - F_HELPER_0_0(name##16); \ - DEF_HELPER_2(f ## name ## 16s, i32, i32, i32) \ - F_HELPER_0_0(name##32); \ - DEF_HELPER_2(f ## name ## 32s, i32, i32, i32) + F_HELPER_0_1(name##16); \ + DEF_HELPER_3(f ## name ## 16s, i32, env, i32, i32) \ + F_HELPER_0_1(name##32); \ + DEF_HELPER_3(f ## name ## 32s, i32, env, i32, i32) VIS_HELPER(padd); VIS_HELPER(psub); #define VIS_CMPHELPER(name) \ - DEF_HELPER_0(f##name##16, i64); \ - DEF_HELPER_0(f##name##32, i64) + DEF_HELPER_1(f##name##16, i64, env); \ + DEF_HELPER_1(f##name##32, i64, env) VIS_CMPHELPER(cmpgt); VIS_CMPHELPER(cmpeq); VIS_CMPHELPER(cmple); VIS_CMPHELPER(cmpne); #endif -#undef F_HELPER_0_0 -#undef F_HELPER_DQ_0_0 +#undef F_HELPER_0_1 +#undef F_HELPER_DQ_0_1 #undef VIS_HELPER #undef VIS_CMPHELPER -DEF_HELPER_0(compute_psr, void); -DEF_HELPER_0(compute_C_icc, i32); +DEF_HELPER_1(compute_psr, void, env); +DEF_HELPER_1(compute_C_icc, i32, env); #include "def-helper.h" diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c new file mode 100644 index 0000000000..3a749bf5df --- /dev/null +++ b/target-sparc/int32_helper.c @@ -0,0 +1,163 @@ +/* + * Sparc32 interrupt helpers + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "trace.h" + +//#define DEBUG_PCALL + +#ifdef DEBUG_PCALL +static const char * const excp_names[0x80] = { + [TT_TFAULT] = "Instruction Access Fault", + [TT_ILL_INSN] = "Illegal Instruction", + [TT_PRIV_INSN] = "Privileged Instruction", + [TT_NFPU_INSN] = "FPU Disabled", + [TT_WIN_OVF] = "Window Overflow", + [TT_WIN_UNF] = "Window Underflow", + [TT_UNALIGNED] = "Unaligned Memory Access", + [TT_FP_EXCP] = "FPU Exception", + [TT_DFAULT] = "Data Access Fault", + [TT_TOVF] = "Tag Overflow", + [TT_EXTINT | 0x1] = "External Interrupt 1", + [TT_EXTINT | 0x2] = "External Interrupt 2", + [TT_EXTINT | 0x3] = "External Interrupt 3", + [TT_EXTINT | 0x4] = "External Interrupt 4", + [TT_EXTINT | 0x5] = "External Interrupt 5", + [TT_EXTINT | 0x6] = "External Interrupt 6", + [TT_EXTINT | 0x7] = "External Interrupt 7", + [TT_EXTINT | 0x8] = "External Interrupt 8", + [TT_EXTINT | 0x9] = "External Interrupt 9", + [TT_EXTINT | 0xa] = "External Interrupt 10", + [TT_EXTINT | 0xb] = "External Interrupt 11", + [TT_EXTINT | 0xc] = "External Interrupt 12", + [TT_EXTINT | 0xd] = "External Interrupt 13", + [TT_EXTINT | 0xe] = "External Interrupt 14", + [TT_EXTINT | 0xf] = "External Interrupt 15", + [TT_TOVF] = "Tag Overflow", + [TT_CODE_ACCESS] = "Instruction Access Error", + [TT_DATA_ACCESS] = "Data Access Error", + [TT_DIV_ZERO] = "Division By Zero", + [TT_NCP_INSN] = "Coprocessor Disabled", +}; +#endif + +void do_interrupt(CPUState *env) +{ + int cwp, intno = env->exception_index; + +#ifdef DEBUG_PCALL + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + const char *name; + + if (intno < 0 || intno >= 0x100) { + name = "Unknown"; + } else if (intno >= 0x80) { + name = "Trap Instruction"; + } else { + name = excp_names[intno]; + if (!name) { + name = "Unknown"; + } + } + + qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", + count, name, intno, + env->pc, + env->npc, env->regwptr[6]); + log_cpu_state(env, 0); +#if 0 + { + int i; + uint8_t *ptr; + + qemu_log(" code="); + ptr = (uint8_t *)env->pc; + for (i = 0; i < 16; i++) { + qemu_log(" %02x", ldub(ptr + i)); + } + qemu_log("\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->psret == 0) { + cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", + env->exception_index); + return; + } +#endif + env->psret = 0; + cwp = cpu_cwp_dec(env, env->cwp - 1); + cpu_set_cwp(env, cwp); + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; + env->psrps = env->psrs; + env->psrs = 1; + env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = -1; + +#if !defined(CONFIG_USER_ONLY) + /* IRQ acknowledgment */ + if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) { + env->qemu_irq_ack(env, env->irq_manager, intno); + } +#endif +} + +#if !defined(CONFIG_USER_ONLY) +static void leon3_cache_control_int(CPUState *env) +{ + uint32_t state = 0; + + if (env->cache_control & CACHE_CTRL_IF) { + /* Instruction cache state */ + state = env->cache_control & CACHE_STATE_MASK; + if (state == CACHE_ENABLED) { + state = CACHE_FROZEN; + trace_int_helper_icache_freeze(); + } + + env->cache_control &= ~CACHE_STATE_MASK; + env->cache_control |= state; + } + + if (env->cache_control & CACHE_CTRL_DF) { + /* Data cache state */ + state = (env->cache_control >> 2) & CACHE_STATE_MASK; + if (state == CACHE_ENABLED) { + state = CACHE_FROZEN; + trace_int_helper_dcache_freeze(); + } + + env->cache_control &= ~(CACHE_STATE_MASK << 2); + env->cache_control |= (state << 2); + } +} + +void leon3_irq_manager(CPUState *env, void *irq_manager, int intno) +{ + leon3_irq_ack(irq_manager, intno); + leon3_cache_control_int(env); +} +#endif diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c new file mode 100644 index 0000000000..1d471db999 --- /dev/null +++ b/target-sparc/int64_helper.c @@ -0,0 +1,201 @@ +/* + * Sparc64 interrupt helpers + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "helper.h" +#include "trace.h" + +//#define DEBUG_PCALL + +#ifdef DEBUG_PCALL +static const char * const excp_names[0x80] = { + [TT_TFAULT] = "Instruction Access Fault", + [TT_TMISS] = "Instruction Access MMU Miss", + [TT_CODE_ACCESS] = "Instruction Access Error", + [TT_ILL_INSN] = "Illegal Instruction", + [TT_PRIV_INSN] = "Privileged Instruction", + [TT_NFPU_INSN] = "FPU Disabled", + [TT_FP_EXCP] = "FPU Exception", + [TT_TOVF] = "Tag Overflow", + [TT_CLRWIN] = "Clean Windows", + [TT_DIV_ZERO] = "Division By Zero", + [TT_DFAULT] = "Data Access Fault", + [TT_DMISS] = "Data Access MMU Miss", + [TT_DATA_ACCESS] = "Data Access Error", + [TT_DPROT] = "Data Protection Error", + [TT_UNALIGNED] = "Unaligned Memory Access", + [TT_PRIV_ACT] = "Privileged Action", + [TT_EXTINT | 0x1] = "External Interrupt 1", + [TT_EXTINT | 0x2] = "External Interrupt 2", + [TT_EXTINT | 0x3] = "External Interrupt 3", + [TT_EXTINT | 0x4] = "External Interrupt 4", + [TT_EXTINT | 0x5] = "External Interrupt 5", + [TT_EXTINT | 0x6] = "External Interrupt 6", + [TT_EXTINT | 0x7] = "External Interrupt 7", + [TT_EXTINT | 0x8] = "External Interrupt 8", + [TT_EXTINT | 0x9] = "External Interrupt 9", + [TT_EXTINT | 0xa] = "External Interrupt 10", + [TT_EXTINT | 0xb] = "External Interrupt 11", + [TT_EXTINT | 0xc] = "External Interrupt 12", + [TT_EXTINT | 0xd] = "External Interrupt 13", + [TT_EXTINT | 0xe] = "External Interrupt 14", + [TT_EXTINT | 0xf] = "External Interrupt 15", +}; +#endif + +void do_interrupt(CPUState *env) +{ + int intno = env->exception_index; + trap_state *tsptr; + +#ifdef DEBUG_PCALL + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + const char *name; + + if (intno < 0 || intno >= 0x180) { + name = "Unknown"; + } else if (intno >= 0x100) { + name = "Trap Instruction"; + } else if (intno >= 0xc0) { + name = "Window Fill"; + } else if (intno >= 0x80) { + name = "Window Spill"; + } else { + name = excp_names[intno]; + if (!name) { + name = "Unknown"; + } + } + + qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 + " SP=%016" PRIx64 "\n", + count, name, intno, + env->pc, + env->npc, env->regwptr[6]); + log_cpu_state(env, 0); +#if 0 + { + int i; + uint8_t *ptr; + + qemu_log(" code="); + ptr = (uint8_t *)env->pc; + for (i = 0; i < 16; i++) { + qemu_log(" %02x", ldub(ptr + i)); + } + qemu_log("\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->tl >= env->maxtl) { + cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d)," + " Error state", env->exception_index, env->tl, env->maxtl); + return; + } +#endif + if (env->tl < env->maxtl - 1) { + env->tl++; + } else { + env->pstate |= PS_RED; + if (env->tl < env->maxtl) { + env->tl++; + } + } + tsptr = cpu_tsptr(env); + + tsptr->tstate = (cpu_get_ccr(env) << 32) | + ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | + cpu_get_cwp64(env); + tsptr->tpc = env->pc; + tsptr->tnpc = env->npc; + tsptr->tt = intno; + + switch (intno) { + case TT_IVEC: + cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG); + break; + case TT_TFAULT: + case TT_DFAULT: + case TT_TMISS ... TT_TMISS + 3: + case TT_DMISS ... TT_DMISS + 3: + case TT_DPROT ... TT_DPROT + 3: + cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG); + break; + default: + cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG); + break; + } + + if (intno == TT_CLRWIN) { + cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1)); + } else if ((intno & 0x1c0) == TT_SPILL) { + cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); + } else if ((intno & 0x1c0) == TT_FILL) { + cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1)); + } + env->tbr &= ~0x7fffULL; + env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = -1; +} + +trap_state *cpu_tsptr(CPUState* env) +{ + return &env->ts[env->tl & MAXTL_MASK]; +} + +static bool do_modify_softint(CPUState *env, uint32_t value) +{ + if (env->softint != value) { + env->softint = value; +#if !defined(CONFIG_USER_ONLY) + if (cpu_interrupts_enabled(env)) { + cpu_check_irqs(env); + } +#endif + return true; + } + return false; +} + +void helper_set_softint(CPUState *env, uint64_t value) +{ + if (do_modify_softint(env, env->softint | (uint32_t)value)) { + trace_int_helper_set_softint(env->softint); + } +} + +void helper_clear_softint(CPUState *env, uint64_t value) +{ + if (do_modify_softint(env, env->softint & (uint32_t)~value)) { + trace_int_helper_clear_softint(env->softint); + } +} + +void helper_write_softint(CPUState *env, uint64_t value) +{ + if (do_modify_softint(env, (uint32_t)value)) { + trace_int_helper_write_softint(env->softint); + } +} diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c new file mode 100644 index 0000000000..1fb3996fdb --- /dev/null +++ b/target-sparc/ldst_helper.c @@ -0,0 +1,2434 @@ +/* + * Helpers for loads and stores + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +//#define DEBUG_MMU +//#define DEBUG_MXCC +//#define DEBUG_UNALIGNED +//#define DEBUG_UNASSIGNED +//#define DEBUG_ASI +//#define DEBUG_CACHE_CONTROL + +#ifdef DEBUG_MMU +#define DPRINTF_MMU(fmt, ...) \ + do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF_MMU(fmt, ...) do {} while (0) +#endif + +#ifdef DEBUG_MXCC +#define DPRINTF_MXCC(fmt, ...) \ + do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF_MXCC(fmt, ...) do {} while (0) +#endif + +#ifdef DEBUG_ASI +#define DPRINTF_ASI(fmt, ...) \ + do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0) +#endif + +#ifdef DEBUG_CACHE_CONTROL +#define DPRINTF_CACHE_CONTROL(fmt, ...) \ + do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0) +#endif + +#ifdef TARGET_SPARC64 +#ifndef TARGET_ABI32 +#define AM_CHECK(env1) ((env1)->pstate & PS_AM) +#else +#define AM_CHECK(env1) (1) +#endif +#endif + +#define DT0 (env->dt0) +#define DT1 (env->dt1) +#define QT0 (env->qt0) +#define QT1 (env->qt1) + +#if !defined(CONFIG_USER_ONLY) +static void do_unassigned_access(target_phys_addr_t addr, int is_write, + int is_exec, int is_asi, int size); +#else +#ifdef TARGET_SPARC64 +static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi, int size); +#endif +#endif + +#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) +/* Calculates TSB pointer value for fault page size 8k or 64k */ +static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, + uint64_t tag_access_register, + int page_size) +{ + uint64_t tsb_base = tsb_register & ~0x1fffULL; + int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0; + int tsb_size = tsb_register & 0xf; + + /* discard lower 13 bits which hold tag access context */ + uint64_t tag_access_va = tag_access_register & ~0x1fffULL; + + /* now reorder bits */ + uint64_t tsb_base_mask = ~0x1fffULL; + uint64_t va = tag_access_va; + + /* move va bits to correct position */ + if (page_size == 8*1024) { + va >>= 9; + } else if (page_size == 64*1024) { + va >>= 12; + } + + if (tsb_size) { + tsb_base_mask <<= tsb_size; + } + + /* calculate tsb_base mask and adjust va if split is in use */ + if (tsb_split) { + if (page_size == 8*1024) { + va &= ~(1ULL << (13 + tsb_size)); + } else if (page_size == 64*1024) { + va |= (1ULL << (13 + tsb_size)); + } + tsb_base_mask <<= 1; + } + + return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL; +} + +/* Calculates tag target register value by reordering bits + in tag access register */ +static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) +{ + return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); +} + +static void replace_tlb_entry(SparcTLBEntry *tlb, + uint64_t tlb_tag, uint64_t tlb_tte, + CPUState *env1) +{ + target_ulong mask, size, va, offset; + + /* flush page range if translation is valid */ + if (TTE_IS_VALID(tlb->tte)) { + + mask = 0xffffffffffffe000ULL; + mask <<= 3 * ((tlb->tte >> 61) & 3); + size = ~mask + 1; + + va = tlb->tag & mask; + + for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) { + tlb_flush_page(env1, va + offset); + } + } + + tlb->tag = tlb_tag; + tlb->tte = tlb_tte; +} + +static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, + const char *strmmu, CPUState *env1) +{ + unsigned int i; + target_ulong mask; + uint64_t context; + + int is_demap_context = (demap_addr >> 6) & 1; + + /* demap context */ + switch ((demap_addr >> 4) & 3) { + case 0: /* primary */ + context = env1->dmmu.mmu_primary_context; + break; + case 1: /* secondary */ + context = env1->dmmu.mmu_secondary_context; + break; + case 2: /* nucleus */ + context = 0; + break; + case 3: /* reserved */ + default: + return; + } + + for (i = 0; i < 64; i++) { + if (TTE_IS_VALID(tlb[i].tte)) { + + if (is_demap_context) { + /* will remove non-global entries matching context value */ + if (TTE_IS_GLOBAL(tlb[i].tte) || + !tlb_compare_context(&tlb[i], context)) { + continue; + } + } else { + /* demap page + will remove any entry matching VA */ + mask = 0xffffffffffffe000ULL; + mask <<= 3 * ((tlb[i].tte >> 61) & 3); + + if (!compare_masked(demap_addr, tlb[i].tag, mask)) { + continue; + } + + /* entry should be global or matching context value */ + if (!TTE_IS_GLOBAL(tlb[i].tte) && + !tlb_compare_context(&tlb[i], context)) { + continue; + } + } + + replace_tlb_entry(&tlb[i], 0, 0, env1); +#ifdef DEBUG_MMU + DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); + dump_mmu(stdout, fprintf, env1); +#endif + } + } +} + +static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, + uint64_t tlb_tag, uint64_t tlb_tte, + const char *strmmu, CPUState *env1) +{ + unsigned int i, replace_used; + + /* Try replacing invalid entry */ + for (i = 0; i < 64; i++) { + if (!TTE_IS_VALID(tlb[i].tte)) { + replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); +#ifdef DEBUG_MMU + DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); + dump_mmu(stdout, fprintf, env1); +#endif + return; + } + } + + /* All entries are valid, try replacing unlocked entry */ + + for (replace_used = 0; replace_used < 2; ++replace_used) { + + /* Used entries are not replaced on first pass */ + + for (i = 0; i < 64; i++) { + if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) { + + replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); +#ifdef DEBUG_MMU + DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", + strmmu, (replace_used ? "used" : "unused"), i); + dump_mmu(stdout, fprintf, env1); +#endif + return; + } + } + + /* Now reset used bit and search for unused entries again */ + + for (i = 0; i < 64; i++) { + TTE_SET_UNUSED(tlb[i].tte); + } + } + +#ifdef DEBUG_MMU + DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu); +#endif + /* error state? */ +} + +#endif + +static inline target_ulong address_mask(CPUState *env1, target_ulong addr) +{ +#ifdef TARGET_SPARC64 + if (AM_CHECK(env1)) { + addr &= 0xffffffffULL; + } +#endif + return addr; +} + +/* returns true if access using this ASI is to have address translated by MMU + otherwise access is to raw physical address */ +static inline int is_translating_asi(int asi) +{ +#ifdef TARGET_SPARC64 + /* Ultrasparc IIi translating asi + - note this list is defined by cpu implementation + */ + switch (asi) { + case 0x04 ... 0x11: + case 0x16 ... 0x19: + case 0x1E ... 0x1F: + case 0x24 ... 0x2C: + case 0x70 ... 0x73: + case 0x78 ... 0x79: + case 0x80 ... 0xFF: + return 1; + + default: + return 0; + } +#else + /* TODO: check sparc32 bits */ + return 0; +#endif +} + +static inline target_ulong asi_address_mask(CPUState *env1, + int asi, target_ulong addr) +{ + if (is_translating_asi(asi)) { + return address_mask(env, addr); + } else { + return addr; + } +} + +void helper_check_align(target_ulong addr, uint32_t align) +{ + if (addr & align) { +#ifdef DEBUG_UNALIGNED + printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx + "\n", addr, env->pc); +#endif + helper_raise_exception(env, TT_UNALIGNED); + } +} + +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \ + defined(DEBUG_MXCC) +static void dump_mxcc(CPUState *env) +{ + printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 + "\n", + env->mxccdata[0], env->mxccdata[1], + env->mxccdata[2], env->mxccdata[3]); + printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 + "\n" + " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 + "\n", + env->mxccregs[0], env->mxccregs[1], + env->mxccregs[2], env->mxccregs[3], + env->mxccregs[4], env->mxccregs[5], + env->mxccregs[6], env->mxccregs[7]); +} +#endif + +#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ + && defined(DEBUG_ASI) +static void dump_asi(const char *txt, target_ulong addr, int asi, int size, + uint64_t r1) +{ + switch (size) { + case 1: + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, + addr, asi, r1 & 0xff); + break; + case 2: + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, + addr, asi, r1 & 0xffff); + break; + case 4: + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, + addr, asi, r1 & 0xffffffff); + break; + case 8: + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt, + addr, asi, r1); + break; + } +} +#endif + +#ifndef TARGET_SPARC64 +#ifndef CONFIG_USER_ONLY + + +/* Leon3 cache control */ + +static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size) +{ + DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n", + addr, val, size); + + if (size != 4) { + DPRINTF_CACHE_CONTROL("32bits only\n"); + return; + } + + switch (addr) { + case 0x00: /* Cache control */ + + /* These values must always be read as zeros */ + val &= ~CACHE_CTRL_FD; + val &= ~CACHE_CTRL_FI; + val &= ~CACHE_CTRL_IB; + val &= ~CACHE_CTRL_IP; + val &= ~CACHE_CTRL_DP; + + env->cache_control = val; + break; + case 0x04: /* Instruction cache configuration */ + case 0x08: /* Data cache configuration */ + /* Read Only */ + break; + default: + DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr); + break; + }; +} + +static uint64_t leon3_cache_control_ld(target_ulong addr, int size) +{ + uint64_t ret = 0; + + if (size != 4) { + DPRINTF_CACHE_CONTROL("32bits only\n"); + return 0; + } + + switch (addr) { + case 0x00: /* Cache control */ + ret = env->cache_control; + break; + + /* Configuration registers are read and only always keep those + predefined values */ + + case 0x04: /* Instruction cache configuration */ + ret = 0x10220000; + break; + case 0x08: /* Data cache configuration */ + ret = 0x18220000; + break; + default: + DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr); + break; + }; + DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n", + addr, ret, size); + return ret; +} + +uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) +{ + uint64_t ret = 0; +#if defined(DEBUG_MXCC) || defined(DEBUG_ASI) + uint32_t last_addr = addr; +#endif + + helper_check_align(addr, size - 1); + switch (asi) { + case 2: /* SuperSparc MXCC registers and Leon3 cache control */ + switch (addr) { + case 0x00: /* Leon3 Cache Control */ + case 0x08: /* Leon3 Instruction Cache config */ + case 0x0C: /* Leon3 Date Cache config */ + if (env->def->features & CPU_FEATURE_CACHE_CTRL) { + ret = leon3_cache_control_ld(addr, size); + } + break; + case 0x01c00a00: /* MXCC control register */ + if (size == 8) { + ret = env->mxccregs[3]; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00a04: /* MXCC control register */ + if (size == 4) { + ret = env->mxccregs[3]; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00c00: /* Module reset register */ + if (size == 8) { + ret = env->mxccregs[5]; + /* should we do something here? */ + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00f00: /* MBus port address register */ + if (size == 8) { + ret = env->mxccregs[7]; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + default: + DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, + size); + break; + } + DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " + "addr = %08x -> ret = %" PRIx64 "," + "addr = %08x\n", asi, size, sign, last_addr, ret, addr); +#ifdef DEBUG_MXCC + dump_mxcc(env); +#endif + break; + case 3: /* MMU probe */ + { + int mmulev; + + mmulev = (addr >> 8) & 15; + if (mmulev > 4) { + ret = 0; + } else { + ret = mmu_probe(env, addr, mmulev); + } + DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", + addr, mmulev, ret); + } + break; + case 4: /* read MMU regs */ + { + int reg = (addr >> 8) & 0x1f; + + ret = env->mmuregs[reg]; + if (reg == 3) { /* Fault status cleared on read */ + env->mmuregs[3] = 0; + } else if (reg == 0x13) { /* Fault status read */ + ret = env->mmuregs[3]; + } else if (reg == 0x14) { /* Fault address read */ + ret = env->mmuregs[4]; + } + DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret); + } + break; + case 5: /* Turbosparc ITLB Diagnostic */ + case 6: /* Turbosparc DTLB Diagnostic */ + case 7: /* Turbosparc IOTLB Diagnostic */ + break; + case 9: /* Supervisor code access */ + switch (size) { + case 1: + ret = ldub_code(addr); + break; + case 2: + ret = lduw_code(addr); + break; + default: + case 4: + ret = ldl_code(addr); + break; + case 8: + ret = ldq_code(addr); + break; + } + break; + case 0xa: /* User data access */ + switch (size) { + case 1: + ret = ldub_user(addr); + break; + case 2: + ret = lduw_user(addr); + break; + default: + case 4: + ret = ldl_user(addr); + break; + case 8: + ret = ldq_user(addr); + break; + } + break; + case 0xb: /* Supervisor data access */ + switch (size) { + case 1: + ret = ldub_kernel(addr); + break; + case 2: + ret = lduw_kernel(addr); + break; + default: + case 4: + ret = ldl_kernel(addr); + break; + case 8: + ret = ldq_kernel(addr); + break; + } + break; + case 0xc: /* I-cache tag */ + case 0xd: /* I-cache data */ + case 0xe: /* D-cache tag */ + case 0xf: /* D-cache data */ + break; + case 0x20: /* MMU passthrough */ + switch (size) { + case 1: + ret = ldub_phys(addr); + break; + case 2: + ret = lduw_phys(addr); + break; + default: + case 4: + ret = ldl_phys(addr); + break; + case 8: + ret = ldq_phys(addr); + break; + } + break; + case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ + switch (size) { + case 1: + ret = ldub_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + case 2: + ret = lduw_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + default: + case 4: + ret = ldl_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + case 8: + ret = ldq_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + } + break; + case 0x30: /* Turbosparc secondary cache diagnostic */ + case 0x31: /* Turbosparc RAM snoop */ + case 0x32: /* Turbosparc page table descriptor diagnostic */ + case 0x39: /* data cache diagnostic register */ + ret = 0; + break; + case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ + { + int reg = (addr >> 8) & 3; + + switch (reg) { + case 0: /* Breakpoint Value (Addr) */ + ret = env->mmubpregs[reg]; + break; + case 1: /* Breakpoint Mask */ + ret = env->mmubpregs[reg]; + break; + case 2: /* Breakpoint Control */ + ret = env->mmubpregs[reg]; + break; + case 3: /* Breakpoint Status */ + ret = env->mmubpregs[reg]; + env->mmubpregs[reg] = 0ULL; + break; + } + DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg, + ret); + } + break; + case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ + ret = env->mmubpctrv; + break; + case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ + ret = env->mmubpctrc; + break; + case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ + ret = env->mmubpctrs; + break; + case 0x4c: /* SuperSPARC MMU Breakpoint Action */ + ret = env->mmubpaction; + break; + case 8: /* User code access, XXX */ + default: + do_unassigned_access(addr, 0, 0, asi, size); + ret = 0; + break; + } + if (sign) { + switch (size) { + case 1: + ret = (int8_t) ret; + break; + case 2: + ret = (int16_t) ret; + break; + case 4: + ret = (int32_t) ret; + break; + default: + break; + } + } +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return ret; +} + +void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) +{ + helper_check_align(addr, size - 1); + switch (asi) { + case 2: /* SuperSparc MXCC registers and Leon3 cache control */ + switch (addr) { + case 0x00: /* Leon3 Cache Control */ + case 0x08: /* Leon3 Instruction Cache config */ + case 0x0C: /* Leon3 Date Cache config */ + if (env->def->features & CPU_FEATURE_CACHE_CTRL) { + leon3_cache_control_st(addr, val, size); + } + break; + + case 0x01c00000: /* MXCC stream data register 0 */ + if (size == 8) { + env->mxccdata[0] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00008: /* MXCC stream data register 1 */ + if (size == 8) { + env->mxccdata[1] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00010: /* MXCC stream data register 2 */ + if (size == 8) { + env->mxccdata[2] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00018: /* MXCC stream data register 3 */ + if (size == 8) { + env->mxccdata[3] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00100: /* MXCC stream source */ + if (size == 8) { + env->mxccregs[0] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 0); + env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 8); + env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 16); + env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 24); + break; + case 0x01c00200: /* MXCC stream destination */ + if (size == 8) { + env->mxccregs[1] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, + env->mxccdata[0]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, + env->mxccdata[1]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, + env->mxccdata[2]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, + env->mxccdata[3]); + break; + case 0x01c00a00: /* MXCC control register */ + if (size == 8) { + env->mxccregs[3] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00a04: /* MXCC control register */ + if (size == 4) { + env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) + | val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00e00: /* MXCC error register */ + /* writing a 1 bit clears the error */ + if (size == 8) { + env->mxccregs[6] &= ~val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + case 0x01c00f00: /* MBus port address register */ + if (size == 8) { + env->mxccregs[7] = val; + } else { + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + } + break; + default: + DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, + size); + break; + } + DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", + asi, size, addr, val); +#ifdef DEBUG_MXCC + dump_mxcc(env); +#endif + break; + case 3: /* MMU flush */ + { + int mmulev; + + mmulev = (addr >> 8) & 15; + DPRINTF_MMU("mmu flush level %d\n", mmulev); + switch (mmulev) { + case 0: /* flush page */ + tlb_flush_page(env, addr & 0xfffff000); + break; + case 1: /* flush segment (256k) */ + case 2: /* flush region (16M) */ + case 3: /* flush context (4G) */ + case 4: /* flush entire */ + tlb_flush(env, 1); + break; + default: + break; + } +#ifdef DEBUG_MMU + dump_mmu(stdout, fprintf, env); +#endif + } + break; + case 4: /* write MMU regs */ + { + int reg = (addr >> 8) & 0x1f; + uint32_t oldreg; + + oldreg = env->mmuregs[reg]; + switch (reg) { + case 0: /* Control Register */ + env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | + (val & 0x00ffffff); + /* Mappings generated during no-fault mode or MMU + disabled mode are invalid in normal mode */ + if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != + (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) { + tlb_flush(env, 1); + } + break; + case 1: /* Context Table Pointer Register */ + env->mmuregs[reg] = val & env->def->mmu_ctpr_mask; + break; + case 2: /* Context Register */ + env->mmuregs[reg] = val & env->def->mmu_cxr_mask; + if (oldreg != env->mmuregs[reg]) { + /* we flush when the MMU context changes because + QEMU has no MMU context support */ + tlb_flush(env, 1); + } + break; + case 3: /* Synchronous Fault Status Register with Clear */ + case 4: /* Synchronous Fault Address Register */ + break; + case 0x10: /* TLB Replacement Control Register */ + env->mmuregs[reg] = val & env->def->mmu_trcr_mask; + break; + case 0x13: /* Synchronous Fault Status Register with Read + and Clear */ + env->mmuregs[3] = val & env->def->mmu_sfsr_mask; + break; + case 0x14: /* Synchronous Fault Address Register */ + env->mmuregs[4] = val; + break; + default: + env->mmuregs[reg] = val; + break; + } + if (oldreg != env->mmuregs[reg]) { + DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", + reg, oldreg, env->mmuregs[reg]); + } +#ifdef DEBUG_MMU + dump_mmu(stdout, fprintf, env); +#endif + } + break; + case 5: /* Turbosparc ITLB Diagnostic */ + case 6: /* Turbosparc DTLB Diagnostic */ + case 7: /* Turbosparc IOTLB Diagnostic */ + break; + case 0xa: /* User data access */ + switch (size) { + case 1: + stb_user(addr, val); + break; + case 2: + stw_user(addr, val); + break; + default: + case 4: + stl_user(addr, val); + break; + case 8: + stq_user(addr, val); + break; + } + break; + case 0xb: /* Supervisor data access */ + switch (size) { + case 1: + stb_kernel(addr, val); + break; + case 2: + stw_kernel(addr, val); + break; + default: + case 4: + stl_kernel(addr, val); + break; + case 8: + stq_kernel(addr, val); + break; + } + break; + case 0xc: /* I-cache tag */ + case 0xd: /* I-cache data */ + case 0xe: /* D-cache tag */ + case 0xf: /* D-cache data */ + case 0x10: /* I/D-cache flush page */ + case 0x11: /* I/D-cache flush segment */ + case 0x12: /* I/D-cache flush region */ + case 0x13: /* I/D-cache flush context */ + case 0x14: /* I/D-cache flush user */ + break; + case 0x17: /* Block copy, sta access */ + { + /* val = src + addr = dst + copy 32 bytes */ + unsigned int i; + uint32_t src = val & ~3, dst = addr & ~3, temp; + + for (i = 0; i < 32; i += 4, src += 4, dst += 4) { + temp = ldl_kernel(src); + stl_kernel(dst, temp); + } + } + break; + case 0x1f: /* Block fill, stda access */ + { + /* addr = dst + fill 32 bytes with val */ + unsigned int i; + uint32_t dst = addr & 7; + + for (i = 0; i < 32; i += 8, dst += 8) { + stq_kernel(dst, val); + } + } + break; + case 0x20: /* MMU passthrough */ + { + switch (size) { + case 1: + stb_phys(addr, val); + break; + case 2: + stw_phys(addr, val); + break; + case 4: + default: + stl_phys(addr, val); + break; + case 8: + stq_phys(addr, val); + break; + } + } + break; + case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ + { + switch (size) { + case 1: + stb_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); + break; + case 2: + stw_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); + break; + case 4: + default: + stl_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); + break; + case 8: + stq_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); + break; + } + } + break; + case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */ + case 0x31: /* store buffer data, Ross RT620 I-cache flush or + Turbosparc snoop RAM */ + case 0x32: /* store buffer control or Turbosparc page table + descriptor diagnostic */ + case 0x36: /* I-cache flash clear */ + case 0x37: /* D-cache flash clear */ + break; + case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ + { + int reg = (addr >> 8) & 3; + + switch (reg) { + case 0: /* Breakpoint Value (Addr) */ + env->mmubpregs[reg] = (val & 0xfffffffffULL); + break; + case 1: /* Breakpoint Mask */ + env->mmubpregs[reg] = (val & 0xfffffffffULL); + break; + case 2: /* Breakpoint Control */ + env->mmubpregs[reg] = (val & 0x7fULL); + break; + case 3: /* Breakpoint Status */ + env->mmubpregs[reg] = (val & 0xfULL); + break; + } + DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg, + env->mmuregs[reg]); + } + break; + case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ + env->mmubpctrv = val & 0xffffffff; + break; + case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ + env->mmubpctrc = val & 0x3; + break; + case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ + env->mmubpctrs = val & 0x3; + break; + case 0x4c: /* SuperSPARC MMU Breakpoint Action */ + env->mmubpaction = val & 0x1fff; + break; + case 8: /* User code access, XXX */ + case 9: /* Supervisor code access, XXX */ + default: + do_unassigned_access(addr, 1, 0, asi, size); + break; + } +#ifdef DEBUG_ASI + dump_asi("write", addr, asi, size, val); +#endif +} + +#endif /* CONFIG_USER_ONLY */ +#else /* TARGET_SPARC64 */ + +#ifdef CONFIG_USER_ONLY +uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) +{ + uint64_t ret = 0; +#if defined(DEBUG_ASI) + target_ulong last_addr = addr; +#endif + + if (asi < 0x80) { + helper_raise_exception(env, TT_PRIV_ACT); + } + + helper_check_align(addr, size - 1); + addr = asi_address_mask(env, asi, addr); + + switch (asi) { + case 0x82: /* Primary no-fault */ + case 0x8a: /* Primary no-fault LE */ + if (page_check_range(addr, size, PAGE_READ) == -1) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return 0; + } + /* Fall through */ + case 0x80: /* Primary */ + case 0x88: /* Primary LE */ + { + switch (size) { + case 1: + ret = ldub_raw(addr); + break; + case 2: + ret = lduw_raw(addr); + break; + case 4: + ret = ldl_raw(addr); + break; + default: + case 8: + ret = ldq_raw(addr); + break; + } + } + break; + case 0x83: /* Secondary no-fault */ + case 0x8b: /* Secondary no-fault LE */ + if (page_check_range(addr, size, PAGE_READ) == -1) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return 0; + } + /* Fall through */ + case 0x81: /* Secondary */ + case 0x89: /* Secondary LE */ + /* XXX */ + break; + default: + break; + } + + /* Convert from little endian */ + switch (asi) { + case 0x88: /* Primary LE */ + case 0x89: /* Secondary LE */ + case 0x8a: /* Primary no-fault LE */ + case 0x8b: /* Secondary no-fault LE */ + switch (size) { + case 2: + ret = bswap16(ret); + break; + case 4: + ret = bswap32(ret); + break; + case 8: + ret = bswap64(ret); + break; + default: + break; + } + default: + break; + } + + /* Convert to signed number */ + if (sign) { + switch (size) { + case 1: + ret = (int8_t) ret; + break; + case 2: + ret = (int16_t) ret; + break; + case 4: + ret = (int32_t) ret; + break; + default: + break; + } + } +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return ret; +} + +void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) +{ +#ifdef DEBUG_ASI + dump_asi("write", addr, asi, size, val); +#endif + if (asi < 0x80) { + helper_raise_exception(env, TT_PRIV_ACT); + } + + helper_check_align(addr, size - 1); + addr = asi_address_mask(env, asi, addr); + + /* Convert to little endian */ + switch (asi) { + case 0x88: /* Primary LE */ + case 0x89: /* Secondary LE */ + switch (size) { + case 2: + val = bswap16(val); + break; + case 4: + val = bswap32(val); + break; + case 8: + val = bswap64(val); + break; + default: + break; + } + default: + break; + } + + switch (asi) { + case 0x80: /* Primary */ + case 0x88: /* Primary LE */ + { + switch (size) { + case 1: + stb_raw(addr, val); + break; + case 2: + stw_raw(addr, val); + break; + case 4: + stl_raw(addr, val); + break; + case 8: + default: + stq_raw(addr, val); + break; + } + } + break; + case 0x81: /* Secondary */ + case 0x89: /* Secondary LE */ + /* XXX */ + return; + + case 0x82: /* Primary no-fault, RO */ + case 0x83: /* Secondary no-fault, RO */ + case 0x8a: /* Primary no-fault LE, RO */ + case 0x8b: /* Secondary no-fault LE, RO */ + default: + do_unassigned_access(addr, 1, 0, 1, size); + return; + } +} + +#else /* CONFIG_USER_ONLY */ + +uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) +{ + uint64_t ret = 0; +#if defined(DEBUG_ASI) + target_ulong last_addr = addr; +#endif + + asi &= 0xff; + + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (cpu_has_hypervisor(env) + && asi >= 0x30 && asi < 0x80 + && !(env->hpstate & HS_PRIV))) { + helper_raise_exception(env, TT_PRIV_ACT); + } + + helper_check_align(addr, size - 1); + addr = asi_address_mask(env, asi, addr); + + /* process nonfaulting loads first */ + if ((asi & 0xf6) == 0x82) { + int mmu_idx; + + /* secondary space access has lowest asi bit equal to 1 */ + if (env->pstate & PS_PRIV) { + mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX; + } else { + mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX; + } + + if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + /* env->exception_index is set in get_physical_address_data(). */ + helper_raise_exception(env, env->exception_index); + } + + /* convert nonfaulting load ASIs to normal load ASIs */ + asi &= ~0x02; + } + + switch (asi) { + case 0x10: /* As if user primary */ + case 0x11: /* As if user secondary */ + case 0x18: /* As if user primary LE */ + case 0x19: /* As if user secondary LE */ + case 0x80: /* Primary */ + case 0x81: /* Secondary */ + case 0x88: /* Primary LE */ + case 0x89: /* Secondary LE */ + case 0xe2: /* UA2007 Primary block init */ + case 0xe3: /* UA2007 Secondary block init */ + if ((asi & 0x80) && (env->pstate & PS_PRIV)) { + if (cpu_hypervisor_mode(env)) { + switch (size) { + case 1: + ret = ldub_hypv(addr); + break; + case 2: + ret = lduw_hypv(addr); + break; + case 4: + ret = ldl_hypv(addr); + break; + default: + case 8: + ret = ldq_hypv(addr); + break; + } + } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { + switch (size) { + case 1: + ret = ldub_kernel_secondary(addr); + break; + case 2: + ret = lduw_kernel_secondary(addr); + break; + case 4: + ret = ldl_kernel_secondary(addr); + break; + default: + case 8: + ret = ldq_kernel_secondary(addr); + break; + } + } else { + switch (size) { + case 1: + ret = ldub_kernel(addr); + break; + case 2: + ret = lduw_kernel(addr); + break; + case 4: + ret = ldl_kernel(addr); + break; + default: + case 8: + ret = ldq_kernel(addr); + break; + } + } + } + } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { + switch (size) { + case 1: + ret = ldub_user_secondary(addr); + break; + case 2: + ret = lduw_user_secondary(addr); + break; + case 4: + ret = ldl_user_secondary(addr); + break; + default: + case 8: + ret = ldq_user_secondary(addr); + break; + } + } else { + switch (size) { + case 1: + ret = ldub_user(addr); + break; + case 2: + ret = lduw_user(addr); + break; + case 4: + ret = ldl_user(addr); + break; + default: + case 8: + ret = ldq_user(addr); + break; + } + } + } + break; + case 0x14: /* Bypass */ + case 0x15: /* Bypass, non-cacheable */ + case 0x1c: /* Bypass LE */ + case 0x1d: /* Bypass, non-cacheable LE */ + { + switch (size) { + case 1: + ret = ldub_phys(addr); + break; + case 2: + ret = lduw_phys(addr); + break; + case 4: + ret = ldl_phys(addr); + break; + default: + case 8: + ret = ldq_phys(addr); + break; + } + break; + } + case 0x24: /* Nucleus quad LDD 128 bit atomic */ + case 0x2c: /* Nucleus quad LDD 128 bit atomic LE + Only ldda allowed */ + helper_raise_exception(env, TT_ILL_INSN); + return 0; + case 0x04: /* Nucleus */ + case 0x0c: /* Nucleus Little Endian (LE) */ + { + switch (size) { + case 1: + ret = ldub_nucleus(addr); + break; + case 2: + ret = lduw_nucleus(addr); + break; + case 4: + ret = ldl_nucleus(addr); + break; + default: + case 8: + ret = ldq_nucleus(addr); + break; + } + break; + } + case 0x4a: /* UPA config */ + /* XXX */ + break; + case 0x45: /* LSU */ + ret = env->lsu; + break; + case 0x50: /* I-MMU regs */ + { + int reg = (addr >> 3) & 0xf; + + if (reg == 0) { + /* I-TSB Tag Target register */ + ret = ultrasparc_tag_target(env->immu.tag_access); + } else { + ret = env->immuregs[reg]; + } + + break; + } + case 0x51: /* I-MMU 8k TSB pointer */ + { + /* env->immuregs[5] holds I-MMU TSB register value + env->immuregs[6] holds I-MMU Tag Access register value */ + ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, + 8*1024); + break; + } + case 0x52: /* I-MMU 64k TSB pointer */ + { + /* env->immuregs[5] holds I-MMU TSB register value + env->immuregs[6] holds I-MMU Tag Access register value */ + ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, + 64*1024); + break; + } + case 0x55: /* I-MMU data access */ + { + int reg = (addr >> 3) & 0x3f; + + ret = env->itlb[reg].tte; + break; + } + case 0x56: /* I-MMU tag read */ + { + int reg = (addr >> 3) & 0x3f; + + ret = env->itlb[reg].tag; + break; + } + case 0x58: /* D-MMU regs */ + { + int reg = (addr >> 3) & 0xf; + + if (reg == 0) { + /* D-TSB Tag Target register */ + ret = ultrasparc_tag_target(env->dmmu.tag_access); + } else { + ret = env->dmmuregs[reg]; + } + break; + } + case 0x59: /* D-MMU 8k TSB pointer */ + { + /* env->dmmuregs[5] holds D-MMU TSB register value + env->dmmuregs[6] holds D-MMU Tag Access register value */ + ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, + 8*1024); + break; + } + case 0x5a: /* D-MMU 64k TSB pointer */ + { + /* env->dmmuregs[5] holds D-MMU TSB register value + env->dmmuregs[6] holds D-MMU Tag Access register value */ + ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, + 64*1024); + break; + } + case 0x5d: /* D-MMU data access */ + { + int reg = (addr >> 3) & 0x3f; + + ret = env->dtlb[reg].tte; + break; + } + case 0x5e: /* D-MMU tag read */ + { + int reg = (addr >> 3) & 0x3f; + + ret = env->dtlb[reg].tag; + break; + } + case 0x46: /* D-cache data */ + case 0x47: /* D-cache tag access */ + case 0x4b: /* E-cache error enable */ + case 0x4c: /* E-cache asynchronous fault status */ + case 0x4d: /* E-cache asynchronous fault address */ + case 0x4e: /* E-cache tag data */ + case 0x66: /* I-cache instruction access */ + case 0x67: /* I-cache tag access */ + case 0x6e: /* I-cache predecode */ + case 0x6f: /* I-cache LRU etc. */ + case 0x76: /* E-cache tag */ + case 0x7e: /* E-cache tag */ + break; + case 0x5b: /* D-MMU data pointer */ + case 0x48: /* Interrupt dispatch, RO */ + case 0x49: /* Interrupt data receive */ + case 0x7f: /* Incoming interrupt vector, RO */ + /* XXX */ + break; + case 0x54: /* I-MMU data in, WO */ + case 0x57: /* I-MMU demap, WO */ + case 0x5c: /* D-MMU data in, WO */ + case 0x5f: /* D-MMU demap, WO */ + case 0x77: /* Interrupt vector, WO */ + default: + do_unassigned_access(addr, 0, 0, 1, size); + ret = 0; + break; + } + + /* Convert from little endian */ + switch (asi) { + case 0x0c: /* Nucleus Little Endian (LE) */ + case 0x18: /* As if user primary LE */ + case 0x19: /* As if user secondary LE */ + case 0x1c: /* Bypass LE */ + case 0x1d: /* Bypass, non-cacheable LE */ + case 0x88: /* Primary LE */ + case 0x89: /* Secondary LE */ + switch(size) { + case 2: + ret = bswap16(ret); + break; + case 4: + ret = bswap32(ret); + break; + case 8: + ret = bswap64(ret); + break; + default: + break; + } + default: + break; + } + + /* Convert to signed number */ + if (sign) { + switch (size) { + case 1: + ret = (int8_t) ret; + break; + case 2: + ret = (int16_t) ret; + break; + case 4: + ret = (int32_t) ret; + break; + default: + break; + } + } +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return ret; +} + +void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) +{ +#ifdef DEBUG_ASI + dump_asi("write", addr, asi, size, val); +#endif + + asi &= 0xff; + + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (cpu_has_hypervisor(env) + && asi >= 0x30 && asi < 0x80 + && !(env->hpstate & HS_PRIV))) { + helper_raise_exception(env, TT_PRIV_ACT); + } + + helper_check_align(addr, size - 1); + addr = asi_address_mask(env, asi, addr); + + /* Convert to little endian */ + switch (asi) { + case 0x0c: /* Nucleus Little Endian (LE) */ + case 0x18: /* As if user primary LE */ + case 0x19: /* As if user secondary LE */ + case 0x1c: /* Bypass LE */ + case 0x1d: /* Bypass, non-cacheable LE */ + case 0x88: /* Primary LE */ + case 0x89: /* Secondary LE */ + switch (size) { + case 2: + val = bswap16(val); + break; + case 4: + val = bswap32(val); + break; + case 8: + val = bswap64(val); + break; + default: + break; + } + default: + break; + } + + switch (asi) { + case 0x10: /* As if user primary */ + case 0x11: /* As if user secondary */ + case 0x18: /* As if user primary LE */ + case 0x19: /* As if user secondary LE */ + case 0x80: /* Primary */ + case 0x81: /* Secondary */ + case 0x88: /* Primary LE */ + case 0x89: /* Secondary LE */ + case 0xe2: /* UA2007 Primary block init */ + case 0xe3: /* UA2007 Secondary block init */ + if ((asi & 0x80) && (env->pstate & PS_PRIV)) { + if (cpu_hypervisor_mode(env)) { + switch (size) { + case 1: + stb_hypv(addr, val); + break; + case 2: + stw_hypv(addr, val); + break; + case 4: + stl_hypv(addr, val); + break; + case 8: + default: + stq_hypv(addr, val); + break; + } + } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { + switch (size) { + case 1: + stb_kernel_secondary(addr, val); + break; + case 2: + stw_kernel_secondary(addr, val); + break; + case 4: + stl_kernel_secondary(addr, val); + break; + case 8: + default: + stq_kernel_secondary(addr, val); + break; + } + } else { + switch (size) { + case 1: + stb_kernel(addr, val); + break; + case 2: + stw_kernel(addr, val); + break; + case 4: + stl_kernel(addr, val); + break; + case 8: + default: + stq_kernel(addr, val); + break; + } + } + } + } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { + switch (size) { + case 1: + stb_user_secondary(addr, val); + break; + case 2: + stw_user_secondary(addr, val); + break; + case 4: + stl_user_secondary(addr, val); + break; + case 8: + default: + stq_user_secondary(addr, val); + break; + } + } else { + switch (size) { + case 1: + stb_user(addr, val); + break; + case 2: + stw_user(addr, val); + break; + case 4: + stl_user(addr, val); + break; + case 8: + default: + stq_user(addr, val); + break; + } + } + } + break; + case 0x14: /* Bypass */ + case 0x15: /* Bypass, non-cacheable */ + case 0x1c: /* Bypass LE */ + case 0x1d: /* Bypass, non-cacheable LE */ + { + switch (size) { + case 1: + stb_phys(addr, val); + break; + case 2: + stw_phys(addr, val); + break; + case 4: + stl_phys(addr, val); + break; + case 8: + default: + stq_phys(addr, val); + break; + } + } + return; + case 0x24: /* Nucleus quad LDD 128 bit atomic */ + case 0x2c: /* Nucleus quad LDD 128 bit atomic LE + Only ldda allowed */ + helper_raise_exception(env, TT_ILL_INSN); + return; + case 0x04: /* Nucleus */ + case 0x0c: /* Nucleus Little Endian (LE) */ + { + switch (size) { + case 1: + stb_nucleus(addr, val); + break; + case 2: + stw_nucleus(addr, val); + break; + case 4: + stl_nucleus(addr, val); + break; + default: + case 8: + stq_nucleus(addr, val); + break; + } + break; + } + + case 0x4a: /* UPA config */ + /* XXX */ + return; + case 0x45: /* LSU */ + { + uint64_t oldreg; + + oldreg = env->lsu; + env->lsu = val & (DMMU_E | IMMU_E); + /* Mappings generated during D/I MMU disabled mode are + invalid in normal mode */ + if (oldreg != env->lsu) { + DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", + oldreg, env->lsu); +#ifdef DEBUG_MMU + dump_mmu(stdout, fprintf, env1); +#endif + tlb_flush(env, 1); + } + return; + } + case 0x50: /* I-MMU regs */ + { + int reg = (addr >> 3) & 0xf; + uint64_t oldreg; + + oldreg = env->immuregs[reg]; + switch (reg) { + case 0: /* RO */ + return; + case 1: /* Not in I-MMU */ + case 2: + return; + case 3: /* SFSR */ + if ((val & 1) == 0) { + val = 0; /* Clear SFSR */ + } + env->immu.sfsr = val; + break; + case 4: /* RO */ + return; + case 5: /* TSB access */ + DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016" + PRIx64 "\n", env->immu.tsb, val); + env->immu.tsb = val; + break; + case 6: /* Tag access */ + env->immu.tag_access = val; + break; + case 7: + case 8: + return; + default: + break; + } + + if (oldreg != env->immuregs[reg]) { + DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" + PRIx64 "\n", reg, oldreg, env->immuregs[reg]); + } +#ifdef DEBUG_MMU + dump_mmu(stdout, fprintf, env); +#endif + return; + } + case 0x54: /* I-MMU data in */ + replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); + return; + case 0x55: /* I-MMU data access */ + { + /* TODO: auto demap */ + + unsigned int i = (addr >> 3) & 0x3f; + + replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); + +#ifdef DEBUG_MMU + DPRINTF_MMU("immu data access replaced entry [%i]\n", i); + dump_mmu(stdout, fprintf, env); +#endif + return; + } + case 0x57: /* I-MMU demap */ + demap_tlb(env->itlb, addr, "immu", env); + return; + case 0x58: /* D-MMU regs */ + { + int reg = (addr >> 3) & 0xf; + uint64_t oldreg; + + oldreg = env->dmmuregs[reg]; + switch (reg) { + case 0: /* RO */ + case 4: + return; + case 3: /* SFSR */ + if ((val & 1) == 0) { + val = 0; /* Clear SFSR, Fault address */ + env->dmmu.sfar = 0; + } + env->dmmu.sfsr = val; + break; + case 1: /* Primary context */ + env->dmmu.mmu_primary_context = val; + /* can be optimized to only flush MMU_USER_IDX + and MMU_KERNEL_IDX entries */ + tlb_flush(env, 1); + break; + case 2: /* Secondary context */ + env->dmmu.mmu_secondary_context = val; + /* can be optimized to only flush MMU_USER_SECONDARY_IDX + and MMU_KERNEL_SECONDARY_IDX entries */ + tlb_flush(env, 1); + break; + case 5: /* TSB access */ + DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016" + PRIx64 "\n", env->dmmu.tsb, val); + env->dmmu.tsb = val; + break; + case 6: /* Tag access */ + env->dmmu.tag_access = val; + break; + case 7: /* Virtual Watchpoint */ + case 8: /* Physical Watchpoint */ + default: + env->dmmuregs[reg] = val; + break; + } + + if (oldreg != env->dmmuregs[reg]) { + DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" + PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); + } +#ifdef DEBUG_MMU + dump_mmu(stdout, fprintf, env); +#endif + return; + } + case 0x5c: /* D-MMU data in */ + replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); + return; + case 0x5d: /* D-MMU data access */ + { + unsigned int i = (addr >> 3) & 0x3f; + + replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); + +#ifdef DEBUG_MMU + DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); + dump_mmu(stdout, fprintf, env); +#endif + return; + } + case 0x5f: /* D-MMU demap */ + demap_tlb(env->dtlb, addr, "dmmu", env); + return; + case 0x49: /* Interrupt data receive */ + /* XXX */ + return; + case 0x46: /* D-cache data */ + case 0x47: /* D-cache tag access */ + case 0x4b: /* E-cache error enable */ + case 0x4c: /* E-cache asynchronous fault status */ + case 0x4d: /* E-cache asynchronous fault address */ + case 0x4e: /* E-cache tag data */ + case 0x66: /* I-cache instruction access */ + case 0x67: /* I-cache tag access */ + case 0x6e: /* I-cache predecode */ + case 0x6f: /* I-cache LRU etc. */ + case 0x76: /* E-cache tag */ + case 0x7e: /* E-cache tag */ + return; + case 0x51: /* I-MMU 8k TSB pointer, RO */ + case 0x52: /* I-MMU 64k TSB pointer, RO */ + case 0x56: /* I-MMU tag read, RO */ + case 0x59: /* D-MMU 8k TSB pointer, RO */ + case 0x5a: /* D-MMU 64k TSB pointer, RO */ + case 0x5b: /* D-MMU data pointer, RO */ + case 0x5e: /* D-MMU tag read, RO */ + case 0x48: /* Interrupt dispatch, RO */ + case 0x7f: /* Incoming interrupt vector, RO */ + case 0x82: /* Primary no-fault, RO */ + case 0x83: /* Secondary no-fault, RO */ + case 0x8a: /* Primary no-fault LE, RO */ + case 0x8b: /* Secondary no-fault LE, RO */ + default: + do_unassigned_access(addr, 1, 0, 1, size); + return; + } +} +#endif /* CONFIG_USER_ONLY */ + +void helper_ldda_asi(target_ulong addr, int asi, int rd) +{ + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (cpu_has_hypervisor(env) + && asi >= 0x30 && asi < 0x80 + && !(env->hpstate & HS_PRIV))) { + helper_raise_exception(env, TT_PRIV_ACT); + } + + addr = asi_address_mask(env, asi, addr); + + switch (asi) { +#if !defined(CONFIG_USER_ONLY) + case 0x24: /* Nucleus quad LDD 128 bit atomic */ + case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */ + helper_check_align(addr, 0xf); + if (rd == 0) { + env->gregs[1] = ldq_nucleus(addr + 8); + if (asi == 0x2c) { + bswap64s(&env->gregs[1]); + } + } else if (rd < 8) { + env->gregs[rd] = ldq_nucleus(addr); + env->gregs[rd + 1] = ldq_nucleus(addr + 8); + if (asi == 0x2c) { + bswap64s(&env->gregs[rd]); + bswap64s(&env->gregs[rd + 1]); + } + } else { + env->regwptr[rd] = ldq_nucleus(addr); + env->regwptr[rd + 1] = ldq_nucleus(addr + 8); + if (asi == 0x2c) { + bswap64s(&env->regwptr[rd]); + bswap64s(&env->regwptr[rd + 1]); + } + } + break; +#endif + default: + helper_check_align(addr, 0x3); + if (rd == 0) { + env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0); + } else if (rd < 8) { + env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0); + env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); + } else { + env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0); + env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); + } + break; + } +} + +void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) +{ + unsigned int i; + CPU_DoubleU u; + + helper_check_align(addr, 3); + addr = asi_address_mask(env, asi, addr); + + switch (asi) { + case 0xf0: /* UA2007/JPS1 Block load primary */ + case 0xf1: /* UA2007/JPS1 Block load secondary */ + case 0xf8: /* UA2007/JPS1 Block load primary LE */ + case 0xf9: /* UA2007/JPS1 Block load secondary LE */ + if (rd & 7) { + helper_raise_exception(env, TT_ILL_INSN); + return; + } + helper_check_align(addr, 0x3f); + for (i = 0; i < 16; i++) { + *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, + 0); + addr += 4; + } + + return; + case 0x16: /* UA2007 Block load primary, user privilege */ + case 0x17: /* UA2007 Block load secondary, user privilege */ + case 0x1e: /* UA2007 Block load primary LE, user privilege */ + case 0x1f: /* UA2007 Block load secondary LE, user privilege */ + case 0x70: /* JPS1 Block load primary, user privilege */ + case 0x71: /* JPS1 Block load secondary, user privilege */ + case 0x78: /* JPS1 Block load primary LE, user privilege */ + case 0x79: /* JPS1 Block load secondary LE, user privilege */ + if (rd & 7) { + helper_raise_exception(env, TT_ILL_INSN); + return; + } + helper_check_align(addr, 0x3f); + for (i = 0; i < 16; i++) { + *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4, + 0); + addr += 4; + } + + return; + default: + break; + } + + switch (size) { + default: + case 4: + *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0); + break; + case 8: + u.ll = helper_ld_asi(addr, asi, size, 0); + *((uint32_t *)&env->fpr[rd++]) = u.l.upper; + *((uint32_t *)&env->fpr[rd++]) = u.l.lower; + break; + case 16: + u.ll = helper_ld_asi(addr, asi, 8, 0); + *((uint32_t *)&env->fpr[rd++]) = u.l.upper; + *((uint32_t *)&env->fpr[rd++]) = u.l.lower; + u.ll = helper_ld_asi(addr + 8, asi, 8, 0); + *((uint32_t *)&env->fpr[rd++]) = u.l.upper; + *((uint32_t *)&env->fpr[rd++]) = u.l.lower; + break; + } +} + +void helper_stf_asi(target_ulong addr, int asi, int size, int rd) +{ + unsigned int i; + target_ulong val = 0; + CPU_DoubleU u; + + helper_check_align(addr, 3); + addr = asi_address_mask(env, asi, addr); + + switch (asi) { + case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */ + case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */ + case 0xf0: /* UA2007/JPS1 Block store primary */ + case 0xf1: /* UA2007/JPS1 Block store secondary */ + case 0xf8: /* UA2007/JPS1 Block store primary LE */ + case 0xf9: /* UA2007/JPS1 Block store secondary LE */ + if (rd & 7) { + helper_raise_exception(env, TT_ILL_INSN); + return; + } + helper_check_align(addr, 0x3f); + for (i = 0; i < 16; i++) { + val = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, val, asi & 0x8f, 4); + addr += 4; + } + + return; + case 0x16: /* UA2007 Block load primary, user privilege */ + case 0x17: /* UA2007 Block load secondary, user privilege */ + case 0x1e: /* UA2007 Block load primary LE, user privilege */ + case 0x1f: /* UA2007 Block load secondary LE, user privilege */ + case 0x70: /* JPS1 Block store primary, user privilege */ + case 0x71: /* JPS1 Block store secondary, user privilege */ + case 0x78: /* JPS1 Block load primary LE, user privilege */ + case 0x79: /* JPS1 Block load secondary LE, user privilege */ + if (rd & 7) { + helper_raise_exception(env, TT_ILL_INSN); + return; + } + helper_check_align(addr, 0x3f); + for (i = 0; i < 16; i++) { + val = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, val, asi & 0x19, 4); + addr += 4; + } + + return; + default: + break; + } + + switch (size) { + default: + case 4: + helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size); + break; + case 8: + u.l.upper = *(uint32_t *)&env->fpr[rd++]; + u.l.lower = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, u.ll, asi, size); + break; + case 16: + u.l.upper = *(uint32_t *)&env->fpr[rd++]; + u.l.lower = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, u.ll, asi, 8); + u.l.upper = *(uint32_t *)&env->fpr[rd++]; + u.l.lower = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr + 8, u.ll, asi, 8); + break; + } +} + +target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, + target_ulong val2, uint32_t asi) +{ + target_ulong ret; + + val2 &= 0xffffffffUL; + ret = helper_ld_asi(addr, asi, 4, 0); + ret &= 0xffffffffUL; + if (val2 == ret) { + helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); + } + return ret; +} + +target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, + target_ulong val2, uint32_t asi) +{ + target_ulong ret; + + ret = helper_ld_asi(addr, asi, 8, 0); + if (val2 == ret) { + helper_st_asi(addr, val1, asi, 8); + } + return ret; +} +#endif /* TARGET_SPARC64 */ + +void helper_stdf(target_ulong addr, int mem_idx) +{ + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case MMU_USER_IDX: + stfq_user(addr, DT0); + break; + case MMU_KERNEL_IDX: + stfq_kernel(addr, DT0); + break; +#ifdef TARGET_SPARC64 + case MMU_HYPV_IDX: + stfq_hypv(addr, DT0); + break; +#endif + default: + DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx); + break; + } +#else + stfq_raw(address_mask(env, addr), DT0); +#endif +} + +void helper_lddf(target_ulong addr, int mem_idx) +{ + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case MMU_USER_IDX: + DT0 = ldfq_user(addr); + break; + case MMU_KERNEL_IDX: + DT0 = ldfq_kernel(addr); + break; +#ifdef TARGET_SPARC64 + case MMU_HYPV_IDX: + DT0 = ldfq_hypv(addr); + break; +#endif + default: + DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx); + break; + } +#else + DT0 = ldfq_raw(address_mask(env, addr)); +#endif +} + +void helper_ldqf(target_ulong addr, int mem_idx) +{ + /* XXX add 128 bit load */ + CPU_QuadU u; + + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case MMU_USER_IDX: + u.ll.upper = ldq_user(addr); + u.ll.lower = ldq_user(addr + 8); + QT0 = u.q; + break; + case MMU_KERNEL_IDX: + u.ll.upper = ldq_kernel(addr); + u.ll.lower = ldq_kernel(addr + 8); + QT0 = u.q; + break; +#ifdef TARGET_SPARC64 + case MMU_HYPV_IDX: + u.ll.upper = ldq_hypv(addr); + u.ll.lower = ldq_hypv(addr + 8); + QT0 = u.q; + break; +#endif + default: + DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx); + break; + } +#else + u.ll.upper = ldq_raw(address_mask(env, addr)); + u.ll.lower = ldq_raw(address_mask(env, addr + 8)); + QT0 = u.q; +#endif +} + +void helper_stqf(target_ulong addr, int mem_idx) +{ + /* XXX add 128 bit store */ + CPU_QuadU u; + + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case MMU_USER_IDX: + u.q = QT0; + stq_user(addr, u.ll.upper); + stq_user(addr + 8, u.ll.lower); + break; + case MMU_KERNEL_IDX: + u.q = QT0; + stq_kernel(addr, u.ll.upper); + stq_kernel(addr + 8, u.ll.lower); + break; +#ifdef TARGET_SPARC64 + case MMU_HYPV_IDX: + u.q = QT0; + stq_hypv(addr, u.ll.upper); + stq_hypv(addr + 8, u.ll.lower); + break; +#endif + default: + DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx); + break; + } +#else + u.q = QT0; + stq_raw(address_mask(env, addr), u.ll.upper); + stq_raw(address_mask(env, addr + 8), u.ll.lower); +#endif +} + +#ifndef TARGET_SPARC64 +#if !defined(CONFIG_USER_ONLY) +static void do_unassigned_access(target_phys_addr_t addr, int is_write, + int is_exec, int is_asi, int size) +{ + int fault_type; + +#ifdef DEBUG_UNASSIGNED + if (is_asi) { + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " asi 0x%02x from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, is_asi, env->pc); + } else { + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, env->pc); + } +#endif + /* Don't overwrite translation and access faults */ + fault_type = (env->mmuregs[3] & 0x1c) >> 2; + if ((fault_type > 4) || (fault_type == 0)) { + env->mmuregs[3] = 0; /* Fault status register */ + if (is_asi) { + env->mmuregs[3] |= 1 << 16; + } + if (env->psrs) { + env->mmuregs[3] |= 1 << 5; + } + if (is_exec) { + env->mmuregs[3] |= 1 << 6; + } + if (is_write) { + env->mmuregs[3] |= 1 << 7; + } + env->mmuregs[3] |= (5 << 2) | 2; + /* SuperSPARC will never place instruction fault addresses in the FAR */ + if (!is_exec) { + env->mmuregs[4] = addr; /* Fault address register */ + } + } + /* overflow (same type fault was not read before another fault) */ + if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) { + env->mmuregs[3] |= 1; + } + + if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { + if (is_exec) { + helper_raise_exception(env, TT_CODE_ACCESS); + } else { + helper_raise_exception(env, TT_DATA_ACCESS); + } + } + + /* flush neverland mappings created during no-fault mode, + so the sequential MMU faults report proper fault types */ + if (env->mmuregs[0] & MMU_NF) { + tlb_flush(env, 1); + } +} +#endif +#else +#if defined(CONFIG_USER_ONLY) +static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi, int size) +#else +static void do_unassigned_access(target_phys_addr_t addr, int is_write, + int is_exec, int is_asi, int size) +#endif +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx + "\n", addr, env->pc); +#endif + + if (is_exec) { + helper_raise_exception(env, TT_CODE_ACCESS); + } else { + helper_raise_exception(env, TT_DATA_ACCESS); + } +} +#endif + +#if !defined(CONFIG_USER_ONLY) +void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr, + int is_write, int is_exec, int is_asi, int size) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + do_unassigned_access(addr, is_write, is_exec, is_asi, size); + env = saved_env; +} +#endif diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c new file mode 100644 index 0000000000..8cdc224ae3 --- /dev/null +++ b/target-sparc/mmu_helper.c @@ -0,0 +1,853 @@ +/* + * Sparc MMU helpers + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "trace.h" + +/* Sparc MMU emulation */ + +#if defined(CONFIG_USER_ONLY) + +int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw, + int mmu_idx) +{ + if (rw & 2) { + env1->exception_index = TT_TFAULT; + } else { + env1->exception_index = TT_DFAULT; + } + return 1; +} + +#else + +#ifndef TARGET_SPARC64 +/* + * Sparc V8 Reference MMU (SRMMU) + */ +static const int access_table[8][8] = { + { 0, 0, 0, 0, 8, 0, 12, 12 }, + { 0, 0, 0, 0, 8, 0, 0, 0 }, + { 8, 8, 0, 0, 0, 8, 12, 12 }, + { 8, 8, 0, 0, 0, 8, 0, 0 }, + { 8, 0, 8, 0, 8, 8, 12, 12 }, + { 8, 0, 8, 0, 8, 0, 8, 0 }, + { 8, 8, 8, 0, 8, 8, 12, 12 }, + { 8, 8, 8, 0, 8, 8, 8, 0 } +}; + +static const int perm_table[2][8] = { + { + PAGE_READ, + PAGE_READ | PAGE_WRITE, + PAGE_READ | PAGE_EXEC, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, + PAGE_EXEC, + PAGE_READ | PAGE_WRITE, + PAGE_READ | PAGE_EXEC, + PAGE_READ | PAGE_WRITE | PAGE_EXEC + }, + { + PAGE_READ, + PAGE_READ | PAGE_WRITE, + PAGE_READ | PAGE_EXEC, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, + PAGE_EXEC, + PAGE_READ, + 0, + 0, + } +}; + +static int get_physical_address(CPUState *env, target_phys_addr_t *physical, + int *prot, int *access_index, + target_ulong address, int rw, int mmu_idx, + target_ulong *page_size) +{ + int access_perms = 0; + target_phys_addr_t pde_ptr; + uint32_t pde; + int error_code = 0, is_dirty, is_user; + unsigned long page_offset; + + is_user = mmu_idx == MMU_USER_IDX; + + if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ + *page_size = TARGET_PAGE_SIZE; + /* Boot mode: instruction fetches are taken from PROM */ + if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { + *physical = env->prom_addr | (address & 0x7ffffULL); + *prot = PAGE_READ | PAGE_EXEC; + return 0; + } + *physical = address; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return 0; + } + + *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1); + *physical = 0xffffffffffff0000ULL; + + /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ + /* Context base + context number */ + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); + pde = ldl_phys(pde_ptr); + + /* Ctx pde */ + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return 1 << 2; + case 2: /* L0 PTE, maybe should not happen? */ + case 3: /* Reserved */ + return 4 << 2; + case 1: /* L0 PDE */ + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return (1 << 8) | (1 << 2); + case 3: /* Reserved */ + return (1 << 8) | (4 << 2); + case 1: /* L1 PDE */ + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return (2 << 8) | (1 << 2); + case 3: /* Reserved */ + return (2 << 8) | (4 << 2); + case 1: /* L2 PDE */ + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return (3 << 8) | (1 << 2); + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return (3 << 8) | (4 << 2); + case 2: /* L3 PTE */ + page_offset = (address & TARGET_PAGE_MASK) & + (TARGET_PAGE_SIZE - 1); + } + *page_size = TARGET_PAGE_SIZE; + break; + case 2: /* L2 PTE */ + page_offset = address & 0x3ffff; + *page_size = 0x40000; + } + break; + case 2: /* L1 PTE */ + page_offset = address & 0xffffff; + *page_size = 0x1000000; + } + } + + /* check access */ + access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; + error_code = access_table[*access_index][access_perms]; + if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) { + return error_code; + } + + /* update page modified and dirty bits */ + is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) { + pde |= PG_MODIFIED_MASK; + } + stl_phys_notdirty(pde_ptr, pde); + } + + /* the page can be put in the TLB */ + *prot = perm_table[is_user][access_perms]; + if (!(pde & PG_MODIFIED_MASK)) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + *prot &= ~PAGE_WRITE; + } + + /* Even if large ptes, we map only one 4KB page in the cache to + avoid filling it too fast */ + *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset; + return error_code; +} + +/* Perform address translation */ +int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx) +{ + target_phys_addr_t paddr; + target_ulong vaddr; + target_ulong page_size; + int error_code = 0, prot, access_index; + + error_code = get_physical_address(env, &paddr, &prot, &access_index, + address, rw, mmu_idx, &page_size); + if (error_code == 0) { + vaddr = address & TARGET_PAGE_MASK; + paddr &= TARGET_PAGE_MASK; +#ifdef DEBUG_MMU + printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " + TARGET_FMT_lx "\n", address, paddr, vaddr); +#endif + tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); + return 0; + } + + if (env->mmuregs[3]) { /* Fault status register */ + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ + } + env->mmuregs[3] |= (access_index << 5) | error_code | 2; + env->mmuregs[4] = address; /* Fault address register */ + + if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { + /* No fault mode: if a mapping is available, just override + permissions. If no mapping is available, redirect accesses to + neverland. Fake/overridden mappings will be flushed when + switching to normal mode. */ + vaddr = address & TARGET_PAGE_MASK; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); + return 0; + } else { + if (rw & 2) { + env->exception_index = TT_TFAULT; + } else { + env->exception_index = TT_DFAULT; + } + return 1; + } +} + +target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) +{ + target_phys_addr_t pde_ptr; + uint32_t pde; + + /* Context base + context number */ + pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) + + (env->mmuregs[2] << 2); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 2: /* PTE, maybe should not happen? */ + case 3: /* Reserved */ + return 0; + case 1: /* L1 PDE */ + if (mmulev == 3) { + return pde; + } + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L1 PTE */ + return pde; + case 1: /* L2 PDE */ + if (mmulev == 2) { + return pde; + } + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L2 PTE */ + return pde; + case 1: /* L3 PDE */ + if (mmulev == 1) { + return pde; + } + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return 0; + case 2: /* L3 PTE */ + return pde; + } + } + } + } + return 0; +} + +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) +{ + target_ulong va, va1, va2; + unsigned int n, m, o; + target_phys_addr_t pde_ptr, pa; + uint32_t pde; + + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); + pde = ldl_phys(pde_ptr); + (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", + (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); + for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { + pde = mmu_probe(env, va, 2); + if (pde) { + pa = cpu_get_phys_page_debug(env, va); + (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + " PDE: " TARGET_FMT_lx "\n", va, pa, pde); + for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { + pde = mmu_probe(env, va1, 1); + if (pde) { + pa = cpu_get_phys_page_debug(env, va1); + (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", + va1, pa, pde); + for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { + pde = mmu_probe(env, va2, 0); + if (pde) { + pa = cpu_get_phys_page_debug(env, va2); + (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PTE: " + TARGET_FMT_lx "\n", + va2, pa, pde); + } + } + } + } + } + } +} + +/* Gdb expects all registers windows to be flushed in ram. This function handles + * reads (and only reads) in stack frames as if windows were flushed. We assume + * that the sparc ABI is followed. + */ +int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + int i; + int len1; + int cwp = env->cwp; + + if (!is_write) { + for (i = 0; i < env->nwindows; i++) { + int off; + target_ulong fp = env->regbase[cwp * 16 + 22]; + + /* Assume fp == 0 means end of frame. */ + if (fp == 0) { + break; + } + + cwp = cpu_cwp_inc(env, cwp + 1); + + /* Invalid window ? */ + if (env->wim & (1 << cwp)) { + break; + } + + /* According to the ABI, the stack is growing downward. */ + if (addr + len < fp) { + break; + } + + /* Not in this frame. */ + if (addr > fp + 64) { + continue; + } + + /* Handle access before this window. */ + if (addr < fp) { + len1 = fp - addr; + if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { + return -1; + } + addr += len1; + len -= len1; + buf += len1; + } + + /* Access byte per byte to registers. Not very efficient but speed + * is not critical. + */ + off = addr - fp; + len1 = 64 - off; + + if (len1 > len) { + len1 = len; + } + + for (; len1; len1--) { + int reg = cwp * 16 + 8 + (off >> 2); + union { + uint32_t v; + uint8_t c[4]; + } u; + u.v = cpu_to_be32(env->regbase[reg]); + *buf++ = u.c[off & 3]; + addr++; + len--; + off++; + } + + if (len == 0) { + return 0; + } + } + } + return cpu_memory_rw_debug(env, addr, buf, len, is_write); +} + +#else /* !TARGET_SPARC64 */ + +/* 41 bit physical address space */ +static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x) +{ + return x & 0x1ffffffffffULL; +} + +/* + * UltraSparc IIi I/DMMUs + */ + +/* Returns true if TTE tag is valid and matches virtual address value + in context requires virtual address mask value calculated from TTE + entry size */ +static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, + uint64_t address, uint64_t context, + target_phys_addr_t *physical) +{ + uint64_t mask; + + switch (TTE_PGSIZE(tlb->tte)) { + default: + case 0x0: /* 8k */ + mask = 0xffffffffffffe000ULL; + break; + case 0x1: /* 64k */ + mask = 0xffffffffffff0000ULL; + break; + case 0x2: /* 512k */ + mask = 0xfffffffffff80000ULL; + break; + case 0x3: /* 4M */ + mask = 0xffffffffffc00000ULL; + break; + } + + /* valid, context match, virtual address match? */ + if (TTE_IS_VALID(tlb->tte) && + (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) + && compare_masked(address, tlb->tag, mask)) { + /* decode physical address */ + *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; + return 1; + } + + return 0; +} + +static int get_physical_address_data(CPUState *env, + target_phys_addr_t *physical, int *prot, + target_ulong address, int rw, int mmu_idx) +{ + unsigned int i; + uint64_t context; + uint64_t sfsr = 0; + + int is_user = (mmu_idx == MMU_USER_IDX || + mmu_idx == MMU_USER_SECONDARY_IDX); + + if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ + *physical = ultrasparc_truncate_physical(address); + *prot = PAGE_READ | PAGE_WRITE; + return 0; + } + + switch (mmu_idx) { + case MMU_USER_IDX: + case MMU_KERNEL_IDX: + context = env->dmmu.mmu_primary_context & 0x1fff; + sfsr |= SFSR_CT_PRIMARY; + break; + case MMU_USER_SECONDARY_IDX: + case MMU_KERNEL_SECONDARY_IDX: + context = env->dmmu.mmu_secondary_context & 0x1fff; + sfsr |= SFSR_CT_SECONDARY; + break; + case MMU_NUCLEUS_IDX: + sfsr |= SFSR_CT_NUCLEUS; + /* FALLTHRU */ + default: + context = 0; + break; + } + + if (rw == 1) { + sfsr |= SFSR_WRITE_BIT; + } else if (rw == 4) { + sfsr |= SFSR_NF_BIT; + } + + for (i = 0; i < 64; i++) { + /* ctx match, vaddr match, valid? */ + if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { + int do_fault = 0; + + /* access ok? */ + /* multiple bits in SFSR.FT may be set on TT_DFAULT */ + if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { + do_fault = 1; + sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ + trace_mmu_helper_dfault(address, context, mmu_idx, env->tl); + } + if (rw == 4) { + if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { + do_fault = 1; + sfsr |= SFSR_FT_NF_E_BIT; + } + } else { + if (TTE_IS_NFO(env->dtlb[i].tte)) { + do_fault = 1; + sfsr |= SFSR_FT_NFO_BIT; + } + } + + if (do_fault) { + /* faults above are reported with TT_DFAULT. */ + env->exception_index = TT_DFAULT; + } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { + do_fault = 1; + env->exception_index = TT_DPROT; + + trace_mmu_helper_dprot(address, context, mmu_idx, env->tl); + } + + if (!do_fault) { + *prot = PAGE_READ; + if (TTE_IS_W_OK(env->dtlb[i].tte)) { + *prot |= PAGE_WRITE; + } + + TTE_SET_USED(env->dtlb[i].tte); + + return 0; + } + + if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ + sfsr |= SFSR_OW_BIT; /* overflow (not read before + another fault) */ + } + + if (env->pstate & PS_PRIV) { + sfsr |= SFSR_PR_BIT; + } + + /* FIXME: ASI field in SFSR must be set */ + env->dmmu.sfsr = sfsr | SFSR_VALID_BIT; + + env->dmmu.sfar = address; /* Fault address register */ + + env->dmmu.tag_access = (address & ~0x1fffULL) | context; + + return 1; + } + } + + trace_mmu_helper_dmiss(address, context); + + /* + * On MMU misses: + * - UltraSPARC IIi: SFSR and SFAR unmodified + * - JPS1: SFAR updated and some fields of SFSR updated + */ + env->dmmu.tag_access = (address & ~0x1fffULL) | context; + env->exception_index = TT_DMISS; + return 1; +} + +static int get_physical_address_code(CPUState *env, + target_phys_addr_t *physical, int *prot, + target_ulong address, int mmu_idx) +{ + unsigned int i; + uint64_t context; + + int is_user = (mmu_idx == MMU_USER_IDX || + mmu_idx == MMU_USER_SECONDARY_IDX); + + if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { + /* IMMU disabled */ + *physical = ultrasparc_truncate_physical(address); + *prot = PAGE_EXEC; + return 0; + } + + if (env->tl == 0) { + /* PRIMARY context */ + context = env->dmmu.mmu_primary_context & 0x1fff; + } else { + /* NUCLEUS context */ + context = 0; + } + + for (i = 0; i < 64; i++) { + /* ctx match, vaddr match, valid? */ + if (ultrasparc_tag_match(&env->itlb[i], + address, context, physical)) { + /* access ok? */ + if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { + /* Fault status register */ + if (env->immu.sfsr & SFSR_VALID_BIT) { + env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before + another fault) */ + } else { + env->immu.sfsr = 0; + } + if (env->pstate & PS_PRIV) { + env->immu.sfsr |= SFSR_PR_BIT; + } + if (env->tl > 0) { + env->immu.sfsr |= SFSR_CT_NUCLEUS; + } + + /* FIXME: ASI field in SFSR must be set */ + env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; + env->exception_index = TT_TFAULT; + + env->immu.tag_access = (address & ~0x1fffULL) | context; + + trace_mmu_helper_tfault(address, context); + + return 1; + } + *prot = PAGE_EXEC; + TTE_SET_USED(env->itlb[i].tte); + return 0; + } + } + + trace_mmu_helper_tmiss(address, context); + + /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ + env->immu.tag_access = (address & ~0x1fffULL) | context; + env->exception_index = TT_TMISS; + return 1; +} + +static int get_physical_address(CPUState *env, target_phys_addr_t *physical, + int *prot, int *access_index, + target_ulong address, int rw, int mmu_idx, + target_ulong *page_size) +{ + /* ??? We treat everything as a small page, then explicitly flush + everything when an entry is evicted. */ + *page_size = TARGET_PAGE_SIZE; + + /* safety net to catch wrong softmmu index use from dynamic code */ + if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { + if (rw == 2) { + trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx, + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context, + address); + } else { + trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx, + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context, + address); + } + } + + if (rw == 2) { + return get_physical_address_code(env, physical, prot, address, + mmu_idx); + } else { + return get_physical_address_data(env, physical, prot, address, rw, + mmu_idx); + } +} + +/* Perform address translation */ +int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx) +{ + target_ulong virt_addr, vaddr; + target_phys_addr_t paddr; + target_ulong page_size; + int error_code = 0, prot, access_index; + + error_code = get_physical_address(env, &paddr, &prot, &access_index, + address, rw, mmu_idx, &page_size); + if (error_code == 0) { + virt_addr = address & TARGET_PAGE_MASK; + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & + (TARGET_PAGE_SIZE - 1)); + + trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl, + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context); + + tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); + return 0; + } + /* XXX */ + return 1; +} + +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) +{ + unsigned int i; + const char *mask; + + (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" + PRId64 "\n", + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context); + if ((env->lsu & DMMU_E) == 0) { + (*cpu_fprintf)(f, "DMMU disabled\n"); + } else { + (*cpu_fprintf)(f, "DMMU dump\n"); + for (i = 0; i < 64; i++) { + switch (TTE_PGSIZE(env->dtlb[i].tte)) { + default: + case 0x0: + mask = " 8k"; + break; + case 0x1: + mask = " 64k"; + break; + case 0x2: + mask = "512k"; + break; + case 0x3: + mask = " 4M"; + break; + } + if (TTE_IS_VALID(env->dtlb[i].tte)) { + (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" + ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", + i, + env->dtlb[i].tag & (uint64_t)~0x1fffULL, + TTE_PA(env->dtlb[i].tte), + mask, + TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", + TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", + TTE_IS_LOCKED(env->dtlb[i].tte) ? + "locked" : "unlocked", + env->dtlb[i].tag & (uint64_t)0x1fffULL, + TTE_IS_GLOBAL(env->dtlb[i].tte) ? + "global" : "local"); + } + } + } + if ((env->lsu & IMMU_E) == 0) { + (*cpu_fprintf)(f, "IMMU disabled\n"); + } else { + (*cpu_fprintf)(f, "IMMU dump\n"); + for (i = 0; i < 64; i++) { + switch (TTE_PGSIZE(env->itlb[i].tte)) { + default: + case 0x0: + mask = " 8k"; + break; + case 0x1: + mask = " 64k"; + break; + case 0x2: + mask = "512k"; + break; + case 0x3: + mask = " 4M"; + break; + } + if (TTE_IS_VALID(env->itlb[i].tte)) { + (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" + ", %s, %s, %s, ctx %" PRId64 " %s\n", + i, + env->itlb[i].tag & (uint64_t)~0x1fffULL, + TTE_PA(env->itlb[i].tte), + mask, + TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", + TTE_IS_LOCKED(env->itlb[i].tte) ? + "locked" : "unlocked", + env->itlb[i].tag & (uint64_t)0x1fffULL, + TTE_IS_GLOBAL(env->itlb[i].tte) ? + "global" : "local"); + } + } + } +} + +#endif /* TARGET_SPARC64 */ + +static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys, + target_ulong addr, int rw, int mmu_idx) +{ + target_ulong page_size; + int prot, access_index; + + return get_physical_address(env, phys, &prot, &access_index, addr, rw, + mmu_idx, &page_size); +} + +#if defined(TARGET_SPARC64) +target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, + int mmu_idx) +{ + target_phys_addr_t phys_addr; + + if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { + return -1; + } + return phys_addr; +} +#endif + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + target_phys_addr_t phys_addr; + int mmu_idx = cpu_mmu_index(env); + + if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { + if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { + return -1; + } + } + if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) { + return -1; + } + return phys_addr; +} +#endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 1cb0636c30..02b660ddf9 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1,4179 +1,8 @@ #include "cpu.h" #include "dyngen-exec.h" -#include "host-utils.h" #include "helper.h" -#include "sysemu.h" #if !defined(CONFIG_USER_ONLY) -#include "softmmu_exec.h" -#endif - -//#define DEBUG_MMU -//#define DEBUG_MXCC -//#define DEBUG_UNALIGNED -//#define DEBUG_UNASSIGNED -//#define DEBUG_ASI -//#define DEBUG_PCALL -//#define DEBUG_PSTATE -//#define DEBUG_CACHE_CONTROL - -#ifdef DEBUG_MMU -#define DPRINTF_MMU(fmt, ...) \ - do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_MMU(fmt, ...) do {} while (0) -#endif - -#ifdef DEBUG_MXCC -#define DPRINTF_MXCC(fmt, ...) \ - do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_MXCC(fmt, ...) do {} while (0) -#endif - -#ifdef DEBUG_ASI -#define DPRINTF_ASI(fmt, ...) \ - do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0) -#endif - -#ifdef DEBUG_PSTATE -#define DPRINTF_PSTATE(fmt, ...) \ - do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_PSTATE(fmt, ...) do {} while (0) -#endif - -#ifdef DEBUG_CACHE_CONTROL -#define DPRINTF_CACHE_CONTROL(fmt, ...) \ - do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0) -#endif - -#ifdef TARGET_SPARC64 -#ifndef TARGET_ABI32 -#define AM_CHECK(env1) ((env1)->pstate & PS_AM) -#else -#define AM_CHECK(env1) (1) -#endif -#endif - -#define DT0 (env->dt0) -#define DT1 (env->dt1) -#define QT0 (env->qt0) -#define QT1 (env->qt1) - -/* Leon3 cache control */ - -/* Cache control: emulate the behavior of cache control registers but without - any effect on the emulated */ - -#define CACHE_STATE_MASK 0x3 -#define CACHE_DISABLED 0x0 -#define CACHE_FROZEN 0x1 -#define CACHE_ENABLED 0x3 - -/* Cache Control register fields */ - -#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */ -#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */ -#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */ -#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */ -#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */ -#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */ -#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */ -#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */ - -#if !defined(CONFIG_USER_ONLY) -static void do_unassigned_access(target_phys_addr_t addr, int is_write, - int is_exec, int is_asi, int size); -#else -#ifdef TARGET_SPARC64 -static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, - int is_asi, int size); -#endif -#endif - -#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) -// Calculates TSB pointer value for fault page size 8k or 64k -static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, - uint64_t tag_access_register, - int page_size) -{ - uint64_t tsb_base = tsb_register & ~0x1fffULL; - int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0; - int tsb_size = tsb_register & 0xf; - - // discard lower 13 bits which hold tag access context - uint64_t tag_access_va = tag_access_register & ~0x1fffULL; - - // now reorder bits - uint64_t tsb_base_mask = ~0x1fffULL; - uint64_t va = tag_access_va; - - // move va bits to correct position - if (page_size == 8*1024) { - va >>= 9; - } else if (page_size == 64*1024) { - va >>= 12; - } - - if (tsb_size) { - tsb_base_mask <<= tsb_size; - } - - // calculate tsb_base mask and adjust va if split is in use - if (tsb_split) { - if (page_size == 8*1024) { - va &= ~(1ULL << (13 + tsb_size)); - } else if (page_size == 64*1024) { - va |= (1ULL << (13 + tsb_size)); - } - tsb_base_mask <<= 1; - } - - return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL; -} - -// Calculates tag target register value by reordering bits -// in tag access register -static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) -{ - return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); -} - -static void replace_tlb_entry(SparcTLBEntry *tlb, - uint64_t tlb_tag, uint64_t tlb_tte, - CPUState *env1) -{ - target_ulong mask, size, va, offset; - - // flush page range if translation is valid - if (TTE_IS_VALID(tlb->tte)) { - - mask = 0xffffffffffffe000ULL; - mask <<= 3 * ((tlb->tte >> 61) & 3); - size = ~mask + 1; - - va = tlb->tag & mask; - - for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) { - tlb_flush_page(env1, va + offset); - } - } - - tlb->tag = tlb_tag; - tlb->tte = tlb_tte; -} - -static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, - const char* strmmu, CPUState *env1) -{ - unsigned int i; - target_ulong mask; - uint64_t context; - - int is_demap_context = (demap_addr >> 6) & 1; - - // demap context - switch ((demap_addr >> 4) & 3) { - case 0: // primary - context = env1->dmmu.mmu_primary_context; - break; - case 1: // secondary - context = env1->dmmu.mmu_secondary_context; - break; - case 2: // nucleus - context = 0; - break; - case 3: // reserved - default: - return; - } - - for (i = 0; i < 64; i++) { - if (TTE_IS_VALID(tlb[i].tte)) { - - if (is_demap_context) { - // will remove non-global entries matching context value - if (TTE_IS_GLOBAL(tlb[i].tte) || - !tlb_compare_context(&tlb[i], context)) { - continue; - } - } else { - // demap page - // will remove any entry matching VA - mask = 0xffffffffffffe000ULL; - mask <<= 3 * ((tlb[i].tte >> 61) & 3); - - if (!compare_masked(demap_addr, tlb[i].tag, mask)) { - continue; - } - - // entry should be global or matching context value - if (!TTE_IS_GLOBAL(tlb[i].tte) && - !tlb_compare_context(&tlb[i], context)) { - continue; - } - } - - replace_tlb_entry(&tlb[i], 0, 0, env1); -#ifdef DEBUG_MMU - DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); - dump_mmu(stdout, fprintf, env1); -#endif - } - } -} - -static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, - uint64_t tlb_tag, uint64_t tlb_tte, - const char* strmmu, CPUState *env1) -{ - unsigned int i, replace_used; - - // Try replacing invalid entry - for (i = 0; i < 64; i++) { - if (!TTE_IS_VALID(tlb[i].tte)) { - replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); -#ifdef DEBUG_MMU - DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); - dump_mmu(stdout, fprintf, env1); -#endif - return; - } - } - - // All entries are valid, try replacing unlocked entry - - for (replace_used = 0; replace_used < 2; ++replace_used) { - - // Used entries are not replaced on first pass - - for (i = 0; i < 64; i++) { - if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) { - - replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); -#ifdef DEBUG_MMU - DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", - strmmu, (replace_used?"used":"unused"), i); - dump_mmu(stdout, fprintf, env1); -#endif - return; - } - } - - // Now reset used bit and search for unused entries again - - for (i = 0; i < 64; i++) { - TTE_SET_UNUSED(tlb[i].tte); - } - } - -#ifdef DEBUG_MMU - DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu); -#endif - // error state? -} - -#endif - -static inline target_ulong address_mask(CPUState *env1, target_ulong addr) -{ -#ifdef TARGET_SPARC64 - if (AM_CHECK(env1)) - addr &= 0xffffffffULL; -#endif - return addr; -} - -/* returns true if access using this ASI is to have address translated by MMU - otherwise access is to raw physical address */ -static inline int is_translating_asi(int asi) -{ -#ifdef TARGET_SPARC64 - /* Ultrasparc IIi translating asi - - note this list is defined by cpu implementation - */ - switch (asi) { - case 0x04 ... 0x11: - case 0x16 ... 0x19: - case 0x1E ... 0x1F: - case 0x24 ... 0x2C: - case 0x70 ... 0x73: - case 0x78 ... 0x79: - case 0x80 ... 0xFF: - return 1; - - default: - return 0; - } -#else - /* TODO: check sparc32 bits */ - return 0; -#endif -} - -static inline target_ulong asi_address_mask(CPUState *env1, - int asi, target_ulong addr) -{ - if (is_translating_asi(asi)) { - return address_mask(env, addr); - } else { - return addr; - } -} - -static void raise_exception(int tt) -{ - env->exception_index = tt; - cpu_loop_exit(env); -} - -void HELPER(raise_exception)(int tt) -{ - raise_exception(tt); -} - -void helper_shutdown(void) -{ -#if !defined(CONFIG_USER_ONLY) - qemu_system_shutdown_request(); -#endif -} - -void helper_check_align(target_ulong addr, uint32_t align) -{ - if (addr & align) { -#ifdef DEBUG_UNALIGNED - printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx - "\n", addr, env->pc); -#endif - raise_exception(TT_UNALIGNED); - } -} - -#define F_HELPER(name, p) void helper_f##name##p(void) - -#define F_BINOP(name) \ - float32 helper_f ## name ## s (float32 src1, float32 src2) \ - { \ - return float32_ ## name (src1, src2, &env->fp_status); \ - } \ - F_HELPER(name, d) \ - { \ - DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ - } \ - F_HELPER(name, q) \ - { \ - QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ - } - -F_BINOP(add); -F_BINOP(sub); -F_BINOP(mul); -F_BINOP(div); -#undef F_BINOP - -void helper_fsmuld(float32 src1, float32 src2) -{ - DT0 = float64_mul(float32_to_float64(src1, &env->fp_status), - float32_to_float64(src2, &env->fp_status), - &env->fp_status); -} - -void helper_fdmulq(void) -{ - QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), - float64_to_float128(DT1, &env->fp_status), - &env->fp_status); -} - -float32 helper_fnegs(float32 src) -{ - return float32_chs(src); -} - -#ifdef TARGET_SPARC64 -F_HELPER(neg, d) -{ - DT0 = float64_chs(DT1); -} - -F_HELPER(neg, q) -{ - QT0 = float128_chs(QT1); -} -#endif - -/* Integer to float conversion. */ -float32 helper_fitos(int32_t src) -{ - return int32_to_float32(src, &env->fp_status); -} - -void helper_fitod(int32_t src) -{ - DT0 = int32_to_float64(src, &env->fp_status); -} - -void helper_fitoq(int32_t src) -{ - QT0 = int32_to_float128(src, &env->fp_status); -} - -#ifdef TARGET_SPARC64 -float32 helper_fxtos(void) -{ - return int64_to_float32(*((int64_t *)&DT1), &env->fp_status); -} - -F_HELPER(xto, d) -{ - DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); -} - -F_HELPER(xto, q) -{ - QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); -} -#endif -#undef F_HELPER - -/* floating point conversion */ -float32 helper_fdtos(void) -{ - return float64_to_float32(DT1, &env->fp_status); -} - -void helper_fstod(float32 src) -{ - DT0 = float32_to_float64(src, &env->fp_status); -} - -float32 helper_fqtos(void) -{ - return float128_to_float32(QT1, &env->fp_status); -} - -void helper_fstoq(float32 src) -{ - QT0 = float32_to_float128(src, &env->fp_status); -} - -void helper_fqtod(void) -{ - DT0 = float128_to_float64(QT1, &env->fp_status); -} - -void helper_fdtoq(void) -{ - QT0 = float64_to_float128(DT1, &env->fp_status); -} - -/* Float to integer conversion. */ -int32_t helper_fstoi(float32 src) -{ - return float32_to_int32_round_to_zero(src, &env->fp_status); -} - -int32_t helper_fdtoi(void) -{ - return float64_to_int32_round_to_zero(DT1, &env->fp_status); -} - -int32_t helper_fqtoi(void) -{ - return float128_to_int32_round_to_zero(QT1, &env->fp_status); -} - -#ifdef TARGET_SPARC64 -void helper_fstox(float32 src) -{ - *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status); -} - -void helper_fdtox(void) -{ - *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); -} - -void helper_fqtox(void) -{ - *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); -} - -void helper_faligndata(void) -{ - uint64_t tmp; - - tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); - /* on many architectures a shift of 64 does nothing */ - if ((env->gsr & 7) != 0) { - tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); - } - *((uint64_t *)&DT0) = tmp; -} - -#ifdef HOST_WORDS_BIGENDIAN -#define VIS_B64(n) b[7 - (n)] -#define VIS_W64(n) w[3 - (n)] -#define VIS_SW64(n) sw[3 - (n)] -#define VIS_L64(n) l[1 - (n)] -#define VIS_B32(n) b[3 - (n)] -#define VIS_W32(n) w[1 - (n)] -#else -#define VIS_B64(n) b[n] -#define VIS_W64(n) w[n] -#define VIS_SW64(n) sw[n] -#define VIS_L64(n) l[n] -#define VIS_B32(n) b[n] -#define VIS_W32(n) w[n] -#endif - -typedef union { - uint8_t b[8]; - uint16_t w[4]; - int16_t sw[4]; - uint32_t l[2]; - uint64_t ll; - float64 d; -} vis64; - -typedef union { - uint8_t b[4]; - uint16_t w[2]; - uint32_t l; - float32 f; -} vis32; - -void helper_fpmerge(void) -{ - vis64 s, d; - - s.d = DT0; - d.d = DT1; - - // Reverse calculation order to handle overlap - d.VIS_B64(7) = s.VIS_B64(3); - d.VIS_B64(6) = d.VIS_B64(3); - d.VIS_B64(5) = s.VIS_B64(2); - d.VIS_B64(4) = d.VIS_B64(2); - d.VIS_B64(3) = s.VIS_B64(1); - d.VIS_B64(2) = d.VIS_B64(1); - d.VIS_B64(1) = s.VIS_B64(0); - //d.VIS_B64(0) = d.VIS_B64(0); - - DT0 = d.d; -} - -void helper_fmul8x16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void helper_fmul8x16al(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void helper_fmul8x16au(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void helper_fmul8sux16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void helper_fmul8ulx16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void helper_fmuld8sux16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_L64(r) = tmp; - - // Reverse calculation order to handle overlap - PMUL(1); - PMUL(0); -#undef PMUL - - DT0 = d.d; -} - -void helper_fmuld8ulx16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_L64(r) = tmp; - - // Reverse calculation order to handle overlap - PMUL(1); - PMUL(0); -#undef PMUL - - DT0 = d.d; -} - -void helper_fexpand(void) -{ - vis32 s; - vis64 d; - - s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); - d.d = DT1; - d.VIS_W64(0) = s.VIS_B32(0) << 4; - d.VIS_W64(1) = s.VIS_B32(1) << 4; - d.VIS_W64(2) = s.VIS_B32(2) << 4; - d.VIS_W64(3) = s.VIS_B32(3) << 4; - - DT0 = d.d; -} - -#define VIS_HELPER(name, F) \ - void name##16(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \ - d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \ - d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \ - d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \ - \ - DT0 = d.d; \ - } \ - \ - uint32_t name##16s(uint32_t src1, uint32_t src2) \ - { \ - vis32 s, d; \ - \ - s.l = src1; \ - d.l = src2; \ - \ - d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ - d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ - \ - return d.l; \ - } \ - \ - void name##32(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \ - d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \ - \ - DT0 = d.d; \ - } \ - \ - uint32_t name##32s(uint32_t src1, uint32_t src2) \ - { \ - vis32 s, d; \ - \ - s.l = src1; \ - d.l = src2; \ - \ - d.l = F(d.l, s.l); \ - \ - return d.l; \ - } - -#define FADD(a, b) ((a) + (b)) -#define FSUB(a, b) ((a) - (b)) -VIS_HELPER(helper_fpadd, FADD) -VIS_HELPER(helper_fpsub, FSUB) - -#define VIS_CMPHELPER(name, F) \ - uint64_t name##16(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \ - d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \ - d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \ - d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \ - d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \ - \ - return d.ll; \ - } \ - \ - uint64_t name##32(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \ - d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \ - d.VIS_L64(1) = 0; \ - \ - return d.ll; \ - } - -#define FCMPGT(a, b) ((a) > (b)) -#define FCMPEQ(a, b) ((a) == (b)) -#define FCMPLE(a, b) ((a) <= (b)) -#define FCMPNE(a, b) ((a) != (b)) - -VIS_CMPHELPER(helper_fcmpgt, FCMPGT) -VIS_CMPHELPER(helper_fcmpeq, FCMPEQ) -VIS_CMPHELPER(helper_fcmple, FCMPLE) -VIS_CMPHELPER(helper_fcmpne, FCMPNE) -#endif - -void helper_check_ieee_exceptions(void) -{ - target_ulong status; - - status = get_float_exception_flags(&env->fp_status); - if (status) { - /* Copy IEEE 754 flags into FSR */ - if (status & float_flag_invalid) - env->fsr |= FSR_NVC; - if (status & float_flag_overflow) - env->fsr |= FSR_OFC; - if (status & float_flag_underflow) - env->fsr |= FSR_UFC; - if (status & float_flag_divbyzero) - env->fsr |= FSR_DZC; - if (status & float_flag_inexact) - env->fsr |= FSR_NXC; - - if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { - /* Unmasked exception, generate a trap */ - env->fsr |= FSR_FTT_IEEE_EXCP; - raise_exception(TT_FP_EXCP); - } else { - /* Accumulate exceptions */ - env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; - } - } -} - -void helper_clear_float_exceptions(void) -{ - set_float_exception_flags(0, &env->fp_status); -} - -float32 helper_fabss(float32 src) -{ - return float32_abs(src); -} - -#ifdef TARGET_SPARC64 -void helper_fabsd(void) -{ - DT0 = float64_abs(DT1); -} - -void helper_fabsq(void) -{ - QT0 = float128_abs(QT1); -} -#endif - -float32 helper_fsqrts(float32 src) -{ - return float32_sqrt(src, &env->fp_status); -} - -void helper_fsqrtd(void) -{ - DT0 = float64_sqrt(DT1, &env->fp_status); -} - -void helper_fsqrtq(void) -{ - QT0 = float128_sqrt(QT1, &env->fp_status); -} - -#define GEN_FCMP(name, size, reg1, reg2, FS, E) \ - void glue(helper_, name) (void) \ - { \ - env->fsr &= FSR_FTT_NMASK; \ - if (E && (glue(size, _is_any_nan)(reg1) || \ - glue(size, _is_any_nan)(reg2)) && \ - (env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - raise_exception(TT_FP_EXCP); \ - } \ - switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ - case float_relation_unordered: \ - if ((env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - raise_exception(TT_FP_EXCP); \ - } else { \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - } \ - break; \ - case float_relation_less: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= FSR_FCC0 << FS; \ - break; \ - case float_relation_greater: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= FSR_FCC1 << FS; \ - break; \ - default: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - break; \ - } \ - } -#define GEN_FCMPS(name, size, FS, E) \ - void glue(helper_, name)(float32 src1, float32 src2) \ - { \ - env->fsr &= FSR_FTT_NMASK; \ - if (E && (glue(size, _is_any_nan)(src1) || \ - glue(size, _is_any_nan)(src2)) && \ - (env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - raise_exception(TT_FP_EXCP); \ - } \ - switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ - case float_relation_unordered: \ - if ((env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - raise_exception(TT_FP_EXCP); \ - } else { \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - } \ - break; \ - case float_relation_less: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= FSR_FCC0 << FS; \ - break; \ - case float_relation_greater: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= FSR_FCC1 << FS; \ - break; \ - default: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - break; \ - } \ - } - -GEN_FCMPS(fcmps, float32, 0, 0); -GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); - -GEN_FCMPS(fcmpes, float32, 0, 1); -GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); - -GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); -GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); - -static uint32_t compute_all_flags(void) -{ - return env->psr & PSR_ICC; -} - -static uint32_t compute_C_flags(void) -{ - return env->psr & PSR_CARRY; -} - -static inline uint32_t get_NZ_icc(int32_t dst) -{ - uint32_t ret = 0; - - if (dst == 0) { - ret = PSR_ZERO; - } else if (dst < 0) { - ret = PSR_NEG; - } - return ret; -} - -#ifdef TARGET_SPARC64 -static uint32_t compute_all_flags_xcc(void) -{ - return env->xcc & PSR_ICC; -} - -static uint32_t compute_C_flags_xcc(void) -{ - return env->xcc & PSR_CARRY; -} - -static inline uint32_t get_NZ_xcc(target_long dst) -{ - uint32_t ret = 0; - - if (!dst) { - ret = PSR_ZERO; - } else if (dst < 0) { - ret = PSR_NEG; - } - return ret; -} -#endif - -static inline uint32_t get_V_div_icc(target_ulong src2) -{ - uint32_t ret = 0; - - if (src2 != 0) { - ret = PSR_OVF; - } - return ret; -} - -static uint32_t compute_all_div(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_V_div_icc(CC_SRC2); - return ret; -} - -static uint32_t compute_C_div(void) -{ - return 0; -} - -static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1) -{ - uint32_t ret = 0; - - if (dst < src1) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1, - uint32_t src2) -{ - uint32_t ret = 0; - - if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1, - uint32_t src2) -{ - uint32_t ret = 0; - - if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) { - ret = PSR_OVF; - } - return ret; -} - -#ifdef TARGET_SPARC64 -static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1) -{ - uint32_t ret = 0; - - if (dst < src1) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1, - target_ulong src2) -{ - uint32_t ret = 0; - - if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1, - target_ulong src2) -{ - uint32_t ret = 0; - - if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) { - ret = PSR_OVF; - } - return ret; -} - -static uint32_t compute_all_add_xcc(void) -{ - uint32_t ret; - - ret = get_NZ_xcc(CC_DST); - ret |= get_C_add_xcc(CC_DST, CC_SRC); - ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_add_xcc(void) -{ - return get_C_add_xcc(CC_DST, CC_SRC); -} -#endif - -static uint32_t compute_all_add(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_add_icc(CC_DST, CC_SRC); - ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_add(void) -{ - return get_C_add_icc(CC_DST, CC_SRC); -} - -#ifdef TARGET_SPARC64 -static uint32_t compute_all_addx_xcc(void) -{ - uint32_t ret; - - ret = get_NZ_xcc(CC_DST); - ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_addx_xcc(void) -{ - uint32_t ret; - - ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} -#endif - -static uint32_t compute_all_addx(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_addx(void) -{ - uint32_t ret; - - ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2) -{ - uint32_t ret = 0; - - if ((src1 | src2) & 0x3) { - ret = PSR_OVF; - } - return ret; -} - -static uint32_t compute_all_tadd(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_add_icc(CC_DST, CC_SRC); - ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_tag_icc(CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_all_taddtv(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_add_icc(CC_DST, CC_SRC); - return ret; -} - -static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2) -{ - uint32_t ret = 0; - - if (src1 < src2) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1, - uint32_t src2) -{ - uint32_t ret = 0; - - if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1, - uint32_t src2) -{ - uint32_t ret = 0; - - if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) { - ret = PSR_OVF; - } - return ret; -} - - -#ifdef TARGET_SPARC64 -static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2) -{ - uint32_t ret = 0; - - if (src1 < src2) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1, - target_ulong src2) -{ - uint32_t ret = 0; - - if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) { - ret = PSR_CARRY; - } - return ret; -} - -static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1, - target_ulong src2) -{ - uint32_t ret = 0; - - if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) { - ret = PSR_OVF; - } - return ret; -} - -static uint32_t compute_all_sub_xcc(void) -{ - uint32_t ret; - - ret = get_NZ_xcc(CC_DST); - ret |= get_C_sub_xcc(CC_SRC, CC_SRC2); - ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_sub_xcc(void) -{ - return get_C_sub_xcc(CC_SRC, CC_SRC2); -} -#endif - -static uint32_t compute_all_sub(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_sub_icc(CC_SRC, CC_SRC2); - ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_sub(void) -{ - return get_C_sub_icc(CC_SRC, CC_SRC2); -} - -#ifdef TARGET_SPARC64 -static uint32_t compute_all_subx_xcc(void) -{ - uint32_t ret; - - ret = get_NZ_xcc(CC_DST); - ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_subx_xcc(void) -{ - uint32_t ret; - - ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} -#endif - -static uint32_t compute_all_subx(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_C_subx(void) -{ - uint32_t ret; - - ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_all_tsub(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_sub_icc(CC_SRC, CC_SRC2); - ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_tag_icc(CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_all_tsubtv(void) -{ - uint32_t ret; - - ret = get_NZ_icc(CC_DST); - ret |= get_C_sub_icc(CC_SRC, CC_SRC2); - return ret; -} - -static uint32_t compute_all_logic(void) -{ - return get_NZ_icc(CC_DST); -} - -static uint32_t compute_C_logic(void) -{ - return 0; -} - -#ifdef TARGET_SPARC64 -static uint32_t compute_all_logic_xcc(void) -{ - return get_NZ_xcc(CC_DST); -} -#endif - -typedef struct CCTable { - uint32_t (*compute_all)(void); /* return all the flags */ - uint32_t (*compute_c)(void); /* return the C flag */ -} CCTable; - -static const CCTable icc_table[CC_OP_NB] = { - /* CC_OP_DYNAMIC should never happen */ - [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags }, - [CC_OP_DIV] = { compute_all_div, compute_C_div }, - [CC_OP_ADD] = { compute_all_add, compute_C_add }, - [CC_OP_ADDX] = { compute_all_addx, compute_C_addx }, - [CC_OP_TADD] = { compute_all_tadd, compute_C_add }, - [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add }, - [CC_OP_SUB] = { compute_all_sub, compute_C_sub }, - [CC_OP_SUBX] = { compute_all_subx, compute_C_subx }, - [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub }, - [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub }, - [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic }, -}; - -#ifdef TARGET_SPARC64 -static const CCTable xcc_table[CC_OP_NB] = { - /* CC_OP_DYNAMIC should never happen */ - [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc }, - [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic }, - [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc }, - [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc }, - [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc }, - [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc }, - [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, - [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc }, - [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, - [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc }, - [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic }, -}; -#endif - -void helper_compute_psr(void) -{ - uint32_t new_psr; - - new_psr = icc_table[CC_OP].compute_all(); - env->psr = new_psr; -#ifdef TARGET_SPARC64 - new_psr = xcc_table[CC_OP].compute_all(); - env->xcc = new_psr; -#endif - CC_OP = CC_OP_FLAGS; -} - -uint32_t helper_compute_C_icc(void) -{ - uint32_t ret; - - ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT; - return ret; -} - -static inline void memcpy32(target_ulong *dst, const target_ulong *src) -{ - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; - dst[4] = src[4]; - dst[5] = src[5]; - dst[6] = src[6]; - dst[7] = src[7]; -} - -static void set_cwp(int new_cwp) -{ - /* put the modified wrap registers at their proper location */ - if (env->cwp == env->nwindows - 1) { - memcpy32(env->regbase, env->regbase + env->nwindows * 16); - } - env->cwp = new_cwp; - - /* put the wrap registers at their temporary location */ - if (new_cwp == env->nwindows - 1) { - memcpy32(env->regbase + env->nwindows * 16, env->regbase); - } - env->regwptr = env->regbase + (new_cwp * 16); -} - -void cpu_set_cwp(CPUState *env1, int new_cwp) -{ - CPUState *saved_env; - - saved_env = env; - env = env1; - set_cwp(new_cwp); - env = saved_env; -} - -static target_ulong get_psr(void) -{ - helper_compute_psr(); - -#if !defined (TARGET_SPARC64) - return env->version | (env->psr & PSR_ICC) | - (env->psref? PSR_EF : 0) | - (env->psrpil << 8) | - (env->psrs? PSR_S : 0) | - (env->psrps? PSR_PS : 0) | - (env->psret? PSR_ET : 0) | env->cwp; -#else - return env->psr & PSR_ICC; -#endif -} - -target_ulong cpu_get_psr(CPUState *env1) -{ - CPUState *saved_env; - target_ulong ret; - - saved_env = env; - env = env1; - ret = get_psr(); - env = saved_env; - return ret; -} - -static void put_psr(target_ulong val) -{ - env->psr = val & PSR_ICC; -#if !defined (TARGET_SPARC64) - env->psref = (val & PSR_EF)? 1 : 0; - env->psrpil = (val & PSR_PIL) >> 8; -#endif -#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) - cpu_check_irqs(env); -#endif -#if !defined (TARGET_SPARC64) - env->psrs = (val & PSR_S)? 1 : 0; - env->psrps = (val & PSR_PS)? 1 : 0; - env->psret = (val & PSR_ET)? 1 : 0; - set_cwp(val & PSR_CWP); -#endif - env->cc_op = CC_OP_FLAGS; -} - -void cpu_put_psr(CPUState *env1, target_ulong val) -{ - CPUState *saved_env; - - saved_env = env; - env = env1; - put_psr(val); - env = saved_env; -} - -static int cwp_inc(int cwp) -{ - if (unlikely(cwp >= env->nwindows)) { - cwp -= env->nwindows; - } - return cwp; -} - -int cpu_cwp_inc(CPUState *env1, int cwp) -{ - CPUState *saved_env; - target_ulong ret; - - saved_env = env; - env = env1; - ret = cwp_inc(cwp); - env = saved_env; - return ret; -} - -static int cwp_dec(int cwp) -{ - if (unlikely(cwp < 0)) { - cwp += env->nwindows; - } - return cwp; -} - -int cpu_cwp_dec(CPUState *env1, int cwp) -{ - CPUState *saved_env; - target_ulong ret; - - saved_env = env; - env = env1; - ret = cwp_dec(cwp); - env = saved_env; - return ret; -} - -#ifdef TARGET_SPARC64 -GEN_FCMPS(fcmps_fcc1, float32, 22, 0); -GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); -GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); - -GEN_FCMPS(fcmps_fcc2, float32, 24, 0); -GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); -GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); - -GEN_FCMPS(fcmps_fcc3, float32, 26, 0); -GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); -GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); - -GEN_FCMPS(fcmpes_fcc1, float32, 22, 1); -GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); -GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); - -GEN_FCMPS(fcmpes_fcc2, float32, 24, 1); -GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); -GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); - -GEN_FCMPS(fcmpes_fcc3, float32, 26, 1); -GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); -GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); -#endif -#undef GEN_FCMPS - -#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \ - defined(DEBUG_MXCC) -static void dump_mxcc(CPUState *env) -{ - printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 - "\n", - env->mxccdata[0], env->mxccdata[1], - env->mxccdata[2], env->mxccdata[3]); - printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 - "\n" - " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 - "\n", - env->mxccregs[0], env->mxccregs[1], - env->mxccregs[2], env->mxccregs[3], - env->mxccregs[4], env->mxccregs[5], - env->mxccregs[6], env->mxccregs[7]); -} -#endif - -#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ - && defined(DEBUG_ASI) -static void dump_asi(const char *txt, target_ulong addr, int asi, int size, - uint64_t r1) -{ - switch (size) - { - case 1: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, - addr, asi, r1 & 0xff); - break; - case 2: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, - addr, asi, r1 & 0xffff); - break; - case 4: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, - addr, asi, r1 & 0xffffffff); - break; - case 8: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt, - addr, asi, r1); - break; - } -} -#endif - -#ifndef TARGET_SPARC64 -#ifndef CONFIG_USER_ONLY - - -/* Leon3 cache control */ - -static void leon3_cache_control_int(void) -{ - uint32_t state = 0; - - if (env->cache_control & CACHE_CTRL_IF) { - /* Instruction cache state */ - state = env->cache_control & CACHE_STATE_MASK; - if (state == CACHE_ENABLED) { - state = CACHE_FROZEN; - DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n"); - } - - env->cache_control &= ~CACHE_STATE_MASK; - env->cache_control |= state; - } - - if (env->cache_control & CACHE_CTRL_DF) { - /* Data cache state */ - state = (env->cache_control >> 2) & CACHE_STATE_MASK; - if (state == CACHE_ENABLED) { - state = CACHE_FROZEN; - DPRINTF_CACHE_CONTROL("Data cache: freeze\n"); - } - - env->cache_control &= ~(CACHE_STATE_MASK << 2); - env->cache_control |= (state << 2); - } -} - -static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size) -{ - DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n", - addr, val, size); - - if (size != 4) { - DPRINTF_CACHE_CONTROL("32bits only\n"); - return; - } - - switch (addr) { - case 0x00: /* Cache control */ - - /* These values must always be read as zeros */ - val &= ~CACHE_CTRL_FD; - val &= ~CACHE_CTRL_FI; - val &= ~CACHE_CTRL_IB; - val &= ~CACHE_CTRL_IP; - val &= ~CACHE_CTRL_DP; - - env->cache_control = val; - break; - case 0x04: /* Instruction cache configuration */ - case 0x08: /* Data cache configuration */ - /* Read Only */ - break; - default: - DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr); - break; - }; -} - -static uint64_t leon3_cache_control_ld(target_ulong addr, int size) -{ - uint64_t ret = 0; - - if (size != 4) { - DPRINTF_CACHE_CONTROL("32bits only\n"); - return 0; - } - - switch (addr) { - case 0x00: /* Cache control */ - ret = env->cache_control; - break; - - /* Configuration registers are read and only always keep those - predefined values */ - - case 0x04: /* Instruction cache configuration */ - ret = 0x10220000; - break; - case 0x08: /* Data cache configuration */ - ret = 0x18220000; - break; - default: - DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr); - break; - }; - DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n", - addr, ret, size); - return ret; -} - -void leon3_irq_manager(void *irq_manager, int intno) -{ - leon3_irq_ack(irq_manager, intno); - leon3_cache_control_int(); -} - -uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) -{ - uint64_t ret = 0; -#if defined(DEBUG_MXCC) || defined(DEBUG_ASI) - uint32_t last_addr = addr; -#endif - - helper_check_align(addr, size - 1); - switch (asi) { - case 2: /* SuperSparc MXCC registers and Leon3 cache control */ - switch (addr) { - case 0x00: /* Leon3 Cache Control */ - case 0x08: /* Leon3 Instruction Cache config */ - case 0x0C: /* Leon3 Date Cache config */ - if (env->def->features & CPU_FEATURE_CACHE_CTRL) { - ret = leon3_cache_control_ld(addr, size); - } - break; - case 0x01c00a00: /* MXCC control register */ - if (size == 8) - ret = env->mxccregs[3]; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00a04: /* MXCC control register */ - if (size == 4) - ret = env->mxccregs[3]; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00c00: /* Module reset register */ - if (size == 8) { - ret = env->mxccregs[5]; - // should we do something here? - } else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00f00: /* MBus port address register */ - if (size == 8) - ret = env->mxccregs[7]; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - default: - DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, - size); - break; - } - DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " - "addr = %08x -> ret = %" PRIx64 "," - "addr = %08x\n", asi, size, sign, last_addr, ret, addr); -#ifdef DEBUG_MXCC - dump_mxcc(env); -#endif - break; - case 3: /* MMU probe */ - { - int mmulev; - - mmulev = (addr >> 8) & 15; - if (mmulev > 4) - ret = 0; - else - ret = mmu_probe(env, addr, mmulev); - DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", - addr, mmulev, ret); - } - break; - case 4: /* read MMU regs */ - { - int reg = (addr >> 8) & 0x1f; - - ret = env->mmuregs[reg]; - if (reg == 3) /* Fault status cleared on read */ - env->mmuregs[3] = 0; - else if (reg == 0x13) /* Fault status read */ - ret = env->mmuregs[3]; - else if (reg == 0x14) /* Fault address read */ - ret = env->mmuregs[4]; - DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret); - } - break; - case 5: // Turbosparc ITLB Diagnostic - case 6: // Turbosparc DTLB Diagnostic - case 7: // Turbosparc IOTLB Diagnostic - break; - case 9: /* Supervisor code access */ - switch(size) { - case 1: - ret = ldub_code(addr); - break; - case 2: - ret = lduw_code(addr); - break; - default: - case 4: - ret = ldl_code(addr); - break; - case 8: - ret = ldq_code(addr); - break; - } - break; - case 0xa: /* User data access */ - switch(size) { - case 1: - ret = ldub_user(addr); - break; - case 2: - ret = lduw_user(addr); - break; - default: - case 4: - ret = ldl_user(addr); - break; - case 8: - ret = ldq_user(addr); - break; - } - break; - case 0xb: /* Supervisor data access */ - switch(size) { - case 1: - ret = ldub_kernel(addr); - break; - case 2: - ret = lduw_kernel(addr); - break; - default: - case 4: - ret = ldl_kernel(addr); - break; - case 8: - ret = ldq_kernel(addr); - break; - } - break; - case 0xc: /* I-cache tag */ - case 0xd: /* I-cache data */ - case 0xe: /* D-cache tag */ - case 0xf: /* D-cache data */ - break; - case 0x20: /* MMU passthrough */ - switch(size) { - case 1: - ret = ldub_phys(addr); - break; - case 2: - ret = lduw_phys(addr); - break; - default: - case 4: - ret = ldl_phys(addr); - break; - case 8: - ret = ldq_phys(addr); - break; - } - break; - case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ - switch(size) { - case 1: - ret = ldub_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32)); - break; - case 2: - ret = lduw_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32)); - break; - default: - case 4: - ret = ldl_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32)); - break; - case 8: - ret = ldq_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32)); - break; - } - break; - case 0x30: // Turbosparc secondary cache diagnostic - case 0x31: // Turbosparc RAM snoop - case 0x32: // Turbosparc page table descriptor diagnostic - case 0x39: /* data cache diagnostic register */ - ret = 0; - break; - case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ - { - int reg = (addr >> 8) & 3; - - switch(reg) { - case 0: /* Breakpoint Value (Addr) */ - ret = env->mmubpregs[reg]; - break; - case 1: /* Breakpoint Mask */ - ret = env->mmubpregs[reg]; - break; - case 2: /* Breakpoint Control */ - ret = env->mmubpregs[reg]; - break; - case 3: /* Breakpoint Status */ - ret = env->mmubpregs[reg]; - env->mmubpregs[reg] = 0ULL; - break; - } - DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg, - ret); - } - break; - case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ - ret = env->mmubpctrv; - break; - case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ - ret = env->mmubpctrc; - break; - case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ - ret = env->mmubpctrs; - break; - case 0x4c: /* SuperSPARC MMU Breakpoint Action */ - ret = env->mmubpaction; - break; - case 8: /* User code access, XXX */ - default: - do_unassigned_access(addr, 0, 0, asi, size); - ret = 0; - break; - } - if (sign) { - switch(size) { - case 1: - ret = (int8_t) ret; - break; - case 2: - ret = (int16_t) ret; - break; - case 4: - ret = (int32_t) ret; - break; - default: - break; - } - } -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return ret; -} - -void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) -{ - helper_check_align(addr, size - 1); - switch(asi) { - case 2: /* SuperSparc MXCC registers and Leon3 cache control */ - switch (addr) { - case 0x00: /* Leon3 Cache Control */ - case 0x08: /* Leon3 Instruction Cache config */ - case 0x0C: /* Leon3 Date Cache config */ - if (env->def->features & CPU_FEATURE_CACHE_CTRL) { - leon3_cache_control_st(addr, val, size); - } - break; - - case 0x01c00000: /* MXCC stream data register 0 */ - if (size == 8) - env->mxccdata[0] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00008: /* MXCC stream data register 1 */ - if (size == 8) - env->mxccdata[1] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00010: /* MXCC stream data register 2 */ - if (size == 8) - env->mxccdata[2] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00018: /* MXCC stream data register 3 */ - if (size == 8) - env->mxccdata[3] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00100: /* MXCC stream source */ - if (size == 8) - env->mxccregs[0] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + - 0); - env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + - 8); - env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + - 16); - env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + - 24); - break; - case 0x01c00200: /* MXCC stream destination */ - if (size == 8) - env->mxccregs[1] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, - env->mxccdata[0]); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, - env->mxccdata[1]); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, - env->mxccdata[2]); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, - env->mxccdata[3]); - break; - case 0x01c00a00: /* MXCC control register */ - if (size == 8) - env->mxccregs[3] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00a04: /* MXCC control register */ - if (size == 4) - env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) - | val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00e00: /* MXCC error register */ - // writing a 1 bit clears the error - if (size == 8) - env->mxccregs[6] &= ~val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - case 0x01c00f00: /* MBus port address register */ - if (size == 8) - env->mxccregs[7] = val; - else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, - size); - break; - default: - DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, - size); - break; - } - DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", - asi, size, addr, val); -#ifdef DEBUG_MXCC - dump_mxcc(env); -#endif - break; - case 3: /* MMU flush */ - { - int mmulev; - - mmulev = (addr >> 8) & 15; - DPRINTF_MMU("mmu flush level %d\n", mmulev); - switch (mmulev) { - case 0: // flush page - tlb_flush_page(env, addr & 0xfffff000); - break; - case 1: // flush segment (256k) - case 2: // flush region (16M) - case 3: // flush context (4G) - case 4: // flush entire - tlb_flush(env, 1); - break; - default: - break; - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - } - break; - case 4: /* write MMU regs */ - { - int reg = (addr >> 8) & 0x1f; - uint32_t oldreg; - - oldreg = env->mmuregs[reg]; - switch(reg) { - case 0: // Control Register - env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | - (val & 0x00ffffff); - // Mappings generated during no-fault mode or MMU - // disabled mode are invalid in normal mode - if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != - (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) - tlb_flush(env, 1); - break; - case 1: // Context Table Pointer Register - env->mmuregs[reg] = val & env->def->mmu_ctpr_mask; - break; - case 2: // Context Register - env->mmuregs[reg] = val & env->def->mmu_cxr_mask; - if (oldreg != env->mmuregs[reg]) { - /* we flush when the MMU context changes because - QEMU has no MMU context support */ - tlb_flush(env, 1); - } - break; - case 3: // Synchronous Fault Status Register with Clear - case 4: // Synchronous Fault Address Register - break; - case 0x10: // TLB Replacement Control Register - env->mmuregs[reg] = val & env->def->mmu_trcr_mask; - break; - case 0x13: // Synchronous Fault Status Register with Read and Clear - env->mmuregs[3] = val & env->def->mmu_sfsr_mask; - break; - case 0x14: // Synchronous Fault Address Register - env->mmuregs[4] = val; - break; - default: - env->mmuregs[reg] = val; - break; - } - if (oldreg != env->mmuregs[reg]) { - DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", - reg, oldreg, env->mmuregs[reg]); - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - } - break; - case 5: // Turbosparc ITLB Diagnostic - case 6: // Turbosparc DTLB Diagnostic - case 7: // Turbosparc IOTLB Diagnostic - break; - case 0xa: /* User data access */ - switch(size) { - case 1: - stb_user(addr, val); - break; - case 2: - stw_user(addr, val); - break; - default: - case 4: - stl_user(addr, val); - break; - case 8: - stq_user(addr, val); - break; - } - break; - case 0xb: /* Supervisor data access */ - switch(size) { - case 1: - stb_kernel(addr, val); - break; - case 2: - stw_kernel(addr, val); - break; - default: - case 4: - stl_kernel(addr, val); - break; - case 8: - stq_kernel(addr, val); - break; - } - break; - case 0xc: /* I-cache tag */ - case 0xd: /* I-cache data */ - case 0xe: /* D-cache tag */ - case 0xf: /* D-cache data */ - case 0x10: /* I/D-cache flush page */ - case 0x11: /* I/D-cache flush segment */ - case 0x12: /* I/D-cache flush region */ - case 0x13: /* I/D-cache flush context */ - case 0x14: /* I/D-cache flush user */ - break; - case 0x17: /* Block copy, sta access */ - { - // val = src - // addr = dst - // copy 32 bytes - unsigned int i; - uint32_t src = val & ~3, dst = addr & ~3, temp; - - for (i = 0; i < 32; i += 4, src += 4, dst += 4) { - temp = ldl_kernel(src); - stl_kernel(dst, temp); - } - } - break; - case 0x1f: /* Block fill, stda access */ - { - // addr = dst - // fill 32 bytes with val - unsigned int i; - uint32_t dst = addr & 7; - - for (i = 0; i < 32; i += 8, dst += 8) - stq_kernel(dst, val); - } - break; - case 0x20: /* MMU passthrough */ - { - switch(size) { - case 1: - stb_phys(addr, val); - break; - case 2: - stw_phys(addr, val); - break; - case 4: - default: - stl_phys(addr, val); - break; - case 8: - stq_phys(addr, val); - break; - } - } - break; - case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ - { - switch(size) { - case 1: - stb_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32), val); - break; - case 2: - stw_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32), val); - break; - case 4: - default: - stl_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32), val); - break; - case 8: - stq_phys((target_phys_addr_t)addr - | ((target_phys_addr_t)(asi & 0xf) << 32), val); - break; - } - } - break; - case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic - case 0x31: // store buffer data, Ross RT620 I-cache flush or - // Turbosparc snoop RAM - case 0x32: // store buffer control or Turbosparc page table - // descriptor diagnostic - case 0x36: /* I-cache flash clear */ - case 0x37: /* D-cache flash clear */ - break; - case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ - { - int reg = (addr >> 8) & 3; - - switch(reg) { - case 0: /* Breakpoint Value (Addr) */ - env->mmubpregs[reg] = (val & 0xfffffffffULL); - break; - case 1: /* Breakpoint Mask */ - env->mmubpregs[reg] = (val & 0xfffffffffULL); - break; - case 2: /* Breakpoint Control */ - env->mmubpregs[reg] = (val & 0x7fULL); - break; - case 3: /* Breakpoint Status */ - env->mmubpregs[reg] = (val & 0xfULL); - break; - } - DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg, - env->mmuregs[reg]); - } - break; - case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ - env->mmubpctrv = val & 0xffffffff; - break; - case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ - env->mmubpctrc = val & 0x3; - break; - case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ - env->mmubpctrs = val & 0x3; - break; - case 0x4c: /* SuperSPARC MMU Breakpoint Action */ - env->mmubpaction = val & 0x1fff; - break; - case 8: /* User code access, XXX */ - case 9: /* Supervisor code access, XXX */ - default: - do_unassigned_access(addr, 1, 0, asi, size); - break; - } -#ifdef DEBUG_ASI - dump_asi("write", addr, asi, size, val); -#endif -} - -#endif /* CONFIG_USER_ONLY */ -#else /* TARGET_SPARC64 */ - -#ifdef CONFIG_USER_ONLY -uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) -{ - uint64_t ret = 0; -#if defined(DEBUG_ASI) - target_ulong last_addr = addr; -#endif - - if (asi < 0x80) - raise_exception(TT_PRIV_ACT); - - helper_check_align(addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - switch (asi) { - case 0x82: // Primary no-fault - case 0x8a: // Primary no-fault LE - if (page_check_range(addr, size, PAGE_READ) == -1) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return 0; - } - // Fall through - case 0x80: // Primary - case 0x88: // Primary LE - { - switch(size) { - case 1: - ret = ldub_raw(addr); - break; - case 2: - ret = lduw_raw(addr); - break; - case 4: - ret = ldl_raw(addr); - break; - default: - case 8: - ret = ldq_raw(addr); - break; - } - } - break; - case 0x83: // Secondary no-fault - case 0x8b: // Secondary no-fault LE - if (page_check_range(addr, size, PAGE_READ) == -1) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return 0; - } - // Fall through - case 0x81: // Secondary - case 0x89: // Secondary LE - // XXX - break; - default: - break; - } - - /* Convert from little endian */ - switch (asi) { - case 0x88: // Primary LE - case 0x89: // Secondary LE - case 0x8a: // Primary no-fault LE - case 0x8b: // Secondary no-fault LE - switch(size) { - case 2: - ret = bswap16(ret); - break; - case 4: - ret = bswap32(ret); - break; - case 8: - ret = bswap64(ret); - break; - default: - break; - } - default: - break; - } - - /* Convert to signed number */ - if (sign) { - switch(size) { - case 1: - ret = (int8_t) ret; - break; - case 2: - ret = (int16_t) ret; - break; - case 4: - ret = (int32_t) ret; - break; - default: - break; - } - } -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return ret; -} - -void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) -{ -#ifdef DEBUG_ASI - dump_asi("write", addr, asi, size, val); -#endif - if (asi < 0x80) - raise_exception(TT_PRIV_ACT); - - helper_check_align(addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - /* Convert to little endian */ - switch (asi) { - case 0x88: // Primary LE - case 0x89: // Secondary LE - switch(size) { - case 2: - val = bswap16(val); - break; - case 4: - val = bswap32(val); - break; - case 8: - val = bswap64(val); - break; - default: - break; - } - default: - break; - } - - switch(asi) { - case 0x80: // Primary - case 0x88: // Primary LE - { - switch(size) { - case 1: - stb_raw(addr, val); - break; - case 2: - stw_raw(addr, val); - break; - case 4: - stl_raw(addr, val); - break; - case 8: - default: - stq_raw(addr, val); - break; - } - } - break; - case 0x81: // Secondary - case 0x89: // Secondary LE - // XXX - return; - - case 0x82: // Primary no-fault, RO - case 0x83: // Secondary no-fault, RO - case 0x8a: // Primary no-fault LE, RO - case 0x8b: // Secondary no-fault LE, RO - default: - do_unassigned_access(addr, 1, 0, 1, size); - return; - } -} - -#else /* CONFIG_USER_ONLY */ - -uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) -{ - uint64_t ret = 0; -#if defined(DEBUG_ASI) - target_ulong last_addr = addr; -#endif - - asi &= 0xff; - - if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (cpu_has_hypervisor(env) - && asi >= 0x30 && asi < 0x80 - && !(env->hpstate & HS_PRIV))) - raise_exception(TT_PRIV_ACT); - - helper_check_align(addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - /* process nonfaulting loads first */ - if ((asi & 0xf6) == 0x82) { - int mmu_idx; - - /* secondary space access has lowest asi bit equal to 1 */ - if (env->pstate & PS_PRIV) { - mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX; - } else { - mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX; - } - - if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - /* env->exception_index is set in get_physical_address_data(). */ - raise_exception(env->exception_index); - } - - /* convert nonfaulting load ASIs to normal load ASIs */ - asi &= ~0x02; - } - - switch (asi) { - case 0x10: // As if user primary - case 0x11: // As if user secondary - case 0x18: // As if user primary LE - case 0x19: // As if user secondary LE - case 0x80: // Primary - case 0x81: // Secondary - case 0x88: // Primary LE - case 0x89: // Secondary LE - case 0xe2: // UA2007 Primary block init - case 0xe3: // UA2007 Secondary block init - if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if (cpu_hypervisor_mode(env)) { - switch(size) { - case 1: - ret = ldub_hypv(addr); - break; - case 2: - ret = lduw_hypv(addr); - break; - case 4: - ret = ldl_hypv(addr); - break; - default: - case 8: - ret = ldq_hypv(addr); - break; - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch(size) { - case 1: - ret = ldub_kernel_secondary(addr); - break; - case 2: - ret = lduw_kernel_secondary(addr); - break; - case 4: - ret = ldl_kernel_secondary(addr); - break; - default: - case 8: - ret = ldq_kernel_secondary(addr); - break; - } - } else { - switch(size) { - case 1: - ret = ldub_kernel(addr); - break; - case 2: - ret = lduw_kernel(addr); - break; - case 4: - ret = ldl_kernel(addr); - break; - default: - case 8: - ret = ldq_kernel(addr); - break; - } - } - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch(size) { - case 1: - ret = ldub_user_secondary(addr); - break; - case 2: - ret = lduw_user_secondary(addr); - break; - case 4: - ret = ldl_user_secondary(addr); - break; - default: - case 8: - ret = ldq_user_secondary(addr); - break; - } - } else { - switch(size) { - case 1: - ret = ldub_user(addr); - break; - case 2: - ret = lduw_user(addr); - break; - case 4: - ret = ldl_user(addr); - break; - default: - case 8: - ret = ldq_user(addr); - break; - } - } - } - break; - case 0x14: // Bypass - case 0x15: // Bypass, non-cacheable - case 0x1c: // Bypass LE - case 0x1d: // Bypass, non-cacheable LE - { - switch(size) { - case 1: - ret = ldub_phys(addr); - break; - case 2: - ret = lduw_phys(addr); - break; - case 4: - ret = ldl_phys(addr); - break; - default: - case 8: - ret = ldq_phys(addr); - break; - } - break; - } - case 0x24: // Nucleus quad LDD 128 bit atomic - case 0x2c: // Nucleus quad LDD 128 bit atomic LE - // Only ldda allowed - raise_exception(TT_ILL_INSN); - return 0; - case 0x04: // Nucleus - case 0x0c: // Nucleus Little Endian (LE) - { - switch(size) { - case 1: - ret = ldub_nucleus(addr); - break; - case 2: - ret = lduw_nucleus(addr); - break; - case 4: - ret = ldl_nucleus(addr); - break; - default: - case 8: - ret = ldq_nucleus(addr); - break; - } - break; - } - case 0x4a: // UPA config - // XXX - break; - case 0x45: // LSU - ret = env->lsu; - break; - case 0x50: // I-MMU regs - { - int reg = (addr >> 3) & 0xf; - - if (reg == 0) { - // I-TSB Tag Target register - ret = ultrasparc_tag_target(env->immu.tag_access); - } else { - ret = env->immuregs[reg]; - } - - break; - } - case 0x51: // I-MMU 8k TSB pointer - { - // env->immuregs[5] holds I-MMU TSB register value - // env->immuregs[6] holds I-MMU Tag Access register value - ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, - 8*1024); - break; - } - case 0x52: // I-MMU 64k TSB pointer - { - // env->immuregs[5] holds I-MMU TSB register value - // env->immuregs[6] holds I-MMU Tag Access register value - ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, - 64*1024); - break; - } - case 0x55: // I-MMU data access - { - int reg = (addr >> 3) & 0x3f; - - ret = env->itlb[reg].tte; - break; - } - case 0x56: // I-MMU tag read - { - int reg = (addr >> 3) & 0x3f; - - ret = env->itlb[reg].tag; - break; - } - case 0x58: // D-MMU regs - { - int reg = (addr >> 3) & 0xf; - - if (reg == 0) { - // D-TSB Tag Target register - ret = ultrasparc_tag_target(env->dmmu.tag_access); - } else { - ret = env->dmmuregs[reg]; - } - break; - } - case 0x59: // D-MMU 8k TSB pointer - { - // env->dmmuregs[5] holds D-MMU TSB register value - // env->dmmuregs[6] holds D-MMU Tag Access register value - ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, - 8*1024); - break; - } - case 0x5a: // D-MMU 64k TSB pointer - { - // env->dmmuregs[5] holds D-MMU TSB register value - // env->dmmuregs[6] holds D-MMU Tag Access register value - ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, - 64*1024); - break; - } - case 0x5d: // D-MMU data access - { - int reg = (addr >> 3) & 0x3f; - - ret = env->dtlb[reg].tte; - break; - } - case 0x5e: // D-MMU tag read - { - int reg = (addr >> 3) & 0x3f; - - ret = env->dtlb[reg].tag; - break; - } - case 0x46: // D-cache data - case 0x47: // D-cache tag access - case 0x4b: // E-cache error enable - case 0x4c: // E-cache asynchronous fault status - case 0x4d: // E-cache asynchronous fault address - case 0x4e: // E-cache tag data - case 0x66: // I-cache instruction access - case 0x67: // I-cache tag access - case 0x6e: // I-cache predecode - case 0x6f: // I-cache LRU etc. - case 0x76: // E-cache tag - case 0x7e: // E-cache tag - break; - case 0x5b: // D-MMU data pointer - case 0x48: // Interrupt dispatch, RO - case 0x49: // Interrupt data receive - case 0x7f: // Incoming interrupt vector, RO - // XXX - break; - case 0x54: // I-MMU data in, WO - case 0x57: // I-MMU demap, WO - case 0x5c: // D-MMU data in, WO - case 0x5f: // D-MMU demap, WO - case 0x77: // Interrupt vector, WO - default: - do_unassigned_access(addr, 0, 0, 1, size); - ret = 0; - break; - } - - /* Convert from little endian */ - switch (asi) { - case 0x0c: // Nucleus Little Endian (LE) - case 0x18: // As if user primary LE - case 0x19: // As if user secondary LE - case 0x1c: // Bypass LE - case 0x1d: // Bypass, non-cacheable LE - case 0x88: // Primary LE - case 0x89: // Secondary LE - switch(size) { - case 2: - ret = bswap16(ret); - break; - case 4: - ret = bswap32(ret); - break; - case 8: - ret = bswap64(ret); - break; - default: - break; - } - default: - break; - } - - /* Convert to signed number */ - if (sign) { - switch(size) { - case 1: - ret = (int8_t) ret; - break; - case 2: - ret = (int16_t) ret; - break; - case 4: - ret = (int32_t) ret; - break; - default: - break; - } - } -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return ret; -} - -void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) -{ -#ifdef DEBUG_ASI - dump_asi("write", addr, asi, size, val); -#endif - - asi &= 0xff; - - if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (cpu_has_hypervisor(env) - && asi >= 0x30 && asi < 0x80 - && !(env->hpstate & HS_PRIV))) - raise_exception(TT_PRIV_ACT); - - helper_check_align(addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - /* Convert to little endian */ - switch (asi) { - case 0x0c: // Nucleus Little Endian (LE) - case 0x18: // As if user primary LE - case 0x19: // As if user secondary LE - case 0x1c: // Bypass LE - case 0x1d: // Bypass, non-cacheable LE - case 0x88: // Primary LE - case 0x89: // Secondary LE - switch(size) { - case 2: - val = bswap16(val); - break; - case 4: - val = bswap32(val); - break; - case 8: - val = bswap64(val); - break; - default: - break; - } - default: - break; - } - - switch(asi) { - case 0x10: // As if user primary - case 0x11: // As if user secondary - case 0x18: // As if user primary LE - case 0x19: // As if user secondary LE - case 0x80: // Primary - case 0x81: // Secondary - case 0x88: // Primary LE - case 0x89: // Secondary LE - case 0xe2: // UA2007 Primary block init - case 0xe3: // UA2007 Secondary block init - if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if (cpu_hypervisor_mode(env)) { - switch(size) { - case 1: - stb_hypv(addr, val); - break; - case 2: - stw_hypv(addr, val); - break; - case 4: - stl_hypv(addr, val); - break; - case 8: - default: - stq_hypv(addr, val); - break; - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch(size) { - case 1: - stb_kernel_secondary(addr, val); - break; - case 2: - stw_kernel_secondary(addr, val); - break; - case 4: - stl_kernel_secondary(addr, val); - break; - case 8: - default: - stq_kernel_secondary(addr, val); - break; - } - } else { - switch(size) { - case 1: - stb_kernel(addr, val); - break; - case 2: - stw_kernel(addr, val); - break; - case 4: - stl_kernel(addr, val); - break; - case 8: - default: - stq_kernel(addr, val); - break; - } - } - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch(size) { - case 1: - stb_user_secondary(addr, val); - break; - case 2: - stw_user_secondary(addr, val); - break; - case 4: - stl_user_secondary(addr, val); - break; - case 8: - default: - stq_user_secondary(addr, val); - break; - } - } else { - switch(size) { - case 1: - stb_user(addr, val); - break; - case 2: - stw_user(addr, val); - break; - case 4: - stl_user(addr, val); - break; - case 8: - default: - stq_user(addr, val); - break; - } - } - } - break; - case 0x14: // Bypass - case 0x15: // Bypass, non-cacheable - case 0x1c: // Bypass LE - case 0x1d: // Bypass, non-cacheable LE - { - switch(size) { - case 1: - stb_phys(addr, val); - break; - case 2: - stw_phys(addr, val); - break; - case 4: - stl_phys(addr, val); - break; - case 8: - default: - stq_phys(addr, val); - break; - } - } - return; - case 0x24: // Nucleus quad LDD 128 bit atomic - case 0x2c: // Nucleus quad LDD 128 bit atomic LE - // Only ldda allowed - raise_exception(TT_ILL_INSN); - return; - case 0x04: // Nucleus - case 0x0c: // Nucleus Little Endian (LE) - { - switch(size) { - case 1: - stb_nucleus(addr, val); - break; - case 2: - stw_nucleus(addr, val); - break; - case 4: - stl_nucleus(addr, val); - break; - default: - case 8: - stq_nucleus(addr, val); - break; - } - break; - } - - case 0x4a: // UPA config - // XXX - return; - case 0x45: // LSU - { - uint64_t oldreg; - - oldreg = env->lsu; - env->lsu = val & (DMMU_E | IMMU_E); - // Mappings generated during D/I MMU disabled mode are - // invalid in normal mode - if (oldreg != env->lsu) { - DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", - oldreg, env->lsu); -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env1); -#endif - tlb_flush(env, 1); - } - return; - } - case 0x50: // I-MMU regs - { - int reg = (addr >> 3) & 0xf; - uint64_t oldreg; - - oldreg = env->immuregs[reg]; - switch(reg) { - case 0: // RO - return; - case 1: // Not in I-MMU - case 2: - return; - case 3: // SFSR - if ((val & 1) == 0) - val = 0; // Clear SFSR - env->immu.sfsr = val; - break; - case 4: // RO - return; - case 5: // TSB access - DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", env->immu.tsb, val); - env->immu.tsb = val; - break; - case 6: // Tag access - env->immu.tag_access = val; - break; - case 7: - case 8: - return; - default: - break; - } - - if (oldreg != env->immuregs[reg]) { - DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", reg, oldreg, env->immuregs[reg]); - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x54: // I-MMU data in - replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); - return; - case 0x55: // I-MMU data access - { - // TODO: auto demap - - unsigned int i = (addr >> 3) & 0x3f; - - replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); - -#ifdef DEBUG_MMU - DPRINTF_MMU("immu data access replaced entry [%i]\n", i); - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x57: // I-MMU demap - demap_tlb(env->itlb, addr, "immu", env); - return; - case 0x58: // D-MMU regs - { - int reg = (addr >> 3) & 0xf; - uint64_t oldreg; - - oldreg = env->dmmuregs[reg]; - switch(reg) { - case 0: // RO - case 4: - return; - case 3: // SFSR - if ((val & 1) == 0) { - val = 0; // Clear SFSR, Fault address - env->dmmu.sfar = 0; - } - env->dmmu.sfsr = val; - break; - case 1: // Primary context - env->dmmu.mmu_primary_context = val; - /* can be optimized to only flush MMU_USER_IDX - and MMU_KERNEL_IDX entries */ - tlb_flush(env, 1); - break; - case 2: // Secondary context - env->dmmu.mmu_secondary_context = val; - /* can be optimized to only flush MMU_USER_SECONDARY_IDX - and MMU_KERNEL_SECONDARY_IDX entries */ - tlb_flush(env, 1); - break; - case 5: // TSB access - DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", env->dmmu.tsb, val); - env->dmmu.tsb = val; - break; - case 6: // Tag access - env->dmmu.tag_access = val; - break; - case 7: // Virtual Watchpoint - case 8: // Physical Watchpoint - default: - env->dmmuregs[reg] = val; - break; - } - - if (oldreg != env->dmmuregs[reg]) { - DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x5c: // D-MMU data in - replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); - return; - case 0x5d: // D-MMU data access - { - unsigned int i = (addr >> 3) & 0x3f; - - replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); - -#ifdef DEBUG_MMU - DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x5f: // D-MMU demap - demap_tlb(env->dtlb, addr, "dmmu", env); - return; - case 0x49: // Interrupt data receive - // XXX - return; - case 0x46: // D-cache data - case 0x47: // D-cache tag access - case 0x4b: // E-cache error enable - case 0x4c: // E-cache asynchronous fault status - case 0x4d: // E-cache asynchronous fault address - case 0x4e: // E-cache tag data - case 0x66: // I-cache instruction access - case 0x67: // I-cache tag access - case 0x6e: // I-cache predecode - case 0x6f: // I-cache LRU etc. - case 0x76: // E-cache tag - case 0x7e: // E-cache tag - return; - case 0x51: // I-MMU 8k TSB pointer, RO - case 0x52: // I-MMU 64k TSB pointer, RO - case 0x56: // I-MMU tag read, RO - case 0x59: // D-MMU 8k TSB pointer, RO - case 0x5a: // D-MMU 64k TSB pointer, RO - case 0x5b: // D-MMU data pointer, RO - case 0x5e: // D-MMU tag read, RO - case 0x48: // Interrupt dispatch, RO - case 0x7f: // Incoming interrupt vector, RO - case 0x82: // Primary no-fault, RO - case 0x83: // Secondary no-fault, RO - case 0x8a: // Primary no-fault LE, RO - case 0x8b: // Secondary no-fault LE, RO - default: - do_unassigned_access(addr, 1, 0, 1, size); - return; - } -} -#endif /* CONFIG_USER_ONLY */ - -void helper_ldda_asi(target_ulong addr, int asi, int rd) -{ - if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (cpu_has_hypervisor(env) - && asi >= 0x30 && asi < 0x80 - && !(env->hpstate & HS_PRIV))) - raise_exception(TT_PRIV_ACT); - - addr = asi_address_mask(env, asi, addr); - - switch (asi) { -#if !defined(CONFIG_USER_ONLY) - case 0x24: // Nucleus quad LDD 128 bit atomic - case 0x2c: // Nucleus quad LDD 128 bit atomic LE - helper_check_align(addr, 0xf); - if (rd == 0) { - env->gregs[1] = ldq_nucleus(addr + 8); - if (asi == 0x2c) - bswap64s(&env->gregs[1]); - } else if (rd < 8) { - env->gregs[rd] = ldq_nucleus(addr); - env->gregs[rd + 1] = ldq_nucleus(addr + 8); - if (asi == 0x2c) { - bswap64s(&env->gregs[rd]); - bswap64s(&env->gregs[rd + 1]); - } - } else { - env->regwptr[rd] = ldq_nucleus(addr); - env->regwptr[rd + 1] = ldq_nucleus(addr + 8); - if (asi == 0x2c) { - bswap64s(&env->regwptr[rd]); - bswap64s(&env->regwptr[rd + 1]); - } - } - break; -#endif - default: - helper_check_align(addr, 0x3); - if (rd == 0) - env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0); - else if (rd < 8) { - env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0); - env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); - } else { - env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0); - env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); - } - break; - } -} - -void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) -{ - unsigned int i; - CPU_DoubleU u; - - helper_check_align(addr, 3); - addr = asi_address_mask(env, asi, addr); - - switch (asi) { - case 0xf0: /* UA2007/JPS1 Block load primary */ - case 0xf1: /* UA2007/JPS1 Block load secondary */ - case 0xf8: /* UA2007/JPS1 Block load primary LE */ - case 0xf9: /* UA2007/JPS1 Block load secondary LE */ - if (rd & 7) { - raise_exception(TT_ILL_INSN); - return; - } - helper_check_align(addr, 0x3f); - for (i = 0; i < 16; i++) { - *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, - 0); - addr += 4; - } - - return; - case 0x16: /* UA2007 Block load primary, user privilege */ - case 0x17: /* UA2007 Block load secondary, user privilege */ - case 0x1e: /* UA2007 Block load primary LE, user privilege */ - case 0x1f: /* UA2007 Block load secondary LE, user privilege */ - case 0x70: /* JPS1 Block load primary, user privilege */ - case 0x71: /* JPS1 Block load secondary, user privilege */ - case 0x78: /* JPS1 Block load primary LE, user privilege */ - case 0x79: /* JPS1 Block load secondary LE, user privilege */ - if (rd & 7) { - raise_exception(TT_ILL_INSN); - return; - } - helper_check_align(addr, 0x3f); - for (i = 0; i < 16; i++) { - *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4, - 0); - addr += 4; - } - - return; - default: - break; - } - - switch(size) { - default: - case 4: - *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0); - break; - case 8: - u.ll = helper_ld_asi(addr, asi, size, 0); - *((uint32_t *)&env->fpr[rd++]) = u.l.upper; - *((uint32_t *)&env->fpr[rd++]) = u.l.lower; - break; - case 16: - u.ll = helper_ld_asi(addr, asi, 8, 0); - *((uint32_t *)&env->fpr[rd++]) = u.l.upper; - *((uint32_t *)&env->fpr[rd++]) = u.l.lower; - u.ll = helper_ld_asi(addr + 8, asi, 8, 0); - *((uint32_t *)&env->fpr[rd++]) = u.l.upper; - *((uint32_t *)&env->fpr[rd++]) = u.l.lower; - break; - } -} - -void helper_stf_asi(target_ulong addr, int asi, int size, int rd) -{ - unsigned int i; - target_ulong val = 0; - CPU_DoubleU u; - - helper_check_align(addr, 3); - addr = asi_address_mask(env, asi, addr); - - switch (asi) { - case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */ - case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */ - case 0xf0: /* UA2007/JPS1 Block store primary */ - case 0xf1: /* UA2007/JPS1 Block store secondary */ - case 0xf8: /* UA2007/JPS1 Block store primary LE */ - case 0xf9: /* UA2007/JPS1 Block store secondary LE */ - if (rd & 7) { - raise_exception(TT_ILL_INSN); - return; - } - helper_check_align(addr, 0x3f); - for (i = 0; i < 16; i++) { - val = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(addr, val, asi & 0x8f, 4); - addr += 4; - } - - return; - case 0x16: /* UA2007 Block load primary, user privilege */ - case 0x17: /* UA2007 Block load secondary, user privilege */ - case 0x1e: /* UA2007 Block load primary LE, user privilege */ - case 0x1f: /* UA2007 Block load secondary LE, user privilege */ - case 0x70: /* JPS1 Block store primary, user privilege */ - case 0x71: /* JPS1 Block store secondary, user privilege */ - case 0x78: /* JPS1 Block load primary LE, user privilege */ - case 0x79: /* JPS1 Block load secondary LE, user privilege */ - if (rd & 7) { - raise_exception(TT_ILL_INSN); - return; - } - helper_check_align(addr, 0x3f); - for (i = 0; i < 16; i++) { - val = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(addr, val, asi & 0x19, 4); - addr += 4; - } - - return; - default: - break; - } - - switch(size) { - default: - case 4: - helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size); - break; - case 8: - u.l.upper = *(uint32_t *)&env->fpr[rd++]; - u.l.lower = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(addr, u.ll, asi, size); - break; - case 16: - u.l.upper = *(uint32_t *)&env->fpr[rd++]; - u.l.lower = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(addr, u.ll, asi, 8); - u.l.upper = *(uint32_t *)&env->fpr[rd++]; - u.l.lower = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(addr + 8, u.ll, asi, 8); - break; - } -} - -target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, - target_ulong val2, uint32_t asi) -{ - target_ulong ret; - - val2 &= 0xffffffffUL; - ret = helper_ld_asi(addr, asi, 4, 0); - ret &= 0xffffffffUL; - if (val2 == ret) - helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); - return ret; -} - -target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, - target_ulong val2, uint32_t asi) -{ - target_ulong ret; - - ret = helper_ld_asi(addr, asi, 8, 0); - if (val2 == ret) - helper_st_asi(addr, val1, asi, 8); - return ret; -} -#endif /* TARGET_SPARC64 */ - -#ifndef TARGET_SPARC64 -void helper_rett(void) -{ - unsigned int cwp; - - if (env->psret == 1) - raise_exception(TT_ILL_INSN); - - env->psret = 1; - cwp = cwp_inc(env->cwp + 1) ; - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_UNF); - } - set_cwp(cwp); - env->psrs = env->psrps; -} -#endif - -static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc) -{ - int overflow = 0; - uint64_t x0; - uint32_t x1; - - x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); - x1 = (b & 0xffffffff); - - if (x1 == 0) { - raise_exception(TT_DIV_ZERO); - } - - x0 = x0 / x1; - if (x0 > 0xffffffff) { - x0 = 0xffffffff; - overflow = 1; - } - - if (cc) { - env->cc_dst = x0; - env->cc_src2 = overflow; - env->cc_op = CC_OP_DIV; - } - return x0; -} - -target_ulong helper_udiv(target_ulong a, target_ulong b) -{ - return helper_udiv_common(a, b, 0); -} - -target_ulong helper_udiv_cc(target_ulong a, target_ulong b) -{ - return helper_udiv_common(a, b, 1); -} - -static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc) -{ - int overflow = 0; - int64_t x0; - int32_t x1; - - x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); - x1 = (b & 0xffffffff); - - if (x1 == 0) { - raise_exception(TT_DIV_ZERO); - } - - x0 = x0 / x1; - if ((int32_t) x0 != x0) { - x0 = x0 < 0 ? 0x80000000: 0x7fffffff; - overflow = 1; - } - - if (cc) { - env->cc_dst = x0; - env->cc_src2 = overflow; - env->cc_op = CC_OP_DIV; - } - return x0; -} - -target_ulong helper_sdiv(target_ulong a, target_ulong b) -{ - return helper_sdiv_common(a, b, 0); -} - -target_ulong helper_sdiv_cc(target_ulong a, target_ulong b) -{ - return helper_sdiv_common(a, b, 1); -} - -void helper_stdf(target_ulong addr, int mem_idx) -{ - helper_check_align(addr, 7); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - stfq_user(addr, DT0); - break; - case MMU_KERNEL_IDX: - stfq_kernel(addr, DT0); - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - stfq_hypv(addr, DT0); - break; -#endif - default: - DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - stfq_raw(address_mask(env, addr), DT0); -#endif -} - -void helper_lddf(target_ulong addr, int mem_idx) -{ - helper_check_align(addr, 7); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - DT0 = ldfq_user(addr); - break; - case MMU_KERNEL_IDX: - DT0 = ldfq_kernel(addr); - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - DT0 = ldfq_hypv(addr); - break; -#endif - default: - DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - DT0 = ldfq_raw(address_mask(env, addr)); -#endif -} - -void helper_ldqf(target_ulong addr, int mem_idx) -{ - // XXX add 128 bit load - CPU_QuadU u; - - helper_check_align(addr, 7); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - u.ll.upper = ldq_user(addr); - u.ll.lower = ldq_user(addr + 8); - QT0 = u.q; - break; - case MMU_KERNEL_IDX: - u.ll.upper = ldq_kernel(addr); - u.ll.lower = ldq_kernel(addr + 8); - QT0 = u.q; - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - u.ll.upper = ldq_hypv(addr); - u.ll.lower = ldq_hypv(addr + 8); - QT0 = u.q; - break; -#endif - default: - DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - u.ll.upper = ldq_raw(address_mask(env, addr)); - u.ll.lower = ldq_raw(address_mask(env, addr + 8)); - QT0 = u.q; -#endif -} - -void helper_stqf(target_ulong addr, int mem_idx) -{ - // XXX add 128 bit store - CPU_QuadU u; - - helper_check_align(addr, 7); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - u.q = QT0; - stq_user(addr, u.ll.upper); - stq_user(addr + 8, u.ll.lower); - break; - case MMU_KERNEL_IDX: - u.q = QT0; - stq_kernel(addr, u.ll.upper); - stq_kernel(addr + 8, u.ll.lower); - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - u.q = QT0; - stq_hypv(addr, u.ll.upper); - stq_hypv(addr + 8, u.ll.lower); - break; -#endif - default: - DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - u.q = QT0; - stq_raw(address_mask(env, addr), u.ll.upper); - stq_raw(address_mask(env, addr + 8), u.ll.lower); -#endif -} - -static inline void set_fsr(void) -{ - int rnd_mode; - - switch (env->fsr & FSR_RD_MASK) { - case FSR_RD_NEAREST: - rnd_mode = float_round_nearest_even; - break; - default: - case FSR_RD_ZERO: - rnd_mode = float_round_to_zero; - break; - case FSR_RD_POS: - rnd_mode = float_round_up; - break; - case FSR_RD_NEG: - rnd_mode = float_round_down; - break; - } - set_float_rounding_mode(rnd_mode, &env->fp_status); -} - -void helper_ldfsr(uint32_t new_fsr) -{ - env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK); - set_fsr(); -} - -#ifdef TARGET_SPARC64 -void helper_ldxfsr(uint64_t new_fsr) -{ - env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK); - set_fsr(); -} -#endif - -void helper_debug(void) -{ - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(env); -} - -#ifndef TARGET_SPARC64 -/* XXX: use another pointer for %iN registers to avoid slow wrapping - handling ? */ -void helper_save(void) -{ - uint32_t cwp; - - cwp = cwp_dec(env->cwp - 1); - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_OVF); - } - set_cwp(cwp); -} - -void helper_restore(void) -{ - uint32_t cwp; - - cwp = cwp_inc(env->cwp + 1); - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_UNF); - } - set_cwp(cwp); -} - -void helper_wrpsr(target_ulong new_psr) -{ - if ((new_psr & PSR_CWP) >= env->nwindows) { - raise_exception(TT_ILL_INSN); - } else { - cpu_put_psr(env, new_psr); - } -} - -target_ulong helper_rdpsr(void) -{ - return get_psr(); -} - -#else -/* XXX: use another pointer for %iN registers to avoid slow wrapping - handling ? */ -void helper_save(void) -{ - uint32_t cwp; - - cwp = cwp_dec(env->cwp - 1); - if (env->cansave == 0) { - raise_exception(TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); - } else { - if (env->cleanwin - env->canrestore == 0) { - // XXX Clean windows without trap - raise_exception(TT_CLRWIN); - } else { - env->cansave--; - env->canrestore++; - set_cwp(cwp); - } - } -} - -void helper_restore(void) -{ - uint32_t cwp; - - cwp = cwp_inc(env->cwp + 1); - if (env->canrestore == 0) { - raise_exception(TT_FILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); - } else { - env->cansave++; - env->canrestore--; - set_cwp(cwp); - } -} - -void helper_flushw(void) -{ - if (env->cansave != env->nwindows - 2) { - raise_exception(TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); - } -} - -void helper_saved(void) -{ - env->cansave++; - if (env->otherwin == 0) - env->canrestore--; - else - env->otherwin--; -} - -void helper_restored(void) -{ - env->canrestore++; - if (env->cleanwin < env->nwindows - 1) - env->cleanwin++; - if (env->otherwin == 0) - env->cansave--; - else - env->otherwin--; -} - -static target_ulong get_ccr(void) -{ - target_ulong psr; - - psr = get_psr(); - - return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20); -} - -target_ulong cpu_get_ccr(CPUState *env1) -{ - CPUState *saved_env; - target_ulong ret; - - saved_env = env; - env = env1; - ret = get_ccr(); - env = saved_env; - return ret; -} - -static void put_ccr(target_ulong val) -{ - env->xcc = (val >> 4) << 20; - env->psr = (val & 0xf) << 20; - CC_OP = CC_OP_FLAGS; -} - -void cpu_put_ccr(CPUState *env1, target_ulong val) -{ - CPUState *saved_env; - - saved_env = env; - env = env1; - put_ccr(val); - env = saved_env; -} - -static target_ulong get_cwp64(void) -{ - return env->nwindows - 1 - env->cwp; -} - -target_ulong cpu_get_cwp64(CPUState *env1) -{ - CPUState *saved_env; - target_ulong ret; - - saved_env = env; - env = env1; - ret = get_cwp64(); - env = saved_env; - return ret; -} - -static void put_cwp64(int cwp) -{ - if (unlikely(cwp >= env->nwindows || cwp < 0)) { - cwp %= env->nwindows; - } - set_cwp(env->nwindows - 1 - cwp); -} - -void cpu_put_cwp64(CPUState *env1, int cwp) -{ - CPUState *saved_env; - - saved_env = env; - env = env1; - put_cwp64(cwp); - env = saved_env; -} - -target_ulong helper_rdccr(void) -{ - return get_ccr(); -} - -void helper_wrccr(target_ulong new_ccr) -{ - put_ccr(new_ccr); -} - -// CWP handling is reversed in V9, but we still use the V8 register -// order. -target_ulong helper_rdcwp(void) -{ - return get_cwp64(); -} - -void helper_wrcwp(target_ulong new_cwp) -{ - put_cwp64(new_cwp); -} - -// This function uses non-native bit order -#define GET_FIELD(X, FROM, TO) \ - ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1)) - -// This function uses the order in the manuals, i.e. bit 0 is 2^0 -#define GET_FIELD_SP(X, FROM, TO) \ - GET_FIELD(X, 63 - (TO), 63 - (FROM)) - -target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize) -{ - return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) | - (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) | - (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) | - (GET_FIELD_SP(pixel_addr, 56, 59) << 13) | - (GET_FIELD_SP(pixel_addr, 35, 38) << 9) | - (GET_FIELD_SP(pixel_addr, 13, 16) << 5) | - (((pixel_addr >> 55) & 1) << 4) | - (GET_FIELD_SP(pixel_addr, 33, 34) << 2) | - GET_FIELD_SP(pixel_addr, 11, 12); -} - -target_ulong helper_alignaddr(target_ulong addr, target_ulong offset) -{ - uint64_t tmp; - - tmp = addr + offset; - env->gsr &= ~7ULL; - env->gsr |= tmp & 7ULL; - return tmp & ~7ULL; -} - -target_ulong helper_popc(target_ulong val) -{ - return ctpop64(val); -} - -static inline uint64_t *get_gregset(uint32_t pstate) -{ - switch (pstate) { - default: - DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n", - pstate, - (pstate & PS_IG) ? " IG" : "", - (pstate & PS_MG) ? " MG" : "", - (pstate & PS_AG) ? " AG" : ""); - /* pass through to normal set of global registers */ - case 0: - return env->bgregs; - case PS_AG: - return env->agregs; - case PS_MG: - return env->mgregs; - case PS_IG: - return env->igregs; - } -} - -static inline void change_pstate(uint32_t new_pstate) -{ - uint32_t pstate_regs, new_pstate_regs; - uint64_t *src, *dst; - - if (env->def->features & CPU_FEATURE_GL) { - // PS_AG is not implemented in this case - new_pstate &= ~PS_AG; - } - - pstate_regs = env->pstate & 0xc01; - new_pstate_regs = new_pstate & 0xc01; - - if (new_pstate_regs != pstate_regs) { - DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n", - pstate_regs, new_pstate_regs); - // Switch global register bank - src = get_gregset(new_pstate_regs); - dst = get_gregset(pstate_regs); - memcpy32(dst, env->gregs); - memcpy32(env->gregs, src); - } - else { - DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n", - new_pstate_regs); - } - env->pstate = new_pstate; -} - -void helper_wrpstate(target_ulong new_state) -{ - change_pstate(new_state & 0xf3f); - -#if !defined(CONFIG_USER_ONLY) - if (cpu_interrupts_enabled(env)) { - cpu_check_irqs(env); - } -#endif -} - -void cpu_change_pstate(CPUState *env1, uint32_t new_pstate) -{ - CPUState *saved_env; - - saved_env = env; - env = env1; - change_pstate(new_pstate); - env = saved_env; -} - -void helper_wrpil(target_ulong new_pil) -{ -#if !defined(CONFIG_USER_ONLY) - DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n", - env->psrpil, (uint32_t)new_pil); - - env->psrpil = new_pil; - - if (cpu_interrupts_enabled(env)) { - cpu_check_irqs(env); - } -#endif -} - -void helper_done(void) -{ - trap_state* tsptr = cpu_tsptr(env); - - env->pc = tsptr->tnpc; - env->npc = tsptr->tnpc + 4; - put_ccr(tsptr->tstate >> 32); - env->asi = (tsptr->tstate >> 24) & 0xff; - change_pstate((tsptr->tstate >> 8) & 0xf3f); - put_cwp64(tsptr->tstate & 0xff); - env->tl--; - - DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl); - -#if !defined(CONFIG_USER_ONLY) - if (cpu_interrupts_enabled(env)) { - cpu_check_irqs(env); - } -#endif -} - -void helper_retry(void) -{ - trap_state* tsptr = cpu_tsptr(env); - - env->pc = tsptr->tpc; - env->npc = tsptr->tnpc; - put_ccr(tsptr->tstate >> 32); - env->asi = (tsptr->tstate >> 24) & 0xff; - change_pstate((tsptr->tstate >> 8) & 0xf3f); - put_cwp64(tsptr->tstate & 0xff); - env->tl--; - - DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl); - -#if !defined(CONFIG_USER_ONLY) - if (cpu_interrupts_enabled(env)) { - cpu_check_irqs(env); - } -#endif -} - -static void do_modify_softint(const char* operation, uint32_t value) -{ - if (env->softint != value) { - env->softint = value; - DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint); -#if !defined(CONFIG_USER_ONLY) - if (cpu_interrupts_enabled(env)) { - cpu_check_irqs(env); - } -#endif - } -} - -void helper_set_softint(uint64_t value) -{ - do_modify_softint("helper_set_softint", env->softint | (uint32_t)value); -} - -void helper_clear_softint(uint64_t value) -{ - do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value); -} - -void helper_write_softint(uint64_t value) -{ - do_modify_softint("helper_write_softint", (uint32_t)value); -} -#endif - -#ifdef TARGET_SPARC64 -trap_state* cpu_tsptr(CPUState* env) -{ - return &env->ts[env->tl & MAXTL_MASK]; -} -#endif - -#if !defined(CONFIG_USER_ONLY) - static void do_unaligned_access(target_ulong addr, int is_write, int is_user, void *retaddr); @@ -4218,7 +47,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, "\n", addr, env->pc); #endif cpu_restore_state2(retaddr); - raise_exception(TT_UNALIGNED); + helper_raise_exception(env, TT_UNALIGNED); } /* try to fill the TLB and return an exception if error. If retaddr is @@ -4243,122 +72,3 @@ void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx, } #endif /* !CONFIG_USER_ONLY */ - -#ifndef TARGET_SPARC64 -#if !defined(CONFIG_USER_ONLY) -static void do_unassigned_access(target_phys_addr_t addr, int is_write, - int is_exec, int is_asi, int size) -{ - int fault_type; - -#ifdef DEBUG_UNASSIGNED - if (is_asi) - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx - " asi 0x%02x from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", size, - size == 1 ? "" : "s", addr, is_asi, env->pc); - else - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx - " from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", size, - size == 1 ? "" : "s", addr, env->pc); -#endif - /* Don't overwrite translation and access faults */ - fault_type = (env->mmuregs[3] & 0x1c) >> 2; - if ((fault_type > 4) || (fault_type == 0)) { - env->mmuregs[3] = 0; /* Fault status register */ - if (is_asi) - env->mmuregs[3] |= 1 << 16; - if (env->psrs) - env->mmuregs[3] |= 1 << 5; - if (is_exec) - env->mmuregs[3] |= 1 << 6; - if (is_write) - env->mmuregs[3] |= 1 << 7; - env->mmuregs[3] |= (5 << 2) | 2; - /* SuperSPARC will never place instruction fault addresses in the FAR */ - if (!is_exec) { - env->mmuregs[4] = addr; /* Fault address register */ - } - } - /* overflow (same type fault was not read before another fault) */ - if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) { - env->mmuregs[3] |= 1; - } - - if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { - if (is_exec) - raise_exception(TT_CODE_ACCESS); - else - raise_exception(TT_DATA_ACCESS); - } - - /* flush neverland mappings created during no-fault mode, - so the sequential MMU faults report proper fault types */ - if (env->mmuregs[0] & MMU_NF) { - tlb_flush(env, 1); - } -} -#endif -#else -#if defined(CONFIG_USER_ONLY) -static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, - int is_asi, int size) -#else -static void do_unassigned_access(target_phys_addr_t addr, int is_write, - int is_exec, int is_asi, int size) -#endif -{ -#ifdef DEBUG_UNASSIGNED - printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx - "\n", addr, env->pc); -#endif - - if (is_exec) - raise_exception(TT_CODE_ACCESS); - else - raise_exception(TT_DATA_ACCESS); -} -#endif - - -#ifdef TARGET_SPARC64 -void helper_tick_set_count(void *opaque, uint64_t count) -{ -#if !defined(CONFIG_USER_ONLY) - cpu_tick_set_count(opaque, count); -#endif -} - -uint64_t helper_tick_get_count(void *opaque) -{ -#if !defined(CONFIG_USER_ONLY) - return cpu_tick_get_count(opaque); -#else - return 0; -#endif -} - -void helper_tick_set_limit(void *opaque, uint64_t limit) -{ -#if !defined(CONFIG_USER_ONLY) - cpu_tick_set_limit(opaque, limit); -#endif -} -#endif - -#if !defined(CONFIG_USER_ONLY) -void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr, - int is_write, int is_exec, int is_asi, int size) -{ - CPUState *saved_env; - - saved_env = env; - env = env1; - /* Ignore unassigned accesses outside of CPU context */ - if (env1) { - do_unassigned_access(addr, is_write, is_exec, is_asi, size); - } - env = saved_env; -} -#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index dee67b334f..383fd9ce26 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -294,7 +294,7 @@ static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2) tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); gen_set_label(l1); tcg_temp_free(r_temp); @@ -310,7 +310,7 @@ static inline void gen_tag_tv(TCGv src1, TCGv src2) tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); gen_set_label(l1); } @@ -428,7 +428,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, default: /* We need external help to produce the carry. */ carry_32 = tcg_temp_new_i32(); - gen_helper_compute_C_icc(carry_32); + gen_helper_compute_C_icc(carry_32, cpu_env); break; } @@ -492,7 +492,7 @@ static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2) tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); gen_set_label(l1); tcg_temp_free(r_temp); @@ -567,7 +567,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, default: /* We need external help to produce the carry. */ carry_32 = tcg_temp_new_i32(); - gen_helper_compute_C_icc(carry_32); + gen_helper_compute_C_icc(carry_32, cpu_env); break; } @@ -719,7 +719,7 @@ static inline void gen_trap_ifdivzero_tl(TCGv divisor) l1 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1); r_const = tcg_const_i32(TT_DIV_ZERO); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); gen_set_label(l1); } @@ -1091,7 +1091,7 @@ static inline void save_state(DisasContext *dc, TCGv cond) /* flush pending conditional evaluations before exposing cpu state */ if (dc->cc_op != CC_OP_FLAGS) { dc->cc_op = CC_OP_FLAGS; - gen_helper_compute_psr(); + gen_helper_compute_psr(cpu_env); } save_npc(dc, cond); } @@ -1133,7 +1133,7 @@ static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, case CC_OP_FLAGS: break; default: - gen_helper_compute_psr(); + gen_helper_compute_psr(cpu_env); dc->cc_op = CC_OP_FLAGS; break; } @@ -1405,16 +1405,16 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2) { switch (fccno) { case 0: - gen_helper_fcmps(r_rs1, r_rs2); + gen_helper_fcmps(cpu_env, r_rs1, r_rs2); break; case 1: - gen_helper_fcmps_fcc1(r_rs1, r_rs2); + gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2); break; case 2: - gen_helper_fcmps_fcc2(r_rs1, r_rs2); + gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2); break; case 3: - gen_helper_fcmps_fcc3(r_rs1, r_rs2); + gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2); break; } } @@ -1423,16 +1423,16 @@ static inline void gen_op_fcmpd(int fccno) { switch (fccno) { case 0: - gen_helper_fcmpd(); + gen_helper_fcmpd(cpu_env); break; case 1: - gen_helper_fcmpd_fcc1(); + gen_helper_fcmpd_fcc1(cpu_env); break; case 2: - gen_helper_fcmpd_fcc2(); + gen_helper_fcmpd_fcc2(cpu_env); break; case 3: - gen_helper_fcmpd_fcc3(); + gen_helper_fcmpd_fcc3(cpu_env); break; } } @@ -1441,16 +1441,16 @@ static inline void gen_op_fcmpq(int fccno) { switch (fccno) { case 0: - gen_helper_fcmpq(); + gen_helper_fcmpq(cpu_env); break; case 1: - gen_helper_fcmpq_fcc1(); + gen_helper_fcmpq_fcc1(cpu_env); break; case 2: - gen_helper_fcmpq_fcc2(); + gen_helper_fcmpq_fcc2(cpu_env); break; case 3: - gen_helper_fcmpq_fcc3(); + gen_helper_fcmpq_fcc3(cpu_env); break; } } @@ -1459,16 +1459,16 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2) { switch (fccno) { case 0: - gen_helper_fcmpes(r_rs1, r_rs2); + gen_helper_fcmpes(cpu_env, r_rs1, r_rs2); break; case 1: - gen_helper_fcmpes_fcc1(r_rs1, r_rs2); + gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2); break; case 2: - gen_helper_fcmpes_fcc2(r_rs1, r_rs2); + gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2); break; case 3: - gen_helper_fcmpes_fcc3(r_rs1, r_rs2); + gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2); break; } } @@ -1477,16 +1477,16 @@ static inline void gen_op_fcmped(int fccno) { switch (fccno) { case 0: - gen_helper_fcmped(); + gen_helper_fcmped(cpu_env); break; case 1: - gen_helper_fcmped_fcc1(); + gen_helper_fcmped_fcc1(cpu_env); break; case 2: - gen_helper_fcmped_fcc2(); + gen_helper_fcmped_fcc2(cpu_env); break; case 3: - gen_helper_fcmped_fcc3(); + gen_helper_fcmped_fcc3(cpu_env); break; } } @@ -1495,16 +1495,16 @@ static inline void gen_op_fcmpeq(int fccno) { switch (fccno) { case 0: - gen_helper_fcmpeq(); + gen_helper_fcmpeq(cpu_env); break; case 1: - gen_helper_fcmpeq_fcc1(); + gen_helper_fcmpeq_fcc1(cpu_env); break; case 2: - gen_helper_fcmpeq_fcc2(); + gen_helper_fcmpeq_fcc2(cpu_env); break; case 3: - gen_helper_fcmpeq_fcc3(); + gen_helper_fcmpeq_fcc3(cpu_env); break; } } @@ -1513,32 +1513,32 @@ static inline void gen_op_fcmpeq(int fccno) static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2) { - gen_helper_fcmps(r_rs1, r_rs2); + gen_helper_fcmps(cpu_env, r_rs1, r_rs2); } static inline void gen_op_fcmpd(int fccno) { - gen_helper_fcmpd(); + gen_helper_fcmpd(cpu_env); } static inline void gen_op_fcmpq(int fccno) { - gen_helper_fcmpq(); + gen_helper_fcmpq(cpu_env); } static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2) { - gen_helper_fcmpes(r_rs1, r_rs2); + gen_helper_fcmpes(cpu_env, r_rs1, r_rs2); } static inline void gen_op_fcmped(int fccno) { - gen_helper_fcmped(); + gen_helper_fcmped(cpu_env); } static inline void gen_op_fcmpeq(int fccno) { - gen_helper_fcmpeq(); + gen_helper_fcmpeq(cpu_env); } #endif @@ -1549,7 +1549,7 @@ static inline void gen_op_fpexception_im(int fsr_flags) tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK); tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags); r_const = tcg_const_i32(TT_FP_EXCP); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); } @@ -1561,7 +1561,7 @@ static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond) save_state(dc, r_cond); r_const = tcg_const_i32(TT_NFPU_INSN); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); dc->is_br = 1; return 1; @@ -1584,7 +1584,7 @@ static inline void gen_op_clear_ieee_excp_and_FTT(void) static inline void gen_clear_float_exceptions(void) { - gen_helper_clear_float_exceptions(); + gen_helper_clear_float_exceptions(cpu_env); } /* asi moves */ @@ -2038,7 +2038,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_helper_shutdown(); } else { - gen_helper_raise_exception(cpu_tmp32); + gen_helper_raise_exception(cpu_env, cpu_tmp32); } } else if (cond != 0) { TCGv r_cond = tcg_temp_new(); @@ -2068,7 +2068,7 @@ static void disas_sparc_insn(DisasContext * dc) tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst); - gen_helper_raise_exception(cpu_tmp32); + gen_helper_raise_exception(cpu_env, cpu_tmp32); gen_set_label(l1); tcg_temp_free(r_cond); @@ -2106,8 +2106,8 @@ static void disas_sparc_insn(DisasContext * dc) break; #ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ - gen_helper_compute_psr(); - gen_helper_rdccr(cpu_dst); + gen_helper_compute_psr(cpu_env); + gen_helper_rdccr(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x3: /* V9 rdasi */ @@ -2182,9 +2182,9 @@ static void disas_sparc_insn(DisasContext * dc) #ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; - gen_helper_compute_psr(); + gen_helper_compute_psr(cpu_env); dc->cc_op = CC_OP_FLAGS; - gen_helper_rdpsr(cpu_dst); + gen_helper_rdpsr(cpu_dst, cpu_env); #else CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) @@ -2297,7 +2297,7 @@ static void disas_sparc_insn(DisasContext * dc) tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 9: // cwp - gen_helper_rdcwp(cpu_tmp0); + gen_helper_rdcwp(cpu_tmp0, cpu_env); break; case 10: // cansave tcg_gen_ld_i32(cpu_tmp32, cpu_env, @@ -2351,7 +2351,7 @@ static void disas_sparc_insn(DisasContext * dc) } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 save_state(dc, cpu_cond); - gen_helper_flushw(); + gen_helper_flushw(cpu_env); #else if (!supervisor(dc)) goto priv_insn; @@ -2383,8 +2383,8 @@ static void disas_sparc_insn(DisasContext * dc) case 0x29: /* fsqrts */ CHECK_FPU_FEATURE(dc, FSQRT); gen_clear_float_exceptions(); - gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fsqrts(cpu_tmp32, cpu_env, cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2392,8 +2392,8 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FSQRT); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fsqrtd(); - gen_helper_check_ieee_exceptions(); + gen_helper_fsqrtd(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2401,15 +2401,16 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fsqrtq(); - gen_helper_check_ieee_exceptions(); + gen_helper_fsqrtq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0x41: /* fadds */ gen_clear_float_exceptions(); - gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fadds(cpu_tmp32, cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2417,8 +2418,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_faddd(); - gen_helper_check_ieee_exceptions(); + gen_helper_faddd(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2427,15 +2428,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_faddq(); - gen_helper_check_ieee_exceptions(); + gen_helper_faddq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0x45: /* fsubs */ gen_clear_float_exceptions(); - gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fsubs(cpu_tmp32, cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2443,8 +2445,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fsubd(); - gen_helper_check_ieee_exceptions(); + gen_helper_fsubd(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2453,16 +2455,17 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fsubq(); - gen_helper_check_ieee_exceptions(); + gen_helper_fsubq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0x49: /* fmuls */ CHECK_FPU_FEATURE(dc, FMUL); gen_clear_float_exceptions(); - gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fmuls(cpu_tmp32, cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2471,8 +2474,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fmuld(); - gen_helper_check_ieee_exceptions(); + gen_helper_fmuld(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2482,15 +2485,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fmulq(); - gen_helper_check_ieee_exceptions(); + gen_helper_fmulq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0x4d: /* fdivs */ gen_clear_float_exceptions(); - gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fdivs(cpu_tmp32, cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2498,8 +2502,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fdivd(); - gen_helper_check_ieee_exceptions(); + gen_helper_fdivd(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2508,16 +2512,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fdivq(); - gen_helper_check_ieee_exceptions(); + gen_helper_fdivq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0x69: /* fsmuld */ CHECK_FPU_FEATURE(dc, FSMULD); gen_clear_float_exceptions(); - gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fsmuld(cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2526,23 +2530,23 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fdmulq(); - gen_helper_check_ieee_exceptions(); + gen_helper_fdmulq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0xc4: /* fitos */ gen_clear_float_exceptions(); - gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fitos(cpu_tmp32, cpu_env, cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; case 0xc6: /* fdtos */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fdtos(cpu_tmp32); - gen_helper_check_ieee_exceptions(); + gen_helper_fdtos(cpu_tmp32, cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2550,18 +2554,18 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fqtos(cpu_tmp32); - gen_helper_check_ieee_exceptions(); + gen_helper_fqtos(cpu_tmp32, cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; case 0xc8: /* fitod */ - gen_helper_fitod(cpu_fpr[rs2]); + gen_helper_fitod(cpu_env, cpu_fpr[rs2]); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0xc9: /* fstod */ - gen_helper_fstod(cpu_fpr[rs2]); + gen_helper_fstod(cpu_env, cpu_fpr[rs2]); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2569,42 +2573,42 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fqtod(); - gen_helper_check_ieee_exceptions(); + gen_helper_fqtod(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0xcc: /* fitoq */ CHECK_FPU_FEATURE(dc, FLOAT128); - gen_helper_fitoq(cpu_fpr[rs2]); + gen_helper_fitoq(cpu_env, cpu_fpr[rs2]); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0xcd: /* fstoq */ CHECK_FPU_FEATURE(dc, FLOAT128); - gen_helper_fstoq(cpu_fpr[rs2]); + gen_helper_fstoq(cpu_env, cpu_fpr[rs2]); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0xce: /* fdtoq */ CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fdtoq(); + gen_helper_fdtoq(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0xd1: /* fstoi */ gen_clear_float_exceptions(); - gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fstoi(cpu_tmp32, cpu_env, cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; case 0xd2: /* fdtoi */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fdtoi(cpu_tmp32); - gen_helper_check_ieee_exceptions(); + gen_helper_fdtoi(cpu_tmp32, cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2612,8 +2616,8 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fqtoi(cpu_tmp32); - gen_helper_check_ieee_exceptions(); + gen_helper_fqtoi(cpu_tmp32, cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; @@ -2637,42 +2641,42 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x6: /* V9 fnegd */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fnegd(); + gen_helper_fnegd(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x7: /* V9 fnegq */ CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_helper_fnegq(); + gen_helper_fnegq(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0xa: /* V9 fabsd */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fabsd(); + gen_helper_fabsd(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0xb: /* V9 fabsq */ CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_helper_fabsq(); + gen_helper_fabsq(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; case 0x81: /* V9 fstox */ gen_clear_float_exceptions(); - gen_helper_fstox(cpu_fpr[rs2]); - gen_helper_check_ieee_exceptions(); + gen_helper_fstox(cpu_env, cpu_fpr[rs2]); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x82: /* V9 fdtox */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fdtox(); - gen_helper_check_ieee_exceptions(); + gen_helper_fdtox(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2680,24 +2684,24 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fqtox(); - gen_helper_check_ieee_exceptions(); + gen_helper_fqtox(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x84: /* V9 fxtos */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fxtos(cpu_tmp32); - gen_helper_check_ieee_exceptions(); + gen_helper_fxtos(cpu_tmp32, cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); gen_update_fprs_dirty(rd); break; case 0x88: /* V9 fxtod */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fxtod(); - gen_helper_check_ieee_exceptions(); + gen_helper_fxtod(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -2705,8 +2709,8 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_clear_float_exceptions(); - gen_helper_fxtoq(); - gen_helper_check_ieee_exceptions(); + gen_helper_fxtoq(cpu_env); + gen_helper_check_ieee_exceptions(cpu_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); break; @@ -3267,19 +3271,23 @@ static void disas_sparc_insn(DisasContext * dc) case 0xe: /* udiv */ CHECK_IU_FEATURE(dc, DIV); if (xop & 0x10) { - gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2); + gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1, + cpu_src2); dc->cc_op = CC_OP_DIV; } else { - gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2); + gen_helper_udiv(cpu_dst, cpu_env, cpu_src1, + cpu_src2); } break; case 0xf: /* sdiv */ CHECK_IU_FEATURE(dc, DIV); if (xop & 0x10) { - gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2); + gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1, + cpu_src2); dc->cc_op = CC_OP_DIV; } else { - gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2); + gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1, + cpu_src2); } break; default: @@ -3317,7 +3325,7 @@ static void disas_sparc_insn(DisasContext * dc) dc->cc_op = CC_OP_TSUBTV; break; case 0x24: /* mulscc */ - gen_helper_compute_psr(); + gen_helper_compute_psr(cpu_env); gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); @@ -3375,7 +3383,7 @@ static void disas_sparc_insn(DisasContext * dc) #else case 0x2: /* V9 wrccr */ tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - gen_helper_wrccr(cpu_dst); + gen_helper_wrccr(cpu_env, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; break; @@ -3408,19 +3416,19 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto illegal_insn; tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); - gen_helper_set_softint(cpu_tmp64); + gen_helper_set_softint(cpu_env, cpu_tmp64); break; case 0x15: /* Softint clear */ if (!supervisor(dc)) goto illegal_insn; tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); - gen_helper_clear_softint(cpu_tmp64); + gen_helper_clear_softint(cpu_env, cpu_tmp64); break; case 0x16: /* Softint write */ if (!supervisor(dc)) goto illegal_insn; tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); - gen_helper_write_softint(cpu_tmp64); + gen_helper_write_softint(cpu_env, cpu_tmp64); break; case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) @@ -3495,10 +3503,10 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef TARGET_SPARC64 switch (rd) { case 0: - gen_helper_saved(); + gen_helper_saved(cpu_env); break; case 1: - gen_helper_restored(); + gen_helper_restored(cpu_env); break; case 2: /* UA2005 allclean */ case 3: /* UA2005 otherw */ @@ -3510,7 +3518,7 @@ static void disas_sparc_insn(DisasContext * dc) } #else tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - gen_helper_wrpsr(cpu_dst); + gen_helper_wrpsr(cpu_env, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; save_state(dc, cpu_cond); @@ -3594,7 +3602,7 @@ static void disas_sparc_insn(DisasContext * dc) tcg_gen_mov_tl(r_tmp, cpu_tmp0); save_state(dc, cpu_cond); - gen_helper_wrpstate(r_tmp); + gen_helper_wrpstate(cpu_env, r_tmp); tcg_temp_free(r_tmp); dc->npc = DYNAMIC_PC; } @@ -3613,10 +3621,10 @@ static void disas_sparc_insn(DisasContext * dc) } break; case 8: // pil - gen_helper_wrpil(cpu_tmp0); + gen_helper_wrpil(cpu_env, cpu_tmp0); break; case 9: // cwp - gen_helper_wrcwp(cpu_tmp0); + gen_helper_wrcwp(cpu_env, cpu_tmp0); break; case 10: // cansave tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); @@ -3828,14 +3836,14 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); gen_movl_reg_TN(rs2, cpu_src2); - gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); + gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); break; case 0x012: /* VIS I array16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); gen_movl_reg_TN(rs2, cpu_src2); - gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); + gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2); tcg_gen_shli_i64(cpu_dst, cpu_dst, 1); gen_movl_TN_reg(rd, cpu_dst); break; @@ -3843,7 +3851,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); gen_movl_reg_TN(rs2, cpu_src2); - gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); + gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2); tcg_gen_shli_i64(cpu_dst, cpu_dst, 2); gen_movl_TN_reg(rd, cpu_dst); break; @@ -3851,7 +3859,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); gen_movl_reg_TN(rs2, cpu_src2); - gen_helper_alignaddr(cpu_dst, cpu_src1, cpu_src2); + gen_helper_alignaddr(cpu_dst, cpu_env, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); break; case 0x019: /* VIS II bmask */ @@ -3862,63 +3870,63 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmple16(cpu_dst); + gen_helper_fcmple16(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x022: /* VIS I fcmpne16 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmpne16(cpu_dst); + gen_helper_fcmpne16(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x024: /* VIS I fcmple32 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmple32(cpu_dst); + gen_helper_fcmple32(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x026: /* VIS I fcmpne32 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmpne32(cpu_dst); + gen_helper_fcmpne32(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x028: /* VIS I fcmpgt16 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmpgt16(cpu_dst); + gen_helper_fcmpgt16(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x02a: /* VIS I fcmpeq16 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmpeq16(cpu_dst); + gen_helper_fcmpeq16(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x02c: /* VIS I fcmpgt32 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmpgt32(cpu_dst); + gen_helper_fcmpgt32(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x02e: /* VIS I fcmpeq32 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fcmpeq32(cpu_dst); + gen_helper_fcmpeq32(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x031: /* VIS I fmul8x16 */ CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmul8x16(); + gen_helper_fmul8x16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3926,7 +3934,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmul8x16au(); + gen_helper_fmul8x16au(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3934,7 +3942,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmul8x16al(); + gen_helper_fmul8x16al(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3942,7 +3950,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmul8sux16(); + gen_helper_fmul8sux16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3950,7 +3958,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmul8ulx16(); + gen_helper_fmul8ulx16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3958,7 +3966,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmuld8sux16(); + gen_helper_fmuld8sux16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3966,7 +3974,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fmuld8ulx16(); + gen_helper_fmuld8ulx16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3980,7 +3988,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_faligndata(); + gen_helper_faligndata(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3988,7 +3996,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fpmerge(); + gen_helper_fpmerge(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -3999,7 +4007,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fexpand(); + gen_helper_fexpand(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; @@ -4007,13 +4015,13 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fpadd16(); + gen_helper_fpadd16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x051: /* VIS I fpadd16s */ CHECK_FPU_FEATURE(dc, VIS1); - gen_helper_fpadd16s(cpu_fpr[rd], + gen_helper_fpadd16s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); gen_update_fprs_dirty(rd); break; @@ -4021,13 +4029,13 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fpadd32(); + gen_helper_fpadd32(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x053: /* VIS I fpadd32s */ CHECK_FPU_FEATURE(dc, VIS1); - gen_helper_fpadd32s(cpu_fpr[rd], + gen_helper_fpadd32s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); gen_update_fprs_dirty(rd); break; @@ -4035,13 +4043,13 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fpsub16(); + gen_helper_fpsub16(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x055: /* VIS I fpsub16s */ CHECK_FPU_FEATURE(dc, VIS1); - gen_helper_fpsub16s(cpu_fpr[rd], + gen_helper_fpsub16s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); gen_update_fprs_dirty(rd); break; @@ -4049,13 +4057,13 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_helper_fpsub32(); + gen_helper_fpsub32(cpu_env); gen_op_store_DT0_fpr(DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); break; case 0x057: /* VIS I fpsub32s */ CHECK_FPU_FEATURE(dc, VIS1); - gen_helper_fpsub32s(cpu_fpr[rd], + gen_helper_fpsub32s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); gen_update_fprs_dirty(rd); break; @@ -4303,7 +4311,7 @@ static void disas_sparc_insn(DisasContext * dc) } else tcg_gen_mov_tl(cpu_dst, cpu_src1); } - gen_helper_restore(); + gen_helper_restore(cpu_env); gen_mov_pc_npc(dc, cpu_cond); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_dst, r_const); @@ -4355,7 +4363,7 @@ static void disas_sparc_insn(DisasContext * dc) tcg_temp_free_i32(r_const); tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; - gen_helper_rett(); + gen_helper_rett(cpu_env); } goto jmp_insn; #endif @@ -4366,12 +4374,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x3c: /* save */ save_state(dc, cpu_cond); - gen_helper_save(); + gen_helper_save(cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x3d: /* restore */ save_state(dc, cpu_cond); - gen_helper_restore(); + gen_helper_restore(cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) @@ -4383,14 +4391,14 @@ static void disas_sparc_insn(DisasContext * dc) goto priv_insn; dc->npc = DYNAMIC_PC; dc->pc = DYNAMIC_PC; - gen_helper_done(); + gen_helper_done(cpu_env); goto jmp_insn; case 1: if (!supervisor(dc)) goto priv_insn; dc->npc = DYNAMIC_PC; dc->pc = DYNAMIC_PC; - gen_helper_retry(); + gen_helper_retry(cpu_env); goto jmp_insn; default: goto illegal_insn; @@ -4413,7 +4421,7 @@ static void disas_sparc_insn(DisasContext * dc) cpu state */ if (dc->cc_op != CC_OP_FLAGS) { dc->cc_op = CC_OP_FLAGS; - gen_helper_compute_psr(); + gen_helper_compute_psr(cpu_env); } cpu_src1 = get_src1(insn, cpu_src1); if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa @@ -4659,16 +4667,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_address_mask(dc, cpu_addr); if (rd == 1) { tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); - gen_helper_ldxfsr(cpu_tmp64); + gen_helper_ldxfsr(cpu_env, cpu_tmp64); } else { tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - gen_helper_ldfsr(cpu_tmp32); + gen_helper_ldfsr(cpu_env, cpu_tmp32); } #else { tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx); - gen_helper_ldfsr(cpu_tmp32); + gen_helper_ldfsr(cpu_env, cpu_tmp32); } #endif break; @@ -4931,7 +4939,7 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc, cpu_cond); r_const = tcg_const_i32(TT_ILL_INSN); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); dc->is_br = 1; } @@ -4942,7 +4950,7 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc, cpu_cond); r_const = tcg_const_i32(TT_UNIMP_FLUSH); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); dc->is_br = 1; } @@ -4954,7 +4962,7 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc, cpu_cond); r_const = tcg_const_i32(TT_PRIV_INSN); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); dc->is_br = 1; } @@ -4979,7 +4987,7 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc, cpu_cond); r_const = tcg_const_i32(TT_NCP_INSN); - gen_helper_raise_exception(r_const); + gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free(r_const); dc->is_br = 1; } @@ -5036,7 +5044,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, if (bp->pc == dc->pc) { if (dc->pc != pc_start) save_state(dc, cpu_cond); - gen_helper_debug(); + gen_helper_debug(cpu_env); tcg_gen_exit_tb(0); dc->is_br = 1; goto exit_gen_loop; @@ -5265,6 +5273,6 @@ void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) /* flush pending conditional evaluations before exposing cpu state */ if (CC_OP != CC_OP_FLAGS) { - helper_compute_psr(); + helper_compute_psr(env); } } diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c new file mode 100644 index 0000000000..a22c10bb43 --- /dev/null +++ b/target-sparc/vis_helper.c @@ -0,0 +1,406 @@ +/* + * VIS op helpers + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "helper.h" + +#define DT0 (env->dt0) +#define DT1 (env->dt1) +#define QT0 (env->qt0) +#define QT1 (env->qt1) + +/* This function uses non-native bit order */ +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1)) + +/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */ +#define GET_FIELD_SP(X, FROM, TO) \ + GET_FIELD(X, 63 - (TO), 63 - (FROM)) + +target_ulong helper_array8(CPUState *env, target_ulong pixel_addr, + target_ulong cubesize) +{ + return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) | + (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) | + (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) | + (GET_FIELD_SP(pixel_addr, 56, 59) << 13) | + (GET_FIELD_SP(pixel_addr, 35, 38) << 9) | + (GET_FIELD_SP(pixel_addr, 13, 16) << 5) | + (((pixel_addr >> 55) & 1) << 4) | + (GET_FIELD_SP(pixel_addr, 33, 34) << 2) | + GET_FIELD_SP(pixel_addr, 11, 12); +} + +target_ulong helper_alignaddr(CPUState *env, target_ulong addr, + target_ulong offset) +{ + uint64_t tmp; + + tmp = addr + offset; + env->gsr &= ~7ULL; + env->gsr |= tmp & 7ULL; + return tmp & ~7ULL; +} + +void helper_faligndata(CPUState *env) +{ + uint64_t tmp; + + tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); + /* on many architectures a shift of 64 does nothing */ + if ((env->gsr & 7) != 0) { + tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); + } + *((uint64_t *)&DT0) = tmp; +} + +#ifdef HOST_WORDS_BIGENDIAN +#define VIS_B64(n) b[7 - (n)] +#define VIS_W64(n) w[3 - (n)] +#define VIS_SW64(n) sw[3 - (n)] +#define VIS_L64(n) l[1 - (n)] +#define VIS_B32(n) b[3 - (n)] +#define VIS_W32(n) w[1 - (n)] +#else +#define VIS_B64(n) b[n] +#define VIS_W64(n) w[n] +#define VIS_SW64(n) sw[n] +#define VIS_L64(n) l[n] +#define VIS_B32(n) b[n] +#define VIS_W32(n) w[n] +#endif + +typedef union { + uint8_t b[8]; + uint16_t w[4]; + int16_t sw[4]; + uint32_t l[2]; + uint64_t ll; + float64 d; +} VIS64; + +typedef union { + uint8_t b[4]; + uint16_t w[2]; + uint32_t l; + float32 f; +} VIS32; + +void helper_fpmerge(CPUState *env) +{ + VIS64 s, d; + + s.d = DT0; + d.d = DT1; + + /* Reverse calculation order to handle overlap */ + d.VIS_B64(7) = s.VIS_B64(3); + d.VIS_B64(6) = d.VIS_B64(3); + d.VIS_B64(5) = s.VIS_B64(2); + d.VIS_B64(4) = d.VIS_B64(2); + d.VIS_B64(3) = s.VIS_B64(1); + d.VIS_B64(2) = d.VIS_B64(1); + d.VIS_B64(1) = s.VIS_B64(0); + /* d.VIS_B64(0) = d.VIS_B64(0); */ + + DT0 = d.d; +} + +void helper_fmul8x16(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8x16al(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8x16au(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8sux16(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8ulx16(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmuld8sux16(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_L64(r) = tmp; + + /* Reverse calculation order to handle overlap */ + PMUL(1); + PMUL(0); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmuld8ulx16(CPUState *env) +{ + VIS64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ + if ((tmp & 0xff) > 0x7f) { \ + tmp += 0x100; \ + } \ + d.VIS_L64(r) = tmp; + + /* Reverse calculation order to handle overlap */ + PMUL(1); + PMUL(0); +#undef PMUL + + DT0 = d.d; +} + +void helper_fexpand(CPUState *env) +{ + VIS32 s; + VIS64 d; + + s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); + d.d = DT1; + d.VIS_W64(0) = s.VIS_B32(0) << 4; + d.VIS_W64(1) = s.VIS_B32(1) << 4; + d.VIS_W64(2) = s.VIS_B32(2) << 4; + d.VIS_W64(3) = s.VIS_B32(3) << 4; + + DT0 = d.d; +} + +#define VIS_HELPER(name, F) \ + void name##16(CPUState *env) \ + { \ + VIS64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \ + d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \ + d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \ + d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \ + \ + DT0 = d.d; \ + } \ + \ + uint32_t name##16s(CPUState *env, uint32_t src1, \ + uint32_t src2) \ + { \ + VIS32 s, d; \ + \ + s.l = src1; \ + d.l = src2; \ + \ + d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ + d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ + \ + return d.l; \ + } \ + \ + void name##32(CPUState *env) \ + { \ + VIS64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \ + d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \ + \ + DT0 = d.d; \ + } \ + \ + uint32_t name##32s(CPUState *env, uint32_t src1, \ + uint32_t src2) \ + { \ + VIS32 s, d; \ + \ + s.l = src1; \ + d.l = src2; \ + \ + d.l = F(d.l, s.l); \ + \ + return d.l; \ + } + +#define FADD(a, b) ((a) + (b)) +#define FSUB(a, b) ((a) - (b)) +VIS_HELPER(helper_fpadd, FADD) +VIS_HELPER(helper_fpsub, FSUB) + +#define VIS_CMPHELPER(name, F) \ + uint64_t name##16(CPUState *env) \ + { \ + VIS64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \ + d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \ + d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \ + d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \ + d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \ + \ + return d.ll; \ + } \ + \ + uint64_t name##32(CPUState *env) \ + { \ + VIS64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \ + d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \ + d.VIS_L64(1) = 0; \ + \ + return d.ll; \ + } + +#define FCMPGT(a, b) ((a) > (b)) +#define FCMPEQ(a, b) ((a) == (b)) +#define FCMPLE(a, b) ((a) <= (b)) +#define FCMPNE(a, b) ((a) != (b)) + +VIS_CMPHELPER(helper_fcmpgt, FCMPGT) +VIS_CMPHELPER(helper_fcmpeq, FCMPEQ) +VIS_CMPHELPER(helper_fcmple, FCMPLE) +VIS_CMPHELPER(helper_fcmpne, FCMPNE) diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c new file mode 100644 index 0000000000..a68c649e7e --- /dev/null +++ b/target-sparc/win_helper.c @@ -0,0 +1,393 @@ +/* + * Helpers for CWP and PSTATE handling + * + * Copyright (c) 2003-2005 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 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 "cpu.h" +#include "helper.h" +#include "trace.h" + +static inline void memcpy32(target_ulong *dst, const target_ulong *src) +{ + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} + +void cpu_set_cwp(CPUState *env, int new_cwp) +{ + /* put the modified wrap registers at their proper location */ + if (env->cwp == env->nwindows - 1) { + memcpy32(env->regbase, env->regbase + env->nwindows * 16); + } + env->cwp = new_cwp; + + /* put the wrap registers at their temporary location */ + if (new_cwp == env->nwindows - 1) { + memcpy32(env->regbase + env->nwindows * 16, env->regbase); + } + env->regwptr = env->regbase + (new_cwp * 16); +} + +target_ulong cpu_get_psr(CPUState *env) +{ + helper_compute_psr(env); + +#if !defined(TARGET_SPARC64) + return env->version | (env->psr & PSR_ICC) | + (env->psref ? PSR_EF : 0) | + (env->psrpil << 8) | + (env->psrs ? PSR_S : 0) | + (env->psrps ? PSR_PS : 0) | + (env->psret ? PSR_ET : 0) | env->cwp; +#else + return env->psr & PSR_ICC; +#endif +} + +void cpu_put_psr(CPUState *env, target_ulong val) +{ + env->psr = val & PSR_ICC; +#if !defined(TARGET_SPARC64) + env->psref = (val & PSR_EF) ? 1 : 0; + env->psrpil = (val & PSR_PIL) >> 8; +#endif +#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) + cpu_check_irqs(env); +#endif +#if !defined(TARGET_SPARC64) + env->psrs = (val & PSR_S) ? 1 : 0; + env->psrps = (val & PSR_PS) ? 1 : 0; + env->psret = (val & PSR_ET) ? 1 : 0; + cpu_set_cwp(env, val & PSR_CWP); +#endif + env->cc_op = CC_OP_FLAGS; +} + +int cpu_cwp_inc(CPUState *env, int cwp) +{ + if (unlikely(cwp >= env->nwindows)) { + cwp -= env->nwindows; + } + return cwp; +} + +int cpu_cwp_dec(CPUState *env, int cwp) +{ + if (unlikely(cwp < 0)) { + cwp += env->nwindows; + } + return cwp; +} + +#ifndef TARGET_SPARC64 +void helper_rett(CPUState *env) +{ + unsigned int cwp; + + if (env->psret == 1) { + helper_raise_exception(env, TT_ILL_INSN); + } + + env->psret = 1; + cwp = cpu_cwp_inc(env, env->cwp + 1) ; + if (env->wim & (1 << cwp)) { + helper_raise_exception(env, TT_WIN_UNF); + } + cpu_set_cwp(env, cwp); + env->psrs = env->psrps; +} + +/* XXX: use another pointer for %iN registers to avoid slow wrapping + handling ? */ +void helper_save(CPUState *env) +{ + uint32_t cwp; + + cwp = cpu_cwp_dec(env, env->cwp - 1); + if (env->wim & (1 << cwp)) { + helper_raise_exception(env, TT_WIN_OVF); + } + cpu_set_cwp(env, cwp); +} + +void helper_restore(CPUState *env) +{ + uint32_t cwp; + + cwp = cpu_cwp_inc(env, env->cwp + 1); + if (env->wim & (1 << cwp)) { + helper_raise_exception(env, TT_WIN_UNF); + } + cpu_set_cwp(env, cwp); +} + +void helper_wrpsr(CPUState *env, target_ulong new_psr) +{ + if ((new_psr & PSR_CWP) >= env->nwindows) { + helper_raise_exception(env, TT_ILL_INSN); + } else { + cpu_put_psr(env, new_psr); + } +} + +target_ulong helper_rdpsr(CPUState *env) +{ + return cpu_get_psr(env); +} + +#else +/* XXX: use another pointer for %iN registers to avoid slow wrapping + handling ? */ +void helper_save(CPUState *env) +{ + uint32_t cwp; + + cwp = cpu_cwp_dec(env, env->cwp - 1); + if (env->cansave == 0) { + helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? + (TT_WOTHER | + ((env->wstate & 0x38) >> 1)) : + ((env->wstate & 0x7) << 2))); + } else { + if (env->cleanwin - env->canrestore == 0) { + /* XXX Clean windows without trap */ + helper_raise_exception(env, TT_CLRWIN); + } else { + env->cansave--; + env->canrestore++; + cpu_set_cwp(env, cwp); + } + } +} + +void helper_restore(CPUState *env) +{ + uint32_t cwp; + + cwp = cpu_cwp_inc(env, env->cwp + 1); + if (env->canrestore == 0) { + helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ? + (TT_WOTHER | + ((env->wstate & 0x38) >> 1)) : + ((env->wstate & 0x7) << 2))); + } else { + env->cansave++; + env->canrestore--; + cpu_set_cwp(env, cwp); + } +} + +void helper_flushw(CPUState *env) +{ + if (env->cansave != env->nwindows - 2) { + helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? + (TT_WOTHER | + ((env->wstate & 0x38) >> 1)) : + ((env->wstate & 0x7) << 2))); + } +} + +void helper_saved(CPUState *env) +{ + env->cansave++; + if (env->otherwin == 0) { + env->canrestore--; + } else { + env->otherwin--; + } +} + +void helper_restored(CPUState *env) +{ + env->canrestore++; + if (env->cleanwin < env->nwindows - 1) { + env->cleanwin++; + } + if (env->otherwin == 0) { + env->cansave--; + } else { + env->otherwin--; + } +} + +target_ulong cpu_get_ccr(CPUState *env) +{ + target_ulong psr; + + psr = cpu_get_psr(env); + + return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20); +} + +void cpu_put_ccr(CPUState *env, target_ulong val) +{ + env->xcc = (val >> 4) << 20; + env->psr = (val & 0xf) << 20; + CC_OP = CC_OP_FLAGS; +} + +target_ulong cpu_get_cwp64(CPUState *env) +{ + return env->nwindows - 1 - env->cwp; +} + +void cpu_put_cwp64(CPUState *env, int cwp) +{ + if (unlikely(cwp >= env->nwindows || cwp < 0)) { + cwp %= env->nwindows; + } + cpu_set_cwp(env, env->nwindows - 1 - cwp); +} + +target_ulong helper_rdccr(CPUState *env) +{ + return cpu_get_ccr(env); +} + +void helper_wrccr(CPUState *env, target_ulong new_ccr) +{ + cpu_put_ccr(env, new_ccr); +} + +/* CWP handling is reversed in V9, but we still use the V8 register + order. */ +target_ulong helper_rdcwp(CPUState *env) +{ + return cpu_get_cwp64(env); +} + +void helper_wrcwp(CPUState *env, target_ulong new_cwp) +{ + cpu_put_cwp64(env, new_cwp); +} + +static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate) +{ + switch (pstate) { + default: + trace_win_helper_gregset_error(pstate); + /* pass through to normal set of global registers */ + case 0: + return env->bgregs; + case PS_AG: + return env->agregs; + case PS_MG: + return env->mgregs; + case PS_IG: + return env->igregs; + } +} + +void cpu_change_pstate(CPUState *env, uint32_t new_pstate) +{ + uint32_t pstate_regs, new_pstate_regs; + uint64_t *src, *dst; + + if (env->def->features & CPU_FEATURE_GL) { + /* PS_AG is not implemented in this case */ + new_pstate &= ~PS_AG; + } + + pstate_regs = env->pstate & 0xc01; + new_pstate_regs = new_pstate & 0xc01; + + if (new_pstate_regs != pstate_regs) { + trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs); + + /* Switch global register bank */ + src = get_gregset(env, new_pstate_regs); + dst = get_gregset(env, pstate_regs); + memcpy32(dst, env->gregs); + memcpy32(env->gregs, src); + } else { + trace_win_helper_no_switch_pstate(new_pstate_regs); + } + env->pstate = new_pstate; +} + +void helper_wrpstate(CPUState *env, target_ulong new_state) +{ + cpu_change_pstate(env, new_state & 0xf3f); + +#if !defined(CONFIG_USER_ONLY) + if (cpu_interrupts_enabled(env)) { + cpu_check_irqs(env); + } +#endif +} + +void helper_wrpil(CPUState *env, target_ulong new_pil) +{ +#if !defined(CONFIG_USER_ONLY) + trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil); + + env->psrpil = new_pil; + + if (cpu_interrupts_enabled(env)) { + cpu_check_irqs(env); + } +#endif +} + +void helper_done(CPUState *env) +{ + trap_state *tsptr = cpu_tsptr(env); + + env->pc = tsptr->tnpc; + env->npc = tsptr->tnpc + 4; + cpu_put_ccr(env, tsptr->tstate >> 32); + env->asi = (tsptr->tstate >> 24) & 0xff; + cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); + cpu_put_cwp64(env, tsptr->tstate & 0xff); + env->tl--; + + trace_win_helper_done(env->tl); + +#if !defined(CONFIG_USER_ONLY) + if (cpu_interrupts_enabled(env)) { + cpu_check_irqs(env); + } +#endif +} + +void helper_retry(CPUState *env) +{ + trap_state *tsptr = cpu_tsptr(env); + + env->pc = tsptr->tpc; + env->npc = tsptr->tnpc; + cpu_put_ccr(env, tsptr->tstate >> 32); + env->asi = (tsptr->tstate >> 24) & 0xff; + cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); + cpu_put_cwp64(env, tsptr->tstate & 0xff); + env->tl--; + + trace_win_helper_retry(env->tl); + +#if !defined(CONFIG_USER_ONLY) + if (cpu_interrupts_enabled(env)) { + cpu_check_irqs(env); + } +#endif +} +#endif diff --git a/trace-events b/trace-events index a06c6c5282..820b1d6ee6 100644 --- a/trace-events +++ b/trace-events @@ -61,6 +61,7 @@ multiwrite_cb(void *mcb, int ret) "mcb %p ret %d" bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d" bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p" bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d" +bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p" bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" @@ -552,3 +553,74 @@ open_eth_reg_read(uint32_t addr, uint32_t v) "MAC[%02x] -> %08x" open_eth_reg_write(uint32_t addr, uint32_t v) "MAC[%02x] <- %08x" open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x" open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x" + +# hw/9pfs/virtio-9p.c +complete_pdu(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d" +v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s" +v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s" +v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s" +v9fs_attach_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d type %d version %d path %"PRId64"" +v9fs_stat(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" +v9fs_stat_return(uint16_t tag, uint8_t id, int32_t mode, int32_t atime, int32_t mtime, int64_t length) "tag %d id %d stat={mode %d atime %d mtime %d length %"PRId64"}" +v9fs_getattr(uint16_t tag, uint8_t id, int32_t fid, uint64_t request_mask) "tag %d id %d fid %d request_mask %"PRIu64"" +v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mode, uint32_t uid, uint32_t gid) "tag %d id %d getattr={result_mask %"PRId64" mode %u uid %u gid %u}" +v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames) "tag %d id %d fid %d newfid %d nwnames %d" +v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p" +v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode) "tag %d id %d fid %d mode %d" +v9fs_open_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" +v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u" +v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" +v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d" +v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" +v9fs_read(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t max_count) "tag %d id %d fid %d off %"PRId64" max_count %d" +v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd" +v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, int64_t offset, int32_t max_count) "tag %d id %d fid %d offset %"PRId64" max_count %d" +v9fs_readdir_return(uint16_t tag, uint8_t id, int32_t count, ssize_t retval) "tag %d id %d count %d retval %zd" +v9fs_write(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t count, int cnt) "tag %d id %d fid %d off %"PRId64" count %d cnt %d" +v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd" +v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d" +v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" +v9fs_symlink(uint16_t tag, uint8_t id, int32_t fid, char* name, char* symname, uint32_t gid) "tag %d id %d fid %d name %s symname %s gid %u" +v9fs_symlink_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}" +v9fs_flush(uint16_t tag, uint8_t id, int16_t flush_tag) "tag %d id %d flush_tag %d" +v9fs_link(uint16_t tag, uint8_t id, int32_t dfid, int32_t oldfid, char* name) "tag %d id %d dfid %d oldfid %d name %s" +v9fs_remove(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" +v9fs_wstat(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, int32_t atime, int32_t mtime) "tag %u id %u fid %d stat={mode %d atime %d mtime %d}" +v9fs_mknod(uint16_t tag, uint8_t id, int32_t fid, int mode, int major, int minor) "tag %d id %d fid %d mode %d major %d minor %d" +v9fs_mknod_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}" +v9fs_lock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length) "tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64"" +v9fs_lock_return(uint16_t tag, uint8_t id, int8_t status) "tag %d id %d status %d" +v9fs_getlock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length)"tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64"" +v9fs_getlock_return(uint16_t tag, uint8_t id, uint8_t type, uint64_t start, uint64_t length, uint32_t proc_id) "tag %d id %d type %d start %"PRIu64" length %"PRIu64" proc_id %u" +v9fs_mkdir(uint16_t tag, uint8_t id, int32_t fid, char* name, int mode, uint32_t gid) "tag %u id %u fid %d name %s mode %d gid %u" +v9fs_mkdir_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int err) "tag %u id %u qid={type %d version %d path %"PRId64"} err %d" +v9fs_xattrwalk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, char* name) "tag %d id %d fid %d newfid %d name %s" +v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size %"PRId64"" +v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, int64_t size, int flags) "tag %d id %d fid %d name %s size %"PRId64" flags %d" +v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" +v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s" + +# target-sparc/mmu_helper.c +mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d" +mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d" +mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at %"PRIx64" context %"PRIx64"" +mmu_helper_tfault(uint64_t address, uint64_t context) "TFAULT at %"PRIx64" context %"PRIx64"" +mmu_helper_tmiss(uint64_t address, uint64_t context) "TMISS at %"PRIx64" context %"PRIx64"" +mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64"" +mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64"" +mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64"" + +# target-sparc/int_helper.c +int_helper_set_softint(uint32_t softint) "new %08x" +int_helper_clear_softint(uint32_t softint) "new %08x" +int_helper_write_softint(uint32_t softint) "new %08x" +int_helper_icache_freeze(void) "Instruction cache: freeze" +int_helper_dcache_freeze(void) "Data cache: freeze" + +# target-sparc/win_helper.c +win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=%x" +win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=%x new=%x" +win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=%x (unchanged)" +win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x" +win_helper_done(uint32_t tl) "tl=%d" +win_helper_retry(uint32_t tl) "tl=%d" diff --git a/ui/spice-core.c b/ui/spice-core.c index 3cbc721ee4..b33366e5d7 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -447,9 +447,9 @@ void do_info_spice(Monitor *mon, QObject **ret_data) static void migration_state_notifier(Notifier *notifier, void *data) { - int state = get_migration_state(); + MigrationState *s = data; - if (state == MIG_STATE_COMPLETED) { + if (migration_has_finished(s)) { #if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */ spice_server_migrate_switch(spice_server); #endif @@ -148,6 +148,7 @@ int main(int argc, char **argv) #include "qemu-objects.h" #include "qemu-options.h" #include "qmp-commands.h" +#include "main-loop.h" #ifdef CONFIG_VIRTFS #include "fsdev/qemu-fsdev.h" #endif @@ -337,16 +338,20 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, + { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING }, + { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_PAUSED, RUN_STATE_RUNNING }, + { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING }, + { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE }, - { RUN_STATE_PRELAUNCH, RUN_STATE_POSTMIGRATE }, { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING }, { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE }, @@ -366,8 +371,10 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING }, { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED }, + { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING }, + { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE }, { RUN_STATE_MAX, RUN_STATE_MAX }, }; @@ -393,9 +400,12 @@ void runstate_init(void) /* This function will abort() on invalid state transitions */ void runstate_set(RunState new_state) { - if (new_state >= RUN_STATE_MAX || - !runstate_valid_transitions[current_run_state][new_state]) { - fprintf(stderr, "invalid runstate transition\n"); + assert(new_state < RUN_STATE_MAX); + + if (!runstate_valid_transitions[current_run_state][new_state]) { + fprintf(stderr, "ERROR: invalid runstate transition: '%s' -> '%s'\n", + RunState_lookup[current_run_state], + RunState_lookup[new_state]); abort(); } @@ -1416,142 +1426,51 @@ void qemu_system_vmstop_request(RunState state) qemu_notify_event(); } -static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ -static int n_poll_fds; -static int max_priority; +qemu_irq qemu_system_powerdown; -static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds, - fd_set *xfds, struct timeval *tv) +static bool main_loop_should_exit(void) { - GMainContext *context = g_main_context_default(); - int i; - int timeout = 0, cur_timeout; - - g_main_context_prepare(context, &max_priority); - - n_poll_fds = g_main_context_query(context, max_priority, &timeout, - poll_fds, ARRAY_SIZE(poll_fds)); - g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds)); - - for (i = 0; i < n_poll_fds; i++) { - GPollFD *p = &poll_fds[i]; - - if ((p->events & G_IO_IN)) { - FD_SET(p->fd, rfds); - *max_fd = MAX(*max_fd, p->fd); - } - if ((p->events & G_IO_OUT)) { - FD_SET(p->fd, wfds); - *max_fd = MAX(*max_fd, p->fd); - } - if ((p->events & G_IO_ERR)) { - FD_SET(p->fd, xfds); - *max_fd = MAX(*max_fd, p->fd); + RunState r; + if (qemu_debug_requested()) { + vm_stop(RUN_STATE_DEBUG); + } + if (qemu_shutdown_requested()) { + qemu_kill_report(); + monitor_protocol_event(QEVENT_SHUTDOWN, NULL); + if (no_shutdown) { + vm_stop(RUN_STATE_SHUTDOWN); + } else { + return true; } } - - cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000); - if (timeout >= 0 && timeout < cur_timeout) { - tv->tv_sec = timeout / 1000; - tv->tv_usec = (timeout % 1000) * 1000; - } -} - -static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds, - bool err) -{ - GMainContext *context = g_main_context_default(); - - if (!err) { - int i; - - for (i = 0; i < n_poll_fds; i++) { - GPollFD *p = &poll_fds[i]; - - if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) { - p->revents |= G_IO_IN; - } - if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) { - p->revents |= G_IO_OUT; - } - if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) { - p->revents |= G_IO_ERR; - } + if (qemu_reset_requested()) { + pause_all_vcpus(); + cpu_synchronize_all_states(); + qemu_system_reset(VMRESET_REPORT); + resume_all_vcpus(); + if (runstate_check(RUN_STATE_INTERNAL_ERROR) || + runstate_check(RUN_STATE_SHUTDOWN)) { + runstate_set(RUN_STATE_PAUSED); } } - - if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) { - g_main_context_dispatch(context); + if (qemu_powerdown_requested()) { + monitor_protocol_event(QEVENT_POWERDOWN, NULL); + qemu_irq_raise(qemu_system_powerdown); } -} - -int main_loop_wait(int nonblocking) -{ - fd_set rfds, wfds, xfds; - int ret, nfds; - struct timeval tv; - int timeout; - - if (nonblocking) - timeout = 0; - else { - timeout = qemu_calculate_timeout(); - qemu_bh_update_timeout(&timeout); - } - - os_host_main_loop_wait(&timeout); - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - - /* poll any events */ - /* XXX: separate device handlers from system ones */ - nfds = -1; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - - qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds); - slirp_select_fill(&nfds, &rfds, &wfds, &xfds); - glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv); - - if (timeout > 0) { - qemu_mutex_unlock_iothread(); + if (qemu_vmstop_requested(&r)) { + vm_stop(r); } - - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); - - if (timeout > 0) { - qemu_mutex_lock_iothread(); - } - - qemu_iohandler_poll(&rfds, &wfds, &xfds, ret); - slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0)); - glib_select_poll(&rfds, &wfds, &xfds, (ret < 0)); - - qemu_run_all_timers(); - - /* Check bottom-halves last in case any of the earlier events triggered - them. */ - qemu_bh_poll(); - - return ret; + return false; } -qemu_irq qemu_system_powerdown; - static void main_loop(void) { bool nonblocking; - int last_io __attribute__ ((unused)) = 0; + int last_io = 0; #ifdef CONFIG_PROFILER int64_t ti; #endif - RunState r; - - qemu_main_loop_start(); - - for (;;) { + do { nonblocking = !kvm_enabled() && last_io > 0; #ifdef CONFIG_PROFILER ti = profile_getclock(); @@ -1560,38 +1479,7 @@ static void main_loop(void) #ifdef CONFIG_PROFILER dev_time += profile_getclock() - ti; #endif - - if (qemu_debug_requested()) { - vm_stop(RUN_STATE_DEBUG); - } - if (qemu_shutdown_requested()) { - qemu_kill_report(); - monitor_protocol_event(QEVENT_SHUTDOWN, NULL); - if (no_shutdown) { - vm_stop(RUN_STATE_SHUTDOWN); - } else - break; - } - if (qemu_reset_requested()) { - pause_all_vcpus(); - cpu_synchronize_all_states(); - qemu_system_reset(VMRESET_REPORT); - resume_all_vcpus(); - if (runstate_check(RUN_STATE_INTERNAL_ERROR) || - runstate_check(RUN_STATE_SHUTDOWN)) { - runstate_set(RUN_STATE_PAUSED); - } - } - if (qemu_powerdown_requested()) { - monitor_protocol_event(QEVENT_POWERDOWN, NULL); - qemu_irq_raise(qemu_system_powerdown); - } - if (qemu_vmstop_requested(&r)) { - vm_stop(r); - } - } - bdrv_close_all(); - pause_all_vcpus(); + } while (!main_loop_should_exit()); } static void version(void) @@ -2302,6 +2190,7 @@ int main(int argc, char **argv, char **envp) runstate_init(); init_clocks(); + rtc_clock = host_clock; qemu_cache_utils_init(envp); @@ -2774,6 +2663,7 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_virtfs: { QemuOpts *fsdev; QemuOpts *device; + const char *writeout; olist = qemu_find_opts("virtfs"); if (!olist) { @@ -2786,16 +2676,14 @@ int main(int argc, char **argv, char **envp) exit(1); } - if (qemu_opt_get(opts, "fstype") == NULL || + if (qemu_opt_get(opts, "fsdriver") == NULL || qemu_opt_get(opts, "mount_tag") == NULL || - qemu_opt_get(opts, "path") == NULL || - qemu_opt_get(opts, "security_model") == NULL) { - fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/," - "security_model=[mapped|passthrough|none]," + qemu_opt_get(opts, "path") == NULL) { + fprintf(stderr, "Usage: -virtfs fsdriver,path=/share_path/," + "[security_model={mapped|passthrough|none}]," "mount_tag=tag.\n"); exit(1); } - fsdev = qemu_opts_create(qemu_find_opts("fsdev"), qemu_opt_get(opts, "mount_tag"), 1); if (!fsdev) { @@ -2803,7 +2691,18 @@ int main(int argc, char **argv, char **envp) qemu_opt_get(opts, "mount_tag")); exit(1); } - qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype")); + + writeout = qemu_opt_get(opts, "writeout"); + if (writeout) { +#ifdef CONFIG_SYNC_FILE_RANGE + qemu_opt_set(fsdev, "writeout", writeout); +#else + fprintf(stderr, "writeout=immediate not supported on " + "this platform\n"); + exit(1); +#endif + } + qemu_opt_set(fsdev, "fsdriver", qemu_opt_get(opts, "fsdriver")); qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path")); qemu_opt_set(fsdev, "security_model", qemu_opt_get(opts, "security_model")); @@ -3279,6 +3178,7 @@ int main(int argc, char **argv, char **envp) configure_accelerator(); + qemu_init_cpu_loop(); if (qemu_init_main_loop()) { fprintf(stderr, "qemu_init_main_loop failed\n"); exit(1); @@ -3545,8 +3445,10 @@ int main(int argc, char **argv, char **envp) os_setup_post(); + resume_all_vcpus(); main_loop(); - quit_timers(); + bdrv_close_all(); + pause_all_vcpus(); net_cleanup(); res_free(); |