diff options
66 files changed, 966 insertions, 454 deletions
@@ -155,10 +155,6 @@ void bdrv_io_limits_enable(BlockDriverState *bs) { qemu_co_queue_init(&bs->throttled_reqs); bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs); - bs->slice_time = 5 * BLOCK_IO_SLICE_TIME; - bs->slice_start = qemu_get_clock_ns(vm_clock); - bs->slice_end = bs->slice_start + bs->slice_time; - memset(&bs->io_base, 0, sizeof(bs->io_base)); bs->io_limits_enabled = true; } @@ -4174,7 +4170,13 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, return -EIO; } else if (bs->read_only) { return -EROFS; - } else if (bs->drv->bdrv_co_discard) { + } + + if (bs->dirty_bitmap) { + set_dirty_bitmap(bs, sector_num, nb_sectors, 0); + } + + 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; diff --git a/block/mirror.c b/block/mirror.c index 8aeacbf12c..6180aa30e5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -225,7 +225,7 @@ static void coroutine_fn mirror_run(void *opaque) } immediate_exit: - g_free(s->buf); + qemu_vfree(s->buf); bdrv_set_dirty_tracking(bs, false); bdrv_iostatus_disable(s->target); if (s->should_complete && ret == 0) { diff --git a/block/qcow2.c b/block/qcow2.c index d603f98a9c..f6abff6111 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -759,7 +759,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, QEMUIOVector hd_qiov; uint64_t bytes_done = 0; uint8_t *cluster_data = NULL; - QCowL2Meta *l2meta; + QCowL2Meta *l2meta = NULL; trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num, remaining_sectors); diff --git a/block/raw-aio.h b/block/raw-aio.h index e77f361148..c61f1595d9 100644 --- a/block/raw-aio.h +++ b/block/raw-aio.h @@ -20,11 +20,14 @@ #define QEMU_AIO_WRITE 0x0002 #define QEMU_AIO_IOCTL 0x0004 #define QEMU_AIO_FLUSH 0x0008 +#define QEMU_AIO_DISCARD 0x0010 #define QEMU_AIO_TYPE_MASK \ - (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH) + (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \ + QEMU_AIO_DISCARD) /* AIO flags */ #define QEMU_AIO_MISALIGNED 0x1000 +#define QEMU_AIO_BLKDEV 0x2000 /* linux-aio.c - Linux native implementation */ diff --git a/block/raw-posix.c b/block/raw-posix.c index c3d7fda7b7..679fcc5113 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -59,6 +59,9 @@ #ifdef CONFIG_FIEMAP #include <linux/fiemap.h> #endif +#ifdef CONFIG_FALLOCATE_PUNCH_HOLE +#include <linux/falloc.h> +#endif #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) #include <sys/disk.h> #include <sys/cdio.h> @@ -138,6 +141,7 @@ typedef struct BDRVRawState { #ifdef CONFIG_XFS bool is_xfs : 1; #endif + bool has_discard : 1; } BDRVRawState; typedef struct BDRVRawReopenState { @@ -159,7 +163,7 @@ typedef struct RawPosixAIOData { void *aio_ioctl_buf; }; int aio_niov; - size_t aio_nbytes; + uint64_t aio_nbytes; #define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */ off_t aio_offset; int aio_type; @@ -289,6 +293,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, } #endif + s->has_discard = 1; #ifdef CONFIG_XFS if (platform_test_xfs_fd(s->fd)) { s->is_xfs = 1; @@ -618,6 +623,72 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb) return nbytes; } +#ifdef CONFIG_XFS +static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes) +{ + struct xfs_flock64 fl; + + memset(&fl, 0, sizeof(fl)); + fl.l_whence = SEEK_SET; + fl.l_start = offset; + fl.l_len = bytes; + + if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) { + DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno)); + return -errno; + } + + return 0; +} +#endif + +static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) +{ + int ret = -EOPNOTSUPP; + BDRVRawState *s = aiocb->bs->opaque; + + if (s->has_discard == 0) { + return 0; + } + + if (aiocb->aio_type & QEMU_AIO_BLKDEV) { +#ifdef BLKDISCARD + do { + uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes }; + if (ioctl(aiocb->aio_fildes, BLKDISCARD, range) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif + } else { +#ifdef CONFIG_XFS + if (s->is_xfs) { + return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes); + } +#endif + +#ifdef CONFIG_FALLOCATE_PUNCH_HOLE + do { + if (fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + aiocb->aio_offset, aiocb->aio_nbytes) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif + } + + if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP || + ret == -ENOTTY) { + s->has_discard = 0; + ret = 0; + } + return ret; +} + static int aio_worker(void *arg) { RawPosixAIOData *aiocb = arg; @@ -652,6 +723,9 @@ static int aio_worker(void *arg) case QEMU_AIO_IOCTL: ret = handle_aiocb_ioctl(aiocb); break; + case QEMU_AIO_DISCARD: + ret = handle_aiocb_discard(aiocb); + break; default: fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); ret = -EINVAL; @@ -1052,37 +1126,14 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, } } -#ifdef CONFIG_XFS -static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors) +static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - struct xfs_flock64 fl; - - memset(&fl, 0, sizeof(fl)); - fl.l_whence = SEEK_SET; - fl.l_start = sector_num << 9; - fl.l_len = (int64_t)nb_sectors << 9; - - if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) { - DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno)); - return -errno; - } - - return 0; -} -#endif - -static coroutine_fn int raw_co_discard(BlockDriverState *bs, - int64_t sector_num, int nb_sectors) -{ -#ifdef CONFIG_XFS BDRVRawState *s = bs->opaque; - if (s->is_xfs) { - return xfs_discard(s, sector_num, nb_sectors); - } -#endif - - return 0; + return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors, + cb, opaque, QEMU_AIO_DISCARD); } static QEMUOptionParameter raw_create_options[] = { @@ -1105,12 +1156,12 @@ static BlockDriver bdrv_file = { .bdrv_reopen_abort = raw_reopen_abort, .bdrv_close = raw_close, .bdrv_create = raw_create, - .bdrv_co_discard = raw_co_discard, .bdrv_co_is_allocated = raw_co_is_allocated, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, .bdrv_aio_flush = raw_aio_flush, + .bdrv_aio_discard = raw_aio_discard, .bdrv_truncate = raw_truncate, .bdrv_getlength = raw_getlength, @@ -1320,6 +1371,19 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs, return thread_pool_submit_aio(aio_worker, acb, cb, opaque); } +static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BDRVRawState *s = bs->opaque; + + if (fd_open(bs) < 0) { + return NULL; + } + return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors, + cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); +} + #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) static int fd_open(BlockDriverState *bs) { @@ -1391,6 +1455,7 @@ static BlockDriver bdrv_host_device = { .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, .bdrv_aio_flush = raw_aio_flush, + .bdrv_aio_discard = hdev_aio_discard, .bdrv_truncate = raw_truncate, .bdrv_getlength = raw_getlength, diff --git a/block/sheepdog.c b/block/sheepdog.c index 462c4b2d5d..3e49bb83bb 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -266,6 +266,7 @@ typedef struct AIOReq { enum AIOCBState { AIOCB_WRITE_UDATA, AIOCB_READ_UDATA, + AIOCB_FLUSH_CACHE, }; struct SheepdogAIOCB { @@ -299,7 +300,6 @@ typedef struct BDRVSheepdogState { char *addr; char *port; int fd; - int flush_fd; CoMutex lock; Coroutine *co_send; @@ -427,12 +427,11 @@ static const AIOCBInfo sd_aiocb_info = { }; static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t sector_num, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) + int64_t sector_num, int nb_sectors) { SheepdogAIOCB *acb; - acb = qemu_aio_get(&sd_aiocb_info, bs, cb, opaque); + acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL); acb->qiov = qiov; @@ -736,6 +735,13 @@ static void coroutine_fn aio_read_response(void *opaque) goto out; } break; + case AIOCB_FLUSH_CACHE: + if (rsp.result == SD_RES_INVALID_PARMS) { + dprintf("disable cache since the server doesn't support it\n"); + s->cache_flags = SD_FLAG_CMD_DIRECT; + rsp.result = SD_RES_SUCCESS; + } + break; } if (rsp.result != SD_RES_SUCCESS) { @@ -950,7 +956,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, { int nr_copies = s->inode.nr_copies; SheepdogObjReq hdr; - unsigned int wlen; + unsigned int wlen = 0; int ret; uint64_t oid = aio_req->oid; unsigned int datalen = aio_req->data_len; @@ -964,18 +970,23 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, memset(&hdr, 0, sizeof(hdr)); - if (aiocb_type == AIOCB_READ_UDATA) { - wlen = 0; + switch (aiocb_type) { + case AIOCB_FLUSH_CACHE: + hdr.opcode = SD_OP_FLUSH_VDI; + break; + case AIOCB_READ_UDATA: hdr.opcode = SD_OP_READ_OBJ; hdr.flags = flags; - } else if (create) { - wlen = datalen; - hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ; - hdr.flags = SD_FLAG_CMD_WRITE | flags; - } else { + break; + case AIOCB_WRITE_UDATA: + if (create) { + hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ; + } else { + hdr.opcode = SD_OP_WRITE_OBJ; + } wlen = datalen; - hdr.opcode = SD_OP_WRITE_OBJ; hdr.flags = SD_FLAG_CMD_WRITE | flags; + break; } if (s->cache_flags) { @@ -1127,15 +1138,6 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) s->cache_flags = SD_FLAG_CMD_DIRECT; } - if (s->cache_flags == SD_FLAG_CMD_CACHE) { - s->flush_fd = connect_to_sdog(s->addr, s->port); - if (s->flush_fd < 0) { - error_report("failed to connect"); - ret = s->flush_fd; - goto out; - } - } - if (snapid || tag[0] != '\0') { dprintf("%" PRIx32 " snapshot inode was open.\n", vid); s->is_snapshot = true; @@ -1397,9 +1399,6 @@ static void sd_close(BlockDriverState *bs) qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); - if (s->cache_flags) { - closesocket(s->flush_fd); - } g_free(s->addr); } @@ -1672,7 +1671,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, bs->total_sectors = sector_num + nb_sectors; } - acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL); + acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors); acb->aio_done_func = sd_write_done; acb->aiocb_type = AIOCB_WRITE_UDATA; @@ -1693,7 +1692,7 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, SheepdogAIOCB *acb; int ret; - acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL); + acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors); acb->aiocb_type = AIOCB_READ_UDATA; acb->aio_done_func = sd_finish_aiocb; @@ -1711,39 +1710,31 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) { BDRVSheepdogState *s = bs->opaque; - SheepdogObjReq hdr = { 0 }; - SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr; - SheepdogInode *inode = &s->inode; + SheepdogAIOCB *acb; + AIOReq *aio_req; int ret; - unsigned int wlen = 0, rlen = 0; if (s->cache_flags != SD_FLAG_CMD_CACHE) { return 0; } - hdr.opcode = SD_OP_FLUSH_VDI; - hdr.oid = vid_to_vdi_oid(inode->vdi_id); + acb = sd_aio_setup(bs, NULL, 0, 0); + acb->aiocb_type = AIOCB_FLUSH_CACHE; + acb->aio_done_func = sd_finish_aiocb; - ret = do_req(s->flush_fd, (SheepdogReq *)&hdr, NULL, &wlen, &rlen); - if (ret) { - error_report("failed to send a request to the sheep"); + aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), + 0, 0, 0, 0, 0); + QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); + ret = add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type); + if (ret < 0) { + error_report("add_aio_request is failed"); + free_aio_req(s, aio_req); + qemu_aio_release(acb); return ret; } - if (rsp->result == SD_RES_INVALID_PARMS) { - dprintf("disable write cache since the server doesn't support it\n"); - - s->cache_flags = SD_FLAG_CMD_DIRECT; - closesocket(s->flush_fd); - return 0; - } - - if (rsp->result != SD_RES_SUCCESS) { - error_report("%s", sd_strerror(rsp->result)); - return -EIO; - } - - return 0; + qemu_coroutine_yield(); + return acb->ret; } static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) diff --git a/block/win32-aio.c b/block/win32-aio.c index 46a5db78cc..03833700b4 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -87,7 +87,7 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s, memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len); p += qiov->iov[i].iov_len; } - g_free(waiocb->buf); + qemu_vfree(waiocb->buf); } } @@ -2584,6 +2584,22 @@ if compile_prog "" "" ; then fallocate=yes fi +# check for fallocate hole punching +fallocate_punch_hole=no +cat > $TMPC << EOF +#include <fcntl.h> +#include <linux/falloc.h> + +int main(void) +{ + fallocate(0, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 0); + return 0; +} +EOF +if compile_prog "" "" ; then + fallocate_punch_hole=yes +fi + # check for sync_file_range sync_file_range=no cat > $TMPC << EOF @@ -3493,6 +3509,9 @@ fi if test "$fallocate" = "yes" ; then echo "CONFIG_FALLOCATE=y" >> $config_host_mak fi +if test "$fallocate_punch_hole" = "yes" ; then + echo "CONFIG_FALLOCATE_PUNCH_HOLE=y" >> $config_host_mak +fi if test "$sync_file_range" = "yes" ; then echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak fi @@ -390,13 +390,15 @@ void hw_error(const char *fmt, ...) { va_list ap; CPUArchState *env; + CPUState *cpu; va_start(ap, fmt); fprintf(stderr, "qemu: hardware error: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); - for(env = first_cpu; env != NULL; env = env->next_cpu) { - fprintf(stderr, "CPU #%d:\n", env->cpu_index); + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); + fprintf(stderr, "CPU #%d:\n", cpu->cpu_index); cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU); } va_end(ap); @@ -740,7 +742,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) cpu->thread_id = qemu_get_thread_id(); cpu_single_env = env; - r = kvm_init_vcpu(env); + r = kvm_init_vcpu(cpu); if (r < 0) { fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r)); exit(1); @@ -1041,8 +1043,8 @@ void qemu_init_vcpu(void *_env) CPUArchState *env = _env; CPUState *cpu = ENV_GET_CPU(env); - env->nr_cores = smp_cores; - env->nr_threads = smp_threads; + cpu->nr_cores = smp_cores; + cpu->nr_threads = smp_threads; cpu->stopped = true; if (kvm_enabled()) { qemu_kvm_start_vcpu(env); @@ -1160,12 +1162,14 @@ static void tcg_exec_all(void) void set_numa_modes(void) { CPUArchState *env; + CPUState *cpu; int i; for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); for (i = 0; i < nb_numa_nodes; i++) { - if (test_bit(env->cpu_index, node_cpumask[i])) { - env->numa_node = i; + if (test_bit(cpu->cpu_index, node_cpumask[i])) { + cpu->numa_node = i; } } } @@ -1213,7 +1217,7 @@ CpuInfoList *qmp_query_cpus(Error **errp) info = g_malloc0(sizeof(*info)); info->value = g_malloc0(sizeof(*info->value)); - info->value->CPU = env->cpu_index; + info->value->CPU = cpu->cpu_index; info->value->current = (env == first_cpu); info->value->halted = env->halted; info->value->thread_id = cpu->thread_id; @@ -1251,6 +1255,7 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, FILE *f; uint32_t l; CPUArchState *env; + CPUState *cpu; uint8_t buf[1024]; if (!has_cpu) { @@ -1258,7 +1263,8 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, } for (env = first_cpu; env; env = env->next_cpu) { - if (cpu_index == env->cpu_index) { + cpu = ENV_GET_CPU(env); + if (cpu_index == cpu->cpu_index) { break; } } @@ -247,24 +247,25 @@ static const VMStateDescription vmstate_cpu_common = { }; #endif -CPUArchState *qemu_get_cpu(int cpu) +CPUState *qemu_get_cpu(int index) { CPUArchState *env = first_cpu; + CPUState *cpu = NULL; while (env) { - if (env->cpu_index == cpu) + cpu = ENV_GET_CPU(env); + if (cpu->cpu_index == index) { break; + } env = env->next_cpu; } - return env; + return cpu; } void cpu_exec_init(CPUArchState *env) { -#ifndef CONFIG_USER_ONLY CPUState *cpu = ENV_GET_CPU(env); -#endif CPUArchState **penv; int cpu_index; @@ -278,8 +279,8 @@ void cpu_exec_init(CPUArchState *env) penv = &(*penv)->next_cpu; cpu_index++; } - env->cpu_index = cpu_index; - env->numa_node = 0; + cpu->cpu_index = cpu_index; + cpu->numa_node = 0; QTAILQ_INIT(&env->breakpoints); QTAILQ_INIT(&env->watchpoints); #ifndef CONFIG_USER_ONLY @@ -531,7 +532,6 @@ CPUArchState *cpu_copy(CPUArchState *env) { CPUArchState *new_env = cpu_init(env->cpu_model_str); CPUArchState *next_cpu = new_env->next_cpu; - int cpu_index = new_env->cpu_index; #if defined(TARGET_HAS_ICE) CPUBreakpoint *bp; CPUWatchpoint *wp; @@ -539,9 +539,8 @@ CPUArchState *cpu_copy(CPUArchState *env) memcpy(new_env, env, sizeof(CPUArchState)); - /* Preserve chaining and index. */ + /* Preserve chaining. */ new_env->next_cpu = next_cpu; - new_env->cpu_index = cpu_index; /* Clone all break/watchpoints. Note: Once we support ptrace with hw-debug register access, make sure @@ -2401,9 +2401,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) thread = strtoull(p+16, (char **)&p, 16); env = find_cpu(thread); if (env != NULL) { + CPUState *cpu = ENV_GET_CPU(env); cpu_synchronize_state(env); len = snprintf((char *)mem_buf, sizeof(mem_buf), - "CPU#%d [%s]", env->cpu_index, + "CPU#%d [%s]", cpu->cpu_index, env->halted ? "halted " : "running"); memtohex(buf, mem_buf, len); put_packet(s, buf); diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index dafb35ddd1..bf9aabfc08 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -75,6 +75,7 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) { CPUAlphaState *env = cpu_single_env; TyphoonState *s = opaque; + CPUState *cpu; uint64_t ret = 0; if (addr & 4) { @@ -95,7 +96,8 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) case 0x0080: /* MISC: Miscellaneous Register. */ - ret = s->cchip.misc | (env->cpu_index & 3); + cpu = ENV_GET_CPU(env); + ret = s->cchip.misc | (cpu->cpu_index & 3); break; case 0x00c0: diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 466dbf7398..90e43d0728 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -39,7 +39,8 @@ static const uint8_t gic_id[] = { static inline int gic_get_current_cpu(GICState *s) { if (s->num_cpu > 1) { - return cpu_single_env->cpu_index; + CPUState *cpu = ENV_GET_CPU(cpu_single_env); + return cpu->cpu_index; } return 0; } diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 0cd3853a36..cdfd62363e 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -49,11 +49,13 @@ typedef struct { static inline int get_current_cpu(arm_mptimer_state *s) { - if (cpu_single_env->cpu_index >= s->num_cpu) { + CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env); + + if (cpu_single_cpu->cpu_index >= s->num_cpu) { hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n", - s->num_cpu, cpu_single_env->cpu_index); + s->num_cpu, cpu_single_cpu->cpu_index); } - return cpu_single_env->cpu_index; + return cpu_single_cpu->cpu_index; } static inline void timerblock_update_irq(timerblock *tb) diff --git a/hw/ide/core.c b/hw/ide/core.c index 6f1938a0a8..14ad0799c3 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -325,14 +325,26 @@ typedef struct TrimAIOCB { BlockDriverAIOCB common; QEMUBH *bh; int ret; + QEMUIOVector *qiov; + BlockDriverAIOCB *aiocb; + int i, j; } TrimAIOCB; static void trim_aio_cancel(BlockDriverAIOCB *acb) { TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common); + /* Exit the loop in case bdrv_aio_cancel calls ide_issue_trim_cb again. */ + iocb->j = iocb->qiov->niov - 1; + iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1; + + /* Tell ide_issue_trim_cb not to trigger the completion, too. */ qemu_bh_delete(iocb->bh); iocb->bh = NULL; + + if (iocb->aiocb) { + bdrv_aio_cancel(iocb->aiocb); + } qemu_aio_release(iocb); } @@ -349,43 +361,60 @@ static void ide_trim_bh_cb(void *opaque) qemu_bh_delete(iocb->bh); iocb->bh = NULL; - qemu_aio_release(iocb); } +static void ide_issue_trim_cb(void *opaque, int ret) +{ + TrimAIOCB *iocb = opaque; + if (ret >= 0) { + while (iocb->j < iocb->qiov->niov) { + int j = iocb->j; + while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) { + int i = iocb->i; + uint64_t *buffer = iocb->qiov->iov[j].iov_base; + + /* 6-byte LBA + 2-byte range per entry */ + uint64_t entry = le64_to_cpu(buffer[i]); + uint64_t sector = entry & 0x0000ffffffffffffULL; + uint16_t count = entry >> 48; + + if (count == 0) { + continue; + } + + /* Got an entry! Submit and exit. */ + iocb->aiocb = bdrv_aio_discard(iocb->common.bs, sector, count, + ide_issue_trim_cb, opaque); + return; + } + + iocb->j++; + iocb->i = -1; + } + } else { + iocb->ret = ret; + } + + iocb->aiocb = NULL; + if (iocb->bh) { + qemu_bh_schedule(iocb->bh); + } +} + BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { TrimAIOCB *iocb; - int i, j, ret; iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque); iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; - - for (j = 0; j < qiov->niov; j++) { - uint64_t *buffer = qiov->iov[j].iov_base; - - for (i = 0; i < qiov->iov[j].iov_len / 8; i++) { - /* 6-byte LBA + 2-byte range per entry */ - uint64_t entry = le64_to_cpu(buffer[i]); - uint64_t sector = entry & 0x0000ffffffffffffULL; - uint16_t count = entry >> 48; - - if (count == 0) { - break; - } - - ret = bdrv_discard(bs, sector, count); - if (!iocb->ret) { - iocb->ret = ret; - } - } - } - - qemu_bh_schedule(iocb->bh); - + iocb->qiov = qiov; + iocb->i = -1; + iocb->j = 0; + ide_issue_trim_cb(iocb, 0); return &iocb->common; } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2250e675a5..771d1256d7 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -743,10 +743,13 @@ static int64_t load_kernel (void) return kernel_entry; } -static void malta_mips_config(CPUMIPSState *env) +static void malta_mips_config(MIPSCPU *cpu) { + CPUMIPSState *env = &cpu->env; + CPUState *cs = CPU(cpu); + env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) | - ((smp_cpus * env->nr_threads - 1) << CP0MVPC0_PTC); + ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC); } static void main_cpu_reset(void *opaque) @@ -763,7 +766,7 @@ static void main_cpu_reset(void *opaque) env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); } - malta_mips_config(env); + malta_mips_config(cpu); } static void cpu_request_exit(void *opaque, int irq, int level) diff --git a/hw/openpic.c b/hw/openpic.c index 23fa8f9635..f6cc07bd6e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -153,11 +153,14 @@ static const int debug_openpic = 0; static int get_current_cpu(void) { + CPUState *cpu_single_cpu; + if (!cpu_single_env) { return -1; } - return cpu_single_env->cpu_index; + cpu_single_cpu = ENV_GET_CPU(cpu_single_env); + return cpu_single_cpu->cpu_index; } static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, diff --git a/hw/pc87312.c b/hw/pc87312.c index 6a17afd45c..38af4c1d10 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -34,10 +34,6 @@ #define REG_FAR 1 #define REG_PTR 2 -#define FER regs[REG_FER] -#define FAR regs[REG_FAR] -#define PTR regs[REG_PTR] - #define FER_PARALLEL_EN 0x01 #define FER_UART1_EN 0x02 #define FER_UART2_EN 0x04 @@ -66,14 +62,14 @@ static inline bool is_parallel_enabled(PC87312State *s) { - return s->FER & FER_PARALLEL_EN; + return s->regs[REG_FER] & FER_PARALLEL_EN; } static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; static inline uint32_t get_parallel_iobase(PC87312State *s) { - return parallel_base[s->FAR & FAR_PARALLEL_ADDR]; + return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR]; } static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; @@ -81,9 +77,9 @@ static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; static inline uint32_t get_parallel_irq(PC87312State *s) { int idx; - idx = (s->FAR & FAR_PARALLEL_ADDR); + idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR); if (idx == 0) { - return (s->PTR & PTR_IRQ_5_7) ? 7 : 5; + return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5; } else { return parallel_irq[idx]; } @@ -91,7 +87,7 @@ static inline uint32_t get_parallel_irq(PC87312State *s) static inline bool is_parallel_epp(PC87312State *s) { - return s->PTR & PTR_EPP_MODE; + return s->regs[REG_PTR] & PTR_EPP_MODE; } @@ -105,26 +101,26 @@ static const uint32_t uart_base[2][4] = { static inline uint32_t get_uart_iobase(PC87312State *s, int i) { int idx; - idx = (s->FAR >> (2 * i + 2)) & 0x3; + idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; if (idx == 0) { return 0x3f8; } else if (idx == 1) { return 0x2f8; } else { - return uart_base[idx & 1][(s->FAR & FAR_UART_3_4) >> 6]; + return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6]; } } static inline uint32_t get_uart_irq(PC87312State *s, int i) { int idx; - idx = (s->FAR >> (2 * i + 2)) & 0x3; + idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; return (idx & 1) ? 3 : 4; } static inline bool is_uart_enabled(PC87312State *s, int i) { - return s->FER & (FER_UART1_EN << i); + return s->regs[REG_FER] & (FER_UART1_EN << i); } @@ -132,12 +128,12 @@ static inline bool is_uart_enabled(PC87312State *s, int i) static inline bool is_fdc_enabled(PC87312State *s) { - return s->FER & FER_FDC_EN; + return s->regs[REG_FER] & FER_FDC_EN; } static inline uint32_t get_fdc_iobase(PC87312State *s) { - return (s->FER & FER_FDC_ADDR) ? 0x370 : 0x3f0; + return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0; } @@ -145,19 +141,19 @@ static inline uint32_t get_fdc_iobase(PC87312State *s) static inline bool is_ide_enabled(PC87312State *s) { - return s->FER & FER_IDE_EN; + return s->regs[REG_FER] & FER_IDE_EN; } static inline uint32_t get_ide_iobase(PC87312State *s) { - return (s->FER & FER_IDE_ADDR) ? 0x170 : 0x1f0; + return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0; } static void reconfigure_devices(PC87312State *s) { error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)", - s->FER, s->FAR, s->PTR); + s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]); } static void pc87312_soft_reset(PC87312State *s) @@ -184,9 +180,9 @@ static void pc87312_soft_reset(PC87312State *s) s->read_id_step = 0; s->selected_index = REG_FER; - s->FER = fer_init[s->config & 0x1f]; - s->FAR = far_init[s->config & 0x1f]; - s->PTR = ptr_init[s->config & 0x1f]; + s->regs[REG_FER] = fer_init[s->config & 0x1f]; + s->regs[REG_FAR] = far_init[s->config & 0x1f]; + s->regs[REG_PTR] = ptr_init[s->config & 0x1f]; } static void pc87312_hard_reset(PC87312State *s) @@ -194,7 +190,8 @@ static void pc87312_hard_reset(PC87312State *s) pc87312_soft_reset(s); } -static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) { PC87312State *s = opaque; @@ -213,7 +210,7 @@ static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr) +static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size) { PC87312State *s = opaque; uint32_t val; @@ -241,6 +238,16 @@ static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr) return val; } +static const MemoryRegionOps pc87312_io_ops = { + .read = pc87312_io_read, + .write = pc87312_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static int pc87312_post_load(void *opaque, int version_id) { PC87312State *s = opaque; @@ -270,6 +277,7 @@ static int pc87312_init(ISADevice *dev) s = PC87312(dev); bus = isa_bus_from_device(dev); pc87312_hard_reset(s); + isa_register_ioport(dev, &s->io, s->iobase); if (is_parallel_enabled(s)) { chr = parallel_hds[0]; @@ -337,11 +345,16 @@ static int pc87312_init(ISADevice *dev) trace_pc87312_info_ide(get_ide_iobase(s)); } - register_ioport_write(s->iobase, 2, 1, pc87312_ioport_write, s); - register_ioport_read(s->iobase, 2, 1, pc87312_ioport_read, s); return 0; } +static void pc87312_initfn(Object *obj) +{ + PC87312State *s = PC87312(obj); + + memory_region_init_io(&s->io, &pc87312_io_ops, s, "pc87312", 2); +} + static const VMStateDescription vmstate_pc87312 = { .name = "pc87312", .version_id = 1, @@ -376,6 +389,7 @@ static const TypeInfo pc87312_type_info = { .name = TYPE_PC87312, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PC87312State), + .instance_init = pc87312_initfn, .class_init = pc87312_class_init, }; diff --git a/hw/pc87312.h b/hw/pc87312.h index 7ca7912ba7..7b9e6f6132 100644 --- a/hw/pc87312.h +++ b/hw/pc87312.h @@ -56,6 +56,8 @@ typedef struct PC87312State { uint32_t base; } ide; + MemoryRegion io; + uint8_t read_id_step; uint8_t selected_index; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 3a9e1c7b43..7b3e2e6723 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -239,25 +239,28 @@ static int ppce500_load_device_tree(CPUPPCState *env, /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { + CPUState *cpu = NULL; char cpu_name[128]; uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index == i) { + cpu = ENV_GET_CPU(env); + if (cpu->cpu_index == i) { break; } } - if (!env) { + if (cpu == NULL) { continue; } - snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index); + snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", + cpu->cpu_index); qemu_devtree_add_subnode(fdt, cpu_name); qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); - qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index); + qemu_devtree_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index); qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", env->dcache_line_size); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", @@ -265,7 +268,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); - if (env->cpu_index) { + if (cpu->cpu_index) { qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr", @@ -479,6 +482,7 @@ void ppce500_init(PPCE500Params *params) irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); for (i = 0; i < smp_cpus; i++) { PowerPCCPU *cpu; + CPUState *cs; qemu_irq *input; cpu = cpu_ppc_init(params->cpu_model); @@ -487,6 +491,7 @@ void ppce500_init(PPCE500Params *params) exit(1); } env = &cpu->env; + cs = CPU(cpu); if (!firstenv) { firstenv = env; @@ -496,7 +501,7 @@ void ppce500_init(PPCE500Params *params) input = (qemu_irq *)env->irq_inputs; irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; - env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; + env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i; env->mpic_iack = MPC8544_CCSRBAR_BASE + MPC8544_MPIC_REGS_OFFSET + 0x200A0; diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 1b2c34f92c..4c206e2834 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -124,21 +124,23 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value, SpinState *s = opaque; int env_idx = addr / sizeof(SpinInfo); CPUPPCState *env; + CPUState *cpu = NULL; SpinInfo *curspin = &s->spin[env_idx]; uint8_t *curspin_p = (uint8_t*)curspin; for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index == env_idx) { + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index == env_idx) { break; } } - if (!env) { + if (cpu == NULL) { /* Unknown CPU */ return; } - if (!env->cpu_index) { + if (cpu->cpu_index == 0) { /* primary CPU doesn't spin */ return; } @@ -69,7 +69,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu); /* pxa2xx_gpio.c */ DeviceState *pxa2xx_gpio_init(hwaddr base, - CPUARMState *env, DeviceState *pic, int lines); + ARMCPU *cpu, DeviceState *pic, int lines); void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler); /* pxa2xx_dma.c */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index f3dffef5ab..492805f2fa 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2045,7 +2045,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11), NULL); - s->gpio = pxa2xx_gpio_init(0x40e00000, &s->cpu->env, s->pic, 121); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { @@ -2176,7 +2176,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), NULL); - s->gpio = pxa2xx_gpio_init(0x40e00000, &s->cpu->env, s->pic, 85); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 016833dfa1..eec2ea3f1c 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -250,13 +250,14 @@ static const MemoryRegionOps pxa_gpio_ops = { }; DeviceState *pxa2xx_gpio_init(hwaddr base, - CPUARMState *env, DeviceState *pic, int lines) + ARMCPU *cpu, DeviceState *pic, int lines) { + CPUState *cs = CPU(cpu); DeviceState *dev; dev = qdev_create(NULL, "pxa2xx-gpio"); qdev_prop_set_int32(dev, "lines", lines); - qdev_prop_set_int32(dev, "ncpu", env->cpu_index); + qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); @@ -276,7 +277,7 @@ static int pxa2xx_gpio_initfn(SysBusDevice *dev) s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); - s->cpu = arm_env_get_cpu(qemu_get_cpu(s->ncpu)); + s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu)); qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f8d7ef3374..96db9a73c7 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -85,9 +85,7 @@ static void scsi_free_request(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - if (r->iov.iov_base) { - qemu_vfree(r->iov.iov_base); - } + qemu_vfree(r->iov.iov_base); } /* Helper function for command completion with sense. */ diff --git a/hw/spapr.c b/hw/spapr.c index b5e15b884a..76aa09ba81 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -140,6 +140,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; CPUPPCState *env; + CPUState *cpu; char cpu_model[32]; int smt = kvmppc_smt_threads(); uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; @@ -147,19 +148,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) assert(spapr->cpu_model); for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = CPU(ppc_env_get_cpu(env)); uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(env->numa_node), - cpu_to_be32(env->cpu_index)}; + cpu_to_be32(cpu->numa_node), + cpu_to_be32(cpu->cpu_index)}; - if ((env->cpu_index % smt) != 0) { + if ((cpu->cpu_index % smt) != 0) { continue; } snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, - env->cpu_index); + cpu->cpu_index); offset = fdt_path_offset(fdt, cpu_model); if (offset < 0) { @@ -308,7 +310,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, spapr->cpu_model = g_strdup(modelname); for (env = first_cpu; env != NULL; env = env->next_cpu) { - int index = env->cpu_index; + CPUState *cpu = CPU(ppc_env_get_cpu(env)); + int index = cpu->cpu_index; uint32_t servers_prop[smp_threads]; uint32_t gservers_prop[smp_threads * 2]; char *nodename; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index afb12973f2..2889742788 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -467,9 +467,11 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong vpa = args[2]; target_ulong ret = H_PARAMETER; CPUPPCState *tenv; + CPUState *tcpu; for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) { - if (tenv->cpu_index == procno) { + tcpu = CPU(ppc_env_get_cpu(tenv)); + if (tcpu->cpu_index == procno) { break; } } diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 81eecd0940..5ec787f29d 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -131,6 +131,7 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, { target_ulong id; CPUPPCState *env; + CPUState *cpu; if (nargs != 1 || nret != 2) { rtas_st(rets, 0, -3); @@ -139,7 +140,8 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, id = rtas_ld(args, 0); for (env = first_cpu; env; env = env->next_cpu) { - if (env->cpu_index != id) { + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index != id) { continue; } @@ -176,9 +178,9 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, r3 = rtas_ld(args, 2); for (env = first_cpu; env; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); + cpu = CPU(ppc_env_get_cpu(env)); - if (env->cpu_index != id) { + if (cpu->cpu_index != id) { continue; } diff --git a/hw/xen_disk.c b/hw/xen_disk.c index a6a64a2455..7fea87156d 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -51,6 +51,13 @@ static int max_requests = 32; #define BLOCK_SIZE 512 #define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2) +struct PersistentGrant { + void *page; + struct XenBlkDev *blkdev; +}; + +typedef struct PersistentGrant PersistentGrant; + struct ioreq { blkif_request_t req; int16_t status; @@ -68,6 +75,7 @@ struct ioreq { int prot; void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST]; void *pages; + int num_unmap; /* aio status */ int aio_inflight; @@ -104,6 +112,12 @@ struct XenBlkDev { int requests_inflight; int requests_finished; + /* Persistent grants extension */ + gboolean feature_persistent; + GTree *persistent_gnts; + unsigned int persistent_gnt_count; + unsigned int max_grants; + /* qemu block driver */ DriveInfo *dinfo; BlockDriverState *bs; @@ -112,6 +126,54 @@ struct XenBlkDev { /* ------------------------------------------------------------- */ +static void ioreq_reset(struct ioreq *ioreq) +{ + memset(&ioreq->req, 0, sizeof(ioreq->req)); + ioreq->status = 0; + ioreq->start = 0; + ioreq->presync = 0; + ioreq->postsync = 0; + ioreq->mapped = 0; + + memset(ioreq->domids, 0, sizeof(ioreq->domids)); + memset(ioreq->refs, 0, sizeof(ioreq->refs)); + ioreq->prot = 0; + memset(ioreq->page, 0, sizeof(ioreq->page)); + ioreq->pages = NULL; + + ioreq->aio_inflight = 0; + ioreq->aio_errors = 0; + + ioreq->blkdev = NULL; + memset(&ioreq->list, 0, sizeof(ioreq->list)); + memset(&ioreq->acct, 0, sizeof(ioreq->acct)); + + qemu_iovec_reset(&ioreq->v); +} + +static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data) +{ + uint ua = GPOINTER_TO_UINT(a); + uint ub = GPOINTER_TO_UINT(b); + return (ua > ub) - (ua < ub); +} + +static void destroy_grant(gpointer pgnt) +{ + PersistentGrant *grant = pgnt; + XenGnttab gnt = grant->blkdev->xendev.gnttabdev; + + if (xc_gnttab_munmap(gnt, grant->page, 1) != 0) { + xen_be_printf(&grant->blkdev->xendev, 0, + "xc_gnttab_munmap failed: %s\n", + strerror(errno)); + } + grant->blkdev->persistent_gnt_count--; + xen_be_printf(&grant->blkdev->xendev, 3, + "unmapped grant %p\n", grant->page); + g_free(grant); +} + static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) { struct ioreq *ioreq = NULL; @@ -129,7 +191,6 @@ static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) /* get one from freelist */ ioreq = QLIST_FIRST(&blkdev->freelist); QLIST_REMOVE(ioreq, list); - qemu_iovec_reset(&ioreq->v); } QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list); blkdev->requests_inflight++; @@ -153,7 +214,7 @@ static void ioreq_release(struct ioreq *ioreq, bool finish) struct XenBlkDev *blkdev = ioreq->blkdev; QLIST_REMOVE(ioreq, list); - memset(ioreq, 0, sizeof(*ioreq)); + ioreq_reset(ioreq); ioreq->blkdev = blkdev; QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); if (finish) { @@ -182,12 +243,11 @@ static int ioreq_parse(struct ioreq *ioreq) case BLKIF_OP_READ: ioreq->prot = PROT_WRITE; /* to memory */ break; - case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + ioreq->presync = 1; if (!ioreq->req.nr_segments) { - ioreq->presync = 1; return 0; } - ioreq->presync = ioreq->postsync = 1; /* fall through */ case BLKIF_OP_WRITE: ioreq->prot = PROT_READ; /* from memory */ @@ -241,21 +301,21 @@ static void ioreq_unmap(struct ioreq *ioreq) XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; int i; - if (ioreq->v.niov == 0 || ioreq->mapped == 0) { + if (ioreq->num_unmap == 0 || ioreq->mapped == 0) { return; } if (batch_maps) { if (!ioreq->pages) { return; } - if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) { + if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->num_unmap) != 0) { xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", strerror(errno)); } - ioreq->blkdev->cnt_map -= ioreq->v.niov; + ioreq->blkdev->cnt_map -= ioreq->num_unmap; ioreq->pages = NULL; } else { - for (i = 0; i < ioreq->v.niov; i++) { + for (i = 0; i < ioreq->num_unmap; i++) { if (!ioreq->page[i]) { continue; } @@ -273,41 +333,120 @@ static void ioreq_unmap(struct ioreq *ioreq) static int ioreq_map(struct ioreq *ioreq) { XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; - int i; + uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int i, j, new_maps = 0; + PersistentGrant *grant; + /* domids and refs variables will contain the information necessary + * to map the grants that are needed to fulfill this request. + * + * After mapping the needed grants, the page array will contain the + * memory address of each granted page in the order specified in ioreq + * (disregarding if it's a persistent grant or not). + */ if (ioreq->v.niov == 0 || ioreq->mapped == 1) { return 0; } - if (batch_maps) { + if (ioreq->blkdev->feature_persistent) { + for (i = 0; i < ioreq->v.niov; i++) { + grant = g_tree_lookup(ioreq->blkdev->persistent_gnts, + GUINT_TO_POINTER(ioreq->refs[i])); + + if (grant != NULL) { + page[i] = grant->page; + xen_be_printf(&ioreq->blkdev->xendev, 3, + "using persistent-grant %" PRIu32 "\n", + ioreq->refs[i]); + } else { + /* Add the grant to the list of grants that + * should be mapped + */ + domids[new_maps] = ioreq->domids[i]; + refs[new_maps] = ioreq->refs[i]; + page[i] = NULL; + new_maps++; + } + } + /* Set the protection to RW, since grants may be reused later + * with a different protection than the one needed for this request + */ + ioreq->prot = PROT_WRITE | PROT_READ; + } else { + /* All grants in the request should be mapped */ + memcpy(refs, ioreq->refs, sizeof(refs)); + memcpy(domids, ioreq->domids, sizeof(domids)); + memset(page, 0, sizeof(page)); + new_maps = ioreq->v.niov; + } + + if (batch_maps && new_maps) { ioreq->pages = xc_gnttab_map_grant_refs - (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot); + (gnt, new_maps, domids, refs, ioreq->prot); if (ioreq->pages == NULL) { xen_be_printf(&ioreq->blkdev->xendev, 0, "can't map %d grant refs (%s, %d maps)\n", - ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map); + new_maps, strerror(errno), ioreq->blkdev->cnt_map); return -1; } - for (i = 0; i < ioreq->v.niov; i++) { - ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE + - (uintptr_t)ioreq->v.iov[i].iov_base; + for (i = 0, j = 0; i < ioreq->v.niov; i++) { + if (page[i] == NULL) { + page[i] = ioreq->pages + (j++) * XC_PAGE_SIZE; + } } - ioreq->blkdev->cnt_map += ioreq->v.niov; - } else { - for (i = 0; i < ioreq->v.niov; i++) { + ioreq->blkdev->cnt_map += new_maps; + } else if (new_maps) { + for (i = 0; i < new_maps; i++) { ioreq->page[i] = xc_gnttab_map_grant_ref - (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot); + (gnt, domids[i], refs[i], ioreq->prot); if (ioreq->page[i] == NULL) { xen_be_printf(&ioreq->blkdev->xendev, 0, "can't map grant ref %d (%s, %d maps)\n", - ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map); + refs[i], strerror(errno), ioreq->blkdev->cnt_map); ioreq_unmap(ioreq); return -1; } - ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base; ioreq->blkdev->cnt_map++; } + for (i = 0, j = 0; i < ioreq->v.niov; i++) { + if (page[i] == NULL) { + page[i] = ioreq->page[j++]; + } + } + } + if (ioreq->blkdev->feature_persistent) { + while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants) + && new_maps) { + /* Go through the list of newly mapped grants and add as many + * as possible to the list of persistently mapped grants. + * + * Since we start at the end of ioreq->page(s), we only need + * to decrease new_maps to prevent this granted pages from + * being unmapped in ioreq_unmap. + */ + grant = g_malloc0(sizeof(*grant)); + new_maps--; + if (batch_maps) { + grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE; + } else { + grant->page = ioreq->page[new_maps]; + } + grant->blkdev = ioreq->blkdev; + xen_be_printf(&ioreq->blkdev->xendev, 3, + "adding grant %" PRIu32 " page: %p\n", + refs[new_maps], grant->page); + g_tree_insert(ioreq->blkdev->persistent_gnts, + GUINT_TO_POINTER(refs[new_maps]), + grant); + ioreq->blkdev->persistent_gnt_count++; + } + } + for (i = 0; i < ioreq->v.niov; i++) { + ioreq->v.iov[i].iov_base += (uintptr_t)page[i]; } ioreq->mapped = 1; + ioreq->num_unmap = new_maps; return 0; } @@ -369,7 +508,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) qemu_aio_complete, ioreq); break; case BLKIF_OP_WRITE: - case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: if (!ioreq->req.nr_segments) { break; } @@ -654,7 +793,8 @@ static int blk_init(struct XenDevice *xendev) blkdev->file_size, blkdev->file_size >> 20); /* fill info */ - xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1); + xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1); + xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 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", @@ -678,6 +818,7 @@ out_error: static int blk_connect(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + int pers; if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) { return -1; @@ -686,6 +827,11 @@ static int blk_connect(struct XenDevice *xendev) &blkdev->xendev.remote_port) == -1) { return -1; } + if (xenstore_read_fe_int(&blkdev->xendev, "feature-persistent", &pers)) { + blkdev->feature_persistent = FALSE; + } else { + blkdev->feature_persistent = !!pers; + } blkdev->protocol = BLKIF_PROTOCOL_NATIVE; if (blkdev->xendev.protocol) { @@ -729,6 +875,15 @@ static int blk_connect(struct XenDevice *xendev) } } + if (blkdev->feature_persistent) { + /* Init persistent grants */ + blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST; + blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp, + NULL, NULL, + (GDestroyNotify)destroy_grant); + blkdev->persistent_gnt_count = 0; + } + xen_be_bind_evtchn(&blkdev->xendev); xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, " @@ -769,6 +924,11 @@ static int blk_free(struct XenDevice *xendev) blk_disconnect(xendev); } + /* Free persistent grants */ + if (blkdev->feature_persistent) { + g_tree_destroy(blkdev->persistent_gnts); + } + while (!QLIST_EMPTY(&blkdev->freelist)) { ioreq = QLIST_FIRST(&blkdev->freelist); QLIST_REMOVE(ioreq, list); @@ -357,10 +357,10 @@ void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); target_ulong cppr = args[0]; - icp_set_cppr(spapr->icp, env->cpu_index, cppr); + icp_set_cppr(spapr->icp, cs->cpu_index, cppr); return H_SUCCESS; } @@ -376,14 +376,13 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, icp_set_mfrr(spapr->icp, server, mfrr); return H_SUCCESS; - } static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; - uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index); + CPUState *cs = CPU(cpu); + uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); args[0] = xirr; return H_SUCCESS; @@ -392,10 +391,10 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); target_ulong xirr = args[0]; - icp_eoi(spapr->icp, env->cpu_index, xirr); + icp_eoi(spapr->icp, cs->cpu_index, xirr); return H_SUCCESS; } @@ -525,14 +524,16 @@ static void xics_reset(void *opaque) struct icp_state *xics_system_init(int nr_irqs) { CPUPPCState *env; + CPUState *cpu; int max_server_num; struct icp_state *icp; struct ics_state *ics; max_server_num = -1; for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index > max_server_num) { - max_server_num = env->cpu_index; + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index > max_server_num) { + max_server_num = cpu->cpu_index; } } @@ -541,7 +542,8 @@ struct icp_state *xics_system_init(int nr_irqs) icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); for (env = first_cpu; env != NULL; env = env->next_cpu) { - struct icp_server_state *ss = &icp->ss[env->cpu_index]; + cpu = CPU(ppc_env_get_cpu(env)); + struct icp_server_state *ss = &icp->ss[cpu->cpu_index]; switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_POWER7: diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 439e88deb4..249e0464f2 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -354,7 +354,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags); #endif CPUArchState *cpu_copy(CPUArchState *env); -CPUArchState *qemu_get_cpu(int cpu); #define CPU_DUMP_CODE 0x00010000 #define CPU_DUMP_FPU 0x00020000 /* dump FPU register state, not just integer */ diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index b22b4c6255..d0cf85a83c 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -193,11 +193,7 @@ typedef struct CPUWatchpoint { int exception_index; \ \ CPUArchState *next_cpu; /* next CPU sharing TB cache */ \ - int cpu_index; /* CPU index (informative) */ \ uint32_t host_tid; /* host thread ID */ \ - int numa_node; /* NUMA node this cpu is belonging to */ \ - int nr_cores; /* number of cores within this CPU package */ \ - int nr_threads;/* number of threads within this CPU */ \ int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ void *opaque; \ diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 668de66000..49231feb29 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -35,7 +35,8 @@ static inline int cpu_index(CPUArchState *env) #if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) return env->host_tid; #else - return env->cpu_index + 1; + CPUState *cpu = ENV_GET_CPU(env); + return cpu->cpu_index + 1; #endif } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index fbacb2756b..773caf9fa1 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -57,6 +57,10 @@ struct kvm_run; /** * CPUState: + * @cpu_index: CPU index (informative). + * @nr_cores: Number of cores within this CPU package. + * @nr_threads: Number of threads within this CPU. + * @numa_node: NUMA node this CPU is belonging to. * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. @@ -69,6 +73,10 @@ struct CPUState { DeviceState parent_obj; /*< public >*/ + int nr_cores; + int nr_threads; + int numa_node; + struct QemuThread *thread; #ifdef _WIN32 HANDLE hThread; @@ -89,6 +97,7 @@ struct CPUState { struct kvm_run *kvm_run; /* TODO Move common fields from CPUArchState here. */ + int cpu_index; /* used by alpha TCG */ }; @@ -147,5 +156,15 @@ bool cpu_is_stopped(CPUState *cpu); */ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); +/** + * qemu_get_cpu: + * @index: The CPUState@cpu_index value of the CPU to obtain. + * + * Gets a CPU matching @index. + * + * Returns: The CPU or %NULL if there is no matching CPU. + */ +CPUState *qemu_get_cpu(int index); + #endif diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 3db19ffdac..6bdd51373e 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -17,10 +17,25 @@ #include <errno.h> #include "config-host.h" #include "qemu/queue.h" +#include "qom/cpu.h" #ifdef CONFIG_KVM #include <linux/kvm.h> #include <linux/kvm_para.h> +#else +/* These constants must never be used at runtime if kvm_enabled() is false. + * They exist so we don't need #ifdefs around KVM-specific code that already + * checks kvm_enabled() properly. + */ +#define KVM_CPUID_SIGNATURE 0 +#define KVM_CPUID_FEATURES 0 +#define KVM_FEATURE_CLOCKSOURCE 0 +#define KVM_FEATURE_NOP_IO_DELAY 0 +#define KVM_FEATURE_MMU_OP 0 +#define KVM_FEATURE_CLOCKSOURCE2 0 +#define KVM_FEATURE_ASYNC_PF 0 +#define KVM_FEATURE_STEAL_TIME 0 +#define KVM_FEATURE_PV_EOI 0 #endif extern int kvm_allowed; @@ -120,9 +135,9 @@ int kvm_has_many_ioeventfds(void); int kvm_has_gsi_routing(void); int kvm_has_intx_set_mask(void); -#ifdef NEED_CPU_H -int kvm_init_vcpu(CPUArchState *env); +int kvm_init_vcpu(CPUState *cpu); +#ifdef NEED_CPU_H int kvm_cpu_exec(CPUArchState *env); #if !defined(CONFIG_USER_ONLY) @@ -214,16 +214,15 @@ static void kvm_reset_vcpu(void *opaque) kvm_arch_reset_vcpu(cpu); } -int kvm_init_vcpu(CPUArchState *env) +int kvm_init_vcpu(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); KVMState *s = kvm_state; long mmap_size; int ret; DPRINTF("kvm_init_vcpu\n"); - ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index); + ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, cpu->cpu_index); if (ret < 0) { DPRINTF("kvm_create_vcpu failed\n"); goto err; diff --git a/kvm-stub.c b/kvm-stub.c index 81f8967180..47f8dca7d5 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -24,7 +24,7 @@ bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; -int kvm_init_vcpu(CPUArchState *env) +int kvm_init_vcpu(CPUState *cpu) { return -ENOSYS; } @@ -872,9 +872,11 @@ EventInfoList *qmp_query_events(Error **errp) int monitor_set_cpu(int cpu_index) { CPUArchState *env; + CPUState *cpu; - for(env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index == cpu_index) { + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); + if (cpu->cpu_index == cpu_index) { cur_mon->mon_cpu = env; return 0; } @@ -893,7 +895,8 @@ static CPUArchState *mon_get_cpu(void) int monitor_get_cpu_index(void) { - return mon_get_cpu()->cpu_index; + CPUState *cpu = ENV_GET_CPU(mon_get_cpu()); + return cpu->cpu_index; } static void do_info_registers(Monitor *mon) @@ -1783,13 +1786,15 @@ static void do_info_numa(Monitor *mon) { int i; CPUArchState *env; + CPUState *cpu; monitor_printf(mon, "%d nodes\n", nb_numa_nodes); for (i = 0; i < nb_numa_nodes; i++) { monitor_printf(mon, "node %d cpus:", i); for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->numa_node == i) { - monitor_printf(mon, " %d", env->cpu_index); + cpu = ENV_GET_CPU(env); + if (cpu->numa_node == i) { + monitor_printf(mon, " %d", cpu->cpu_index); } } monitor_printf(mon, "\n"); @@ -1991,6 +1996,7 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) { X86CPU *cpu; CPUX86State *cenv; + CPUState *cs; int cpu_index = qdict_get_int(qdict, "cpu_index"); int bank = qdict_get_int(qdict, "bank"); uint64_t status = qdict_get_int(qdict, "status"); @@ -2004,7 +2010,8 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) } for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { cpu = x86_env_get_cpu(cenv); - if (cenv->cpu_index == cpu_index) { + cs = CPU(cpu); + if (cs->cpu_index == cpu_index) { cpu_x86_inject_mce(mon, cpu, bank, status, mcg_status, addr, misc, flags); break; diff --git a/qga/channel-posix.c b/qga/channel-posix.c index ca9e4aaaf9..e65dda3822 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -46,6 +46,7 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel, ret = ga_channel_client_add(c, client_fd); if (ret) { g_warning("error setting up connection"); + close(client_fd); goto out; } accepted = true; @@ -140,19 +141,21 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod ); if (fd == -1) { g_critical("error opening channel: %s", strerror(errno)); - exit(EXIT_FAILURE); + return false; } #ifdef CONFIG_SOLARIS ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI); if (ret == -1) { g_critical("error setting event mask for channel: %s", strerror(errno)); - exit(EXIT_FAILURE); + close(fd); + return false; } #endif ret = ga_channel_client_add(c, fd); if (ret) { g_critical("error adding channel to main loop"); + close(fd); return false; } break; @@ -162,7 +165,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { g_critical("error opening channel: %s", strerror(errno)); - exit(EXIT_FAILURE); + return false; } tcgetattr(fd, &tio); /* set up serial port for non-canonical, dumb byte streaming */ @@ -182,7 +185,9 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod tcsetattr(fd, TCSANOW, &tio); ret = ga_channel_client_add(c, fd); if (ret) { - g_error("error adding channel to main loop"); + g_critical("error adding channel to main loop"); + close(fd); + return false; } break; } diff --git a/qga/main.c b/qga/main.c index a9b968c507..db281a508b 100644 --- a/qga/main.c +++ b/qga/main.c @@ -261,13 +261,26 @@ void ga_set_response_delimited(GAState *s) s->delimit_response = true; } +static FILE *ga_open_logfile(const char *logfile) +{ + FILE *f; + + f = fopen(logfile, "a"); + if (!f) { + return NULL; + } + + qemu_set_cloexec(fileno(f)); + return f; +} + #ifndef _WIN32 static bool ga_open_pidfile(const char *pidfile) { int pidfd; char pidstr[32]; - pidfd = open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); + pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); if (pidfd == -1 || lockf(pidfd, F_TLOCK, 0)) { g_critical("Cannot lock pid file, %s", strerror(errno)); if (pidfd != -1) { @@ -276,7 +289,7 @@ static bool ga_open_pidfile(const char *pidfile) return false; } - if (ftruncate(pidfd, 0) || lseek(pidfd, 0, SEEK_SET)) { + if (ftruncate(pidfd, 0)) { g_critical("Failed to truncate pid file"); goto fail; } @@ -286,10 +299,12 @@ static bool ga_open_pidfile(const char *pidfile) goto fail; } + /* keep pidfile open & locked forever */ return true; fail: unlink(pidfile); + close(pidfd); return false; } #else /* _WIN32 */ @@ -402,7 +417,7 @@ void ga_unset_frozen(GAState *s) * in a frozen state at start up, do it now */ if (s->deferred_options.log_filepath) { - s->log_file = fopen(s->deferred_options.log_filepath, "a"); + s->log_file = ga_open_logfile(s->deferred_options.log_filepath); if (!s->log_file) { s->log_file = stderr; } @@ -605,6 +620,7 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data) if (!s->virtio) { return false; } + /* fall through */ case G_IO_STATUS_AGAIN: /* virtio causes us to spin here when no process is attached to * host-side chardev. sleep a bit to mitigate this @@ -884,7 +900,7 @@ int main(int argc, char **argv) become_daemon(pid_filepath); } if (log_filepath) { - FILE *log_file = fopen(log_filepath, "a"); + FILE *log_file = ga_open_logfile(log_filepath); if (!log_file) { g_critical("unable to open specified log file: %s", strerror(errno)); diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index ed0eb698c6..d91d903256 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -31,7 +31,7 @@ # # Since: 1.1 # ## -{ 'command': 'guest-sync-delimited' +{ 'command': 'guest-sync-delimited', 'data': { 'id': 'int' }, 'returns': 'int' } @@ -69,7 +69,7 @@ # # Since: 0.15.0 ## -{ 'command': 'guest-sync' +{ 'command': 'guest-sync', 'data': { 'id': 'int' }, 'returns': 'int' } diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 5cb40b7ab6..f687b95c63 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1579,7 +1579,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) case 0x3C: /* WHAMI */ tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, cpu_index)); + -offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index)); break; default: diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 94536bb0cc..07588a13b2 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -64,7 +64,7 @@ static void arm_cpu_reset(CPUState *s) CPUARMState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-arm/helper.c b/target-arm/helper.c index 66ab78e3f1..37c34a11c4 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -902,7 +902,8 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { static int mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { - uint32_t mpidr = env->cpu_index; + CPUState *cs = CPU(arm_env_get_cpu(env)); + uint32_t mpidr = cs->cpu_index; /* We don't support setting cluster ID ([8..11]) * so these bits always RAZ. */ diff --git a/target-cris/cpu.c b/target-cris/cpu.c index c596609bd4..3f64a5747e 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -35,7 +35,7 @@ static void cris_cpu_reset(CPUState *s) uint32_t vr; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 78bd61e18f..333745b456 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -95,6 +95,17 @@ static const char *ext3_feature_name[] = { NULL, NULL, NULL, NULL, }; +static const char *ext4_feature_name[] = { + NULL, NULL, "xstore", "xstore-en", + NULL, NULL, "xcrypt", "xcrypt-en", + "ace2", "ace2-en", "phe", "phe-en", + "pmm", "pmm-en", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + static const char *kvm_feature_name[] = { "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", NULL, @@ -124,6 +135,47 @@ static const char *cpuid_7_0_ebx_feature_name[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; +typedef struct FeatureWordInfo { + const char **feat_names; + uint32_t cpuid_eax; /* Input EAX for CPUID */ + int cpuid_reg; /* R_* register constant */ +} FeatureWordInfo; + +static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + [FEAT_1_EDX] = { + .feat_names = feature_name, + .cpuid_eax = 1, .cpuid_reg = R_EDX, + }, + [FEAT_1_ECX] = { + .feat_names = ext_feature_name, + .cpuid_eax = 1, .cpuid_reg = R_ECX, + }, + [FEAT_8000_0001_EDX] = { + .feat_names = ext2_feature_name, + .cpuid_eax = 0x80000001, .cpuid_reg = R_EDX, + }, + [FEAT_8000_0001_ECX] = { + .feat_names = ext3_feature_name, + .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX, + }, + [FEAT_C000_0001_EDX] = { + .feat_names = ext4_feature_name, + .cpuid_eax = 0xC0000001, .cpuid_reg = R_EDX, + }, + [FEAT_KVM] = { + .feat_names = kvm_feature_name, + .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, + }, + [FEAT_SVM] = { + .feat_names = svm_feature_name, + .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, + }, + [FEAT_7_0_EBX] = { + .feat_names = cpuid_7_0_ebx_feature_name, + .cpuid_eax = 7, .cpuid_reg = R_EBX, + }, +}; + const char *get_register_name_32(unsigned int reg) { static const char *reg_names[CPU_NB_REGS32] = { @@ -148,9 +200,7 @@ const char *get_register_name_32(unsigned int reg) typedef struct model_features_t { uint32_t *guest_feat; uint32_t *host_feat; - const char **flag_names; - uint32_t cpuid; - int reg; + FeatureWord feat_word; } model_features_t; int check_cpuid = 0; @@ -159,7 +209,6 @@ int enforce_cpuid = 0; #if defined(CONFIG_KVM) static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) | (1 << KVM_FEATURE_NOP_IO_DELAY) | - (1 << KVM_FEATURE_MMU_OP) | (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_STEAL_TIME) | @@ -272,23 +321,20 @@ static bool lookup_feature(uint32_t *pval, const char *s, const char *e, return found; } -static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features, - uint32_t *ext_features, - uint32_t *ext2_features, - uint32_t *ext3_features, - uint32_t *kvm_features, - uint32_t *svm_features, - uint32_t *cpuid_7_0_ebx_features) +static void add_flagname_to_bitmaps(const char *flagname, + FeatureWordArray words) { - if (!lookup_feature(features, flagname, NULL, feature_name) && - !lookup_feature(ext_features, flagname, NULL, ext_feature_name) && - !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) && - !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) && - !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) && - !lookup_feature(svm_features, flagname, NULL, svm_feature_name) && - !lookup_feature(cpuid_7_0_ebx_features, flagname, NULL, - cpuid_7_0_ebx_feature_name)) - fprintf(stderr, "CPU feature %s not found\n", flagname); + FeatureWord w; + for (w = 0; w < FEATURE_WORDS; w++) { + FeatureWordInfo *wi = &feature_word_info[w]; + if (wi->feat_names && + lookup_feature(&words[w], flagname, NULL, wi->feat_names)) { + break; + } + } + if (w == FEATURE_WORDS) { + fprintf(stderr, "CPU feature %s not found\n", flagname); + } } typedef struct x86_def_t { @@ -952,55 +998,69 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) #endif /* CONFIG_KVM */ } -static int unavailable_host_feature(struct model_features_t *f, uint32_t mask) +static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask) { int i; for (i = 0; i < 32; ++i) if (1 << i & mask) { - const char *reg = get_register_name_32(f->reg); + const char *reg = get_register_name_32(f->cpuid_reg); assert(reg); fprintf(stderr, "warning: host doesn't support requested feature: " "CPUID.%02XH:%s%s%s [bit %d]\n", - f->cpuid, reg, - f->flag_names[i] ? "." : "", - f->flag_names[i] ? f->flag_names[i] : "", i); + f->cpuid_eax, reg, + f->feat_names[i] ? "." : "", + f->feat_names[i] ? f->feat_names[i] : "", i); break; } return 0; } -/* best effort attempt to inform user requested cpu flags aren't making - * their way to the guest. +/* Check if all requested cpu flags are making their way to the guest + * + * Returns 0 if all flags are supported by the host, non-zero otherwise. * * This function may be called only if KVM is enabled. */ -static int kvm_check_features_against_host(x86_def_t *guest_def) +static int kvm_check_features_against_host(X86CPU *cpu) { + CPUX86State *env = &cpu->env; x86_def_t host_def; uint32_t mask; int rv, i; struct model_features_t ft[] = { - {&guest_def->features, &host_def.features, - feature_name, 0x00000001, R_EDX}, - {&guest_def->ext_features, &host_def.ext_features, - ext_feature_name, 0x00000001, R_ECX}, - {&guest_def->ext2_features, &host_def.ext2_features, - ext2_feature_name, 0x80000001, R_EDX}, - {&guest_def->ext3_features, &host_def.ext3_features, - ext3_feature_name, 0x80000001, R_ECX} + {&env->cpuid_features, &host_def.features, + FEAT_1_EDX }, + {&env->cpuid_ext_features, &host_def.ext_features, + FEAT_1_ECX }, + {&env->cpuid_ext2_features, &host_def.ext2_features, + FEAT_8000_0001_EDX }, + {&env->cpuid_ext3_features, &host_def.ext3_features, + FEAT_8000_0001_ECX }, + {&env->cpuid_ext4_features, &host_def.ext4_features, + FEAT_C000_0001_EDX }, + {&env->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features, + FEAT_7_0_EBX }, + {&env->cpuid_svm_features, &host_def.svm_features, + FEAT_SVM }, + {&env->cpuid_kvm_features, &host_def.kvm_features, + FEAT_KVM }, }; assert(kvm_enabled()); kvm_cpu_fill_host(&host_def); - for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) - for (mask = 1; mask; mask <<= 1) + for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) { + FeatureWord w = ft[i].feat_word; + FeatureWordInfo *wi = &feature_word_info[w]; + for (mask = 1; mask; mask <<= 1) { if (*ft[i].guest_feat & mask && !(*ft[i].host_feat & mask)) { - unavailable_host_feature(&ft[i], mask); - rv = 1; - } + unavailable_host_feature(wi, mask); + rv = 1; + } + } + } return rv; } @@ -1284,35 +1344,19 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) unsigned int i; char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ - uint32_t plus_features = 0, plus_ext_features = 0; - uint32_t plus_ext2_features = 0, plus_ext3_features = 0; - uint32_t plus_kvm_features = kvm_default_features, plus_svm_features = 0; - uint32_t plus_7_0_ebx_features = 0; + FeatureWordArray plus_features = { 0 }; /* Features to be removed */ - uint32_t minus_features = 0, minus_ext_features = 0; - uint32_t minus_ext2_features = 0, minus_ext3_features = 0; - uint32_t minus_kvm_features = 0, minus_svm_features = 0; - uint32_t minus_7_0_ebx_features = 0; + FeatureWordArray minus_features = { 0 }; uint32_t numvalue; - add_flagname_to_bitmaps("hypervisor", &plus_features, - &plus_ext_features, &plus_ext2_features, &plus_ext3_features, - &plus_kvm_features, &plus_svm_features, &plus_7_0_ebx_features); - featurestr = features ? strtok(features, ",") : NULL; while (featurestr) { char *val; if (featurestr[0] == '+') { - add_flagname_to_bitmaps(featurestr + 1, &plus_features, - &plus_ext_features, &plus_ext2_features, - &plus_ext3_features, &plus_kvm_features, - &plus_svm_features, &plus_7_0_ebx_features); + add_flagname_to_bitmaps(featurestr + 1, plus_features); } else if (featurestr[0] == '-') { - add_flagname_to_bitmaps(featurestr + 1, &minus_features, - &minus_ext_features, &minus_ext2_features, - &minus_ext3_features, &minus_kvm_features, - &minus_svm_features, &minus_7_0_ebx_features); + add_flagname_to_bitmaps(featurestr + 1, minus_features); } else if ((val = strchr(featurestr, '='))) { *val = 0; val++; if (!strcmp(featurestr, "family")) { @@ -1412,24 +1456,22 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } featurestr = strtok(NULL, ","); } - x86_cpu_def->features |= plus_features; - x86_cpu_def->ext_features |= plus_ext_features; - x86_cpu_def->ext2_features |= plus_ext2_features; - x86_cpu_def->ext3_features |= plus_ext3_features; - x86_cpu_def->kvm_features |= plus_kvm_features; - x86_cpu_def->svm_features |= plus_svm_features; - x86_cpu_def->cpuid_7_0_ebx_features |= plus_7_0_ebx_features; - x86_cpu_def->features &= ~minus_features; - x86_cpu_def->ext_features &= ~minus_ext_features; - x86_cpu_def->ext2_features &= ~minus_ext2_features; - x86_cpu_def->ext3_features &= ~minus_ext3_features; - x86_cpu_def->kvm_features &= ~minus_kvm_features; - x86_cpu_def->svm_features &= ~minus_svm_features; - x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features; - if (check_cpuid && kvm_enabled()) { - if (kvm_check_features_against_host(x86_cpu_def) && enforce_cpuid) - goto error; - } + x86_cpu_def->features |= plus_features[FEAT_1_EDX]; + x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX]; + x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX]; + x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX]; + x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX]; + x86_cpu_def->kvm_features |= plus_features[FEAT_KVM]; + x86_cpu_def->svm_features |= plus_features[FEAT_SVM]; + x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; + x86_cpu_def->features &= ~minus_features[FEAT_1_EDX]; + x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX]; + x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; + x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; + x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; + x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM]; + x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM]; + x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; return 0; error: @@ -1549,17 +1591,23 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) model_pieces = g_strsplit(cpu_model, ",", 2); if (!model_pieces[0]) { - goto error; + error_setg(&error, "Invalid/empty CPU model name"); + goto out; } name = model_pieces[0]; features = model_pieces[1]; if (cpu_x86_find_by_name(def, name) < 0) { - goto error; + error_setg(&error, "Unable to find CPU definition: %s", name); + goto out; } + def->kvm_features |= kvm_default_features; + def->ext_features |= CPUID_EXT_HYPERVISOR; + if (cpu_x86_parse_featurestr(def, features) < 0) { - goto error; + error_setg(&error, "Invalid cpu_model string format: %s", cpu_model); + goto out; } assert(def->vendor1); env->cpuid_vendor1 = def->vendor1; @@ -1584,17 +1632,15 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) "tsc-frequency", &error); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); + +out: + g_strfreev(model_pieces); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); error_free(error); - goto error; + return -1; } - - g_strfreev(model_pieces); return 0; -error: - g_strfreev(model_pieces); - return -1; } #if !defined(CONFIG_USER_ONLY) @@ -1691,8 +1737,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ *ecx = env->cpuid_ext_features; *edx = env->cpuid_features; - if (env->nr_cores * env->nr_threads > 1) { - *ebx |= (env->nr_cores * env->nr_threads) << 16; + if (cs->nr_cores * cs->nr_threads > 1) { + *ebx |= (cs->nr_cores * cs->nr_threads) << 16; *edx |= 1 << 28; /* HTT bit */ } break; @@ -1705,8 +1751,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 4: /* cache info: needed for Core compatibility */ - if (env->nr_cores > 1) { - *eax = (env->nr_cores - 1) << 26; + if (cs->nr_cores > 1) { + *eax = (cs->nr_cores - 1) << 26; } else { *eax = 0; } @@ -1725,8 +1771,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 2: /* L2 cache info */ *eax |= 0x0000143; - if (env->nr_threads > 1) { - *eax |= (env->nr_threads - 1) << 14; + if (cs->nr_threads > 1) { + *eax |= (cs->nr_threads - 1) << 14; } *ebx = 0x3c0003f; *ecx = 0x0000fff; @@ -1830,7 +1876,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * discards multiple thread information if it is set. * So dont set it here for Intel to make Linux guests happy. */ - if (env->nr_cores * env->nr_threads > 1) { + if (cs->nr_cores * cs->nr_threads > 1) { uint32_t tebx, tecx, tedx; get_cpuid_vendor(env, &tebx, &tecx, &tedx); if (tebx != CPUID_VENDOR_INTEL_1 || @@ -1878,8 +1924,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx = 0; *ecx = 0; *edx = 0; - if (env->nr_cores * env->nr_threads > 1) { - *ecx |= (env->nr_cores * env->nr_threads) - 1; + if (cs->nr_cores * cs->nr_threads > 1) { + *ecx |= (cs->nr_cores * cs->nr_threads) - 1; } break; case 0x8000000A: @@ -1936,7 +1982,7 @@ static void x86_cpu_reset(CPUState *s) int i; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP); } @@ -2010,7 +2056,7 @@ static void x86_cpu_reset(CPUState *s) #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ - if (env->cpu_index == 0) { + if (s->cpu_index == 0) { apic_designate_bsp(env->apic_state); } @@ -2128,6 +2174,11 @@ void x86_cpu_realize(Object *obj, Error **errp) #ifdef CONFIG_KVM filter_features_for_kvm(cpu); #endif + if (check_cpuid && kvm_check_features_against_host(cpu) + && enforce_cpuid) { + error_setg(errp, "Host's CPU doesn't support requested features"); + return; + } } #ifndef CONFIG_USER_ONLY @@ -2148,6 +2199,7 @@ void x86_cpu_realize(Object *obj, Error **errp) static void x86_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); X86CPU *cpu = X86_CPU(obj); CPUX86State *env = &cpu->env; static int inited; @@ -2179,7 +2231,7 @@ static void x86_cpu_initfn(Object *obj) x86_cpuid_get_tsc_freq, x86_cpuid_set_tsc_freq, NULL, NULL, NULL); - env->cpuid_apic_id = env->cpu_index; + env->cpuid_apic_id = cs->cpu_index; /* init various static tables used in TCG mode */ if (tcg_enabled() && !inited) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e56921bbe3..4e091cdec3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -231,6 +231,12 @@ #define DR7_TYPE_SHIFT 16 #define DR7_LEN_SHIFT 18 #define DR7_FIXED_1 0x00000400 +#define DR7_LOCAL_BP_MASK 0x55 +#define DR7_MAX_BP 4 +#define DR7_TYPE_BP_INST 0x0 +#define DR7_TYPE_DATA_WR 0x1 +#define DR7_TYPE_IO_RW 0x2 +#define DR7_TYPE_DATA_RW 0x3 #define PG_PRESENT_BIT 0 #define PG_RW_BIT 1 @@ -361,6 +367,21 @@ #define MSR_VM_HSAVE_PA 0xc0010117 +/* CPUID feature words */ +typedef enum FeatureWord { + FEAT_1_EDX, /* CPUID[1].EDX */ + FEAT_1_ECX, /* CPUID[1].ECX */ + FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */ + FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ + FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ + FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ + FEAT_SVM, /* CPUID[8000_000A].EDX */ + FEATURE_WORDS, +} FeatureWord; + +typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + /* cpuid_features bits */ #define CPUID_FP87 (1 << 0) #define CPUID_VME (1 << 1) @@ -993,9 +1014,20 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, #define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault void cpu_x86_set_a20(CPUX86State *env, int a20_state); -static inline int hw_breakpoint_enabled(unsigned long dr7, int index) +static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 1; +} + +static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 2; + +} +static inline bool hw_breakpoint_enabled(unsigned long dr7, int index) { - return (dr7 >> (index * 2)) & 3; + return hw_global_breakpoint_enabled(dr7, index) || + hw_local_breakpoint_enabled(dr7, index); } static inline int hw_breakpoint_type(unsigned long dr7, int index) @@ -1011,7 +1043,7 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index) void hw_breakpoint_insert(CPUX86State *env, int index); void hw_breakpoint_remove(CPUX86State *env, int index); -int check_hw_breakpoints(CPUX86State *env, int force_dr6_update); +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update); void breakpoint_handler(CPUX86State *env); /* will be suppressed */ diff --git a/target-i386/helper.c b/target-i386/helper.c index dca1360962..547c25ee9d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -966,30 +966,35 @@ hwaddr cpu_get_phys_page_debug(CPUX86State *env, target_ulong addr) void hw_breakpoint_insert(CPUX86State *env, int index) { - int type, err = 0; + int type = 0, err = 0; switch (hw_breakpoint_type(env->dr[7], index)) { - case 0: - if (hw_breakpoint_enabled(env->dr[7], index)) + case DR7_TYPE_BP_INST: + if (hw_breakpoint_enabled(env->dr[7], index)) { err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU, &env->cpu_breakpoint[index]); + } break; - case 1: + case DR7_TYPE_DATA_WR: type = BP_CPU | BP_MEM_WRITE; - goto insert_wp; - case 2: - /* No support for I/O watchpoints yet */ break; - case 3: + case DR7_TYPE_IO_RW: + /* No support for I/O watchpoints yet */ + break; + case DR7_TYPE_DATA_RW: type = BP_CPU | BP_MEM_ACCESS; - insert_wp: + break; + } + + if (type != 0) { err = cpu_watchpoint_insert(env, env->dr[index], hw_breakpoint_len(env->dr[7], index), type, &env->cpu_watchpoint[index]); - break; } - if (err) + + if (err) { env->cpu_breakpoint[index] = NULL; + } } void hw_breakpoint_remove(CPUX86State *env, int index) @@ -997,39 +1002,60 @@ void hw_breakpoint_remove(CPUX86State *env, int index) if (!env->cpu_breakpoint[index]) return; switch (hw_breakpoint_type(env->dr[7], index)) { - case 0: - if (hw_breakpoint_enabled(env->dr[7], index)) + case DR7_TYPE_BP_INST: + if (hw_breakpoint_enabled(env->dr[7], index)) { cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]); + } break; - case 1: - case 3: + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]); break; - case 2: + case DR7_TYPE_IO_RW: /* No support for I/O watchpoints yet */ break; } } -int check_hw_breakpoints(CPUX86State *env, int force_dr6_update) +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update) { target_ulong dr6; - int reg, type; - int hit_enabled = 0; + int reg; + bool hit_enabled = false; dr6 = env->dr[6] & ~0xf; - for (reg = 0; reg < 4; reg++) { - type = hw_breakpoint_type(env->dr[7], reg); - if ((type == 0 && env->dr[reg] == env->eip) || - ((type & 1) && env->cpu_watchpoint[reg] && - (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) { + for (reg = 0; reg < DR7_MAX_BP; reg++) { + bool bp_match = false; + bool wp_match = false; + + switch (hw_breakpoint_type(env->dr[7], reg)) { + case DR7_TYPE_BP_INST: + if (env->dr[reg] == env->eip) { + bp_match = true; + } + break; + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: + if (env->cpu_watchpoint[reg] && + env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) { + wp_match = true; + } + break; + case DR7_TYPE_IO_RW: + break; + } + if (bp_match || wp_match) { dr6 |= 1 << reg; - if (hw_breakpoint_enabled(env->dr[7], reg)) - hit_enabled = 1; + if (hw_breakpoint_enabled(env->dr[7], reg)) { + hit_enabled = true; + } } } - if (hit_enabled || force_dr6_update) + + if (hit_enabled || force_dr6_update) { env->dr[6] = dr6; + } + return hit_enabled; } @@ -1040,16 +1066,17 @@ void breakpoint_handler(CPUX86State *env) if (env->watchpoint_hit) { if (env->watchpoint_hit->flags & BP_CPU) { env->watchpoint_hit = NULL; - if (check_hw_breakpoints(env, 0)) + if (check_hw_breakpoints(env, false)) { raise_exception(env, EXCP01_DB); - else + } else { cpu_resume_from_signal(env, NULL); + } } } else { QTAILQ_FOREACH(bp, &env->breakpoints, entry) if (bp->pc == env->eip) { if (bp->flags & BP_CPU) { - check_hw_breakpoints(env, 1); + check_hw_breakpoints(env, true); raise_exception(env, EXCP01_DB); } break; @@ -1059,7 +1086,7 @@ void breakpoint_handler(CPUX86State *env) typedef struct MCEInjectionParams { Monitor *mon; - CPUX86State *env; + X86CPU *cpu; int bank; uint64_t status; uint64_t mcg_status; @@ -1071,7 +1098,8 @@ typedef struct MCEInjectionParams { static void do_inject_x86_mce(void *data) { MCEInjectionParams *params = data; - CPUX86State *cenv = params->env; + CPUX86State *cenv = ¶ms->cpu->env; + CPUState *cpu = CPU(params->cpu); uint64_t *banks = cenv->mce_banks + 4 * params->bank; cpu_synchronize_state(cenv); @@ -1094,7 +1122,7 @@ static void do_inject_x86_mce(void *data) if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) { monitor_printf(params->mon, "CPU %d: Uncorrected error reporting disabled\n", - cenv->cpu_index); + cpu->cpu_index); return; } @@ -1106,7 +1134,7 @@ static void do_inject_x86_mce(void *data) monitor_printf(params->mon, "CPU %d: Uncorrected error reporting disabled for" " bank %d\n", - cenv->cpu_index, params->bank); + cpu->cpu_index, params->bank); return; } @@ -1115,7 +1143,7 @@ static void do_inject_x86_mce(void *data) monitor_printf(params->mon, "CPU %d: Previous MCE still in progress, raising" " triple fault\n", - cenv->cpu_index); + cpu->cpu_index); qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); qemu_system_reset_request(); return; @@ -1148,7 +1176,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, CPUX86State *cenv = &cpu->env; MCEInjectionParams params = { .mon = mon, - .env = cenv, + .cpu = cpu, .bank = bank, .status = status, .mcg_status = mcg_status, @@ -1188,7 +1216,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, if (cenv == env) { continue; } - params.env = env; + params.cpu = x86_env_get_cpu(env); run_on_cpu(CPU(cpu), do_inject_x86_mce, ¶ms); } } diff --git a/target-i386/machine.c b/target-i386/machine.c index 8354572c7b..8df6a6b645 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -265,10 +265,11 @@ static int cpu_post_load(void *opaque, int version_id) cpu_breakpoint_remove_all(env, BP_CPU); cpu_watchpoint_remove_all(env, BP_CPU); - for (i = 0; i < 4; i++) + for (i = 0; i < DR7_MAX_BP; i++) { hw_breakpoint_insert(env, i); - + } tlb_flush(env, 1); + return 0; } diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index db3126b79b..b6d574019a 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -110,7 +110,7 @@ void helper_into(CPUX86State *env, int next_eip_addend) void helper_single_step(CPUX86State *env) { #ifndef CONFIG_USER_ONLY - check_hw_breakpoints(env, 1); + check_hw_breakpoints(env, true); env->dr[6] |= DR6_BS; #endif raise_exception(env, EXCP01_DB); @@ -197,11 +197,11 @@ void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0) env->dr[reg] = t0; hw_breakpoint_insert(env, reg); } else if (reg == 7) { - for (i = 0; i < 4; i++) { + for (i = 0; i < DR7_MAX_BP; i++) { hw_breakpoint_remove(env, i); } env->dr[7] = t0; - for (i = 0; i < 4; i++) { + for (i = 0; i < DR7_MAX_BP; i++) { hw_breakpoint_insert(env, i); } } else { @@ -580,14 +580,17 @@ void helper_monitor(CPUX86State *env, target_ulong ptr) void helper_mwait(CPUX86State *env, int next_eip_addend) { + CPUState *cpu; + if ((uint32_t)ECX != 0) { raise_exception(env, EXCP0D_GPF); } cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0); EIP += next_eip_addend; + cpu = CPU(x86_env_get_cpu(env)); /* XXX: not complete but not completely erroneous */ - if (env->cpu_index != 0 || env->next_cpu != NULL) { + if (cpu->cpu_index != 0 || env->next_cpu != NULL) { /* more than one CPU: do not sleep because another CPU may wake this one */ } else { diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index c2a99ee9bc..3247deeb60 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -465,13 +465,14 @@ static void switch_tss(CPUX86State *env, int tss_selector, #ifndef CONFIG_USER_ONLY /* reset local breakpoints */ - if (env->dr[7] & 0x55) { - for (i = 0; i < 4; i++) { - if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) { + if (env->dr[7] & DR7_LOCAL_BP_MASK) { + for (i = 0; i < DR7_MAX_BP; i++) { + if (hw_local_breakpoint_enabled(env->dr[7], i) && + !hw_global_breakpoint_enabled(env->dr[7], i)) { hw_breakpoint_remove(env, i); } } - env->dr[7] &= ~0x55; + env->dr[7] &= ~DR7_LOCAL_BP_MASK; } #endif } diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index caa4834075..eca2dca427 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -30,7 +30,7 @@ static void lm32_cpu_reset(CPUState *s) CPULM32State *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 3e70bb0ead..ce89674a08 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -35,7 +35,7 @@ static void m68k_cpu_reset(CPUState *s) CPUM68KState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 34b3a9bfdc..0f858fd869 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -32,7 +32,7 @@ static void mb_cpu_reset(CPUState *s) CPUMBState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 004406232b..10ff46d6a7 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -29,8 +29,16 @@ static void mips_cpu_reset(CPUState *s) MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu); CPUMIPSState *env = &cpu->env; + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); + log_cpu_state(env, 0); + } + mcc->parent_reset(s); + memset(env, 0, offsetof(CPUMIPSState, breakpoints)); + tlb_flush(env, 1); + cpu_state_reset(env); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d5c61e8a84..1bca4a159e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -572,17 +572,23 @@ static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) } } -/* tc should point to an int with the value of the global TC index. - This function will transform it into a local index within the - returned CPUMIPSState. - - FIXME: This code assumes that all VPEs have the same number of TCs, +/** + * mips_cpu_map_tc: + * @env: CPU from which mapping is performed. + * @tc: Should point to an int with the value of the global TC index. + * + * This function will transform @tc into a local index within the + * returned #CPUMIPSState. + */ +/* FIXME: This code assumes that all VPEs have the same number of TCs, which depends on runtime setup. Can probably be fixed by walking the list of CPUMIPSStates. */ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) { - CPUMIPSState *other; - int vpe_idx, nr_threads = env->nr_threads; + MIPSCPU *cpu; + CPUState *cs; + CPUState *other_cs; + int vpe_idx; int tc_idx = *tc; if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) { @@ -591,10 +597,15 @@ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) return env; } - vpe_idx = tc_idx / nr_threads; - *tc = tc_idx % nr_threads; - other = qemu_get_cpu(vpe_idx); - return other ? other : env; + cs = CPU(mips_env_get_cpu(env)); + vpe_idx = tc_idx / cs->nr_threads; + *tc = tc_idx % cs->nr_threads; + other_cs = qemu_get_cpu(vpe_idx); + if (other_cs == NULL) { + return env; + } + cpu = MIPS_CPU(other_cs); + return &cpu->env; } /* The per VPE CP0_Status register shares some fields with the per TC diff --git a/target-mips/translate.c b/target-mips/translate.c index 6281e70471..206ba83401 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15878,13 +15878,10 @@ MIPSCPU *cpu_mips_init(const char *cpu_model) void cpu_state_reset(CPUMIPSState *env) { - if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); - log_cpu_state(env, 0); - } - - memset(env, 0, offsetof(CPUMIPSState, breakpoints)); - tlb_flush(env, 1); +#ifndef CONFIG_USER_ONLY + MIPSCPU *cpu = mips_env_get_cpu(env); + CPUState *cs = CPU(cpu); +#endif /* Reset registers to their default values */ env->CP0_PRid = env->cpu_model->CP0_PRid; @@ -15953,7 +15950,7 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_Random = env->tlb->nb_tlb - 1; env->tlb->tlb_in_use = env->tlb->nb_tlb; env->CP0_Wired = 0; - env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF); + env->CP0_EBase = 0x80000000 | (cs->cpu_index & 0x3FF); env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); /* vectored interrupts not implemented, timer on int 7, no performance counters. */ @@ -15976,13 +15973,13 @@ void cpu_state_reset(CPUMIPSState *env) /* Only TC0 on VPE 0 starts as active. */ for (i = 0; i < ARRAY_SIZE(env->tcs); i++) { - env->tcs[i].CP0_TCBind = env->cpu_index << CP0TCBd_CurVPE; + env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE; env->tcs[i].CP0_TCHalt = 1; } env->active_tc.CP0_TCHalt = 1; env->halted = 1; - if (!env->cpu_index) { + if (cs->cpu_index == 0) { /* VPE0 starts up enabled. */ env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index ba35b17581..56544d8ab5 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -27,7 +27,7 @@ static void openrisc_cpu_reset(CPUState *s) OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu); if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", cpu->env.cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(&cpu->env, 0); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 4846acfc0d..19e9f25b19 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -766,8 +766,9 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) dprintf("injected interrupt %d\n", irq); r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); - if (r < 0) - printf("cpu %d fail inject %x\n", env->cpu_index, irq); + if (r < 0) { + printf("cpu %d fail inject %x\n", cs->cpu_index, irq); + } /* Always wake up soon in case the interrupt was level based */ qemu_mod_timer(idle_timer, qemu_get_clock_ns(vm_clock) + @@ -1275,14 +1276,15 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) } } -int kvmppc_fixup_cpu(CPUPPCState *env) +int kvmppc_fixup_cpu(PowerPCCPU *cpu) { + CPUState *cs = CPU(cpu); int smt; /* Adjust cpu index for SMT */ smt = kvmppc_smt_threads(); - env->cpu_index = (env->cpu_index / smp_threads) * smt - + (env->cpu_index % smp_threads); + cs->cpu_index = (cs->cpu_index / smp_threads) * smt + + (cs->cpu_index % smp_threads); return 0; } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 4b2172360a..3db21fc889 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -33,7 +33,7 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ -int kvmppc_fixup_cpu(CPUPPCState *env); +int kvmppc_fixup_cpu(PowerPCCPU *cpu); #else @@ -122,7 +122,7 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env) #endif /* !CONFIG_USER_ONLY */ -static inline int kvmppc_fixup_cpu(CPUPPCState *env) +static inline int kvmppc_fixup_cpu(PowerPCCPU *cpu) { return -1; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2b03756ee1..3f199c4bb9 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10005,8 +10005,10 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) return 0; } -static int ppc_fixup_cpu(CPUPPCState *env) +static int ppc_fixup_cpu(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + /* TCG doesn't (yet) emulate some groups of instructions that * are implemented on some otherwise supported CPUs (e.g. VSX * and decimal floating point instructions on POWER7). We @@ -10036,12 +10038,12 @@ static void ppc_cpu_realize(Object *obj, Error **errp) Error *local_err = NULL; if (kvm_enabled()) { - if (kvmppc_fixup_cpu(env) != 0) { + if (kvmppc_fixup_cpu(cpu) != 0) { error_setg(errp, "Unable to virtualize selected CPU with KVM"); return; } } else { - if (ppc_fixup_cpu(env) != 0) { + if (ppc_fixup_cpu(cpu) != 0) { error_setg(errp, "Unable to emulate selected CPU with TCG"); return; } @@ -10460,7 +10462,7 @@ static void ppc_cpu_reset(CPUState *s) target_ulong msr; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 249f063d94..2ed23127d1 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -33,7 +33,7 @@ static void s390_cpu_reset(CPUState *s) CPUS390XState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index a1a177fa88..e4858a03ed 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -31,7 +31,7 @@ static void superh_cpu_reset(CPUState *s) CPUSH4State *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 882d30642a..f404aa8b5f 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -31,7 +31,7 @@ static void sparc_cpu_reset(CPUState *s) CPUSPARCState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/util/oslib-win32.c b/util/oslib-win32.c index e7e283e875..640194c0cf 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -71,7 +71,9 @@ void *qemu_vmalloc(size_t size) void qemu_vfree(void *ptr) { trace_qemu_vfree(ptr); - VirtualFree(ptr, 0, MEM_RELEASE); + if (ptr) { + VirtualFree(ptr, 0, MEM_RELEASE); + } } /* FIXME: add proper locking */ @@ -585,9 +585,7 @@ static void xen_reset_vcpu(void *opaque) void xen_vcpu_init(void) { - CPUArchState *first_cpu; - - if ((first_cpu = qemu_get_cpu(0))) { + if (first_cpu != NULL) { qemu_register_reset(xen_reset_vcpu, first_cpu); xen_reset_vcpu(first_cpu); } |