summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch_init.c49
-rw-r--r--audio/spiceaudio.c27
-rw-r--r--block/qcow2.c21
-rw-r--r--block/qed.c6
-rw-r--r--block/vhdx-log.c4
-rw-r--r--block/vhdx.c8
-rw-r--r--block/vmdk.c48
-rw-r--r--exec.c35
-rw-r--r--hw/arm/pxa2xx.c2
-rw-r--r--hw/block/dataplane/virtio-blk.c2
-rw-r--r--hw/char/lm32_juart.c2
-rw-r--r--hw/char/lm32_uart.c2
-rw-r--r--hw/char/milkymist-uart.c2
-rw-r--r--hw/cris/Makefile.objs1
-rw-r--r--hw/cris/axis_dev88.c7
-rw-r--r--hw/cris/pic_cpu.c47
-rw-r--r--hw/display/milkymist-vgafb_template.h2
-rw-r--r--hw/display/qxl.c16
-rw-r--r--hw/i386/bios-linker-loader.c3
-rw-r--r--hw/lm32/lm32_boards.c10
-rw-r--r--hw/lm32/milkymist.c5
-rw-r--r--hw/misc/lm32_sys.c8
-rw-r--r--hw/ppc/ppc4xx_devs.c2
-rw-r--r--hw/s390x/Makefile.objs1
-rw-r--r--hw/s390x/event-facility.c6
-rw-r--r--hw/s390x/sclp.c53
-rw-r--r--hw/s390x/sclpcpu.c112
-rw-r--r--include/exec/ram_addr.h3
-rw-r--r--include/exec/softmmu_template.h5
-rw-r--r--include/hw/cris/etraxfs.h2
-rw-r--r--include/hw/ptimer.h10
-rw-r--r--include/hw/s390x/event-facility.h5
-rw-r--r--include/hw/s390x/sclp.h75
-rw-r--r--include/migration/migration.h1
-rw-r--r--include/migration/page_cache.h4
-rw-r--r--include/migration/vmstate.h8
-rw-r--r--include/qemu/readline.h3
-rw-r--r--kvm-all.c7
-rw-r--r--linux-headers/asm-x86/hyperv.h3
-rw-r--r--linux-headers/linux/kvm.h1
-rw-r--r--linux-user/signal.c8
-rw-r--r--migration.c18
-rw-r--r--monitor.c3
-rw-r--r--page_cache.c34
-rw-r--r--pc-bios/QEMU,tcx.binbin1242 -> 1410 bytes
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/bios-256k.binbin262144 -> 262144 bytes
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--pc-bios/openbios-ppcbin729880 -> 729912 bytes
-rw-r--r--pc-bios/openbios-sparc32bin381488 -> 381512 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1598328 -> 1598376 bytes
-rw-r--r--pc-bios/vgabios-cirrus.binbin36864 -> 36864 bytes
-rw-r--r--pc-bios/vgabios-qxl.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios-stdvga.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios-vmware.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios.binbin36864 -> 36864 bytes
-rw-r--r--qemu-doc.texi23
-rw-r--r--qemu-img.texi23
-rw-r--r--qemu-io.c3
-rw-r--r--roms/Makefile22
m---------roms/openbios0
m---------roms/seabios0
-rw-r--r--spice-qemu-char.c25
-rw-r--r--target-cris/cpu.c26
-rw-r--r--target-cris/cpu.h4
-rw-r--r--target-cris/helper.c5
-rw-r--r--target-i386/cpu-qom.h1
-rw-r--r--target-i386/cpu.c148
-rw-r--r--target-i386/cpu.h4
-rw-r--r--target-i386/kvm.c109
-rw-r--r--target-i386/machine.c67
-rw-r--r--target-lm32/TODO2
-rw-r--r--target-lm32/cpu-qom.h6
-rw-r--r--target-lm32/cpu.c188
-rw-r--r--target-lm32/cpu.h34
-rw-r--r--target-lm32/helper.c218
-rw-r--r--target-lm32/helper.h4
-rw-r--r--target-lm32/op_helper.c75
-rw-r--r--target-lm32/translate.c193
-rw-r--r--target-s390x/cpu.h17
-rw-r--r--target-s390x/kvm.c136
-rw-r--r--tcg/s390/tcg-target.c19
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/libqtest.c45
-rwxr-xr-xtests/qemu-iotests/04028
-rwxr-xr-xtests/qemu-iotests/0712
-rw-r--r--tests/tcg/lm32/Makefile8
-rw-r--r--util/osdep.c1
88 files changed, 1412 insertions, 698 deletions
diff --git a/arch_init.c b/arch_init.c
index 77912e7..80574a0 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -164,20 +164,22 @@ static struct {
uint8_t *encoded_buf;
/* buffer for storing page content */
uint8_t *current_buf;
- /* buffer used for XBZRLE decoding */
- uint8_t *decoded_buf;
/* Cache for XBZRLE */
PageCache *cache;
} XBZRLE = {
.encoded_buf = NULL,
.current_buf = NULL,
- .decoded_buf = NULL,
.cache = NULL,
};
-
+/* buffer used for XBZRLE decoding */
+static uint8_t *xbzrle_decoded_buf;
int64_t xbzrle_cache_resize(int64_t new_size)
{
+ if (new_size < TARGET_PAGE_SIZE) {
+ return -1;
+ }
+
if (XBZRLE.cache != NULL) {
return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
TARGET_PAGE_SIZE;
@@ -282,7 +284,9 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
if (!last_stage) {
- cache_insert(XBZRLE.cache, current_addr, current_data);
+ if (cache_insert(XBZRLE.cache, current_addr, current_data) == -1) {
+ return -1;
+ }
}
acct_info.xbzrle_cache_miss++;
return -1;
@@ -602,6 +606,12 @@ uint64_t ram_bytes_total(void)
return total;
}
+void free_xbzrle_decoded_buf(void)
+{
+ g_free(xbzrle_decoded_buf);
+ xbzrle_decoded_buf = NULL;
+}
+
static void migration_end(void)
{
if (migration_bitmap) {
@@ -615,8 +625,9 @@ static void migration_end(void)
g_free(XBZRLE.cache);
g_free(XBZRLE.encoded_buf);
g_free(XBZRLE.current_buf);
- g_free(XBZRLE.decoded_buf);
XBZRLE.cache = NULL;
+ XBZRLE.encoded_buf = NULL;
+ XBZRLE.current_buf = NULL;
}
}
@@ -655,8 +666,22 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
DPRINTF("Error creating cache\n");
return -1;
}
- XBZRLE.encoded_buf = g_malloc0(TARGET_PAGE_SIZE);
- XBZRLE.current_buf = g_malloc(TARGET_PAGE_SIZE);
+
+ /* We prefer not to abort if there is no memory */
+ XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
+ if (!XBZRLE.encoded_buf) {
+ DPRINTF("Error allocating encoded_buf\n");
+ return -1;
+ }
+
+ XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
+ if (!XBZRLE.current_buf) {
+ DPRINTF("Error allocating current_buf\n");
+ g_free(XBZRLE.encoded_buf);
+ XBZRLE.encoded_buf = NULL;
+ return -1;
+ }
+
acct_clear();
}
@@ -807,8 +832,8 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
unsigned int xh_len;
int xh_flags;
- if (!XBZRLE.decoded_buf) {
- XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE);
+ if (!xbzrle_decoded_buf) {
+ xbzrle_decoded_buf = g_malloc(TARGET_PAGE_SIZE);
}
/* extract RLE header */
@@ -825,10 +850,10 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
return -1;
}
/* load data and decode */
- qemu_get_buffer(f, XBZRLE.decoded_buf, xh_len);
+ qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
/* decode RLE */
- ret = xbzrle_decode_buffer(XBZRLE.decoded_buf, xh_len, host,
+ ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
TARGET_PAGE_SIZE);
if (ret == -1) {
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 5af436c..fceee50 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -25,8 +25,17 @@
#include "audio.h"
#include "audio_int.h"
-#define LINE_IN_SAMPLES 1024
-#define LINE_OUT_SAMPLES 1024
+#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
+#define LINE_OUT_SAMPLES (480 * 4)
+#else
+#define LINE_OUT_SAMPLES (256 * 4)
+#endif
+
+#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
+#define LINE_IN_SAMPLES (480 * 4)
+#else
+#define LINE_IN_SAMPLES (256 * 4)
+#endif
typedef struct SpiceRateCtl {
int64_t start_ticks;
@@ -111,7 +120,11 @@ static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
struct audsettings settings;
+#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
+ settings.freq = spice_server_get_best_playback_rate(NULL);
+#else
settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
+#endif
settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
settings.fmt = AUD_FMT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS;
@@ -122,6 +135,9 @@ static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
out->sin.base.sif = &playback_sif.base;
qemu_spice_add_interface (&out->sin.base);
+#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
+ spice_server_set_playback_rate(&out->sin, settings.freq);
+#endif
return 0;
}
@@ -232,7 +248,11 @@ static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
struct audsettings settings;
+#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
+ settings.freq = spice_server_get_best_record_rate(NULL);
+#else
settings.freq = SPICE_INTERFACE_RECORD_FREQ;
+#endif
settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
settings.fmt = AUD_FMT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS;
@@ -243,6 +263,9 @@ static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
in->sin.base.sif = &record_sif.base;
qemu_spice_add_interface (&in->sin.base);
+#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
+ spice_server_set_record_rate(&in->sin, settings.freq);
+#endif
return 0;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 2da62b8..99a1ad1 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1689,26 +1689,6 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options,
return ret;
}
-static int qcow2_make_empty(BlockDriverState *bs)
-{
-#if 0
- /* XXX: not correct */
- BDRVQcowState *s = bs->opaque;
- uint32_t l1_length = s->l1_size * sizeof(uint64_t);
- int ret;
-
- memset(s->l1_table, 0, l1_length);
- if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0)
- return -1;
- ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
- if (ret < 0)
- return ret;
-
- l2_cache_reset(bs);
-#endif
- return 0;
-}
-
static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
{
@@ -2252,7 +2232,6 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_get_block_status = qcow2_co_get_block_status,
.bdrv_set_key = qcow2_set_key,
- .bdrv_make_empty = qcow2_make_empty,
.bdrv_co_readv = qcow2_co_readv,
.bdrv_co_writev = qcow2_co_writev,
diff --git a/block/qed.c b/block/qed.c
index 694e6e2..b9ca7ac 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -731,11 +731,6 @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
return cb.status;
}
-static int bdrv_qed_make_empty(BlockDriverState *bs)
-{
- return -ENOTSUP;
-}
-
static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
{
return acb->common.bs->opaque;
@@ -1617,7 +1612,6 @@ static BlockDriver bdrv_qed = {
.bdrv_create = bdrv_qed_create,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
- .bdrv_make_empty = bdrv_qed_make_empty,
.bdrv_aio_readv = bdrv_qed_aio_readv,
.bdrv_aio_writev = bdrv_qed_aio_writev,
.bdrv_co_write_zeroes = bdrv_qed_co_write_zeroes,
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
index 8c9ae0d..02755b8 100644
--- a/block/vhdx-log.c
+++ b/block/vhdx-log.c
@@ -965,8 +965,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
cpu_to_le32s((uint32_t *)(buffer + 4));
/* now write to the log */
- vhdx_log_write_sectors(bs, &s->log, &sectors_written, buffer,
- desc_sectors + sectors);
+ ret = vhdx_log_write_sectors(bs, &s->log, &sectors_written, buffer,
+ desc_sectors + sectors);
if (ret < 0) {
goto exit;
}
diff --git a/block/vhdx.c b/block/vhdx.c
index 9ee0a61..55689cf 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -374,7 +374,7 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
inactive_header->log_guid = *log_guid;
}
- vhdx_write_header(bs->file, inactive_header, header_offset, true);
+ ret = vhdx_write_header(bs->file, inactive_header, header_offset, true);
if (ret < 0) {
goto exit;
}
@@ -1810,13 +1810,13 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options,
creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL,
&creator_items, NULL);
signature = cpu_to_le64(VHDX_FILE_SIGNATURE);
- bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature));
+ ret = bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature));
if (ret < 0) {
goto delete_and_exit;
}
if (creator) {
- bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET + sizeof(signature), creator,
- creator_items * sizeof(gunichar2));
+ ret = bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET + sizeof(signature),
+ creator, creator_items * sizeof(gunichar2));
if (ret < 0) {
goto delete_and_exit;
}
diff --git a/block/vmdk.c b/block/vmdk.c
index 99ca60f..e809e2e 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1942,6 +1942,53 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
return info;
}
+static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
+ BdrvCheckMode fix)
+{
+ BDRVVmdkState *s = bs->opaque;
+ VmdkExtent *extent = NULL;
+ int64_t sector_num = 0;
+ int64_t total_sectors = bdrv_getlength(bs) / BDRV_SECTOR_SIZE;
+ int ret;
+ uint64_t cluster_offset;
+
+ if (fix) {
+ return -ENOTSUP;
+ }
+
+ for (;;) {
+ if (sector_num >= total_sectors) {
+ return 0;
+ }
+ extent = find_extent(s, sector_num, extent);
+ if (!extent) {
+ fprintf(stderr,
+ "ERROR: could not find extent for sector %" PRId64 "\n",
+ sector_num);
+ break;
+ }
+ ret = get_cluster_offset(bs, extent, NULL,
+ sector_num << BDRV_SECTOR_BITS,
+ 0, &cluster_offset);
+ if (ret == VMDK_ERROR) {
+ fprintf(stderr,
+ "ERROR: could not get cluster_offset for sector %"
+ PRId64 "\n", sector_num);
+ break;
+ }
+ if (ret == VMDK_OK && cluster_offset >= bdrv_getlength(extent->file)) {
+ fprintf(stderr,
+ "ERROR: cluster offset for sector %"
+ PRId64 " points after EOF\n", sector_num);
+ break;
+ }
+ sector_num += extent->cluster_sectors;
+ }
+
+ result->corruptions++;
+ return 0;
+}
+
static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
{
int i;
@@ -2015,6 +2062,7 @@ static BlockDriver bdrv_vmdk = {
.instance_size = sizeof(BDRVVmdkState),
.bdrv_probe = vmdk_probe,
.bdrv_open = vmdk_open,
+ .bdrv_check = vmdk_check,
.bdrv_reopen_prepare = vmdk_reopen_prepare,
.bdrv_read = vmdk_co_read,
.bdrv_write = vmdk_co_write,
diff --git a/exec.c b/exec.c
index 9ad0a4b..be93ebb 100644
--- a/exec.c
+++ b/exec.c
@@ -325,7 +325,7 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
hwaddr *plen, bool resolve_subpage)
{
MemoryRegionSection *section;
- Int128 diff, diff_page;
+ Int128 diff;
section = address_space_lookup_region(d, addr, resolve_subpage);
/* Compute offset within MemoryRegionSection */
@@ -334,13 +334,23 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
/* Compute offset within MemoryRegion */
*xlat = addr + section->offset_within_region;
- diff_page = int128_make64(((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr);
diff = int128_sub(section->mr->size, int128_make64(addr));
- diff = int128_min(diff, diff_page);
*plen = int128_get64(int128_min(diff, int128_make64(*plen)));
return section;
}
+static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
+{
+ if (memory_region_is_ram(mr)) {
+ return !(is_write && mr->readonly);
+ }
+ if (memory_region_is_romd(mr)) {
+ return !is_write;
+ }
+
+ return false;
+}
+
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
hwaddr *xlat, hwaddr *plen,
bool is_write)
@@ -351,7 +361,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
hwaddr len = *plen;
for (;;) {
- section = address_space_translate_internal(as->dispatch, addr, &addr, &len, true);
+ section = address_space_translate_internal(as->dispatch, addr, &addr, plen, true);
mr = section->mr;
if (!mr->iommu_ops) {
@@ -370,6 +380,11 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
as = iotlb.target_as;
}
+ if (memory_access_is_direct(mr, is_write)) {
+ hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
+ len = MIN(page, len);
+ }
+
*plen = len;
*xlat = addr;
return mr;
@@ -1925,18 +1940,6 @@ static void invalidate_and_set_dirty(hwaddr addr,
xen_modified_memory(addr, length);
}
-static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
-{
- if (memory_region_is_ram(mr)) {
- return !(is_write && mr->readonly);
- }
- if (memory_region_is_romd(mr)) {
- return !is_write;
- }
-
- return false;
-}
-
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
{
unsigned access_size_max = mr->ops->valid.max_access_size;
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 02b7016..25ec549 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1448,7 +1448,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
VMSTATE_UINT8(data, PXA2xxI2CState),
VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
- vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState *),
+ vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 456d437..2237edb 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -145,7 +145,7 @@ static void do_get_id_cmd(VirtIOBlockDataPlane *s,
{
char id[VIRTIO_BLK_ID_BYTES];
- /* Serial number not NUL-terminated when shorter than buffer */
+ /* Serial number not NUL-terminated when longer than buffer */
strncpy(id, s->blk->serial ? s->blk->serial : "", sizeof(id));
iov_from_buf(iov, iov_cnt, 0, id, sizeof(id));
complete_request_early(s, elem, inhdr, VIRTIO_BLK_S_OK);
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index 252fe46..380cb5d 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -75,7 +75,7 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
s->jtx = jtx;
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
}
}
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index 85d7265..84c2549 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -177,7 +177,7 @@ static void uart_write(void *opaque, hwaddr addr,
switch (addr) {
case R_RXTX:
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
}
break;
case R_IER:
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index 2c52a0f..da51f82 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -124,7 +124,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
switch (addr) {
case R_RXTX:
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
}
s->regs[R_STAT] |= STAT_TX_EVT;
break;
diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs
index 776db7c..7624173 100644
--- a/hw/cris/Makefile.objs
+++ b/hw/cris/Makefile.objs
@@ -1,3 +1,2 @@
-obj-y += pic_cpu.o
obj-y += boot.o
obj-y += axis_dev88.o
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
index 5524088..645e45c 100644
--- a/hw/cris/axis_dev88.c
+++ b/hw/cris/axis_dev88.c
@@ -254,7 +254,7 @@ void axisdev88_init(QEMUMachineInitArgs *args)
DeviceState *dev;
SysBusDevice *s;
DriveInfo *nand;
- qemu_irq irq[30], nmi[2], *cpu_irq;
+ qemu_irq irq[30], nmi[2];
void *etraxfs_dmac;
struct etraxfs_dma_client *dma_eth;
int i;
@@ -296,15 +296,14 @@ void axisdev88_init(QEMUMachineInitArgs *args)
&gpio_state.iomem);
- cpu_irq = cris_pic_init_cpu(env);
dev = qdev_create(NULL, "etraxfs,pic");
/* FIXME: Is there a proper way to signal vectors to the CPU core? */
qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, 0x3001c000);
- sysbus_connect_irq(s, 0, cpu_irq[0]);
- sysbus_connect_irq(s, 1, cpu_irq[1]);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ));
+ sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI));
for (i = 0; i < 30; i++) {
irq[i] = qdev_get_gpio_in(dev, i);
}
diff --git a/hw/cris/pic_cpu.c b/hw/cris/pic_cpu.c
deleted file mode 100644
index bd47bf1..0000000
--- a/hw/cris/pic_cpu.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * QEMU CRIS CPU interrupt wrapper logic.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/cris/etraxfs.h"
-
-#define D(x)
-
-static void cris_pic_cpu_handler(void *opaque, int irq, int level)
-{
- CRISCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
-
- if (level) {
- cpu_interrupt(cs, type);
- } else {
- cpu_reset_interrupt(cs, type);
- }
-}
-
-qemu_irq *cris_pic_init_cpu(CPUCRISState *env)
-{
- return qemu_allocate_irqs(cris_pic_cpu_handler, cris_env_get_cpu(env), 2);
-}
diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h
index e0036e1..4883780 100644
--- a/hw/display/milkymist-vgafb_template.h
+++ b/hw/display/milkymist-vgafb_template.h
@@ -61,7 +61,7 @@ static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
uint8_t r, g, b;
while (width--) {
- memcpy(&rgb565, s, sizeof(rgb565));
+ rgb565 = lduw_be_p(s);
r = ((rgb565 >> 11) & 0x1f) << 3;
g = ((rgb565 >> 5) & 0x3f) << 2;
b = ((rgb565 >> 0) & 0x1f) << 3;
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index e4f172e..334c271 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -19,6 +19,7 @@
*/
#include <zlib.h>
+#include <stdint.h>
#include "qemu-common.h"
#include "qemu/timer.h"
@@ -1126,6 +1127,7 @@ static void qxl_reset_state(PCIQXLDevice *d)
d->num_free_res = 0;
d->last_release = NULL;
memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+ qxl_update_irq(d);
}
static void qxl_soft_reset(PCIQXLDevice *d)
@@ -1360,14 +1362,16 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
{
QXLDevSurfaceCreate surface;
QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
- int size;
- int requested_height = le32_to_cpu(sc->height);
+ uint32_t requested_height = le32_to_cpu(sc->height);
int requested_stride = le32_to_cpu(sc->stride);
- size = abs(requested_stride) * requested_height;
- if (size > qxl->vgamem_size) {
- qxl_set_guest_bug(qxl, "%s: requested primary larger then framebuffer"
- " size", __func__);
+ if (requested_stride == INT32_MIN ||
+ abs(requested_stride) * (uint64_t)requested_height
+ > qxl->vgamem_size) {
+ qxl_set_guest_bug(qxl, "%s: requested primary larger than framebuffer"
+ " stride %d x height %" PRIu32 " > %" PRIu32,
+ __func__, requested_stride, requested_height,
+ qxl->vgamem_size);
return;
}
diff --git a/hw/i386/bios-linker-loader.c b/hw/i386/bios-linker-loader.c
index fd23611..aa56184 100644
--- a/hw/i386/bios-linker-loader.c
+++ b/hw/i386/bios-linker-loader.c
@@ -18,11 +18,10 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu-common.h"
#include "bios-linker-loader.h"
#include "hw/nvram/fw_cfg.h"
-#include <string.h>
-#include <assert.h>
#include "qemu/bswap.h"
#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
index c032bb8..5e22e9b 100644
--- a/hw/lm32/lm32_boards.c
+++ b/hw/lm32/lm32_boards.c
@@ -101,6 +101,11 @@ static void lm32_evr_init(QEMUMachineInitArgs *args)
cpu_model = "lm32-full";
}
cpu = cpu_lm32_init(cpu_model);
+ if (cpu == NULL) {
+ fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);
+ exit(1);
+ }
+
env = &cpu->env;
reset_info->cpu = cpu;
@@ -198,6 +203,11 @@ static void lm32_uclinux_init(QEMUMachineInitArgs *args)
cpu_model = "lm32-full";
}
cpu = cpu_lm32_init(cpu_model);
+ if (cpu == NULL) {
+ fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);
+ exit(1);
+ }
+
env = &cpu->env;
reset_info->cpu = cpu;
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index 15053c4..baf234c 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -108,6 +108,11 @@ milkymist_init(QEMUMachineInitArgs *args)
cpu_model = "lm32-full";
}
cpu = cpu_lm32_init(cpu_model);
+ if (cpu == NULL) {
+ fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);
+ exit(1);
+ }
+
env = &cpu->env;
reset_info->cpu = cpu;
diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c
index 9bdb781..e394f2e 100644
--- a/hw/misc/lm32_sys.c
+++ b/hw/misc/lm32_sys.c
@@ -42,7 +42,7 @@ enum {
R_MAX
};
-#define MAX_TESTNAME_LEN 16
+#define MAX_TESTNAME_LEN 32
#define TYPE_LM32_SYS "lm32-sys"
#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS)
@@ -80,7 +80,11 @@ static void sys_write(void *opaque, hwaddr addr,
case R_PASSFAIL:
s->regs[addr] = value;
testname = (char *)s->testname;
- qemu_log("TC %-16s %s\n", testname, (value) ? "FAILED" : "OK");
+ fprintf(stderr, "TC %-*s %s\n", MAX_TESTNAME_LEN,
+ testname, (value) ? "FAILED" : "OK");
+ if (value) {
+ cpu_dump_state(qemu_get_cpu(0), stderr, fprintf, 0);
+ }
break;
case R_TESTNAME:
s->regs[addr] = value;
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 239aada..9160ee7 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -27,8 +27,6 @@
#include "qemu/log.h"
#include "exec/address-spaces.h"
-//#define DEBUG_MMIO
-//#define DEBUG_UNASSIGNED
#define DEBUG_UIC
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 77e1218..1ba6c3a 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -3,6 +3,7 @@ obj-y += s390-virtio-hcall.o
obj-y += sclp.o
obj-y += event-facility.o
obj-y += sclpquiesce.o
+obj-y += sclpcpu.o
obj-y += ipl.o
obj-y += css.o
obj-y += s390-virtio-ccw.o
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 25951a0..a73c0b9 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -32,6 +32,8 @@ struct SCLPEventFacility {
unsigned int receive_mask;
};
+SCLPEvent cpu_hotplug;
+
/* return true if any child has event pending set */
static bool event_pending(SCLPEventFacility *ef)
{
@@ -335,6 +337,10 @@ static int init_event_facility(S390SCLPDevice *sdev)
}
qdev_init_nofail(quiesce);
+ object_initialize(&cpu_hotplug, sizeof(cpu_hotplug), TYPE_SCLP_CPU_HOTPLUG);
+ qdev_set_parent_bus(DEVICE(&cpu_hotplug), BUS(&event_facility->sbus));
+ object_property_set_bool(OBJECT(&cpu_hotplug), true, "realized", NULL);
+
return 0;
}
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 86d6ae0..4e0c564 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -15,6 +15,7 @@
#include "cpu.h"
#include "sysemu/kvm.h"
#include "exec/memory.h"
+#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
@@ -31,7 +32,26 @@ static inline S390SCLPDevice *get_event_facility(void)
static void read_SCP_info(SCCB *sccb)
{
ReadInfo *read_info = (ReadInfo *) sccb;
+ CPUState *cpu;
int shift = 0;
+ int cpu_count = 0;
+ int i = 0;
+
+ CPU_FOREACH(cpu) {
+ cpu_count++;
+ }
+
+ /* CPU information */
+ read_info->entries_cpu = cpu_to_be16(cpu_count);
+ read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries));
+ read_info->highest_cpu = cpu_to_be16(max_cpus);
+
+ for (i = 0; i < cpu_count; i++) {
+ read_info->entries[i].address = i;
+ read_info->entries[i].type = 0;
+ }
+
+ read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO);
while ((ram_size >> (20 + shift)) > 65535) {
shift++;
@@ -41,15 +61,46 @@ static void read_SCP_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
+/* Provide information about the CPU */
+static void sclp_read_cpu_info(SCCB *sccb)
+{
+ ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
+ CPUState *cpu;
+ int cpu_count = 0;
+ int i = 0;
+
+ CPU_FOREACH(cpu) {
+ cpu_count++;
+ }
+
+ cpu_info->nr_configured = cpu_to_be16(cpu_count);
+ cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries));
+ cpu_info->nr_standby = cpu_to_be16(0);
+
+ /* The standby offset is 16-byte for each CPU */
+ cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured
+ + cpu_info->nr_configured*sizeof(CPUEntry));
+
+ for (i = 0; i < cpu_count; i++) {
+ cpu_info->entries[i].address = i;
+ cpu_info->entries[i].type = 0;
+ }
+
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
+}
+
static void sclp_execute(SCCB *sccb, uint64_t code)
{
S390SCLPDevice *sdev = get_event_facility();
- switch (code) {
+ switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
case SCLP_CMDW_READ_SCP_INFO_FORCED:
read_SCP_info(sccb);
break;
+ case SCLP_CMDW_READ_CPU_INFO:
+ sclp_read_cpu_info(sccb);
+ break;
default:
sdev->sclp_command_handler(sdev->ef, sccb, code);
break;
diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c
new file mode 100644
index 0000000..b9c238a
--- /dev/null
+++ b/hw/s390x/sclpcpu.c
@@ -0,0 +1,112 @@
+/*
+ * SCLP event type
+ * Signal CPU - Trigger SCLP interrupt for system CPU configure or
+ * de-configure
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * Thang Pham <thang.pham@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+#include "sysemu/sysemu.h"
+#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
+#include "cpu.h"
+#include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
+
+typedef struct ConfigMgtData {
+ EventBufferHeader ebh;
+ uint8_t reserved;
+ uint8_t event_qualifier;
+} QEMU_PACKED ConfigMgtData;
+
+static qemu_irq irq_cpu_hotplug; /* Only used in this file */
+
+#define EVENT_QUAL_CPU_CHANGE 1
+
+void raise_irq_cpu_hotplug(void)
+{
+ qemu_irq_raise(irq_cpu_hotplug);
+}
+
+static unsigned int send_mask(void)
+{
+ return SCLP_EVENT_MASK_CONFIG_MGT_DATA;
+}
+
+static unsigned int receive_mask(void)
+{
+ return 0;
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen)
+{
+ ConfigMgtData *cdata = (ConfigMgtData *) evt_buf_hdr;
+ if (*slen < sizeof(ConfigMgtData)) {
+ return 0;
+ }
+
+ /* Event is no longer pending */
+ if (!event->event_pending) {
+ return 0;
+ }
+ event->event_pending = false;
+
+ /* Event header data */
+ cdata->ebh.length = cpu_to_be16(sizeof(ConfigMgtData));
+ cdata->ebh.type = SCLP_EVENT_CONFIG_MGT_DATA;
+ cdata->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+
+ /* Trigger a rescan of CPUs by setting event qualifier */
+ cdata->event_qualifier = EVENT_QUAL_CPU_CHANGE;
+ *slen -= sizeof(ConfigMgtData);
+
+ return 1;
+}
+
+static void trigger_signal(void *opaque, int n, int level)
+{
+ SCLPEvent *event = opaque;
+ event->event_pending = true;
+
+ /* Trigger SCLP read operation */
+ sclp_service_interrupt(0);
+}
+
+static int irq_cpu_hotplug_init(SCLPEvent *event)
+{
+ irq_cpu_hotplug = *qemu_allocate_irqs(trigger_signal, event, 1);
+ return 0;
+}
+
+static void cpu_class_init(ObjectClass *oc, void *data)
+{
+ SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
+
+ k->init = irq_cpu_hotplug_init;
+ k->get_send_mask = send_mask;
+ k->get_receive_mask = receive_mask;
+ k->read_event_data = read_event_data;
+ k->write_event_data = NULL;
+}
+
+static const TypeInfo sclp_cpu_info = {
+ .name = "sclp-cpu-hotplug",
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPEvent),
+ .class_init = cpu_class_init,
+ .class_size = sizeof(SCLPEventClass),
+};
+
+static void sclp_cpu_register_types(void)
+{
+ type_register_static(&sclp_cpu_info);
+}
+
+type_init(sclp_cpu_register_types)
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 481a447..2edfa96 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -93,7 +93,8 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
/* start address is aligned at the start of a word? */
- if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
+ if ((((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) &&
+ (hpratio == 1)) {
long k;
long nr = BITS_TO_LONGS(pages);
diff --git a/include/exec/softmmu_template.h b/include/exec/softmmu_template.h
index c6a5440..8712dcd 100644
--- a/include/exec/softmmu_template.h
+++ b/include/exec/softmmu_template.h
@@ -30,23 +30,26 @@
#define SUFFIX q
#define LSUFFIX q
#define SDATA_TYPE int64_t
+#define DATA_TYPE uint64_t
#elif DATA_SIZE == 4
#define SUFFIX l
#define LSUFFIX l
#define SDATA_TYPE int32_t
+#define DATA_TYPE uint32_t
#elif DATA_SIZE == 2
#define SUFFIX w
#define LSUFFIX uw
#define SDATA_TYPE int16_t
+#define DATA_TYPE uint16_t
#elif DATA_SIZE == 1
#define SUFFIX b
#define LSUFFIX ub
#define SDATA_TYPE int8_t
+#define DATA_TYPE uint8_t
#else
#error unsupported data size
#endif
-#define DATA_TYPE glue(u, SDATA_TYPE)
/* For the benefit of TCG generated code, we want to avoid the complication
of ABI-specific return type promotion and always return a value extended
diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h
index ab30559..73a6134 100644
--- a/include/hw/cris/etraxfs.h
+++ b/include/hw/cris/etraxfs.h
@@ -28,8 +28,6 @@
#include "net/net.h"
#include "hw/cris/etraxfs_dma.h"
-qemu_irq *cris_pic_init_cpu(CPUCRISState *env);
-
/* Instantiate an ETRAXFS Ethernet MAC. */
static inline DeviceState *
etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr,
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index a33edf4..8ebacbb 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -27,14 +27,8 @@ void ptimer_stop(ptimer_state *s);
extern const VMStateDescription vmstate_ptimer;
-#define VMSTATE_PTIMER(_field, _state) { \
- .name = (stringify(_field)), \
- .version_id = (1), \
- .vmsd = &vmstate_ptimer, \
- .size = sizeof(ptimer_state *), \
- .flags = VMS_STRUCT|VMS_POINTER, \
- .offset = vmstate_offset_pointer(_state, _field, ptimer_state), \
-}
+#define VMSTATE_PTIMER(_field, _state) \
+ VMSTATE_STRUCT_POINTER_V(_field, _state, 1, vmstate_ptimer, ptimer_state)
#define VMSTATE_PTIMER_ARRAY(_f, _s, _n) \
VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(_f, _s, _n, 0, \
diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h
index 7ce7079..870edd4 100644
--- a/include/hw/s390x/event-facility.h
+++ b/include/hw/s390x/event-facility.h
@@ -17,10 +17,12 @@
#include <hw/qdev.h>
#include "qemu/thread.h"
+#include "hw/s390x/sclp.h"
/* SCLP event types */
#define SCLP_EVENT_OPRTNS_COMMAND 0x01
#define SCLP_EVENT_MESSAGE 0x02
+#define SCLP_EVENT_CONFIG_MGT_DATA 0x04
#define SCLP_EVENT_PMSGCMD 0x09
#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a
#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d
@@ -28,6 +30,7 @@
/* SCLP event masks */
#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008
#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040
+#define SCLP_EVENT_MASK_CONFIG_MGT_DATA 0x10000000
#define SCLP_EVENT_MASK_OP_CMD 0x80000000
#define SCLP_EVENT_MASK_MSG 0x40000000
#define SCLP_EVENT_MASK_PMSGCMD 0x00800000
@@ -43,6 +46,8 @@
#define SCLP_EVENT_GET_CLASS(obj) \
OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
+#define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug"
+
typedef struct WriteEventMask {
SCCBHeader h;
uint16_t _reserved;
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
index 231a38a..35112d9 100644
--- a/include/hw/s390x/sclp.h
+++ b/include/hw/s390x/sclp.h
@@ -17,21 +17,41 @@
#include <hw/sysbus.h>
#include <hw/qdev.h>
+#define SCLP_CMD_CODE_MASK 0xffff00ff
+
/* SCLP command codes */
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
+#define SCLP_READ_STORAGE_ELEMENT_INFO 0x00040001
+#define SCLP_ATTACH_STORAGE_ELEMENT 0x00080001
+#define SCLP_ASSIGN_STORAGE 0x000D0001
+#define SCLP_UNASSIGN_STORAGE 0x000C0001
#define SCLP_CMD_READ_EVENT_DATA 0x00770005
#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
#define SCLP_CMD_READ_EVENT_DATA 0x00770005
#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005
+/* SCLP Memory hotplug codes */
+#define SCLP_FC_ASSIGN_ATTACH_READ_STOR 0xE00000000000ULL
+#define SCLP_STARTING_SUBINCREMENT_ID 0x10001
+#define SCLP_INCREMENT_UNIT 0x10000
+#define MAX_AVAIL_SLOTS 32
+
+/* CPU hotplug SCLP codes */
+#define SCLP_HAS_CPU_INFO 0x0C00000000000000ULL
+#define SCLP_CMDW_READ_CPU_INFO 0x00010001
+#define SCLP_CMDW_CONFIGURE_CPU 0x00110001
+#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001
+
/* SCLP response codes */
#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010
#define SCLP_RC_NORMAL_COMPLETION 0x0020
+#define SCLP_RC_SCCB_BOUNDARY_VIOLATION 0x0100
#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0
#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340
#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300
+#define SCLP_RC_STANDBY_READ_COMPLETION 0x0410
#define SCLP_RC_INVALID_FUNCTION 0x40f0
#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0
#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0
@@ -71,12 +91,66 @@ typedef struct SCCBHeader {
#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
+/* CPU information */
+typedef struct CPUEntry {
+ uint8_t address;
+ uint8_t reserved0[13];
+ uint8_t type;
+ uint8_t reserved1;
+} QEMU_PACKED CPUEntry;
+
typedef struct ReadInfo {
SCCBHeader h;
uint16_t rnmax;
uint8_t rnsize;
+ uint8_t _reserved1[16 - 11]; /* 11-15 */
+ uint16_t entries_cpu; /* 16-17 */
+ uint16_t offset_cpu; /* 18-19 */
+ uint8_t _reserved2[24 - 20]; /* 20-23 */
+ uint8_t loadparm[8]; /* 24-31 */
+ uint8_t _reserved3[48 - 32]; /* 32-47 */
+ uint64_t facilities; /* 48-55 */
+ uint8_t _reserved0[100 - 56];
+ uint32_t rnsize2;
+ uint64_t rnmax2;
+ uint8_t _reserved4[120-112]; /* 112-119 */
+ uint16_t highest_cpu;
+ uint8_t _reserved5[128 - 122]; /* 122-127 */
+ struct CPUEntry entries[0];
} QEMU_PACKED ReadInfo;
+typedef struct ReadCpuInfo {
+ SCCBHeader h;
+ uint16_t nr_configured; /* 8-9 */
+ uint16_t offset_configured; /* 10-11 */
+ uint16_t nr_standby; /* 12-13 */
+ uint16_t offset_standby; /* 14-15 */
+ uint8_t reserved0[24-16]; /* 16-23 */
+ struct CPUEntry entries[0];
+} QEMU_PACKED ReadCpuInfo;
+
+typedef struct ReadStorageElementInfo {
+ SCCBHeader h;
+ uint16_t max_id;
+ uint16_t assigned;
+ uint16_t standby;
+ uint8_t _reserved0[16 - 14]; /* 14-15 */
+ uint32_t entries[0];
+} QEMU_PACKED ReadStorageElementInfo;
+
+typedef struct AttachStorageElement {
+ SCCBHeader h;
+ uint8_t _reserved0[10 - 8]; /* 8-9 */
+ uint16_t assigned;
+ uint8_t _reserved1[16 - 12]; /* 12-15 */
+ uint32_t entries[0];
+} QEMU_PACKED AttachStorageElement;
+
+typedef struct AssignStorage {
+ SCCBHeader h;
+ uint16_t rn;
+} QEMU_PACKED AssignStorage;
+
typedef struct SCCB {
SCCBHeader h;
char data[SCCB_DATA_LEN];
@@ -114,5 +188,6 @@ typedef struct S390SCLPDeviceClass {
void s390_sclp_init(void);
void sclp_service_interrupt(uint32_t sccb);
+void raise_irq_cpu_hotplug(void);
#endif
diff --git a/include/migration/migration.h b/include/migration/migration.h
index bfa3951..3e1e6c7 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -109,6 +109,7 @@ MigrationState *migrate_get_current(void);
uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_transferred(void);
uint64_t ram_bytes_total(void);
+void free_xbzrle_decoded_buf(void);
void acct_update_position(QEMUFile *f, size_t size, bool zero);
diff --git a/include/migration/page_cache.h b/include/migration/page_cache.h
index 87894fe..d156f0d 100644
--- a/include/migration/page_cache.h
+++ b/include/migration/page_cache.h
@@ -60,11 +60,13 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr);
* cache_insert: insert the page into the cache. the page cache
* will dup the data on insert. the previous value will be overwritten
*
+ * Returns -1 on error
+ *
* @cache pointer to the PageCache struct
* @addr: page address
* @pdata: pointer to the page
*/
-void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata);
+int cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata);
/**
* cache_resize: resize the page cache. In case of size reduction the extra
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index be193ba..fbd16a0 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -314,9 +314,9 @@ extern const VMStateInfo vmstate_info_bitmap;
.name = (stringify(_field)), \
.version_id = (_version), \
.vmsd = &(_vmsd), \
- .size = sizeof(_type), \
+ .size = sizeof(_type *), \
.flags = VMS_STRUCT|VMS_POINTER, \
- .offset = vmstate_offset_value(_state, _field, _type), \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
}
#define VMSTATE_STRUCT_POINTER_TEST_V(_field, _state, _test, _version, _vmsd, _type) { \
@@ -324,9 +324,9 @@ extern const VMStateInfo vmstate_info_bitmap;
.version_id = (_version), \
.field_exists = (_test), \
.vmsd = &(_vmsd), \
- .size = sizeof(_type), \
+ .size = sizeof(_type *), \
.flags = VMS_STRUCT|VMS_POINTER, \
- .offset = vmstate_offset_value(_state, _field, _type), \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
}
#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\
diff --git a/include/qemu/readline.h b/include/qemu/readline.h
index a89fe4a..49efe4e 100644
--- a/include/qemu/readline.h
+++ b/include/qemu/readline.h
@@ -5,7 +5,8 @@
#define READLINE_MAX_CMDS 64
#define READLINE_MAX_COMPLETIONS 256
-typedef void ReadLinePrintfFunc(void *opaque, const char *fmt, ...);
+typedef void GCC_FMT_ATTR(2, 3) ReadLinePrintfFunc(void *opaque,
+ const char *fmt, ...);
typedef void ReadLineFlushFunc(void *opaque);
typedef void ReadLineFunc(void *opaque, const char *str,
void *readline_opaque);
diff --git a/kvm-all.c b/kvm-all.c
index 9588fea..2ca9143 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1546,17 +1546,16 @@ static void kvm_handle_io(uint16_t port, void *data, int direction, int size,
static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
{
- fprintf(stderr, "KVM internal error.");
+ fprintf(stderr, "KVM internal error. Suberror: %d\n",
+ run->internal.suberror);
+
if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
int i;
- fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
for (i = 0; i < run->internal.ndata; ++i) {
fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
i, (uint64_t)run->internal.data[i]);
}
- } else {
- fprintf(stderr, "\n");
}
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
fprintf(stderr, "emulation failure\n");
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index b8f1c01..3b400ee 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -149,6 +149,9 @@
/* MSR used to read the per-partition time reference counter */
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
+/* A partition's reference time stamp counter (TSC) page */
+#define HV_X64_MSR_REFERENCE_TSC 0x40000021
+
/* MSR used to retrieve the TSC frequency */
#define HV_X64_MSR_TSC_FREQUENCY 0x40000022
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 5a49671..999fb13 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -674,6 +674,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_ARM_EL1_32BIT 93
#define KVM_CAP_SPAPR_MULTITCE 94
#define KVM_CAP_EXT_EMUL_CPUID 95
+#define KVM_CAP_HYPERV_TIME 96
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 01d7c39..82e8592 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3659,7 +3659,7 @@ struct target_sigcontext {
struct target_signal_frame {
struct target_sigcontext sc;
uint32_t extramask[TARGET_NSIG_WORDS - 1];
- uint8_t retcode[8]; /* Trampoline code. */
+ uint16_t retcode[4]; /* Trampoline code. */
};
struct rt_signal_frame {
@@ -3667,7 +3667,7 @@ struct rt_signal_frame {
void *puc;
siginfo_t info;
struct ucontext uc;
- uint8_t retcode[8]; /* Trampoline code. */
+ uint16_t retcode[4]; /* Trampoline code. */
};
static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
@@ -3745,8 +3745,8 @@ static void setup_frame(int sig, struct target_sigaction *ka,
*/
err |= __put_user(0x9c5f, frame->retcode+0);
err |= __put_user(TARGET_NR_sigreturn,
- frame->retcode+2);
- err |= __put_user(0xe93d, frame->retcode+4);
+ frame->retcode + 1);
+ err |= __put_user(0xe93d, frame->retcode + 2);
/* Save the mask. */
err |= __put_user(set->sig[0], &frame->sc.oldmask);
diff --git a/migration.c b/migration.c
index 7235c23..25add6f 100644
--- a/migration.c
+++ b/migration.c
@@ -105,6 +105,7 @@ static void process_incoming_migration_co(void *opaque)
ret = qemu_loadvm_state(f);
qemu_fclose(f);
+ free_xbzrle_decoded_buf();
if (ret < 0) {
fprintf(stderr, "load of migration failed\n");
exit(EXIT_FAILURE);
@@ -469,6 +470,7 @@ void qmp_migrate_cancel(Error **errp)
void qmp_migrate_set_cache_size(int64_t value, Error **errp)
{
MigrationState *s = migrate_get_current();
+ int64_t new_size;
/* Check for truncation */
if (value != (size_t)value) {
@@ -477,7 +479,21 @@ void qmp_migrate_set_cache_size(int64_t value, Error **errp)
return;
}
- s->xbzrle_cache_size = xbzrle_cache_resize(value);
+ /* Cache should not be larger than guest ram size */
+ if (value > ram_bytes_total()) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+ "exceeds guest ram size ");
+ return;
+ }
+
+ new_size = xbzrle_cache_resize(value);
+ if (new_size < 0) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+ "is smaller than page size");
+ return;
+ }
+
+ s->xbzrle_cache_size = new_size;
}
int64_t qmp_query_migrate_cache_size(Error **errp)
diff --git a/monitor.c b/monitor.c
index cba56bc..b1ea262 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4888,7 +4888,8 @@ static void sortcmdlist(void)
/* These functions just adapt the readline interface in a typesafe way. We
* could cast function pointers but that discards compiler checks.
*/
-static void monitor_readline_printf(void *opaque, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
+ const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
diff --git a/page_cache.c b/page_cache.c
index a05db64..3ef6ee7 100644
--- a/page_cache.c
+++ b/page_cache.c
@@ -60,8 +60,12 @@ PageCache *cache_init(int64_t num_pages, unsigned int page_size)
return NULL;
}
- cache = g_malloc(sizeof(*cache));
-
+ /* We prefer not to abort if there is no memory */
+ cache = g_try_malloc(sizeof(*cache));
+ if (!cache) {
+ DPRINTF("Failed to allocate cache\n");
+ return NULL;
+ }
/* round down to the nearest power of 2 */
if (!is_power_of_2(num_pages)) {
num_pages = pow2floor(num_pages);
@@ -74,8 +78,14 @@ PageCache *cache_init(int64_t num_pages, unsigned int page_size)
DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items);
- cache->page_cache = g_malloc((cache->max_num_items) *
- sizeof(*cache->page_cache));
+ /* We prefer not to abort if there is no memory */
+ cache->page_cache = g_try_malloc((cache->max_num_items) *
+ sizeof(*cache->page_cache));
+ if (!cache->page_cache) {
+ DPRINTF("Failed to allocate cache->page_cache\n");
+ g_free(cache);
+ return NULL;
+ }
for (i = 0; i < cache->max_num_items; i++) {
cache->page_cache[i].it_data = NULL;
@@ -140,7 +150,7 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr)
return cache_get_by_addr(cache, addr)->it_data;
}
-void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
+int cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
{
CacheItem *it = NULL;
@@ -151,16 +161,22 @@ void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
/* actual update of entry */
it = cache_get_by_addr(cache, addr);
- /* free old cached data if any */
- g_free(it->it_data);
-
+ /* allocate page */
if (!it->it_data) {
+ it->it_data = g_try_malloc(cache->page_size);
+ if (!it->it_data) {
+ DPRINTF("Error allocating page\n");
+ return -1;
+ }
cache->num_items++;
}
- it->it_data = g_memdup(pdata, cache->page_size);
+ memcpy(it->it_data, pdata, cache->page_size);
+
it->it_age = ++cache->max_item_age;
it->it_addr = addr;
+
+ return 0;
}
int64_t cache_resize(PageCache *cache, int64_t new_num_pages)
diff --git a/pc-bios/QEMU,tcx.bin b/pc-bios/QEMU,tcx.bin
index a8ddd70..eed108f 100644
--- a/pc-bios/QEMU,tcx.bin
+++ b/pc-bios/QEMU,tcx.bin
Binary files differ
diff --git a/pc-bios/README b/pc-bios/README
index a110125..f190068 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -12,7 +12,7 @@
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
Sparc32 (including QEMU,tcx.bin) and Sparc64 are built from OpenBIOS SVN
- revision 1229.
+ revision 1246.
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin
index 68017e5..93202c5 100644
--- a/pc-bios/bios-256k.bin
+++ b/pc-bios/bios-256k.bin
Binary files differ
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index 4f4383b..d7899bd 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 550273a..f4a3a39 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index 01105fc..bb7cdfb 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 62c9e77..46b4fdd 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin
index 36b197d..d8cb9d2 100644
--- a/pc-bios/vgabios-cirrus.bin
+++ b/pc-bios/vgabios-cirrus.bin
Binary files differ
diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin
index aaa3b10..fe57401 100644
--- a/pc-bios/vgabios-qxl.bin
+++ b/pc-bios/vgabios-qxl.bin
Binary files differ
diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin
index d329e24..2aa659c 100644
--- a/pc-bios/vgabios-stdvga.bin
+++ b/pc-bios/vgabios-stdvga.bin
Binary files differ
diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin
index 31d56a9..bed7068 100644
--- a/pc-bios/vgabios-vmware.bin
+++ b/pc-bios/vgabios-vmware.bin
Binary files differ
diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin
index b87f74d..928095f 100644
--- a/pc-bios/vgabios.bin
+++ b/pc-bios/vgabios.bin
Binary files differ
diff --git a/qemu-doc.texi b/qemu-doc.texi
index ce61f30..ad31f2d 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -547,10 +547,27 @@ File name of a base image (see @option{create} subcommand)
@item backing_fmt
Image format of the base image
@item encryption
-If this option is set to @code{on}, the image is encrypted.
+If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC.
+
+The use of encryption in qcow and qcow2 images is considered to be flawed by
+modern cryptography standards, suffering from a number of design problems:
+
+@itemize @minus
+@item The AES-CBC cipher is used with predictable initialization vectors based
+on the sector number. This makes it vulnerable to chosen plaintext attacks
+which can reveal the existence of encrypted data.
+@item The user passphrase is directly used as the encryption key. A poorly
+chosen or short passphrase will compromise the security of the encryption.
+@item In the event of the passphrase being compromised there is no way to
+change the passphrase to protect data in any qcow images. The files must
+be cloned, using a different encryption passphrase in the new file. The
+original file must then be securely erased using a program like shred,
+though even this is ineffective with many modern storage technologies.
+@end itemize
-Encryption uses the AES format which is very secure (128 bit keys). Use
-a long password (16 characters) to get maximum protection.
+Use of qcow / qcow2 encryption is thus strongly discouraged. Users are
+recommended to use an alternative encryption technology such as the
+Linux dm-crypt / LUKS system.
@item cluster_size
Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster
diff --git a/qemu-img.texi b/qemu-img.texi
index 526d56a..f84590e 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -409,10 +409,27 @@ File name of a base image (see @option{create} subcommand)
@item backing_fmt
Image format of the base image
@item encryption
-If this option is set to @code{on}, the image is encrypted.
+If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC.
-Encryption uses the AES format which is very secure (128 bit keys). Use
-a long password (16 characters) to get maximum protection.
+The use of encryption in qcow and qcow2 images is considered to be flawed by
+modern cryptography standards, suffering from a number of design problems:
+
+@itemize @minus
+@item The AES-CBC cipher is used with predictable initialization vectors based
+on the sector number. This makes it vulnerable to chosen plaintext attacks
+which can reveal the existence of encrypted data.
+@item The user passphrase is directly used as the encryption key. A poorly
+chosen or short passphrase will compromise the security of the encryption.
+@item In the event of the passphrase being compromised there is no way to
+change the passphrase to protect data in any qcow images. The files must
+be cloned, using a different encryption passphrase in the new file. The
+original file must then be securely erased using a program like shred,
+though even this is ineffective with many modern storage technologies.
+@end itemize
+
+Use of qcow / qcow2 encryption is thus strongly discouraged. Users are
+recommended to use an alternative encryption technology such as the
+Linux dm-crypt / LUKS system.
@item cluster_size
Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster
diff --git a/qemu-io.c b/qemu-io.c
index d669028..7f459d8 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -219,7 +219,8 @@ static char *get_prompt(void)
return prompt;
}
-static void readline_printf_func(void *opaque, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) readline_printf_func(void *opaque,
+ const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
diff --git a/roms/Makefile b/roms/Makefile
index 1e04669..2721b02 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -72,11 +72,11 @@ seavgabios-%: build-seabios-config-vga-%
build-seabios-config-%: config.%
mkdir -p seabios/builds/$*
cp $< seabios/builds/$*/.config
- $(MAKE) $(MAKEFLAGS) -C seabios \
+ $(MAKE) -C seabios \
CROSS_COMPILE=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ oldnoconfig
- $(MAKE) $(MAKEFLAGS) -C seabios \
+ $(MAKE) -C seabios \
CROSS_COMPILE=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ all
@@ -90,12 +90,12 @@ lgplvgabios-%: build-lgplvgabios
cp vgabios/VGABIOS-lgpl-latest.$*.bin ../pc-bios/vgabios-$*.bin
build-lgplvgabios:
- $(MAKE) $(MAKEFLAGS) -C vgabios $(vgabios_targets)
+ $(MAKE) -C vgabios $(vgabios_targets)
.PHONY: sgabios
sgabios:
- $(MAKE) $(MAKEFLAGS) -C sgabios
+ $(MAKE) -C sgabios
cp sgabios/sgabios.bin ../pc-bios
@@ -114,12 +114,12 @@ efi-rom-%: build-pxe-roms build-efi-roms
-o ../pc-bios/efi-$*.rom
build-pxe-roms: ipxe/src/config/local/general.h
- $(MAKE) $(MAKEFLAGS) -C ipxe/src GITVERSION="" \
+ $(MAKE) -C ipxe/src GITVERSION="" \
CROSS_COMPILE=$(x86_64_cross_prefix) \
$(patsubst %,bin/%.rom,$(pxerom_targets))
build-efi-roms: build-pxe-roms ipxe/src/config/local/general.h
- $(MAKE) $(MAKEFLAGS) -C ipxe/src GITVERSION="" \
+ $(MAKE) -C ipxe/src GITVERSION="" \
CROSS_COMPILE=$(x86_64_cross_prefix) \
$(patsubst %,bin-i386-efi/%.efidrv,$(pxerom_targets)) \
$(patsubst %,bin-x86_64-efi/%.efidrv,$(pxerom_targets))
@@ -129,15 +129,15 @@ ipxe/src/config/local/%: config.ipxe.%
slof:
- $(MAKE) $(MAKEFLAGS) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
+ $(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
cp SLOF/boot_rom.bin ../pc-bios/slof.bin
clean:
rm -rf seabios/.config seabios/out seabios/builds
- $(MAKE) $(MAKEFLAGS) -C vgabios clean
+ $(MAKE) -C vgabios clean
rm -f vgabios/VGABIOS-lgpl-latest*
- $(MAKE) $(MAKEFLAGS) -C sgabios clean
+ $(MAKE) -C sgabios clean
rm -f sgabios/.depend
- $(MAKE) $(MAKEFLAGS) -C ipxe/src veryclean
- $(MAKE) $(MAKEFLAGS) -C SLOF clean
+ $(MAKE) -C ipxe/src veryclean
+ $(MAKE) -C SLOF clean
diff --git a/roms/openbios b/roms/openbios
-Subproject d363cf50c50c268da7e6d0bf707adde1893d1ab
+Subproject 888126272f92294b0da45158393f1b862742cf6
diff --git a/roms/seabios b/roms/seabios
-Subproject 31b8b4eea9d9ad58a73b22a6060d3ac1c419c26
+Subproject 96917a8ed761f017fc8c72ba3b9181fbac03ac5
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 16439c5..6624559 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -212,7 +212,7 @@ static void spice_chr_close(struct CharDriverState *chr)
g_free(s);
}
-static void spice_chr_set_fe_open(struct CharDriverState *chr, int fe_open)
+static void spice_vmc_set_fe_open(struct CharDriverState *chr, int fe_open)
{
SpiceCharDriver *s = chr->opaque;
if (fe_open) {
@@ -222,6 +222,19 @@ static void spice_chr_set_fe_open(struct CharDriverState *chr, int fe_open)
}
}
+static void spice_port_set_fe_open(struct CharDriverState *chr, int fe_open)
+{
+#if SPICE_SERVER_VERSION >= 0x000c02
+ SpiceCharDriver *s = chr->opaque;
+
+ if (fe_open) {
+ spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
+ } else {
+ spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED);
+ }
+#endif
+}
+
static void spice_chr_fe_event(struct CharDriverState *chr, int event)
{
#if SPICE_SERVER_VERSION >= 0x000c02
@@ -248,7 +261,9 @@ static void print_allowed_subtypes(void)
fprintf(stderr, "\n");
}
-static CharDriverState *chr_open(const char *subtype)
+static CharDriverState *chr_open(const char *subtype,
+ void (*set_fe_open)(struct CharDriverState *, int))
+
{
CharDriverState *chr;
SpiceCharDriver *s;
@@ -262,7 +277,7 @@ static CharDriverState *chr_open(const char *subtype)
chr->chr_write = spice_chr_write;
chr->chr_add_watch = spice_chr_add_watch;
chr->chr_close = spice_chr_close;
- chr->chr_set_fe_open = spice_chr_set_fe_open;
+ chr->chr_set_fe_open = set_fe_open;
chr->explicit_be_open = true;
chr->chr_fe_event = spice_chr_fe_event;
@@ -291,7 +306,7 @@ CharDriverState *qemu_chr_open_spice_vmc(const char *type)
return NULL;
}
- return chr_open(type);
+ return chr_open(type, spice_vmc_set_fe_open);
}
#if SPICE_SERVER_VERSION >= 0x000c02
@@ -305,7 +320,7 @@ CharDriverState *qemu_chr_open_spice_port(const char *name)
return NULL;
}
- chr = chr_open("port");
+ chr = chr_open("port", spice_port_set_fe_open);
s = chr->opaque;
s->sin.portname = g_strdup(name);
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 44301a4..1ac8124 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -66,6 +66,12 @@ static ObjectClass *cris_cpu_class_by_name(const char *cpu_model)
return NULL;
}
+#if defined(CONFIG_USER_ONLY)
+ if (strcasecmp(cpu_model, "any") == 0) {
+ return object_class_by_name("crisv32-" TYPE_CRIS_CPU);
+ }
+#endif
+
typename = g_strdup_printf("%s-" TYPE_CRIS_CPU, cpu_model);
oc = object_class_by_name(typename);
g_free(typename);
@@ -146,6 +152,21 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp)
ccc->parent_realize(dev, errp);
}
+#ifndef CONFIG_USER_ONLY
+static void cris_cpu_set_irq(void *opaque, int irq, int level)
+{
+ CRISCPU *cpu = opaque;
+ CPUState *cs = CPU(cpu);
+ int type = irq == CRIS_CPU_IRQ ? CPU_INTERRUPT_HARD : CPU_INTERRUPT_NMI;
+
+ if (level) {
+ cpu_interrupt(cs, type);
+ } else {
+ cpu_reset_interrupt(cs, type);
+ }
+}
+#endif
+
static void cris_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -159,6 +180,11 @@ static void cris_cpu_initfn(Object *obj)
env->pregs[PR_VR] = ccc->vr;
+#ifndef CONFIG_USER_ONLY
+ /* IRQ and NMI lines. */
+ qdev_init_gpio_in(DEVICE(cpu), cris_cpu_set_irq, 2);
+#endif
+
if (tcg_enabled() && !tcg_initialized) {
tcg_initialized = true;
if (env->pregs[PR_VR] < 32) {
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 4b9fc4c..1d7d80d 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -42,6 +42,10 @@
/* CRIS-specific interrupt pending bits. */
#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3
+/* CRUS CPU device objects interrupt lines. */
+#define CRIS_CPU_IRQ 0
+#define CRIS_CPU_NMI 1
+
/* Register aliases. R0 - R15 */
#define R_FP 8
#define R_SP 14
diff --git a/target-cris/helper.c b/target-cris/helper.c
index d274b38..c940582 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -126,6 +126,11 @@ void crisv10_cpu_do_interrupt(CPUState *cs)
env->exception_index,
cs->interrupt_request);
+ if (env->dslot) {
+ /* CRISv10 never takes interrupts while in a delay-slot. */
+ cpu_abort(env, "CRIS: Interrupt on delay-slot\n");
+ }
+
assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
switch (env->exception_index) {
case EXCP_BREAK:
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index d1751a4..722f11a 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -69,6 +69,7 @@ typedef struct X86CPU {
bool hyperv_vapic;
bool hyperv_relaxed_timing;
int hyperv_spinlock_attempts;
+ bool hyperv_time;
bool check_cpuid;
bool enforce_cpuid;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index e6f7eaf..0e8812a 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -374,7 +374,6 @@ void disable_kvm_pv_eoi(void)
void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
-#if defined(CONFIG_KVM)
uint32_t vec[4];
#ifdef __x86_64__
@@ -382,7 +381,7 @@ void host_cpuid(uint32_t function, uint32_t count,
: "=a"(vec[0]), "=b"(vec[1]),
"=c"(vec[2]), "=d"(vec[3])
: "0"(function), "c"(count) : "cc");
-#else
+#elif defined(__i386__)
asm volatile("pusha \n\t"
"cpuid \n\t"
"mov %%eax, 0(%2) \n\t"
@@ -392,6 +391,8 @@ void host_cpuid(uint32_t function, uint32_t count,
"popa"
: : "a"(function), "c"(count), "S"(vec)
: "memory", "cc");
+#else
+ abort();
#endif
if (eax)
@@ -402,7 +403,6 @@ void host_cpuid(uint32_t function, uint32_t count,
*ecx = vec[2];
if (edx)
*edx = vec[3];
-#endif
}
#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
@@ -1119,7 +1119,6 @@ void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
}
}
-#ifdef CONFIG_KVM
static int cpu_x86_fill_model_id(char *str)
{
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -1134,7 +1133,6 @@ static int cpu_x86_fill_model_id(char *str)
}
return 0;
}
-#endif
/* Fill a x86_def_t struct with information about the host CPU, and
* the CPU features supported by the host hardware + host kernel
@@ -1143,7 +1141,6 @@ static int cpu_x86_fill_model_id(char *str)
*/
static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
{
-#ifdef CONFIG_KVM
KVMState *s = kvm_state;
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -1160,46 +1157,19 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
x86_cpu_def->stepping = eax & 0x0F;
x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
- x86_cpu_def->features[FEAT_1_EDX] =
- kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
- x86_cpu_def->features[FEAT_1_ECX] =
- kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
-
- if (x86_cpu_def->level >= 7) {
- x86_cpu_def->features[FEAT_7_0_EBX] =
- kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
- } else {
- x86_cpu_def->features[FEAT_7_0_EBX] = 0;
- }
-
x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
- x86_cpu_def->features[FEAT_8000_0001_EDX] =
- kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
- x86_cpu_def->features[FEAT_8000_0001_ECX] =
- kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
+ x86_cpu_def->xlevel2 =
+ kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
cpu_x86_fill_model_id(x86_cpu_def->model_id);
- /* Call Centaur's CPUID instruction. */
- if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
- host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
- eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
- if (eax >= 0xC0000001) {
- /* Support VIA max extended level */
- x86_cpu_def->xlevel2 = eax;
- host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->features[FEAT_C000_0001_EDX] =
- kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
- }
+ FeatureWord w;
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ FeatureWordInfo *wi = &feature_word_info[w];
+ x86_cpu_def->features[w] =
+ kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, wi->cpuid_ecx,
+ wi->cpuid_reg);
}
-
- /* Other KVM-specific feature fields: */
- x86_cpu_def->features[FEAT_SVM] =
- kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
- x86_cpu_def->features[FEAT_KVM] =
- kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
-
-#endif /* CONFIG_KVM */
}
static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
@@ -1226,48 +1196,23 @@ static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
*
* This function may be called only if KVM is enabled.
*/
-static int kvm_check_features_against_host(X86CPU *cpu)
+static int kvm_check_features_against_host(KVMState *s, X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
- x86_def_t host_def;
- uint32_t mask;
- int rv, i;
- struct model_features_t ft[] = {
- {&env->features[FEAT_1_EDX],
- &host_def.features[FEAT_1_EDX],
- FEAT_1_EDX },
- {&env->features[FEAT_1_ECX],
- &host_def.features[FEAT_1_ECX],
- FEAT_1_ECX },
- {&env->features[FEAT_8000_0001_EDX],
- &host_def.features[FEAT_8000_0001_EDX],
- FEAT_8000_0001_EDX },
- {&env->features[FEAT_8000_0001_ECX],
- &host_def.features[FEAT_8000_0001_ECX],
- FEAT_8000_0001_ECX },
- {&env->features[FEAT_C000_0001_EDX],
- &host_def.features[FEAT_C000_0001_EDX],
- FEAT_C000_0001_EDX },
- {&env->features[FEAT_7_0_EBX],
- &host_def.features[FEAT_7_0_EBX],
- FEAT_7_0_EBX },
- {&env->features[FEAT_SVM],
- &host_def.features[FEAT_SVM],
- FEAT_SVM },
- {&env->features[FEAT_KVM],
- &host_def.features[FEAT_KVM],
- FEAT_KVM },
- };
+ int rv = 0;
+ FeatureWord w;
assert(kvm_enabled());
- kvm_cpu_fill_host(&host_def);
- for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) {
- FeatureWord w = ft[i].feat_word;
+ for (w = 0; w < FEATURE_WORDS; w++) {
FeatureWordInfo *wi = &feature_word_info[w];
+ uint32_t guest_feat = env->features[w];
+ uint32_t host_feat = kvm_arch_get_supported_cpuid(s, wi->cpuid_eax,
+ wi->cpuid_ecx,
+ wi->cpuid_reg);
+ uint32_t mask;
for (mask = 1; mask; mask <<= 1) {
- if (*ft[i].guest_feat & mask &&
- !(*ft[i].host_feat & mask)) {
+ if (guest_feat & mask && !(host_feat & mask)) {
unavailable_host_feature(wi, mask);
rv = 1;
}
@@ -1656,18 +1601,6 @@ static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t *x86_cpu_def,
def = &builtin_x86_defs[i];
if (strcmp(name, def->name) == 0) {
memcpy(x86_cpu_def, def, sizeof(*def));
- /* sysenter isn't supported in compatibility mode on AMD,
- * syscall isn't supported in compatibility mode on Intel.
- * Normally we advertise the actual CPU vendor, but you can
- * override this using the 'vendor' property if you want to use
- * KVM's sysenter/syscall emulation in compatibility mode and
- * when doing cross vendor migration
- */
- if (kvm_enabled()) {
- uint32_t ebx = 0, ecx = 0, edx = 0;
- host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
- x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
- }
return 0;
}
}
@@ -1867,7 +1800,6 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
return cpu_list;
}
-#ifdef CONFIG_KVM
static void filter_features_for_kvm(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
@@ -1884,7 +1816,6 @@ static void filter_features_for_kvm(X86CPU *cpu)
cpu->filtered_features[w] = requested_features & ~env->features[w];
}
}
-#endif
static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
{
@@ -1898,12 +1829,6 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
return;
}
- if (kvm_enabled()) {
- def->features[FEAT_KVM] |= kvm_default_features;
- }
- def->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
-
- object_property_set_str(OBJECT(cpu), def->vendor, "vendor", errp);
object_property_set_int(OBJECT(cpu), def->level, "level", errp);
object_property_set_int(OBJECT(cpu), def->family, "family", errp);
object_property_set_int(OBJECT(cpu), def->model, "model", errp);
@@ -1921,6 +1846,31 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
cpu->cache_info_passthrough = def->cache_info_passthrough;
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
+
+ /* Special cases not set in the x86_def_t structs: */
+ if (kvm_enabled()) {
+ env->features[FEAT_KVM] |= kvm_default_features;
+ }
+ env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
+
+ /* sysenter isn't supported in compatibility mode on AMD,
+ * syscall isn't supported in compatibility mode on Intel.
+ * Normally we advertise the actual CPU vendor, but you can
+ * override this using the 'vendor' property if you want to use
+ * KVM's sysenter/syscall emulation in compatibility mode and
+ * when doing cross vendor migration
+ */
+ const char *vendor = def->vendor;
+ char host_vendor[CPUID_VENDOR_SZ + 1];
+ if (kvm_enabled()) {
+ uint32_t ebx = 0, ecx = 0, edx = 0;
+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
+ x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx);
+ vendor = host_vendor;
+ }
+
+ object_property_set_str(OBJECT(cpu), vendor, "vendor", errp);
+
}
X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
@@ -2588,15 +2538,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
env->features[FEAT_8000_0001_ECX] &= TCG_EXT3_FEATURES;
env->features[FEAT_SVM] &= TCG_SVM_FEATURES;
} else {
+ KVMState *s = kvm_state;
if ((cpu->check_cpuid || cpu->enforce_cpuid)
- && kvm_check_features_against_host(cpu) && cpu->enforce_cpuid) {
+ && kvm_check_features_against_host(s, cpu) && cpu->enforce_cpuid) {
error_setg(&local_err,
"Host's CPU doesn't support requested features");
goto out;
}
-#ifdef CONFIG_KVM
filter_features_for_kvm(cpu);
-#endif
}
#ifndef CONFIG_USER_ONLY
@@ -2751,6 +2700,7 @@ static Property x86_cpu_properties[] = {
{ .name = "hv-spinlocks", .info = &qdev_prop_spinlocks },
DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
+ DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
DEFINE_PROP_END_OF_LIST()
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 1fcbc82..1b94f0f 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -862,6 +862,10 @@ typedef struct CPUX86State {
uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS];
uint64_t msr_gp_counters[MAX_GP_COUNTERS];
uint64_t msr_gp_evtsel[MAX_GP_COUNTERS];
+ uint64_t msr_hv_hypercall;
+ uint64_t msr_hv_guest_os_id;
+ uint64_t msr_hv_vapic;
+ uint64_t msr_hv_tsc;
/* exception/interrupt handling */
int error_code;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 0a21c30..e555040 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -72,6 +72,9 @@ static bool has_msr_misc_enable;
static bool has_msr_bndcfgs;
static bool has_msr_kvm_steal_time;
static int lm_capable_kernel;
+static bool has_msr_hv_hypercall;
+static bool has_msr_hv_vapic;
+static bool has_msr_hv_tsc;
static bool has_msr_architectural_pmu;
static uint32_t num_architectural_pmu_counters;
@@ -437,8 +440,11 @@ static bool hyperv_hypercall_available(X86CPU *cpu)
static bool hyperv_enabled(X86CPU *cpu)
{
- return hyperv_hypercall_available(cpu) ||
- cpu->hyperv_relaxed_timing;
+ CPUState *cs = CPU(cpu);
+ return kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0 &&
+ (hyperv_hypercall_available(cpu) ||
+ cpu->hyperv_time ||
+ cpu->hyperv_relaxed_timing);
}
#define KVM_MAX_CPUID_ENTRIES 100
@@ -455,6 +461,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
uint32_t unused;
struct kvm_cpuid_entry2 *c;
uint32_t signature[3];
+ int kvm_base = KVM_CPUID_SIGNATURE;
int r;
memset(&cpuid_data, 0, sizeof(cpuid_data));
@@ -462,26 +469,22 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpuid_i = 0;
/* Paravirtualization CPUIDs */
- c = &cpuid_data.entries[cpuid_i++];
- c->function = KVM_CPUID_SIGNATURE;
- if (!hyperv_enabled(cpu)) {
- memcpy(signature, "KVMKVMKVM\0\0\0", 12);
- c->eax = 0;
- } else {
+ if (hyperv_enabled(cpu)) {
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
memcpy(signature, "Microsoft Hv", 12);
c->eax = HYPERV_CPUID_MIN;
- }
- c->ebx = signature[0];
- c->ecx = signature[1];
- c->edx = signature[2];
-
- c = &cpuid_data.entries[cpuid_i++];
- c->function = KVM_CPUID_FEATURES;
- c->eax = env->features[FEAT_KVM];
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
- if (hyperv_enabled(cpu)) {
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = HYPERV_CPUID_INTERFACE;
memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
c->eax = signature[0];
+ c->ebx = 0;
+ c->ecx = 0;
+ c->edx = 0;
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_VERSION;
@@ -496,14 +499,21 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (cpu->hyperv_vapic) {
c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
+ has_msr_hv_vapic = true;
+ }
+ if (cpu->hyperv_time &&
+ kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) {
+ c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+ c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
+ c->eax |= 0x200;
+ has_msr_hv_tsc = true;
}
-
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
if (cpu->hyperv_relaxed_timing) {
c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
}
- if (cpu->hyperv_vapic) {
+ if (has_msr_hv_vapic) {
c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
}
c->ebx = cpu->hyperv_spinlock_attempts;
@@ -513,15 +523,22 @@ int kvm_arch_init_vcpu(CPUState *cs)
c->eax = 0x40;
c->ebx = 0x40;
- c = &cpuid_data.entries[cpuid_i++];
- c->function = KVM_CPUID_SIGNATURE_NEXT;
- memcpy(signature, "KVMKVMKVM\0\0\0", 12);
- c->eax = 0;
- c->ebx = signature[0];
- c->ecx = signature[1];
- c->edx = signature[2];
+ kvm_base = KVM_CPUID_SIGNATURE_NEXT;
+ has_msr_hv_hypercall = true;
}
+ memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = KVM_CPUID_SIGNATURE | kvm_base;
+ c->eax = 0;
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
+
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = KVM_CPUID_FEATURES | kvm_base;
+ c->eax = env->features[FEAT_KVM];
+
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);
@@ -1220,12 +1237,19 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_CTRL,
env->msr_global_ctrl);
}
- if (hyperv_hypercall_available(cpu)) {
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
+ if (has_msr_hv_hypercall) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID,
+ env->msr_hv_guest_os_id);
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL,
+ env->msr_hv_hypercall);
}
- if (cpu->hyperv_vapic) {
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
+ if (has_msr_hv_vapic) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE,
+ env->msr_hv_vapic);
+ }
+ if (has_msr_hv_tsc) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
+ env->msr_hv_tsc);
}
/* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
@@ -1511,6 +1535,17 @@ static int kvm_get_msrs(X86CPU *cpu)
}
}
+ if (has_msr_hv_hypercall) {
+ msrs[n++].index = HV_X64_MSR_HYPERCALL;
+ msrs[n++].index = HV_X64_MSR_GUEST_OS_ID;
+ }
+ if (has_msr_hv_vapic) {
+ msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
+ }
+ if (has_msr_hv_tsc) {
+ msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
+ }
+
msr_data.info.nmsrs = n;
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
if (ret < 0) {
@@ -1618,6 +1653,18 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL0 + MAX_GP_COUNTERS - 1:
env->msr_gp_evtsel[index - MSR_P6_EVNTSEL0] = msrs[i].data;
break;
+ case HV_X64_MSR_HYPERCALL:
+ env->msr_hv_hypercall = msrs[i].data;
+ break;
+ case HV_X64_MSR_GUEST_OS_ID:
+ env->msr_hv_guest_os_id = msrs[i].data;
+ break;
+ case HV_X64_MSR_APIC_ASSIST_PAGE:
+ env->msr_hv_vapic = msrs[i].data;
+ break;
+ case HV_X64_MSR_REFERENCE_TSC:
+ env->msr_hv_tsc = msrs[i].data;
+ break;
}
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 2de1964..d548c05 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -554,6 +554,64 @@ static const VMStateDescription vmstate_mpx = {
}
};
+static bool hyperv_hypercall_enable_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->msr_hv_hypercall != 0 || env->msr_hv_guest_os_id != 0;
+}
+
+static const VMStateDescription vmstate_msr_hypercall_hypercall = {
+ .name = "cpu/msr_hyperv_hypercall",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
+ VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool hyperv_vapic_enable_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->msr_hv_vapic != 0;
+}
+
+static const VMStateDescription vmstate_msr_hyperv_vapic = {
+ .name = "cpu/msr_hyperv_vapic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(env.msr_hv_vapic, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool hyperv_time_enable_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->msr_hv_tsc != 0;
+}
+
+static const VMStateDescription vmstate_msr_hyperv_time = {
+ .name = "cpu/msr_hyperv_time",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(env.msr_hv_tsc, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
@@ -688,6 +746,15 @@ const VMStateDescription vmstate_x86_cpu = {
} , {
.vmsd = &vmstate_mpx,
.needed = mpx_needed,
+ }, {
+ .vmsd = &vmstate_msr_hypercall_hypercall,
+ .needed = hyperv_hypercall_enable_needed,
+ }, {
+ .vmsd = &vmstate_msr_hyperv_vapic,
+ .needed = hyperv_vapic_enable_needed,
+ }, {
+ .vmsd = &vmstate_msr_hyperv_time,
+ .needed = hyperv_time_enable_needed,
} , {
/* empty */
}
diff --git a/target-lm32/TODO b/target-lm32/TODO
index b9ea0c8..e163c42 100644
--- a/target-lm32/TODO
+++ b/target-lm32/TODO
@@ -1,3 +1 @@
-* disassembler (lm32-dis.c)
* linux-user emulation
-* native bp/wp emulation (?)
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index 723f604..9f15093 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -60,6 +60,12 @@ typedef struct LM32CPU {
/*< public >*/
CPULM32State env;
+
+ uint32_t revision;
+ uint8_t num_interrupts;
+ uint8_t num_breakpoints;
+ uint8_t num_watchpoints;
+ uint32_t features;
} LM32CPU;
static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env)
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 869878c..7e716fb 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -29,6 +29,87 @@ static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
cpu->env.pc = value;
}
+/* Sort alphabetically by type name. */
+static gint lm32_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+ const char *name_a, *name_b;
+
+ name_a = object_class_get_name(class_a);
+ name_b = object_class_get_name(class_b);
+ return strcmp(name_a, name_b);
+}
+
+static void lm32_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CPUListState *s = user_data;
+ const char *typename = object_class_get_name(oc);
+ char *name;
+
+ name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_LM32_CPU));
+ (*s->cpu_fprintf)(s->file, " %s\n", name);
+ g_free(name);
+}
+
+
+void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ CPUListState s = {
+ .file = f,
+ .cpu_fprintf = cpu_fprintf,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_LM32_CPU, false);
+ list = g_slist_sort(list, lm32_cpu_list_compare);
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ g_slist_foreach(list, lm32_cpu_list_entry, &s);
+ g_slist_free(list);
+}
+
+static void lm32_cpu_init_cfg_reg(LM32CPU *cpu)
+{
+ CPULM32State *env = &cpu->env;
+ uint32_t cfg = 0;
+
+ if (cpu->features & LM32_FEATURE_MULTIPLY) {
+ cfg |= CFG_M;
+ }
+
+ if (cpu->features & LM32_FEATURE_DIVIDE) {
+ cfg |= CFG_D;
+ }
+
+ if (cpu->features & LM32_FEATURE_SHIFT) {
+ cfg |= CFG_S;
+ }
+
+ if (cpu->features & LM32_FEATURE_SIGN_EXTEND) {
+ cfg |= CFG_X;
+ }
+
+ if (cpu->features & LM32_FEATURE_I_CACHE) {
+ cfg |= CFG_IC;
+ }
+
+ if (cpu->features & LM32_FEATURE_D_CACHE) {
+ cfg |= CFG_DC;
+ }
+
+ if (cpu->features & LM32_FEATURE_CYCLE_COUNT) {
+ cfg |= CFG_CC;
+ }
+
+ cfg |= (cpu->num_interrupts << CFG_INT_SHIFT);
+ cfg |= (cpu->num_breakpoints << CFG_BP_SHIFT);
+ cfg |= (cpu->num_watchpoints << CFG_WP_SHIFT);
+ cfg |= (cpu->revision << CFG_REV_SHIFT);
+
+ env->cfg = cfg;
+}
+
/* CPUClass::reset() */
static void lm32_cpu_reset(CPUState *s)
{
@@ -41,6 +122,7 @@ static void lm32_cpu_reset(CPUState *s)
/* reset cpu state */
memset(env, 0, offsetof(CPULM32State, breakpoints));
+ lm32_cpu_init_cfg_reg(cpu);
tlb_flush(env, 1);
}
@@ -71,7 +153,93 @@ static void lm32_cpu_initfn(Object *obj)
if (tcg_enabled() && !tcg_initialized) {
tcg_initialized = true;
lm32_translate_init();
+ cpu_set_debug_excp_handler(lm32_debug_excp_handler);
+ }
+}
+
+static void lm32_basic_cpu_initfn(Object *obj)
+{
+ LM32CPU *cpu = LM32_CPU(obj);
+
+ cpu->revision = 3;
+ cpu->num_interrupts = 32;
+ cpu->num_breakpoints = 4;
+ cpu->num_watchpoints = 4;
+ cpu->features = LM32_FEATURE_SHIFT
+ | LM32_FEATURE_SIGN_EXTEND
+ | LM32_FEATURE_CYCLE_COUNT;
+}
+
+static void lm32_standard_cpu_initfn(Object *obj)
+{
+ LM32CPU *cpu = LM32_CPU(obj);
+
+ cpu->revision = 3;
+ cpu->num_interrupts = 32;
+ cpu->num_breakpoints = 4;
+ cpu->num_watchpoints = 4;
+ cpu->features = LM32_FEATURE_MULTIPLY
+ | LM32_FEATURE_DIVIDE
+ | LM32_FEATURE_SHIFT
+ | LM32_FEATURE_SIGN_EXTEND
+ | LM32_FEATURE_I_CACHE
+ | LM32_FEATURE_CYCLE_COUNT;
+}
+
+static void lm32_full_cpu_initfn(Object *obj)
+{
+ LM32CPU *cpu = LM32_CPU(obj);
+
+ cpu->revision = 3;
+ cpu->num_interrupts = 32;
+ cpu->num_breakpoints = 4;
+ cpu->num_watchpoints = 4;
+ cpu->features = LM32_FEATURE_MULTIPLY
+ | LM32_FEATURE_DIVIDE
+ | LM32_FEATURE_SHIFT
+ | LM32_FEATURE_SIGN_EXTEND
+ | LM32_FEATURE_I_CACHE
+ | LM32_FEATURE_D_CACHE
+ | LM32_FEATURE_CYCLE_COUNT;
+}
+
+typedef struct LM32CPUInfo {
+ const char *name;
+ void (*initfn)(Object *obj);
+} LM32CPUInfo;
+
+static const LM32CPUInfo lm32_cpus[] = {
+ {
+ .name = "lm32-basic",
+ .initfn = lm32_basic_cpu_initfn,
+ },
+ {
+ .name = "lm32-standard",
+ .initfn = lm32_standard_cpu_initfn,
+ },
+ {
+ .name = "lm32-full",
+ .initfn = lm32_full_cpu_initfn,
+ },
+};
+
+static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+
+ if (cpu_model == NULL) {
+ return NULL;
}
+
+ typename = g_strdup_printf("%s-" TYPE_LM32_CPU, cpu_model);
+ oc = object_class_by_name(typename);
+ g_free(typename);
+ if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_LM32_CPU) ||
+ object_class_is_abstract(oc))) {
+ oc = NULL;
+ }
+ return oc;
}
static void lm32_cpu_class_init(ObjectClass *oc, void *data)
@@ -86,6 +254,7 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
lcc->parent_reset = cc->reset;
cc->reset = lm32_cpu_reset;
+ cc->class_by_name = lm32_cpu_class_by_name;
cc->do_interrupt = lm32_cpu_do_interrupt;
cc->dump_state = lm32_cpu_dump_state;
cc->set_pc = lm32_cpu_set_pc;
@@ -98,19 +267,36 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_num_core_regs = 32 + 7;
}
+static void lm32_register_cpu_type(const LM32CPUInfo *info)
+{
+ TypeInfo type_info = {
+ .parent = TYPE_LM32_CPU,
+ .instance_init = info->initfn,
+ };
+
+ type_info.name = g_strdup_printf("%s-" TYPE_LM32_CPU, info->name);
+ type_register(&type_info);
+ g_free((void *)type_info.name);
+}
+
static const TypeInfo lm32_cpu_type_info = {
.name = TYPE_LM32_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(LM32CPU),
.instance_init = lm32_cpu_initfn,
- .abstract = false,
+ .abstract = true,
.class_size = sizeof(LM32CPUClass),
.class_init = lm32_cpu_class_init,
};
static void lm32_cpu_register_types(void)
{
+ int i;
+
type_register_static(&lm32_cpu_type_info);
+ for (i = 0; i < ARRAY_SIZE(lm32_cpus); i++) {
+ lm32_register_cpu_type(&lm32_cpus[i]);
+ }
}
type_init(lm32_cpu_register_types)
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index dbfe043..18cf348 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -163,8 +163,11 @@ struct CPULM32State {
/* debug registers */
uint32_t dc; /* debug control */
- uint32_t bp[4]; /* breakpoint addresses */
- uint32_t wp[4]; /* watchpoint addresses */
+ uint32_t bp[4]; /* breakpoints */
+ uint32_t wp[4]; /* watchpoints */
+
+ CPUBreakpoint * cpu_breakpoint[4];
+ CPUWatchpoint * cpu_watchpoint[4];
CPU_COMMON
@@ -177,25 +180,42 @@ struct CPULM32State {
DeviceState *juart_state;
/* processor core features */
- uint32_t features;
uint32_t flags;
- uint8_t num_bps;
- uint8_t num_wps;
};
+typedef enum {
+ LM32_WP_DISABLED = 0,
+ LM32_WP_READ,
+ LM32_WP_WRITE,
+ LM32_WP_READ_WRITE,
+} lm32_wp_t;
+
+static inline lm32_wp_t lm32_wp_type(uint32_t dc, int idx)
+{
+ assert(idx < 4);
+ return (dc >> (idx+1)*2) & 0x3;
+}
+
#include "cpu-qom.h"
LM32CPU *cpu_lm32_init(const char *cpu_model);
-void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
int cpu_lm32_exec(CPULM32State *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
int cpu_lm32_signal_handler(int host_signum, void *pinfo,
void *puc);
+void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf);
void lm32_translate_init(void);
void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value);
+void QEMU_NORETURN raise_exception(CPULM32State *env, int index);
+void lm32_debug_excp_handler(CPULM32State *env);
+void lm32_breakpoint_insert(CPULM32State *env, int index, target_ulong address);
+void lm32_breakpoint_remove(CPULM32State *env, int index);
+void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
+ lm32_wp_t wp_type);
+void lm32_watchpoint_remove(CPULM32State *env, int index);
static inline CPULM32State *cpu_init(const char *cpu_model)
{
@@ -206,7 +226,7 @@ static inline CPULM32State *cpu_init(const char *cpu_model)
return &cpu->env;
}
-#define cpu_list cpu_lm32_list
+#define cpu_list lm32_cpu_list
#define cpu_exec cpu_lm32_exec
#define cpu_gen_code cpu_lm32_gen_code
#define cpu_signal_handler cpu_lm32_signal_handler
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 15bc615..eecb9f6 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -49,6 +49,96 @@ hwaddr lm32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
}
}
+void lm32_breakpoint_insert(CPULM32State *env, int idx, target_ulong address)
+{
+ cpu_breakpoint_insert(env, address, BP_CPU, &env->cpu_breakpoint[idx]);
+}
+
+void lm32_breakpoint_remove(CPULM32State *env, int idx)
+{
+ if (!env->cpu_breakpoint[idx]) {
+ return;
+ }
+
+ cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[idx]);
+ env->cpu_breakpoint[idx] = NULL;
+}
+
+void lm32_watchpoint_insert(CPULM32State *env, int idx, target_ulong address,
+ lm32_wp_t wp_type)
+{
+ int flags = 0;
+
+ switch (wp_type) {
+ case LM32_WP_DISABLED:
+ /* nothing to to */
+ break;
+ case LM32_WP_READ:
+ flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_READ;
+ break;
+ case LM32_WP_WRITE:
+ flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_WRITE;
+ break;
+ case LM32_WP_READ_WRITE:
+ flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_ACCESS;
+ break;
+ }
+
+ if (flags != 0) {
+ cpu_watchpoint_insert(env, address, 1, flags,
+ &env->cpu_watchpoint[idx]);
+ }
+}
+
+void lm32_watchpoint_remove(CPULM32State *env, int idx)
+{
+ if (!env->cpu_watchpoint[idx]) {
+ return;
+ }
+
+ cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[idx]);
+ env->cpu_watchpoint[idx] = NULL;
+}
+
+static bool check_watchpoints(CPULM32State *env)
+{
+ LM32CPU *cpu = lm32_env_get_cpu(env);
+ int i;
+
+ for (i = 0; i < cpu->num_watchpoints; i++) {
+ if (env->cpu_watchpoint[i] &&
+ env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void lm32_debug_excp_handler(CPULM32State *env)
+{
+ CPUBreakpoint *bp;
+
+ if (env->watchpoint_hit) {
+ if (env->watchpoint_hit->flags & BP_CPU) {
+ env->watchpoint_hit = NULL;
+ if (check_watchpoints(env)) {
+ raise_exception(env, EXCP_WATCHPOINT);
+ } else {
+ cpu_resume_from_signal(env, NULL);
+ }
+ }
+ } else {
+ QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+ if (bp->pc == env->pc) {
+ if (bp->flags & BP_CPU) {
+ raise_exception(env, EXCP_BREAKPOINT);
+ }
+ break;
+ }
+ }
+ }
+}
+
void lm32_cpu_do_interrupt(CPUState *cs)
{
LM32CPU *cpu = LM32_CPU(cs);
@@ -90,136 +180,16 @@ void lm32_cpu_do_interrupt(CPUState *cs)
}
}
-typedef struct {
- const char *name;
- uint32_t revision;
- uint8_t num_interrupts;
- uint8_t num_breakpoints;
- uint8_t num_watchpoints;
- uint32_t features;
-} LM32Def;
-
-static const LM32Def lm32_defs[] = {
- {
- .name = "lm32-basic",
- .revision = 3,
- .num_interrupts = 32,
- .num_breakpoints = 4,
- .num_watchpoints = 4,
- .features = (LM32_FEATURE_SHIFT
- | LM32_FEATURE_SIGN_EXTEND
- | LM32_FEATURE_CYCLE_COUNT),
- },
- {
- .name = "lm32-standard",
- .revision = 3,
- .num_interrupts = 32,
- .num_breakpoints = 4,
- .num_watchpoints = 4,
- .features = (LM32_FEATURE_MULTIPLY
- | LM32_FEATURE_DIVIDE
- | LM32_FEATURE_SHIFT
- | LM32_FEATURE_SIGN_EXTEND
- | LM32_FEATURE_I_CACHE
- | LM32_FEATURE_CYCLE_COUNT),
- },
- {
- .name = "lm32-full",
- .revision = 3,
- .num_interrupts = 32,
- .num_breakpoints = 4,
- .num_watchpoints = 4,
- .features = (LM32_FEATURE_MULTIPLY
- | LM32_FEATURE_DIVIDE
- | LM32_FEATURE_SHIFT
- | LM32_FEATURE_SIGN_EXTEND
- | LM32_FEATURE_I_CACHE
- | LM32_FEATURE_D_CACHE
- | LM32_FEATURE_CYCLE_COUNT),
- }
-};
-
-void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf)
-{
- int i;
-
- cpu_fprintf(f, "Available CPUs:\n");
- for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
- cpu_fprintf(f, " %s\n", lm32_defs[i].name);
- }
-}
-
-static const LM32Def *cpu_lm32_find_by_name(const char *name)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
- if (strcasecmp(name, lm32_defs[i].name) == 0) {
- return &lm32_defs[i];
- }
- }
-
- return NULL;
-}
-
-static uint32_t cfg_by_def(const LM32Def *def)
-{
- uint32_t cfg = 0;
-
- if (def->features & LM32_FEATURE_MULTIPLY) {
- cfg |= CFG_M;
- }
-
- if (def->features & LM32_FEATURE_DIVIDE) {
- cfg |= CFG_D;
- }
-
- if (def->features & LM32_FEATURE_SHIFT) {
- cfg |= CFG_S;
- }
-
- if (def->features & LM32_FEATURE_SIGN_EXTEND) {
- cfg |= CFG_X;
- }
-
- if (def->features & LM32_FEATURE_I_CACHE) {
- cfg |= CFG_IC;
- }
-
- if (def->features & LM32_FEATURE_D_CACHE) {
- cfg |= CFG_DC;
- }
-
- if (def->features & LM32_FEATURE_CYCLE_COUNT) {
- cfg |= CFG_CC;
- }
-
- cfg |= (def->num_interrupts << CFG_INT_SHIFT);
- cfg |= (def->num_breakpoints << CFG_BP_SHIFT);
- cfg |= (def->num_watchpoints << CFG_WP_SHIFT);
- cfg |= (def->revision << CFG_REV_SHIFT);
-
- return cfg;
-}
-
LM32CPU *cpu_lm32_init(const char *cpu_model)
{
LM32CPU *cpu;
- CPULM32State *env;
- const LM32Def *def;
+ ObjectClass *oc;
- def = cpu_lm32_find_by_name(cpu_model);
- if (!def) {
+ oc = cpu_class_by_name(TYPE_LM32_CPU, cpu_model);
+ if (oc == NULL) {
return NULL;
}
-
- cpu = LM32_CPU(object_new(TYPE_LM32_CPU));
- env = &cpu->env;
-
- env->features = def->features;
- env->num_bps = def->num_breakpoints;
- env->num_wps = def->num_watchpoints;
- env->cfg = cfg_by_def(def);
+ cpu = LM32_CPU(object_new(object_class_get_name(oc)));
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
diff --git a/target-lm32/helper.h b/target-lm32/helper.h
index 3ea15a6..f4442e0 100644
--- a/target-lm32/helper.h
+++ b/target-lm32/helper.h
@@ -2,6 +2,9 @@
DEF_HELPER_2(raise_exception, void, env, i32)
DEF_HELPER_1(hlt, void, env)
+DEF_HELPER_3(wcsr_bp, void, env, i32, i32)
+DEF_HELPER_3(wcsr_wp, void, env, i32, i32)
+DEF_HELPER_2(wcsr_dc, void, env, i32)
DEF_HELPER_2(wcsr_im, void, env, i32)
DEF_HELPER_2(wcsr_ip, void, env, i32)
DEF_HELPER_2(wcsr_jtx, void, env, i32)
@@ -10,5 +13,6 @@ DEF_HELPER_1(rcsr_im, i32, env)
DEF_HELPER_1(rcsr_ip, i32, env)
DEF_HELPER_1(rcsr_jtx, i32, env)
DEF_HELPER_1(rcsr_jrx, i32, env)
+DEF_HELPER_1(ill, void, env)
#include "exec/def-helper.h"
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 8f5ef55..7189cb5 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -8,6 +8,10 @@
#include "exec/softmmu_exec.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu/sysemu.h"
+#endif
+
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _mmu
#define SHIFT 0
@@ -19,12 +23,17 @@
#define SHIFT 3
#include "exec/softmmu_template.h"
-void HELPER(raise_exception)(CPULM32State *env, uint32_t index)
+void raise_exception(CPULM32State *env, int index)
{
env->exception_index = index;
cpu_loop_exit(env);
}
+void HELPER(raise_exception)(CPULM32State *env, uint32_t index)
+{
+ raise_exception(env, index);
+}
+
void HELPER(hlt)(CPULM32State *env)
{
CPUState *cs = CPU(lm32_env_get_cpu(env));
@@ -34,6 +43,70 @@ void HELPER(hlt)(CPULM32State *env)
cpu_loop_exit(env);
}
+void HELPER(ill)(CPULM32State *env)
+{
+#ifndef CONFIG_USER_ONLY
+ CPUState *cs = CPU(lm32_env_get_cpu(env));
+ fprintf(stderr, "VM paused due to illegal instruction. "
+ "Connect a debugger or switch to the monitor console "
+ "to find out more.\n");
+ qemu_system_vmstop_request(RUN_STATE_PAUSED);
+ cs->halted = 1;
+ raise_exception(env, EXCP_HALTED);
+#endif
+}
+
+void HELPER(wcsr_bp)(CPULM32State *env, uint32_t bp, uint32_t idx)
+{
+ uint32_t addr = bp & ~1;
+
+ assert(idx < 4);
+
+ env->bp[idx] = bp;
+ lm32_breakpoint_remove(env, idx);
+ if (bp & 1) {
+ lm32_breakpoint_insert(env, idx, addr);
+ }
+}
+
+void HELPER(wcsr_wp)(CPULM32State *env, uint32_t wp, uint32_t idx)
+{
+ lm32_wp_t wp_type;
+
+ assert(idx < 4);
+
+ env->wp[idx] = wp;
+
+ wp_type = lm32_wp_type(env->dc, idx);
+ lm32_watchpoint_remove(env, idx);
+ if (wp_type != LM32_WP_DISABLED) {
+ lm32_watchpoint_insert(env, idx, wp, wp_type);
+ }
+}
+
+void HELPER(wcsr_dc)(CPULM32State *env, uint32_t dc)
+{
+ uint32_t old_dc;
+ int i;
+ lm32_wp_t old_type;
+ lm32_wp_t new_type;
+
+ old_dc = env->dc;
+ env->dc = dc;
+
+ for (i = 0; i < 4; i++) {
+ old_type = lm32_wp_type(old_dc, i);
+ new_type = lm32_wp_type(dc, i);
+
+ if (old_type != new_type) {
+ lm32_watchpoint_remove(env, i);
+ if (new_type != LM32_WP_DISABLED) {
+ lm32_watchpoint_insert(env, i, env->wp[i], new_type);
+ }
+ }
+ }
+}
+
void HELPER(wcsr_im)(CPULM32State *env, uint32_t im)
{
lm32_pic_set_im(env->pic_state, im);
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index 6ea0ecd..80bffc7 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -64,7 +64,6 @@ enum {
/* This is the state at translation time. */
typedef struct DisasContext {
- CPULM32State *env;
target_ulong pc;
/* Decoder. */
@@ -80,9 +79,12 @@ typedef struct DisasContext {
unsigned int tb_flags, synced_flags; /* tb dependent flags. */
int is_jmp;
- int nr_nops;
struct TranslationBlock *tb;
int singlestep_enabled;
+
+ uint32_t features;
+ uint8_t num_breakpoints;
+ uint8_t num_watchpoints;
} DisasContext;
static const char *regnames[] = {
@@ -120,6 +122,12 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
tcg_temp_free_i32(tmp);
}
+static inline void t_gen_illegal_insn(DisasContext *dc)
+{
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ gen_helper_ill(cpu_env);
+}
+
static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
{
TranslationBlock *tb;
@@ -421,8 +429,10 @@ static void dec_divu(DisasContext *dc)
LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
- cpu_abort(dc->env, "hardware divider is not available\n");
+ if (!(dc->features & LM32_FEATURE_DIVIDE)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
}
l1 = gen_new_label();
@@ -499,8 +509,10 @@ static void dec_modu(DisasContext *dc)
LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
- if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
- cpu_abort(dc->env, "hardware divider is not available\n");
+ if (!(dc->features & LM32_FEATURE_DIVIDE)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
}
l1 = gen_new_label();
@@ -520,8 +532,11 @@ static void dec_mul(DisasContext *dc)
LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
- cpu_abort(dc->env, "hardware multiplier is not available\n");
+ if (!(dc->features & LM32_FEATURE_MULTIPLY)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware multiplier is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
}
if (dc->format == OP_FMT_RI) {
@@ -585,20 +600,21 @@ static void dec_orhi(DisasContext *dc)
static void dec_scall(DisasContext *dc)
{
- if (dc->imm5 == 7) {
- LOG_DIS("scall\n");
- } else if (dc->imm5 == 2) {
+ switch (dc->imm5) {
+ case 2:
LOG_DIS("break\n");
- } else {
- cpu_abort(dc->env, "invalid opcode\n");
- }
-
- if (dc->imm5 == 7) {
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
- } else {
tcg_gen_movi_tl(cpu_pc, dc->pc);
t_gen_raise_exception(dc, EXCP_BREAKPOINT);
+ break;
+ case 7:
+ LOG_DIS("scall\n");
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc);
+ t_gen_illegal_insn(dc);
+ break;
}
}
@@ -647,10 +663,10 @@ static void dec_rcsr(DisasContext *dc)
case CSR_WP1:
case CSR_WP2:
case CSR_WP3:
- cpu_abort(dc->env, "invalid read access csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid read access csr=%x\n", dc->csr);
break;
default:
- cpu_abort(dc->env, "read_csr: unknown csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "read_csr: unknown csr=%x\n", dc->csr);
break;
}
}
@@ -671,8 +687,11 @@ static void dec_sextb(DisasContext *dc)
{
LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
- if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
- cpu_abort(dc->env, "hardware sign extender is not available\n");
+ if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware sign extender is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
}
tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
@@ -682,8 +701,11 @@ static void dec_sexth(DisasContext *dc)
{
LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
- if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
- cpu_abort(dc->env, "hardware sign extender is not available\n");
+ if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware sign extender is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
}
tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
@@ -709,8 +731,10 @@ static void dec_sl(DisasContext *dc)
LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
- cpu_abort(dc->env, "hardware shifter is not available\n");
+ if (!(dc->features & LM32_FEATURE_SHIFT)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
}
if (dc->format == OP_FMT_RI) {
@@ -731,22 +755,32 @@ static void dec_sr(DisasContext *dc)
LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
- if (dc->format == OP_FMT_RI) {
- /* TODO: check r1 == 1 during runtime */
- } else {
- if (dc->imm5 != 1) {
- cpu_abort(dc->env, "hardware shifter is not available\n");
- }
- }
- }
-
+ /* The real CPU (w/o hardware shifter) only supports right shift by exactly
+ * one bit */
if (dc->format == OP_FMT_RI) {
+ if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware shifter is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
+ }
tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
} else {
- TCGv t0 = tcg_temp_new();
+ int l1 = gen_new_label();
+ int l2 = gen_new_label();
+ TCGv t0 = tcg_temp_local_new();
tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+
+ if (!(dc->features & LM32_FEATURE_SHIFT)) {
+ tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1);
+ t_gen_illegal_insn(dc);
+ tcg_gen_br(l2);
+ }
+
+ gen_set_label(l1);
tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+ gen_set_label(l2);
+
tcg_temp_free(t0);
}
}
@@ -759,22 +793,30 @@ static void dec_sru(DisasContext *dc)
LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
- if (dc->format == OP_FMT_RI) {
- /* TODO: check r1 == 1 during runtime */
- } else {
- if (dc->imm5 != 1) {
- cpu_abort(dc->env, "hardware shifter is not available\n");
- }
- }
- }
-
if (dc->format == OP_FMT_RI) {
+ if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware shifter is not available\n");
+ t_gen_illegal_insn(dc);
+ return;
+ }
tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
} else {
- TCGv t0 = tcg_temp_new();
+ int l1 = gen_new_label();
+ int l2 = gen_new_label();
+ TCGv t0 = tcg_temp_local_new();
tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+
+ if (!(dc->features & LM32_FEATURE_SHIFT)) {
+ tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1);
+ t_gen_illegal_insn(dc);
+ tcg_gen_br(l2);
+ }
+
+ gen_set_label(l1);
tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+ gen_set_label(l2);
+
tcg_temp_free(t0);
}
}
@@ -802,7 +844,8 @@ static void dec_user(DisasContext *dc)
{
LOG_DIS("user");
- cpu_abort(dc->env, "user insn undefined\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "user instruction undefined\n");
+ t_gen_illegal_insn(dc);
}
static void dec_wcsr(DisasContext *dc)
@@ -860,34 +903,42 @@ static void dec_wcsr(DisasContext *dc)
gen_helper_wcsr_jrx(cpu_env, cpu_R[dc->r1]);
break;
case CSR_DC:
- tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]);
+ gen_helper_wcsr_dc(cpu_env, cpu_R[dc->r1]);
break;
case CSR_BP0:
case CSR_BP1:
case CSR_BP2:
case CSR_BP3:
no = dc->csr - CSR_BP0;
- if (dc->env->num_bps <= no) {
- cpu_abort(dc->env, "breakpoint #%i is not available\n", no);
+ if (dc->num_breakpoints <= no) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "breakpoint #%i is not available\n", no);
+ t_gen_illegal_insn(dc);
+ break;
}
- tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
+ gen_helper_wcsr_bp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no));
break;
case CSR_WP0:
case CSR_WP1:
case CSR_WP2:
case CSR_WP3:
no = dc->csr - CSR_WP0;
- if (dc->env->num_wps <= no) {
- cpu_abort(dc->env, "watchpoint #%i is not available\n", no);
+ if (dc->num_watchpoints <= no) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "watchpoint #%i is not available\n", no);
+ t_gen_illegal_insn(dc);
+ break;
}
- tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
+ gen_helper_wcsr_wp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no));
break;
case CSR_CC:
case CSR_CFG:
- cpu_abort(dc->env, "invalid write access csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid write access csr=%x\n",
+ dc->csr);
break;
default:
- cpu_abort(dc->env, "write_csr unknown csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "write_csr: unknown csr=%x\n",
+ dc->csr);
break;
}
}
@@ -933,7 +984,8 @@ static void dec_xor(DisasContext *dc)
static void dec_ill(DisasContext *dc)
{
- cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode);
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode 0x%02x\n", dc->opcode);
+ t_gen_illegal_insn(dc);
}
typedef void (*DecoderInfo)(DisasContext *dc);
@@ -959,18 +1011,6 @@ static inline void decode(DisasContext *dc, uint32_t ir)
dc->ir = ir;
LOG_DIS("%8.8x\t", dc->ir);
- /* try guessing 'empty' instruction memory, although it may be a valid
- * instruction sequence (eg. srui r0, r0, 0) */
- if (dc->ir) {
- dc->nr_nops = 0;
- } else {
- LOG_DIS("nr_nops=%d\t", dc->nr_nops);
- dc->nr_nops++;
- if (dc->nr_nops > 4) {
- cpu_abort(dc->env, "fetching nop sequence\n");
- }
- }
-
dc->opcode = EXTRACT_FIELD(ir, 26, 31);
dc->imm5 = EXTRACT_FIELD(ir, 0, 4);
@@ -1026,7 +1066,9 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
int max_insns;
pc_start = tb->pc;
- dc->env = env;
+ dc->features = cpu->features;
+ dc->num_breakpoints = cpu->num_breakpoints;
+ dc->num_watchpoints = cpu->num_watchpoints;
dc->tb = tb;
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
@@ -1034,10 +1076,11 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
dc->singlestep_enabled = cs->singlestep_enabled;
- dc->nr_nops = 0;
if (pc_start & 3) {
- cpu_abort(env, "LM32: unaligned PC=%x\n", pc_start);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "unaligned PC=%x. Ignoring lowest bits.\n", pc_start);
+ pc_start &= ~3;
}
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 68b5ab7..96c2b4a 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -78,11 +78,6 @@ typedef struct MchkQueue {
uint16_t type;
} MchkQueue;
-/* Defined values for CPUS390XState.runtime_reg_dirty_mask */
-#define KVM_S390_RUNTIME_DIRTY_NONE 0
-#define KVM_S390_RUNTIME_DIRTY_PARTIAL 1
-#define KVM_S390_RUNTIME_DIRTY_FULL 2
-
typedef struct CPUS390XState {
uint64_t regs[16]; /* GP registers */
CPU_DoubleU fregs[16]; /* FP registers */
@@ -126,13 +121,6 @@ typedef struct CPUS390XState {
uint64_t cputm;
uint32_t todpr;
- /* on S390 the runtime register set has two dirty states:
- * a partial dirty state in which only the registers that
- * are needed all the time are fetched. And a fully dirty
- * state in which all runtime registers are fetched.
- */
- uint32_t runtime_reg_dirty_mask;
-
CPU_COMMON
/* reset does memset(0) up to here */
@@ -1076,7 +1064,6 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id,
uint32_t io_int_word);
void kvm_s390_crw_mchk(S390CPU *cpu);
void kvm_s390_enable_css_support(S390CPU *cpu);
-int kvm_s390_get_registers_partial(CPUState *cpu);
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign);
int kvm_s390_cpu_restart(S390CPU *cpu);
@@ -1094,10 +1081,6 @@ static inline void kvm_s390_crw_mchk(S390CPU *cpu)
static inline void kvm_s390_enable_css_support(S390CPU *cpu)
{
}
-static inline int kvm_s390_get_registers_partial(CPUState *cpu)
-{
- return -ENOSYS;
-}
static inline int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier,
uint32_t sch, int vq,
bool assign)
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index f7b7726..f60ccdc 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -152,33 +152,30 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
}
- if (env->runtime_reg_dirty_mask == KVM_S390_RUNTIME_DIRTY_FULL) {
- reg.id = KVM_REG_S390_CPU_TIMER;
- reg.addr = (__u64)&(env->cputm);
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
- if (ret < 0) {
- return ret;
- }
+ /* Do we need to save more than that? */
+ if (level == KVM_PUT_RUNTIME_STATE) {
+ return 0;
+ }
- reg.id = KVM_REG_S390_CLOCK_COMP;
- reg.addr = (__u64)&(env->ckc);
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
- if (ret < 0) {
- return ret;
- }
+ reg.id = KVM_REG_S390_CPU_TIMER;
+ reg.addr = (__u64)&(env->cputm);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ return ret;
+ }
- reg.id = KVM_REG_S390_TODPR;
- reg.addr = (__u64)&(env->todpr);
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
- if (ret < 0) {
- return ret;
- }
+ reg.id = KVM_REG_S390_CLOCK_COMP;
+ reg.addr = (__u64)&(env->ckc);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ return ret;
}
- env->runtime_reg_dirty_mask = KVM_S390_RUNTIME_DIRTY_NONE;
- /* Do we need to save more than that? */
- if (level == KVM_PUT_RUNTIME_STATE) {
- return 0;
+ reg.id = KVM_REG_S390_TODPR;
+ reg.addr = (__u64)&(env->todpr);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ return ret;
}
if (cap_sync_regs &&
@@ -216,50 +213,9 @@ int kvm_arch_get_registers(CPUState *cs)
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
struct kvm_one_reg reg;
- int r;
-
- r = kvm_s390_get_registers_partial(cs);
- if (r < 0) {
- return r;
- }
-
- reg.id = KVM_REG_S390_CPU_TIMER;
- reg.addr = (__u64)&(env->cputm);
- r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
- if (r < 0) {
- return r;
- }
-
- reg.id = KVM_REG_S390_CLOCK_COMP;
- reg.addr = (__u64)&(env->ckc);
- r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
- if (r < 0) {
- return r;
- }
-
- reg.id = KVM_REG_S390_TODPR;
- reg.addr = (__u64)&(env->todpr);
- r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
- if (r < 0) {
- return r;
- }
-
- env->runtime_reg_dirty_mask = KVM_S390_RUNTIME_DIRTY_FULL;
- return 0;
-}
-
-int kvm_s390_get_registers_partial(CPUState *cs)
-{
- S390CPU *cpu = S390_CPU(cs);
- CPUS390XState *env = &cpu->env;
struct kvm_sregs sregs;
struct kvm_regs regs;
- int ret;
- int i;
-
- if (env->runtime_reg_dirty_mask) {
- return 0;
- }
+ int i, r;
/* get the PSW */
env->psw.addr = cs->kvm_run->psw_addr;
@@ -271,9 +227,9 @@ int kvm_s390_get_registers_partial(CPUState *cs)
env->regs[i] = cs->kvm_run->s.regs.gprs[i];
}
} else {
- ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
- if (ret < 0) {
- return ret;
+ r = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
+ if (r < 0) {
+ return r;
}
for (i = 0; i < 16; i++) {
env->regs[i] = regs.gprs[i];
@@ -289,9 +245,9 @@ int kvm_s390_get_registers_partial(CPUState *cs)
env->cregs[i] = cs->kvm_run->s.regs.crs[i];
}
} else {
- ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
- if (ret < 0) {
- return ret;
+ r = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
+ if (r < 0) {
+ return r;
}
for (i = 0; i < 16; i++) {
env->aregs[i] = sregs.acrs[i];
@@ -299,14 +255,33 @@ int kvm_s390_get_registers_partial(CPUState *cs)
}
}
- /* Finally the prefix */
+ /* The prefix */
if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) {
env->psa = cs->kvm_run->s.regs.prefix;
- } else {
- /* no prefix without sync regs */
}
- env->runtime_reg_dirty_mask = KVM_S390_RUNTIME_DIRTY_PARTIAL;
+ /* One Regs */
+ reg.id = KVM_REG_S390_CPU_TIMER;
+ reg.addr = (__u64)&(env->cputm);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (r < 0) {
+ return r;
+ }
+
+ reg.id = KVM_REG_S390_CLOCK_COMP;
+ reg.addr = (__u64)&(env->ckc);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (r < 0) {
+ return r;
+ }
+
+ reg.id = KVM_REG_S390_TODPR;
+ reg.addr = (__u64)&(env->todpr);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (r < 0) {
+ return r;
+ }
+
return 0;
}
@@ -442,15 +417,13 @@ static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
uint8_t ipa0, uint8_t ipa1, uint8_t ipb)
{
CPUS390XState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
if (ipa0 != 0xb2) {
/* Not handled for now. */
return -1;
}
- kvm_s390_get_registers_partial(cs);
- cs->kvm_vcpu_dirty = true;
+ cpu_synchronize_state(CPU(cpu));
switch (ipa1) {
case PRIV_XSCH:
@@ -537,11 +510,9 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run,
static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
{
- CPUState *cs = CPU(cpu);
CPUS390XState *env = &cpu->env;
- kvm_s390_get_registers_partial(cs);
- cs->kvm_vcpu_dirty = true;
+ cpu_synchronize_state(CPU(cpu));
env->regs[2] = s390_virtio_hypercall(env);
return 0;
@@ -767,8 +738,7 @@ static int handle_tsch(S390CPU *cpu)
struct kvm_run *run = cs->kvm_run;
int ret;
- kvm_s390_get_registers_partial(cs);
- cs->kvm_vcpu_dirty = true;
+ cpu_synchronize_state(cs);
ret = ioinst_handle_tsch(env, env->regs[1], run->s390_tsch.ipb);
if (ret >= 0) {
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 248726e..907d9d1 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -2214,25 +2214,6 @@ static const TCGTargetOpDef s390_op_defs[] = {
{ -1 },
};
-/* ??? Linux kernels provide an AUXV entry AT_HWCAP that provides most of
- this information. However, getting at that entry is not easy this far
- away from main. Our options are: start searching from environ, but
- that fails as soon as someone does a setenv in between. Read the data
- from /proc/self/auxv. Or do the probing ourselves. The only thing
- extra that AT_HWCAP gives us is HWCAP_S390_HIGH_GPRS, which indicates
- that the kernel saves all 64-bits of the registers around traps while
- in 31-bit mode. But this is true of all "recent" kernels (ought to dig
- back and see from when this might not be true). */
-
-#include <signal.h>
-
-static volatile sig_atomic_t got_sigill;
-
-static void sigill_handler(int sig)
-{
- got_sigill = 1;
-}
-
static void query_facilities(void)
{
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
diff --git a/tests/.gitignore b/tests/.gitignore
index 1aed224..9ba9d96 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -4,6 +4,7 @@ check-qint
check-qjson
check-qlist
check-qstring
+check-qom-interface
test-aio
test-bitops
test-throttle
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 359d571..c9a4f89 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -43,9 +43,8 @@ struct QTestState
int qmp_fd;
bool irq_level[MAX_IRQ];
GString *rx;
- gchar *pid_file; /* QEMU PID file */
int child_pid; /* Child process created to execute QEMU */
- char *socket_path, *qmp_socket_path;
+ pid_t qemu_pid; /* QEMU process spawned by our child */
};
#define g_assert_no_errno(ret) do { \
@@ -90,13 +89,13 @@ static int socket_accept(int sock)
return ret;
}
-static pid_t qtest_qemu_pid(QTestState *s)
+static pid_t read_pid_file(const char *pid_file)
{
FILE *f;
char buffer[1024];
pid_t pid = -1;
- f = fopen(s->pid_file, "r");
+ f = fopen(pid_file, "r");
if (f) {
if (fgets(buffer, sizeof(buffer), f)) {
pid = atoi(buffer);
@@ -110,6 +109,8 @@ QTestState *qtest_init(const char *extra_args)
{
QTestState *s;
int sock, qmpsock, i;
+ gchar *socket_path;
+ gchar *qmp_socket_path;
gchar *pid_file;
gchar *command;
const char *qemu_binary;
@@ -120,12 +121,12 @@ QTestState *qtest_init(const char *extra_args)
s = g_malloc(sizeof(*s));
- s->socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
- s->qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
+ socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
+ qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
- sock = init_socket(s->socket_path);
- qmpsock = init_socket(s->qmp_socket_path);
+ sock = init_socket(socket_path);
+ qmpsock = init_socket(qmp_socket_path);
pid = fork();
if (pid == 0) {
@@ -136,8 +137,8 @@ QTestState *qtest_init(const char *extra_args)
"-pidfile %s "
"-machine accel=qtest "
"-display none "
- "%s", qemu_binary, s->socket_path,
- s->qmp_socket_path, pid_file,
+ "%s", qemu_binary, socket_path,
+ qmp_socket_path, pid_file,
extra_args ?: "");
execlp("/bin/sh", "sh", "-c", command, NULL);
exit(1);
@@ -145,9 +146,12 @@ QTestState *qtest_init(const char *extra_args)
s->fd = socket_accept(sock);
s->qmp_fd = socket_accept(qmpsock);
+ unlink(socket_path);
+ unlink(qmp_socket_path);
+ g_free(socket_path);
+ g_free(qmp_socket_path);
s->rx = g_string_new("");
- s->pid_file = pid_file;
s->child_pid = pid;
for (i = 0; i < MAX_IRQ; i++) {
s->irq_level[i] = false;
@@ -157,8 +161,12 @@ QTestState *qtest_init(const char *extra_args)
qtest_qmp_discard_response(s, "");
qtest_qmp_discard_response(s, "{ 'execute': 'qmp_capabilities' }");
+ s->qemu_pid = read_pid_file(pid_file);
+ unlink(pid_file);
+ g_free(pid_file);
+
if (getenv("QTEST_STOP")) {
- kill(qtest_qemu_pid(s), SIGSTOP);
+ kill(s->qemu_pid, SIGSTOP);
}
return s;
@@ -168,21 +176,14 @@ void qtest_quit(QTestState *s)
{
int status;
- pid_t pid = qtest_qemu_pid(s);
- if (pid != -1) {
- kill(pid, SIGTERM);
- waitpid(pid, &status, 0);
+ if (s->qemu_pid != -1) {
+ kill(s->qemu_pid, SIGTERM);
+ waitpid(s->qemu_pid, &status, 0);
}
close(s->fd);
close(s->qmp_fd);
g_string_free(s->rx, true);
- unlink(s->pid_file);
- unlink(s->socket_path);
- unlink(s->qmp_socket_path);
- g_free(s->pid_file);
- g_free(s->socket_path);
- g_free(s->qmp_socket_path);
g_free(s);
}
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
index 72eaad5..734b6a6 100755
--- a/tests/qemu-iotests/040
+++ b/tests/qemu-iotests/040
@@ -35,12 +35,8 @@ test_img = os.path.join(iotests.test_dir, 'test.img')
class ImageCommitTestCase(iotests.QMPTestCase):
'''Abstract base class for image commit test cases'''
- def assert_no_active_commit(self):
- result = self.vm.qmp('query-block-jobs')
- self.assert_qmp(result, 'return', [])
-
def run_commit_test(self, top, base):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top=top, base=base)
self.assert_qmp(result, 'return', {})
@@ -59,7 +55,7 @@ class ImageCommitTestCase(iotests.QMPTestCase):
self.assert_qmp(event, 'data/len', self.image_len)
self.vm.qmp('block-job-complete', device='drive0')
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
class TestSingleDrive(ImageCommitTestCase):
@@ -91,19 +87,19 @@ class TestSingleDrive(ImageCommitTestCase):
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
def test_top_same_base(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % backing_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % backing_img)
def test_top_invalid(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % backing_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Top image file badfile not found')
def test_base_invalid(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % mid_img, base='badfile')
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found')
@@ -114,13 +110,13 @@ class TestSingleDrive(ImageCommitTestCase):
self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
def test_top_and_base_reversed(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img)
def test_top_omitted(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0')
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', "Parameter 'top' is missing")
@@ -181,19 +177,19 @@ class TestRelativePaths(ImageCommitTestCase):
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
def test_top_same_base(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='%s' % self.mid_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % self.mid_img)
def test_top_invalid(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % self.backing_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Top image file badfile not found')
def test_base_invalid(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='badfile')
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found')
@@ -204,7 +200,7 @@ class TestRelativePaths(ImageCommitTestCase):
self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed"))
def test_top_and_base_reversed(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.backing_img, base='%s' % self.mid_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % self.mid_img)
@@ -229,7 +225,7 @@ class TestSetSpeed(ImageCommitTestCase):
os.remove(backing_img)
def test_set_speed(self):
- self.assert_no_active_commit()
+ self.assert_no_active_block_jobs()
self.vm.pause_drive('drive0')
result = self.vm.qmp('block-commit', device='drive0', top=mid_img, speed=1024 * 1024)
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 2a22546..dbc07c6 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt generic
+_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile
index 9a00ef7..8e5d405 100644
--- a/tests/tcg/lm32/Makefile
+++ b/tests/tcg/lm32/Makefile
@@ -96,10 +96,10 @@ all: build
build: $(CRT) $(TESTCASES)
-check: $(CRT) $(SYS) $(TESTCASES)
- @for case in $(TESTCASES); do \
- $(SIM) $(SIMFLAGS) ./$$case; \
- done
+check: $(TESTCASES:test_%.tst=check_%)
+
+check_%: test_%.tst $(CRT) $(SYS)
+ $(SIM) $(SIMFLAGS) $<
clean:
$(RM) -fr $(TESTCASES) $(CRT)
diff --git a/util/osdep.c b/util/osdep.c
index 62072b4..bd4f530 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -46,7 +46,6 @@ extern int madvise(caddr_t, size_t, int);
#endif
#include "qemu-common.h"
-#include "trace.h"
#include "qemu/sockets.h"
#include "monitor/monitor.h"
OpenPOWER on IntegriCloud