From 835cab85ad83ed8dfe1c13243aeda5959b153e3e Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 13 Aug 2012 10:32:32 +0200 Subject: spice: abort on invalid streaming cmdline params When parsing its command line parameters, spice aborts when it finds unexpected values, except for the 'streaming-video' option. This happens because the parsing of the parameters for this option is done using the 'name2enum' helper, which does not error out on unknown values. Using the 'parse_name' helper makes sure we error out in this case. Looking at git history, the use of 'name2enum' instead of 'parse_name' seems to have been an oversight, so let's change to that now. Fixes rhbz#831708 Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 4fc48f890..bb4f58584 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -344,7 +344,8 @@ static const char *stream_video_names[] = { [ SPICE_STREAM_VIDEO_FILTER ] = "filter", }; #define parse_stream_video(_name) \ - name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names)) + parse_name(_name, "stream video control", \ + stream_video_names, ARRAY_SIZE(stream_video_names)) static const char *compression_names[] = { [ SPICE_IMAGE_COMPRESS_OFF ] = "off", -- cgit v1.2.3 From f5bb039c6d97ef3e664094eab3c9a4dc1824ed73 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 21 Aug 2012 11:51:55 +0300 Subject: spice: notify spice server on vm start/stop Spice server needs to know about the vm state in order to prevent attempts to write to devices when they are stopped, mainly during the non-live stage of migration. Instead, spice will take care of restoring this writes, on the migration target side, after migration completes. Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ui/spice-core.c b/ui/spice-core.c index bb4f58584..a515c946c 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -546,6 +546,18 @@ static int add_channel(const char *name, const char *value, void *opaque) return 0; } +static void vm_change_state_handler(void *opaque, int running, + RunState state) +{ +#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ + if (running) { + spice_server_vm_start(spice_server); + } else { + spice_server_vm_stop(spice_server); + } +#endif +} + void qemu_spice_init(void) { QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); @@ -719,6 +731,8 @@ void qemu_spice_init(void) qemu_spice_input_init(); qemu_spice_audio_init(); + qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server); + g_free(x509_key_file); g_free(x509_cert_file); g_free(x509_cacert_file); -- cgit v1.2.3 From 71d388d420e68ac77cd42f15f7e68cf5a6fb01b2 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 21 Aug 2012 11:51:56 +0300 Subject: spice: notify on vm state change only via spice_server_vm_start/stop QXLWorker->start/stop are deprecated since spice-server 0.11.2 Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 7 ++++--- ui/spice-core.c | 4 ++++ ui/spice-display.c | 32 ++++++++++++++++++++++++++++++-- ui/spice-display.h | 9 +++++++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index c2dd3b471..95bbc031c 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -958,9 +958,10 @@ static void qxl_update_irq(PCIQXLDevice *d) static void qxl_check_state(PCIQXLDevice *d) { QXLRam *ram = d->ram; + int spice_display_running = qemu_spice_display_is_running(&d->ssd); - assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); - assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); + assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); + assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); } static void qxl_reset_state(PCIQXLDevice *d) @@ -1538,7 +1539,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) uint32_t old_pending; uint32_t le_events = cpu_to_le32(events); - assert(d->ssd.running); + assert(qemu_spice_display_is_running(&d->ssd)); old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); if ((old_pending & le_events) == le_events) { return; diff --git a/ui/spice-core.c b/ui/spice-core.c index a515c946c..1a7a77345 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -37,6 +37,7 @@ #include "migration.h" #include "monitor.h" #include "hw/hw.h" +#include "spice-display.h" /* core bits */ @@ -551,9 +552,11 @@ static void vm_change_state_handler(void *opaque, int running, { #if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ if (running) { + qemu_spice_display_start(); spice_server_vm_start(spice_server); } else { spice_server_vm_stop(spice_server); + qemu_spice_display_stop(); } #endif } @@ -755,6 +758,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) spice_server = spice_server_new(); spice_server_init(spice_server, &core_interface); } + return spice_server_add_interface(spice_server, sin); } diff --git a/ui/spice-display.c b/ui/spice-display.c index 3e8f0b3ad..1c31418a4 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -126,18 +126,44 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) ssd->worker->wakeup(ssd->worker); } -void qemu_spice_start(SimpleSpiceDisplay *ssd) +#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ +static void qemu_spice_start(SimpleSpiceDisplay *ssd) { trace_qemu_spice_start(ssd->qxl.id); ssd->worker->start(ssd->worker); } -void qemu_spice_stop(SimpleSpiceDisplay *ssd) +static void qemu_spice_stop(SimpleSpiceDisplay *ssd) { trace_qemu_spice_stop(ssd->qxl.id); ssd->worker->stop(ssd->worker); } +#else + +static int spice_display_is_running; + +void qemu_spice_display_start(void) +{ + spice_display_is_running = true; +} + +void qemu_spice_display_stop(void) +{ + spice_display_is_running = false; +} + +#endif + +int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) +{ +#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ + return ssd->running; +#else + return spice_display_is_running; +#endif +} + static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) { SimpleSpiceUpdate *update; @@ -272,6 +298,7 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) void qemu_spice_vm_change_state_handler(void *opaque, int running, RunState state) { +#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ SimpleSpiceDisplay *ssd = opaque; if (running) { @@ -281,6 +308,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, qemu_spice_stop(ssd); ssd->running = false; } +#endif } void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) diff --git a/ui/spice-display.h b/ui/spice-display.h index 12e50b6ef..672d65ec3 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -82,7 +82,9 @@ struct SimpleSpiceDisplay { QXLRect dirty; int notify; +#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ int running; +#endif /* * All struct members below this comment can be accessed from @@ -129,5 +131,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, qxl_async_io async); void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); -void qemu_spice_start(SimpleSpiceDisplay *ssd); -void qemu_spice_stop(SimpleSpiceDisplay *ssd); +#if SPICE_SERVER_VERSION >= 0x000b02 /* before 0.11.2 */ +void qemu_spice_display_start(void); +void qemu_spice_display_stop(void); +#endif +int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd); -- cgit v1.2.3 From 2fdd16e239c2a2763aa3266e637718123328688c Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 21 Aug 2012 11:51:57 +0300 Subject: spice migration: add QEVENT_SPICE_MIGRATE_COMPLETED When migrating, libvirt queries the migration status, and upon migration completions, it closes the migration src. On the other hand, when migration is completed, spice transfers data from the src to destination via the client. This data is required for keeping the spice session after migration, without suffering from data loss and inconsistencies. In order to allow this data transfer, we add QEVENT for signaling libvirt that spice migration has completed, and libvirt needs to wait for this event before quitting the src process. Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- monitor.c | 1 + monitor.h | 1 + ui/spice-core.c | 9 ++++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index b17b1bb84..413edf4b3 100644 --- a/monitor.c +++ b/monitor.c @@ -455,6 +455,7 @@ static const char *monitor_event_names[] = { [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", [QEVENT_WAKEUP] = "WAKEUP", [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", + [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED", }; QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) diff --git a/monitor.h b/monitor.h index 47d556b9d..5fc2983b9 100644 --- a/monitor.h +++ b/monitor.h @@ -43,6 +43,7 @@ typedef enum MonitorEvent { QEVENT_SUSPEND_DISK, QEVENT_WAKEUP, QEVENT_BALLOON_CHANGE, + QEVENT_SPICE_MIGRATE_COMPLETED, /* Add to 'monitor_event_names' array in monitor.c when * defining new events here */ diff --git a/ui/spice-core.c b/ui/spice-core.c index 1a7a77345..851e869ec 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -285,6 +285,7 @@ typedef struct SpiceMigration { } SpiceMigration; static void migrate_connect_complete_cb(SpiceMigrateInstance *sin); +static void migrate_end_complete_cb(SpiceMigrateInstance *sin); static const SpiceMigrateInterface migrate_interface = { .base.type = SPICE_INTERFACE_MIGRATION, @@ -292,7 +293,7 @@ static const SpiceMigrateInterface migrate_interface = { .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR, .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR, .migrate_connect_complete = migrate_connect_complete_cb, - .migrate_end_complete = NULL, + .migrate_end_complete = migrate_end_complete_cb, }; static SpiceMigration spice_migrate; @@ -305,6 +306,11 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) } sm->connect_complete.cb = NULL; } + +static void migrate_end_complete_cb(SpiceMigrateInstance *sin) +{ + monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); +} #endif /* config string parsing */ @@ -489,6 +495,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) } else if (migration_has_finished(s)) { #ifndef SPICE_INTERFACE_MIGRATION spice_server_migrate_switch(spice_server); + monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); #else spice_server_migrate_end(spice_server, true); } else if (migration_has_failed(s)) { -- cgit v1.2.3 From 61c4efe2cb85b0a9c6bc68f6a2dd107c8d7ec080 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 21 Aug 2012 11:51:58 +0300 Subject: spice: add 'migrated' flag to spice info The flag is 'true' when spice migration has completed on the src side. It is needed for a case where libvirt dies before migration completes and it misses the event QEVENT_SPICE_MIGRATE_COMPLETED. When libvirt is restored and queries the migration status, it also needs to query spice and check if its migration has completed. Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- hmp.c | 2 ++ qapi-schema.json | 5 ++++- ui/spice-core.c | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hmp.c b/hmp.c index 81c8acb67..ec4274b3d 100644 --- a/hmp.c +++ b/hmp.c @@ -413,6 +413,8 @@ void hmp_info_spice(Monitor *mon) monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", info->host, info->tls_port); } + monitor_printf(mon, " migrated: %s\n", + info->migrated ? "true" : "false"); monitor_printf(mon, " auth: %s\n", info->auth); monitor_printf(mon, " compiled: %s\n", info->compiled_version); monitor_printf(mon, " mouse-mode: %s\n", diff --git a/qapi-schema.json b/qapi-schema.json index bd8ad7449..8ddde1298 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -808,6 +808,9 @@ # # @enabled: true if the SPICE server is enabled, false otherwise # +# @migrated: true if the last guest migration completed and spice +# migration had completed as well. false otherwise. +# # @host: #optional The hostname the SPICE server is bound to. This depends on # the name resolution on the host and may be an IP address. # @@ -833,7 +836,7 @@ # Since: 0.14.0 ## { 'type': 'SpiceInfo', - 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int', + 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int', '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} } diff --git a/ui/spice-core.c b/ui/spice-core.c index 851e869ec..ab069c5b6 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -46,6 +46,7 @@ static Notifier migration_state; static const char *auth = "spice"; static char *auth_passwd; static time_t auth_expires = TIME_MAX; +static int spice_migration_completed; int using_spice = 0; static QemuThread me; @@ -310,6 +311,7 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) static void migrate_end_complete_cb(SpiceMigrateInstance *sin) { monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); + spice_migration_completed = true; } #endif @@ -443,6 +445,7 @@ SpiceInfo *qmp_query_spice(Error **errp) } info->enabled = true; + info->migrated = spice_migration_completed; addr = qemu_opt_get(opts, "addr"); port = qemu_opt_get_number(opts, "port", 0); @@ -496,6 +499,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) #ifndef SPICE_INTERFACE_MIGRATION spice_server_migrate_switch(spice_server); monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); + spice_migration_completed = true; #else spice_server_migrate_end(spice_server, true); } else if (migration_has_failed(s)) { -- cgit v1.2.3 From 8c9570530c819821b9b5cc3113d2b2966afe7621 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 21 Aug 2012 11:51:59 +0300 Subject: spice: adding seamless-migration option to the command line The seamless-migration flag is required in order to identify whether libvirt supports the new QEVENT_SPICE_MIGRATE_COMPLETED or not (by default the flag is off). New libvirt versions that wait for QEVENT_SPICE_MIGRATE_COMPLETED should turn on this flag. When this flag is off, spice fallbacks to its old migration method, which can result in data loss. Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- qemu-config.c | 3 +++ qemu-options.hx | 3 +++ ui/spice-core.c | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/qemu-config.c b/qemu-config.c index c05ffbc44..eba977ebc 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -537,6 +537,9 @@ QemuOptsList qemu_spice_opts = { },{ .name = "playback-compression", .type = QEMU_OPT_BOOL, + }, { + .name = "seamless-migration", + .type = QEMU_OPT_BOOL, }, { /* end of list */ } }, diff --git a/qemu-options.hx b/qemu-options.hx index 3c411c427..96a7bb192 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -920,6 +920,9 @@ Enable/disable passing mouse events via vdagent. Default is on. @item playback-compression=[on|off] Enable/disable audio stream compression (using celt 0.5.1). Default is on. +@item seamless-migration=[on|off] +Enable/disable spice seamless migration. Default is off. + @end table ETEXI diff --git a/ui/spice-core.c b/ui/spice-core.c index ab069c5b6..ba0d0bdbc 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -585,6 +585,9 @@ void qemu_spice_init(void) int port, tls_port, len, addr_flags; spice_image_compression_t compression; spice_wan_compression_t wan_compr; +#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ + bool seamless_migration; +#endif qemu_thread_get_self(&me); @@ -728,6 +731,10 @@ void qemu_spice_init(void) spice_server_set_uuid(spice_server, qemu_uuid); #endif +#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ + seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); + spice_server_set_seamless_migration(spice_server, seamless_migration); +#endif if (0 != spice_server_init(spice_server, &core_interface)) { error_report("failed to initialize spice server"); exit(1); -- cgit v1.2.3 From 27af778828db9aa893fa1de928744141e5de20e5 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 21 Aug 2012 13:54:20 +0300 Subject: spice: increase the verbosity of spice section in "qemu --help" Added all spice options to the help string. This can be used by libvirt to determine which spice related features are supported by qemu. Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- qemu-options.hx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 96a7bb192..804a2d173 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -838,7 +838,23 @@ Enable SDL. ETEXI DEF("spice", HAS_ARG, QEMU_OPTION_spice, - "-spice enable spice\n", QEMU_ARCH_ALL) + "-spice [port=port][,tls-port=secured-port][,x509-dir=]\n" + " [,x509-key-file=][,x509-key-password=]\n" + " [,x509-cert-file=][,x509-cacert-file=]\n" + " [,x509-dh-key-file=][,addr=addr][,ipv4|ipv6]\n" + " [,tls-ciphers=]\n" + " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n" + " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n" + " [,sasl][,password=][,disable-ticketing]\n" + " [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n" + " [,jpeg-wan-compression=[auto|never|always]]\n" + " [,zlib-glz-wan-compression=[auto|never|always]]\n" + " [,streaming-video=[off|all|filter]][,disable-copy-paste]\n" + " [,agent-mouse=[on|off]][,playback-compression=[on|off]]\n" + " [,seamless-migration=[on|off]]\n" + " enable spice\n" + " at least one of {port, tls-port} is mandatory\n", + QEMU_ARCH_ALL) STEXI @item -spice @var{option}[,@var{option}[,...]] @findex -spice -- cgit v1.2.3 From 511b13e2c9b426b3c56060909693de5097f0b496 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Tue, 21 Aug 2012 13:51:31 +0300 Subject: qxl/update_area_io: guest_bug on invalid parameters Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index 95bbc031c..baf9bb4df 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1386,6 +1386,18 @@ async_common: QXLCookie *cookie = NULL; QXLRect update = d->ram->update_area; + if (d->ram->update_surface > NUM_SURFACES) { + qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", + d->ram->update_surface); + return; + } + if (update.left >= update.right || update.top >= update.bottom) { + qxl_set_guest_bug(d, + "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", + update.left, update.top, update.right, update.bottom); + return; + } + if (async == QXL_ASYNC) { cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, QXL_IO_UPDATE_AREA_ASYNC); -- cgit v1.2.3 From 36839d355e4ffc77d8f937caa6bb4c5530b9237e Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Tue, 21 Aug 2012 13:51:32 +0300 Subject: qxl: disallow unknown revisions Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/qxl.c b/hw/qxl.c index baf9bb4df..d134a701d 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1798,10 +1798,13 @@ static int qxl_init_common(PCIQXLDevice *qxl) io_size = 16; break; case 3: /* qxl-3 */ - default: pci_device_rev = QXL_DEFAULT_REVISION; io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); break; + default: + error_report("Invalid revision %d for qxl device (max %d)", + qxl->revision, QXL_DEFAULT_REVISION); + return -1; } pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); -- cgit v1.2.3 From 020af1c45fec664d5d4cf3b8e5117f8bc1d691f2 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 22 Aug 2012 11:16:25 +0300 Subject: qxl: add QXL_IO_MONITORS_CONFIG_ASYNC Revision bumped to 4 for new IO support, enabled for spice-server >= 0.11.1. New io enabled if revision is 4. Revision can be set to 4. [ kraxel: 3 continues to be the default revision. Once we have a new stable spice-server release and the qemu patches to enable the new bits merged we'll go flip the switch and make rev4 the default ] This io calls the corresponding new spice api spice_qxl_monitors_config_async to let spice-server read a new guest set monitors config and notify the client. On migration reissue spice_qxl_monitors_config_async. RHBZ: 770842 Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann fixup Signed-off-by: Gerd Hoffmann --- configure | 7 ++++ hw/qxl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/qxl.h | 7 ++++ trace-events | 1 + ui/spice-display.h | 1 + 5 files changed, 109 insertions(+), 4 deletions(-) diff --git a/configure b/configure index d97fd8170..59521ea69 100755 --- a/configure +++ b/configure @@ -2701,6 +2701,9 @@ EOF spice="yes" libs_softmmu="$libs_softmmu $spice_libs" QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" + if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then + spice_qxl_io_monitors_config_async="yes" + fi else if test "$spice" = "yes" ; then feature_not_found "spice" @@ -3438,6 +3441,10 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi +if test "$spice_qxl_io_monitors_config_async" = "yes" ; then + echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak +fi + if test "$smartcard" = "yes" ; then echo "CONFIG_SMARTCARD=y" >> $config_host_mak fi diff --git a/hw/qxl.c b/hw/qxl.c index d134a701d..adf17fd79 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -27,6 +27,11 @@ #include "qxl.h" +#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC +/* spice-protocol is too old, add missing definitions */ +#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1) +#endif + /* * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as * such can be changed by the guest, so to avoid a guest trigerrable @@ -249,6 +254,39 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) } } +static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) +{ + trace_qxl_spice_monitors_config(qxl->id); +/* 0x000b01 == 0.11.1 */ +#if SPICE_SERVER_VERSION >= 0x000b01 && \ + defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) + if (replay) { + /* + * don't use QXL_COOKIE_TYPE_IO: + * - we are not running yet (post_load), we will assert + * in send_events + * - this is not a guest io, but a reply, so async_io isn't set. + */ + spice_qxl_monitors_config_async(&qxl->ssd.qxl, + qxl->guest_monitors_config, + MEMSLOT_GROUP_GUEST, + (uintptr_t)qxl_cookie_new( + QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, + 0)); + } else { + qxl->guest_monitors_config = qxl->ram->monitors_config; + spice_qxl_monitors_config_async(&qxl->ssd.qxl, + qxl->ram->monitors_config, + MEMSLOT_GROUP_GUEST, + (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_MONITORS_CONFIG_ASYNC)); + } +#else + fprintf(stderr, "qxl: too old spice-protocol/spice-server for " + "QXL_IO_MONITORS_CONFIG_ASYNC\n"); +#endif +} + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) { trace_qxl_spice_reset_image_cache(qxl->id); @@ -538,6 +576,7 @@ static const char *io_port_to_string(uint32_t io_port) = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", + [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC", }; return io_port_to_string[io_port]; } @@ -819,6 +858,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) case QXL_IO_DESTROY_PRIMARY_ASYNC: case QXL_IO_UPDATE_AREA_ASYNC: case QXL_IO_FLUSH_SURFACES_ASYNC: + case QXL_IO_MONITORS_CONFIG_ASYNC: break; case QXL_IO_CREATE_PRIMARY_ASYNC: qxl_create_guest_primary_complete(qxl); @@ -894,6 +934,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: qxl_render_update_area_done(qxl, cookie); break; + case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG: + break; default: fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", __func__, cookie->type); @@ -1315,6 +1357,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, return; } + if (d->revision <= QXL_REVISION_STABLE_V10 && + io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) { + qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", + io_port, d->revision); + return; + } + switch (io_port) { case QXL_IO_RESET: case QXL_IO_SET_MODE: @@ -1334,7 +1383,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, io_port, io_port_to_string(io_port)); /* be nice to buggy guest drivers */ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && - io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { + io_port < QXL_IO_RANGE_SIZE) { qxl_send_events(d, QXL_INTERRUPT_IO_CMD); } return; @@ -1362,6 +1411,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, io_port = QXL_IO_DESTROY_ALL_SURFACES; goto async_common; case QXL_IO_FLUSH_SURFACES_ASYNC: + case QXL_IO_MONITORS_CONFIG_ASYNC: async_common: async = QXL_ASYNC; qemu_mutex_lock(&d->async_lock); @@ -1503,6 +1553,9 @@ async_common: d->mode = QXL_MODE_UNDEFINED; qxl_spice_destroy_surfaces(d, async); break; + case QXL_IO_MONITORS_CONFIG_ASYNC: + qxl_spice_monitors_config_async(d, 0); + break; default: qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port); } @@ -1798,9 +1851,17 @@ static int qxl_init_common(PCIQXLDevice *qxl) io_size = 16; break; case 3: /* qxl-3 */ - pci_device_rev = QXL_DEFAULT_REVISION; + pci_device_rev = QXL_REVISION_STABLE_V10; + io_size = 32; /* PCI region size must be pow2 */ + break; +/* 0x000b01 == 0.11.1 */ +#if SPICE_SERVER_VERSION >= 0x000b01 && \ + defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) + case 4: /* qxl-4 */ + pci_device_rev = QXL_REVISION_STABLE_V12; io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); break; +#endif default: error_report("Invalid revision %d for qxl device (max %d)", qxl->revision, QXL_DEFAULT_REVISION); @@ -1999,7 +2060,9 @@ static int qxl_post_load(void *opaque, int version) } qxl_spice_loadvm_commands(d, cmds, out); g_free(cmds); - + if (d->guest_monitors_config) { + qxl_spice_monitors_config_async(d, 1); + } break; case QXL_MODE_COMPAT: /* note: no need to call qxl_create_memslots, qxl_set_mode @@ -2012,6 +2075,14 @@ static int qxl_post_load(void *opaque, int version) #define QXL_SAVE_VERSION 21 +static bool qxl_monitors_config_needed(void *opaque) +{ + PCIQXLDevice *qxl = opaque; + + return qxl->guest_monitors_config != 0; +} + + static VMStateDescription qxl_memslot = { .name = "qxl-memslot", .version_id = QXL_SAVE_VERSION, @@ -2042,6 +2113,16 @@ static VMStateDescription qxl_surface = { } }; +static VMStateDescription qxl_vmstate_monitors_config = { + .name = "qxl/monitors-config", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice), + VMSTATE_END_OF_LIST() + }, +}; + static VMStateDescription qxl_vmstate = { .name = "qxl", .version_id = QXL_SAVE_VERSION, @@ -2049,7 +2130,7 @@ static VMStateDescription qxl_vmstate = { .pre_save = qxl_pre_save, .pre_load = qxl_pre_load, .post_load = qxl_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(pci, PCIQXLDevice), VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState), VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice), @@ -2068,6 +2149,14 @@ static VMStateDescription qxl_vmstate = { VMSTATE_UINT64(guest_cursor, PCIQXLDevice), VMSTATE_END_OF_LIST() }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &qxl_vmstate_monitors_config, + .needed = qxl_monitors_config_needed, + }, { + /* empty */ + } + } }; static Property qxl_properties[] = { diff --git a/hw/qxl.h b/hw/qxl.h index 172baf6cc..9cfedb72d 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -71,6 +71,8 @@ typedef struct PCIQXLDevice { } guest_surfaces; QXLPHYSICAL guest_cursor; + QXLPHYSICAL guest_monitors_config; + QemuMutex track_lock; /* thread signaling */ @@ -128,7 +130,12 @@ typedef struct PCIQXLDevice { } \ } while (0) +#if 0 +/* spice-server 0.12 is still in development */ +#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12 +#else #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 +#endif /* qxl.c */ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); diff --git a/trace-events b/trace-events index 04b072392..8fcbc50f9 100644 --- a/trace-events +++ b/trace-events @@ -956,6 +956,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" +qxl_spice_monitors_config(int id) "%d" qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" qxl_spice_oom(int qid) "%d" qxl_spice_reset_cursor(int qid) "%d" diff --git a/ui/spice-display.h b/ui/spice-display.h index 672d65ec3..bcff1147b 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -51,6 +51,7 @@ typedef enum qxl_async_io { enum { QXL_COOKIE_TYPE_IO, QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, + QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, }; typedef struct QXLCookie { -- cgit v1.2.3 From 2e0e3c399aa8067148055b9ea0edb822c5b584d2 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 22 Aug 2012 11:16:26 +0300 Subject: configure: print spice-protocol and spice-server versions Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- configure | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 59521ea69..9592095d6 100755 --- a/configure +++ b/configure @@ -2701,6 +2701,8 @@ EOF spice="yes" libs_softmmu="$libs_softmmu $spice_libs" QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" + spice_protocol_version=$($pkg_config --modversion spice-protocol) + spice_server_version=$($pkg_config --modversion spice-server) if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then spice_qxl_io_monitors_config_async="yes" fi @@ -3159,7 +3161,7 @@ echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" echo "Trace backend $trace_backend" echo "Trace output file $trace_file-" -echo "spice support $spice" +echo "spice support $spice ($spice_protocol_version/$spice_server_version)" echo "rbd support $rbd" echo "xfsctl support $xfs" echo "nss used $smartcard_nss" -- cgit v1.2.3 From ddd8fdc78ee30fc445e3d1f5bd2056acfcdefe47 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 4 Sep 2012 11:39:41 +0200 Subject: spice: make number of surfaces runtime-configurable. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 31 +++++++++++++++++-------------- hw/qxl.h | 3 +-- ui/spice-display.c | 5 ++++- ui/spice-display.h | 3 +-- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index adf17fd79..8725f67d4 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -236,7 +236,8 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) { trace_qxl_spice_destroy_surfaces_complete(qxl->id); qemu_mutex_lock(&qxl->track_lock); - memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); + memset(qxl->guest_surfaces.cmds, 0, + sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces); qxl->guest_surfaces.count = 0; qemu_mutex_unlock(&qxl->track_lock); } @@ -345,7 +346,7 @@ static void init_qxl_rom(PCIQXLDevice *d) rom->slot_id_bits = MEMSLOT_SLOT_BITS; rom->slots_start = 1; rom->slots_end = NUM_MEMSLOTS - 1; - rom->n_surfaces = cpu_to_le32(NUM_SURFACES); + rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces); for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) { fb = qxl_modes[i].y_res * qxl_modes[i].stride; @@ -449,9 +450,9 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) } uint32_t id = le32_to_cpu(cmd->surface_id); - if (id >= NUM_SURFACES) { + if (id >= qxl->ssd.num_surfaces) { qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id, - NUM_SURFACES); + qxl->ssd.num_surfaces); return 1; } qemu_mutex_lock(&qxl->track_lock); @@ -527,7 +528,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; info->internal_groupslot_id = 0; info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS; - info->n_surfaces = NUM_SURFACES; + info->n_surfaces = qxl->ssd.num_surfaces; } static const char *qxl_mode_to_string(int mode) @@ -1436,7 +1437,7 @@ async_common: QXLCookie *cookie = NULL; QXLRect update = d->ram->update_area; - if (d->ram->update_surface > NUM_SURFACES) { + if (d->ram->update_surface > d->ssd.num_surfaces) { qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", d->ram->update_surface); return; @@ -1529,7 +1530,7 @@ async_common: } break; case QXL_IO_DESTROY_SURFACE_WAIT: - if (val >= NUM_SURFACES) { + if (val >= d->ssd.num_surfaces) { qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):" "%" PRIu64 " >= NUM_SURFACES", async, val); goto cancel_async; @@ -1707,7 +1708,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); /* dirty the off-screen surfaces */ - for (i = 0; i < NUM_SURFACES; i++) { + for (i = 0; i < qxl->ssd.num_surfaces; i++) { QXLSurfaceCmd *cmd; intptr_t surface_offset; int surface_size; @@ -1835,7 +1836,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) qxl->mode = QXL_MODE_UNDEFINED; qxl->generation = 1; qxl->num_memslots = NUM_MEMSLOTS; - qxl->num_surfaces = NUM_SURFACES; qemu_mutex_init(&qxl->track_lock); qemu_mutex_init(&qxl->async_lock); qxl->current_async = QXL_UNDEFINED_IO; @@ -1877,6 +1877,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) init_qxl_rom(qxl); init_qxl_ram(qxl); + qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces); memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size); vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, @@ -2042,8 +2043,8 @@ static int qxl_post_load(void *opaque, int version) qxl_create_guest_primary(d, 1, QXL_SYNC); /* replay surface-create and cursor-set commands */ - cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); - for (in = 0, out = 0; in < NUM_SURFACES; in++) { + cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1)); + for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) { if (d->guest_surfaces.cmds[in] == 0) { continue; } @@ -2143,9 +2144,10 @@ static VMStateDescription qxl_vmstate = { qxl_memslot, struct guest_slots), VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0, qxl_surface, QXLSurfaceCreate), - VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice), - VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0, - vmstate_info_uint64, uint64_t), + VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice), + VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice, + ssd.num_surfaces, 0, + vmstate_info_uint64, uint64_t), VMSTATE_UINT64(guest_cursor, PCIQXLDevice), VMSTATE_END_OF_LIST() }, @@ -2173,6 +2175,7 @@ static Property qxl_properties[] = { DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16), + DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/qxl.h b/hw/qxl.h index 9cfedb72d..5553824be 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -40,7 +40,6 @@ typedef struct PCIQXLDevice { uint32_t revision; int32_t num_memslots; - int32_t num_surfaces; uint32_t current_async; QemuMutex async_lock; @@ -65,7 +64,7 @@ typedef struct PCIQXLDevice { } guest_primary; struct surfaces { - QXLPHYSICAL cmds[NUM_SURFACES]; + QXLPHYSICAL *cmds; uint32_t count; uint32_t max; } guest_surfaces; diff --git a/ui/spice-display.c b/ui/spice-display.c index 1c31418a4..99bc665bc 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -317,6 +317,9 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) qemu_mutex_init(&ssd->lock); ssd->mouse_x = -1; ssd->mouse_y = -1; + if (ssd->num_surfaces == 0) { + ssd->num_surfaces = 1024; + } ssd->bufsize = (16 * 1024 * 1024); ssd->buf = g_malloc(ssd->bufsize); } @@ -427,7 +430,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; info->internal_groupslot_id = 0; info->qxl_ram_size = ssd->bufsize; - info->n_surfaces = NUM_SURFACES; + info->n_surfaces = ssd->num_surfaces; } static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) diff --git a/ui/spice-display.h b/ui/spice-display.h index bcff1147b..512ab7831 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -32,8 +32,6 @@ #define MEMSLOT_GROUP_GUEST 1 #define NUM_MEMSLOTS_GROUPS 2 -#define NUM_SURFACES 1024 - /* * Internal enum to differenciate between options for * io calls that have a sync (old) version and an _async (new) @@ -80,6 +78,7 @@ struct SimpleSpiceDisplay { QXLInstance qxl; uint32_t unique; QemuPfConv *conv; + int32_t num_surfaces; QXLRect dirty; int notify; -- cgit v1.2.3 From c10018d6c77c94a8c703b9e4f026da74cad73d9e Mon Sep 17 00:00:00 2001 From: Søren Sandmann Pedersen Date: Tue, 4 Sep 2012 10:14:48 -0400 Subject: qxl: Add set_client_capabilities() interface to QXLInterface This new interface lets spice server inform the guest whether (a) a client is connected (b) what capabilities the client has There is a fixed number (464) of bits reserved for capabilities, and when the capabilities bits change, the QXL_INTERRUPT_CLIENT interrupt is generated. Signed-off-by: Soren Sandmann Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index 8725f67d4..2aa58485c 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -944,6 +944,26 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) } } +#if SPICE_SERVER_VERSION >= 0x000b04 + +/* called from spice server thread context only */ +static void interface_set_client_capabilities(QXLInstance *sin, + uint8_t client_present, + uint8_t caps[58]) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + + qxl->shadow_rom.client_present = client_present; + memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); + qxl->rom->client_present = client_present; + memcpy(qxl->rom->client_capabilities, caps, sizeof(caps)); + qxl_rom_set_dirty(qxl); + + qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); +} + +#endif + static const QXLInterface qxl_interface = { .base.type = SPICE_INTERFACE_QXL, .base.description = "qxl gpu", @@ -965,6 +985,9 @@ static const QXLInterface qxl_interface = { .flush_resources = interface_flush_resources, .async_complete = interface_async_complete, .update_area_complete = interface_update_area_complete, +#if SPICE_SERVER_VERSION >= 0x000b04 + .set_client_capabilities = interface_set_client_capabilities, +#endif }; static void qxl_enter_vga_mode(PCIQXLDevice *d) -- cgit v1.2.3 From 265db734901df7d8f24796ad7c43923249651289 Mon Sep 17 00:00:00 2001 From: Søren Sandmann Pedersen Date: Tue, 4 Sep 2012 10:14:49 -0400 Subject: Remove #ifdef QXL_COMMAND_FLAG_COMPAT_16BPP We require spice >= 0.8 now, so this flag is always present. Signed-off-by: Soren Sandmann Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index 2aa58485c..b726c194b 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1359,11 +1359,9 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) d->mode = QXL_MODE_COMPAT; d->cmdflags = QXL_COMMAND_FLAG_COMPAT; -#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */ if (mode->bits == 16) { d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP; } -#endif d->shadow_rom.mode = cpu_to_le32(modenr); d->rom->mode = cpu_to_le32(modenr); qxl_rom_set_dirty(d); -- cgit v1.2.3 From f45ddd14209a4d1b95a4096d50a561b7f6270118 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 5 Sep 2012 11:44:53 -0500 Subject: Open up 1.3 development tree Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 26aaba0e8..99188f0c6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.0 +1.2.50 -- cgit v1.2.3 From fa779b65fa77d5632df1f8b2df33e9023dbc4cc8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 15 Aug 2012 11:33:47 +0100 Subject: Add support for pretty-printing response in qmp-shell Add a '-p' arg to the QMP/qmp-shell test program, which uses the python pprint module to pretty-print the dictionary returned from a command $ qmp-shell -p /tmp/qemu Welcome to the QMP low-level shell! Connected to QEMU 1.1.50 (QEMU) query-cpus { u'return': [ { u'CPU': 0, u'current': True, u'halted': True, u'pc': 1048556, u'thread_id': 7108}]} Signed-off-by: Daniel P. Berrange Signed-off-by: Luiz Capitulino --- QMP/qmp-shell | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/QMP/qmp-shell b/QMP/qmp-shell index 42dabc8c6..24b665c8c 100755 --- a/QMP/qmp-shell +++ b/QMP/qmp-shell @@ -33,6 +33,7 @@ import qmp import readline import sys +import pprint class QMPCompleter(list): def complete(self, text, state): @@ -52,10 +53,11 @@ class QMPShellBadPort(QMPShellError): # TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and # _execute_cmd()). Let's design a better one. class QMPShell(qmp.QEMUMonitorProtocol): - def __init__(self, address): + def __init__(self, address, pp=None): qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address)) self._greeting = None self._completer = None + self._pp = pp def __get_address(self, arg): """ @@ -114,7 +116,11 @@ class QMPShell(qmp.QEMUMonitorProtocol): if resp is None: print 'Disconnected' return False - print resp + + if self._pp is not None: + self._pp.pprint(resp) + else: + print resp return True def connect(self): @@ -222,22 +228,36 @@ def die(msg): def fail_cmdline(option=None): if option: sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option) - sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n') + sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n') sys.exit(1) def main(): addr = '' + qemu = None + hmp = False + pp = None + try: - if len(sys.argv) == 2: - qemu = QMPShell(sys.argv[1]) - addr = sys.argv[1] - elif len(sys.argv) == 3: - if sys.argv[1] != '-H': - fail_cmdline(sys.argv[1]) - qemu = HMPShell(sys.argv[2]) - addr = sys.argv[2] - else: - fail_cmdline() + for arg in sys.argv[1:]: + if arg == "-H": + if qemu is not None: + fail_cmdline(arg) + hmp = True + elif arg == "-p": + if pp is not None: + fail_cmdline(arg) + pp = pprint.PrettyPrinter(indent=4) + else: + if qemu is not None: + fail_cmdline(arg) + if hmp: + qemu = HMPShell(arg) + else: + qemu = QMPShell(arg, pp) + addr = arg + + if qemu is None: + fail_cmdline() except QMPShellBadPort: die('bad port number in command-line') -- cgit v1.2.3 From 886cc706ce5d4d3d1c296f028ddc2991cfbe3bbe Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:20 +0800 Subject: fix doc of using raw values with sendkey (qemu) sendkey a (qemu) sendkey 0x1e (qemu) sendkey #0x1e unknown key: '#0x1e' The last command doesn't work, '#' is not requested before raw values, and the raw value in decimal format is not supported. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index f6104b099..6a70a9c59 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -512,9 +512,9 @@ STEXI @item sendkey @var{keys} @findex sendkey -Send @var{keys} to the emulator. @var{keys} could be the name of the -key or @code{#} followed by the raw value in either decimal or hexadecimal -format. Use @code{-} to press several keys simultaneously. Example: +Send @var{keys} to the guest. @var{keys} could be the name of the +key or the raw value in hexadecimal format. Use @code{-} to press +several keys simultaneously. Example: @example sendkey ctrl-alt-f1 @end example -- cgit v1.2.3 From cd383492bfb5ea805d518e129d7a5402c7b99ef2 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:21 +0800 Subject: monitor: rename keyname '<' to 'less' There are many maps of keycode 0x56 in pc-bios/keymaps/* pc-bios/keymaps/common:less 0x56 pc-bios/keymaps/common:greater 0x56 shift pc-bios/keymaps/common:bar 0x56 altgr pc-bios/keymaps/common:brokenbar 0x56 shift altgr This patch just renamed '<' to 'less', QAPI might add new variable by adding a prefix to keyname, '$PREFIX_<' is not available, '$PREFIX_less' is ok. For compatibility, convert user inputted '<' to 'less'. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- monitor.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index b17b1bb84..c97c12006 100644 --- a/monitor.c +++ b/monitor.c @@ -1400,7 +1400,7 @@ static const KeyDef key_defs[] = { { 0x48, "kp_8" }, { 0x49, "kp_9" }, - { 0x56, "<" }, + { 0x56, "less" }, { 0x57, "f11" }, { 0x58, "f12" }, @@ -1504,6 +1504,13 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) monitor_printf(mon, "too many keys\n"); return; } + + /* Be compatible with old interface, convert user inputted "<" */ + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); + keyname_len = 4; + } + keyname_buf[keyname_len] = 0; keycode = get_keycode(keyname_buf); if (keycode < 0) { -- cgit v1.2.3 From 2ef20c15b4736c9b0afc7ef2b14239182fbcd3e1 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:22 +0800 Subject: hmp: rename arguments Rename 'string' to 'keys', rename 'hold_time' to 'hold-time'. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 2 +- monitor.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 6a70a9c59..bd0c6c919 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -502,7 +502,7 @@ ETEXI { .name = "sendkey", - .args_type = "string:s,hold_time:i?", + .args_type = "keys:s,hold-time:i?", .params = "keys [hold_ms]", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", .mhandler.cmd = do_sendkey, diff --git a/monitor.c b/monitor.c index c97c12006..84176eb8f 100644 --- a/monitor.c +++ b/monitor.c @@ -1480,9 +1480,9 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) char keyname_buf[16]; char *separator; int keyname_len, keycode, i; - const char *string = qdict_get_str(qdict, "string"); - int has_hold_time = qdict_haskey(qdict, "hold_time"); - int hold_time = qdict_get_try_int(qdict, "hold_time", -1); + const char *keys = qdict_get_str(qdict, "keys"); + int has_hold_time = qdict_haskey(qdict, "hold-time"); + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); if (nb_pending_keycodes > 0) { qemu_del_timer(key_timer); @@ -1492,10 +1492,10 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) hold_time = 100; i = 0; while (1) { - separator = strchr(string, '-'); - keyname_len = separator ? separator - string : strlen(string); + separator = strchr(keys, '-'); + keyname_len = separator ? separator - keys : strlen(keys); if (keyname_len > 0) { - pstrcpy(keyname_buf, sizeof(keyname_buf), string); + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); if (keyname_len > sizeof(keyname_buf) - 1) { monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf); return; @@ -1521,7 +1521,7 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) } if (!separator) break; - string = separator + 1; + keys = separator + 1; } nb_pending_keycodes = i; /* key down events */ -- cgit v1.2.3 From b9c4b48d50057b6aee7c70879b240ff76f39c85b Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:23 +0800 Subject: qapi: generate list struct and visit_list for enum Currently, if we define an 'enum' and use it in one command's data, list struct for enum could not be generated, but it's used in qmp function. For example: KeyCodesList could not be generated. >>> qapi-schema.json: { 'enum': 'KeyCodes', 'data': [ 'shift', 'alt' ... ] } { 'command': 'sendkey', 'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } } >>> qmp-command.h: void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t hold_time, Error **errp); This patch lets qapi generate list struct and visit_list for enum. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- scripts/qapi-types.py | 16 +++++++++++++++- scripts/qapi-visit.py | 14 +++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index cf601ae2d..49ef569a2 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -28,6 +28,16 @@ typedef struct %(name)sList ''', name=name) +def generate_fwd_enum_struct(name, members): + return mcgen(''' +typedef struct %(name)sList +{ + %(name)s value; + struct %(name)sList *next; +} %(name)sList; +''', + name=name) + def generate_struct(structname, fieldname, members): ret = mcgen(''' struct %(name)s @@ -276,7 +286,8 @@ for expr in exprs: if expr.has_key('type'): ret += generate_fwd_struct(expr['type'], expr['data']) elif expr.has_key('enum'): - ret += generate_enum(expr['enum'], expr['data']) + ret += generate_enum(expr['enum'], expr['data']) + "\n" + ret += generate_fwd_enum_struct(expr['enum'], expr['data']) fdef.write(generate_enum_lookup(expr['enum'], expr['data'])) elif expr.has_key('union'): ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" @@ -300,6 +311,9 @@ for expr in exprs: fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n") ret += generate_type_cleanup_decl(expr['union']) fdef.write(generate_type_cleanup(expr['union']) + "\n") + elif expr.has_key('enum'): + ret += generate_type_cleanup_decl(expr['enum'] + "List") + fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n") else: continue fdecl.write(ret) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 04ef7c41a..cbec24da1 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -217,6 +217,16 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, return ret +def generate_enum_declaration(name, members, genlist=True): + ret = "" + if genlist: + ret += mcgen(''' +void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); +''', + name=name) + + return ret + def generate_decl_enum(name, members, genlist=True): return mcgen(''' @@ -335,10 +345,12 @@ for expr in exprs: ret += generate_declaration(expr['union'], expr['data']) fdecl.write(ret) elif expr.has_key('enum'): - ret = generate_visit_enum(expr['enum'], expr['data']) + ret = generate_visit_list(expr['enum'], expr['data']) + ret += generate_visit_enum(expr['enum'], expr['data']) fdef.write(ret) ret = generate_decl_enum(expr['enum'], expr['data']) + ret += generate_enum_declaration(expr['enum'], expr['data']) fdecl.write(ret) fdecl.write(''' -- cgit v1.2.3 From 411656f48d71131d6d1cb5b6db792fc7b451e72e Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:24 +0800 Subject: qapi: add the QKeyCode enum key_defs[] in monitor.c is a mapping table of keys and keycodes, this patch added a QKeyCode enum. Key's index in the enmu is same as keycode's index in key_defs[]. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- qapi-schema.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index bd8ad7449..856e11a72 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2493,3 +2493,29 @@ # Since: 1.2.0 ## { 'command': 'query-target', 'returns': 'TargetInfo' } + +## +# @QKeyCode: +# +# An enumeration of key name. +# +# This is used by the send-key command. +# +# Since: 1.3.0 +## +{ 'enum': 'QKeyCode', + 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', + 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e', + 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right', + 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon', + 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b', + 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock', + 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', + 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', + 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0', + 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8', + 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end', + 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', + 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', + 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } -- cgit v1.2.3 From 1048c88f03545fa42bdebb077871a743a614d2ab Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:25 +0800 Subject: monitor: move key_defs[] table and introduce two help functions This patch added two help functions to convert key/code to index of mapping table, those functions will return Q_KEY_CODE_MAX if the code/key is invalid. Patch also moved key_defs[] to input.c, and removed useless KeyDef struct. Key's index in QKeyCode enmu is same as keycode's index in new key_defs[]. Monitor functions were changed to access key_defs[] directly. key_defs[] is used in do_send_key(), so export key_defs[]. It will be changed to static in next patch. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- console.h | 6 ++ input.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ monitor.c | 183 ++++--------------------------------------------------------- 3 files changed, 203 insertions(+), 172 deletions(-) diff --git a/console.h b/console.h index 4334db5ca..7934b1189 100644 --- a/console.h +++ b/console.h @@ -6,6 +6,7 @@ #include "notify.h" #include "monitor.h" #include "trace.h" +#include "qapi-types.h" /* keyboard/mouse support */ @@ -397,4 +398,9 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires) /* curses.c */ void curses_display_init(DisplayState *ds, int full_screen); +/* input.c */ +extern const int key_defs[]; +int index_from_key(const char *key); +int index_from_keycode(int code); + #endif diff --git a/input.c b/input.c index 6968b3178..5630cb19d 100644 --- a/input.c +++ b/input.c @@ -37,6 +37,192 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = static NotifierList mouse_mode_notifiers = NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); +const int key_defs[] = { + [Q_KEY_CODE_SHIFT] = 0x2a, + [Q_KEY_CODE_SHIFT_R] = 0x36, + + [Q_KEY_CODE_ALT] = 0x38, + [Q_KEY_CODE_ALT_R] = 0xb8, + [Q_KEY_CODE_ALTGR] = 0x64, + [Q_KEY_CODE_ALTGR_R] = 0xe4, + [Q_KEY_CODE_CTRL] = 0x1d, + [Q_KEY_CODE_CTRL_R] = 0x9d, + + [Q_KEY_CODE_MENU] = 0xdd, + + [Q_KEY_CODE_ESC] = 0x01, + + [Q_KEY_CODE_1] = 0x02, + [Q_KEY_CODE_2] = 0x03, + [Q_KEY_CODE_3] = 0x04, + [Q_KEY_CODE_4] = 0x05, + [Q_KEY_CODE_5] = 0x06, + [Q_KEY_CODE_6] = 0x07, + [Q_KEY_CODE_7] = 0x08, + [Q_KEY_CODE_8] = 0x09, + [Q_KEY_CODE_9] = 0x0a, + [Q_KEY_CODE_0] = 0x0b, + [Q_KEY_CODE_MINUS] = 0x0c, + [Q_KEY_CODE_EQUAL] = 0x0d, + [Q_KEY_CODE_BACKSPACE] = 0x0e, + + [Q_KEY_CODE_TAB] = 0x0f, + [Q_KEY_CODE_Q] = 0x10, + [Q_KEY_CODE_W] = 0x11, + [Q_KEY_CODE_E] = 0x12, + [Q_KEY_CODE_R] = 0x13, + [Q_KEY_CODE_T] = 0x14, + [Q_KEY_CODE_Y] = 0x15, + [Q_KEY_CODE_U] = 0x16, + [Q_KEY_CODE_I] = 0x17, + [Q_KEY_CODE_O] = 0x18, + [Q_KEY_CODE_P] = 0x19, + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, + [Q_KEY_CODE_RET] = 0x1c, + + [Q_KEY_CODE_A] = 0x1e, + [Q_KEY_CODE_S] = 0x1f, + [Q_KEY_CODE_D] = 0x20, + [Q_KEY_CODE_F] = 0x21, + [Q_KEY_CODE_G] = 0x22, + [Q_KEY_CODE_H] = 0x23, + [Q_KEY_CODE_J] = 0x24, + [Q_KEY_CODE_K] = 0x25, + [Q_KEY_CODE_L] = 0x26, + [Q_KEY_CODE_SEMICOLON] = 0x27, + [Q_KEY_CODE_APOSTROPHE] = 0x28, + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, + + [Q_KEY_CODE_BACKSLASH] = 0x2b, + [Q_KEY_CODE_Z] = 0x2c, + [Q_KEY_CODE_X] = 0x2d, + [Q_KEY_CODE_C] = 0x2e, + [Q_KEY_CODE_V] = 0x2f, + [Q_KEY_CODE_B] = 0x30, + [Q_KEY_CODE_N] = 0x31, + [Q_KEY_CODE_M] = 0x32, + [Q_KEY_CODE_COMMA] = 0x33, + [Q_KEY_CODE_DOT] = 0x34, + [Q_KEY_CODE_SLASH] = 0x35, + + [Q_KEY_CODE_ASTERISK] = 0x37, + + [Q_KEY_CODE_SPC] = 0x39, + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, + [Q_KEY_CODE_F1] = 0x3b, + [Q_KEY_CODE_F2] = 0x3c, + [Q_KEY_CODE_F3] = 0x3d, + [Q_KEY_CODE_F4] = 0x3e, + [Q_KEY_CODE_F5] = 0x3f, + [Q_KEY_CODE_F6] = 0x40, + [Q_KEY_CODE_F7] = 0x41, + [Q_KEY_CODE_F8] = 0x42, + [Q_KEY_CODE_F9] = 0x43, + [Q_KEY_CODE_F10] = 0x44, + [Q_KEY_CODE_NUM_LOCK] = 0x45, + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, + + [Q_KEY_CODE_KP_DIVIDE] = 0xb5, + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, + [Q_KEY_CODE_KP_ADD] = 0x4e, + [Q_KEY_CODE_KP_ENTER] = 0x9c, + [Q_KEY_CODE_KP_DECIMAL] = 0x53, + [Q_KEY_CODE_SYSRQ] = 0x54, + + [Q_KEY_CODE_KP_0] = 0x52, + [Q_KEY_CODE_KP_1] = 0x4f, + [Q_KEY_CODE_KP_2] = 0x50, + [Q_KEY_CODE_KP_3] = 0x51, + [Q_KEY_CODE_KP_4] = 0x4b, + [Q_KEY_CODE_KP_5] = 0x4c, + [Q_KEY_CODE_KP_6] = 0x4d, + [Q_KEY_CODE_KP_7] = 0x47, + [Q_KEY_CODE_KP_8] = 0x48, + [Q_KEY_CODE_KP_9] = 0x49, + + [Q_KEY_CODE_LESS] = 0x56, + + [Q_KEY_CODE_F11] = 0x57, + [Q_KEY_CODE_F12] = 0x58, + + [Q_KEY_CODE_PRINT] = 0xb7, + + [Q_KEY_CODE_HOME] = 0xc7, + [Q_KEY_CODE_PGUP] = 0xc9, + [Q_KEY_CODE_PGDN] = 0xd1, + [Q_KEY_CODE_END] = 0xcf, + + [Q_KEY_CODE_LEFT] = 0xcb, + [Q_KEY_CODE_UP] = 0xc8, + [Q_KEY_CODE_DOWN] = 0xd0, + [Q_KEY_CODE_RIGHT] = 0xcd, + + [Q_KEY_CODE_INSERT] = 0xd2, + [Q_KEY_CODE_DELETE] = 0xd3, +#ifdef NEED_CPU_H +#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) + [Q_KEY_CODE_STOP] = 0xf0, + [Q_KEY_CODE_AGAIN] = 0xf1, + [Q_KEY_CODE_PROPS] = 0xf2, + [Q_KEY_CODE_UNDO] = 0xf3, + [Q_KEY_CODE_FRONT] = 0xf4, + [Q_KEY_CODE_COPY] = 0xf5, + [Q_KEY_CODE_OPEN] = 0xf6, + [Q_KEY_CODE_PASTE] = 0xf7, + [Q_KEY_CODE_FIND] = 0xf8, + [Q_KEY_CODE_CUT] = 0xf9, + [Q_KEY_CODE_LF] = 0xfa, + [Q_KEY_CODE_HELP] = 0xfb, + [Q_KEY_CODE_META_L] = 0xfc, + [Q_KEY_CODE_META_R] = 0xfd, + [Q_KEY_CODE_COMPOSE] = 0xfe, +#endif +#endif + [Q_KEY_CODE_MAX] = 0, +}; + +int index_from_key(const char *key) +{ + int i, keycode; + char *endp; + + for (i = 0; QKeyCode_lookup[i] != NULL; i++) { + if (!strcmp(key, QKeyCode_lookup[i])) { + break; + } + } + + if (strstart(key, "0x", NULL)) { + keycode = strtoul(key, &endp, 0); + if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) { + for (i = 0; i < Q_KEY_CODE_MAX; i++) { + if (keycode == key_defs[i]) { + break; + } + } + } + } + + /* Return Q_KEY_CODE_MAX if the key is invalid */ + return i; +} + +int index_from_keycode(int code) +{ + int i; + + for (i = 0; i < Q_KEY_CODE_MAX; i++) { + if (key_defs[i] == code) { + break; + } + } + + /* Return Q_KEY_CODE_MAX if the code is invalid */ + return i; +} + void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { qemu_put_kbd_event_opaque = opaque; diff --git a/monitor.c b/monitor.c index 84176eb8f..0c4f86f63 100644 --- a/monitor.c +++ b/monitor.c @@ -1290,173 +1290,6 @@ static void do_sum(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%05d\n", sum); } -typedef struct { - int keycode; - const char *name; -} KeyDef; - -static const KeyDef key_defs[] = { - { 0x2a, "shift" }, - { 0x36, "shift_r" }, - - { 0x38, "alt" }, - { 0xb8, "alt_r" }, - { 0x64, "altgr" }, - { 0xe4, "altgr_r" }, - { 0x1d, "ctrl" }, - { 0x9d, "ctrl_r" }, - - { 0xdd, "menu" }, - - { 0x01, "esc" }, - - { 0x02, "1" }, - { 0x03, "2" }, - { 0x04, "3" }, - { 0x05, "4" }, - { 0x06, "5" }, - { 0x07, "6" }, - { 0x08, "7" }, - { 0x09, "8" }, - { 0x0a, "9" }, - { 0x0b, "0" }, - { 0x0c, "minus" }, - { 0x0d, "equal" }, - { 0x0e, "backspace" }, - - { 0x0f, "tab" }, - { 0x10, "q" }, - { 0x11, "w" }, - { 0x12, "e" }, - { 0x13, "r" }, - { 0x14, "t" }, - { 0x15, "y" }, - { 0x16, "u" }, - { 0x17, "i" }, - { 0x18, "o" }, - { 0x19, "p" }, - { 0x1a, "bracket_left" }, - { 0x1b, "bracket_right" }, - { 0x1c, "ret" }, - - { 0x1e, "a" }, - { 0x1f, "s" }, - { 0x20, "d" }, - { 0x21, "f" }, - { 0x22, "g" }, - { 0x23, "h" }, - { 0x24, "j" }, - { 0x25, "k" }, - { 0x26, "l" }, - { 0x27, "semicolon" }, - { 0x28, "apostrophe" }, - { 0x29, "grave_accent" }, - - { 0x2b, "backslash" }, - { 0x2c, "z" }, - { 0x2d, "x" }, - { 0x2e, "c" }, - { 0x2f, "v" }, - { 0x30, "b" }, - { 0x31, "n" }, - { 0x32, "m" }, - { 0x33, "comma" }, - { 0x34, "dot" }, - { 0x35, "slash" }, - - { 0x37, "asterisk" }, - - { 0x39, "spc" }, - { 0x3a, "caps_lock" }, - { 0x3b, "f1" }, - { 0x3c, "f2" }, - { 0x3d, "f3" }, - { 0x3e, "f4" }, - { 0x3f, "f5" }, - { 0x40, "f6" }, - { 0x41, "f7" }, - { 0x42, "f8" }, - { 0x43, "f9" }, - { 0x44, "f10" }, - { 0x45, "num_lock" }, - { 0x46, "scroll_lock" }, - - { 0xb5, "kp_divide" }, - { 0x37, "kp_multiply" }, - { 0x4a, "kp_subtract" }, - { 0x4e, "kp_add" }, - { 0x9c, "kp_enter" }, - { 0x53, "kp_decimal" }, - { 0x54, "sysrq" }, - - { 0x52, "kp_0" }, - { 0x4f, "kp_1" }, - { 0x50, "kp_2" }, - { 0x51, "kp_3" }, - { 0x4b, "kp_4" }, - { 0x4c, "kp_5" }, - { 0x4d, "kp_6" }, - { 0x47, "kp_7" }, - { 0x48, "kp_8" }, - { 0x49, "kp_9" }, - - { 0x56, "less" }, - - { 0x57, "f11" }, - { 0x58, "f12" }, - - { 0xb7, "print" }, - - { 0xc7, "home" }, - { 0xc9, "pgup" }, - { 0xd1, "pgdn" }, - { 0xcf, "end" }, - - { 0xcb, "left" }, - { 0xc8, "up" }, - { 0xd0, "down" }, - { 0xcd, "right" }, - - { 0xd2, "insert" }, - { 0xd3, "delete" }, -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) - { 0xf0, "stop" }, - { 0xf1, "again" }, - { 0xf2, "props" }, - { 0xf3, "undo" }, - { 0xf4, "front" }, - { 0xf5, "copy" }, - { 0xf6, "open" }, - { 0xf7, "paste" }, - { 0xf8, "find" }, - { 0xf9, "cut" }, - { 0xfa, "lf" }, - { 0xfb, "help" }, - { 0xfc, "meta_l" }, - { 0xfd, "meta_r" }, - { 0xfe, "compose" }, -#endif - { 0, NULL }, -}; - -static int get_keycode(const char *key) -{ - const KeyDef *p; - char *endp; - int ret; - - for(p = key_defs; p->name != NULL; p++) { - if (!strcmp(key, p->name)) - return p->keycode; - } - if (strstart(key, "0x", NULL)) { - ret = strtoul(key, &endp, 0); - if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) - return ret; - } - return -1; -} - #define MAX_KEYCODES 16 static uint8_t keycodes[MAX_KEYCODES]; static int nb_pending_keycodes; @@ -1479,7 +1312,7 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) { char keyname_buf[16]; char *separator; - int keyname_len, keycode, i; + int keyname_len, keycode, i, idx; const char *keys = qdict_get_str(qdict, "keys"); int has_hold_time = qdict_haskey(qdict, "hold-time"); int hold_time = qdict_get_try_int(qdict, "hold-time", -1); @@ -1512,7 +1345,14 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) } keyname_buf[keyname_len] = 0; - keycode = get_keycode(keyname_buf); + + idx = index_from_key(keyname_buf); + if (idx == Q_KEY_CODE_MAX) { + monitor_printf(mon, "invalid parameter: %s\n", keyname_buf); + return; + } + + keycode = key_defs[idx]; if (keycode < 0) { monitor_printf(mon, "unknown key: '%s'\n", keyname_buf); return; @@ -4322,7 +4162,6 @@ static void monitor_find_completion(const char *cmdline) int nb_args, i, len; const char *ptype, *str; const mon_cmd_t *cmd; - const KeyDef *key; parse_cmdline(cmdline, &nb_args, args); #ifdef DEBUG_COMPLETION @@ -4396,8 +4235,8 @@ static void monitor_find_completion(const char *cmdline) if (sep) str = sep + 1; readline_set_completion_index(cur_mon->rs, strlen(str)); - for(key = key_defs; key->name != NULL; key++) { - cmd_completion(str, key->name); + for (i = 0; i < Q_KEY_CODE_MAX; i++) { + cmd_completion(str, QKeyCode_lookup[i]); } } else if (!strcmp(cmd->name, "help|?")) { readline_set_completion_index(cur_mon->rs, strlen(str)); -- cgit v1.2.3 From e4c8f004c55d9da3eae3e14df740238bf805b5d6 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 31 Aug 2012 10:56:26 +0800 Subject: qapi: convert sendkey Convert 'sendkey' to use QAPI. QAPI passes key's index of mapping table to qmp_send_key(), not keycode. So we use help functions to convert key/code to index of key_defs, and 'index' will be converted to 'keycode' inside qmp_send_key(). For qmp, QAPI would check invalid key and raise error. For hmp, invalid key is checked in hmp_send_key(). 'send-key' of QMP doesn't support key in hexadecimal format. Signed-off-by: Amos Kong Signed-off-by: Luiz Capitulino --- console.h | 1 - hmp-commands.hx | 2 +- hmp.c | 55 +++++++++++++++++++++++++++++++++++ hmp.h | 1 + input.c | 67 ++++++++++++++++++++++++++++++++++++++++++- monitor.c | 87 -------------------------------------------------------- qapi-schema.json | 20 +++++++++++++ qmp-commands.hx | 28 ++++++++++++++++++ 8 files changed, 171 insertions(+), 90 deletions(-) diff --git a/console.h b/console.h index 7934b1189..c702b2372 100644 --- a/console.h +++ b/console.h @@ -399,7 +399,6 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires) void curses_display_init(DisplayState *ds, int full_screen); /* input.c */ -extern const int key_defs[]; int index_from_key(const char *key); int index_from_keycode(int code); diff --git a/hmp-commands.hx b/hmp-commands.hx index bd0c6c919..5cee1310c 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -505,7 +505,7 @@ ETEXI .args_type = "keys:s,hold-time:i?", .params = "keys [hold_ms]", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", - .mhandler.cmd = do_sendkey, + .mhandler.cmd = hmp_send_key, }, STEXI diff --git a/hmp.c b/hmp.c index 81c8acb67..ba99b2fb3 100644 --- a/hmp.c +++ b/hmp.c @@ -19,6 +19,7 @@ #include "qemu-timer.h" #include "qmp-commands.h" #include "monitor.h" +#include "console.h" static void hmp_handle_error(Monitor *mon, Error **errp) { @@ -1102,3 +1103,57 @@ void hmp_closefd(Monitor *mon, const QDict *qdict) qmp_closefd(fdname, &errp); hmp_handle_error(mon, &errp); } + +void hmp_send_key(Monitor *mon, const QDict *qdict) +{ + const char *keys = qdict_get_str(qdict, "keys"); + QKeyCodeList *keylist, *head = NULL, *tmp = NULL; + int has_hold_time = qdict_haskey(qdict, "hold-time"); + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); + Error *err = NULL; + char keyname_buf[16]; + char *separator; + int keyname_len, idx; + + while (1) { + separator = strchr(keys, '-'); + keyname_len = separator ? separator - keys : strlen(keys); + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); + + /* Be compatible with old interface, convert user inputted "<" */ + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); + keyname_len = 4; + } + keyname_buf[keyname_len] = 0; + + idx = index_from_key(keyname_buf); + if (idx == Q_KEY_CODE_MAX) { + monitor_printf(mon, "invalid parameter: %s\n", keyname_buf); + break; + } + + keylist = g_malloc0(sizeof(*keylist)); + keylist->value = idx; + keylist->next = NULL; + + if (!head) { + head = keylist; + } + if (tmp) { + tmp->next = keylist; + } + tmp = keylist; + + if (!separator) { + break; + } + keys = separator + 1; + } + + if (idx != Q_KEY_CODE_MAX) { + qmp_send_key(head, has_hold_time, hold_time, &err); + } + hmp_handle_error(mon, &err); + qapi_free_QKeyCodeList(head); +} diff --git a/hmp.h b/hmp.h index 7dd93bf0f..8e7838ce5 100644 --- a/hmp.h +++ b/hmp.h @@ -71,5 +71,6 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict); void hmp_netdev_del(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); +void hmp_send_key(Monitor *mon, const QDict *qdict); #endif diff --git a/input.c b/input.c index 5630cb19d..c4b0619a7 100644 --- a/input.c +++ b/input.c @@ -28,6 +28,7 @@ #include "console.h" #include "error.h" #include "qmp-commands.h" +#include "qapi-types.h" static QEMUPutKBDEvent *qemu_put_kbd_event; static void *qemu_put_kbd_event_opaque; @@ -37,7 +38,7 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = static NotifierList mouse_mode_notifiers = NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); -const int key_defs[] = { +static const int key_defs[] = { [Q_KEY_CODE_SHIFT] = 0x2a, [Q_KEY_CODE_SHIFT_R] = 0x36, @@ -223,6 +224,70 @@ int index_from_keycode(int code) return i; } +static QKeyCodeList *keycodes; +static QEMUTimer *key_timer; + +static void release_keys(void *opaque) +{ + int keycode; + QKeyCodeList *p; + + for (p = keycodes; p != NULL; p = p->next) { + keycode = key_defs[p->value]; + if (keycode & 0x80) { + kbd_put_keycode(0xe0); + } + kbd_put_keycode(keycode | 0x80); + } + qapi_free_QKeyCodeList(keycodes); + keycodes = NULL; +} + +void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t hold_time, + Error **errp) +{ + int keycode; + QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL; + + if (!key_timer) { + key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); + } + + if (keycodes != NULL) { + qemu_del_timer(key_timer); + release_keys(NULL); + } + if (!has_hold_time) { + hold_time = 100; + } + + for (p = keys; p != NULL; p = p->next) { + keylist = g_malloc0(sizeof(*keylist)); + keylist->value = p->value; + keylist->next = NULL; + + if (!head) { + head = keylist; + } + if (tmp) { + tmp->next = keylist; + } + tmp = keylist; + + /* key down events */ + keycode = key_defs[p->value]; + if (keycode & 0x80) { + kbd_put_keycode(0xe0); + } + kbd_put_keycode(keycode & 0x7f); + } + keycodes = head; + + /* delayed key up events */ + qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + + muldiv64(get_ticks_per_sec(), hold_time, 1000)); +} + void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { qemu_put_kbd_event_opaque = opaque; diff --git a/monitor.c b/monitor.c index 0c4f86f63..d73bad831 100644 --- a/monitor.c +++ b/monitor.c @@ -1290,92 +1290,6 @@ static void do_sum(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%05d\n", sum); } -#define MAX_KEYCODES 16 -static uint8_t keycodes[MAX_KEYCODES]; -static int nb_pending_keycodes; -static QEMUTimer *key_timer; - -static void release_keys(void *opaque) -{ - int keycode; - - while (nb_pending_keycodes > 0) { - nb_pending_keycodes--; - keycode = keycodes[nb_pending_keycodes]; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); - } -} - -static void do_sendkey(Monitor *mon, const QDict *qdict) -{ - char keyname_buf[16]; - char *separator; - int keyname_len, keycode, i, idx; - const char *keys = qdict_get_str(qdict, "keys"); - int has_hold_time = qdict_haskey(qdict, "hold-time"); - int hold_time = qdict_get_try_int(qdict, "hold-time", -1); - - if (nb_pending_keycodes > 0) { - qemu_del_timer(key_timer); - release_keys(NULL); - } - if (!has_hold_time) - hold_time = 100; - i = 0; - while (1) { - separator = strchr(keys, '-'); - keyname_len = separator ? separator - keys : strlen(keys); - if (keyname_len > 0) { - pstrcpy(keyname_buf, sizeof(keyname_buf), keys); - if (keyname_len > sizeof(keyname_buf) - 1) { - monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf); - return; - } - if (i == MAX_KEYCODES) { - monitor_printf(mon, "too many keys\n"); - return; - } - - /* Be compatible with old interface, convert user inputted "<" */ - if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { - pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); - keyname_len = 4; - } - - keyname_buf[keyname_len] = 0; - - idx = index_from_key(keyname_buf); - if (idx == Q_KEY_CODE_MAX) { - monitor_printf(mon, "invalid parameter: %s\n", keyname_buf); - return; - } - - keycode = key_defs[idx]; - if (keycode < 0) { - monitor_printf(mon, "unknown key: '%s'\n", keyname_buf); - return; - } - keycodes[i++] = keycode; - } - if (!separator) - break; - keys = separator + 1; - } - nb_pending_keycodes = i; - /* key down events */ - for (i = 0; i < nb_pending_keycodes; i++) { - keycode = keycodes[i]; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode & 0x7f); - } - /* delayed key up events */ - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + - muldiv64(get_ticks_per_sec(), hold_time, 1000)); -} - static int mouse_button_state; static void do_mouse_move(Monitor *mon, const QDict *qdict) @@ -4772,7 +4686,6 @@ void monitor_init(CharDriverState *chr, int flags) Monitor *mon; if (is_first_init) { - key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); monitor_protocol_event_init(); is_first_init = 0; } diff --git a/qapi-schema.json b/qapi-schema.json index 856e11a72..542138299 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2519,3 +2519,23 @@ 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } + +## +# @send-key: +# +# Send keys to guest. +# +# @keys: key sequence. 'keys' is the name of the key. Use a JSON array to +# press several keys simultaneously. +# +# @hold-time: #optional time to delay key up events, milliseconds. Defaults +# to 100 +# +# Returns: Nothing on success +# If key is unknown or redundant, InvalidParameter +# +# Since: 1.3.0 +# +## +{ 'command': 'send-key', + 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } } diff --git a/qmp-commands.hx b/qmp-commands.hx index 3745a2119..470f08ed9 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -332,6 +332,34 @@ Example: -> { "execute": "device_del", "arguments": { "id": "net1" } } <- { "return": {} } +EQMP + + { + .name = "send-key", + .args_type = "keys:O,hold-time:i?", + .mhandler.cmd_new = qmp_marshal_input_send_key, + }, + +SQMP +send-key +---------- + +Send keys to VM. + +Arguments: + +keys array: + - "key": key sequence (a json-array of key enum values) + +- hold-time: time to delay key up events, milliseconds. Defaults to 100 + (json-int, optional) + +Example: + +-> { "execute": "send-key", + "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } } +<- { "return": {} } + EQMP { -- cgit v1.2.3 From 227ccf6bff234c29974c2c18ecd3a29e6b965e3d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 1 Sep 2012 09:30:39 +0200 Subject: qapi: Fix potential NULL pointer segfault Report from smatch: qapi-visit.c:1640 visit_type_BlockdevAction(8) error: we previously assumed 'obj' could be null (see line 1639) qapi-visit.c:2432 visit_type_NetClientOptions(8) error: we previously assumed 'obj' could be null (see line 2431) Signed-off-by: Stefan Weil Reviewed-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- scripts/qapi-visit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index cbec24da1..e2093e894 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -157,7 +157,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** if (!error_is_set(errp)) { visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); if (!err) { - if (!obj || *obj) { + if (obj && *obj) { visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err); if (!err) { switch ((*obj)->kind) { -- cgit v1.2.3 From 149474c93490e1c66f838391bd491db83136d91d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 3 Sep 2012 21:19:11 +0200 Subject: json-parser: Fix potential NULL pointer segfault Report from smatch: json-parser.c:474 parse_object(62) error: potential null derefence 'dict'. json-parser.c:553 parse_array(75) error: potential null derefence 'list'. Label 'out' in json-parser.c can be called with list == NULL which is passed to QDECREF. Modify QDECREF to handle a NULL argument (inline function qobject_decref already handles them, too). Signed-off-by: Stefan Weil Signed-off-by: Luiz Capitulino --- qobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qobject.h b/qobject.h index d42386dde..9124649ed 100644 --- a/qobject.h +++ b/qobject.h @@ -71,7 +71,7 @@ typedef struct QObject { /* High-level interface for qobject_decref() */ #define QDECREF(obj) \ - qobject_decref(QOBJECT(obj)) + qobject_decref(obj ? QOBJECT(obj) : NULL) /* Initialize an object to default values */ #define QOBJECT_INIT(obj, qtype_type) \ -- cgit v1.2.3 From 75d789f8d38be693bbee3e77b558e59012e33997 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 29 Aug 2012 11:20:57 -0300 Subject: error: add error_setg() Signed-off-by: Luiz Capitulino --- error.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/error.h b/error.h index 96fc20328..da7fed399 100644 --- a/error.h +++ b/error.h @@ -29,6 +29,12 @@ typedef struct Error Error; */ void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4); +/** + * Same as error_set(), but sets a generic error + */ +#define error_setg(err, fmt, ...) \ + error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) + /** * Returns true if an indirect pointer to an error is pointing to a valid * error object. -- cgit v1.2.3 From d7098135d4baac8141b2e76f2daa8a7f61599c72 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 21 May 2012 16:41:37 -0300 Subject: console: vga_hw_screen_dump_ptr: take Error argument All devices that register a screen dump callback via graphic_console_init() are updated. The new argument is not used in this commit. Error handling will be added to each device individually later. This change is a preparation to convert the screendump command to the QAPI. Signed-off-by: Luiz Capitulino --- console.c | 2 +- console.h | 4 +++- hw/blizzard.c | 2 +- hw/g364fb.c | 3 ++- hw/omap_lcdc.c | 3 ++- hw/qxl.c | 5 +++-- hw/tcx.c | 12 ++++++++---- hw/vga.c | 6 ++++-- hw/vmware_vga.c | 5 +++-- 9 files changed, 27 insertions(+), 15 deletions(-) diff --git a/console.c b/console.c index 3b5cabba3..8228773dd 100644 --- a/console.c +++ b/console.c @@ -190,7 +190,7 @@ void vga_hw_screen_dump(const char *filename) console_select(0); } if (consoles[0] && consoles[0]->hw_screen_dump) { - consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch); + consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, NULL); } else { error_report("screen dump not implemented"); } diff --git a/console.h b/console.h index c702b2372..fd68ecca7 100644 --- a/console.h +++ b/console.h @@ -7,6 +7,7 @@ #include "monitor.h" #include "trace.h" #include "qapi-types.h" +#include "error.h" /* keyboard/mouse support */ @@ -344,7 +345,8 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) typedef void (*vga_hw_update_ptr)(void *); typedef void (*vga_hw_invalidate_ptr)(void *); -typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch); +typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch, + Error **errp); typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); DisplayState *graphic_console_init(vga_hw_update_ptr update, diff --git a/hw/blizzard.c b/hw/blizzard.c index 29074c4fa..a2b90537c 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -933,7 +933,7 @@ static void blizzard_update_display(void *opaque) } static void blizzard_screen_dump(void *opaque, const char *filename, - bool cswitch) + bool cswitch, Error **errp) { BlizzardState *s = (BlizzardState *) opaque; diff --git a/hw/g364fb.c b/hw/g364fb.c index 3a0b68fba..498154be2 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -289,7 +289,8 @@ static void g364fb_reset(G364State *s) g364fb_invalidate_display(s); } -static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch) +static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { G364State *s = opaque; int y, x; diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 4a08e9d00..39b78cd6d 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -264,7 +264,8 @@ static int ppm_save(const char *filename, uint8_t *data, return 0; } -static void omap_screen_dump(void *opaque, const char *filename, bool cswitch) +static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { struct omap_lcd_panel_s *omap_lcd = opaque; diff --git a/hw/qxl.c b/hw/qxl.c index c2dd3b471..46a929dc3 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1595,7 +1595,8 @@ static void qxl_hw_invalidate(void *opaque) vga->invalidate(vga); } -static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch) +static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { PCIQXLDevice *qxl = opaque; VGACommonState *vga = &qxl->vga; @@ -1607,7 +1608,7 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch) ppm_save(filename, qxl->ssd.ds->surface); break; case QXL_MODE_VGA: - vga->screen_dump(vga, filename, cswitch); + vga->screen_dump(vga, filename, cswitch, errp); break; default: break; diff --git a/hw/tcx.c b/hw/tcx.c index ac7dcb428..74a708542 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -56,8 +56,10 @@ typedef struct TCXState { uint8_t dac_index, dac_state; } TCXState; -static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch); -static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch); +static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp); +static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp); static void tcx_set_dirty(TCXState *s) { @@ -574,7 +576,8 @@ static int tcx_init1(SysBusDevice *dev) return 0; } -static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch) +static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { TCXState *s = opaque; FILE *f; @@ -601,7 +604,8 @@ static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch) return; } -static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch) +static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { TCXState *s = opaque; FILE *f; diff --git a/hw/vga.c b/hw/vga.c index f82ced8e6..dd703cf41 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -166,7 +166,8 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; -static void vga_screen_dump(void *opaque, const char *filename, bool cswitch); +static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp); static void vga_update_memory_access(VGACommonState *s) { @@ -2435,7 +2436,8 @@ int ppm_save(const char *filename, struct DisplaySurface *ds) /* save the vga display in a PPM image even if no display is available */ -static void vga_screen_dump(void *opaque, const char *filename, bool cswitch) +static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { VGACommonState *s = opaque; diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index f5e4f440d..29750e1b0 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1003,11 +1003,12 @@ static void vmsvga_invalidate_display(void *opaque) /* save the vga display in a PPM image even if no display is available */ -static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch) +static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { struct vmsvga_state_s *s = opaque; if (!s->enable) { - s->vga.screen_dump(&s->vga, filename, cswitch); + s->vga.screen_dump(&s->vga, filename, cswitch, errp); return; } -- cgit v1.2.3 From ad39cf6d150e951e4c67c8120d495ae7e78054a6 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 24 May 2012 13:48:23 -0300 Subject: qapi: convert screendump Next commits will update devices to propagate errors. Signed-off-by: Luiz Capitulino --- console.c | 7 ++++--- console.h | 1 - hmp-commands.hx | 3 +-- hmp.c | 9 +++++++++ hmp.h | 1 + monitor.c | 6 ------ qapi-schema.json | 13 +++++++++++++ qmp-commands.hx | 5 +---- 8 files changed, 29 insertions(+), 16 deletions(-) diff --git a/console.c b/console.c index 8228773dd..c1ed5e09e 100644 --- a/console.c +++ b/console.c @@ -24,6 +24,7 @@ #include "qemu-common.h" #include "console.h" #include "qemu-timer.h" +#include "qmp-commands.h" //#define DEBUG_CONSOLE #define DEFAULT_BACKSCROLL 512 @@ -176,7 +177,7 @@ void vga_hw_invalidate(void) active_console->hw_invalidate(active_console->hw); } -void vga_hw_screen_dump(const char *filename) +void qmp_screendump(const char *filename, Error **errp) { TextConsole *previous_active_console; bool cswitch; @@ -190,9 +191,9 @@ void vga_hw_screen_dump(const char *filename) console_select(0); } if (consoles[0] && consoles[0]->hw_screen_dump) { - consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, NULL); + consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp); } else { - error_report("screen dump not implemented"); + error_setg(errp, "device doesn't support screendump\n"); } if (cswitch) { diff --git a/console.h b/console.h index fd68ecca7..f990684ef 100644 --- a/console.h +++ b/console.h @@ -357,7 +357,6 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update, void vga_hw_update(void); void vga_hw_invalidate(void); -void vga_hw_screen_dump(const char *filename); void vga_hw_text_update(console_ch_t *chardata); int is_graphic_console(void); diff --git a/hmp-commands.hx b/hmp-commands.hx index 5cee1310c..ed67e997f 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -194,8 +194,7 @@ ETEXI .args_type = "filename:F", .params = "filename", .help = "save screen into PPM image 'filename'", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_screen_dump, + .mhandler.cmd = hmp_screen_dump, }, STEXI diff --git a/hmp.c b/hmp.c index ba99b2fb3..1bdab2277 100644 --- a/hmp.c +++ b/hmp.c @@ -1157,3 +1157,12 @@ void hmp_send_key(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &err); qapi_free_QKeyCodeList(head); } + +void hmp_screen_dump(Monitor *mon, const QDict *qdict) +{ + const char *filename = qdict_get_str(qdict, "filename"); + Error *err = NULL; + + qmp_screendump(filename, &err); + hmp_handle_error(mon, &err); +} diff --git a/hmp.h b/hmp.h index 8e7838ce5..48b9c59f8 100644 --- a/hmp.h +++ b/hmp.h @@ -72,5 +72,6 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); void hmp_send_key(Monitor *mon, const QDict *qdict); +void hmp_screen_dump(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor.c b/monitor.c index d73bad831..e315b270e 100644 --- a/monitor.c +++ b/monitor.c @@ -1016,12 +1016,6 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, return -1; } -static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - vga_hw_screen_dump(qdict_get_str(qdict, "filename")); - return 0; -} - static void do_logfile(Monitor *mon, const QDict *qdict) { cpu_set_log_filename(qdict_get_str(qdict, "filename")); diff --git a/qapi-schema.json b/qapi-schema.json index 542138299..df47fcee2 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2539,3 +2539,16 @@ ## { 'command': 'send-key', 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } } + +## +# @screendump: +# +# Write a PPM of the VGA screen to a file. +# +# @filename: the path of a new PPM file to store the image +# +# Returns: Nothing on success +# +# Since: 0.14.0 +## +{ 'command': 'screendump', 'data': {'filename': 'str'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index 470f08ed9..6e21ddba6 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -146,10 +146,7 @@ EQMP { .name = "screendump", .args_type = "filename:F", - .params = "filename", - .help = "save screen into PPM image 'filename'", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_screen_dump, + .mhandler.cmd_new = qmp_marshal_input_screendump, }, SQMP -- cgit v1.2.3 From d663174dcd9623c44f3af2a46de2a55d16f15c19 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 24 May 2012 10:42:25 -0300 Subject: vga: ppm_save(): add error handling Signed-off-by: Luiz Capitulino --- hw/blizzard.c | 2 +- hw/qxl.c | 2 +- hw/vga.c | 32 +++++++++++++++++++++++++------- hw/vga_int.h | 3 ++- hw/vmware_vga.c | 2 +- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/hw/blizzard.c b/hw/blizzard.c index a2b90537c..d1c9d8151 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -939,7 +939,7 @@ static void blizzard_screen_dump(void *opaque, const char *filename, blizzard_update_display(opaque); if (s && ds_get_data(s->state)) - ppm_save(filename, s->state->surface); + ppm_save(filename, s->state->surface, errp); } #define DEPTH 8 diff --git a/hw/qxl.c b/hw/qxl.c index 46a929dc3..bae575819 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1605,7 +1605,7 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch, case QXL_MODE_COMPAT: case QXL_MODE_NATIVE: qxl_render_update(qxl); - ppm_save(filename, qxl->ssd.ds->surface); + ppm_save(filename, qxl->ssd.ds->surface, errp); break; case QXL_MODE_VGA: vga->screen_dump(vga, filename, cswitch, errp); diff --git a/hw/vga.c b/hw/vga.c index dd703cf41..80299ea1d 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -2390,7 +2390,7 @@ void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) /********************************************************/ /* vga screen dump */ -int ppm_save(const char *filename, struct DisplaySurface *ds) +void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp) { FILE *f; uint8_t *d, *d1; @@ -2402,10 +2402,16 @@ int ppm_save(const char *filename, struct DisplaySurface *ds) trace_ppm_save(filename, ds); f = fopen(filename, "wb"); - if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", - ds->width, ds->height, 255); + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; + } + ret = fprintf(f, "P6\n%d %d\n%d\n", ds->width, ds->height, 255); + if (ret < 0) { + linebuf = NULL; + goto write_err; + } linebuf = g_malloc(ds->width * 3); d1 = ds->data; for(y = 0; y < ds->height; y++) { @@ -2426,12 +2432,24 @@ int ppm_save(const char *filename, struct DisplaySurface *ds) d += ds->pf.bytes_per_pixel; } d1 += ds->linesize; + clearerr(f); ret = fwrite(linebuf, 1, pbuf - linebuf, f); (void)ret; + if (ferror(f)) { + goto write_err; + } } + +out: g_free(linebuf); fclose(f); - return 0; + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } /* save the vga display in a PPM image even if no display is @@ -2445,5 +2463,5 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, vga_invalidate_display(s); } vga_hw_update(); - ppm_save(filename, s->ds->surface); + ppm_save(filename, s->ds->surface, errp); } diff --git a/hw/vga_int.h b/hw/vga_int.h index 893809368..330a32f77 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -23,6 +23,7 @@ */ #include +#include "error.h" #include "memory.h" #define ST01_V_RETRACE 0x08 @@ -204,7 +205,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val); uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr); void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val); void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2); -int ppm_save(const char *filename, struct DisplaySurface *ds); +void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp); int vga_ioport_invalid(VGACommonState *s, uint32_t addr); void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space); diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 29750e1b0..b68e88367 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1015,7 +1015,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, if (s->depth == 32) { DisplaySurface *ds = qemu_create_displaysurface_from(s->width, s->height, 32, ds_get_linesize(s->vga.ds), s->vga.vram_ptr); - ppm_save(filename, ds); + ppm_save(filename, ds, errp); g_free(ds); } } -- cgit v1.2.3 From 8dc4cc7bb57d3f0d6a1d8ba372d9eda1494bcc64 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 21 May 2012 15:18:58 -0300 Subject: omap_lcdc: rename ppm_save() to omap_ppm_save() Avoids confusion with the global ppm_save() defined in hw/vga.c. Signed-off-by: Luiz Capitulino Reviewed-by: Peter Maydell --- hw/omap_lcdc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 39b78cd6d..3d6328feb 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -224,8 +224,8 @@ static void omap_update_display(void *opaque) omap_lcd->invalidate = 0; } -static int ppm_save(const char *filename, uint8_t *data, - int w, int h, int linesize) +static int omap_ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize) { FILE *f; uint8_t *d, *d1; @@ -271,9 +271,9 @@ static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, omap_update_display(opaque); if (omap_lcd && ds_get_data(omap_lcd->state)) - ppm_save(filename, ds_get_data(omap_lcd->state), - omap_lcd->width, omap_lcd->height, - ds_get_linesize(omap_lcd->state)); + omap_ppm_save(filename, ds_get_data(omap_lcd->state), + omap_lcd->width, omap_lcd->height, + ds_get_linesize(omap_lcd->state)); } static void omap_invalidate_display(void *opaque) { -- cgit v1.2.3 From d9c7ebb10042a7d29d50b47c110e5cb754293d89 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 24 May 2012 11:24:34 -0300 Subject: omap_lcdc: omap_ppm_save(): add error handling Signed-off-by: Luiz Capitulino --- hw/omap_lcdc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 3d6328feb..e2ba10834 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -224,18 +224,24 @@ static void omap_update_display(void *opaque) omap_lcd->invalidate = 0; } -static int omap_ppm_save(const char *filename, uint8_t *data, - int w, int h, int linesize) +static void omap_ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize, Error **errp) { FILE *f; uint8_t *d, *d1; unsigned int v; - int y, x, bpp; + int ret, y, x, bpp; f = fopen(filename, "wb"); - if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; + } + ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); + if (ret < 0) { + goto write_err; + } d1 = data; bpp = linesize / w; for (y = 0; y < h; y ++) { @@ -244,24 +250,49 @@ static int omap_ppm_save(const char *filename, uint8_t *data, v = *(uint32_t *) d; switch (bpp) { case 2: - fputc((v >> 8) & 0xf8, f); - fputc((v >> 3) & 0xfc, f); - fputc((v << 3) & 0xf8, f); + ret = fputc((v >> 8) & 0xf8, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v >> 3) & 0xfc, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v << 3) & 0xf8, f); + if (ret == EOF) { + goto write_err; + } break; case 3: case 4: default: - fputc((v >> 16) & 0xff, f); - fputc((v >> 8) & 0xff, f); - fputc((v) & 0xff, f); + ret = fputc((v >> 16) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v >> 8) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v) & 0xff, f); + if (ret == EOF) { + goto write_err; + } break; } d += bpp; } d1 += linesize; } +out: fclose(f); - return 0; + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, @@ -273,7 +304,7 @@ static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, if (omap_lcd && ds_get_data(omap_lcd->state)) omap_ppm_save(filename, ds_get_data(omap_lcd->state), omap_lcd->width, omap_lcd->height, - ds_get_linesize(omap_lcd->state)); + ds_get_linesize(omap_lcd->state), errp); } static void omap_invalidate_display(void *opaque) { -- cgit v1.2.3 From 61a3f955c1caca775729fc59e97fb9c97808ffca Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 24 May 2012 11:28:17 -0300 Subject: g364fb: g364fb_screen_dump(): add error handling Signed-off-by: Luiz Capitulino --- hw/g364fb.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/hw/g364fb.c b/hw/g364fb.c index 498154be2..059e6220e 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -293,7 +293,7 @@ static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { G364State *s = opaque; - int y, x; + int ret, y, x; uint8_t index; uint8_t *data_buffer; FILE *f; @@ -301,35 +301,63 @@ static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch, qemu_flush_coalesced_mmio_buffer(); if (s->depth != 8) { - error_report("g364: unknown guest depth %d", s->depth); + error_setg(errp, "g364: unknown guest depth %d", s->depth); return; } f = fopen(filename, "wb"); - if (!f) + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); return; + } if (s->ctla & CTLA_FORCE_BLANK) { /* blank screen */ - fprintf(f, "P4\n%d %d\n", - s->width, s->height); + ret = fprintf(f, "P4\n%d %d\n", s->width, s->height); + if (ret < 0) { + goto write_err; + } for (y = 0; y < s->height; y++) - for (x = 0; x < s->width; x++) - fputc(0, f); + for (x = 0; x < s->width; x++) { + ret = fputc(0, f); + if (ret == EOF) { + goto write_err; + } + } } else { data_buffer = s->vram + s->top_of_screen; - fprintf(f, "P6\n%d %d\n%d\n", - s->width, s->height, 255); + ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + if (ret < 0) { + goto write_err; + } for (y = 0; y < s->height; y++) for (x = 0; x < s->width; x++, data_buffer++) { index = *data_buffer; - fputc(s->color_palette[index][0], f); - fputc(s->color_palette[index][1], f); - fputc(s->color_palette[index][2], f); + ret = fputc(s->color_palette[index][0], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->color_palette[index][1], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->color_palette[index][2], f); + if (ret == EOF) { + goto write_err; + } } } +out: fclose(f); + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } /* called for accesses to io ports */ -- cgit v1.2.3 From 537f2d2b0d4c27e21b3e610e57d6511e315d76cc Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 24 May 2012 11:30:40 -0300 Subject: tcx: tcx24_screen_dump(): add error handling Signed-off-by: Luiz Capitulino --- hw/tcx.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index 74a708542..428649e66 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -611,12 +611,18 @@ static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, FILE *f; uint8_t *d, *d1, v; uint32_t *s24, *cptr, dval; - int y, x; + int ret, y, x; f = fopen(filename, "wb"); - if (!f) + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); return; - fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + } + ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + if (ret < 0) { + goto write_err; + } d1 = s->vram; s24 = s->vram24; cptr = s->cplane; @@ -625,20 +631,46 @@ static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, for(x = 0; x < s->width; x++, d++, s24++) { if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct dval = *s24 & 0x00ffffff; - fputc((dval >> 16) & 0xff, f); - fputc((dval >> 8) & 0xff, f); - fputc(dval & 0xff, f); + ret = fputc((dval >> 16) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((dval >> 8) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(dval & 0xff, f); + if (ret == EOF) { + goto write_err; + } } else { v = *d; - fputc(s->r[v], f); - fputc(s->g[v], f); - fputc(s->b[v], f); + ret = fputc(s->r[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->g[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->b[v], f); + if (ret == EOF) { + goto write_err; + } } } d1 += MAXX; } + +out: fclose(f); return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } static Property tcx_properties[] = { -- cgit v1.2.3 From 0ab6b63655ba59d7c05089017acb721a44979526 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 24 May 2012 11:33:25 -0300 Subject: tcx: tcx_screen_dump(): add error handling Signed-off-by: Luiz Capitulino --- hw/tcx.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index 428649e66..93994d644 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -582,26 +582,49 @@ static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, TCXState *s = opaque; FILE *f; uint8_t *d, *d1, v; - int y, x; + int ret, y, x; f = fopen(filename, "wb"); - if (!f) + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); return; - fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + } + ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + if (ret < 0) { + goto write_err; + } d1 = s->vram; for(y = 0; y < s->height; y++) { d = d1; for(x = 0; x < s->width; x++) { v = *d; - fputc(s->r[v], f); - fputc(s->g[v], f); - fputc(s->b[v], f); + ret = fputc(s->r[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->g[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->b[v], f); + if (ret == EOF) { + goto write_err; + } d++; } d1 += MAXX; } + +out: fclose(f); return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, -- cgit v1.2.3 From a99ac041e9f30dafb0afa326ddbeb8a481ba3f81 Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Sun, 2 Sep 2012 19:22:35 -0400 Subject: CHECKPATCH: Add --debug adv_dcs Add debug options to find this issue. They were not listed in the help because the are not simple to understand the output of. Signed-off-by: Don Slutz Signed-off-by: Blue Swirl --- scripts/checkpatch.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index b98dc6cad..0b0f3f379 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -97,6 +97,7 @@ my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; my $dbg_attr = 0; +my $dbg_adv_dcs = 0; for my $key (keys %debug) { ## no critic eval "\${dbg_$key} = '$debug{$key}';"; @@ -2575,6 +2576,8 @@ sub process { $allowed = 1; } } + print "DCS: level=$level block<$block> allowed=$allowed\n" + if $dbg_adv_dcs; if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) { my $herectx = $here . "\n";; my $cnt = statement_rawlines($block); -- cgit v1.2.3 From 5424302e56ca587b665e3f409c4daa1bc2ff1cf7 Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Sun, 2 Sep 2012 19:22:36 -0400 Subject: CHECKPATCH: Add --debug adv_checking Add debug options to find this issue. They were not listed in the help because the are not simple to understand the output of. Signed-off-by: Don Slutz Signed-off-by: Blue Swirl --- scripts/checkpatch.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 0b0f3f379..8c83b56c6 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -98,6 +98,7 @@ my $dbg_possible = 0; my $dbg_type = 0; my $dbg_attr = 0; my $dbg_adv_dcs = 0; +my $dbg_adv_checking = 0; for my $key (keys %debug) { ## no critic eval "\${dbg_$key} = '$debug{$key}';"; @@ -2549,7 +2550,8 @@ sub process { # Check the condition. my ($cond, $block) = @{$chunks[0]}; - #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; + print "CHECKING<$linenr> cond<$cond> block<$block>\n" + if $dbg_adv_checking; if (defined $cond) { substr($block, 0, length($cond), ''); } -- cgit v1.2.3 From 69402a6944f506f51efee13c9db94bd1605eb478 Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Sun, 2 Sep 2012 19:22:37 -0400 Subject: CHECKPATCH: Add --debug adv_apw Add debug options to find this issue. They were not listed in the help because the are not simple to understand the output of. Signed-off-by: Don Slutz Signed-off-by: Blue Swirl --- scripts/checkpatch.pl | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 8c83b56c6..7ec8846ac 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -99,6 +99,7 @@ my $dbg_type = 0; my $dbg_attr = 0; my $dbg_adv_dcs = 0; my $dbg_adv_checking = 0; +my $dbg_adv_apw = 0; for my $key (keys %debug) { ## no critic eval "\${dbg_$key} = '$debug{$key}';"; @@ -2488,8 +2489,11 @@ sub process { if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) { my ($level, $endln, @chunks) = ctx_statement_full($linenr, $realcnt, 1); - #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; - #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; + if ($dbg_adv_apw) { + print "APW: chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; + print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n" + if $#chunks >= 1; + } if ($#chunks >= 0 && $level == 0) { my $allowed = 0; my $seen = 0; @@ -2514,18 +2518,22 @@ sub process { $seen++ if ($block =~ /^\s*{/); - #print "cond<$cond> block<$block> allowed<$allowed>\n"; + print "APW: cond<$cond> block<$block> allowed<$allowed>\n" + if $dbg_adv_apw; if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; + print "APW: ALLOWED: cond<$cond>\n" + if $dbg_adv_apw; + $allowed = 1; } if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: lines block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } } if ($seen != ($#chunks + 1)) { @@ -2541,8 +2549,9 @@ sub process { # Check the pre-context. if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { - #print "APW: ALLOWED: pre<$1>\n"; - $allowed = 1; + print "APW: ALLOWED: pre<$pre> line<$line>\n" + if $dbg_adv_apw; + $allowed = 1; } my ($level, $endln, @chunks) = @@ -2556,16 +2565,19 @@ sub process { substr($block, 0, length($cond), ''); } if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; + print "APW: ALLOWED: cond<$cond>\n" + if $dbg_adv_apw; + $allowed = 1; } if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: lines block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } # Check the post-context. if (defined $chunks[1]) { @@ -2574,8 +2586,9 @@ sub process { substr($block, 0, length($cond), ''); } if ($block =~ /^\s*\{/) { - #print "APW: ALLOWED: chunk-1 block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: chunk-1 block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } } print "DCS: level=$level block<$block> allowed=$allowed\n" -- cgit v1.2.3 From dfe7053a34353079503bf350f83cb8b6101a450d Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Sun, 2 Sep 2012 19:22:38 -0400 Subject: CHECKPATCH: Add warning for single else statement. For an example: WARNING: braces {} are necessary even for single statement blocks + } else + return env->regs[R_EAX]; total: 0 errors, 1 warnings, 41 lines checked Signed-off-by: Don Slutz Signed-off-by: Blue Swirl --- scripts/checkpatch.pl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 7ec8846ac..ec0aa4cd9 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2547,12 +2547,16 @@ sub process { $line !~ /\#\s*else/) { my $allowed = 0; - # Check the pre-context. - if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { - print "APW: ALLOWED: pre<$pre> line<$line>\n" - if $dbg_adv_apw; - $allowed = 1; - } + # Check the pre-context. + if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { + my $pre = $1; + + if ($line !~ /else/) { + print "APW: ALLOWED: pre<$pre> line<$line>\n" + if $dbg_adv_apw; + $allowed = 1; + } + } my ($level, $endln, @chunks) = ctx_statement_full($linenr, $realcnt, $-[0]); -- cgit v1.2.3 From d6ce52c1f183add6f60509bc3344a61104489613 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 29 Aug 2012 23:54:25 +0400 Subject: target-xtensa: convert host errno values to guest Guest errno values are taken from the newlib. Convert only those errno values that can be returned from used system calls. Signed-off-by: Max Filippov Signed-off-by: Blue Swirl --- target-xtensa/xtensa-semi.c | 106 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c index 6d001c2c1..e745bef0e 100644 --- a/target-xtensa/xtensa-semi.c +++ b/target-xtensa/xtensa-semi.c @@ -54,6 +54,96 @@ enum { SELECT_ONE_EXCEPT = 3, }; +enum { + TARGET_EPERM = 1, + TARGET_ENOENT = 2, + TARGET_ESRCH = 3, + TARGET_EINTR = 4, + TARGET_EIO = 5, + TARGET_ENXIO = 6, + TARGET_E2BIG = 7, + TARGET_ENOEXEC = 8, + TARGET_EBADF = 9, + TARGET_ECHILD = 10, + TARGET_EAGAIN = 11, + TARGET_ENOMEM = 12, + TARGET_EACCES = 13, + TARGET_EFAULT = 14, + TARGET_ENOTBLK = 15, + TARGET_EBUSY = 16, + TARGET_EEXIST = 17, + TARGET_EXDEV = 18, + TARGET_ENODEV = 19, + TARGET_ENOTDIR = 20, + TARGET_EISDIR = 21, + TARGET_EINVAL = 22, + TARGET_ENFILE = 23, + TARGET_EMFILE = 24, + TARGET_ENOTTY = 25, + TARGET_ETXTBSY = 26, + TARGET_EFBIG = 27, + TARGET_ENOSPC = 28, + TARGET_ESPIPE = 29, + TARGET_EROFS = 30, + TARGET_EMLINK = 31, + TARGET_EPIPE = 32, + TARGET_EDOM = 33, + TARGET_ERANGE = 34, + TARGET_ENOSYS = 88, + TARGET_ELOOP = 92, +}; + +static uint32_t errno_h2g(int host_errno) +{ + static const uint32_t guest_errno[] = { + [EPERM] = TARGET_EPERM, + [ENOENT] = TARGET_ENOENT, + [ESRCH] = TARGET_ESRCH, + [EINTR] = TARGET_EINTR, + [EIO] = TARGET_EIO, + [ENXIO] = TARGET_ENXIO, + [E2BIG] = TARGET_E2BIG, + [ENOEXEC] = TARGET_ENOEXEC, + [EBADF] = TARGET_EBADF, + [ECHILD] = TARGET_ECHILD, + [EAGAIN] = TARGET_EAGAIN, + [ENOMEM] = TARGET_ENOMEM, + [EACCES] = TARGET_EACCES, + [EFAULT] = TARGET_EFAULT, + [ENOTBLK] = TARGET_ENOTBLK, + [EBUSY] = TARGET_EBUSY, + [EEXIST] = TARGET_EEXIST, + [EXDEV] = TARGET_EXDEV, + [ENODEV] = TARGET_ENODEV, + [ENOTDIR] = TARGET_ENOTDIR, + [EISDIR] = TARGET_EISDIR, + [EINVAL] = TARGET_EINVAL, + [ENFILE] = TARGET_ENFILE, + [EMFILE] = TARGET_EMFILE, + [ENOTTY] = TARGET_ENOTTY, + [ETXTBSY] = TARGET_ETXTBSY, + [EFBIG] = TARGET_EFBIG, + [ENOSPC] = TARGET_ENOSPC, + [ESPIPE] = TARGET_ESPIPE, + [EROFS] = TARGET_EROFS, + [EMLINK] = TARGET_EMLINK, + [EPIPE] = TARGET_EPIPE, + [EDOM] = TARGET_EDOM, + [ERANGE] = TARGET_ERANGE, + [ENOSYS] = TARGET_ENOSYS, + [ELOOP] = TARGET_ELOOP, + }; + + if (host_errno == 0) { + return 0; + } else if (host_errno > 0 && host_errno < ARRAY_SIZE(guest_errno) && + guest_errno[host_errno]) { + return guest_errno[host_errno]; + } else { + return TARGET_EINVAL; + } +} + void HELPER(simcall)(CPUXtensaState *env) { uint32_t *regs = env->regs; @@ -87,14 +177,14 @@ void HELPER(simcall)(CPUXtensaState *env) regs[2] = is_write ? write(fd, buf, io_sz) : read(fd, buf, io_sz); - regs[3] = errno; + regs[3] = errno_h2g(errno); cpu_physical_memory_unmap(buf, sz, is_write, sz); if (regs[2] == -1) { break; } } else { regs[2] = -1; - regs[3] = EINVAL; + regs[3] = TARGET_EINVAL; break; } } @@ -117,10 +207,10 @@ void HELPER(simcall)(CPUXtensaState *env) if (rc == 0 && i < ARRAY_SIZE(name)) { regs[2] = open(name, regs[4], regs[5]); - regs[3] = errno; + regs[3] = errno_h2g(errno); } else { regs[2] = -1; - regs[3] = EINVAL; + regs[3] = TARGET_EINVAL; } } break; @@ -130,13 +220,13 @@ void HELPER(simcall)(CPUXtensaState *env) regs[2] = regs[3] = 0; } else { regs[2] = close(regs[3]); - regs[3] = errno; + regs[3] = errno_h2g(errno); } break; case TARGET_SYS_lseek: regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]); - regs[3] = errno; + regs[3] = errno_h2g(errno); break; case TARGET_SYS_select_one: @@ -163,7 +253,7 @@ void HELPER(simcall)(CPUXtensaState *env) rq == SELECT_ONE_WRITE ? &fdset : NULL, rq == SELECT_ONE_EXCEPT ? &fdset : NULL, target_tv ? &tv : NULL); - regs[3] = errno; + regs[3] = errno_h2g(errno); } break; @@ -219,7 +309,7 @@ void HELPER(simcall)(CPUXtensaState *env) default: qemu_log("%s(%d): not implemented\n", __func__, regs[2]); regs[2] = -1; - regs[3] = ENOSYS; + regs[3] = TARGET_ENOSYS; break; } } -- cgit v1.2.3 From 6e4c0d1f03d6ab407509c32fab7cb4b8230f57ff Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 27 Aug 2012 12:32:36 +0100 Subject: hw/pl110: Fix spelling of 'palette' Fix the spelling of 'palette' used in various local variables, structure members and comments. Signed-off-by: Peter Maydell Reviewed-by: Stefan Weil Signed-off-by: Aurelien Jarno --- hw/pl110.c | 30 +++++++++++++++--------------- hw/pl110_template.h | 22 +++++++++++----------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hw/pl110.c b/hw/pl110.c index f94608cb6..a5826407a 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -55,8 +55,8 @@ typedef struct { enum pl110_bppmode bpp; int invalidate; uint32_t mux_ctrl; - uint32_t pallette[256]; - uint32_t raw_pallette[128]; + uint32_t palette[256]; + uint32_t raw_palette[128]; qemu_irq irq; } pl110_state; @@ -79,8 +79,8 @@ static const VMStateDescription vmstate_pl110 = { VMSTATE_INT32(rows, pl110_state), VMSTATE_UINT32(bpp, pl110_state), VMSTATE_INT32(invalidate, pl110_state), - VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256), - VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128), + VMSTATE_UINT32_ARRAY(palette, pl110_state, 256), + VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128), VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2), VMSTATE_END_OF_LIST() } @@ -236,7 +236,7 @@ static void pl110_update_display(void *opaque) s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, - fn, s->pallette, + fn, s->palette, &first, &last); if (first >= 0) { dpy_update(s->ds, 0, first, s->cols, last - first + 1); @@ -253,13 +253,13 @@ static void pl110_invalidate_display(void * opaque) } } -static void pl110_update_pallette(pl110_state *s, int n) +static void pl110_update_palette(pl110_state *s, int n) { int i; uint32_t raw; unsigned int r, g, b; - raw = s->raw_pallette[n]; + raw = s->raw_palette[n]; n <<= 1; for (i = 0; i < 2; i++) { r = (raw & 0x1f) << 3; @@ -271,17 +271,17 @@ static void pl110_update_pallette(pl110_state *s, int n) raw >>= 6; switch (ds_get_bits_per_pixel(s->ds)) { case 8: - s->pallette[n] = rgb_to_pixel8(r, g, b); + s->palette[n] = rgb_to_pixel8(r, g, b); break; case 15: - s->pallette[n] = rgb_to_pixel15(r, g, b); + s->palette[n] = rgb_to_pixel15(r, g, b); break; case 16: - s->pallette[n] = rgb_to_pixel16(r, g, b); + s->palette[n] = rgb_to_pixel16(r, g, b); break; case 24: case 32: - s->pallette[n] = rgb_to_pixel32(r, g, b); + s->palette[n] = rgb_to_pixel32(r, g, b); break; } n++; @@ -314,7 +314,7 @@ static uint64_t pl110_read(void *opaque, target_phys_addr_t offset, return idregs[s->version][(offset - 0xfe0) >> 2]; } if (offset >= 0x200 && offset < 0x400) { - return s->raw_pallette[(offset - 0x200) >> 2]; + return s->raw_palette[(offset - 0x200) >> 2]; } switch (offset >> 2) { case 0: /* LCDTiming0 */ @@ -364,10 +364,10 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, is written to. */ s->invalidate = 1; if (offset >= 0x200 && offset < 0x400) { - /* Pallette. */ + /* Palette. */ n = (offset - 0x200) >> 2; - s->raw_pallette[(offset - 0x200) >> 2] = val; - pl110_update_pallette(s, n); + s->raw_palette[(offset - 0x200) >> 2] = val; + pl110_update_palette(s, n); return; } switch (offset >> 2) { diff --git a/hw/pl110_template.h b/hw/pl110_template.h index 1dce32a0c..e738e4a24 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -129,14 +129,14 @@ static drawfn glue(pl110_draw_fn_,BITS)[48] = static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]); #endif #ifdef SWAP_WORDS FN_8(24) @@ -157,14 +157,14 @@ static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]); #endif #ifdef SWAP_WORDS FN_4(0, 24) @@ -185,14 +185,14 @@ static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]); #endif #ifdef SWAP_WORDS FN_2(0, 24) @@ -213,11 +213,11 @@ static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; -#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); +#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]); #ifdef SWAP_WORDS FN(24) FN(16) -- cgit v1.2.3 From 692e587fc61fd32d755234d187b4f082e28c3993 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 19 Jul 2012 17:26:10 +0300 Subject: qemu: add .exrc I've been using this to get correct indenting with vim in qemu for a while, but it's a bit easier if we put the settings in the central place. Note that 1. you still need to enable 'exrc' and 'secure' options in your vimrc for these settings to take effect. 2. you can create a .vimrc file if 'exrc' is on but there's need to bypass this configuration. Signed-off-by: Michael S. Tsirkin --- .exrc | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .exrc diff --git a/.exrc b/.exrc new file mode 100644 index 000000000..37755ede8 --- /dev/null +++ b/.exrc @@ -0,0 +1,7 @@ +"VIM settings to match QEMU coding style. They are activated by adding the +"following settings (without the " symbol) as last two lines in $HOME/.vimrc: +"set secure +"set exrc +set expandtab +set shiftwidth=4 +set smarttab -- cgit v1.2.3 From 1de53459272d89c52bb21b45d5d970de40fbb642 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Wed, 8 Aug 2012 14:29:12 -0400 Subject: pcie: drop version_id field for live migration While testing q35 live migration, I found that the migration would abort with the following error: "Unknown savevm section type 76". The error is due to this check failing in 'vmstate_load_state()': while(field->name) { if ((field->field_exists && field->field_exists(opaque, version_id)) || (!field->field_exists && field->version_id <= version_id)) { The VMSTATE_PCIE_DEVICE() currently has a 'version_id' set to 2. However, 'version_id' in the above check is 1. And thus we fail to load the pcie device field. Further the code returns to 'qemu_loadvm_state()' which produces the error that I saw. I'm proposing to fix this by simply dropping the 'version_id' field from VMSTATE_PCIE_DEVICE(). VMSTATE_PCI_DEVICE() defines no such field and further the vmstate_pcie_device that VMSTATE_PCI_DEVICE() refers to is already versioned. Thus, any versioning issues could be detected at the vmsd level. Taking a step back, I think that the 'field->version_id' should be compared against a saved version number for the field not the 'version_id'. Futhermore, once vmstate_load_state() is called recursively on another vmsd, the check of: if (version_id > vmsd->version_id) { return -EINVAL; } Will never fail since version_id is always equal to vmsd->version_id. So I'm wondering why we aren't storing the vmsd version id of the source in the migration stream? This patch also renames the 'name' field of vmstate_pcie_device from: PCIDevice -> PCIEDevice to differentiate it from vmstate_pci_device. Signed-off-by: Jason Baron Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- hw/pcie.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 4d9598480..f855cf3f3 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -439,7 +439,7 @@ const VMStateDescription vmstate_pci_device = { }; const VMStateDescription vmstate_pcie_device = { - .name = "PCIDevice", + .name = "PCIEDevice", .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, diff --git a/hw/pcie.h b/hw/pcie.h index b8ab0c7b4..4889194ae 100644 --- a/hw/pcie.h +++ b/hw/pcie.h @@ -133,7 +133,6 @@ extern const VMStateDescription vmstate_pcie_device; #define VMSTATE_PCIE_DEVICE(_field, _state) { \ .name = (stringify(_field)), \ - .version_id = 2, \ .size = sizeof(PCIDevice), \ .vmsd = &vmstate_pcie_device, \ .flags = VMS_STRUCT, \ -- cgit v1.2.3 From 0e180d9c8a7429c55d23d2e7855f1e490a063aaa Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Tue, 4 Sep 2012 16:22:46 -0400 Subject: pcie_aer: clear cmask for Advanced Error Interrupt Message Number The Advanced Error Interrupt Message Number (bits 31:27 of the Root Error Status Register) is updated when the number of msi messages assigned to a device changes. Migration of windows 7 on q35 chipset failed because the check in get_pci_config_device() fails due to cmask being set on these bits. Its valid to update these bits and we must restore this state across migration. Signed-off-by: Jason Baron Signed-off-by: Michael S. Tsirkin --- hw/pcie_aer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c index 3b6981c7b..b04c164e2 100644 --- a/hw/pcie_aer.c +++ b/hw/pcie_aer.c @@ -738,6 +738,11 @@ void pcie_aer_root_init(PCIDevice *dev) PCI_ERR_ROOT_CMD_EN_MASK); pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, PCI_ERR_ROOT_STATUS_REPORT_MASK); + /* PCI_ERR_ROOT_IRQ is RO but devices change it using a + * device-specific method. + */ + pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, + ~PCI_ERR_ROOT_IRQ); } void pcie_aer_root_reset(PCIDevice *dev) -- cgit v1.2.3 From a96ed02fc73e23748c8b3e38880eeac91f83ab9f Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 21 Aug 2012 20:52:07 +0000 Subject: monitor: Rename+move net_handle_fd_param -> monitor_handle_fd_param This patch renames+moves the net_handle_fd_param() caller used to obtain a file descriptor from either qemu_parse_fd() (the normal case) or from monitor_get_fd() (migration case) into a generically prefixed monitor_handle_fd_param() to be used by vhost-scsi code. Also update net/[socket,tap].c consumers to use the new prefix. Reported-by: Michael S. Tsirkin Cc: Michael S. Tsirkin Cc: Stefan Hajnoczi Cc: Paolo Bonzini Cc: Anthony Liguori Signed-off-by: Nicholas Bellinger Signed-off-by: Michael S. Tsirkin --- monitor.c | 18 ++++++++++++++++++ monitor.h | 1 + net.c | 18 ------------------ net.h | 2 -- net/socket.c | 2 +- net/tap.c | 4 ++-- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/monitor.c b/monitor.c index b17b1bb84..6b70b20b9 100644 --- a/monitor.c +++ b/monitor.c @@ -2651,6 +2651,24 @@ int monitor_fdset_dup_fd_remove(int dup_fd) return monitor_fdset_dup_fd_find_remove(dup_fd, true); } +int monitor_handle_fd_param(Monitor *mon, const char *fdname) +{ + int fd; + + if (!qemu_isdigit(fdname[0]) && mon) { + + fd = monitor_get_fd(mon, fdname); + if (fd == -1) { + error_report("No file descriptor named %s found", fdname); + return -1; + } + } else { + fd = qemu_parse_fd(fdname); + } + + return fd; +} + /* mon_cmds and info_cmds would be sorted at runtime */ static mon_cmd_t mon_cmds[] = { #include "hmp-commands.h" diff --git a/monitor.h b/monitor.h index 47d556b9d..714b9ea5b 100644 --- a/monitor.h +++ b/monitor.h @@ -66,6 +66,7 @@ int monitor_read_block_device_key(Monitor *mon, const char *device, void *opaque); int monitor_get_fd(Monitor *mon, const char *fdname); +int monitor_handle_fd_param(Monitor *mon, const char *fdname); void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); diff --git a/net.c b/net.c index 60043ddec..e5d25d4b6 100644 --- a/net.c +++ b/net.c @@ -522,24 +522,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, return -1; } -int net_handle_fd_param(Monitor *mon, const char *param) -{ - int fd; - - if (!qemu_isdigit(param[0]) && mon) { - - fd = monitor_get_fd(mon, param); - if (fd == -1) { - error_report("No file descriptor named %s found", param); - return -1; - } - } else { - fd = qemu_parse_fd(param); - } - - return fd; -} - static int net_init_nic(const NetClientOptions *opts, const char *name, NetClientState *peer) { diff --git a/net.h b/net.h index 29750567e..04fda1d6c 100644 --- a/net.h +++ b/net.h @@ -168,8 +168,6 @@ int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret); void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd); -int net_handle_fd_param(Monitor *mon, const char *param); - #define POLYNOMIAL 0x04c11db6 unsigned compute_mcast_idx(const uint8_t *ep); diff --git a/net/socket.c b/net/socket.c index c172c249b..7c602e4c3 100644 --- a/net/socket.c +++ b/net/socket.c @@ -629,7 +629,7 @@ int net_init_socket(const NetClientOptions *opts, const char *name, if (sock->has_fd) { int fd; - fd = net_handle_fd_param(cur_mon, sock->fd); + fd = monitor_handle_fd_param(cur_mon, sock->fd); if (fd == -1 || !net_socket_fd_init(peer, "socket", name, fd, 1)) { return -1; } diff --git a/net/tap.c b/net/tap.c index 197152579..a88ae8f61 100644 --- a/net/tap.c +++ b/net/tap.c @@ -610,7 +610,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, return -1; } - fd = net_handle_fd_param(cur_mon, tap->fd); + fd = monitor_handle_fd_param(cur_mon, tap->fd); if (fd == -1) { return -1; } @@ -686,7 +686,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, int vhostfd; if (tap->has_vhostfd) { - vhostfd = net_handle_fd_param(cur_mon, tap->vhostfd); + vhostfd = monitor_handle_fd_param(cur_mon, tap->vhostfd); if (vhostfd == -1) { return -1; } -- cgit v1.2.3 From 1241ed94c331ddd8fc8297b02b4508ead59467de Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Aug 2012 20:52:08 +0000 Subject: vhost: Pass device path to vhost_dev_init() The path to /dev/vhost-net is currently hardcoded in vhost_dev_init(). This needs to be changed so that /dev/vhost-scsi can be used. Pass in the device path instead of hardcoding it. Signed-off-by: Stefan Hajnoczi Cc: Paolo Bonzini Cc: Michael S. Tsirkin Signed-off-by: Nicholas Bellinger Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 5 +++-- hw/vhost.h | 3 ++- hw/vhost_net.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 0fd8da84e..d0ce5aad9 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -747,14 +747,15 @@ static void vhost_eventfd_del(MemoryListener *listener, { } -int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force) +int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, + bool force) { uint64_t features; int r; if (devfd >= 0) { hdev->control = devfd; } else { - hdev->control = open("/dev/vhost-net", O_RDWR); + hdev->control = open(devpath, O_RDWR); if (hdev->control < 0) { return -errno; } diff --git a/hw/vhost.h b/hw/vhost.h index 80e64df86..0c47229f9 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -44,7 +44,8 @@ struct vhost_dev { bool force; }; -int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force); +int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, + bool force); void vhost_dev_cleanup(struct vhost_dev *hdev); bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev); int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); diff --git a/hw/vhost_net.c b/hw/vhost_net.c index ecaa22dfb..df2c4a30a 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -109,7 +109,7 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, (1 << VHOST_NET_F_VIRTIO_NET_HDR); net->backend = r; - r = vhost_dev_init(&net->dev, devfd, force); + r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force); if (r < 0) { goto fail; } -- cgit v1.2.3 From 7e9c7ffe9fd9dfc3d0168dd584936db8144b230b Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Wed, 5 Sep 2012 14:56:39 +0200 Subject: fix entry pointer for ELF kernels loaded with -kernel option Find a hopefully proper patch attached. Take it or leave it. Reviewed-by: Kevin Wolf Signed-off-by: Henning Schild Signed-off-by: Aurelien Jarno --- hw/elf_ops.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/elf_ops.h b/hw/elf_ops.h index fa65ce2f9..731a98385 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd, addr = ph->p_paddr; } + /* the entry pointer in the ELF header is a virtual + * address, if the text segments paddr and vaddr differ + * we need to adjust the entry */ + if (pentry && !translate_fn && + ph->p_vaddr != ph->p_paddr && + ehdr.e_entry >= ph->p_vaddr && + ehdr.e_entry < ph->p_vaddr + ph->p_filesz && + ph->p_flags & PF_X) { + *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr; + } + snprintf(label, sizeof(label), "phdr #%d: %s", i, name); rom_add_blob_fixed(label, data, mem_size, addr); -- cgit v1.2.3 From 449bc90e1f2e2fbafb64eb0c76d16c9352b0d2df Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 10 Jun 2012 23:18:44 +0200 Subject: lan9118: fix multicast filtering The lan9118 emulation tries to compute the multicast index by calling directly the crc32() function from zlib, but fails to get the correct result. Use the common compute_mcast_idx() function instead, which gives the correct result. This fixes IPv6 support. Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- hw/lan9118.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/lan9118.c b/hw/lan9118.c index ff0a50be1..ceaf96fc3 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -500,7 +500,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) } } else { /* Hash matching */ - hash = (crc32(~0, addr, 6) >> 26); + hash = compute_mcast_idx(addr); if (hash & 0x20) { return (s->mac_hashh >> (hash & 0x1f)) & 1; } else { -- cgit v1.2.3 From 03e6e5017757645f00b2f3b4f3a257973985e455 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 8 Jun 2012 02:04:40 +0100 Subject: MIPS/user: Fix reset CPU state initialization This change updates the CPU reset sequence to use a common piece of code that figures out CPU state flags, fixing the problem with MIPS_HFLAG_COP1X not being set where applicable that causes floating-point MADD family instructions (and other instructions from the MIPS IV FP subset) to trap. As compute_hflags is now shared between op_helper.c and translate.c, the function is now moved to a common header. There are no changes to this function. The problem was seen with the 24Kf MIPS32r2 processor in user emulation. The new approach prevents system and user emulation from diverging -- all the hflags state is initialized in one place now. Signed-off-by: Maciej W. Rozycki Signed-off-by: Aurelien Jarno --- target-mips/cpu.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ target-mips/op_helper.c | 49 ------------------------------------------------- target-mips/translate.c | 16 +++------------- 3 files changed, 52 insertions(+), 62 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index ce3467f14..88d92f118 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -742,4 +742,53 @@ static inline void cpu_pc_from_tb(CPUMIPSState *env, TranslationBlock *tb) env->hflags |= tb->flags & MIPS_HFLAG_BMASK; } +static inline void compute_hflags(CPUMIPSState *env) +{ + env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | + MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | + MIPS_HFLAG_UX); + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM)) { + env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; + } +#if defined(TARGET_MIPS64) + if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX))) { + env->hflags |= MIPS_HFLAG_64; + } + if (env->CP0_Status & (1 << CP0St_UX)) { + env->hflags |= MIPS_HFLAG_UX; + } +#endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || + !(env->hflags & MIPS_HFLAG_KSU)) { + env->hflags |= MIPS_HFLAG_CP0; + } + if (env->CP0_Status & (1 << CP0St_CU1)) { + env->hflags |= MIPS_HFLAG_FPU; + } + if (env->CP0_Status & (1 << CP0St_FR)) { + env->hflags |= MIPS_HFLAG_F64; + } + if (env->insn_flags & ISA_MIPS32R2) { + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } else if (env->insn_flags & ISA_MIPS32) { + if (env->hflags & MIPS_HFLAG_64) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } else if (env->insn_flags & ISA_MIPS4) { + /* All supported MIPS IV CPUs use the XX (CU3) to enable + and disable the MIPS IV extensions to the MIPS III ISA. + Some other MIPS IV CPUs ignore the bit, so the check here + would be too restrictive for them. */ + if (env->CP0_Status & (1 << CP0St_CU3)) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } +} + #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e5bc93e22..3d242aafd 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -32,55 +32,6 @@ static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global); #endif -static inline void compute_hflags(CPUMIPSState *env) -{ - env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | - MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | - MIPS_HFLAG_UX); - if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM)) { - env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; - } -#if defined(TARGET_MIPS64) - if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || - (env->CP0_Status & (1 << CP0St_PX)) || - (env->CP0_Status & (1 << CP0St_UX))) { - env->hflags |= MIPS_HFLAG_64; - } - if (env->CP0_Status & (1 << CP0St_UX)) { - env->hflags |= MIPS_HFLAG_UX; - } -#endif - if ((env->CP0_Status & (1 << CP0St_CU0)) || - !(env->hflags & MIPS_HFLAG_KSU)) { - env->hflags |= MIPS_HFLAG_CP0; - } - if (env->CP0_Status & (1 << CP0St_CU1)) { - env->hflags |= MIPS_HFLAG_FPU; - } - if (env->CP0_Status & (1 << CP0St_FR)) { - env->hflags |= MIPS_HFLAG_F64; - } - if (env->insn_flags & ISA_MIPS32R2) { - if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } else if (env->insn_flags & ISA_MIPS32) { - if (env->hflags & MIPS_HFLAG_64) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } else if (env->insn_flags & ISA_MIPS4) { - /* All supported MIPS IV CPUs use the XX (CU3) to enable - and disable the MIPS IV extensions to the MIPS III ISA. - Some other MIPS IV CPUs ignore the bit, so the check here - would be too restrictive for them. */ - if (env->CP0_Status & (1 << CP0St_CU3)) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } -} - /*****************************************************************************/ /* Exceptions processing helpers */ diff --git a/target-mips/translate.c b/target-mips/translate.c index b29341953..a884f751b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12787,18 +12787,13 @@ void cpu_state_reset(CPUMIPSState *env) env->insn_flags = env->cpu_model->insn_flags; #if defined(CONFIG_USER_ONLY) - env->hflags = MIPS_HFLAG_UM; + env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); /* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR hardware registers. */ env->CP0_HWREna |= 0x0000000F; if (env->CP0_Config1 & (1 << CP0C1_FP)) { - env->hflags |= MIPS_HFLAG_FPU; + env->CP0_Status |= (1 << CP0St_CU1); } -#ifdef TARGET_MIPS64 - if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { - env->hflags |= MIPS_HFLAG_F64; - } -#endif #else if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, @@ -12828,7 +12823,6 @@ void cpu_state_reset(CPUMIPSState *env) } /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); - env->hflags = MIPS_HFLAG_CP0; if (env->CP0_Config3 & (1 << CP0C3_MT)) { int i; @@ -12856,11 +12850,7 @@ void cpu_state_reset(CPUMIPSState *env) } } #endif -#if defined(TARGET_MIPS64) - if (env->cpu_model->insn_flags & ISA_MIPS3) { - env->hflags |= MIPS_HFLAG_64; - } -#endif + compute_hflags(env); env->exception_index = EXCP_NONE; } -- cgit v1.2.3 From c001ed15f7bfeaa3cabde5c9cc79c4dfdb674769 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Sep 2012 22:36:08 +0200 Subject: target-cris: Fix buffer overflow Report from smatch: target-cris/translate.c:3464 cpu_dump_state(32) error: buffer overflow 'env->sregs' 4 <= 255 sregs is declared 'uint32_t sregs[4][16]', so the first index must be less than 4 or ARRAY_SIZE(env->sregs). Signed-off-by: Stefan Weil --- target-cris/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-cris/translate.c b/target-cris/translate.c index 1ad9ec788..ad3187773 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3458,7 +3458,7 @@ void cpu_dump_state (CPUCRISState *env, FILE *f, fprintf_function cpu_fprintf, } srs = env->pregs[PR_SRS]; cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); - if (srs < 256) { + if (srs < ARRAY_SIZE(env->sregs)) { for (i = 0; i < 16; i++) { cpu_fprintf(f, "s%2.2d=%8.8x ", i, env->sregs[srs][i]); -- cgit v1.2.3 From c29b1bee4b025f51f02cc9f521ca19cb5f3eb432 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 6 Sep 2012 04:36:46 +0400 Subject: target-xtensa: fix missing errno codes for mingw32 Put the following errno value mappings under #ifdef: xtensa-semi.c: In function 'errno_h2g': xtensa-semi.c:113: error: 'ENOTBLK' undeclared (first use in this function) xtensa-semi.c:113: error: (Each undeclared identifier is reported only once xtensa-semi.c:113: error: for each function it appears in.) xtensa-semi.c:113: error: array index in initializer not of integer type xtensa-semi.c:113: error: (near initialization for 'guest_errno') xtensa-semi.c:124: error: 'ETXTBSY' undeclared (first use in this function) xtensa-semi.c:124: error: array index in initializer not of integer type xtensa-semi.c:124: error: (near initialization for 'guest_errno') xtensa-semi.c:134: error: 'ELOOP' undeclared (first use in this function) xtensa-semi.c:134: error: array index in initializer not of integer type xtensa-semi.c:134: error: (near initialization for 'guest_errno') Signed-off-by: Max Filippov Signed-off-by: Blue Swirl --- target-xtensa/xtensa-semi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c index e745bef0e..52be07a36 100644 --- a/target-xtensa/xtensa-semi.c +++ b/target-xtensa/xtensa-semi.c @@ -110,7 +110,9 @@ static uint32_t errno_h2g(int host_errno) [ENOMEM] = TARGET_ENOMEM, [EACCES] = TARGET_EACCES, [EFAULT] = TARGET_EFAULT, +#ifdef ENOTBLK [ENOTBLK] = TARGET_ENOTBLK, +#endif [EBUSY] = TARGET_EBUSY, [EEXIST] = TARGET_EEXIST, [EXDEV] = TARGET_EXDEV, @@ -121,7 +123,9 @@ static uint32_t errno_h2g(int host_errno) [ENFILE] = TARGET_ENFILE, [EMFILE] = TARGET_EMFILE, [ENOTTY] = TARGET_ENOTTY, +#ifdef ETXTBSY [ETXTBSY] = TARGET_ETXTBSY, +#endif [EFBIG] = TARGET_EFBIG, [ENOSPC] = TARGET_ENOSPC, [ESPIPE] = TARGET_ESPIPE, @@ -131,7 +135,9 @@ static uint32_t errno_h2g(int host_errno) [EDOM] = TARGET_EDOM, [ERANGE] = TARGET_ERANGE, [ENOSYS] = TARGET_ENOSYS, +#ifdef ELOOP [ELOOP] = TARGET_ELOOP, +#endif }; if (host_errno == 0) { -- cgit v1.2.3 From 5acfc8320fdd455c3ee5c21fe7d3403dbc755372 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 7 Sep 2012 17:13:28 +0200 Subject: target-sparc: fix fcmp{s,d,q} instructions wrt exception fcmp{s,d,q} instructions are supposed to ignore quiet NaN (contrary to the fcmpe{s,d,q} instructions), but the current code is wrongly setting the NV exception in that case. Moreover the current code is duplicated: first the arguments are checked for NaN to generate an exception, and later in case the comparison is unordered (which can only happens if one of the argument is a NaN), the same check is done to generate an exception. Fix that by calling clear_float_exceptions() followed by check_ieee_exceptions() as for the other floating point instructions. Use the _compare_quiet functions for fcmp{s,d,q} and the _compare ones for fcmpe{s,d,q}. Simplify the flag setting by not clearing a flag that is set the line just below. This fix allows the math glibc testsuite to pass. Cc: Blue Swirl Signed-off-by: Aurelien Jarno Signed-off-by: Blue Swirl --- target-sparc/fop_helper.c | 67 +++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c index 9c64ef89f..f4b62a5ba 100644 --- a/target-sparc/fop_helper.c +++ b/target-sparc/fop_helper.c @@ -334,34 +334,28 @@ void helper_fsqrtq(CPUSPARCState *env) } #define GEN_FCMP(name, size, reg1, reg2, FS, E) \ - void glue(helper_, name) (CPUSPARCState *env) \ + void glue(helper_, name) (CPUSPARCState *env) \ { \ - env->fsr &= FSR_FTT_NMASK; \ - if (E && (glue(size, _is_any_nan)(reg1) || \ - glue(size, _is_any_nan)(reg2)) && \ - (env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ + int ret; \ + clear_float_exceptions(env); \ + if (E) { \ + ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ + } else { \ + ret = glue(size, _compare_quiet)(reg1, reg2, \ + &env->fp_status); \ } \ - switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ + check_ieee_exceptions(env); \ + switch (ret) { \ case float_relation_unordered: \ - if ((env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ - } else { \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - } \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ + env->fsr |= FSR_NVA; \ break; \ case float_relation_less: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC1) << FS; \ env->fsr |= FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC0) << FS; \ env->fsr |= FSR_FCC1 << FS; \ break; \ default: \ @@ -370,34 +364,27 @@ void helper_fsqrtq(CPUSPARCState *env) } \ } #define GEN_FCMP_T(name, size, FS, E) \ - void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ + void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ { \ - env->fsr &= FSR_FTT_NMASK; \ - if (E && (glue(size, _is_any_nan)(src1) || \ - glue(size, _is_any_nan)(src2)) && \ - (env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ + int ret; \ + clear_float_exceptions(env); \ + if (E) { \ + ret = glue(size, _compare)(src1, src2, &env->fp_status); \ + } else { \ + ret = glue(size, _compare_quiet)(src1, src2, \ + &env->fp_status); \ } \ - switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ + check_ieee_exceptions(env); \ + switch (ret) { \ case float_relation_unordered: \ - if ((env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ - } else { \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - } \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ break; \ case float_relation_less: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC1 << FS); \ env->fsr |= FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC0 << FS); \ env->fsr |= FSR_FCC1 << FS; \ break; \ default: \ -- cgit v1.2.3 From ce6c760c37b9a88db87c5b9b9bf39ca866e570f6 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Tue, 22 May 2012 10:14:28 +0200 Subject: Add MAINTAINERS entry for leon3 Signed-off-by: Fabien Chouteau Signed-off-by: Blue Swirl --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6d864c1ce..61f8b45cb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -398,6 +398,12 @@ M: Blue Swirl S: Maintained F: hw/sun4u.c +Leon3 +M: Fabien Chouteau +S: Maintained +F: hw/leon3.c +F: hw/grlib* + S390 Machines ------------- S390 Virtio -- cgit v1.2.3 From 0c267217ca9985e6d118ec8368bebd382db7a099 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 8 Sep 2012 11:52:39 +0200 Subject: musicpal: Fix flash mapping The old arithmetic assumed 32 physical address bits which is no longer true for ARM since 3cc0cd61f4. Signed-off-by: Jan Kiszka Signed-off-by: Blue Swirl --- hw/musicpal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/musicpal.c b/hw/musicpal.c index ad725b559..f305e2103 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size, * image is smaller than 32 MB. */ #ifdef TARGET_WORDS_BIGENDIAN - pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, "musicpal.flash", flash_size, dinfo->bdrv, 0x10000, (flash_size + 0xffff) >> 16, @@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size, 2, 0x00BF, 0x236D, 0x0000, 0x0000, 0x5555, 0x2AAA, 1); #else - pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, "musicpal.flash", flash_size, dinfo->bdrv, 0x10000, (flash_size + 0xffff) >> 16, -- cgit v1.2.3 From 62fe83318d2fc5b31f473d66326910d94c1c4907 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 10 Aug 2012 15:11:45 +0200 Subject: qemu: Use valgrind annotations to mark kvm guest memory as defined valgrind with kvm produces a big amount of false positives regarding "Conditional jump or move depends on uninitialised value(s)". This happens because the guest memory is allocated with qemu_vmalloc which boils down posix_memalign etc. This function is (correctly) considered by valgrind as returning undefined memory. Since valgrind is based on jitting code, it will not be able to see changes made by the guest to guest memory if this is done by KVM_RUN, thus keeping most of the guest memory undefined. Now lots of places in qemu will then use guest memory to change behaviour. To avoid the flood of these messages, lets declare the whole guest memory as defined. This will reduce the noise and allows us to see real problems. In the future we might want to make this conditional, since there is actually something that we can use those false positives for: These messages will point to code that depends on guest memory, so we can use these backtraces to actually make an audit that is focussed only at those code places. For normal development we dont want to see those messages, though. Signed-off-by: Christian Borntraeger Signed-off-by: Avi Kivity --- configure | 3 ++- kvm-all.c | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/configure b/configure index d97fd8170..056b3561b 100755 --- a/configure +++ b/configure @@ -2963,11 +2963,12 @@ if compile_prog "-Werror" "" ; then fi ######################################## -# check if we have valgrind/valgrind.h +# check if we have valgrind/valgrind.h and valgrind/memcheck.h valgrind_h=no cat > $TMPC << EOF #include +#include int main(void) { return 0; } diff --git a/kvm-all.c b/kvm-all.c index 34b02c1fb..e0244b6d1 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -39,6 +39,10 @@ #include #endif +#ifdef CONFIG_VALGRIND_H +#include +#endif + /* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */ #define PAGE_SIZE TARGET_PAGE_SIZE @@ -1719,6 +1723,9 @@ void *kvm_vmalloc(ram_addr_t size) void kvm_setup_guest_memory(void *start, size_t size) { +#ifdef CONFIG_VALGRIND_H + VALGRIND_MAKE_MEM_DEFINED(start, size); +#endif if (!kvm_has_sync_mmu()) { int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK); -- cgit v1.2.3 From b131c74a0e485b084ddaffc8214c8a19af492be7 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 20 Aug 2012 10:55:56 +0200 Subject: kvm: Clean up irqfd API No need to expose the fd-based interface, everyone will already be fine with the more handy EventNotifier variant. Rename the latter to clarify that we are still talking about irqfds here. Signed-off-by: Jan Kiszka Acked-by: Alex Williamson Signed-off-by: Avi Kivity --- hw/virtio-pci.c | 4 ++-- kvm-all.c | 18 ++++-------------- kvm-stub.c | 14 ++------------ kvm.h | 6 ++---- 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index b3f0710f3..400f3c26b 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -517,7 +517,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, } irqfd->users++; - ret = kvm_irqchip_add_irq_notifier(kvm_state, n, irqfd->virq); + ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); if (ret < 0) { if (--irqfd->users == 0) { kvm_irqchip_release_virq(kvm_state, irqfd->virq); @@ -538,7 +538,7 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; - ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq); + ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); assert(ret == 0); if (--irqfd->users == 0) { diff --git a/kvm-all.c b/kvm-all.c index e0244b6d1..f96be2103 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1166,24 +1166,14 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) } #endif /* !KVM_CAP_IRQ_ROUTING */ -int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq) +int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) { - return kvm_irqchip_assign_irqfd(s, fd, virq, true); + return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), virq, true); } -int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq) +int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) { - return kvm_irqchip_add_irqfd(s, event_notifier_get_fd(n), virq); -} - -int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq) -{ - return kvm_irqchip_assign_irqfd(s, fd, virq, false); -} - -int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq) -{ - return kvm_irqchip_remove_irqfd(s, event_notifier_get_fd(n), virq); + return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), virq, false); } static int kvm_irqchip_create(KVMState *s) diff --git a/kvm-stub.c b/kvm-stub.c index 94c9ea15b..3c52eb5bc 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -141,22 +141,12 @@ void kvm_irqchip_release_virq(KVMState *s, int virq) { } -int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq) +int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) { return -ENOSYS; } -int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq) -{ - return -ENOSYS; -} - -int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq) -{ - return -ENOSYS; -} - -int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq) +int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) { return -ENOSYS; } diff --git a/kvm.h b/kvm.h index 5b8f58881..37d1f8166 100644 --- a/kvm.h +++ b/kvm.h @@ -272,8 +272,6 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign); int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg); void kvm_irqchip_release_virq(KVMState *s, int virq); -int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq); -int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq); -int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq); -int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq); +int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq); +int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq); #endif -- cgit v1.2.3 From 71e470886fb6092504503a5fe41092ace71c096c Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:30 +0000 Subject: target-s390x: fix style Before splitting op_helper.c and helper.c in the next patches, fix style issues. No functional changes. Replace also GCC specific __FUNCTION__ with standard __func__. Don't init static variable (cpu_s390x_init:inited) with 0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/helper.c | 96 ++++++----- target-s390x/op_helper.c | 438 +++++++++++++++++++++++++++-------------------- 2 files changed, 297 insertions(+), 237 deletions(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index d0a1180a8..d98e6d9dc 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -74,7 +74,7 @@ S390CPU *cpu_s390x_init(const char *cpu_model) { S390CPU *cpu; CPUS390XState *env; - static int inited = 0; + static int inited; cpu = S390_CPU(object_new(TYPE_S390_CPU)); env = &cpu->env; @@ -91,25 +91,27 @@ S390CPU *cpu_s390x_init(const char *cpu_model) #if defined(CONFIG_USER_ONLY) -void do_interrupt (CPUS390XState *env) +void do_interrupt(CPUS390XState *env) { env->exception_index = -1; } -int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw, - int mmu_idx) +int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, + int rw, int mmu_idx) { - /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n", - __FUNCTION__, address, rw, mmu_idx); */ + /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", + __func__, address, rw, mmu_idx); */ env->exception_index = EXCP_ADDR; - env->__excp_addr = address; /* FIXME: find out how this works on a real machine */ + /* FIXME: find out how this works on a real machine */ + env->__excp_addr = address; return 1; } #else /* !CONFIG_USER_ONLY */ /* Ensure to exit the TB after this call! */ -static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilc) +static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, + uint32_t ilc) { env->exception_index = EXCP_PGM; env->int_pgm_code = code; @@ -138,19 +140,20 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) return bits; } -static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) +static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, + uint64_t mode) { int ilc = ILC_LATER_INC_2; int bits = trans_bits(env, mode) | 4; - DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits); + DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); trigger_pgm_exception(env, PGM_PROTECTION, ilc); } -static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, - uint64_t asc, int rw) +static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, + uint32_t type, uint64_t asc, int rw) { int ilc = ILC_LATER; int bits = trans_bits(env, asc); @@ -160,26 +163,26 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t ilc = 2; } - DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits); + DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); trigger_pgm_exception(env, type, ilc); } -static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc, - uint64_t asce, int level, target_ulong *raddr, - int *flags, int rw) +static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, uint64_t asce, int level, + target_ulong *raddr, int *flags, int rw) { uint64_t offs = 0; uint64_t origin; uint64_t new_asce; - PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce); + PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, asce); if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) || ((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) { /* XXX different regions have different faults */ - DPRINTF("%s: invalid region\n", __FUNCTION__); + DPRINTF("%s: invalid region\n", __func__); trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw); return -1; } @@ -222,7 +225,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a new_asce = ldq_phys(origin + offs); PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", - __FUNCTION__, origin, offs, new_asce); + __func__, origin, offs, new_asce); if (level != _ASCE_TYPE_SEGMENT) { /* yet another region */ @@ -232,7 +235,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a /* PTE */ if (new_asce & _PAGE_INVALID) { - DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce); + DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, new_asce); trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); return -1; } @@ -243,13 +246,14 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a *raddr = new_asce & _ASCE_ORIGIN; - PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce); + PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, new_asce); return 0; } -static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t asc, - target_ulong *raddr, int *flags, int rw) +static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, target_ulong *raddr, int *flags, + int rw) { uint64_t asce = 0; int level, new_level; @@ -257,15 +261,15 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as switch (asc) { case PSW_ASC_PRIMARY: - PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__); + PTE_DPRINTF("%s: asc=primary\n", __func__); asce = env->cregs[1]; break; case PSW_ASC_SECONDARY: - PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__); + PTE_DPRINTF("%s: asc=secondary\n", __func__); asce = env->cregs[7]; break; case PSW_ASC_HOME: - PTE_DPRINTF("%s: asc=home\n", __FUNCTION__); + PTE_DPRINTF("%s: asc=home\n", __func__); asce = env->cregs[13]; break; } @@ -276,8 +280,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as case _ASCE_TYPE_REGION2: if (vaddr & 0xffe0000000000000ULL) { DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 - " 0xffe0000000000000ULL\n", __FUNCTION__, - vaddr); + " 0xffe0000000000000ULL\n", __func__, vaddr); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); return -1; } @@ -285,8 +288,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as case _ASCE_TYPE_REGION3: if (vaddr & 0xfffffc0000000000ULL) { DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 - " 0xfffffc0000000000ULL\n", __FUNCTION__, - vaddr); + " 0xfffffc0000000000ULL\n", __func__, vaddr); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); return -1; } @@ -294,8 +296,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as case _ASCE_TYPE_SEGMENT: if (vaddr & 0xffffffff80000000ULL) { DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 - " 0xffffffff80000000ULL\n", __FUNCTION__, - vaddr); + " 0xffffffff80000000ULL\n", __func__, vaddr); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); return -1; } @@ -358,7 +359,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, break; } -out: + out: /* Convert real address -> absolute address */ if (*raddr < 0x2000) { *raddr = *raddr + env->psa; @@ -378,18 +379,18 @@ out: return r; } -int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw, - int mmu_idx) +int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, + int rw, int mmu_idx) { uint64_t asc = env->psw.mask & PSW_MASK_ASC; target_ulong vaddr, raddr; int prot; DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n", - __FUNCTION__, _vaddr, rw, mmu_idx); + __func__, _vaddr, rw, mmu_idx); - _vaddr &= TARGET_PAGE_MASK; - vaddr = _vaddr; + orig_vaddr &= TARGET_PAGE_MASK; + vaddr = orig_vaddr; /* 31-Bit mode */ if (!(env->psw.mask & PSW_MASK_64)) { @@ -403,22 +404,23 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw, /* check out of RAM access */ if (raddr > (ram_size + virtio_size)) { - DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__, + DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)aaddr, (uint64_t)ram_size); trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); return 1; } - DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__, + DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __func__, (uint64_t)vaddr, (uint64_t)raddr, prot); - tlb_set_page(env, _vaddr, raddr, prot, + tlb_set_page(env, orig_vaddr, raddr, prot, mmu_idx, TARGET_PAGE_SIZE); return 0; } -target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, target_ulong vaddr) +target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, + target_ulong vaddr) { target_ulong raddr; int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -509,7 +511,7 @@ static void do_program_interrupt(CPUS390XState *env) break; } - qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc); + qemu_log("%s: code=0x%x ilc=%d\n", __func__, env->int_pgm_code, ilc); lowcore = cpu_physical_memory_map(env->psa, &len, 1); @@ -522,7 +524,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_physical_memory_unmap(lowcore, len, 1, len); - DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__, + DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, env->int_pgm_code, ilc, env->psw.mask, env->psw.addr); @@ -565,15 +567,15 @@ static void do_ext_interrupt(CPUS390XState *env) env->pending_int &= ~INTERRUPT_EXT; } - DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__, + DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); } -void do_interrupt (CPUS390XState *env) +void do_interrupt(CPUS390XState *env) { - qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index, + qemu_log("%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); s390_add_running_cpu(env); diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index abc35ddd7..195e93ed5 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -31,13 +31,13 @@ #include #endif -#if !defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) #include "sysemu.h" #endif /*****************************************************************************/ /* Softmmu support */ -#if !defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #define MMUSUFFIX _mmu @@ -95,7 +95,7 @@ void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, /* raise an exception */ void HELPER(exception)(uint32_t excp) { - HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); + HELPER_LOG("%s: exception %d\n", __func__, excp); env->exception_index = excp; cpu_loop_exit(env); } @@ -164,7 +164,7 @@ uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) uint32_t cc = 0; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); + __func__, l, dest, src); for (i = 0; i <= l; i++) { x = ldub(dest + i) & ldub(src + i); if (x) { @@ -183,7 +183,7 @@ uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) uint32_t cc = 0; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); + __func__, l, dest, src); #ifndef CONFIG_USER_ONLY /* xor with itself is the same as memset(0) */ @@ -217,7 +217,7 @@ uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) uint32_t cc = 0; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); + __func__, l, dest, src); for (i = 0; i <= l; i++) { x = ldub(dest + i) | ldub(src + i); if (x) { @@ -236,7 +236,7 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) uint32_t l_64 = (l + 1) / 8; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); + __func__, l, dest, src); #ifndef CONFIG_USER_ONLY if ((l > 32) && @@ -278,10 +278,11 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) { int i; - unsigned char x,y; + unsigned char x, y; uint32_t cc; + HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", - __FUNCTION__, l, s1, s2); + __func__, l, s1, s2); for (i = 0; i <= l; i++) { x = ldub(s1 + i); y = ldub(s2 + i); @@ -295,7 +296,7 @@ uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) } } cc = 0; -done: + done: HELPER_LOG("\n"); return cc; } @@ -303,9 +304,10 @@ done: /* compare logical under mask */ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) { - uint8_t r,d; + uint8_t r, d; uint32_t cc; - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1, + + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, mask, addr); cc = 0; while (mask) { @@ -313,7 +315,7 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) d = ldub(addr); r = (r1 & 0xff000000UL) >> 24; HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, - addr); + addr); if (r < d) { cc = 1; break; @@ -334,7 +336,8 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) { uint8_t r; - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask, + + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, addr); while (mask) { if (mask & 8) { @@ -355,6 +358,7 @@ void HELPER(mlg)(uint32_t r1, uint64_t v2) #if HOST_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ __uint128_t res = (__uint128_t)env->regs[r1 + 1]; + res *= (__uint128_t)v2; env->regs[r1] = (uint64_t)(res >> 64); env->regs[r1 + 1] = (uint64_t)res; @@ -370,18 +374,18 @@ void HELPER(dlg)(uint32_t r1, uint64_t v2) if (!env->regs[r1]) { /* 64 -> 64/64 case */ - env->regs[r1] = env->regs[r1+1] % divisor; - env->regs[r1+1] = env->regs[r1+1] / divisor; + env->regs[r1] = env->regs[r1 + 1] % divisor; + env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; return; } else { - #if HOST_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | - (env->regs[r1+1]); + (env->regs[r1 + 1]); __uint128_t quotient = dividend / divisor; - env->regs[r1+1] = quotient; __uint128_t remainder = dividend % divisor; + + env->regs[r1 + 1] = quotient; env->regs[r1] = remainder; #else /* 32-bit hosts would need special wrapper functionality - just abort if @@ -431,7 +435,7 @@ uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) uint64_t str = get_address_31fix(r2); uint64_t end = get_address_31fix(r1); - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__, + HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, c, env->regs[r1], env->regs[r2]); for (i = str; i != end; i++) { @@ -452,11 +456,12 @@ uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) uint64_t s2 = get_address_31fix(r2); uint8_t v1, v2; uint32_t cc; + c = c & 0xff; #ifdef CONFIG_USER_ONLY if (!c) { HELPER_LOG("%s: comparing '%s' and '%s'\n", - __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2)); + __func__, (char *)g2h(s1), (char *)g2h(s2)); } #endif for (;;) { @@ -501,10 +506,11 @@ void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) uint64_t dest = get_address_31fix(r1); uint64_t src = get_address_31fix(r2); uint8_t v; + c = c & 0xff; #ifdef CONFIG_USER_ONLY if (!c) { - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src), + HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), dest); } #endif @@ -526,6 +532,7 @@ uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) /* FIXME: locking? */ uint32_t cc; uint64_t v2 = ldq(a2); + if (env->regs[r1] == v2) { cc = 0; stq(a2, env->regs[r3]); @@ -564,8 +571,9 @@ uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) { /* FIXME: locking? */ uint32_t cc; - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3); uint32_t v2 = ldl(a2); + + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); if (((uint32_t)env->regs[r1]) == v2) { cc = 0; stl(a2, (uint32_t)env->regs[r3]); @@ -612,14 +620,16 @@ static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) it does not change the program counter in other words: tricky... currently implemented by interpreting the cases it is most commonly used in - */ +*/ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) { uint16_t insn = lduw_code(addr); - HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr, - insn); + + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, + insn); if ((insn & 0xf0ff) == 0xd000) { uint32_t l, insn2, b1, b2, d1, d2; + l = v1 & 0xff; insn2 = ldl_code(addr + 2); b1 = (insn2 >> 28) & 0xf; @@ -645,13 +655,14 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) } } else if ((insn & 0xff00) == 0x0a00) { /* supervisor call */ - HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff); + HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); env->psw.addr = ret - 4; - env->int_svc_code = (insn|v1) & 0xff; + env->int_svc_code = (insn | v1) & 0xff; env->int_svc_ilc = 4; helper_exception(EXCP_SVC); } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; + insn2 = ldl_code(addr + 2); r1 = (insn2 >> 20) & 0xf; r3 = (insn2 >> 16) & 0xf; @@ -659,7 +670,7 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) d2 = insn2 & 0xfff; cc = helper_icm(r1, get_address(0, b2, d2), r3); } else { -abort: + abort: cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", insn); } @@ -689,7 +700,7 @@ int32_t HELPER(nabs_i32)(int32_t val) /* absolute value 64-bit */ uint64_t HELPER(abs_i64)(int64_t val) { - HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val); + HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); if (val < 0) { return -val; @@ -774,9 +785,9 @@ void HELPER(ipm)(uint32_t cc, uint32_t r1) uint64_t r = env->regs[r1]; r &= 0xffffffff00ffffffULL; - r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf ); + r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); env->regs[r1] = r; - HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__, + HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, cc, env->psw.mask, r); } @@ -908,7 +919,7 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) uint64_t srclen = env->regs[r3 + 1]; uint64_t src = get_address_31fix(r3); uint8_t pad = a2 & 0xff; - uint8_t v1 = 0,v2 = 0; + uint8_t v1 = 0, v2 = 0; uint32_t cc = 0; if (!(destlen || srclen)) { @@ -1036,7 +1047,7 @@ static uint32_t set_cc_nz_f128(float128 v) /* convert 32-bit int to 64-bit float */ void HELPER(cdfbr)(uint32_t f1, int32_t v2) { - HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1); + HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); } @@ -1044,6 +1055,7 @@ void HELPER(cdfbr)(uint32_t f1, int32_t v2) void HELPER(cxfbr)(uint32_t f1, int32_t v2) { CPU_QuadU v1; + v1.q = int32_to_float128(v2, &env->fpu_status); env->fregs[f1].ll = v1.ll.upper; env->fregs[f1 + 2].ll = v1.ll.lower; @@ -1052,14 +1064,14 @@ void HELPER(cxfbr)(uint32_t f1, int32_t v2) /* convert 64-bit int to 32-bit float */ void HELPER(cegbr)(uint32_t f1, int64_t v2) { - HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); } /* convert 64-bit int to 64-bit float */ void HELPER(cdgbr)(uint32_t f1, int64_t v2) { - HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); } @@ -1067,8 +1079,9 @@ void HELPER(cdgbr)(uint32_t f1, int64_t v2) void HELPER(cxgbr)(uint32_t f1, int64_t v2) { CPU_QuadU x1; + x1.q = int64_to_float128(v2, &env->fpu_status); - HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, + HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, x1.ll.upper, x1.ll.lower); env->fregs[f1].ll = x1.ll.upper; env->fregs[f1 + 2].ll = x1.ll.lower; @@ -1078,7 +1091,7 @@ void HELPER(cxgbr)(uint32_t f1, int64_t v2) void HELPER(cefbr)(uint32_t f1, int32_t v2) { env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); - HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, + HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, env->fregs[f1].l.upper, f1); } @@ -1088,7 +1101,7 @@ uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, env->fregs[f2].l.upper, &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); return set_cc_nz_f32(env->fregs[f1].l.upper); @@ -1099,7 +1112,7 @@ uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); - HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, + HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, env->fregs[f2].d, env->fregs[f1].d, f1); return set_cc_nz_f64(env->fregs[f1].d); @@ -1111,7 +1124,7 @@ uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, env->fregs[f2].l.upper, &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); return set_cc_nz_f32(env->fregs[f1].l.upper); @@ -1123,7 +1136,7 @@ uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", - __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); + __func__, env->fregs[f2].d, env->fregs[f1].d, f1); return set_cc_nz_f64(env->fregs[f1].d); } @@ -1140,12 +1153,13 @@ void HELPER(debr)(uint32_t f1, uint32_t f2) void HELPER(dxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; res.q = float128_div(v1.q, v2.q, &env->fpu_status); env->fregs[f1].ll = res.ll.upper; env->fregs[f1 + 2].ll = res.ll.lower; @@ -1162,12 +1176,13 @@ void HELPER(mdbr)(uint32_t f1, uint32_t f2) void HELPER(mxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; res.q = float128_mul(v1.q, v2.q, &env->fpu_status); env->fregs[f1].ll = res.ll.upper; env->fregs[f1 + 2].ll = res.ll.lower; @@ -1184,16 +1199,18 @@ void HELPER(ldebr)(uint32_t r1, uint32_t r2) void HELPER(ldxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU x2; + x2.ll.upper = env->fregs[f2].ll; x2.ll.lower = env->fregs[f2 + 2].ll; env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d); + HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); } /* convert 64-bit float to 128-bit float */ void HELPER(lxdbr)(uint32_t f1, uint32_t f2) { CPU_QuadU res; + res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); env->fregs[f1].ll = res.ll.upper; env->fregs[f1 + 2].ll = res.ll.lower; @@ -1203,6 +1220,7 @@ void HELPER(lxdbr)(uint32_t f1, uint32_t f2) void HELPER(ledbr)(uint32_t f1, uint32_t f2) { float64 d2 = env->fregs[f2].d; + env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); } @@ -1210,10 +1228,11 @@ void HELPER(ledbr)(uint32_t f1, uint32_t f2) void HELPER(lexbr)(uint32_t f1, uint32_t f2) { CPU_QuadU x2; + x2.ll.upper = env->fregs[f2].ll; x2.ll.lower = env->fregs[f2 + 2].ll; env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper); + HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); } /* absolute value of 32-bit float */ @@ -1221,6 +1240,7 @@ uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) { float32 v1; float32 v2 = env->fregs[f2].d; + v1 = float32_abs(v2); env->fregs[f1].d = v1; return set_cc_nz_f32(v1); @@ -1231,6 +1251,7 @@ uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) { float64 v1; float64 v2 = env->fregs[f2].d; + v1 = float64_abs(v2); env->fregs[f1].d = v1; return set_cc_nz_f64(v1); @@ -1241,6 +1262,7 @@ uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; v1.q = float128_abs(v2.q); @@ -1267,6 +1289,7 @@ uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU x; + x.ll.upper = env->fregs[f2].ll; x.ll.lower = env->fregs[f2 + 2].ll; env->fregs[f1].ll = x.ll.upper; @@ -1294,6 +1317,7 @@ uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU x1, x2; + x2.ll.upper = env->fregs[f2].ll; x2.ll.lower = env->fregs[f2 + 2].ll; x1.q = float128_chs(x2.q); @@ -1307,8 +1331,9 @@ void HELPER(aeb)(uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; + v2.l = val; - HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, + HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, v1, f1, v2.f); env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); } @@ -1318,8 +1343,9 @@ void HELPER(deb)(uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; + v2.l = val; - HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, + HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, v1, f1, v2.f); env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); } @@ -1329,8 +1355,9 @@ void HELPER(meeb)(uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; + v2.l = val; - HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, + HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, v1, f1, v2.f); env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); } @@ -1340,7 +1367,8 @@ uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) { float32 v1 = env->fregs[f1].l.upper; float32 v2 = env->fregs[f2].l.upper; - HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, + + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, v1, f1, v2); return set_cc_f32(v1, v2); } @@ -1350,7 +1378,8 @@ uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) { float64 v1 = env->fregs[f1].d; float64 v2 = env->fregs[f2].d; - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__, + + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, v1, f1, v2); return set_cc_f64(v1, v2); } @@ -1359,14 +1388,15 @@ uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU v1; + CPU_QuadU v2; + v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, - &env->fpu_status)); + &env->fpu_status)); } /* 64-bit FP compare RM */ @@ -1374,8 +1404,9 @@ uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; + v2.ll = ldq(a2); - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1, + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, f1, v2.d); return set_cc_f64(v1, v2.d); } @@ -1385,8 +1416,9 @@ uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; + v2.ll = ldq(a2); - HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__, + HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, v1, f1, v2.d); env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); return set_cc_nz_f64(v1); @@ -1397,6 +1429,7 @@ void HELPER(seb)(uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; + v2.l = val; env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); } @@ -1406,6 +1439,7 @@ uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; + v2.ll = ldq(a2); env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); return set_cc_nz_f64(v1); @@ -1416,8 +1450,9 @@ void HELPER(mdb)(uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; + v2.ll = ldq(a2); - HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__, + HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, v1, f1, v2.d); env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); } @@ -1427,8 +1462,9 @@ void HELPER(ddb)(uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; + v2.ll = ldq(a2); - HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__, + HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, v1, f1, v2.d); env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); } @@ -1464,6 +1500,7 @@ static void set_round_mode(int m3) uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) { float32 v2 = env->fregs[f2].l.upper; + set_round_mode(m3); env->regs[r1] = float32_to_int64(v2, &env->fpu_status); return set_cc_nz_f32(v2); @@ -1473,6 +1510,7 @@ uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) { float64 v2 = env->fregs[f2].d; + set_round_mode(m3); env->regs[r1] = float64_to_int64(v2, &env->fpu_status); return set_cc_nz_f64(v2); @@ -1482,6 +1520,7 @@ uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) { CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; set_round_mode(m3); @@ -1501,9 +1540,10 @@ uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) { float32 v2 = env->fregs[f2].l.upper; + set_round_mode(m3); env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float32_to_int32(v2, &env->fpu_status); + float32_to_int32(v2, &env->fpu_status); return set_cc_nz_f32(v2); } @@ -1511,9 +1551,10 @@ uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) { float64 v2 = env->fregs[f2].d; + set_round_mode(m3); env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float64_to_int32(v2, &env->fpu_status); + float64_to_int32(v2, &env->fpu_status); return set_cc_nz_f64(v2); } @@ -1521,10 +1562,11 @@ uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) { CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float128_to_int32(v2.q, &env->fpu_status); + float128_to_int32(v2.q, &env->fpu_status); return set_cc_nz_f128(v2.q); } @@ -1544,6 +1586,7 @@ void HELPER(lzdr)(uint32_t f1) void HELPER(lzxr)(uint32_t f1) { CPU_QuadU x; + x.q = float64_to_float128(float64_zero, &env->fpu_status); env->fregs[f1].ll = x.ll.upper; env->fregs[f1 + 1].ll = x.ll.lower; @@ -1553,12 +1596,13 @@ void HELPER(lzxr)(uint32_t f1) uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) { CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; res.q = float128_sub(v1.q, v2.q, &env->fpu_status); env->fregs[f1].ll = res.ll.upper; env->fregs[f1 + 2].ll = res.ll.lower; @@ -1569,12 +1613,13 @@ uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) { CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; res.q = float128_add(v1.q, v2.q, &env->fpu_status); env->fregs[f1].ll = res.ll.upper; env->fregs[f1 + 2].ll = res.ll.lower; @@ -1599,8 +1644,9 @@ void HELPER(ddbr)(uint32_t f1, uint32_t f2) /* 64-bit FP multiply and add RM */ void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) { - HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3); CPU_DoubleU v2; + + HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); v2.ll = ldq(a2); env->fregs[f1].d = float64_add(env->fregs[f1].d, float64_mul(v2.d, env->fregs[f3].d, @@ -1611,7 +1657,7 @@ void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) /* 64-bit FP multiply and add RR */ void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), @@ -1621,7 +1667,7 @@ void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) /* 64-bit FP multiply and subtract RR */ void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), @@ -1642,6 +1688,7 @@ void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) void HELPER(ldeb)(uint32_t f1, uint64_t a2) { uint32_t v2; + v2 = ldl(a2); env->fregs[f1].d = float32_to_float64(v2, &env->fpu_status); @@ -1651,8 +1698,9 @@ void HELPER(ldeb)(uint32_t f1, uint64_t a2) void HELPER(lxdb)(uint32_t f1, uint64_t a2) { CPU_DoubleU v2; - v2.ll = ldq(a2); CPU_QuadU v1; + + v2.ll = ldq(a2); v1.q = float64_to_float128(v2.d, &env->fpu_status); env->fregs[f1].ll = v1.ll.upper; env->fregs[f1 + 2].ll = v1.ll.lower; @@ -1665,7 +1713,7 @@ uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) int neg = float32_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg); + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -1687,7 +1735,7 @@ uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) int neg = float64_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -1706,10 +1754,12 @@ uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) { CPU_QuadU v1; uint32_t cc = 0; + int neg; + v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; - int neg = float128_is_neg(v1.q); + neg = float128_is_neg(v1.q); if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || @@ -1787,7 +1837,7 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) /* store result */ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); + ((uint32_t)cksm + (cksm >> 32)); } static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, @@ -1848,10 +1898,12 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, } } -static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) +static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, + uint32_t mask) { - HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask); uint16_t r = val & mask; + + HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); if (r == 0 || mask == 0) { return 0; } else if (r == mask) { @@ -1862,10 +1914,12 @@ static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t } /* set condition code for test under mask */ -static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint32_t mask) +static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, + uint32_t mask) { uint16_t r = val & mask; - HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r); + + HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); if (r == 0 || mask == 0) { return 0; } else if (r == mask) { @@ -1888,8 +1942,8 @@ static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) return !!dst; } -static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2, - int64_t ar) +static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, + int64_t a2, int64_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -1904,8 +1958,8 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2 } } -static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t a2, - uint64_t ar) +static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) { if (ar == 0) { if (a1) { @@ -1915,15 +1969,15 @@ static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t } } else { if (ar < a1 || ar < a2) { - return 3; + return 3; } else { - return 1; + return 1; } } } -static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2, - int64_t ar) +static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, + int64_t a2, int64_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -1938,8 +1992,8 @@ static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2 } } -static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, uint64_t a2, - uint64_t ar) +static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) { if (ar == 0) { return 2; @@ -1982,8 +2036,8 @@ static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) } -static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2, - int32_t ar) +static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, + int32_t a2, int32_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -1998,26 +2052,26 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2 } } -static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, uint32_t a2, - uint32_t ar) +static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) { if (ar == 0) { if (a1) { - return 2; + return 2; } else { - return 0; + return 0; } } else { if (ar < a1 || ar < a2) { - return 3; + return 3; } else { - return 1; + return 1; } } } -static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2, - int32_t ar) +static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, + int32_t a2, int32_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -2032,8 +2086,8 @@ static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2 } } -static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, uint32_t a2, - uint32_t ar) +static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) { if (ar == 0) { return 2; @@ -2076,11 +2130,12 @@ static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) } /* calculate condition code for insert character under mask insn */ -static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_t val) +static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, + uint32_t val) { - HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val); uint32_t cc; + HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); if (mask == 0xf) { if (!val) { return 0; @@ -2107,7 +2162,8 @@ static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_ return cc; } -static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t shift) +static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, + uint64_t shift) { uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); uint64_t match, r; @@ -2136,8 +2192,8 @@ static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t s } -static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, - uint64_t dst, uint64_t vr) +static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, + uint64_t src, uint64_t dst, uint64_t vr) { uint32_t r = 0; @@ -2244,7 +2300,7 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t s cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); } - HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__, + HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, cc_name(cc_op), src, dst, vr, r); return r; } @@ -2334,6 +2390,7 @@ void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) for (i = 0; i <= len; i++) { uint8_t byte = ldub(array + i); uint8_t new_byte = ldub(trans + byte); + stb(array + i, new_byte); } } @@ -2363,7 +2420,7 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) } /* - * ret < 0 indicates program check, ret = 0,1,2,3 -> cc + * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc */ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) { @@ -2382,24 +2439,24 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) return -PGM_SPECIFICATION; } - switch(code) { - case SCLP_CMDW_READ_SCP_INFO: - case SCLP_CMDW_READ_SCP_INFO_FORCED: - while ((ram_size >> (20 + shift)) > 65535) { - shift++; - } - stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); - stb_phys(sccb + SCP_INCREMENT, 1 << shift); - stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); + switch (code) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + while ((ram_size >> (20 + shift)) > 65535) { + shift++; + } + stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); + stb_phys(sccb + SCP_INCREMENT, 1 << shift); + stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); - s390_sclp_extint(sccb & ~3); - break; - default: + s390_sclp_extint(sccb & ~3); + break; + default: #ifdef DEBUG_HELPER - printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); + printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); #endif - r = 3; - break; + r = 3; + break; } return r; @@ -2479,7 +2536,7 @@ static inline uint64_t clock_value(CPUS390XState *env) uint64_t time; time = env->tod_offset + - time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); + time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); return time; } @@ -2503,7 +2560,6 @@ uint32_t HELPER(stcke)(uint64_t a1) /* XXX programmable fields */ stw(a1 + 17, 0); - return 0; } @@ -2584,7 +2640,7 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) ebcdic_put(sysib.model, "QEMU ", 16); ebcdic_put(sysib.sequence, "QEMU ", 16); ebcdic_put(sysib.plant, "QEMU", 4); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); } else if ((sel1 == 2) && (sel2 == 1)) { /* Basic Machine CPU */ struct sysib_121 sysib; @@ -2594,7 +2650,7 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ebcdic_put(sysib.plant, "QEMU", 4); stw_p(&sysib.cpu_addr, env->cpu_num); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); } else if ((sel1 == 2) && (sel2 == 2)) { /* Basic Machine CPUs */ struct sysib_122 sysib; @@ -2606,68 +2662,68 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) stw_p(&sysib.active_cpus, 1); stw_p(&sysib.standby_cpus, 0); stw_p(&sysib.reserved_cpus, 0); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); } else { cc = 3; } break; case STSI_LEVEL_2: - { - if ((sel1 == 2) && (sel2 == 1)) { - /* LPAR CPU */ - struct sysib_221 sysib; - - memset(&sysib, 0, sizeof(sysib)); - /* XXX make different for different CPUs? */ - ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); - stw_p(&sysib.cpu_id, 0); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 2)) { - /* LPAR CPUs */ - struct sysib_222 sysib; - - memset(&sysib, 0, sizeof(sysib)); - stw_p(&sysib.lpar_num, 0); - sysib.lcpuc = 0; - /* XXX change when SMP comes */ - stw_p(&sysib.total_cpus, 1); - stw_p(&sysib.conf_cpus, 1); - stw_p(&sysib.standby_cpus, 0); - stw_p(&sysib.reserved_cpus, 0); - ebcdic_put(sysib.name, "QEMU ", 8); - stl_p(&sysib.caf, 1000); - stw_p(&sysib.dedicated_cpus, 0); - stw_p(&sysib.shared_cpus, 0); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else { - cc = 3; + { + if ((sel1 == 2) && (sel2 == 1)) { + /* LPAR CPU */ + struct sysib_221 sysib; + + memset(&sysib, 0, sizeof(sysib)); + /* XXX make different for different CPUs? */ + ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_id, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 2)) { + /* LPAR CPUs */ + struct sysib_222 sysib; + + memset(&sysib, 0, sizeof(sysib)); + stw_p(&sysib.lpar_num, 0); + sysib.lcpuc = 0; + /* XXX change when SMP comes */ + stw_p(&sysib.total_cpus, 1); + stw_p(&sysib.conf_cpus, 1); + stw_p(&sysib.standby_cpus, 0); + stw_p(&sysib.reserved_cpus, 0); + ebcdic_put(sysib.name, "QEMU ", 8); + stl_p(&sysib.caf, 1000); + stw_p(&sysib.dedicated_cpus, 0); + stw_p(&sysib.shared_cpus, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; } - break; - } case STSI_LEVEL_3: - { - if ((sel1 == 2) && (sel2 == 2)) { - /* VM CPUs */ - struct sysib_322 sysib; - - memset(&sysib, 0, sizeof(sysib)); - sysib.count = 1; - /* XXX change when SMP comes */ - stw_p(&sysib.vm[0].total_cpus, 1); - stw_p(&sysib.vm[0].conf_cpus, 1); - stw_p(&sysib.vm[0].standby_cpus, 0); - stw_p(&sysib.vm[0].reserved_cpus, 0); - ebcdic_put(sysib.vm[0].name, "KVMguest", 8); - stl_p(&sysib.vm[0].caf, 1000); - ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else { - cc = 3; + { + if ((sel1 == 2) && (sel2 == 2)) { + /* VM CPUs */ + struct sysib_322 sysib; + + memset(&sysib, 0, sizeof(sysib)); + sysib.count = 1; + /* XXX change when SMP comes */ + stw_p(&sysib.vm[0].total_cpus, 1); + stw_p(&sysib.vm[0].conf_cpus, 1); + stw_p(&sysib.vm[0].standby_cpus, 0); + stw_p(&sysib.vm[0].reserved_cpus, 0); + ebcdic_put(sysib.vm[0].name, "KVMguest", 8); + stl_p(&sysib.vm[0].caf, 1000); + ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; } - break; - } case STSI_LEVEL_CURRENT: env->regs[0] = STSI_LEVEL_3; break; @@ -2781,6 +2837,7 @@ uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) { uint8_t re; uint8_t key; + if (r2 > ram_size) { return 0; } @@ -2865,7 +2922,7 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) { HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __FUNCTION__, l, a1, a2); + __func__, l, a1, a2); return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); } @@ -2873,7 +2930,7 @@ uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) { HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __FUNCTION__, l, a1, a2); + __func__, l, a1, a2); return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); } @@ -2883,9 +2940,9 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) int cc = 0; HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", - __FUNCTION__, order_code, r1, cpu_addr); + __func__, order_code, r1, cpu_addr); - /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register" + /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" as parameter (input). Status (output) is always R1. */ switch (order_code) { @@ -2901,7 +2958,7 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) env->regs[r1] &= 0xffffffff00000000ULL; cc = 1; break; -#if !defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) case SIGP_RESTART: qemu_system_reset_request(); cpu_loop_exit(env); @@ -2922,7 +2979,7 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) void HELPER(sacf)(uint64_t a1) { - HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1); + HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); switch (a1 & 0xf00) { case 0x000: @@ -2953,13 +3010,13 @@ void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) /* XXX broadcast to other CPUs */ /* XXX Linux is nice enough to give us the exact pte address. - According to spec we'd have to find it out ourselves */ + According to spec we'd have to find it out ourselves */ /* XXX Linux is fine with overwriting the pte, the spec requires - us to only set the invalid bit */ + us to only set the invalid bit */ stq_phys(pte_addr, pte | _PAGE_INVALID); /* XXX we exploit the fact that Linux passes the exact virtual - address here - it's not obliged to! */ + address here - it's not obliged to! */ tlb_flush_page(env, page); /* XXX 31-bit hack */ @@ -3008,7 +3065,8 @@ uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) env->exception_index = old_exc; if (!(env->psw.mask & PSW_MASK_64)) { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + (ret & 0xffffffffULL); } else { env->regs[r1] = ret; } -- cgit v1.2.3 From e72ca652aa08e3d07c59349f239ba596f27c97af Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:31 +0000 Subject: target-s390x: split FPU ops Move floating point instructions to fpu_helper.c. While exporting some condition code helpers, avoid duplicate identifier conflict with translate.c. Remove unused set_cc_nz_f64() in translate.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 2 + target-s390x/cpu.h | 6 + target-s390x/fpu_helper.c | 836 +++++++++++++++++++++++++++++++++++++++++++++ target-s390x/op_helper.c | 802 ------------------------------------------- target-s390x/translate.c | 11 +- 5 files changed, 847 insertions(+), 810 deletions(-) create mode 100644 target-s390x/fpu_helper.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 80be3bbdb..23b3bd998 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,5 +1,7 @@ obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o +obj-y += fpu_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 18ac6e393..b4620c502 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -999,4 +999,10 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) env->psw.addr = tb->pc; } +/* fpu_helper.c */ +uint32_t set_cc_f32(float32 v1, float32 v2); +uint32_t set_cc_f64(float64 v1, float64 v2); +uint32_t set_cc_nz_f32(float32 v); +uint32_t set_cc_nz_f64(float64 v); + #endif diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c new file mode 100644 index 000000000..1389052f5 --- /dev/null +++ b/target-s390x/fpu_helper.c @@ -0,0 +1,836 @@ +/* + * S/390 FPU helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +static inline int float_comp_to_cc(int float_compare) +{ + switch (float_compare) { + case float_relation_equal: + return 0; + case float_relation_less: + return 1; + case float_relation_greater: + return 2; + case float_relation_unordered: + return 3; + default: + cpu_abort(env, "unknown return value for float compare\n"); + } +} + +/* condition codes for binary FP ops */ +uint32_t set_cc_f32(float32 v1, float32 v2) +{ + return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); +} + +uint32_t set_cc_f64(float64 v1, float64 v2) +{ + return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); +} + +/* condition codes for unary FP ops */ +uint32_t set_cc_nz_f32(float32 v) +{ + if (float32_is_any_nan(v)) { + return 3; + } else if (float32_is_zero(v)) { + return 0; + } else if (float32_is_neg(v)) { + return 1; + } else { + return 2; + } +} + +uint32_t set_cc_nz_f64(float64 v) +{ + if (float64_is_any_nan(v)) { + return 3; + } else if (float64_is_zero(v)) { + return 0; + } else if (float64_is_neg(v)) { + return 1; + } else { + return 2; + } +} + +static uint32_t set_cc_nz_f128(float128 v) +{ + if (float128_is_any_nan(v)) { + return 3; + } else if (float128_is_zero(v)) { + return 0; + } else if (float128_is_neg(v)) { + return 1; + } else { + return 2; + } +} + +/* convert 32-bit int to 64-bit float */ +void HELPER(cdfbr)(uint32_t f1, int32_t v2) +{ + HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); +} + +/* convert 32-bit int to 128-bit float */ +void HELPER(cxfbr)(uint32_t f1, int32_t v2) +{ + CPU_QuadU v1; + + v1.q = int32_to_float128(v2, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; +} + +/* convert 64-bit int to 32-bit float */ +void HELPER(cegbr)(uint32_t f1, int64_t v2) +{ + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); +} + +/* convert 64-bit int to 64-bit float */ +void HELPER(cdgbr)(uint32_t f1, int64_t v2) +{ + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); +} + +/* convert 64-bit int to 128-bit float */ +void HELPER(cxgbr)(uint32_t f1, int64_t v2) +{ + CPU_QuadU x1; + + x1.q = int64_to_float128(v2, &env->fpu_status); + HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, + x1.ll.upper, x1.ll.lower); + env->fregs[f1].ll = x1.ll.upper; + env->fregs[f1 + 2].ll = x1.ll.lower; +} + +/* convert 32-bit int to 32-bit float */ +void HELPER(cefbr)(uint32_t f1, int32_t v2) +{ + env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); + HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, + env->fregs[f1].l.upper, f1); +} + +/* 32-bit FP addition RR */ +uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, + env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* 64-bit FP addition RR */ +uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, + env->fregs[f2].d, env->fregs[f1].d, f1); + + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* 32-bit FP subtraction RR */ +uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, + env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* 64-bit FP subtraction RR */ +uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", + __func__, env->fregs[f2].d, env->fregs[f1].d, f1); + + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* 32-bit FP division RR */ +void HELPER(debr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); +} + +/* 128-bit FP division RR */ +void HELPER(dxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_div(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +} + +/* 64-bit FP multiplication RR */ +void HELPER(mdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +} + +/* 128-bit FP multiplication RR */ +void HELPER(mxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_mul(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +} + +/* convert 32-bit float to 64-bit float */ +void HELPER(ldebr)(uint32_t r1, uint32_t r2) +{ + env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, + &env->fpu_status); +} + +/* convert 128-bit float to 64-bit float */ +void HELPER(ldxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU x2; + + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); + HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); +} + +/* convert 64-bit float to 128-bit float */ +void HELPER(lxdbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU res; + + res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +} + +/* convert 64-bit float to 32-bit float */ +void HELPER(ledbr)(uint32_t f1, uint32_t f2) +{ + float64 d2 = env->fregs[f2].d; + + env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); +} + +/* convert 128-bit float to 32-bit float */ +void HELPER(lexbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU x2; + + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); + HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); +} + +/* absolute value of 32-bit float */ +uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) +{ + float32 v1; + float32 v2 = env->fregs[f2].d; + + v1 = float32_abs(v2); + env->fregs[f1].d = v1; + return set_cc_nz_f32(v1); +} + +/* absolute value of 64-bit float */ +uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) +{ + float64 v1; + float64 v2 = env->fregs[f2].d; + + v1 = float64_abs(v2); + env->fregs[f1].d = v1; + return set_cc_nz_f64(v1); +} + +/* absolute value of 128-bit float */ +uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + v1.q = float128_abs(v2.q); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; + return set_cc_nz_f128(v1.q); +} + +/* load and test 64-bit float */ +uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = env->fregs[f2].d; + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* load and test 32-bit float */ +uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = env->fregs[f2].l.upper; + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* load and test 128-bit float */ +uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU x; + + x.ll.upper = env->fregs[f2].ll; + x.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].ll = x.ll.upper; + env->fregs[f1 + 2].ll = x.ll.lower; + return set_cc_nz_f128(x.q); +} + +/* load complement of 32-bit float */ +uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* load complement of 64-bit float */ +uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_chs(env->fregs[f2].d); + + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* load complement of 128-bit float */ +uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU x1, x2; + + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + x1.q = float128_chs(x2.q); + env->fregs[f1].ll = x1.ll.upper; + env->fregs[f1 + 2].ll = x1.ll.lower; + return set_cc_nz_f128(x1.q); +} + +/* 32-bit FP addition RM */ +void HELPER(aeb)(uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); +} + +/* 32-bit FP division RM */ +void HELPER(deb)(uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); +} + +/* 32-bit FP multiplication RM */ +void HELPER(meeb)(uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); +} + +/* 32-bit FP compare RR */ +uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) +{ + float32 v1 = env->fregs[f1].l.upper; + float32 v2 = env->fregs[f2].l.upper; + + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2); + return set_cc_f32(v1, v2); +} + +/* 64-bit FP compare RR */ +uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) +{ + float64 v1 = env->fregs[f1].d; + float64 v2 = env->fregs[f2].d; + + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, + v1, f1, v2); + return set_cc_f64(v1, v2); +} + +/* 128-bit FP compare RR */ +uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + + return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, + &env->fpu_status)); +} + +/* 64-bit FP compare RM */ +uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = ldq(a2); + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, + f1, v2.d); + return set_cc_f64(v1, v2.d); +} + +/* 64-bit FP addition RM */ +uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = ldq(a2); + HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +} + +/* 32-bit FP subtraction RM */ +void HELPER(seb)(uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); +} + +/* 64-bit FP subtraction RM */ +uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = ldq(a2); + env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +} + +/* 64-bit FP multiplication RM */ +void HELPER(mdb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = ldq(a2); + HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); +} + +/* 64-bit FP division RM */ +void HELPER(ddb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = ldq(a2); + HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); +} + +static void set_round_mode(int m3) +{ + switch (m3) { + case 0: + /* current mode */ + break; + case 1: + /* biased round no nearest */ + case 4: + /* round to nearest */ + set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); + break; + case 5: + /* round to zero */ + set_float_rounding_mode(float_round_to_zero, &env->fpu_status); + break; + case 6: + /* round to +inf */ + set_float_rounding_mode(float_round_up, &env->fpu_status); + break; + case 7: + /* round to -inf */ + set_float_rounding_mode(float_round_down, &env->fpu_status); + break; + } +} + +/* convert 32-bit float to 64-bit int */ +uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float32 v2 = env->fregs[f2].l.upper; + + set_round_mode(m3); + env->regs[r1] = float32_to_int64(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +} + +/* convert 64-bit float to 64-bit int */ +uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float64 v2 = env->fregs[f2].d; + + set_round_mode(m3); + env->regs[r1] = float64_to_int64(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +} + +/* convert 128-bit float to 64-bit int */ +uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + set_round_mode(m3); + env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); + if (float128_is_any_nan(v2.q)) { + return 3; + } else if (float128_is_zero(v2.q)) { + return 0; + } else if (float128_is_neg(v2.q)) { + return 1; + } else { + return 2; + } +} + +/* convert 32-bit float to 32-bit int */ +uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float32 v2 = env->fregs[f2].l.upper; + + set_round_mode(m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float32_to_int32(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +} + +/* convert 64-bit float to 32-bit int */ +uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float64 v2 = env->fregs[f2].d; + + set_round_mode(m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float64_to_int32(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +} + +/* convert 128-bit float to 32-bit int */ +uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float128_to_int32(v2.q, &env->fpu_status); + return set_cc_nz_f128(v2.q); +} + +/* load 32-bit FP zero */ +void HELPER(lzer)(uint32_t f1) +{ + env->fregs[f1].l.upper = float32_zero; +} + +/* load 64-bit FP zero */ +void HELPER(lzdr)(uint32_t f1) +{ + env->fregs[f1].d = float64_zero; +} + +/* load 128-bit FP zero */ +void HELPER(lzxr)(uint32_t f1) +{ + CPU_QuadU x; + + x.q = float64_to_float128(float64_zero, &env->fpu_status); + env->fregs[f1].ll = x.ll.upper; + env->fregs[f1 + 1].ll = x.ll.lower; +} + +/* 128-bit FP subtraction RR */ +uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_sub(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; + return set_cc_nz_f128(res.q); +} + +/* 128-bit FP addition RR */ +uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_add(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; + return set_cc_nz_f128(res.q); +} + +/* 32-bit FP multiplication RR */ +void HELPER(meebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); +} + +/* 64-bit FP division RR */ +void HELPER(ddbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +} + +/* 64-bit FP multiply and add RM */ +void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) +{ + CPU_DoubleU v2; + + HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); + v2.ll = ldq(a2); + env->fregs[f1].d = float64_add(env->fregs[f1].d, + float64_mul(v2.d, env->fregs[f3].d, + &env->fpu_status), + &env->fpu_status); +} + +/* 64-bit FP multiply and add RR */ +void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) +{ + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, + env->fregs[f3].d, + &env->fpu_status), + env->fregs[f1].d, &env->fpu_status); +} + +/* 64-bit FP multiply and subtract RR */ +void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) +{ + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, + env->fregs[f3].d, + &env->fpu_status), + env->fregs[f1].d, &env->fpu_status); +} + +/* 32-bit FP multiply and add RR */ +void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + float32_mul(env->fregs[f2].l.upper, + env->fregs[f3].l.upper, + &env->fpu_status), + &env->fpu_status); +} + +/* convert 32-bit float to 64-bit float */ +void HELPER(ldeb)(uint32_t f1, uint64_t a2) +{ + uint32_t v2; + + v2 = ldl(a2); + env->fregs[f1].d = float32_to_float64(v2, + &env->fpu_status); +} + +/* convert 64-bit float to 128-bit float */ +void HELPER(lxdb)(uint32_t f1, uint64_t a2) +{ + CPU_DoubleU v2; + CPU_QuadU v1; + + v2.ll = ldq(a2); + v1.q = float64_to_float128(v2.d, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; +} + +/* test data class 32-bit */ +uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) +{ + float32 v1 = env->fregs[f1].l.upper; + int neg = float32_is_neg(v1); + uint32_t cc = 0; + + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); + if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { + cc = 1; + } else if (m2 & (1 << (9-neg))) { + /* assume normalized number */ + cc = 1; + } + + /* FIXME: denormalized? */ + return cc; +} + +/* test data class 64-bit */ +uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) +{ + float64 v1 = env->fregs[f1].d; + int neg = float64_is_neg(v1); + uint32_t cc = 0; + + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); + if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { + cc = 1; + } else if (m2 & (1 << (9-neg))) { + /* assume normalized number */ + cc = 1; + } + /* FIXME: denormalized? */ + return cc; +} + +/* test data class 128-bit */ +uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) +{ + CPU_QuadU v1; + uint32_t cc = 0; + int neg; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + + neg = float128_is_neg(v1.q); + if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || + (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || + (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || + (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { + cc = 1; + } else if (m2 & (1 << (9-neg))) { + /* assume normalized number */ + cc = 1; + } + /* FIXME: denormalized? */ + return cc; +} + +/* square root 64-bit RR */ +void HELPER(sqdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); +} diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 195e93ed5..270bf14f0 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -977,802 +977,6 @@ uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) } } -static inline int float_comp_to_cc(int float_compare) -{ - switch (float_compare) { - case float_relation_equal: - return 0; - case float_relation_less: - return 1; - case float_relation_greater: - return 2; - case float_relation_unordered: - return 3; - default: - cpu_abort(env, "unknown return value for float compare\n"); - } -} - -/* condition codes for binary FP ops */ -static uint32_t set_cc_f32(float32 v1, float32 v2) -{ - return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); -} - -static uint32_t set_cc_f64(float64 v1, float64 v2) -{ - return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); -} - -/* condition codes for unary FP ops */ -static uint32_t set_cc_nz_f32(float32 v) -{ - if (float32_is_any_nan(v)) { - return 3; - } else if (float32_is_zero(v)) { - return 0; - } else if (float32_is_neg(v)) { - return 1; - } else { - return 2; - } -} - -static uint32_t set_cc_nz_f64(float64 v) -{ - if (float64_is_any_nan(v)) { - return 3; - } else if (float64_is_zero(v)) { - return 0; - } else if (float64_is_neg(v)) { - return 1; - } else { - return 2; - } -} - -static uint32_t set_cc_nz_f128(float128 v) -{ - if (float128_is_any_nan(v)) { - return 3; - } else if (float128_is_zero(v)) { - return 0; - } else if (float128_is_neg(v)) { - return 1; - } else { - return 2; - } -} - -/* convert 32-bit int to 64-bit float */ -void HELPER(cdfbr)(uint32_t f1, int32_t v2) -{ - HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); -} - -/* convert 32-bit int to 128-bit float */ -void HELPER(cxfbr)(uint32_t f1, int32_t v2) -{ - CPU_QuadU v1; - - v1.q = int32_to_float128(v2, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - -/* convert 64-bit int to 32-bit float */ -void HELPER(cegbr)(uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); -} - -/* convert 64-bit int to 64-bit float */ -void HELPER(cdgbr)(uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); -} - -/* convert 64-bit int to 128-bit float */ -void HELPER(cxgbr)(uint32_t f1, int64_t v2) -{ - CPU_QuadU x1; - - x1.q = int64_to_float128(v2, &env->fpu_status); - HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, - x1.ll.upper, x1.ll.lower); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; -} - -/* convert 32-bit int to 32-bit float */ -void HELPER(cefbr)(uint32_t f1, int32_t v2) -{ - env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); - HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, - env->fregs[f1].l.upper, f1); -} - -/* 32-bit FP addition RR */ -uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* 64-bit FP addition RR */ -uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, - env->fregs[f2].d, env->fregs[f1].d, f1); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* 32-bit FP subtraction RR */ -uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* 64-bit FP subtraction RR */ -uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", - __func__, env->fregs[f2].d, env->fregs[f1].d, f1); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* 32-bit FP division RR */ -void HELPER(debr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); -} - -/* 128-bit FP division RR */ -void HELPER(dxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_div(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* 64-bit FP multiplication RR */ -void HELPER(mdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); -} - -/* 128-bit FP multiplication RR */ -void HELPER(mxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_mul(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* convert 32-bit float to 64-bit float */ -void HELPER(ldebr)(uint32_t r1, uint32_t r2) -{ - env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, - &env->fpu_status); -} - -/* convert 128-bit float to 64-bit float */ -void HELPER(ldxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); -} - -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU res; - - res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* convert 64-bit float to 32-bit float */ -void HELPER(ledbr)(uint32_t f1, uint32_t f2) -{ - float64 d2 = env->fregs[f2].d; - - env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); -} - -/* convert 128-bit float to 32-bit float */ -void HELPER(lexbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); -} - -/* absolute value of 32-bit float */ -uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) -{ - float32 v1; - float32 v2 = env->fregs[f2].d; - - v1 = float32_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f32(v1); -} - -/* absolute value of 64-bit float */ -uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) -{ - float64 v1; - float64 v2 = env->fregs[f2].d; - - v1 = float64_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f64(v1); -} - -/* absolute value of 128-bit float */ -uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - v1.q = float128_abs(v2.q); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; - return set_cc_nz_f128(v1.q); -} - -/* load and test 64-bit float */ -uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = env->fregs[f2].d; - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load and test 32-bit float */ -uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = env->fregs[f2].l.upper; - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load and test 128-bit float */ -uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x; - - x.ll.upper = env->fregs[f2].ll; - x.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 2].ll = x.ll.lower; - return set_cc_nz_f128(x.q); -} - -/* load complement of 32-bit float */ -uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load complement of 64-bit float */ -uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_chs(env->fregs[f2].d); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load complement of 128-bit float */ -uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x1, x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - x1.q = float128_chs(x2.q); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; - return set_cc_nz_f128(x1.q); -} - -/* 32-bit FP addition RM */ -void HELPER(aeb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP division RM */ -void HELPER(deb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP multiplication RM */ -void HELPER(meeb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP compare RR */ -uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) -{ - float32 v1 = env->fregs[f1].l.upper; - float32 v2 = env->fregs[f2].l.upper; - - HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2); - return set_cc_f32(v1, v2); -} - -/* 64-bit FP compare RR */ -uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) -{ - float64 v1 = env->fregs[f1].d; - float64 v2 = env->fregs[f2].d; - - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, - v1, f1, v2); - return set_cc_f64(v1, v2); -} - -/* 128-bit FP compare RR */ -uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - - return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, - &env->fpu_status)); -} - -/* 64-bit FP compare RM */ -uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = ldq(a2); - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, - f1, v2.d); - return set_cc_f64(v1, v2.d); -} - -/* 64-bit FP addition RM */ -uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = ldq(a2); - HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); -} - -/* 32-bit FP subtraction RM */ -void HELPER(seb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); -} - -/* 64-bit FP subtraction RM */ -uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = ldq(a2); - env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); -} - -/* 64-bit FP multiplication RM */ -void HELPER(mdb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = ldq(a2); - HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); -} - -/* 64-bit FP division RM */ -void HELPER(ddb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = ldq(a2); - HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); -} - -static void set_round_mode(int m3) -{ - switch (m3) { - case 0: - /* current mode */ - break; - case 1: - /* biased round no nearest */ - case 4: - /* round to nearest */ - set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); - break; - case 5: - /* round to zero */ - set_float_rounding_mode(float_round_to_zero, &env->fpu_status); - break; - case 6: - /* round to +inf */ - set_float_rounding_mode(float_round_up, &env->fpu_status); - break; - case 7: - /* round to -inf */ - set_float_rounding_mode(float_round_down, &env->fpu_status); - break; - } -} - -/* convert 32-bit float to 64-bit int */ -uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(m3); - env->regs[r1] = float32_to_int64(v2, &env->fpu_status); - return set_cc_nz_f32(v2); -} - -/* convert 64-bit float to 64-bit int */ -uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float64 v2 = env->fregs[f2].d; - - set_round_mode(m3); - env->regs[r1] = float64_to_int64(v2, &env->fpu_status); - return set_cc_nz_f64(v2); -} - -/* convert 128-bit float to 64-bit int */ -uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - set_round_mode(m3); - env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); - if (float128_is_any_nan(v2.q)) { - return 3; - } else if (float128_is_zero(v2.q)) { - return 0; - } else if (float128_is_neg(v2.q)) { - return 1; - } else { - return 2; - } -} - -/* convert 32-bit float to 32-bit int */ -uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float32_to_int32(v2, &env->fpu_status); - return set_cc_nz_f32(v2); -} - -/* convert 64-bit float to 32-bit int */ -uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float64 v2 = env->fregs[f2].d; - - set_round_mode(m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float64_to_int32(v2, &env->fpu_status); - return set_cc_nz_f64(v2); -} - -/* convert 128-bit float to 32-bit int */ -uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float128_to_int32(v2.q, &env->fpu_status); - return set_cc_nz_f128(v2.q); -} - -/* load 32-bit FP zero */ -void HELPER(lzer)(uint32_t f1) -{ - env->fregs[f1].l.upper = float32_zero; -} - -/* load 64-bit FP zero */ -void HELPER(lzdr)(uint32_t f1) -{ - env->fregs[f1].d = float64_zero; -} - -/* load 128-bit FP zero */ -void HELPER(lzxr)(uint32_t f1) -{ - CPU_QuadU x; - - x.q = float64_to_float128(float64_zero, &env->fpu_status); - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 1].ll = x.ll.lower; -} - -/* 128-bit FP subtraction RR */ -uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_sub(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - -/* 128-bit FP addition RR */ -uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_add(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - -/* 32-bit FP multiplication RR */ -void HELPER(meebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); -} - -/* 64-bit FP division RR */ -void HELPER(ddbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); -} - -/* 64-bit FP multiply and add RM */ -void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) -{ - CPU_DoubleU v2; - - HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); - v2.ll = ldq(a2); - env->fregs[f1].d = float64_add(env->fregs[f1].d, - float64_mul(v2.d, env->fregs[f3].d, - &env->fpu_status), - &env->fpu_status); -} - -/* 64-bit FP multiply and add RR */ -void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) -{ - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); -} - -/* 64-bit FP multiply and subtract RR */ -void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) -{ - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); -} - -/* 32-bit FP multiply and add RR */ -void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - float32_mul(env->fregs[f2].l.upper, - env->fregs[f3].l.upper, - &env->fpu_status), - &env->fpu_status); -} - -/* convert 32-bit float to 64-bit float */ -void HELPER(ldeb)(uint32_t f1, uint64_t a2) -{ - uint32_t v2; - - v2 = ldl(a2); - env->fregs[f1].d = float32_to_float64(v2, - &env->fpu_status); -} - -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdb)(uint32_t f1, uint64_t a2) -{ - CPU_DoubleU v2; - CPU_QuadU v1; - - v2.ll = ldq(a2); - v1.q = float64_to_float128(v2.d, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - -/* test data class 32-bit */ -uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) -{ - float32 v1 = env->fregs[f1].l.upper; - int neg = float32_is_neg(v1); - uint32_t cc = 0; - - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); - if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - - /* FIXME: denormalized? */ - return cc; -} - -/* test data class 64-bit */ -uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) -{ - float64 v1 = env->fregs[f1].d; - int neg = float64_is_neg(v1); - uint32_t cc = 0; - - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); - if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; -} - -/* test data class 128-bit */ -uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) -{ - CPU_QuadU v1; - uint32_t cc = 0; - int neg; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - - neg = float128_is_neg(v1.q); - if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || - (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || - (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || - (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; -} - /* find leftmost one */ uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) { @@ -1795,12 +999,6 @@ uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) } } -/* square root 64-bit RR */ -void HELPER(sqdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); -} - /* checksum */ void HELPER(cksm)(uint32_t r1, uint32_t r2) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1c1baf534..c370df3b6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -667,16 +667,11 @@ static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) s->cc_op = CC_OP_LTGT_F32; } -static void set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) +static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); } -static inline void set_cc_nz_f64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_NZ_F64, v1); -} - /* CC value is in env->cc_op */ static inline void set_cc_static(DisasContext *s) { @@ -2235,7 +2230,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tcg_temp_free_i32(tmp32); tmp32 = load_freg32(r1); - set_cc_nz_f32(s, tmp32); + gen_set_cc_nz_f32(s, tmp32); tcg_temp_free_i32(tmp32); break; case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ @@ -2248,7 +2243,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tcg_temp_free_i32(tmp32); tmp32 = load_freg32(r1); - set_cc_nz_f32(s, tmp32); + gen_set_cc_nz_f32(s, tmp32); tcg_temp_free_i32(tmp32); break; case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ -- cgit v1.2.3 From a78b0504e8d5487fca77b6b0cd8d3c98b9bace8c Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:32 +0000 Subject: target-s390x: split condition code helpers Move condition code helpers to cc_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 3 +- target-s390x/cc_helper.c | 551 +++++++++++++++++++++++++++++++++++++++++++++ target-s390x/cpu.h | 3 + target-s390x/op_helper.c | 522 +----------------------------------------- 4 files changed, 557 insertions(+), 522 deletions(-) create mode 100644 target-s390x/cc_helper.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 23b3bd998..f9437d615 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,7 +1,8 @@ obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o -obj-y += fpu_helper.o +obj-y += fpu_helper.o cc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c new file mode 100644 index 000000000..2ac165962 --- /dev/null +++ b/target-s390x/cc_helper.c @@ -0,0 +1,551 @@ +/* + * S/390 condition code helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, + int32_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) +{ + return cc_calc_ltgt_32(env, dst, 0); +} + +static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, + int64_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) +{ + return cc_calc_ltgt_64(env, dst, 0); +} + +static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, + uint32_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, + uint64_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, + uint32_t mask) +{ + uint16_t r = val & mask; + + HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); + if (r == 0 || mask == 0) { + return 0; + } else if (r == mask) { + return 3; + } else { + return 1; + } +} + +/* set condition code for test under mask */ +static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, + uint32_t mask) +{ + uint16_t r = val & mask; + + HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); + if (r == 0 || mask == 0) { + return 0; + } else if (r == mask) { + return 3; + } else { + while (!(mask & 0x8000)) { + mask <<= 1; + val <<= 1; + } + if (val & 0x8000) { + return 2; + } else { + return 1; + } + } +} + +static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) +{ + return !!dst; +} + +static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, + int64_t a2, int64_t ar) +{ + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + if (ar == 0) { + if (a1) { + return 2; + } else { + return 0; + } + } else { + if (ar < a1 || ar < a2) { + return 3; + } else { + return 1; + } + } +} + +static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, + int64_t a2, int64_t ar) +{ + if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + if (ar == 0) { + return 2; + } else { + if (a2 > a1) { + return 1; + } else { + return 3; + } + } +} + +static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) +{ + if ((uint64_t)dst == 0x8000000000000000ULL) { + return 3; + } else if (dst) { + return 1; + } else { + return 0; + } +} + +static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) +{ + return !!dst; +} + +static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) +{ + if ((uint64_t)dst == 0x8000000000000000ULL) { + return 3; + } else if (dst < 0) { + return 1; + } else if (dst > 0) { + return 2; + } else { + return 0; + } +} + + +static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, + int32_t a2, int32_t ar) +{ + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + if (ar == 0) { + if (a1) { + return 2; + } else { + return 0; + } + } else { + if (ar < a1 || ar < a2) { + return 3; + } else { + return 1; + } + } +} + +static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, + int32_t a2, int32_t ar) +{ + if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + if (ar == 0) { + return 2; + } else { + if (a2 > a1) { + return 1; + } else { + return 3; + } + } +} + +static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) +{ + if ((uint32_t)dst == 0x80000000UL) { + return 3; + } else if (dst) { + return 1; + } else { + return 0; + } +} + +static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) +{ + return !!dst; +} + +static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) +{ + if ((uint32_t)dst == 0x80000000UL) { + return 3; + } else if (dst < 0) { + return 1; + } else if (dst > 0) { + return 2; + } else { + return 0; + } +} + +/* calculate condition code for insert character under mask insn */ +static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, + uint32_t val) +{ + uint32_t cc; + + HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); + if (mask == 0xf) { + if (!val) { + return 0; + } else if (val & 0x80000000) { + return 1; + } else { + return 2; + } + } + + if (!val || !mask) { + cc = 0; + } else { + while (mask != 1) { + mask >>= 1; + val >>= 8; + } + if (val & 0x80) { + cc = 1; + } else { + cc = 2; + } + } + return cc; +} + +static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, + uint64_t shift) +{ + uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t match, r; + + /* check if the sign bit stays the same */ + if (src & (1ULL << 63)) { + match = mask; + } else { + match = 0; + } + + if ((src & mask) != match) { + /* overflow */ + return 3; + } + + r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); + + if ((int64_t)r == 0) { + return 0; + } else if ((int64_t)r < 0) { + return 1; + } + + return 2; +} + + +static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, + uint64_t src, uint64_t dst, uint64_t vr) +{ + uint32_t r = 0; + + switch (cc_op) { + case CC_OP_CONST0: + case CC_OP_CONST1: + case CC_OP_CONST2: + case CC_OP_CONST3: + /* cc_op value _is_ cc */ + r = cc_op; + break; + case CC_OP_LTGT0_32: + r = cc_calc_ltgt0_32(env, dst); + break; + case CC_OP_LTGT0_64: + r = cc_calc_ltgt0_64(env, dst); + break; + case CC_OP_LTGT_32: + r = cc_calc_ltgt_32(env, src, dst); + break; + case CC_OP_LTGT_64: + r = cc_calc_ltgt_64(env, src, dst); + break; + case CC_OP_LTUGTU_32: + r = cc_calc_ltugtu_32(env, src, dst); + break; + case CC_OP_LTUGTU_64: + r = cc_calc_ltugtu_64(env, src, dst); + break; + case CC_OP_TM_32: + r = cc_calc_tm_32(env, src, dst); + break; + case CC_OP_TM_64: + r = cc_calc_tm_64(env, src, dst); + break; + case CC_OP_NZ: + r = cc_calc_nz(env, dst); + break; + case CC_OP_ADD_64: + r = cc_calc_add_64(env, src, dst, vr); + break; + case CC_OP_ADDU_64: + r = cc_calc_addu_64(env, src, dst, vr); + break; + case CC_OP_SUB_64: + r = cc_calc_sub_64(env, src, dst, vr); + break; + case CC_OP_SUBU_64: + r = cc_calc_subu_64(env, src, dst, vr); + break; + case CC_OP_ABS_64: + r = cc_calc_abs_64(env, dst); + break; + case CC_OP_NABS_64: + r = cc_calc_nabs_64(env, dst); + break; + case CC_OP_COMP_64: + r = cc_calc_comp_64(env, dst); + break; + + case CC_OP_ADD_32: + r = cc_calc_add_32(env, src, dst, vr); + break; + case CC_OP_ADDU_32: + r = cc_calc_addu_32(env, src, dst, vr); + break; + case CC_OP_SUB_32: + r = cc_calc_sub_32(env, src, dst, vr); + break; + case CC_OP_SUBU_32: + r = cc_calc_subu_32(env, src, dst, vr); + break; + case CC_OP_ABS_32: + r = cc_calc_abs_64(env, dst); + break; + case CC_OP_NABS_32: + r = cc_calc_nabs_64(env, dst); + break; + case CC_OP_COMP_32: + r = cc_calc_comp_32(env, dst); + break; + + case CC_OP_ICM: + r = cc_calc_icm_32(env, src, dst); + break; + case CC_OP_SLAG: + r = cc_calc_slag(env, src, dst); + break; + + case CC_OP_LTGT_F32: + r = set_cc_f32(src, dst); + break; + case CC_OP_LTGT_F64: + r = set_cc_f64(src, dst); + break; + case CC_OP_NZ_F32: + r = set_cc_nz_f32(dst); + break; + case CC_OP_NZ_F64: + r = set_cc_nz_f64(dst); + break; + + default: + cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); + } + + HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, + cc_name(cc_op), src, dst, vr, r); + return r; +} + +uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, + uint64_t vr) +{ + return do_calc_cc(env, cc_op, src, dst, vr); +} + +uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, + uint64_t vr) +{ + return do_calc_cc(env, cc_op, src, dst, vr); +} + +/* insert psw mask and condition code into r1 */ +void HELPER(ipm)(uint32_t cc, uint32_t r1) +{ + uint64_t r = env->regs[r1]; + + r &= 0xffffffff00ffffffULL; + r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); + env->regs[r1] = r; + HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, + cc, env->psw.mask, r); +} + +#ifndef CONFIG_USER_ONLY +void HELPER(load_psw)(uint64_t mask, uint64_t addr) +{ + load_psw(env, mask, addr); + cpu_loop_exit(env); +} + +void HELPER(sacf)(uint64_t a1) +{ + HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); + + switch (a1 & 0xf00) { + case 0x000: + env->psw.mask &= ~PSW_MASK_ASC; + env->psw.mask |= PSW_ASC_PRIMARY; + break; + case 0x100: + env->psw.mask &= ~PSW_MASK_ASC; + env->psw.mask |= PSW_ASC_SECONDARY; + break; + case 0x300: + env->psw.mask &= ~PSW_MASK_ASC; + env->psw.mask |= PSW_ASC_HOME; + break; + default: + qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); + program_interrupt(env, PGM_SPECIFICATION, 2); + break; + } +} +#endif diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b4620c502..97fde5e2e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1005,4 +1005,7 @@ uint32_t set_cc_f64(float64 v1, float64 v2); uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); +/* op_helper.c */ +void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); + #endif diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 270bf14f0..eced89089 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -779,18 +779,6 @@ uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) return cc; } -/* insert psw mask and condition code into r1 */ -void HELPER(ipm)(uint32_t cc, uint32_t r1) -{ - uint64_t r = env->regs[r1]; - - r &= 0xffffffff00ffffffULL; - r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); - env->regs[r1] = r; - HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, - cc, env->psw.mask, r); -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) { @@ -1038,483 +1026,6 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) ((uint32_t)cksm + (cksm >> 32)); } -static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, - int32_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) -{ - return cc_calc_ltgt_32(env, dst, 0); -} - -static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, - int64_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) -{ - return cc_calc_ltgt_64(env, dst, 0); -} - -static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, - uint32_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, - uint64_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, - uint32_t mask) -{ - uint16_t r = val & mask; - - HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); - if (r == 0 || mask == 0) { - return 0; - } else if (r == mask) { - return 3; - } else { - return 1; - } -} - -/* set condition code for test under mask */ -static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, - uint32_t mask) -{ - uint16_t r = val & mask; - - HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); - if (r == 0 || mask == 0) { - return 0; - } else if (r == mask) { - return 3; - } else { - while (!(mask & 0x8000)) { - mask <<= 1; - val <<= 1; - } - if (val & 0x8000) { - return 2; - } else { - return 1; - } - } -} - -static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) -{ - return !!dst; -} - -static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) -{ - if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) -{ - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } -} - -static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) -{ - if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) -{ - if (ar == 0) { - return 2; - } else { - if (a2 > a1) { - return 1; - } else { - return 3; - } - } -} - -static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) -{ - if ((uint64_t)dst == 0x8000000000000000ULL) { - return 3; - } else if (dst) { - return 1; - } else { - return 0; - } -} - -static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) -{ - return !!dst; -} - -static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) -{ - if ((uint64_t)dst == 0x8000000000000000ULL) { - return 3; - } else if (dst < 0) { - return 1; - } else if (dst > 0) { - return 2; - } else { - return 0; - } -} - - -static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) -{ - if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) -{ - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } -} - -static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) -{ - if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) -{ - if (ar == 0) { - return 2; - } else { - if (a2 > a1) { - return 1; - } else { - return 3; - } - } -} - -static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) -{ - if ((uint32_t)dst == 0x80000000UL) { - return 3; - } else if (dst) { - return 1; - } else { - return 0; - } -} - -static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) -{ - return !!dst; -} - -static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) -{ - if ((uint32_t)dst == 0x80000000UL) { - return 3; - } else if (dst < 0) { - return 1; - } else if (dst > 0) { - return 2; - } else { - return 0; - } -} - -/* calculate condition code for insert character under mask insn */ -static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, - uint32_t val) -{ - uint32_t cc; - - HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); - if (mask == 0xf) { - if (!val) { - return 0; - } else if (val & 0x80000000) { - return 1; - } else { - return 2; - } - } - - if (!val || !mask) { - cc = 0; - } else { - while (mask != 1) { - mask >>= 1; - val >>= 8; - } - if (val & 0x80) { - cc = 1; - } else { - cc = 2; - } - } - return cc; -} - -static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, - uint64_t shift) -{ - uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); - uint64_t match, r; - - /* check if the sign bit stays the same */ - if (src & (1ULL << 63)) { - match = mask; - } else { - match = 0; - } - - if ((src & mask) != match) { - /* overflow */ - return 3; - } - - r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); - - if ((int64_t)r == 0) { - return 0; - } else if ((int64_t)r < 0) { - return 1; - } - - return 2; -} - - -static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, - uint64_t src, uint64_t dst, uint64_t vr) -{ - uint32_t r = 0; - - switch (cc_op) { - case CC_OP_CONST0: - case CC_OP_CONST1: - case CC_OP_CONST2: - case CC_OP_CONST3: - /* cc_op value _is_ cc */ - r = cc_op; - break; - case CC_OP_LTGT0_32: - r = cc_calc_ltgt0_32(env, dst); - break; - case CC_OP_LTGT0_64: - r = cc_calc_ltgt0_64(env, dst); - break; - case CC_OP_LTGT_32: - r = cc_calc_ltgt_32(env, src, dst); - break; - case CC_OP_LTGT_64: - r = cc_calc_ltgt_64(env, src, dst); - break; - case CC_OP_LTUGTU_32: - r = cc_calc_ltugtu_32(env, src, dst); - break; - case CC_OP_LTUGTU_64: - r = cc_calc_ltugtu_64(env, src, dst); - break; - case CC_OP_TM_32: - r = cc_calc_tm_32(env, src, dst); - break; - case CC_OP_TM_64: - r = cc_calc_tm_64(env, src, dst); - break; - case CC_OP_NZ: - r = cc_calc_nz(env, dst); - break; - case CC_OP_ADD_64: - r = cc_calc_add_64(env, src, dst, vr); - break; - case CC_OP_ADDU_64: - r = cc_calc_addu_64(env, src, dst, vr); - break; - case CC_OP_SUB_64: - r = cc_calc_sub_64(env, src, dst, vr); - break; - case CC_OP_SUBU_64: - r = cc_calc_subu_64(env, src, dst, vr); - break; - case CC_OP_ABS_64: - r = cc_calc_abs_64(env, dst); - break; - case CC_OP_NABS_64: - r = cc_calc_nabs_64(env, dst); - break; - case CC_OP_COMP_64: - r = cc_calc_comp_64(env, dst); - break; - - case CC_OP_ADD_32: - r = cc_calc_add_32(env, src, dst, vr); - break; - case CC_OP_ADDU_32: - r = cc_calc_addu_32(env, src, dst, vr); - break; - case CC_OP_SUB_32: - r = cc_calc_sub_32(env, src, dst, vr); - break; - case CC_OP_SUBU_32: - r = cc_calc_subu_32(env, src, dst, vr); - break; - case CC_OP_ABS_32: - r = cc_calc_abs_64(env, dst); - break; - case CC_OP_NABS_32: - r = cc_calc_nabs_64(env, dst); - break; - case CC_OP_COMP_32: - r = cc_calc_comp_32(env, dst); - break; - - case CC_OP_ICM: - r = cc_calc_icm_32(env, src, dst); - break; - case CC_OP_SLAG: - r = cc_calc_slag(env, src, dst); - break; - - case CC_OP_LTGT_F32: - r = set_cc_f32(src, dst); - break; - case CC_OP_LTGT_F64: - r = set_cc_f64(src, dst); - break; - case CC_OP_NZ_F32: - r = set_cc_nz_f32(dst); - break; - case CC_OP_NZ_F64: - r = set_cc_nz_f64(dst); - break; - - default: - cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); - } - - HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, - cc_name(cc_op), src, dst, vr, r); - return r; -} - -uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr) -{ - return do_calc_cc(env, cc_op, src, dst, vr); -} - -uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr) -{ - return do_calc_cc(env, cc_op, src, dst, vr); -} - uint64_t HELPER(cvd)(int32_t bin) { /* positive 0 */ @@ -1594,14 +1105,7 @@ void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) } #ifndef CONFIG_USER_ONLY - -void HELPER(load_psw)(uint64_t mask, uint64_t addr) -{ - load_psw(env, mask, addr); - cpu_loop_exit(env); -} - -static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) { qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); @@ -2175,30 +1679,6 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) return cc; } -void HELPER(sacf)(uint64_t a1) -{ - HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); - - switch (a1 & 0xf00) { - case 0x000: - env->psw.mask &= ~PSW_MASK_ASC; - env->psw.mask |= PSW_ASC_PRIMARY; - break; - case 0x100: - env->psw.mask &= ~PSW_MASK_ASC; - env->psw.mask |= PSW_ASC_SECONDARY; - break; - case 0x300: - env->psw.mask &= ~PSW_MASK_ASC; - env->psw.mask |= PSW_ASC_HOME; - break; - default: - qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); - program_interrupt(env, PGM_SPECIFICATION, 2); - break; - } -} - /* invalidate pte */ void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) { -- cgit v1.2.3 From fc8d72c2d34afd6789e8c4374d275a5f69c603f1 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:33 +0000 Subject: target-s390x: split integer helpers Move integer helpers to int_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 3 +- target-s390x/int_helper.c | 201 +++++++++++++++++++++++++++++++++++++++++++++ target-s390x/op_helper.c | 170 -------------------------------------- 3 files changed, 203 insertions(+), 171 deletions(-) create mode 100644 target-s390x/int_helper.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index f9437d615..e8f66e93a 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,8 +1,9 @@ obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o -obj-y += fpu_helper.o cc_helper.o +obj-y += int_helper.o fpu_helper.o cc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c new file mode 100644 index 000000000..e2eeb0757 --- /dev/null +++ b/target-s390x/int_helper.c @@ -0,0 +1,201 @@ +/* + * S/390 integer helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "cpu.h" +#include "dyngen-exec.h" +#include "host-utils.h" +#include "helper.h" + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +/* 64/64 -> 128 unsigned multiplication */ +void HELPER(mlg)(uint32_t r1, uint64_t v2) +{ +#if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ + __uint128_t res = (__uint128_t)env->regs[r1 + 1]; + + res *= (__uint128_t)v2; + env->regs[r1] = (uint64_t)(res >> 64); + env->regs[r1 + 1] = (uint64_t)res; +#else + mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); +#endif +} + +/* 128 -> 64/64 unsigned division */ +void HELPER(dlg)(uint32_t r1, uint64_t v2) +{ + uint64_t divisor = v2; + + if (!env->regs[r1]) { + /* 64 -> 64/64 case */ + env->regs[r1] = env->regs[r1 + 1] % divisor; + env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; + return; + } else { +#if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ + __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | + (env->regs[r1 + 1]); + __uint128_t quotient = dividend / divisor; + __uint128_t remainder = dividend % divisor; + + env->regs[r1 + 1] = quotient; + env->regs[r1] = remainder; +#else + /* 32-bit hosts would need special wrapper functionality - just abort if + we encounter such a case; it's very unlikely anyways. */ + cpu_abort(env, "128 -> 64/64 division not implemented\n"); +#endif + } +} + +/* absolute value 32-bit */ +uint32_t HELPER(abs_i32)(int32_t val) +{ + if (val < 0) { + return -val; + } else { + return val; + } +} + +/* negative absolute value 32-bit */ +int32_t HELPER(nabs_i32)(int32_t val) +{ + if (val < 0) { + return val; + } else { + return -val; + } +} + +/* absolute value 64-bit */ +uint64_t HELPER(abs_i64)(int64_t val) +{ + HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); + + if (val < 0) { + return -val; + } else { + return val; + } +} + +/* negative absolute value 64-bit */ +int64_t HELPER(nabs_i64)(int64_t val) +{ + if (val < 0) { + return val; + } else { + return -val; + } +} + +/* add with carry 32-bit unsigned */ +uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) +{ + uint32_t res; + + res = v1 + v2; + if (cc & 2) { + res++; + } + + return res; +} + +/* subtract unsigned v2 from v1 with borrow */ +uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) +{ + uint32_t v1 = env->regs[r1]; + uint32_t res = v1 + (~v2) + (cc >> 1); + + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; + if (cc & 2) { + /* borrow */ + return v1 ? 1 : 0; + } else { + return v1 ? 3 : 2; + } +} + +/* subtract unsigned v2 from v1 with borrow */ +uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) +{ + uint64_t res = v1 + (~v2) + (cc >> 1); + + env->regs[r1] = res; + if (cc & 2) { + /* borrow */ + return v1 ? 1 : 0; + } else { + return v1 ? 3 : 2; + } +} + +/* find leftmost one */ +uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) +{ + uint64_t res = 0; + uint64_t ov2 = v2; + + while (!(v2 & 0x8000000000000000ULL) && v2) { + v2 <<= 1; + res++; + } + + if (!v2) { + env->regs[r1] = 64; + env->regs[r1 + 1] = 0; + return 0; + } else { + env->regs[r1] = res; + env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); + return 2; + } +} + +uint64_t HELPER(cvd)(int32_t bin) +{ + /* positive 0 */ + uint64_t dec = 0x0c; + int shift = 4; + + if (bin < 0) { + bin = -bin; + dec = 0x0d; + } + + for (shift = 4; (shift < 64) && bin; shift += 4) { + int current_number = bin % 10; + + dec |= (current_number) << shift; + bin /= 10; + } + + return dec; +} diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index eced89089..3b8b997ab 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -352,49 +352,6 @@ void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) HELPER_LOG("\n"); } -/* 64/64 -> 128 unsigned multiplication */ -void HELPER(mlg)(uint32_t r1, uint64_t v2) -{ -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t res = (__uint128_t)env->regs[r1 + 1]; - - res *= (__uint128_t)v2; - env->regs[r1] = (uint64_t)(res >> 64); - env->regs[r1 + 1] = (uint64_t)res; -#else - mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); -#endif -} - -/* 128 -> 64/64 unsigned division */ -void HELPER(dlg)(uint32_t r1, uint64_t v2) -{ - uint64_t divisor = v2; - - if (!env->regs[r1]) { - /* 64 -> 64/64 case */ - env->regs[r1] = env->regs[r1 + 1] % divisor; - env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; - return; - } else { -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | - (env->regs[r1 + 1]); - __uint128_t quotient = dividend / divisor; - __uint128_t remainder = dividend % divisor; - - env->regs[r1 + 1] = quotient; - env->regs[r1] = remainder; -#else - /* 32-bit hosts would need special wrapper functionality - just abort if - we encounter such a case; it's very unlikely anyways. */ - cpu_abort(env, "128 -> 64/64 division not implemented\n"); -#endif - } -} - static inline uint64_t get_address(int x2, int b2, int d2) { uint64_t r = d2; @@ -677,61 +634,6 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) return cc; } -/* absolute value 32-bit */ -uint32_t HELPER(abs_i32)(int32_t val) -{ - if (val < 0) { - return -val; - } else { - return val; - } -} - -/* negative absolute value 32-bit */ -int32_t HELPER(nabs_i32)(int32_t val) -{ - if (val < 0) { - return val; - } else { - return -val; - } -} - -/* absolute value 64-bit */ -uint64_t HELPER(abs_i64)(int64_t val) -{ - HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); - - if (val < 0) { - return -val; - } else { - return val; - } -} - -/* negative absolute value 64-bit */ -int64_t HELPER(nabs_i64)(int64_t val) -{ - if (val < 0) { - return val; - } else { - return -val; - } -} - -/* add with carry 32-bit unsigned */ -uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) -{ - uint32_t res; - - res = v1 + v2; - if (cc & 2) { - res++; - } - - return res; -} - /* store character under mask high operates on the upper half of r1 */ void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) { @@ -936,57 +838,6 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) return cc; } -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) -{ - uint32_t v1 = env->regs[r1]; - uint32_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) -{ - uint64_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* find leftmost one */ -uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) -{ - uint64_t res = 0; - uint64_t ov2 = v2; - - while (!(v2 & 0x8000000000000000ULL) && v2) { - v2 <<= 1; - res++; - } - - if (!v2) { - env->regs[r1] = 64; - env->regs[r1 + 1] = 0; - return 0; - } else { - env->regs[r1] = res; - env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); - return 2; - } -} - /* checksum */ void HELPER(cksm)(uint32_t r1, uint32_t r2) { @@ -1026,27 +877,6 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) ((uint32_t)cksm + (cksm >> 32)); } -uint64_t HELPER(cvd)(int32_t bin) -{ - /* positive 0 */ - uint64_t dec = 0x0c; - int shift = 4; - - if (bin < 0) { - bin = -bin; - dec = 0x0d; - } - - for (shift = 4; (shift < 64) && bin; shift += 4) { - int current_number = bin % 10; - - dec |= (current_number) << shift; - bin /= 10; - } - - return dec; -} - void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) { int len_dest = len >> 4; -- cgit v1.2.3 From 8ef7f78e190b3a34e167a31c9a8e43c813c7ff78 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:34 +0000 Subject: target-s390x: split memory access helpers Move memory access helpers to mem_helper.c. Signed-off-by: Blue Swirl [agraf: fold softmmu include ifdefs together] Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 3 +- target-s390x/mem_helper.c | 1190 ++++++++++++++++++++++++++++++++++++++++++++ target-s390x/op_helper.c | 1159 +----------------------------------------- 3 files changed, 1193 insertions(+), 1159 deletions(-) create mode 100644 target-s390x/mem_helper.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index e8f66e93a..b9b306170 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,5 +1,5 @@ obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o -obj-y += int_helper.o fpu_helper.o cc_helper.o +obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o @@ -7,3 +7,4 @@ $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +$(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c new file mode 100644 index 000000000..ba05e65cd --- /dev/null +++ b/target-s390x/mem_helper.c @@ -0,0 +1,1190 @@ +/* + * S/390 memory access helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +/*****************************************************************************/ +/* Softmmu support */ +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) +{ + TranslationBlock *tb; + CPUS390XState *saved_env; + int ret; + + saved_env = env; + env = env1; + ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret != 0)) { + if (likely(retaddr)) { + /* now we have a real cpu fault */ + tb = tb_find_pc(retaddr); + if (likely(tb)) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, retaddr); + } + } + cpu_loop_exit(env); + } + env = saved_env; +} + +#endif + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +#ifndef CONFIG_USER_ONLY +static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, + uint8_t byte) +{ + target_phys_addr_t dest_phys; + target_phys_addr_t len = l; + void *dest_p; + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + int flags; + + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { + stb(dest, byte); + cpu_abort(env, "should never reach here"); + } + dest_phys |= dest & ~TARGET_PAGE_MASK; + + dest_p = cpu_physical_memory_map(dest_phys, &len, 1); + + memset(dest_p, byte, len); + + cpu_physical_memory_unmap(dest_p, 1, len, len); +} + +static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + target_phys_addr_t dest_phys; + target_phys_addr_t src_phys; + target_phys_addr_t len = l; + void *dest_p; + void *src_p; + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + int flags; + + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { + stb(dest, 0); + cpu_abort(env, "should never reach here"); + } + dest_phys |= dest & ~TARGET_PAGE_MASK; + + if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { + ldub(src); + cpu_abort(env, "should never reach here"); + } + src_phys |= src & ~TARGET_PAGE_MASK; + + dest_p = cpu_physical_memory_map(dest_phys, &len, 1); + src_p = cpu_physical_memory_map(src_phys, &len, 0); + + memmove(dest_p, src_p, len); + + cpu_physical_memory_unmap(dest_p, 1, len, len); + cpu_physical_memory_unmap(src_p, 0, len, len); +} +#endif + +/* and on array */ +uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) +{ + int i; + unsigned char x; + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) & ldub(src + i); + if (x) { + cc = 1; + } + stb(dest + i, x); + } + return cc; +} + +/* xor on array */ +uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) +{ + int i; + unsigned char x; + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + +#ifndef CONFIG_USER_ONLY + /* xor with itself is the same as memset(0) */ + if ((l > 32) && (src == dest) && + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) { + mvc_fast_memset(env, l + 1, dest, 0); + return 0; + } +#else + if (src == dest) { + memset(g2h(dest), 0, l + 1); + return 0; + } +#endif + + for (i = 0; i <= l; i++) { + x = ldub(dest + i) ^ ldub(src + i); + if (x) { + cc = 1; + } + stb(dest + i, x); + } + return cc; +} + +/* or on array */ +uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) +{ + int i; + unsigned char x; + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) | ldub(src + i); + if (x) { + cc = 1; + } + stb(dest + i, x); + } + return cc; +} + +/* memmove */ +void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) +{ + int i = 0; + int x = 0; + uint32_t l_64 = (l + 1) / 8; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + +#ifndef CONFIG_USER_ONLY + if ((l > 32) && + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && + (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { + if (dest == (src + 1)) { + mvc_fast_memset(env, l + 1, dest, ldub(src)); + return; + } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { + mvc_fast_memmove(env, l + 1, dest, src); + return; + } + } +#else + if (dest == (src + 1)) { + memset(g2h(dest), ldub(src), l + 1); + return; + } else { + memmove(g2h(dest), g2h(src), l + 1); + return; + } +#endif + + /* handle the parts that fit into 8-byte loads/stores */ + if (dest != (src + 1)) { + for (i = 0; i < l_64; i++) { + stq(dest + x, ldq(src + x)); + x += 8; + } + } + + /* slow version crossing pages with byte accesses */ + for (i = x; i <= l; i++) { + stb(dest + i, ldub(src + i)); + } +} + +/* compare unsigned byte arrays */ +uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) +{ + int i; + unsigned char x, y; + uint32_t cc; + + HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", + __func__, l, s1, s2); + for (i = 0; i <= l; i++) { + x = ldub(s1 + i); + y = ldub(s2 + i); + HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); + if (x < y) { + cc = 1; + goto done; + } else if (x > y) { + cc = 2; + goto done; + } + } + cc = 0; + done: + HELPER_LOG("\n"); + return cc; +} + +/* compare logical under mask */ +uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) +{ + uint8_t r, d; + uint32_t cc; + + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, + mask, addr); + cc = 0; + while (mask) { + if (mask & 8) { + d = ldub(addr); + r = (r1 & 0xff000000UL) >> 24; + HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, + addr); + if (r < d) { + cc = 1; + break; + } else if (r > d) { + cc = 2; + break; + } + addr++; + } + mask = (mask << 1) & 0xf; + r1 <<= 8; + } + HELPER_LOG("\n"); + return cc; +} + +/* store character under mask */ +void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) +{ + uint8_t r; + + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, + addr); + while (mask) { + if (mask & 8) { + r = (r1 & 0xff000000UL) >> 24; + stb(addr, r); + HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); + addr++; + } + mask = (mask << 1) & 0xf; + r1 <<= 8; + } + HELPER_LOG("\n"); +} + +static inline uint64_t get_address(int x2, int b2, int d2) +{ + uint64_t r = d2; + + if (x2) { + r += env->regs[x2]; + } + + if (b2) { + r += env->regs[b2]; + } + + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + r &= 0x7fffffff; + } + + return r; +} + +static inline uint64_t get_address_31fix(int reg) +{ + uint64_t r = env->regs[reg]; + + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + r &= 0x7fffffff; + } + + return r; +} + +/* search string (c is byte to search, r2 is string, r1 end of string) */ +uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t i; + uint32_t cc = 2; + uint64_t str = get_address_31fix(r2); + uint64_t end = get_address_31fix(r1); + + HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, + c, env->regs[r1], env->regs[r2]); + + for (i = str; i != end; i++) { + if (ldub(i) == c) { + env->regs[r1] = i; + cc = 1; + break; + } + } + + return cc; +} + +/* unsigned string compare (c is string terminator) */ +uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t s1 = get_address_31fix(r1); + uint64_t s2 = get_address_31fix(r2); + uint8_t v1, v2; + uint32_t cc; + + c = c & 0xff; +#ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: comparing '%s' and '%s'\n", + __func__, (char *)g2h(s1), (char *)g2h(s2)); + } +#endif + for (;;) { + v1 = ldub(s1); + v2 = ldub(s2); + if ((v1 == c || v2 == c) || (v1 != v2)) { + break; + } + s1++; + s2++; + } + + if (v1 == v2) { + cc = 0; + } else { + cc = (v1 < v2) ? 1 : 2; + /* FIXME: 31-bit mode! */ + env->regs[r1] = s1; + env->regs[r2] = s2; + } + return cc; +} + +/* move page */ +void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) +{ + /* XXX missing r0 handling */ +#ifdef CONFIG_USER_ONLY + int i; + + for (i = 0; i < TARGET_PAGE_SIZE; i++) { + stb(r1 + i, ldub(r2 + i)); + } +#else + mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); +#endif +} + +/* string copy (c is string terminator) */ +void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t dest = get_address_31fix(r1); + uint64_t src = get_address_31fix(r2); + uint8_t v; + + c = c & 0xff; +#ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), + dest); + } +#endif + for (;;) { + v = ldub(src); + stb(dest, v); + if (v == c) { + break; + } + src++; + dest++; + } + env->regs[r1] = dest; /* FIXME: 31-bit mode! */ +} + +/* compare and swap 64-bit */ +uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint64_t v2 = ldq(a2); + + if (env->regs[r1] == v2) { + cc = 0; + stq(a2, env->regs[r3]); + } else { + cc = 1; + env->regs[r1] = v2; + } + return cc; +} + +/* compare double and swap 64-bit */ +uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint64_t v2_hi = ldq(a2); + uint64_t v2_lo = ldq(a2 + 8); + uint64_t v1_hi = env->regs[r1]; + uint64_t v1_lo = env->regs[r1 + 1]; + + if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { + cc = 0; + stq(a2, env->regs[r3]); + stq(a2 + 8, env->regs[r3 + 1]); + } else { + cc = 1; + env->regs[r1] = v2_hi; + env->regs[r1 + 1] = v2_lo; + } + + return cc; +} + +/* compare and swap 32-bit */ +uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint32_t v2 = ldl(a2); + + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); + if (((uint32_t)env->regs[r1]) == v2) { + cc = 0; + stl(a2, (uint32_t)env->regs[r3]); + } else { + cc = 1; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; + } + return cc; +} + +static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) +{ + int pos = 24; /* top of the lower half of r1 */ + uint64_t rmask = 0xff000000ULL; + uint8_t val = 0; + int ccd = 0; + uint32_t cc = 0; + + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; + val = ldub(address); + if ((val & 0x80) && !ccd) { + cc = 1; + } + ccd = 1; + if (val && cc == 0) { + cc = 2; + } + env->regs[r1] |= (uint64_t)val << pos; + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + rmask >>= 8; + } + + return cc; +} + +/* execute instruction + this instruction executes an insn modified with the contents of r1 + it does not change the executed instruction in memory + it does not change the program counter + in other words: tricky... + currently implemented by interpreting the cases it is most commonly used in +*/ +uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) +{ + uint16_t insn = lduw_code(addr); + + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, + insn); + if ((insn & 0xf0ff) == 0xd000) { + uint32_t l, insn2, b1, b2, d1, d2; + + l = v1 & 0xff; + insn2 = ldl_code(addr + 2); + b1 = (insn2 >> 28) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d1 = (insn2 >> 16) & 0xfff; + d2 = insn2 & 0xfff; + switch (insn & 0xf00) { + case 0x200: + helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); + break; + case 0x500: + cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); + break; + case 0x700: + cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); + break; + case 0xc00: + helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); + break; + default: + goto abort; + break; + } + } else if ((insn & 0xff00) == 0x0a00) { + /* supervisor call */ + HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); + env->psw.addr = ret - 4; + env->int_svc_code = (insn | v1) & 0xff; + env->int_svc_ilc = 4; + helper_exception(EXCP_SVC); + } else if ((insn & 0xff00) == 0xbf00) { + uint32_t insn2, r1, r3, b2, d2; + + insn2 = ldl_code(addr + 2); + r1 = (insn2 >> 20) & 0xf; + r3 = (insn2 >> 16) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d2 = insn2 & 0xfff; + cc = helper_icm(r1, get_address(0, b2, d2), r3); + } else { + abort: + cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", + insn); + } + return cc; +} + +/* store character under mask high operates on the upper half of r1 */ +void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) +{ + int pos = 56; /* top of the upper half of r1 */ + + while (mask) { + if (mask & 8) { + stb(address, (env->regs[r1] >> pos) & 0xff); + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + } +} + +/* insert character under mask high; same as icm, but operates on the + upper half of r1 */ +uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) +{ + int pos = 56; /* top of the upper half of r1 */ + uint64_t rmask = 0xff00000000000000ULL; + uint8_t val = 0; + int ccd = 0; + uint32_t cc = 0; + + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; + val = ldub(address); + if ((val & 0x80) && !ccd) { + cc = 1; + } + ccd = 1; + if (val && cc == 0) { + cc = 2; + } + env->regs[r1] |= (uint64_t)val << pos; + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + rmask >>= 8; + } + + return cc; +} + +/* load access registers r1 to r3 from memory at a2 */ +void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + + for (i = r1;; i = (i + 1) % 16) { + env->aregs[i] = ldl(a2); + a2 += 4; + + if (i == r3) { + break; + } + } +} + +/* store access registers r1 to r3 in memory at a2 */ +void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + + for (i = r1;; i = (i + 1) % 16) { + stl(a2, env->aregs[i]); + a2 += 4; + + if (i == r3) { + break; + } + } +} + +/* move long */ +uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) +{ + uint64_t destlen = env->regs[r1 + 1] & 0xffffff; + uint64_t dest = get_address_31fix(r1); + uint64_t srclen = env->regs[r2 + 1] & 0xffffff; + uint64_t src = get_address_31fix(r2); + uint8_t pad = src >> 24; + uint8_t v; + uint32_t cc; + + if (destlen == srclen) { + cc = 0; + } else if (destlen < srclen) { + cc = 1; + } else { + cc = 2; + } + + if (srclen > destlen) { + srclen = destlen; + } + + for (; destlen && srclen; src++, dest++, destlen--, srclen--) { + v = ldub(src); + stb(dest, v); + } + + for (; destlen; dest++, destlen--) { + stb(dest, pad); + } + + env->regs[r1 + 1] = destlen; + /* can't use srclen here, we trunc'ed it */ + env->regs[r2 + 1] -= src - env->regs[r2]; + env->regs[r1] = dest; + env->regs[r2] = src; + + return cc; +} + +/* move long extended another memcopy insn with more bells and whistles */ +uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = env->regs[r1]; + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = env->regs[r3]; + uint8_t pad = a2 & 0xff; + uint8_t v; + uint32_t cc; + + if (!(env->psw.mask & PSW_MASK_64)) { + destlen = (uint32_t)destlen; + srclen = (uint32_t)srclen; + dest &= 0x7fffffff; + src &= 0x7fffffff; + } + + if (destlen == srclen) { + cc = 0; + } else if (destlen < srclen) { + cc = 1; + } else { + cc = 2; + } + + if (srclen > destlen) { + srclen = destlen; + } + + for (; destlen && srclen; src++, dest++, destlen--, srclen--) { + v = ldub(src); + stb(dest, v); + } + + for (; destlen; dest++, destlen--) { + stb(dest, pad); + } + + env->regs[r1 + 1] = destlen; + /* can't use srclen here, we trunc'ed it */ + /* FIXME: 31-bit mode! */ + env->regs[r3 + 1] -= src - env->regs[r3]; + env->regs[r1] = dest; + env->regs[r3] = src; + + return cc; +} + +/* compare logical long extended memcompare insn with padding */ +uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = get_address_31fix(r1); + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = get_address_31fix(r3); + uint8_t pad = a2 & 0xff; + uint8_t v1 = 0, v2 = 0; + uint32_t cc = 0; + + if (!(destlen || srclen)) { + return cc; + } + + if (srclen > destlen) { + srclen = destlen; + } + + for (; destlen || srclen; src++, dest++, destlen--, srclen--) { + v1 = srclen ? ldub(src) : pad; + v2 = destlen ? ldub(dest) : pad; + if (v1 != v2) { + cc = (v1 < v2) ? 1 : 2; + break; + } + } + + env->regs[r1 + 1] = destlen; + /* can't use srclen here, we trunc'ed it */ + env->regs[r3 + 1] -= src - env->regs[r3]; + env->regs[r1] = dest; + env->regs[r3] = src; + + return cc; +} + +/* checksum */ +void HELPER(cksm)(uint32_t r1, uint32_t r2) +{ + uint64_t src = get_address_31fix(r2); + uint64_t src_len = env->regs[(r2 + 1) & 15]; + uint64_t cksm = (uint32_t)env->regs[r1]; + + while (src_len >= 4) { + cksm += ldl(src); + + /* move to next word */ + src_len -= 4; + src += 4; + } + + switch (src_len) { + case 0: + break; + case 1: + cksm += ldub(src) << 24; + break; + case 2: + cksm += lduw(src) << 16; + break; + case 3: + cksm += lduw(src) << 16; + cksm += ldub(src + 2) << 8; + break; + } + + /* indicate we've processed everything */ + env->regs[r2] = src + src_len; + env->regs[(r2 + 1) & 15] = 0; + + /* store result */ + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + ((uint32_t)cksm + (cksm >> 32)); +} + +void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) +{ + int len_dest = len >> 4; + int len_src = len & 0xf; + uint8_t b; + int second_nibble = 0; + + dest += len_dest; + src += len_src; + + /* last byte is special, it only flips the nibbles */ + b = ldub(src); + stb(dest, (b << 4) | (b >> 4)); + src--; + len_src--; + + /* now pad every nibble with 0xf0 */ + + while (len_dest > 0) { + uint8_t cur_byte = 0; + + if (len_src > 0) { + cur_byte = ldub(src); + } + + len_dest--; + dest--; + + /* only advance one nibble at a time */ + if (second_nibble) { + cur_byte >>= 4; + len_src--; + src--; + } + second_nibble = !second_nibble; + + /* digit */ + cur_byte = (cur_byte & 0xf); + /* zone bits */ + cur_byte |= 0xf0; + + stb(dest, cur_byte); + } +} + +void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) +{ + int i; + + for (i = 0; i <= len; i++) { + uint8_t byte = ldub(array + i); + uint8_t new_byte = ldub(trans + byte); + + stb(array + i, new_byte); + } +} + +#if !defined(CONFIG_USER_ONLY) +void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t src = a2; + + for (i = r1;; i = (i + 1) % 16) { + env->cregs[i] = ldq(src); + HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", + i, src, env->cregs[i]); + src += sizeof(uint64_t); + + if (i == r3) { + break; + } + } + + tlb_flush(env, 1); +} + +void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t src = a2; + + for (i = r1;; i = (i + 1) % 16) { + env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); + src += sizeof(uint32_t); + + if (i == r3) { + break; + } + } + + tlb_flush(env, 1); +} + +void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t dest = a2; + + for (i = r1;; i = (i + 1) % 16) { + stq(dest, env->cregs[i]); + dest += sizeof(uint64_t); + + if (i == r3) { + break; + } + } +} + +void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t dest = a2; + + for (i = r1;; i = (i + 1) % 16) { + stl(dest, env->cregs[i]); + dest += sizeof(uint32_t); + + if (i == r3) { + break; + } + } +} + +uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) +{ + /* XXX implement */ + + return 0; +} + +/* insert storage key extended */ +uint64_t HELPER(iske)(uint64_t r2) +{ + uint64_t addr = get_address(0, 0, r2); + + if (addr > ram_size) { + return 0; + } + + return env->storage_keys[addr / TARGET_PAGE_SIZE]; +} + +/* set storage key extended */ +void HELPER(sske)(uint32_t r1, uint64_t r2) +{ + uint64_t addr = get_address(0, 0, r2); + + if (addr > ram_size) { + return; + } + + env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; +} + +/* reset reference bit extended */ +uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) +{ + uint8_t re; + uint8_t key; + + if (r2 > ram_size) { + return 0; + } + + key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; + re = key & (SK_R | SK_C); + env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); + + /* + * cc + * + * 0 Reference bit zero; change bit zero + * 1 Reference bit zero; change bit one + * 2 Reference bit one; change bit zero + * 3 Reference bit one; change bit one + */ + + return re >> 1; +} + +/* compare and swap and purge */ +uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) +{ + uint32_t cc; + uint32_t o1 = env->regs[r1]; + uint64_t a2 = get_address_31fix(r2) & ~3ULL; + uint32_t o2 = ldl(a2); + + if (o1 == o2) { + stl(a2, env->regs[(r1 + 1) & 15]); + if (env->regs[r2] & 0x3) { + /* flush TLB / ALB */ + tlb_flush(env, 1); + } + cc = 0; + } else { + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; + cc = 1; + } + + return cc; +} + +static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, + uint64_t mode2) +{ + target_ulong src, dest; + int flags, cc = 0, i; + + if (!l) { + return 0; + } else if (l > 256) { + /* max 256 */ + l = 256; + cc = 3; + } + + if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { + cpu_loop_exit(env); + } + dest |= a1 & ~TARGET_PAGE_MASK; + + if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { + cpu_loop_exit(env); + } + src |= a2 & ~TARGET_PAGE_MASK; + + /* XXX replace w/ memcpy */ + for (i = 0; i < l; i++) { + /* XXX be more clever */ + if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || + (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { + mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); + break; + } + stb_phys(dest + i, ldub_phys(src + i)); + } + + return cc; +} + +uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) +{ + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + + return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); +} + +uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) +{ + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + + return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); +} + +/* invalidate pte */ +void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) +{ + uint64_t page = vaddr & TARGET_PAGE_MASK; + uint64_t pte = 0; + + /* XXX broadcast to other CPUs */ + + /* XXX Linux is nice enough to give us the exact pte address. + According to spec we'd have to find it out ourselves */ + /* XXX Linux is fine with overwriting the pte, the spec requires + us to only set the invalid bit */ + stq_phys(pte_addr, pte | _PAGE_INVALID); + + /* XXX we exploit the fact that Linux passes the exact virtual + address here - it's not obliged to! */ + tlb_flush_page(env, page); + + /* XXX 31-bit hack */ + if (page & 0x80000000) { + tlb_flush_page(env, page & ~0x80000000); + } else { + tlb_flush_page(env, page | 0x80000000); + } +} + +/* flush local tlb */ +void HELPER(ptlb)(void) +{ + tlb_flush(env, 1); +} + +/* store using real address */ +void HELPER(stura)(uint64_t addr, uint32_t v1) +{ + stw_phys(get_address(0, 0, addr), v1); +} + +/* load real address */ +uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) +{ + uint32_t cc = 0; + int old_exc = env->exception_index; + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + uint64_t ret; + int flags; + + /* XXX incomplete - has more corner cases */ + if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { + program_interrupt(env, PGM_SPECIAL_OP, 2); + } + + env->exception_index = old_exc; + if (mmu_translate(env, addr, 0, asc, &ret, &flags)) { + cc = 3; + } + if (env->exception_index == EXCP_PGM) { + ret = env->int_pgm_code | 0x80000000; + } else { + ret |= addr & ~TARGET_PAGE_MASK; + } + env->exception_index = old_exc; + + if (!(env->psw.mask & PSW_MASK_64)) { + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + (ret & 0xffffffffULL); + } else { + env->regs[r1] = ret; + } + + return cc; +} + +#endif diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 3b8b997ab..bb8dbf55d 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -31,58 +31,9 @@ #include #endif -#if !defined(CONFIG_USER_ONLY) -#include "sysemu.h" -#endif - -/*****************************************************************************/ -/* Softmmu support */ #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" - -#define MMUSUFFIX _mmu - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, - uintptr_t retaddr) -{ - TranslationBlock *tb; - CPUS390XState *saved_env; - int ret; - - saved_env = env; - env = env1; - ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); - if (unlikely(ret != 0)) { - if (likely(retaddr)) { - /* now we have a real cpu fault */ - tb = tb_find_pc(retaddr); - if (likely(tb)) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, retaddr); - } - } - cpu_loop_exit(env); - } - env = saved_env; -} - +#include "sysemu.h" #endif /* #define DEBUG_HELPER */ @@ -100,840 +51,6 @@ void HELPER(exception)(uint32_t excp) cpu_loop_exit(env); } -#ifndef CONFIG_USER_ONLY -static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, - uint8_t byte) -{ - target_phys_addr_t dest_phys; - target_phys_addr_t len = l; - void *dest_p; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; - int flags; - - if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { - stb(dest, byte); - cpu_abort(env, "should never reach here"); - } - dest_phys |= dest & ~TARGET_PAGE_MASK; - - dest_p = cpu_physical_memory_map(dest_phys, &len, 1); - - memset(dest_p, byte, len); - - cpu_physical_memory_unmap(dest_p, 1, len, len); -} - -static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, - uint64_t src) -{ - target_phys_addr_t dest_phys; - target_phys_addr_t src_phys; - target_phys_addr_t len = l; - void *dest_p; - void *src_p; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; - int flags; - - if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { - stb(dest, 0); - cpu_abort(env, "should never reach here"); - } - dest_phys |= dest & ~TARGET_PAGE_MASK; - - if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { - ldub(src); - cpu_abort(env, "should never reach here"); - } - src_phys |= src & ~TARGET_PAGE_MASK; - - dest_p = cpu_physical_memory_map(dest_phys, &len, 1); - src_p = cpu_physical_memory_map(src_phys, &len, 0); - - memmove(dest_p, src_p, len); - - cpu_physical_memory_unmap(dest_p, 1, len, len); - cpu_physical_memory_unmap(src_p, 0, len, len); -} -#endif - -/* and on array */ -uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i; - unsigned char x; - uint32_t cc = 0; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __func__, l, dest, src); - for (i = 0; i <= l; i++) { - x = ldub(dest + i) & ldub(src + i); - if (x) { - cc = 1; - } - stb(dest + i, x); - } - return cc; -} - -/* xor on array */ -uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i; - unsigned char x; - uint32_t cc = 0; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __func__, l, dest, src); - -#ifndef CONFIG_USER_ONLY - /* xor with itself is the same as memset(0) */ - if ((l > 32) && (src == dest) && - (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) { - mvc_fast_memset(env, l + 1, dest, 0); - return 0; - } -#else - if (src == dest) { - memset(g2h(dest), 0, l + 1); - return 0; - } -#endif - - for (i = 0; i <= l; i++) { - x = ldub(dest + i) ^ ldub(src + i); - if (x) { - cc = 1; - } - stb(dest + i, x); - } - return cc; -} - -/* or on array */ -uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i; - unsigned char x; - uint32_t cc = 0; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __func__, l, dest, src); - for (i = 0; i <= l; i++) { - x = ldub(dest + i) | ldub(src + i); - if (x) { - cc = 1; - } - stb(dest + i, x); - } - return cc; -} - -/* memmove */ -void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i = 0; - int x = 0; - uint32_t l_64 = (l + 1) / 8; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __func__, l, dest, src); - -#ifndef CONFIG_USER_ONLY - if ((l > 32) && - (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && - (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { - if (dest == (src + 1)) { - mvc_fast_memset(env, l + 1, dest, ldub(src)); - return; - } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { - mvc_fast_memmove(env, l + 1, dest, src); - return; - } - } -#else - if (dest == (src + 1)) { - memset(g2h(dest), ldub(src), l + 1); - return; - } else { - memmove(g2h(dest), g2h(src), l + 1); - return; - } -#endif - - /* handle the parts that fit into 8-byte loads/stores */ - if (dest != (src + 1)) { - for (i = 0; i < l_64; i++) { - stq(dest + x, ldq(src + x)); - x += 8; - } - } - - /* slow version crossing pages with byte accesses */ - for (i = x; i <= l; i++) { - stb(dest + i, ldub(src + i)); - } -} - -/* compare unsigned byte arrays */ -uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) -{ - int i; - unsigned char x, y; - uint32_t cc; - - HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", - __func__, l, s1, s2); - for (i = 0; i <= l; i++) { - x = ldub(s1 + i); - y = ldub(s2 + i); - HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); - if (x < y) { - cc = 1; - goto done; - } else if (x > y) { - cc = 2; - goto done; - } - } - cc = 0; - done: - HELPER_LOG("\n"); - return cc; -} - -/* compare logical under mask */ -uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) -{ - uint8_t r, d; - uint32_t cc; - - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, - mask, addr); - cc = 0; - while (mask) { - if (mask & 8) { - d = ldub(addr); - r = (r1 & 0xff000000UL) >> 24; - HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, - addr); - if (r < d) { - cc = 1; - break; - } else if (r > d) { - cc = 2; - break; - } - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; - } - HELPER_LOG("\n"); - return cc; -} - -/* store character under mask */ -void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) -{ - uint8_t r; - - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, - addr); - while (mask) { - if (mask & 8) { - r = (r1 & 0xff000000UL) >> 24; - stb(addr, r); - HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; - } - HELPER_LOG("\n"); -} - -static inline uint64_t get_address(int x2, int b2, int d2) -{ - uint64_t r = d2; - - if (x2) { - r += env->regs[x2]; - } - - if (b2) { - r += env->regs[b2]; - } - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; -} - -static inline uint64_t get_address_31fix(int reg) -{ - uint64_t r = env->regs[reg]; - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; -} - -/* search string (c is byte to search, r2 is string, r1 end of string) */ -uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) -{ - uint64_t i; - uint32_t cc = 2; - uint64_t str = get_address_31fix(r2); - uint64_t end = get_address_31fix(r1); - - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, - c, env->regs[r1], env->regs[r2]); - - for (i = str; i != end; i++) { - if (ldub(i) == c) { - env->regs[r1] = i; - cc = 1; - break; - } - } - - return cc; -} - -/* unsigned string compare (c is string terminator) */ -uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) -{ - uint64_t s1 = get_address_31fix(r1); - uint64_t s2 = get_address_31fix(r2); - uint8_t v1, v2; - uint32_t cc; - - c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: comparing '%s' and '%s'\n", - __func__, (char *)g2h(s1), (char *)g2h(s2)); - } -#endif - for (;;) { - v1 = ldub(s1); - v2 = ldub(s2); - if ((v1 == c || v2 == c) || (v1 != v2)) { - break; - } - s1++; - s2++; - } - - if (v1 == v2) { - cc = 0; - } else { - cc = (v1 < v2) ? 1 : 2; - /* FIXME: 31-bit mode! */ - env->regs[r1] = s1; - env->regs[r2] = s2; - } - return cc; -} - -/* move page */ -void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) -{ - /* XXX missing r0 handling */ -#ifdef CONFIG_USER_ONLY - int i; - - for (i = 0; i < TARGET_PAGE_SIZE; i++) { - stb(r1 + i, ldub(r2 + i)); - } -#else - mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); -#endif -} - -/* string copy (c is string terminator) */ -void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) -{ - uint64_t dest = get_address_31fix(r1); - uint64_t src = get_address_31fix(r2); - uint8_t v; - - c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), - dest); - } -#endif - for (;;) { - v = ldub(src); - stb(dest, v); - if (v == c) { - break; - } - src++; - dest++; - } - env->regs[r1] = dest; /* FIXME: 31-bit mode! */ -} - -/* compare and swap 64-bit */ -uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2 = ldq(a2); - - if (env->regs[r1] == v2) { - cc = 0; - stq(a2, env->regs[r3]); - } else { - cc = 1; - env->regs[r1] = v2; - } - return cc; -} - -/* compare double and swap 64-bit */ -uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2_hi = ldq(a2); - uint64_t v2_lo = ldq(a2 + 8); - uint64_t v1_hi = env->regs[r1]; - uint64_t v1_lo = env->regs[r1 + 1]; - - if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { - cc = 0; - stq(a2, env->regs[r3]); - stq(a2 + 8, env->regs[r3 + 1]); - } else { - cc = 1; - env->regs[r1] = v2_hi; - env->regs[r1 + 1] = v2_lo; - } - - return cc; -} - -/* compare and swap 32-bit */ -uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint32_t v2 = ldl(a2); - - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); - if (((uint32_t)env->regs[r1]) == v2) { - cc = 0; - stl(a2, (uint32_t)env->regs[r3]); - } else { - cc = 1; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; - } - return cc; -} - -static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) -{ - int pos = 24; /* top of the lower half of r1 */ - uint64_t rmask = 0xff000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = ldub(address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - -/* execute instruction - this instruction executes an insn modified with the contents of r1 - it does not change the executed instruction in memory - it does not change the program counter - in other words: tricky... - currently implemented by interpreting the cases it is most commonly used in -*/ -uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) -{ - uint16_t insn = lduw_code(addr); - - HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, - insn); - if ((insn & 0xf0ff) == 0xd000) { - uint32_t l, insn2, b1, b2, d1, d2; - - l = v1 & 0xff; - insn2 = ldl_code(addr + 2); - b1 = (insn2 >> 28) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d1 = (insn2 >> 16) & 0xfff; - d2 = insn2 & 0xfff; - switch (insn & 0xf00) { - case 0x200: - helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - case 0x500: - cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - case 0x700: - cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - case 0xc00: - helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - default: - goto abort; - break; - } - } else if ((insn & 0xff00) == 0x0a00) { - /* supervisor call */ - HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); - env->psw.addr = ret - 4; - env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilc = 4; - helper_exception(EXCP_SVC); - } else if ((insn & 0xff00) == 0xbf00) { - uint32_t insn2, r1, r3, b2, d2; - - insn2 = ldl_code(addr + 2); - r1 = (insn2 >> 20) & 0xf; - r3 = (insn2 >> 16) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d2 = insn2 & 0xfff; - cc = helper_icm(r1, get_address(0, b2, d2), r3); - } else { - abort: - cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", - insn); - } - return cc; -} - -/* store character under mask high operates on the upper half of r1 */ -void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - - while (mask) { - if (mask & 8) { - stb(address, (env->regs[r1] >> pos) & 0xff); - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - } -} - -/* insert character under mask high; same as icm, but operates on the - upper half of r1 */ -uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - uint64_t rmask = 0xff00000000000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = ldub(address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - -/* load access registers r1 to r3 from memory at a2 */ -void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - - for (i = r1;; i = (i + 1) % 16) { - env->aregs[i] = ldl(a2); - a2 += 4; - - if (i == r3) { - break; - } - } -} - -/* store access registers r1 to r3 in memory at a2 */ -void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - - for (i = r1;; i = (i + 1) % 16) { - stl(a2, env->aregs[i]); - a2 += 4; - - if (i == r3) { - break; - } - } -} - -/* move long */ -uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) -{ - uint64_t destlen = env->regs[r1 + 1] & 0xffffff; - uint64_t dest = get_address_31fix(r1); - uint64_t srclen = env->regs[r2 + 1] & 0xffffff; - uint64_t src = get_address_31fix(r2); - uint8_t pad = src >> 24; - uint8_t v; - uint32_t cc; - - if (destlen == srclen) { - cc = 0; - } else if (destlen < srclen) { - cc = 1; - } else { - cc = 2; - } - - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = ldub(src); - stb(dest, v); - } - - for (; destlen; dest++, destlen--) { - stb(dest, pad); - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - env->regs[r2 + 1] -= src - env->regs[r2]; - env->regs[r1] = dest; - env->regs[r2] = src; - - return cc; -} - -/* move long extended another memcopy insn with more bells and whistles */ -uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = env->regs[r1]; - uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = env->regs[r3]; - uint8_t pad = a2 & 0xff; - uint8_t v; - uint32_t cc; - - if (!(env->psw.mask & PSW_MASK_64)) { - destlen = (uint32_t)destlen; - srclen = (uint32_t)srclen; - dest &= 0x7fffffff; - src &= 0x7fffffff; - } - - if (destlen == srclen) { - cc = 0; - } else if (destlen < srclen) { - cc = 1; - } else { - cc = 2; - } - - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = ldub(src); - stb(dest, v); - } - - for (; destlen; dest++, destlen--) { - stb(dest, pad); - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - /* FIXME: 31-bit mode! */ - env->regs[r3 + 1] -= src - env->regs[r3]; - env->regs[r1] = dest; - env->regs[r3] = src; - - return cc; -} - -/* compare logical long extended memcompare insn with padding */ -uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = get_address_31fix(r1); - uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = get_address_31fix(r3); - uint8_t pad = a2 & 0xff; - uint8_t v1 = 0, v2 = 0; - uint32_t cc = 0; - - if (!(destlen || srclen)) { - return cc; - } - - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen || srclen; src++, dest++, destlen--, srclen--) { - v1 = srclen ? ldub(src) : pad; - v2 = destlen ? ldub(dest) : pad; - if (v1 != v2) { - cc = (v1 < v2) ? 1 : 2; - break; - } - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - env->regs[r3 + 1] -= src - env->regs[r3]; - env->regs[r1] = dest; - env->regs[r3] = src; - - return cc; -} - -/* checksum */ -void HELPER(cksm)(uint32_t r1, uint32_t r2) -{ - uint64_t src = get_address_31fix(r2); - uint64_t src_len = env->regs[(r2 + 1) & 15]; - uint64_t cksm = (uint32_t)env->regs[r1]; - - while (src_len >= 4) { - cksm += ldl(src); - - /* move to next word */ - src_len -= 4; - src += 4; - } - - switch (src_len) { - case 0: - break; - case 1: - cksm += ldub(src) << 24; - break; - case 2: - cksm += lduw(src) << 16; - break; - case 3: - cksm += lduw(src) << 16; - cksm += ldub(src + 2) << 8; - break; - } - - /* indicate we've processed everything */ - env->regs[r2] = src + src_len; - env->regs[(r2 + 1) & 15] = 0; - - /* store result */ - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); -} - -void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) -{ - int len_dest = len >> 4; - int len_src = len & 0xf; - uint8_t b; - int second_nibble = 0; - - dest += len_dest; - src += len_src; - - /* last byte is special, it only flips the nibbles */ - b = ldub(src); - stb(dest, (b << 4) | (b >> 4)); - src--; - len_src--; - - /* now pad every nibble with 0xf0 */ - - while (len_dest > 0) { - uint8_t cur_byte = 0; - - if (len_src > 0) { - cur_byte = ldub(src); - } - - len_dest--; - dest--; - - /* only advance one nibble at a time */ - if (second_nibble) { - cur_byte >>= 4; - len_src--; - src--; - } - second_nibble = !second_nibble; - - /* digit */ - cur_byte = (cur_byte & 0xf); - /* zone bits */ - cur_byte |= 0xf0; - - stb(dest, cur_byte); - } -} - -void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) -{ - int i; - - for (i = 0; i <= len; i++) { - uint8_t byte = ldub(array + i); - uint8_t new_byte = ldub(trans + byte); - - stb(array + i, new_byte); - } -} - #ifndef CONFIG_USER_ONLY void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) { @@ -1267,206 +384,6 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) return cc; } -void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t src = a2; - - for (i = r1;; i = (i + 1) % 16) { - env->cregs[i] = ldq(src); - HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", - i, src, env->cregs[i]); - src += sizeof(uint64_t); - - if (i == r3) { - break; - } - } - - tlb_flush(env, 1); -} - -void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t src = a2; - - for (i = r1;; i = (i + 1) % 16) { - env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); - src += sizeof(uint32_t); - - if (i == r3) { - break; - } - } - - tlb_flush(env, 1); -} - -void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t dest = a2; - - for (i = r1;; i = (i + 1) % 16) { - stq(dest, env->cregs[i]); - dest += sizeof(uint64_t); - - if (i == r3) { - break; - } - } -} - -void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t dest = a2; - - for (i = r1;; i = (i + 1) % 16) { - stl(dest, env->cregs[i]); - dest += sizeof(uint32_t); - - if (i == r3) { - break; - } - } -} - -uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) -{ - /* XXX implement */ - - return 0; -} - -/* insert storage key extended */ -uint64_t HELPER(iske)(uint64_t r2) -{ - uint64_t addr = get_address(0, 0, r2); - - if (addr > ram_size) { - return 0; - } - - return env->storage_keys[addr / TARGET_PAGE_SIZE]; -} - -/* set storage key extended */ -void HELPER(sske)(uint32_t r1, uint64_t r2) -{ - uint64_t addr = get_address(0, 0, r2); - - if (addr > ram_size) { - return; - } - - env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; -} - -/* reset reference bit extended */ -uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) -{ - uint8_t re; - uint8_t key; - - if (r2 > ram_size) { - return 0; - } - - key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; - re = key & (SK_R | SK_C); - env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); - - /* - * cc - * - * 0 Reference bit zero; change bit zero - * 1 Reference bit zero; change bit one - * 2 Reference bit one; change bit zero - * 3 Reference bit one; change bit one - */ - - return re >> 1; -} - -/* compare and swap and purge */ -uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) -{ - uint32_t cc; - uint32_t o1 = env->regs[r1]; - uint64_t a2 = get_address_31fix(r2) & ~3ULL; - uint32_t o2 = ldl(a2); - - if (o1 == o2) { - stl(a2, env->regs[(r1 + 1) & 15]); - if (env->regs[r2] & 0x3) { - /* flush TLB / ALB */ - tlb_flush(env, 1); - } - cc = 0; - } else { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; - cc = 1; - } - - return cc; -} - -static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, - uint64_t mode2) -{ - target_ulong src, dest; - int flags, cc = 0, i; - - if (!l) { - return 0; - } else if (l > 256) { - /* max 256 */ - l = 256; - cc = 3; - } - - if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { - cpu_loop_exit(env); - } - dest |= a1 & ~TARGET_PAGE_MASK; - - if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { - cpu_loop_exit(env); - } - src |= a2 & ~TARGET_PAGE_MASK; - - /* XXX replace w/ memcpy */ - for (i = 0; i < l; i++) { - /* XXX be more clever */ - if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || - (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { - mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); - break; - } - stb_phys(dest + i, ldub_phys(src + i)); - } - - return cc; -} - -uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) -{ - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __func__, l, a1, a2); - - return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); -} - -uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) -{ - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __func__, l, a1, a2); - - return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); -} - uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) { int cc = 0; @@ -1508,78 +425,4 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) return cc; } - -/* invalidate pte */ -void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) -{ - uint64_t page = vaddr & TARGET_PAGE_MASK; - uint64_t pte = 0; - - /* XXX broadcast to other CPUs */ - - /* XXX Linux is nice enough to give us the exact pte address. - According to spec we'd have to find it out ourselves */ - /* XXX Linux is fine with overwriting the pte, the spec requires - us to only set the invalid bit */ - stq_phys(pte_addr, pte | _PAGE_INVALID); - - /* XXX we exploit the fact that Linux passes the exact virtual - address here - it's not obliged to! */ - tlb_flush_page(env, page); - - /* XXX 31-bit hack */ - if (page & 0x80000000) { - tlb_flush_page(env, page & ~0x80000000); - } else { - tlb_flush_page(env, page | 0x80000000); - } -} - -/* flush local tlb */ -void HELPER(ptlb)(void) -{ - tlb_flush(env, 1); -} - -/* store using real address */ -void HELPER(stura)(uint64_t addr, uint32_t v1) -{ - stw_phys(get_address(0, 0, addr), v1); -} - -/* load real address */ -uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) -{ - uint32_t cc = 0; - int old_exc = env->exception_index; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; - uint64_t ret; - int flags; - - /* XXX incomplete - has more corner cases */ - if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { - program_interrupt(env, PGM_SPECIAL_OP, 2); - } - - env->exception_index = old_exc; - if (mmu_translate(env, addr, 0, asc, &ret, &flags)) { - cc = 3; - } - if (env->exception_index == EXCP_PGM) { - ret = env->int_pgm_code | 0x80000000; - } else { - ret |= addr & ~TARGET_PAGE_MASK; - } - env->exception_index = old_exc; - - if (!(env->psw.mask & PSW_MASK_64)) { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - (ret & 0xffffffffULL); - } else { - env->regs[r1] = ret; - } - - return cc; -} - #endif -- cgit v1.2.3 From aea1e885b2b59cf93d0db9356fd5bb6cb1780f01 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:35 +0000 Subject: target-s390x: rename op_helper.c to misc_helper.c Now op_helper.c contains miscellaneous helpers, rename it to misc_helper.c. Signed-off-by: Blue Swirl [agraf: fix conflict] Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 6 +- target-s390x/cpu.h | 2 +- target-s390x/misc_helper.c | 428 +++++++++++++++++++++++++++++++++++++++++++++ target-s390x/op_helper.c | 428 --------------------------------------------- 4 files changed, 432 insertions(+), 432 deletions(-) create mode 100644 target-s390x/misc_helper.c delete mode 100644 target-s390x/op_helper.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index b9b306170..a87d26fae 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,10 +1,10 @@ -obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o -obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o +obj-y += translate.o helper.o cpu.o interrupt.o +obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o -$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 97fde5e2e..0ccb55182 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1005,7 +1005,7 @@ uint32_t set_cc_f64(float64 v1, float64 v2); uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); -/* op_helper.c */ +/* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); #endif diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c new file mode 100644 index 000000000..1d5137f98 --- /dev/null +++ b/target-s390x/misc_helper.c @@ -0,0 +1,428 @@ +/* + * S/390 misc helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "cpu.h" +#include "memory.h" +#include "cputlb.h" +#include "dyngen-exec.h" +#include "host-utils.h" +#include "helper.h" +#include +#include "kvm.h" +#include "qemu-timer.h" +#ifdef CONFIG_KVM +#include +#endif + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#include "sysemu.h" +#endif + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +/* raise an exception */ +void HELPER(exception)(uint32_t excp) +{ + HELPER_LOG("%s: exception %d\n", __func__, excp); + env->exception_index = excp; + cpu_loop_exit(env); +} + +#ifndef CONFIG_USER_ONLY +void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +{ + qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); + + if (kvm_enabled()) { +#ifdef CONFIG_KVM + kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); +#endif + } else { + env->int_pgm_code = code; + env->int_pgm_ilc = ilc; + env->exception_index = EXCP_PGM; + cpu_loop_exit(env); + } +} + +/* + * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc + */ +int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) +{ + int r = 0; + int shift = 0; + +#ifdef DEBUG_HELPER + printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); +#endif + + /* basic checks */ + if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { + return -PGM_ADDRESSING; + } + if (sccb & ~0x7ffffff8ul) { + return -PGM_SPECIFICATION; + } + + switch (code) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + while ((ram_size >> (20 + shift)) > 65535) { + shift++; + } + stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); + stb_phys(sccb + SCP_INCREMENT, 1 << shift); + stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); + + s390_sclp_extint(sccb & ~3); + break; + default: +#ifdef DEBUG_HELPER + printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); +#endif + r = 3; + break; + } + + return r; +} + +/* SCLP service call */ +uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) +{ + int r; + + r = sclp_service_call(env, r1, r2); + if (r < 0) { + program_interrupt(env, -r, 4); + return 0; + } + return r; +} + +/* DIAG */ +uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) +{ + uint64_t r; + + switch (num) { + case 0x500: + /* KVM hypercall */ + r = s390_virtio_hypercall(env, mem, code); + break; + case 0x44: + /* yield */ + r = 0; + break; + case 0x308: + /* ipl */ + r = 0; + break; + default: + r = -1; + break; + } + + if (r) { + program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); + } + + return r; +} + +/* Store CPU ID */ +void HELPER(stidp)(uint64_t a1) +{ + stq(a1, env->cpu_num); +} + +/* Set Prefix */ +void HELPER(spx)(uint64_t a1) +{ + uint32_t prefix; + + prefix = ldl(a1); + env->psa = prefix & 0xfffff000; + qemu_log("prefix: %#x\n", prefix); + tlb_flush_page(env, 0); + tlb_flush_page(env, TARGET_PAGE_SIZE); +} + +/* Set Clock */ +uint32_t HELPER(sck)(uint64_t a1) +{ + /* XXX not implemented - is it necessary? */ + + return 0; +} + +static inline uint64_t clock_value(CPUS390XState *env) +{ + uint64_t time; + + time = env->tod_offset + + time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); + + return time; +} + +/* Store Clock */ +uint32_t HELPER(stck)(uint64_t a1) +{ + stq(a1, clock_value(env)); + + return 0; +} + +/* Store Clock Extended */ +uint32_t HELPER(stcke)(uint64_t a1) +{ + stb(a1, 0); + /* basically the same value as stck */ + stq(a1 + 1, clock_value(env) | env->cpu_num); + /* more fine grained than stck */ + stq(a1 + 9, 0); + /* XXX programmable fields */ + stw(a1 + 17, 0); + + return 0; +} + +/* Set Clock Comparator */ +void HELPER(sckc)(uint64_t a1) +{ + uint64_t time = ldq(a1); + + if (time == -1ULL) { + return; + } + + /* difference between now and then */ + time -= clock_value(env); + /* nanoseconds */ + time = (time * 125) >> 9; + + qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); +} + +/* Store Clock Comparator */ +void HELPER(stckc)(uint64_t a1) +{ + /* XXX implement */ + stq(a1, 0); +} + +/* Set CPU Timer */ +void HELPER(spt)(uint64_t a1) +{ + uint64_t time = ldq(a1); + + if (time == -1ULL) { + return; + } + + /* nanoseconds */ + time = (time * 125) >> 9; + + qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); +} + +/* Store CPU Timer */ +void HELPER(stpt)(uint64_t a1) +{ + /* XXX implement */ + stq(a1, 0); +} + +/* Store System Information */ +uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) +{ + int cc = 0; + int sel1, sel2; + + if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && + ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { + /* valid function code, invalid reserved bits */ + program_interrupt(env, PGM_SPECIFICATION, 2); + } + + sel1 = r0 & STSI_R0_SEL1_MASK; + sel2 = r1 & STSI_R1_SEL2_MASK; + + /* XXX: spec exception if sysib is not 4k-aligned */ + + switch (r0 & STSI_LEVEL_MASK) { + case STSI_LEVEL_1: + if ((sel1 == 1) && (sel2 == 1)) { + /* Basic Machine Configuration */ + struct sysib_111 sysib; + + memset(&sysib, 0, sizeof(sysib)); + ebcdic_put(sysib.manuf, "QEMU ", 16); + /* same as machine type number in STORE CPU ID */ + ebcdic_put(sysib.type, "QEMU", 4); + /* same as model number in STORE CPU ID */ + ebcdic_put(sysib.model, "QEMU ", 16); + ebcdic_put(sysib.sequence, "QEMU ", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 1)) { + /* Basic Machine CPU */ + struct sysib_121 sysib; + + memset(&sysib, 0, sizeof(sysib)); + /* XXX make different for different CPUs? */ + ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + stw_p(&sysib.cpu_addr, env->cpu_num); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 2)) { + /* Basic Machine CPUs */ + struct sysib_122 sysib; + + memset(&sysib, 0, sizeof(sysib)); + stl_p(&sysib.capability, 0x443afc29); + /* XXX change when SMP comes */ + stw_p(&sysib.total_cpus, 1); + stw_p(&sysib.active_cpus, 1); + stw_p(&sysib.standby_cpus, 0); + stw_p(&sysib.reserved_cpus, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + case STSI_LEVEL_2: + { + if ((sel1 == 2) && (sel2 == 1)) { + /* LPAR CPU */ + struct sysib_221 sysib; + + memset(&sysib, 0, sizeof(sysib)); + /* XXX make different for different CPUs? */ + ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_id, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 2)) { + /* LPAR CPUs */ + struct sysib_222 sysib; + + memset(&sysib, 0, sizeof(sysib)); + stw_p(&sysib.lpar_num, 0); + sysib.lcpuc = 0; + /* XXX change when SMP comes */ + stw_p(&sysib.total_cpus, 1); + stw_p(&sysib.conf_cpus, 1); + stw_p(&sysib.standby_cpus, 0); + stw_p(&sysib.reserved_cpus, 0); + ebcdic_put(sysib.name, "QEMU ", 8); + stl_p(&sysib.caf, 1000); + stw_p(&sysib.dedicated_cpus, 0); + stw_p(&sysib.shared_cpus, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + } + case STSI_LEVEL_3: + { + if ((sel1 == 2) && (sel2 == 2)) { + /* VM CPUs */ + struct sysib_322 sysib; + + memset(&sysib, 0, sizeof(sysib)); + sysib.count = 1; + /* XXX change when SMP comes */ + stw_p(&sysib.vm[0].total_cpus, 1); + stw_p(&sysib.vm[0].conf_cpus, 1); + stw_p(&sysib.vm[0].standby_cpus, 0); + stw_p(&sysib.vm[0].reserved_cpus, 0); + ebcdic_put(sysib.vm[0].name, "KVMguest", 8); + stl_p(&sysib.vm[0].caf, 1000); + ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + } + case STSI_LEVEL_CURRENT: + env->regs[0] = STSI_LEVEL_3; + break; + default: + cc = 3; + break; + } + + return cc; +} + +uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) +{ + int cc = 0; + + HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", + __func__, order_code, r1, cpu_addr); + + /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" + as parameter (input). Status (output) is always R1. */ + + switch (order_code) { + case SIGP_SET_ARCH: + /* switch arch */ + break; + case SIGP_SENSE: + /* enumerate CPU status */ + if (cpu_addr) { + /* XXX implement when SMP comes */ + return 3; + } + env->regs[r1] &= 0xffffffff00000000ULL; + cc = 1; + break; +#if !defined(CONFIG_USER_ONLY) + case SIGP_RESTART: + qemu_system_reset_request(); + cpu_loop_exit(env); + break; + case SIGP_STOP: + qemu_system_shutdown_request(); + cpu_loop_exit(env); + break; +#endif + default: + /* unknown sigp */ + fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); + cc = 3; + } + + return cc; +} +#endif diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c deleted file mode 100644 index bb8dbf55d..000000000 --- a/target-s390x/op_helper.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * S/390 helper routines - * - * Copyright (c) 2009 Ulrich Hecht - * Copyright (c) 2009 Alexander Graf - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "cpu.h" -#include "memory.h" -#include "cputlb.h" -#include "dyngen-exec.h" -#include "host-utils.h" -#include "helper.h" -#include -#include "kvm.h" -#include "qemu-timer.h" -#ifdef CONFIG_KVM -#include -#endif - -#if !defined(CONFIG_USER_ONLY) -#include "softmmu_exec.h" -#include "sysemu.h" -#endif - -/* #define DEBUG_HELPER */ -#ifdef DEBUG_HELPER -#define HELPER_LOG(x...) qemu_log(x) -#else -#define HELPER_LOG(x...) -#endif - -/* raise an exception */ -void HELPER(exception)(uint32_t excp) -{ - HELPER_LOG("%s: exception %d\n", __func__, excp); - env->exception_index = excp; - cpu_loop_exit(env); -} - -#ifndef CONFIG_USER_ONLY -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) -{ - qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); - - if (kvm_enabled()) { -#ifdef CONFIG_KVM - kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); -#endif - } else { - env->int_pgm_code = code; - env->int_pgm_ilc = ilc; - env->exception_index = EXCP_PGM; - cpu_loop_exit(env); - } -} - -/* - * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc - */ -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) -{ - int r = 0; - int shift = 0; - -#ifdef DEBUG_HELPER - printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); -#endif - - /* basic checks */ - if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { - return -PGM_ADDRESSING; - } - if (sccb & ~0x7ffffff8ul) { - return -PGM_SPECIFICATION; - } - - switch (code) { - case SCLP_CMDW_READ_SCP_INFO: - case SCLP_CMDW_READ_SCP_INFO_FORCED: - while ((ram_size >> (20 + shift)) > 65535) { - shift++; - } - stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); - stb_phys(sccb + SCP_INCREMENT, 1 << shift); - stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); - - s390_sclp_extint(sccb & ~3); - break; - default: -#ifdef DEBUG_HELPER - printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); -#endif - r = 3; - break; - } - - return r; -} - -/* SCLP service call */ -uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) -{ - int r; - - r = sclp_service_call(env, r1, r2); - if (r < 0) { - program_interrupt(env, -r, 4); - return 0; - } - return r; -} - -/* DIAG */ -uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) -{ - uint64_t r; - - switch (num) { - case 0x500: - /* KVM hypercall */ - r = s390_virtio_hypercall(env, mem, code); - break; - case 0x44: - /* yield */ - r = 0; - break; - case 0x308: - /* ipl */ - r = 0; - break; - default: - r = -1; - break; - } - - if (r) { - program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); - } - - return r; -} - -/* Store CPU ID */ -void HELPER(stidp)(uint64_t a1) -{ - stq(a1, env->cpu_num); -} - -/* Set Prefix */ -void HELPER(spx)(uint64_t a1) -{ - uint32_t prefix; - - prefix = ldl(a1); - env->psa = prefix & 0xfffff000; - qemu_log("prefix: %#x\n", prefix); - tlb_flush_page(env, 0); - tlb_flush_page(env, TARGET_PAGE_SIZE); -} - -/* Set Clock */ -uint32_t HELPER(sck)(uint64_t a1) -{ - /* XXX not implemented - is it necessary? */ - - return 0; -} - -static inline uint64_t clock_value(CPUS390XState *env) -{ - uint64_t time; - - time = env->tod_offset + - time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); - - return time; -} - -/* Store Clock */ -uint32_t HELPER(stck)(uint64_t a1) -{ - stq(a1, clock_value(env)); - - return 0; -} - -/* Store Clock Extended */ -uint32_t HELPER(stcke)(uint64_t a1) -{ - stb(a1, 0); - /* basically the same value as stck */ - stq(a1 + 1, clock_value(env) | env->cpu_num); - /* more fine grained than stck */ - stq(a1 + 9, 0); - /* XXX programmable fields */ - stw(a1 + 17, 0); - - return 0; -} - -/* Set Clock Comparator */ -void HELPER(sckc)(uint64_t a1) -{ - uint64_t time = ldq(a1); - - if (time == -1ULL) { - return; - } - - /* difference between now and then */ - time -= clock_value(env); - /* nanoseconds */ - time = (time * 125) >> 9; - - qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); -} - -/* Store Clock Comparator */ -void HELPER(stckc)(uint64_t a1) -{ - /* XXX implement */ - stq(a1, 0); -} - -/* Set CPU Timer */ -void HELPER(spt)(uint64_t a1) -{ - uint64_t time = ldq(a1); - - if (time == -1ULL) { - return; - } - - /* nanoseconds */ - time = (time * 125) >> 9; - - qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); -} - -/* Store CPU Timer */ -void HELPER(stpt)(uint64_t a1) -{ - /* XXX implement */ - stq(a1, 0); -} - -/* Store System Information */ -uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) -{ - int cc = 0; - int sel1, sel2; - - if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && - ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { - /* valid function code, invalid reserved bits */ - program_interrupt(env, PGM_SPECIFICATION, 2); - } - - sel1 = r0 & STSI_R0_SEL1_MASK; - sel2 = r1 & STSI_R1_SEL2_MASK; - - /* XXX: spec exception if sysib is not 4k-aligned */ - - switch (r0 & STSI_LEVEL_MASK) { - case STSI_LEVEL_1: - if ((sel1 == 1) && (sel2 == 1)) { - /* Basic Machine Configuration */ - struct sysib_111 sysib; - - memset(&sysib, 0, sizeof(sysib)); - ebcdic_put(sysib.manuf, "QEMU ", 16); - /* same as machine type number in STORE CPU ID */ - ebcdic_put(sysib.type, "QEMU", 4); - /* same as model number in STORE CPU ID */ - ebcdic_put(sysib.model, "QEMU ", 16); - ebcdic_put(sysib.sequence, "QEMU ", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 1)) { - /* Basic Machine CPU */ - struct sysib_121 sysib; - - memset(&sysib, 0, sizeof(sysib)); - /* XXX make different for different CPUs? */ - ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); - cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 2)) { - /* Basic Machine CPUs */ - struct sysib_122 sysib; - - memset(&sysib, 0, sizeof(sysib)); - stl_p(&sysib.capability, 0x443afc29); - /* XXX change when SMP comes */ - stw_p(&sysib.total_cpus, 1); - stw_p(&sysib.active_cpus, 1); - stw_p(&sysib.standby_cpus, 0); - stw_p(&sysib.reserved_cpus, 0); - cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); - } else { - cc = 3; - } - break; - case STSI_LEVEL_2: - { - if ((sel1 == 2) && (sel2 == 1)) { - /* LPAR CPU */ - struct sysib_221 sysib; - - memset(&sysib, 0, sizeof(sysib)); - /* XXX make different for different CPUs? */ - ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); - stw_p(&sysib.cpu_id, 0); - cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 2)) { - /* LPAR CPUs */ - struct sysib_222 sysib; - - memset(&sysib, 0, sizeof(sysib)); - stw_p(&sysib.lpar_num, 0); - sysib.lcpuc = 0; - /* XXX change when SMP comes */ - stw_p(&sysib.total_cpus, 1); - stw_p(&sysib.conf_cpus, 1); - stw_p(&sysib.standby_cpus, 0); - stw_p(&sysib.reserved_cpus, 0); - ebcdic_put(sysib.name, "QEMU ", 8); - stl_p(&sysib.caf, 1000); - stw_p(&sysib.dedicated_cpus, 0); - stw_p(&sysib.shared_cpus, 0); - cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); - } else { - cc = 3; - } - break; - } - case STSI_LEVEL_3: - { - if ((sel1 == 2) && (sel2 == 2)) { - /* VM CPUs */ - struct sysib_322 sysib; - - memset(&sysib, 0, sizeof(sysib)); - sysib.count = 1; - /* XXX change when SMP comes */ - stw_p(&sysib.vm[0].total_cpus, 1); - stw_p(&sysib.vm[0].conf_cpus, 1); - stw_p(&sysib.vm[0].standby_cpus, 0); - stw_p(&sysib.vm[0].reserved_cpus, 0); - ebcdic_put(sysib.vm[0].name, "KVMguest", 8); - stl_p(&sysib.vm[0].caf, 1000); - ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); - cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); - } else { - cc = 3; - } - break; - } - case STSI_LEVEL_CURRENT: - env->regs[0] = STSI_LEVEL_3; - break; - default: - cc = 3; - break; - } - - return cc; -} - -uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) -{ - int cc = 0; - - HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", - __func__, order_code, r1, cpu_addr); - - /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" - as parameter (input). Status (output) is always R1. */ - - switch (order_code) { - case SIGP_SET_ARCH: - /* switch arch */ - break; - case SIGP_SENSE: - /* enumerate CPU status */ - if (cpu_addr) { - /* XXX implement when SMP comes */ - return 3; - } - env->regs[r1] &= 0xffffffff00000000ULL; - cc = 1; - break; -#if !defined(CONFIG_USER_ONLY) - case SIGP_RESTART: - qemu_system_reset_request(); - cpu_loop_exit(env); - break; - case SIGP_STOP: - qemu_system_shutdown_request(); - cpu_loop_exit(env); - break; -#endif - default: - /* unknown sigp */ - fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); - cc = 3; - } - - return cc; -} -#endif -- cgit v1.2.3 From 449c0d70b6d5692bafd8b028e2a8a4e0ed7076fe Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:36 +0000 Subject: target-s390x: avoid AREG0 for FPU helpers Make FPU helpers take a parameter for CPUState instead of relying on global env. Introduce temporary wrappers for FPU load and store ops. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 1 - target-s390x/cc_helper.c | 4 +- target-s390x/cpu.h | 14 +++- target-s390x/fpu_helper.c | 184 +++++++++++++++++++++++---------------------- target-s390x/helper.h | 126 +++++++++++++++---------------- target-s390x/mem_helper.c | 49 ++++++++++++ target-s390x/translate.c | 70 ++++++++--------- 7 files changed, 257 insertions(+), 191 deletions(-) diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index a87d26fae..7d965e9ca 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -4,7 +4,6 @@ obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) -$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 2ac165962..9c3a2c459 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -473,10 +473,10 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, break; case CC_OP_LTGT_F32: - r = set_cc_f32(src, dst); + r = set_cc_f32(env, src, dst); break; case CC_OP_LTGT_F64: - r = set_cc_f64(src, dst); + r = set_cc_f64(env, src, dst); break; case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 0ccb55182..9b7a2e3ad 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1000,12 +1000,22 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) } /* fpu_helper.c */ -uint32_t set_cc_f32(float32 v1, float32 v2); -uint32_t set_cc_f64(float64 v1, float64 v2); +uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2); +uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2); uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); +/* temporary wrappers */ +uint32_t cpu_ldub_data(CPUS390XState *env, target_ulong ptr); +uint32_t cpu_lduw_data(CPUS390XState *env, target_ulong ptr); +uint32_t cpu_ldl_data(CPUS390XState *env, target_ulong ptr); +uint64_t cpu_ldq_data(CPUS390XState *env, target_ulong ptr); + +void cpu_stb_data(CPUS390XState *env, target_ulong ptr, uint32_t data); +void cpu_stw_data(CPUS390XState *env, target_ulong ptr, uint32_t data); +void cpu_stl_data(CPUS390XState *env, target_ulong ptr, uint32_t data); +void cpu_stq_data(CPUS390XState *env, target_ulong ptr, uint64_t data); #endif diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 1389052f5..e23541922 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -19,10 +19,10 @@ */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" -#if !defined(CONFIG_USER_ONLY) +/* temporarily disabled due to wrapper use */ +#if 0 && !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif @@ -33,7 +33,7 @@ #define HELPER_LOG(x...) #endif -static inline int float_comp_to_cc(int float_compare) +static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) { switch (float_compare) { case float_relation_equal: @@ -50,14 +50,16 @@ static inline int float_comp_to_cc(int float_compare) } /* condition codes for binary FP ops */ -uint32_t set_cc_f32(float32 v1, float32 v2) +uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2) { - return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); + return float_comp_to_cc(env, float32_compare_quiet(v1, v2, + &env->fpu_status)); } -uint32_t set_cc_f64(float64 v1, float64 v2) +uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2) { - return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); + return float_comp_to_cc(env, float64_compare_quiet(v1, v2, + &env->fpu_status)); } /* condition codes for unary FP ops */ @@ -101,14 +103,14 @@ static uint32_t set_cc_nz_f128(float128 v) } /* convert 32-bit int to 64-bit float */ -void HELPER(cdfbr)(uint32_t f1, int32_t v2) +void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) { HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); } /* convert 32-bit int to 128-bit float */ -void HELPER(cxfbr)(uint32_t f1, int32_t v2) +void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) { CPU_QuadU v1; @@ -118,21 +120,21 @@ void HELPER(cxfbr)(uint32_t f1, int32_t v2) } /* convert 64-bit int to 32-bit float */ -void HELPER(cegbr)(uint32_t f1, int64_t v2) +void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2) { HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); } /* convert 64-bit int to 64-bit float */ -void HELPER(cdgbr)(uint32_t f1, int64_t v2) +void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) { HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); } /* convert 64-bit int to 128-bit float */ -void HELPER(cxgbr)(uint32_t f1, int64_t v2) +void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) { CPU_QuadU x1; @@ -144,7 +146,7 @@ void HELPER(cxgbr)(uint32_t f1, int64_t v2) } /* convert 32-bit int to 32-bit float */ -void HELPER(cefbr)(uint32_t f1, int32_t v2) +void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) { env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, @@ -152,7 +154,7 @@ void HELPER(cefbr)(uint32_t f1, int32_t v2) } /* 32-bit FP addition RR */ -uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, env->fregs[f2].l.upper, @@ -164,7 +166,7 @@ uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) } /* 64-bit FP addition RR */ -uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); @@ -175,7 +177,7 @@ uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) } /* 32-bit FP subtraction RR */ -uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, env->fregs[f2].l.upper, @@ -187,7 +189,7 @@ uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) } /* 64-bit FP subtraction RR */ -uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); @@ -198,7 +200,7 @@ uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) } /* 32-bit FP division RR */ -void HELPER(debr)(uint32_t f1, uint32_t f2) +void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, env->fregs[f2].l.upper, @@ -206,7 +208,7 @@ void HELPER(debr)(uint32_t f1, uint32_t f2) } /* 128-bit FP division RR */ -void HELPER(dxbr)(uint32_t f1, uint32_t f2) +void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; @@ -222,14 +224,14 @@ void HELPER(dxbr)(uint32_t f1, uint32_t f2) } /* 64-bit FP multiplication RR */ -void HELPER(mdbr)(uint32_t f1, uint32_t f2) +void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); } /* 128-bit FP multiplication RR */ -void HELPER(mxbr)(uint32_t f1, uint32_t f2) +void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; @@ -245,14 +247,14 @@ void HELPER(mxbr)(uint32_t f1, uint32_t f2) } /* convert 32-bit float to 64-bit float */ -void HELPER(ldebr)(uint32_t r1, uint32_t r2) +void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2) { env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, &env->fpu_status); } /* convert 128-bit float to 64-bit float */ -void HELPER(ldxbr)(uint32_t f1, uint32_t f2) +void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU x2; @@ -263,7 +265,7 @@ void HELPER(ldxbr)(uint32_t f1, uint32_t f2) } /* convert 64-bit float to 128-bit float */ -void HELPER(lxdbr)(uint32_t f1, uint32_t f2) +void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU res; @@ -273,7 +275,7 @@ void HELPER(lxdbr)(uint32_t f1, uint32_t f2) } /* convert 64-bit float to 32-bit float */ -void HELPER(ledbr)(uint32_t f1, uint32_t f2) +void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { float64 d2 = env->fregs[f2].d; @@ -281,7 +283,7 @@ void HELPER(ledbr)(uint32_t f1, uint32_t f2) } /* convert 128-bit float to 32-bit float */ -void HELPER(lexbr)(uint32_t f1, uint32_t f2) +void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU x2; @@ -292,7 +294,7 @@ void HELPER(lexbr)(uint32_t f1, uint32_t f2) } /* absolute value of 32-bit float */ -uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { float32 v1; float32 v2 = env->fregs[f2].d; @@ -303,7 +305,7 @@ uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) } /* absolute value of 64-bit float */ -uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { float64 v1; float64 v2 = env->fregs[f2].d; @@ -314,7 +316,7 @@ uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) } /* absolute value of 128-bit float */ -uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; @@ -328,21 +330,21 @@ uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) } /* load and test 64-bit float */ -uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = env->fregs[f2].d; return set_cc_nz_f64(env->fregs[f1].d); } /* load and test 32-bit float */ -uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].l.upper = env->fregs[f2].l.upper; return set_cc_nz_f32(env->fregs[f1].l.upper); } /* load and test 128-bit float */ -uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU x; @@ -354,7 +356,7 @@ uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) } /* load complement of 32-bit float */ -uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); @@ -362,7 +364,7 @@ uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) } /* load complement of 64-bit float */ -uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_chs(env->fregs[f2].d); @@ -370,7 +372,7 @@ uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) } /* load complement of 128-bit float */ -uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU x1, x2; @@ -383,7 +385,7 @@ uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) } /* 32-bit FP addition RM */ -void HELPER(aeb)(uint32_t f1, uint32_t val) +void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; @@ -395,7 +397,7 @@ void HELPER(aeb)(uint32_t f1, uint32_t val) } /* 32-bit FP division RM */ -void HELPER(deb)(uint32_t f1, uint32_t val) +void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; @@ -407,7 +409,7 @@ void HELPER(deb)(uint32_t f1, uint32_t val) } /* 32-bit FP multiplication RM */ -void HELPER(meeb)(uint32_t f1, uint32_t val) +void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; @@ -419,29 +421,29 @@ void HELPER(meeb)(uint32_t f1, uint32_t val) } /* 32-bit FP compare RR */ -uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { float32 v1 = env->fregs[f1].l.upper; float32 v2 = env->fregs[f2].l.upper; HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, v1, f1, v2); - return set_cc_f32(v1, v2); + return set_cc_f32(env, v1, v2); } /* 64-bit FP compare RR */ -uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { float64 v1 = env->fregs[f1].d; float64 v2 = env->fregs[f2].d; HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, v1, f1, v2); - return set_cc_f64(v1, v2); + return set_cc_f64(env, v1, v2); } /* 128-bit FP compare RR */ -uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; @@ -451,29 +453,29 @@ uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; - return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, + return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q, &env->fpu_status)); } /* 64-bit FP compare RM */ -uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) +uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, f1, v2.d); - return set_cc_f64(v1, v2.d); + return set_cc_f64(env, v1, v2.d); } /* 64-bit FP addition RM */ -uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) +uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, v1, f1, v2.d); env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); @@ -481,7 +483,7 @@ uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) } /* 32-bit FP subtraction RM */ -void HELPER(seb)(uint32_t f1, uint32_t val) +void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val) { float32 v1 = env->fregs[f1].l.upper; CPU_FloatU v2; @@ -491,41 +493,41 @@ void HELPER(seb)(uint32_t f1, uint32_t val) } /* 64-bit FP subtraction RM */ -uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) +uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); return set_cc_nz_f64(v1); } /* 64-bit FP multiplication RM */ -void HELPER(mdb)(uint32_t f1, uint64_t a2) +void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, v1, f1, v2.d); env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); } /* 64-bit FP division RM */ -void HELPER(ddb)(uint32_t f1, uint64_t a2) +void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { float64 v1 = env->fregs[f1].d; CPU_DoubleU v2; - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, v1, f1, v2.d); env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); } -static void set_round_mode(int m3) +static void set_round_mode(CPUS390XState *env, int m3) { switch (m3) { case 0: @@ -553,33 +555,36 @@ static void set_round_mode(int m3) } /* convert 32-bit float to 64-bit int */ -uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) +uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) { float32 v2 = env->fregs[f2].l.upper; - set_round_mode(m3); + set_round_mode(env, m3); env->regs[r1] = float32_to_int64(v2, &env->fpu_status); return set_cc_nz_f32(v2); } /* convert 64-bit float to 64-bit int */ -uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) { float64 v2 = env->fregs[f2].d; - set_round_mode(m3); + set_round_mode(env, m3); env->regs[r1] = float64_to_int64(v2, &env->fpu_status); return set_cc_nz_f64(v2); } /* convert 128-bit float to 64-bit int */ -uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) { CPU_QuadU v2; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; - set_round_mode(m3); + set_round_mode(env, m3); env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); if (float128_is_any_nan(v2.q)) { return 3; @@ -593,29 +598,32 @@ uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) } /* convert 32-bit float to 32-bit int */ -uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) +uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) { float32 v2 = env->fregs[f2].l.upper; - set_round_mode(m3); + set_round_mode(env, m3); env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float32_to_int32(v2, &env->fpu_status); return set_cc_nz_f32(v2); } /* convert 64-bit float to 32-bit int */ -uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) { float64 v2 = env->fregs[f2].d; - set_round_mode(m3); + set_round_mode(env, m3); env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float64_to_int32(v2, &env->fpu_status); return set_cc_nz_f64(v2); } /* convert 128-bit float to 32-bit int */ -uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) { CPU_QuadU v2; @@ -627,19 +635,19 @@ uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) } /* load 32-bit FP zero */ -void HELPER(lzer)(uint32_t f1) +void HELPER(lzer)(CPUS390XState *env, uint32_t f1) { env->fregs[f1].l.upper = float32_zero; } /* load 64-bit FP zero */ -void HELPER(lzdr)(uint32_t f1) +void HELPER(lzdr)(CPUS390XState *env, uint32_t f1) { env->fregs[f1].d = float64_zero; } /* load 128-bit FP zero */ -void HELPER(lzxr)(uint32_t f1) +void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) { CPU_QuadU x; @@ -649,7 +657,7 @@ void HELPER(lzxr)(uint32_t f1) } /* 128-bit FP subtraction RR */ -uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; @@ -666,7 +674,7 @@ uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) } /* 128-bit FP addition RR */ -uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) +uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; @@ -683,7 +691,7 @@ uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) } /* 32-bit FP multiplication RR */ -void HELPER(meebr)(uint32_t f1, uint32_t f2) +void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, env->fregs[f2].l.upper, @@ -691,19 +699,19 @@ void HELPER(meebr)(uint32_t f1, uint32_t f2) } /* 64-bit FP division RR */ -void HELPER(ddbr)(uint32_t f1, uint32_t f2) +void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); } /* 64-bit FP multiply and add RM */ -void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) +void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) { CPU_DoubleU v2; HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); env->fregs[f1].d = float64_add(env->fregs[f1].d, float64_mul(v2.d, env->fregs[f3].d, &env->fpu_status), @@ -711,7 +719,7 @@ void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) } /* 64-bit FP multiply and add RR */ -void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) +void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) { HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, @@ -721,7 +729,7 @@ void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) } /* 64-bit FP multiply and subtract RR */ -void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) +void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) { HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, @@ -731,7 +739,7 @@ void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) } /* 32-bit FP multiply and add RR */ -void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) +void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) { env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, float32_mul(env->fregs[f2].l.upper, @@ -741,29 +749,29 @@ void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) } /* convert 32-bit float to 64-bit float */ -void HELPER(ldeb)(uint32_t f1, uint64_t a2) +void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { uint32_t v2; - v2 = ldl(a2); + v2 = cpu_ldl_data(env, a2); env->fregs[f1].d = float32_to_float64(v2, &env->fpu_status); } /* convert 64-bit float to 128-bit float */ -void HELPER(lxdb)(uint32_t f1, uint64_t a2) +void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { CPU_DoubleU v2; CPU_QuadU v1; - v2.ll = ldq(a2); + v2.ll = cpu_ldq_data(env, a2); v1.q = float64_to_float128(v2.d, &env->fpu_status); env->fregs[f1].ll = v1.ll.upper; env->fregs[f1 + 2].ll = v1.ll.lower; } /* test data class 32-bit */ -uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) +uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) { float32 v1 = env->fregs[f1].l.upper; int neg = float32_is_neg(v1); @@ -785,7 +793,7 @@ uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) } /* test data class 64-bit */ -uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) +uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) { float64 v1 = env->fregs[f1].d; int neg = float64_is_neg(v1); @@ -806,7 +814,7 @@ uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) } /* test data class 128-bit */ -uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) +uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) { CPU_QuadU v1; uint32_t cc = 0; @@ -830,7 +838,7 @@ uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) } /* square root 64-bit RR */ -void HELPER(sqdbr)(uint32_t f1, uint32_t f2) +void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); } diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 01c8d0ea8..af987732f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -45,70 +45,70 @@ DEF_HELPER_3(mvcle, i32, i32, i64, i32) DEF_HELPER_3(clcle, i32, i32, i64, i32) DEF_HELPER_3(slb, i32, i32, i32, i32) DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) -DEF_HELPER_2(cefbr, void, i32, s32) -DEF_HELPER_2(cdfbr, void, i32, s32) -DEF_HELPER_2(cxfbr, void, i32, s32) -DEF_HELPER_2(cegbr, void, i32, s64) -DEF_HELPER_2(cdgbr, void, i32, s64) -DEF_HELPER_2(cxgbr, void, i32, s64) -DEF_HELPER_2(adbr, i32, i32, i32) -DEF_HELPER_2(aebr, i32, i32, i32) -DEF_HELPER_2(sebr, i32, i32, i32) -DEF_HELPER_2(sdbr, i32, i32, i32) -DEF_HELPER_2(debr, void, i32, i32) -DEF_HELPER_2(dxbr, void, i32, i32) -DEF_HELPER_2(mdbr, void, i32, i32) -DEF_HELPER_2(mxbr, void, i32, i32) -DEF_HELPER_2(ldebr, void, i32, i32) -DEF_HELPER_2(ldxbr, void, i32, i32) -DEF_HELPER_2(lxdbr, void, i32, i32) -DEF_HELPER_2(ledbr, void, i32, i32) -DEF_HELPER_2(lexbr, void, i32, i32) -DEF_HELPER_2(lpebr, i32, i32, i32) -DEF_HELPER_2(lpdbr, i32, i32, i32) -DEF_HELPER_2(lpxbr, i32, i32, i32) -DEF_HELPER_2(ltebr, i32, i32, i32) -DEF_HELPER_2(ltdbr, i32, i32, i32) -DEF_HELPER_2(ltxbr, i32, i32, i32) -DEF_HELPER_2(lcebr, i32, i32, i32) -DEF_HELPER_2(lcdbr, i32, i32, i32) -DEF_HELPER_2(lcxbr, i32, i32, i32) -DEF_HELPER_2(aeb, void, i32, i32) -DEF_HELPER_2(deb, void, i32, i32) -DEF_HELPER_2(meeb, void, i32, i32) -DEF_HELPER_2(cdb, i32, i32, i64) -DEF_HELPER_2(adb, i32, i32, i64) -DEF_HELPER_2(seb, void, i32, i32) -DEF_HELPER_2(sdb, i32, i32, i64) -DEF_HELPER_2(mdb, void, i32, i64) -DEF_HELPER_2(ddb, void, i32, i64) -DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_3(cgebr, i32, i32, i32, i32) -DEF_HELPER_3(cgdbr, i32, i32, i32, i32) -DEF_HELPER_3(cgxbr, i32, i32, i32, i32) -DEF_HELPER_1(lzer, void, i32) -DEF_HELPER_1(lzdr, void, i32) -DEF_HELPER_1(lzxr, void, i32) -DEF_HELPER_3(cfebr, i32, i32, i32, i32) -DEF_HELPER_3(cfdbr, i32, i32, i32, i32) -DEF_HELPER_3(cfxbr, i32, i32, i32, i32) -DEF_HELPER_2(axbr, i32, i32, i32) -DEF_HELPER_2(sxbr, i32, i32, i32) -DEF_HELPER_2(meebr, void, i32, i32) -DEF_HELPER_2(ddbr, void, i32, i32) -DEF_HELPER_3(madb, void, i32, i64, i32) -DEF_HELPER_3(maebr, void, i32, i32, i32) -DEF_HELPER_3(madbr, void, i32, i32, i32) -DEF_HELPER_3(msdbr, void, i32, i32, i32) -DEF_HELPER_2(ldeb, void, i32, i64) -DEF_HELPER_2(lxdb, void, i32, i64) -DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64) -DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64) -DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64) +DEF_HELPER_3(cefbr, void, env, i32, s32) +DEF_HELPER_3(cdfbr, void, env, i32, s32) +DEF_HELPER_3(cxfbr, void, env, i32, s32) +DEF_HELPER_3(cegbr, void, env, i32, s64) +DEF_HELPER_3(cdgbr, void, env, i32, s64) +DEF_HELPER_3(cxgbr, void, env, i32, s64) +DEF_HELPER_3(adbr, i32, env, i32, i32) +DEF_HELPER_3(aebr, i32, env, i32, i32) +DEF_HELPER_3(sebr, i32, env, i32, i32) +DEF_HELPER_3(sdbr, i32, env, i32, i32) +DEF_HELPER_3(debr, void, env, i32, i32) +DEF_HELPER_3(dxbr, void, env, i32, i32) +DEF_HELPER_3(mdbr, void, env, i32, i32) +DEF_HELPER_3(mxbr, void, env, i32, i32) +DEF_HELPER_3(ldebr, void, env, i32, i32) +DEF_HELPER_3(ldxbr, void, env, i32, i32) +DEF_HELPER_3(lxdbr, void, env, i32, i32) +DEF_HELPER_3(ledbr, void, env, i32, i32) +DEF_HELPER_3(lexbr, void, env, i32, i32) +DEF_HELPER_3(lpebr, i32, env, i32, i32) +DEF_HELPER_3(lpdbr, i32, env, i32, i32) +DEF_HELPER_3(lpxbr, i32, env, i32, i32) +DEF_HELPER_3(ltebr, i32, env, i32, i32) +DEF_HELPER_3(ltdbr, i32, env, i32, i32) +DEF_HELPER_3(ltxbr, i32, env, i32, i32) +DEF_HELPER_3(lcebr, i32, env, i32, i32) +DEF_HELPER_3(lcdbr, i32, env, i32, i32) +DEF_HELPER_3(lcxbr, i32, env, i32, i32) +DEF_HELPER_3(aeb, void, env, i32, i32) +DEF_HELPER_3(deb, void, env, i32, i32) +DEF_HELPER_3(meeb, void, env, i32, i32) +DEF_HELPER_3(cdb, i32, env, i32, i64) +DEF_HELPER_3(adb, i32, env, i32, i64) +DEF_HELPER_3(seb, void, env, i32, i32) +DEF_HELPER_3(sdb, i32, env, i32, i64) +DEF_HELPER_3(mdb, void, env, i32, i64) +DEF_HELPER_3(ddb, void, env, i32, i64) +DEF_HELPER_FLAGS_3(cebr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) +DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) +DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) +DEF_HELPER_2(lzer, void, env, i32) +DEF_HELPER_2(lzdr, void, env, i32) +DEF_HELPER_2(lzxr, void, env, i32) +DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) +DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) +DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) +DEF_HELPER_3(axbr, i32, env, i32, i32) +DEF_HELPER_3(sxbr, i32, env, i32, i32) +DEF_HELPER_3(meebr, void, env, i32, i32) +DEF_HELPER_3(ddbr, void, env, i32, i32) +DEF_HELPER_4(madb, void, env, i32, i64, i32) +DEF_HELPER_4(maebr, void, env, i32, i32, i32) +DEF_HELPER_4(madbr, void, env, i32, i32, i32) +DEF_HELPER_4(msdbr, void, env, i32, i32, i32) +DEF_HELPER_3(ldeb, void, env, i32, i64) +DEF_HELPER_3(lxdb, void, env, i32, i64) +DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) DEF_HELPER_2(flogr, i32, i32, i64) -DEF_HELPER_2(sqdbr, void, i32, i32) +DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) DEF_HELPER_3(unpk, void, i32, i64, i64) DEF_HELPER_3(tr, void, i32, i64, i64) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index ba05e65cd..3f8b3bab7 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1188,3 +1188,52 @@ uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) } #endif + +/* temporary wrappers */ +#if defined(CONFIG_USER_ONLY) +#define ldub_data(addr) ldub_raw(addr) +#define lduw_data(addr) lduw_raw(addr) +#define ldl_data(addr) ldl_raw(addr) +#define ldq_data(addr) ldq_raw(addr) + +#define stb_data(addr, data) stb_raw(addr, data) +#define stw_data(addr, data) stw_raw(addr, data) +#define stl_data(addr, data) stl_raw(addr, data) +#define stq_data(addr, data) stq_raw(addr, data) +#endif + +#define WRAP_LD(rettype, fn) \ + rettype cpu_ ## fn(CPUS390XState *env1, target_ulong addr) \ + { \ + CPUS390XState *saved_env; \ + rettype ret; \ + \ + saved_env = env; \ + env = env1; \ + ret = fn(addr); \ + env = saved_env; \ + return ret; \ + } + +WRAP_LD(uint32_t, ldub_data) +WRAP_LD(uint32_t, lduw_data) +WRAP_LD(uint32_t, ldl_data) +WRAP_LD(uint64_t, ldq_data) +#undef WRAP_LD + +#define WRAP_ST(datatype, fn) \ + void cpu_ ## fn(CPUS390XState *env1, target_ulong addr, datatype val) \ + { \ + CPUS390XState *saved_env; \ + \ + saved_env = env; \ + env = env1; \ + fn(addr, val); \ + env = saved_env; \ + } + +WRAP_ST(uint32_t, stb_data) +WRAP_ST(uint32_t, stw_data) +WRAP_ST(uint32_t, stl_data) +WRAP_ST(uint64_t, stq_data) +#undef WRAP_ST diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c370df3b6..b1f20718e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2206,11 +2206,11 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, switch (op) { case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_ldeb(tmp_r1, addr); + gen_helper_ldeb(cpu_env, tmp_r1, addr); break; case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_lxdb(tmp_r1, addr); + gen_helper_lxdb(cpu_env, tmp_r1, addr); break; case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ tmp = tcg_temp_new_i64(); @@ -2225,7 +2225,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_aeb(tmp_r1, tmp32); + gen_helper_aeb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); @@ -2238,7 +2238,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_seb(tmp_r1, tmp32); + gen_helper_seb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); @@ -2251,23 +2251,23 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_deb(tmp_r1, tmp32); + gen_helper_deb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_tceb(cc_op, tmp_r1, addr); + gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_tcdb(cc_op, tmp_r1, addr); + gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_tcxb(cc_op, tmp_r1, addr); + gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ @@ -2275,38 +2275,38 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_meeb(tmp_r1, tmp32); + gen_helper_meeb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_cdb(cc_op, tmp_r1, addr); + gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_adb(cc_op, tmp_r1, addr); + gen_helper_adb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_sdb(cc_op, tmp_r1, addr); + gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_mdb(tmp_r1, addr); + gen_helper_mdb(cpu_env, tmp_r1, addr); break; case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_ddb(tmp_r1, addr); + gen_helper_ddb(cpu_env, tmp_r1, addr); break; case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ /* for RXF insns, r1 is R3 and r1b is R1 */ tmp32 = tcg_const_i32(r1b); potential_page_fault(s); - gen_helper_madb(tmp32, addr, tmp_r1); + gen_helper_madb(cpu_env, tmp32, addr, tmp_r1); tcg_temp_free_i32(tmp32); break; default: @@ -3001,14 +3001,14 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) #define FP_HELPER(i) \ tmp32_1 = tcg_const_i32(r1); \ tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i (tmp32_1, tmp32_2); \ + gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \ tcg_temp_free_i32(tmp32_1); \ tcg_temp_free_i32(tmp32_2); #define FP_HELPER_CC(i) \ tmp32_1 = tcg_const_i32(r1); \ tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i (cc_op, tmp32_1, tmp32_2); \ + gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \ set_cc_static(s); \ tcg_temp_free_i32(tmp32_1); \ tcg_temp_free_i32(tmp32_2); @@ -3080,13 +3080,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_3 = tcg_const_i32(r1); switch (op) { case 0xe: - gen_helper_maebr(tmp32_1, tmp32_3, tmp32_2); + gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2); break; case 0x1e: - gen_helper_madbr(tmp32_1, tmp32_3, tmp32_2); + gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); break; case 0x1f: - gen_helper_msdbr(tmp32_1, tmp32_3, tmp32_2); + gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); break; default: tcg_abort(); @@ -3138,17 +3138,17 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) break; case 0x74: /* LZER R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); - gen_helper_lzer(tmp32_1); + gen_helper_lzer(cpu_env, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x75: /* LZDR R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); - gen_helper_lzdr(tmp32_1); + gen_helper_lzdr(cpu_env, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x76: /* LZXR R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); - gen_helper_lzxr(tmp32_1); + gen_helper_lzxr(cpu_env, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x84: /* SFPC R1 [RRE] */ @@ -3169,13 +3169,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_2 = load_reg32(r2); switch (op) { case 0x94: - gen_helper_cefbr(tmp32_1, tmp32_2); + gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2); break; case 0x95: - gen_helper_cdfbr(tmp32_1, tmp32_2); + gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2); break; case 0x96: - gen_helper_cxfbr(tmp32_1, tmp32_2); + gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2); break; default: tcg_abort(); @@ -3191,13 +3191,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_3 = tcg_const_i32(m3); switch (op) { case 0x98: - gen_helper_cfebr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); break; case 0x99: - gen_helper_cfdbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); break; case 0x9a: - gen_helper_cfxbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); break; default: tcg_abort(); @@ -3213,10 +3213,10 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp = load_reg(r2); switch (op) { case 0xa4: - gen_helper_cegbr(tmp32_1, tmp); + gen_helper_cegbr(cpu_env, tmp32_1, tmp); break; case 0xa5: - gen_helper_cdgbr(tmp32_1, tmp); + gen_helper_cdgbr(cpu_env, tmp32_1, tmp); break; default: tcg_abort(); @@ -3227,7 +3227,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) case 0xa6: /* CXGBR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp = load_reg(r2); - gen_helper_cxgbr(tmp32_1, tmp); + gen_helper_cxgbr(cpu_env, tmp32_1, tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; @@ -3235,7 +3235,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); tmp32_3 = tcg_const_i32(m3); - gen_helper_cgebr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3245,7 +3245,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); tmp32_3 = tcg_const_i32(m3); - gen_helper_cgdbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3255,7 +3255,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); tmp32_3 = tcg_const_i32(m3); - gen_helper_cgxbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); -- cgit v1.2.3 From 4fda26a7b0d6ffbb4055ab8b756cd94647f5fd22 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:37 +0000 Subject: target-s390x: avoid AREG0 for integer helpers Make integer helpers take a parameter for CPUState instead of relying on global env. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 1 - target-s390x/helper.h | 10 +++++----- target-s390x/int_helper.c | 12 ++++++------ target-s390x/translate.c | 16 ++++++++-------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 7d965e9ca..7b2c5c107 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -3,7 +3,6 @@ obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o -$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index af987732f..c03cd5934 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -12,8 +12,8 @@ DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) DEF_HELPER_3(clm, i32, i32, i32, i64) DEF_HELPER_3(stcm, void, i32, i32, i64) -DEF_HELPER_2(mlg, void, i32, i64) -DEF_HELPER_2(dlg, void, i32, i64) +DEF_HELPER_3(mlg, void, env, i32, i64) +DEF_HELPER_3(dlg, void, env, i32, i64) DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) @@ -43,8 +43,8 @@ DEF_HELPER_3(stam, void, i32, i64, i32) DEF_HELPER_3(lam, void, i32, i64, i32) DEF_HELPER_3(mvcle, i32, i32, i64, i32) DEF_HELPER_3(clcle, i32, i32, i64, i32) -DEF_HELPER_3(slb, i32, i32, i32, i32) -DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) +DEF_HELPER_4(slb, i32, env, i32, i32, i32) +DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) DEF_HELPER_3(cefbr, void, env, i32, s32) DEF_HELPER_3(cdfbr, void, env, i32, s32) DEF_HELPER_3(cxfbr, void, env, i32, s32) @@ -107,7 +107,7 @@ DEF_HELPER_3(lxdb, void, env, i32, i64) DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64) DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) -DEF_HELPER_2(flogr, i32, i32, i64) +DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) DEF_HELPER_3(unpk, void, i32, i64, i64) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index e2eeb0757..f202a7e1d 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -19,7 +19,6 @@ */ #include "cpu.h" -#include "dyngen-exec.h" #include "host-utils.h" #include "helper.h" @@ -31,7 +30,7 @@ #endif /* 64/64 -> 128 unsigned multiplication */ -void HELPER(mlg)(uint32_t r1, uint64_t v2) +void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) { #if HOST_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ @@ -46,7 +45,7 @@ void HELPER(mlg)(uint32_t r1, uint64_t v2) } /* 128 -> 64/64 unsigned division */ -void HELPER(dlg)(uint32_t r1, uint64_t v2) +void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) { uint64_t divisor = v2; @@ -129,7 +128,7 @@ uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) } /* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) +uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) { uint32_t v1 = env->regs[r1]; uint32_t res = v1 + (~v2) + (cc >> 1); @@ -144,7 +143,8 @@ uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) } /* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) +uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, + uint64_t v1, uint64_t v2) { uint64_t res = v1 + (~v2) + (cc >> 1); @@ -158,7 +158,7 @@ uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) } /* find leftmost one */ -uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) +uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) { uint64_t res = 0; uint64_t ov2 = v2; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b1f20718e..2a61e92f1 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1803,7 +1803,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_mlg(tmp32_1, tmp2); + gen_helper_mlg(cpu_env, tmp32_1, tmp2); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; @@ -1811,7 +1811,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_dlg(tmp32_1, tmp2); + gen_helper_dlg(cpu_env, tmp32_1, tmp2); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; @@ -1837,7 +1837,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); /* XXX possible optimization point */ gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cc_op, tmp32_1, regs[r1], tmp2); + gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2); set_cc_static(s); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); @@ -1917,7 +1917,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tcg_gen_trunc_i64_i32(tmp32_2, tmp2); /* XXX possible optimization point */ gen_op_calc_cc(s); - gen_helper_slb(cc_op, cc_op, tmp32_1, tmp32_2); + gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); @@ -3535,7 +3535,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); - gen_helper_flogr(cc_op, tmp32_1, tmp); + gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -3555,7 +3555,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) case 0x87: /* DLGR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp = load_reg(r2); - gen_helper_dlg(tmp32_1, tmp); + gen_helper_dlg(cpu_env, tmp32_1, tmp); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; @@ -3580,7 +3580,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) tmp2 = load_reg(r2); tmp32_1 = tcg_const_i32(r1); gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cc_op, tmp32_1, tmp, tmp2); + gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -3647,7 +3647,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) tmp32_1 = load_reg32(r2); tmp32_2 = tcg_const_i32(r1); gen_op_calc_cc(s); - gen_helper_slb(cc_op, cc_op, tmp32_2, tmp32_1); + gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); -- cgit v1.2.3 From 932385a367b2c67f1ea7148dcafb013db188cd23 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:38 +0000 Subject: target-s390x: avoid AREG0 for condition code helpers Make condition code helpers take a parameter for CPUState instead of relying on global env. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 1 - target-s390x/cc_helper.c | 11 +++++------ target-s390x/helper.h | 10 +++++----- target-s390x/translate.c | 16 ++++++++-------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 7b2c5c107..736cf331b 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -3,6 +3,5 @@ obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o -$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 9c3a2c459..19ef145da 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -19,7 +19,6 @@ */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" /* #define DEBUG_HELPER */ @@ -500,14 +499,14 @@ uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, return do_calc_cc(env, cc_op, src, dst, vr); } -uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr) +uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, + uint64_t dst, uint64_t vr) { return do_calc_cc(env, cc_op, src, dst, vr); } /* insert psw mask and condition code into r1 */ -void HELPER(ipm)(uint32_t cc, uint32_t r1) +void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1) { uint64_t r = env->regs[r1]; @@ -519,13 +518,13 @@ void HELPER(ipm)(uint32_t cc, uint32_t r1) } #ifndef CONFIG_USER_ONLY -void HELPER(load_psw)(uint64_t mask, uint64_t addr) +void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) { load_psw(env, mask, addr); cpu_loop_exit(env); } -void HELPER(sacf)(uint64_t a1) +void HELPER(sacf)(CPUS390XState *env, uint64_t a1) { HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c03cd5934..876b88e53 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -36,7 +36,7 @@ DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64) DEF_HELPER_3(stcmh, void, i32, i64, i32) DEF_HELPER_3(icmh, i32, i32, i64, i32) -DEF_HELPER_2(ipm, void, i32, i32) +DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) DEF_HELPER_3(stam, void, i32, i64, i32) @@ -115,7 +115,7 @@ DEF_HELPER_3(tr, void, i32, i64, i64) DEF_HELPER_2(servc, i32, i32, i64) DEF_HELPER_3(diag, i64, i32, i64, i64) -DEF_HELPER_2(load_psw, void, i64, i64) +DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_1(program_interrupt, void, i32) DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64) DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64) @@ -139,14 +139,14 @@ DEF_HELPER_2(csp, i32, i32, i32) DEF_HELPER_3(mvcs, i32, i64, i64, i64) DEF_HELPER_3(mvcp, i32, i64, i64, i64) DEF_HELPER_3(sigp, i32, i64, i32, i64) -DEF_HELPER_1(sacf, void, i64) +DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) DEF_HELPER_2(lra, i32, i64, i32) DEF_HELPER_2(stura, void, i64, i32) DEF_HELPER_2(cksm, void, i32, i32) -DEF_HELPER_FLAGS_4(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, - i32, i32, i64, i64, i64) +DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, + i32, env, i32, i64, i64, i64) #include "def-helper.h" diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2a61e92f1..1d8727211 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -722,7 +722,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_NZ_F32: case CC_OP_NZ_F64: /* 1 argument */ - gen_helper_calc_cc(cc_op, local_cc_op, dummy, cc_dst, dummy); + gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; case CC_OP_ICM: case CC_OP_LTGT_32: @@ -735,7 +735,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LTGT_F64: case CC_OP_SLAG: /* 2 arguments */ - gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, dummy); + gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; case CC_OP_ADD_64: case CC_OP_ADDU_64: @@ -746,11 +746,11 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_SUB_32: case CC_OP_SUBU_32: /* 3 arguments */ - gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, cc_vr); + gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); break; case CC_OP_DYNAMIC: /* unknown operation - assume 3 arguments and cc_op in env */ - gen_helper_calc_cc(cc_op, cc_op, cc_src, cc_dst, cc_vr); + gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr); break; default: tcg_abort(); @@ -2628,7 +2628,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) case 0x22: /* IPM R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); gen_op_calc_cc(s); - gen_helper_ipm(cc_op, tmp32_1); + gen_helper_ipm(cpu_env, cc_op, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x41: /* CKSM R1,R2 [RRE] */ @@ -2916,7 +2916,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_sacf(tmp); + gen_helper_sacf(cpu_env, tmp); tcg_temp_free_i64(tmp); /* addressing mode has changed, so end the block */ s->pc += ilc * 2; @@ -2967,7 +2967,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); tcg_gen_addi_i64(tmp, tmp, 8); tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(tmp2, tmp3); + gen_helper_load_psw(cpu_env, tmp2, tmp3); /* we need to keep cc_op intact */ s->is_jmp = DISAS_JUMP; tcg_temp_free_i64(tmp); @@ -4527,7 +4527,7 @@ static void disas_s390_insn(DisasContext *s) tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); tcg_gen_addi_i64(tmp, tmp, 4); tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(tmp2, tmp3); + gen_helper_load_psw(cpu_env, tmp2, tmp3); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); -- cgit v1.2.3 From 089f5c06926105a35df461003ae32b7387ed4236 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:39 +0000 Subject: target-s390x: avoid AREG0 for misc helpers Make misc helpers take a parameter for CPUState instead of relying on global env. Signed-off-by: Blue Swirl [agraf: fix conflict] Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 1 - target-s390x/helper.h | 26 +++++++++++----------- target-s390x/mem_helper.c | 2 +- target-s390x/misc_helper.c | 55 +++++++++++++++++++++++++--------------------- target-s390x/translate.c | 32 +++++++++++++-------------- 5 files changed, 60 insertions(+), 56 deletions(-) diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 736cf331b..156d9469a 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -4,4 +4,3 @@ obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) -$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 876b88e53..f4e0b3737 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,6 +1,6 @@ #include "def-helper.h" -DEF_HELPER_1(exception, void, i32) +DEF_HELPER_2(exception, void, env, i32) DEF_HELPER_3(nc, i32, i32, i64, i64) DEF_HELPER_3(oc, i32, i32, i64, i64) DEF_HELPER_3(xc, i32, i32, i64, i64) @@ -113,20 +113,20 @@ DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) DEF_HELPER_3(unpk, void, i32, i64, i64) DEF_HELPER_3(tr, void, i32, i64, i64) -DEF_HELPER_2(servc, i32, i32, i64) -DEF_HELPER_3(diag, i64, i32, i64, i64) +DEF_HELPER_3(servc, i32, env, i32, i64) +DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_1(program_interrupt, void, i32) -DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64) +DEF_HELPER_FLAGS_2(stidp, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(spx, TCG_CALL_CONST, void, env, i64) DEF_HELPER_FLAGS_1(sck, TCG_CALL_CONST, i32, i64) -DEF_HELPER_1(stck, i32, i64) -DEF_HELPER_1(stcke, i32, i64) -DEF_HELPER_FLAGS_1(sckc, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(stckc, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(spt, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(stpt, TCG_CALL_CONST, void, i64) -DEF_HELPER_3(stsi, i32, i64, i32, i32) +DEF_HELPER_2(stck, i32, env, i64) +DEF_HELPER_2(stcke, i32, env, i64) +DEF_HELPER_FLAGS_2(sckc, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(stckc, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(spt, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(stpt, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_4(stsi, i32, env, i64, i32, i32) DEF_HELPER_3(lctl, void, i32, i64, i32) DEF_HELPER_3(lctlg, void, i32, i64, i32) DEF_HELPER_3(stctl, void, i32, i64, i32) @@ -138,7 +138,7 @@ DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64) DEF_HELPER_2(csp, i32, i32, i32) DEF_HELPER_3(mvcs, i32, i64, i64, i64) DEF_HELPER_3(mvcp, i32, i64, i64, i64) -DEF_HELPER_3(sigp, i32, i64, i32, i64) +DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 3f8b3bab7..52f2602e5 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -595,7 +595,7 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) env->psw.addr = ret - 4; env->int_svc_code = (insn | v1) & 0xff; env->int_svc_ilc = 4; - helper_exception(EXCP_SVC); + helper_exception(env, EXCP_SVC); } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 1d5137f98..ced26c6f1 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "memory.h" #include "cputlb.h" -#include "dyngen-exec.h" #include "host-utils.h" #include "helper.h" #include @@ -32,7 +31,10 @@ #endif #if !defined(CONFIG_USER_ONLY) +/* temporarily disabled due to wrapper use */ +#if 0 #include "softmmu_exec.h" +#endif #include "sysemu.h" #endif @@ -44,7 +46,7 @@ #endif /* raise an exception */ -void HELPER(exception)(uint32_t excp) +void HELPER(exception)(CPUS390XState *env, uint32_t excp) { HELPER_LOG("%s: exception %d\n", __func__, excp); env->exception_index = excp; @@ -112,7 +114,7 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) } /* SCLP service call */ -uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) +uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) { int r; @@ -125,7 +127,8 @@ uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) } /* DIAG */ -uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) +uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, + uint64_t code) { uint64_t r; @@ -155,17 +158,17 @@ uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) } /* Store CPU ID */ -void HELPER(stidp)(uint64_t a1) +void HELPER(stidp)(CPUS390XState *env, uint64_t a1) { - stq(a1, env->cpu_num); + cpu_stq_data(env, a1, env->cpu_num); } /* Set Prefix */ -void HELPER(spx)(uint64_t a1) +void HELPER(spx)(CPUS390XState *env, uint64_t a1) { uint32_t prefix; - prefix = ldl(a1); + prefix = cpu_ldl_data(env, a1); env->psa = prefix & 0xfffff000; qemu_log("prefix: %#x\n", prefix); tlb_flush_page(env, 0); @@ -191,31 +194,31 @@ static inline uint64_t clock_value(CPUS390XState *env) } /* Store Clock */ -uint32_t HELPER(stck)(uint64_t a1) +uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1) { - stq(a1, clock_value(env)); + cpu_stq_data(env, a1, clock_value(env)); return 0; } /* Store Clock Extended */ -uint32_t HELPER(stcke)(uint64_t a1) +uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) { - stb(a1, 0); + cpu_stb_data(env, a1, 0); /* basically the same value as stck */ - stq(a1 + 1, clock_value(env) | env->cpu_num); + cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num); /* more fine grained than stck */ - stq(a1 + 9, 0); + cpu_stq_data(env, a1 + 9, 0); /* XXX programmable fields */ - stw(a1 + 17, 0); + cpu_stw_data(env, a1 + 17, 0); return 0; } /* Set Clock Comparator */ -void HELPER(sckc)(uint64_t a1) +void HELPER(sckc)(CPUS390XState *env, uint64_t a1) { - uint64_t time = ldq(a1); + uint64_t time = cpu_ldq_data(env, a1); if (time == -1ULL) { return; @@ -230,16 +233,16 @@ void HELPER(sckc)(uint64_t a1) } /* Store Clock Comparator */ -void HELPER(stckc)(uint64_t a1) +void HELPER(stckc)(CPUS390XState *env, uint64_t a1) { /* XXX implement */ - stq(a1, 0); + cpu_stq_data(env, a1, 0); } /* Set CPU Timer */ -void HELPER(spt)(uint64_t a1) +void HELPER(spt)(CPUS390XState *env, uint64_t a1) { - uint64_t time = ldq(a1); + uint64_t time = cpu_ldq_data(env, a1); if (time == -1ULL) { return; @@ -252,14 +255,15 @@ void HELPER(spt)(uint64_t a1) } /* Store CPU Timer */ -void HELPER(stpt)(uint64_t a1) +void HELPER(stpt)(CPUS390XState *env, uint64_t a1) { /* XXX implement */ - stq(a1, 0); + cpu_stq_data(env, a1, 0); } /* Store System Information */ -uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) +uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0, + uint32_t r1) { int cc = 0; int sel1, sel2; @@ -384,7 +388,8 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) return cc; } -uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) +uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, + uint64_t cpu_addr) { int cc = 0; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1d8727211..0c61e6334 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -312,7 +312,7 @@ static inline void gen_debug(DisasContext *s) TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); update_psw_addr(s); gen_op_calc_cc(s); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); s->is_jmp = DISAS_EXCP; } @@ -324,7 +324,7 @@ static void gen_illegal_opcode(DisasContext *s, int ilc) TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); update_psw_addr(s); gen_op_calc_cc(s); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); s->is_jmp = DISAS_EXCP; } @@ -377,7 +377,7 @@ static void gen_program_exception(DisasContext *s, int ilc, int code) /* trigger exception */ tmp = tcg_const_i32(EXCP_PGM); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); /* end TB here */ @@ -2712,7 +2712,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stidp(tmp); + gen_helper_stidp(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x04: /* SCK D2(B2) [S] */ @@ -2730,7 +2730,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stck(cc_op, tmp); + gen_helper_stck(cc_op, cpu_env, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); break; @@ -2740,7 +2740,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_sckc(tmp); + gen_helper_sckc(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x07: /* STCKC D2(B2) [S] */ @@ -2749,7 +2749,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stckc(tmp); + gen_helper_stckc(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x08: /* SPT D2(B2) [S] */ @@ -2758,7 +2758,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_spt(tmp); + gen_helper_spt(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x09: /* STPT D2(B2) [S] */ @@ -2767,7 +2767,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stpt(tmp); + gen_helper_stpt(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x0a: /* SPKA D2(B2) [S] */ @@ -2793,7 +2793,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_spx(tmp); + gen_helper_spx(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x11: /* STPX D2(B2) [S] */ @@ -2906,7 +2906,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stcke(cc_op, tmp); + gen_helper_stcke(cc_op, cpu_env, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); break; @@ -2930,7 +2930,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_1 = load_reg32(0); tmp32_2 = load_reg32(1); potential_page_fault(s); - gen_helper_stsi(cc_op, tmp, tmp32_1, tmp32_2); + gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2980,7 +2980,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) potential_page_fault(s); tmp32_1 = load_reg32(r2); tmp = load_reg(r1); - gen_helper_servc(cc_op, tmp32_1, tmp); + gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); @@ -3926,7 +3926,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_3 = tcg_const_i32(EXCP_SVC); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); - gen_helper_exception(tmp32_3); + gen_helper_exception(cpu_env, tmp32_3); s->is_jmp = DISAS_EXCP; tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4543,7 +4543,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(insn & 0xfff); tmp2 = load_reg(2); tmp3 = load_reg(1); - gen_helper_diag(tmp2, tmp32_1, tmp2, tmp3); + gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3); store_reg(2, tmp2); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp2); @@ -4777,7 +4777,7 @@ static void disas_s390_insn(DisasContext *s) tmp2 = load_reg(r3); tmp32_1 = tcg_const_i32(r1); potential_page_fault(s); - gen_helper_sigp(cc_op, tmp, tmp32_1, tmp2); + gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); -- cgit v1.2.3 From 19b0516fb4fd22b08c6ee42ea4162aaf3b9c8ee1 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 2 Sep 2012 07:33:40 +0000 Subject: target-s390x: switch to AREG0 free mode Add an explicit CPUState parameter instead of relying on AREG0. Remove temporary wrappers and switch to AREG0 free mode. Signed-off-by: Blue Swirl [agraf: fix conflicts] Signed-off-by: Alexander Graf --- configure | 2 +- target-s390x/Makefile.objs | 2 - target-s390x/cpu.h | 10 -- target-s390x/fpu_helper.c | 3 +- target-s390x/helper.c | 6 +- target-s390x/helper.h | 78 +++++------ target-s390x/mem_helper.c | 338 ++++++++++++++++++++------------------------- target-s390x/misc_helper.c | 3 - target-s390x/translate.c | 88 ++++++------ 9 files changed, 239 insertions(+), 291 deletions(-) diff --git a/configure b/configure index d97fd8170..a88a4659b 100755 --- a/configure +++ b/configure @@ -3829,7 +3829,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" case "$target_arch2" in - alpha | i386 | or32 | sparc* | x86_64 | xtensa* | ppc*) + alpha | i386 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak ;; esac diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 156d9469a..e728abf75 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -2,5 +2,3 @@ obj-y += translate.o helper.o cpu.o interrupt.o obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o - -$(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 9b7a2e3ad..ed81af33a 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1008,14 +1008,4 @@ uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); -/* temporary wrappers */ -uint32_t cpu_ldub_data(CPUS390XState *env, target_ulong ptr); -uint32_t cpu_lduw_data(CPUS390XState *env, target_ulong ptr); -uint32_t cpu_ldl_data(CPUS390XState *env, target_ulong ptr); -uint64_t cpu_ldq_data(CPUS390XState *env, target_ulong ptr); - -void cpu_stb_data(CPUS390XState *env, target_ulong ptr, uint32_t data); -void cpu_stw_data(CPUS390XState *env, target_ulong ptr, uint32_t data); -void cpu_stl_data(CPUS390XState *env, target_ulong ptr, uint32_t data); -void cpu_stq_data(CPUS390XState *env, target_ulong ptr, uint64_t data); #endif diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index e23541922..ee9420d44 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -21,8 +21,7 @@ #include "cpu.h" #include "helper.h" -/* temporarily disabled due to wrapper use */ -#if 0 && !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif diff --git a/target-s390x/helper.c b/target-s390x/helper.c index d98e6d9dc..a5741ecde 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -499,14 +499,14 @@ static void do_program_interrupt(CPUS390XState *env) switch (ilc) { case ILC_LATER: - ilc = get_ilc(ldub_code(env->psw.addr)); + ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); break; case ILC_LATER_INC: - ilc = get_ilc(ldub_code(env->psw.addr)); + ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); env->psw.addr += ilc * 2; break; case ILC_LATER_INC_2: - ilc = get_ilc(ldub_code(env->psw.addr)) * 2; + ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; env->psw.addr += ilc; break; } diff --git a/target-s390x/helper.h b/target-s390x/helper.h index f4e0b3737..5419f37dc 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,17 +1,17 @@ #include "def-helper.h" DEF_HELPER_2(exception, void, env, i32) -DEF_HELPER_3(nc, i32, i32, i64, i64) -DEF_HELPER_3(oc, i32, i32, i64, i64) -DEF_HELPER_3(xc, i32, i32, i64, i64) -DEF_HELPER_3(mvc, void, i32, i64, i64) -DEF_HELPER_3(clc, i32, i32, i64, i64) -DEF_HELPER_2(mvcl, i32, i32, i32) +DEF_HELPER_4(nc, i32, env, i32, i64, i64) +DEF_HELPER_4(oc, i32, env, i32, i64, i64) +DEF_HELPER_4(xc, i32, env, i32, i64, i64) +DEF_HELPER_4(mvc, void, env, i32, i64, i64) +DEF_HELPER_4(clc, i32, env, i32, i64, i64) +DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) -DEF_HELPER_3(clm, i32, i32, i32, i64) -DEF_HELPER_3(stcm, void, i32, i32, i64) +DEF_HELPER_4(clm, i32, env, i32, i32, i64) +DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_3(mlg, void, env, i32, i64) DEF_HELPER_3(dlg, void, env, i32, i64) DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) @@ -22,27 +22,27 @@ DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s6 DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) -DEF_HELPER_3(srst, i32, i32, i32, i32) -DEF_HELPER_3(clst, i32, i32, i32, i32) -DEF_HELPER_3(mvpg, void, i64, i64, i64) -DEF_HELPER_3(mvst, void, i32, i32, i32) -DEF_HELPER_3(csg, i32, i32, i64, i32) -DEF_HELPER_3(cdsg, i32, i32, i64, i32) -DEF_HELPER_3(cs, i32, i32, i64, i32) -DEF_HELPER_4(ex, i32, i32, i64, i64, i64) +DEF_HELPER_4(srst, i32, env, i32, i32, i32) +DEF_HELPER_4(clst, i32, env, i32, i32, i32) +DEF_HELPER_4(mvpg, void, env, i64, i64, i64) +DEF_HELPER_4(mvst, void, env, i32, i32, i32) +DEF_HELPER_4(csg, i32, env, i32, i64, i32) +DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) +DEF_HELPER_4(cs, i32, env, i32, i64, i32) +DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_PURE|TCG_CALL_CONST, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64) -DEF_HELPER_3(stcmh, void, i32, i64, i32) -DEF_HELPER_3(icmh, i32, i32, i64, i32) +DEF_HELPER_4(stcmh, void, env, i32, i64, i32) +DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) -DEF_HELPER_3(stam, void, i32, i64, i32) -DEF_HELPER_3(lam, void, i32, i64, i32) -DEF_HELPER_3(mvcle, i32, i32, i64, i32) -DEF_HELPER_3(clcle, i32, i32, i64, i32) +DEF_HELPER_4(stam, void, env, i32, i64, i32) +DEF_HELPER_4(lam, void, env, i32, i64, i32) +DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) +DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_4(slb, i32, env, i32, i32, i32) DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) DEF_HELPER_3(cefbr, void, env, i32, s32) @@ -110,8 +110,8 @@ DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) -DEF_HELPER_3(unpk, void, i32, i64, i64) -DEF_HELPER_3(tr, void, i32, i64, i64) +DEF_HELPER_4(unpk, void, env, i32, i64, i64) +DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) @@ -127,24 +127,24 @@ DEF_HELPER_FLAGS_2(stckc, TCG_CALL_CONST, void, env, i64) DEF_HELPER_FLAGS_2(spt, TCG_CALL_CONST, void, env, i64) DEF_HELPER_FLAGS_2(stpt, TCG_CALL_CONST, void, env, i64) DEF_HELPER_4(stsi, i32, env, i64, i32, i32) -DEF_HELPER_3(lctl, void, i32, i64, i32) -DEF_HELPER_3(lctlg, void, i32, i64, i32) -DEF_HELPER_3(stctl, void, i32, i64, i32) -DEF_HELPER_3(stctg, void, i32, i64, i32) +DEF_HELPER_4(lctl, void, env, i32, i64, i32) +DEF_HELPER_4(lctlg, void, env, i32, i64, i32) +DEF_HELPER_4(stctl, void, env, i32, i64, i32) +DEF_HELPER_4(stctg, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_CONST, i32, i64, i64) -DEF_HELPER_FLAGS_1(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64) -DEF_HELPER_FLAGS_2(sske, TCG_CALL_CONST, void, i32, i64) -DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64) -DEF_HELPER_2(csp, i32, i32, i32) -DEF_HELPER_3(mvcs, i32, i64, i64, i64) -DEF_HELPER_3(mvcp, i32, i64, i64, i64) +DEF_HELPER_FLAGS_2(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, env, i64) +DEF_HELPER_FLAGS_3(sske, TCG_CALL_CONST, void, env, i32, i64) +DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_CONST, i32, env, i32, i64) +DEF_HELPER_3(csp, i32, env, i32, i32) +DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) +DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_2(sacf, void, env, i64) -DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) -DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) -DEF_HELPER_2(lra, i32, i64, i32) -DEF_HELPER_2(stura, void, i64, i32) -DEF_HELPER_2(cksm, void, i32, i32) +DEF_HELPER_FLAGS_3(ipte, TCG_CALL_CONST, void, env, i64, i64) +DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_CONST, void, env) +DEF_HELPER_3(lra, i32, env, i64, i32) +DEF_HELPER_3(stura, void, env, i64, i32) +DEF_HELPER_3(cksm, void, env, i32, i32) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, i32, env, i32, i64, i64, i64) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 52f2602e5..b21b37c5e 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -19,7 +19,6 @@ */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" /*****************************************************************************/ @@ -45,15 +44,12 @@ NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, +void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx, uintptr_t retaddr) { TranslationBlock *tb; - CPUS390XState *saved_env; int ret; - saved_env = env; - env = env1; ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); if (unlikely(ret != 0)) { if (likely(retaddr)) { @@ -67,7 +63,6 @@ void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, } cpu_loop_exit(env); } - env = saved_env; } #endif @@ -90,7 +85,7 @@ static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, int flags; if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { - stb(dest, byte); + cpu_stb_data(env, dest, byte); cpu_abort(env, "should never reach here"); } dest_phys |= dest & ~TARGET_PAGE_MASK; @@ -114,13 +109,13 @@ static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, int flags; if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { - stb(dest, 0); + cpu_stb_data(env, dest, 0); cpu_abort(env, "should never reach here"); } dest_phys |= dest & ~TARGET_PAGE_MASK; if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { - ldub(src); + cpu_ldub_data(env, src); cpu_abort(env, "should never reach here"); } src_phys |= src & ~TARGET_PAGE_MASK; @@ -136,7 +131,8 @@ static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, #endif /* and on array */ -uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) +uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) { int i; unsigned char x; @@ -145,17 +141,18 @@ uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); for (i = 0; i <= l; i++) { - x = ldub(dest + i) & ldub(src + i); + x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i); if (x) { cc = 1; } - stb(dest + i, x); + cpu_stb_data(env, dest + i, x); } return cc; } /* xor on array */ -uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) +uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) { int i; unsigned char x; @@ -179,17 +176,18 @@ uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) #endif for (i = 0; i <= l; i++) { - x = ldub(dest + i) ^ ldub(src + i); + x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i); if (x) { cc = 1; } - stb(dest + i, x); + cpu_stb_data(env, dest + i, x); } return cc; } /* or on array */ -uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) +uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) { int i; unsigned char x; @@ -198,17 +196,17 @@ uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); for (i = 0; i <= l; i++) { - x = ldub(dest + i) | ldub(src + i); + x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i); if (x) { cc = 1; } - stb(dest + i, x); + cpu_stb_data(env, dest + i, x); } return cc; } /* memmove */ -void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) +void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) { int i = 0; int x = 0; @@ -222,7 +220,7 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { if (dest == (src + 1)) { - mvc_fast_memset(env, l + 1, dest, ldub(src)); + mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src)); return; } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { mvc_fast_memmove(env, l + 1, dest, src); @@ -231,7 +229,7 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) } #else if (dest == (src + 1)) { - memset(g2h(dest), ldub(src), l + 1); + memset(g2h(dest), cpu_ldub_data(env, src), l + 1); return; } else { memmove(g2h(dest), g2h(src), l + 1); @@ -242,19 +240,19 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) /* handle the parts that fit into 8-byte loads/stores */ if (dest != (src + 1)) { for (i = 0; i < l_64; i++) { - stq(dest + x, ldq(src + x)); + cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x)); x += 8; } } /* slow version crossing pages with byte accesses */ for (i = x; i <= l; i++) { - stb(dest + i, ldub(src + i)); + cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i)); } } /* compare unsigned byte arrays */ -uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) +uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) { int i; unsigned char x, y; @@ -263,8 +261,8 @@ uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", __func__, l, s1, s2); for (i = 0; i <= l; i++) { - x = ldub(s1 + i); - y = ldub(s2 + i); + x = cpu_ldub_data(env, s1 + i); + y = cpu_ldub_data(env, s2 + i); HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); if (x < y) { cc = 1; @@ -281,7 +279,8 @@ uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) } /* compare logical under mask */ -uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) +uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, + uint64_t addr) { uint8_t r, d; uint32_t cc; @@ -291,7 +290,7 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) cc = 0; while (mask) { if (mask & 8) { - d = ldub(addr); + d = cpu_ldub_data(env, addr); r = (r1 & 0xff000000UL) >> 24; HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, addr); @@ -312,7 +311,8 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) } /* store character under mask */ -void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) +void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask, + uint64_t addr) { uint8_t r; @@ -321,7 +321,7 @@ void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) while (mask) { if (mask & 8) { r = (r1 & 0xff000000UL) >> 24; - stb(addr, r); + cpu_stb_data(env, addr, r); HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); addr++; } @@ -331,7 +331,7 @@ void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) HELPER_LOG("\n"); } -static inline uint64_t get_address(int x2, int b2, int d2) +static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) { uint64_t r = d2; @@ -351,7 +351,7 @@ static inline uint64_t get_address(int x2, int b2, int d2) return r; } -static inline uint64_t get_address_31fix(int reg) +static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) { uint64_t r = env->regs[reg]; @@ -364,18 +364,18 @@ static inline uint64_t get_address_31fix(int reg) } /* search string (c is byte to search, r2 is string, r1 end of string) */ -uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) +uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) { uint64_t i; uint32_t cc = 2; - uint64_t str = get_address_31fix(r2); - uint64_t end = get_address_31fix(r1); + uint64_t str = get_address_31fix(env, r2); + uint64_t end = get_address_31fix(env, r1); HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, c, env->regs[r1], env->regs[r2]); for (i = str; i != end; i++) { - if (ldub(i) == c) { + if (cpu_ldub_data(env, i) == c) { env->regs[r1] = i; cc = 1; break; @@ -386,10 +386,10 @@ uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) } /* unsigned string compare (c is string terminator) */ -uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) +uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) { - uint64_t s1 = get_address_31fix(r1); - uint64_t s2 = get_address_31fix(r2); + uint64_t s1 = get_address_31fix(env, r1); + uint64_t s2 = get_address_31fix(env, r2); uint8_t v1, v2; uint32_t cc; @@ -401,8 +401,8 @@ uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) } #endif for (;;) { - v1 = ldub(s1); - v2 = ldub(s2); + v1 = cpu_ldub_data(env, s1); + v2 = cpu_ldub_data(env, s2); if ((v1 == c || v2 == c) || (v1 != v2)) { break; } @@ -422,14 +422,14 @@ uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) } /* move page */ -void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) +void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) { /* XXX missing r0 handling */ #ifdef CONFIG_USER_ONLY int i; for (i = 0; i < TARGET_PAGE_SIZE; i++) { - stb(r1 + i, ldub(r2 + i)); + cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i)); } #else mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); @@ -437,10 +437,10 @@ void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) } /* string copy (c is string terminator) */ -void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) +void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) { - uint64_t dest = get_address_31fix(r1); - uint64_t src = get_address_31fix(r2); + uint64_t dest = get_address_31fix(env, r1); + uint64_t src = get_address_31fix(env, r2); uint8_t v; c = c & 0xff; @@ -451,8 +451,8 @@ void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) } #endif for (;;) { - v = ldub(src); - stb(dest, v); + v = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, v); if (v == c) { break; } @@ -463,15 +463,15 @@ void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) } /* compare and swap 64-bit */ -uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) +uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { /* FIXME: locking? */ uint32_t cc; - uint64_t v2 = ldq(a2); + uint64_t v2 = cpu_ldq_data(env, a2); if (env->regs[r1] == v2) { cc = 0; - stq(a2, env->regs[r3]); + cpu_stq_data(env, a2, env->regs[r3]); } else { cc = 1; env->regs[r1] = v2; @@ -480,19 +480,19 @@ uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) } /* compare double and swap 64-bit */ -uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) +uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { /* FIXME: locking? */ uint32_t cc; - uint64_t v2_hi = ldq(a2); - uint64_t v2_lo = ldq(a2 + 8); + uint64_t v2_hi = cpu_ldq_data(env, a2); + uint64_t v2_lo = cpu_ldq_data(env, a2 + 8); uint64_t v1_hi = env->regs[r1]; uint64_t v1_lo = env->regs[r1 + 1]; if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { cc = 0; - stq(a2, env->regs[r3]); - stq(a2 + 8, env->regs[r3 + 1]); + cpu_stq_data(env, a2, env->regs[r3]); + cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]); } else { cc = 1; env->regs[r1] = v2_hi; @@ -503,16 +503,16 @@ uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) } /* compare and swap 32-bit */ -uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) +uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { /* FIXME: locking? */ uint32_t cc; - uint32_t v2 = ldl(a2); + uint32_t v2 = cpu_ldl_data(env, a2); HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); if (((uint32_t)env->regs[r1]) == v2) { cc = 0; - stl(a2, (uint32_t)env->regs[r3]); + cpu_stl_data(env, a2, (uint32_t)env->regs[r3]); } else { cc = 1; env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; @@ -520,7 +520,8 @@ uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) return cc; } -static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) +static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, + uint32_t mask) { int pos = 24; /* top of the lower half of r1 */ uint64_t rmask = 0xff000000ULL; @@ -531,7 +532,7 @@ static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) while (mask) { if (mask & 8) { env->regs[r1] &= ~rmask; - val = ldub(address); + val = cpu_ldub_data(env, address); if ((val & 0x80) && !ccd) { cc = 1; } @@ -557,9 +558,10 @@ static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) in other words: tricky... currently implemented by interpreting the cases it is most commonly used in */ -uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) +uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, + uint64_t addr, uint64_t ret) { - uint16_t insn = lduw_code(addr); + uint16_t insn = cpu_lduw_code(env, addr); HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, insn); @@ -567,23 +569,27 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) uint32_t l, insn2, b1, b2, d1, d2; l = v1 & 0xff; - insn2 = ldl_code(addr + 2); + insn2 = cpu_ldl_code(env, addr + 2); b1 = (insn2 >> 28) & 0xf; b2 = (insn2 >> 12) & 0xf; d1 = (insn2 >> 16) & 0xfff; d2 = insn2 & 0xfff; switch (insn & 0xf00) { case 0x200: - helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); + helper_mvc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); break; case 0x500: - cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); + cc = helper_clc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); break; case 0x700: - cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); + cc = helper_xc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); break; case 0xc00: - helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); + helper_tr(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); break; default: goto abort; @@ -599,12 +605,12 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; - insn2 = ldl_code(addr + 2); + insn2 = cpu_ldl_code(env, addr + 2); r1 = (insn2 >> 20) & 0xf; r3 = (insn2 >> 16) & 0xf; b2 = (insn2 >> 12) & 0xf; d2 = insn2 & 0xfff; - cc = helper_icm(r1, get_address(0, b2, d2), r3); + cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); } else { abort: cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", @@ -614,13 +620,14 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) } /* store character under mask high operates on the upper half of r1 */ -void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) +void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, + uint32_t mask) { int pos = 56; /* top of the upper half of r1 */ while (mask) { if (mask & 8) { - stb(address, (env->regs[r1] >> pos) & 0xff); + cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff); address++; } mask = (mask << 1) & 0xf; @@ -630,7 +637,8 @@ void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) /* insert character under mask high; same as icm, but operates on the upper half of r1 */ -uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) +uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, + uint32_t mask) { int pos = 56; /* top of the upper half of r1 */ uint64_t rmask = 0xff00000000000000ULL; @@ -641,7 +649,7 @@ uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) while (mask) { if (mask & 8) { env->regs[r1] &= ~rmask; - val = ldub(address); + val = cpu_ldub_data(env, address); if ((val & 0x80) && !ccd) { cc = 1; } @@ -661,12 +669,12 @@ uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) } /* load access registers r1 to r3 from memory at a2 */ -void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) +void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { int i; for (i = r1;; i = (i + 1) % 16) { - env->aregs[i] = ldl(a2); + env->aregs[i] = cpu_ldl_data(env, a2); a2 += 4; if (i == r3) { @@ -676,12 +684,12 @@ void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) } /* store access registers r1 to r3 in memory at a2 */ -void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) +void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { int i; for (i = r1;; i = (i + 1) % 16) { - stl(a2, env->aregs[i]); + cpu_stl_data(env, a2, env->aregs[i]); a2 += 4; if (i == r3) { @@ -691,12 +699,12 @@ void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) } /* move long */ -uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) +uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) { uint64_t destlen = env->regs[r1 + 1] & 0xffffff; - uint64_t dest = get_address_31fix(r1); + uint64_t dest = get_address_31fix(env, r1); uint64_t srclen = env->regs[r2 + 1] & 0xffffff; - uint64_t src = get_address_31fix(r2); + uint64_t src = get_address_31fix(env, r2); uint8_t pad = src >> 24; uint8_t v; uint32_t cc; @@ -714,12 +722,12 @@ uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) } for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = ldub(src); - stb(dest, v); + v = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, v); } for (; destlen; dest++, destlen--) { - stb(dest, pad); + cpu_stb_data(env, dest, pad); } env->regs[r1 + 1] = destlen; @@ -732,7 +740,8 @@ uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) } /* move long extended another memcopy insn with more bells and whistles */ -uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) +uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) { uint64_t destlen = env->regs[r1 + 1]; uint64_t dest = env->regs[r1]; @@ -762,12 +771,12 @@ uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) } for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = ldub(src); - stb(dest, v); + v = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, v); } for (; destlen; dest++, destlen--) { - stb(dest, pad); + cpu_stb_data(env, dest, pad); } env->regs[r1 + 1] = destlen; @@ -781,12 +790,13 @@ uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) } /* compare logical long extended memcompare insn with padding */ -uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) +uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) { uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = get_address_31fix(r1); + uint64_t dest = get_address_31fix(env, r1); uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = get_address_31fix(r3); + uint64_t src = get_address_31fix(env, r3); uint8_t pad = a2 & 0xff; uint8_t v1 = 0, v2 = 0; uint32_t cc = 0; @@ -800,8 +810,8 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) } for (; destlen || srclen; src++, dest++, destlen--, srclen--) { - v1 = srclen ? ldub(src) : pad; - v2 = destlen ? ldub(dest) : pad; + v1 = srclen ? cpu_ldub_data(env, src) : pad; + v2 = destlen ? cpu_ldub_data(env, dest) : pad; if (v1 != v2) { cc = (v1 < v2) ? 1 : 2; break; @@ -818,14 +828,14 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) } /* checksum */ -void HELPER(cksm)(uint32_t r1, uint32_t r2) +void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) { - uint64_t src = get_address_31fix(r2); + uint64_t src = get_address_31fix(env, r2); uint64_t src_len = env->regs[(r2 + 1) & 15]; uint64_t cksm = (uint32_t)env->regs[r1]; while (src_len >= 4) { - cksm += ldl(src); + cksm += cpu_ldl_data(env, src); /* move to next word */ src_len -= 4; @@ -836,14 +846,14 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) case 0: break; case 1: - cksm += ldub(src) << 24; + cksm += cpu_ldub_data(env, src) << 24; break; case 2: - cksm += lduw(src) << 16; + cksm += cpu_lduw_data(env, src) << 16; break; case 3: - cksm += lduw(src) << 16; - cksm += ldub(src + 2) << 8; + cksm += cpu_lduw_data(env, src) << 16; + cksm += cpu_ldub_data(env, src + 2) << 8; break; } @@ -856,7 +866,8 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) ((uint32_t)cksm + (cksm >> 32)); } -void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) +void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, + uint64_t src) { int len_dest = len >> 4; int len_src = len & 0xf; @@ -867,8 +878,8 @@ void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) src += len_src; /* last byte is special, it only flips the nibbles */ - b = ldub(src); - stb(dest, (b << 4) | (b >> 4)); + b = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, (b << 4) | (b >> 4)); src--; len_src--; @@ -878,7 +889,7 @@ void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) uint8_t cur_byte = 0; if (len_src > 0) { - cur_byte = ldub(src); + cur_byte = cpu_ldub_data(env, src); } len_dest--; @@ -897,30 +908,31 @@ void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) /* zone bits */ cur_byte |= 0xf0; - stb(dest, cur_byte); + cpu_stb_data(env, dest, cur_byte); } } -void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) +void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans) { int i; for (i = 0; i <= len; i++) { - uint8_t byte = ldub(array + i); - uint8_t new_byte = ldub(trans + byte); + uint8_t byte = cpu_ldub_data(env, array + i); + uint8_t new_byte = cpu_ldub_data(env, trans + byte); - stb(array + i, new_byte); + cpu_stb_data(env, array + i, new_byte); } } #if !defined(CONFIG_USER_ONLY) -void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) +void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { int i; uint64_t src = a2; for (i = r1;; i = (i + 1) % 16) { - env->cregs[i] = ldq(src); + env->cregs[i] = cpu_ldq_data(env, src); HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", i, src, env->cregs[i]); src += sizeof(uint64_t); @@ -933,13 +945,14 @@ void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) tlb_flush(env, 1); } -void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) +void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { int i; uint64_t src = a2; for (i = r1;; i = (i + 1) % 16) { - env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); + env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | + cpu_ldl_data(env, src); src += sizeof(uint32_t); if (i == r3) { @@ -950,13 +963,13 @@ void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) tlb_flush(env, 1); } -void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) +void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { int i; uint64_t dest = a2; for (i = r1;; i = (i + 1) % 16) { - stq(dest, env->cregs[i]); + cpu_stq_data(env, dest, env->cregs[i]); dest += sizeof(uint64_t); if (i == r3) { @@ -965,13 +978,13 @@ void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) } } -void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) +void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { int i; uint64_t dest = a2; for (i = r1;; i = (i + 1) % 16) { - stl(dest, env->cregs[i]); + cpu_stl_data(env, dest, env->cregs[i]); dest += sizeof(uint32_t); if (i == r3) { @@ -988,9 +1001,9 @@ uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) } /* insert storage key extended */ -uint64_t HELPER(iske)(uint64_t r2) +uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) { - uint64_t addr = get_address(0, 0, r2); + uint64_t addr = get_address(env, 0, 0, r2); if (addr > ram_size) { return 0; @@ -1000,9 +1013,9 @@ uint64_t HELPER(iske)(uint64_t r2) } /* set storage key extended */ -void HELPER(sske)(uint32_t r1, uint64_t r2) +void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) { - uint64_t addr = get_address(0, 0, r2); + uint64_t addr = get_address(env, 0, 0, r2); if (addr > ram_size) { return; @@ -1012,7 +1025,7 @@ void HELPER(sske)(uint32_t r1, uint64_t r2) } /* reset reference bit extended */ -uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) +uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) { uint8_t re; uint8_t key; @@ -1038,15 +1051,15 @@ uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) } /* compare and swap and purge */ -uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) +uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2) { uint32_t cc; uint32_t o1 = env->regs[r1]; - uint64_t a2 = get_address_31fix(r2) & ~3ULL; - uint32_t o2 = ldl(a2); + uint64_t a2 = get_address_31fix(env, r2) & ~3ULL; + uint32_t o2 = cpu_ldl_data(env, a2); if (o1 == o2) { - stl(a2, env->regs[(r1 + 1) & 15]); + cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); if (env->regs[r2] & 0x3) { /* flush TLB / ALB */ tlb_flush(env, 1); @@ -1060,8 +1073,8 @@ uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) return cc; } -static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, - uint64_t mode2) +static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1, + uint64_t mode1, uint64_t a2, uint64_t mode2) { target_ulong src, dest; int flags, cc = 0, i; @@ -1089,7 +1102,7 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, /* XXX be more clever */ if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { - mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); + mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2); break; } stb_phys(dest + i, ldub_phys(src + i)); @@ -1098,24 +1111,24 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, return cc; } -uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) +uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", __func__, l, a1, a2); - return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); + return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); } -uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) +uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", __func__, l, a1, a2); - return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); + return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); } /* invalidate pte */ -void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) +void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr) { uint64_t page = vaddr & TARGET_PAGE_MASK; uint64_t pte = 0; @@ -1141,19 +1154,19 @@ void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) } /* flush local tlb */ -void HELPER(ptlb)(void) +void HELPER(ptlb)(CPUS390XState *env) { tlb_flush(env, 1); } /* store using real address */ -void HELPER(stura)(uint64_t addr, uint32_t v1) +void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) { - stw_phys(get_address(0, 0, addr), v1); + stw_phys(get_address(env, 0, 0, addr), v1); } /* load real address */ -uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) +uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) { uint32_t cc = 0; int old_exc = env->exception_index; @@ -1188,52 +1201,3 @@ uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) } #endif - -/* temporary wrappers */ -#if defined(CONFIG_USER_ONLY) -#define ldub_data(addr) ldub_raw(addr) -#define lduw_data(addr) lduw_raw(addr) -#define ldl_data(addr) ldl_raw(addr) -#define ldq_data(addr) ldq_raw(addr) - -#define stb_data(addr, data) stb_raw(addr, data) -#define stw_data(addr, data) stw_raw(addr, data) -#define stl_data(addr, data) stl_raw(addr, data) -#define stq_data(addr, data) stq_raw(addr, data) -#endif - -#define WRAP_LD(rettype, fn) \ - rettype cpu_ ## fn(CPUS390XState *env1, target_ulong addr) \ - { \ - CPUS390XState *saved_env; \ - rettype ret; \ - \ - saved_env = env; \ - env = env1; \ - ret = fn(addr); \ - env = saved_env; \ - return ret; \ - } - -WRAP_LD(uint32_t, ldub_data) -WRAP_LD(uint32_t, lduw_data) -WRAP_LD(uint32_t, ldl_data) -WRAP_LD(uint64_t, ldq_data) -#undef WRAP_LD - -#define WRAP_ST(datatype, fn) \ - void cpu_ ## fn(CPUS390XState *env1, target_ulong addr, datatype val) \ - { \ - CPUS390XState *saved_env; \ - \ - saved_env = env; \ - env = env1; \ - fn(addr, val); \ - env = saved_env; \ - } - -WRAP_ST(uint32_t, stb_data) -WRAP_ST(uint32_t, stw_data) -WRAP_ST(uint32_t, stl_data) -WRAP_ST(uint64_t, stq_data) -#undef WRAP_ST diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index ced26c6f1..2938ac9c7 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -31,10 +31,7 @@ #endif #if !defined(CONFIG_USER_ONLY) -/* temporarily disabled due to wrapper use */ -#if 0 #include "softmmu_exec.h" -#endif #include "sysemu.h" #endif diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0c61e6334..66119cd12 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -276,19 +276,19 @@ static inline void potential_page_fault(DisasContext *s) static inline uint64_t ld_code2(uint64_t pc) { - return (uint64_t)lduw_code(pc); + return (uint64_t)cpu_lduw_code(cpu_single_env, pc); } static inline uint64_t ld_code4(uint64_t pc) { - return (uint64_t)ldl_code(pc); + return (uint64_t)cpu_ldl_code(cpu_single_env, pc); } static inline uint64_t ld_code6(uint64_t pc) { uint64_t opc; - opc = (uint64_t)lduw_code(pc) << 32; - opc |= (uint64_t)(uint32_t)ldl_code(pc+2); + opc = (uint64_t)cpu_lduw_code(cpu_single_env, pc) << 32; + opc |= (uint64_t)(uint32_t)cpu_ldl_code(cpu_single_env, pc + 2); return opc; } @@ -1263,7 +1263,7 @@ static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) /* Fall back to helper */ vl = tcg_const_i32(l); potential_page_fault(s); - gen_helper_mvc(vl, s1, s2); + gen_helper_mvc(cpu_env, vl, s1, s2); tcg_temp_free_i32(vl); return; } @@ -1455,7 +1455,7 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) potential_page_fault(s); vl = tcg_const_i32(l); - gen_helper_clc(cc_op, vl, s1, s2); + gen_helper_clc(cc_op, cpu_env, vl, s1, s2); tcg_temp_free_i32(vl); set_cc_static(s); } @@ -2094,7 +2094,7 @@ do_mh: tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stcmh(tmp32_1, tmp, tmp32_2); + gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2107,7 +2107,7 @@ do_mh: tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_lctlg(tmp32_1, tmp, tmp32_2); + gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2119,7 +2119,7 @@ do_mh: tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stctg(tmp32_1, tmp, tmp32_2); + gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2131,7 +2131,7 @@ do_mh: tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); /* XXX rewrite in tcg */ - gen_helper_csg(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2143,7 +2143,7 @@ do_mh: tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2183,7 +2183,7 @@ do_mh: tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); /* XXX split CC calculation out */ - gen_helper_icmh(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2635,7 +2635,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_cksm(tmp32_1, tmp32_2); + gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); gen_op_movi_cc(s, 0); @@ -2664,7 +2664,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp2 = load_reg(r1); tmp3 = load_reg(r2); potential_page_fault(s); - gen_helper_mvpg(tmp, tmp2, tmp3); + gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); @@ -2676,7 +2676,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_2 = tcg_const_i32(r1); tmp32_3 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_mvst(tmp32_1, tmp32_2, tmp32_3); + gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); tcg_temp_free_i32(tmp32_3); @@ -2687,7 +2687,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_2 = tcg_const_i32(r1); tmp32_3 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_clst(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2698,7 +2698,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_2 = tcg_const_i32(r1); tmp32_3 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_srst(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2785,7 +2785,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) case 0x0d: /* PTLB [S] */ /* Purge TLB */ check_privileged(s, ilc); - gen_helper_ptlb(); + gen_helper_ptlb(cpu_env); break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ @@ -2828,7 +2828,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp = load_reg(r1); tmp2 = load_reg(r2); - gen_helper_ipte(tmp, tmp2); + gen_helper_ipte(cpu_env, tmp, tmp2); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; @@ -2839,7 +2839,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp = load_reg(r2); tmp2 = tcg_temp_new_i64(); - gen_helper_iske(tmp2, tmp); + gen_helper_iske(tmp2, cpu_env, tmp); store_reg(r1, tmp2); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -2851,7 +2851,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp32_1 = load_reg32(r1); tmp = load_reg(r2); - gen_helper_rrbe(cc_op, tmp32_1, tmp); + gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); @@ -2863,7 +2863,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp32_1 = load_reg32(r1); tmp = load_reg(r2); - gen_helper_sske(tmp32_1, tmp); + gen_helper_sske(cpu_env, tmp32_1, tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; @@ -2880,7 +2880,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_1 = load_reg32(r1); tmp = load_reg(r2); potential_page_fault(s); - gen_helper_stura(tmp, tmp32_1); + gen_helper_stura(cpu_env, tmp, tmp32_1); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; @@ -2891,7 +2891,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); - gen_helper_csp(cc_op, tmp32_1, tmp32_2); + gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3865,7 +3865,7 @@ static void disas_s390_insn(DisasContext *s) int ilc; int l1; - opc = ldub_code(s->pc); + opc = cpu_ldub_code(cpu_single_env, s->pc); LOG_DISAS("opc 0x%x\n", opc); ilc = get_ilc(opc); @@ -3951,7 +3951,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_mvcl(cc_op, tmp32_1, tmp32_2); + gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4165,7 +4165,7 @@ static void disas_s390_insn(DisasContext *s) tmp3 = tcg_const_i64(s->pc + 4); update_psw_addr(s); gen_op_calc_cc(s); - gen_helper_ex(cc_op, cc_op, tmp2, tmp, tmp3); + gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -4694,7 +4694,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_lam(tmp32_1, tmp, tmp32_2); + gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4706,7 +4706,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stam(tmp32_1, tmp, tmp32_2); + gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4732,7 +4732,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_mvcle(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4745,7 +4745,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_clcle(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4789,7 +4789,7 @@ static void disas_s390_insn(DisasContext *s) tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); tmp32_1 = tcg_const_i32(r1); potential_page_fault(s); - gen_helper_lra(cc_op, tmp, tmp32_1); + gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4835,7 +4835,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stctl(tmp32_1, tmp, tmp32_2); + gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4849,7 +4849,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_lctl(tmp32_1, tmp, tmp32_2); + gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4869,7 +4869,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_cs(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4882,7 +4882,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = load_reg32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_clm(cc_op, tmp32_1, tmp32_2, tmp); + gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4895,7 +4895,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = load_reg32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stcm(tmp32_1, tmp32_2, tmp); + gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4992,7 +4992,7 @@ static void disas_s390_insn(DisasContext *s) break; case 0xd4: potential_page_fault(s); - gen_helper_nc(cc_op, vl, tmp, tmp2); + gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xd5: @@ -5000,22 +5000,22 @@ static void disas_s390_insn(DisasContext *s) break; case 0xd6: potential_page_fault(s); - gen_helper_oc(cc_op, vl, tmp, tmp2); + gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xd7: potential_page_fault(s); - gen_helper_xc(cc_op, vl, tmp, tmp2); + gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xdc: potential_page_fault(s); - gen_helper_tr(vl, tmp, tmp2); + gen_helper_tr(cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xf3: potential_page_fault(s); - gen_helper_unpk(vl, tmp, tmp2); + gen_helper_unpk(cpu_env, vl, tmp, tmp2); break; default: tcg_abort(); @@ -5040,9 +5040,9 @@ static void disas_s390_insn(DisasContext *s) tmp2 = get_address(s, 0, b1, d1); tmp3 = get_address(s, 0, b2, d2); if (opc == 0xda) { - gen_helper_mvcp(cc_op, tmp, tmp2, tmp3); + gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3); } else { - gen_helper_mvcs(cc_op, tmp, tmp2, tmp3); + gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3); } set_cc_static(s); tcg_temp_free_i64(tmp); -- cgit v1.2.3 From 6845df48cec9cc6833429942b3ceed333a791119 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 03:45:43 +0000 Subject: tcg/s390: fix ld/st with CONFIG_TCG_PASS_AREG0 The load/store slow path has been broken in e141ab52d: - We need to move 4 registers for store functions and 3 registers for load functions and not the reverse. - According to the s390x calling convention the arguments of a function should be zero extended. This means that the register shift should be done with TCG_TYPE_I64 to ensure the higher word is correctly zero extended when needed. I am aware that CONFIG_TCG_PASS_AREG0 is being removed and thus that this patch can be improved, but doing so means it can also be applied to the 1.1 and 1.2 stable branches. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- tcg/s390/tcg-target.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 04662c15f..99b53390c 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -1509,11 +1509,13 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index); #ifdef CONFIG_TCG_PASS_AREG0 /* XXX/FIXME: suboptimal */ - tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], tcg_target_call_iarg_regs[1]); - tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], tcg_target_call_iarg_regs[0]); - tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); #endif tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]); @@ -1521,13 +1523,11 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); #ifdef CONFIG_TCG_PASS_AREG0 /* XXX/FIXME: suboptimal */ - tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], - tcg_target_call_iarg_regs[2]); tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], tcg_target_call_iarg_regs[1]); - tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], tcg_target_call_iarg_regs[0]); - tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); #endif tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]); -- cgit v1.2.3 From cc57407e966e8467f9742e7a4ad47567b5951122 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 27 Aug 2012 08:28:38 +0200 Subject: kvm: Introduce kvm_irqchip_update_msi_route This service allows to update an MSI route without releasing/reacquiring the associated VIRQ. Will be used by PCI device assignment, later on likely also by virtio/vhost and VFIO. Signed-off-by: Jan Kiszka Acked-by: Acked-by: Michael S. Tsirkin Signed-off-by: Avi Kivity --- kvm-all.c | 42 ++++++++++++++++++++++++++++++++++++++++++ kvm.h | 1 + 2 files changed, 43 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index f96be2103..e2abfb98d 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -963,6 +963,30 @@ static void kvm_add_routing_entry(KVMState *s, kvm_irqchip_commit_routes(s); } +static int kvm_update_routing_entry(KVMState *s, + struct kvm_irq_routing_entry *new_entry) +{ + struct kvm_irq_routing_entry *entry; + int n; + + for (n = 0; n < s->irq_routes->nr; n++) { + entry = &s->irq_routes->entries[n]; + if (entry->gsi != new_entry->gsi) { + continue; + } + + entry->type = new_entry->type; + entry->flags = new_entry->flags; + entry->u = new_entry->u; + + kvm_irqchip_commit_routes(s); + + return 0; + } + + return -ESRCH; +} + void kvm_irqchip_add_irq_route(KVMState *s, int irq, int irqchip, int pin) { struct kvm_irq_routing_entry e; @@ -1125,6 +1149,24 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) return virq; } +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) +{ + struct kvm_irq_routing_entry kroute; + + if (!kvm_irqchip_in_kernel()) { + return -ENOSYS; + } + + kroute.gsi = virq; + kroute.type = KVM_IRQ_ROUTING_MSI; + kroute.flags = 0; + kroute.u.msi.address_lo = (uint32_t)msg.address; + kroute.u.msi.address_hi = msg.address >> 32; + kroute.u.msi.data = msg.data; + + return kvm_update_routing_entry(s, &kroute); +} + static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) { struct kvm_irqfd irqfd = { diff --git a/kvm.h b/kvm.h index 37d1f8166..5cefe3a1a 100644 --- a/kvm.h +++ b/kvm.h @@ -270,6 +270,7 @@ int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign, int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign); int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg); +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg); void kvm_irqchip_release_virq(KVMState *s, int virq); int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq); -- cgit v1.2.3 From 3ab73842446a9f2d9d78b23daa43ff382679eece Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 27 Aug 2012 08:28:39 +0200 Subject: kvm: Introduce kvm_has_intx_set_mask Will be used by PCI device assignment code. Signed-off-by: Jan Kiszka Acked-by: Acked-by: Michael S. Tsirkin Signed-off-by: Avi Kivity --- kvm-all.c | 8 ++++++++ kvm.h | 1 + 2 files changed, 9 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index e2abfb98d..39cff55f5 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -88,6 +88,7 @@ struct KVMState int pit_state2; int xsave, xcrs; int many_ioeventfds; + int intx_set_mask; /* The man page (and posix) say ioctl numbers are signed int, but * they're not. Linux, glibc and *BSD all treat ioctl numbers as * unsigned, and treating them as signed here can break things */ @@ -1386,6 +1387,8 @@ int kvm_init(void) s->direct_msi = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0); #endif + s->intx_set_mask = kvm_check_extension(s, KVM_CAP_PCI_2_3); + ret = kvm_arch_init(s); if (ret < 0) { goto err; @@ -1740,6 +1743,11 @@ int kvm_has_gsi_routing(void) #endif } +int kvm_has_intx_set_mask(void) +{ + return kvm_state->intx_set_mask; +} + void *kvm_vmalloc(ram_addr_t size) { #ifdef TARGET_S390X diff --git a/kvm.h b/kvm.h index 5cefe3a1a..dea2998fd 100644 --- a/kvm.h +++ b/kvm.h @@ -117,6 +117,7 @@ int kvm_has_xcrs(void); int kvm_has_pit_state2(void); int kvm_has_many_ioeventfds(void); int kvm_has_gsi_routing(void); +int kvm_has_intx_set_mask(void); #ifdef NEED_CPU_H int kvm_init_vcpu(CPUArchState *env); -- cgit v1.2.3 From b139bd300f4f579c526d153efa4960c380e2b6e3 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 27 Aug 2012 08:28:40 +0200 Subject: kvm: i386: Add services required for PCI device assignment These helpers abstract the interaction of upcoming pci-assign with the KVM kernel services. Put them under i386 only as other archs will implement device pass-through via VFIO and not this classic interface. Signed-off-by: Jan Kiszka Acked-by: Acked-by: Michael S. Tsirkin Signed-off-by: Avi Kivity --- target-i386/kvm.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/kvm_i386.h | 22 ++++++++ 2 files changed, 163 insertions(+) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ffc294ec3..6790180b0 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -31,6 +31,7 @@ #include "hw/apic.h" #include "ioport.h" #include "hyperv.h" +#include "hw/pci.h" //#define DEBUG_KVM @@ -2068,3 +2069,143 @@ void kvm_arch_init_irq_routing(KVMState *s) kvm_msi_via_irqfd_allowed = true; kvm_gsi_routing_allowed = true; } + +/* Classic KVM device assignment interface. Will remain x86 only. */ +int kvm_device_pci_assign(KVMState *s, PCIHostDeviceAddress *dev_addr, + uint32_t flags, uint32_t *dev_id) +{ + struct kvm_assigned_pci_dev dev_data = { + .segnr = dev_addr->domain, + .busnr = dev_addr->bus, + .devfn = PCI_DEVFN(dev_addr->slot, dev_addr->function), + .flags = flags, + }; + int ret; + + dev_data.assigned_dev_id = + (dev_addr->domain << 16) | (dev_addr->bus << 8) | dev_data.devfn; + + ret = kvm_vm_ioctl(s, KVM_ASSIGN_PCI_DEVICE, &dev_data); + if (ret < 0) { + return ret; + } + + *dev_id = dev_data.assigned_dev_id; + + return 0; +} + +int kvm_device_pci_deassign(KVMState *s, uint32_t dev_id) +{ + struct kvm_assigned_pci_dev dev_data = { + .assigned_dev_id = dev_id, + }; + + return kvm_vm_ioctl(s, KVM_DEASSIGN_PCI_DEVICE, &dev_data); +} + +static int kvm_assign_irq_internal(KVMState *s, uint32_t dev_id, + uint32_t irq_type, uint32_t guest_irq) +{ + struct kvm_assigned_irq assigned_irq = { + .assigned_dev_id = dev_id, + .guest_irq = guest_irq, + .flags = irq_type, + }; + + if (kvm_check_extension(s, KVM_CAP_ASSIGN_DEV_IRQ)) { + return kvm_vm_ioctl(s, KVM_ASSIGN_DEV_IRQ, &assigned_irq); + } else { + return kvm_vm_ioctl(s, KVM_ASSIGN_IRQ, &assigned_irq); + } +} + +int kvm_device_intx_assign(KVMState *s, uint32_t dev_id, bool use_host_msi, + uint32_t guest_irq) +{ + uint32_t irq_type = KVM_DEV_IRQ_GUEST_INTX | + (use_host_msi ? KVM_DEV_IRQ_HOST_MSI : KVM_DEV_IRQ_HOST_INTX); + + return kvm_assign_irq_internal(s, dev_id, irq_type, guest_irq); +} + +int kvm_device_intx_set_mask(KVMState *s, uint32_t dev_id, bool masked) +{ + struct kvm_assigned_pci_dev dev_data = { + .assigned_dev_id = dev_id, + .flags = masked ? KVM_DEV_ASSIGN_MASK_INTX : 0, + }; + + return kvm_vm_ioctl(s, KVM_ASSIGN_SET_INTX_MASK, &dev_data); +} + +static int kvm_deassign_irq_internal(KVMState *s, uint32_t dev_id, + uint32_t type) +{ + struct kvm_assigned_irq assigned_irq = { + .assigned_dev_id = dev_id, + .flags = type, + }; + + return kvm_vm_ioctl(s, KVM_DEASSIGN_DEV_IRQ, &assigned_irq); +} + +int kvm_device_intx_deassign(KVMState *s, uint32_t dev_id, bool use_host_msi) +{ + return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_INTX | + (use_host_msi ? KVM_DEV_IRQ_HOST_MSI : KVM_DEV_IRQ_HOST_INTX)); +} + +int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, int virq) +{ + return kvm_assign_irq_internal(s, dev_id, KVM_DEV_IRQ_HOST_MSI | + KVM_DEV_IRQ_GUEST_MSI, virq); +} + +int kvm_device_msi_deassign(KVMState *s, uint32_t dev_id) +{ + return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_MSI | + KVM_DEV_IRQ_HOST_MSI); +} + +bool kvm_device_msix_supported(KVMState *s) +{ + /* The kernel lacks a corresponding KVM_CAP, so we probe by calling + * KVM_ASSIGN_SET_MSIX_NR with an invalid parameter. */ + return kvm_vm_ioctl(s, KVM_ASSIGN_SET_MSIX_NR, NULL) == -EFAULT; +} + +int kvm_device_msix_init_vectors(KVMState *s, uint32_t dev_id, + uint32_t nr_vectors) +{ + struct kvm_assigned_msix_nr msix_nr = { + .assigned_dev_id = dev_id, + .entry_nr = nr_vectors, + }; + + return kvm_vm_ioctl(s, KVM_ASSIGN_SET_MSIX_NR, &msix_nr); +} + +int kvm_device_msix_set_vector(KVMState *s, uint32_t dev_id, uint32_t vector, + int virq) +{ + struct kvm_assigned_msix_entry msix_entry = { + .assigned_dev_id = dev_id, + .gsi = virq, + .entry = vector, + }; + + return kvm_vm_ioctl(s, KVM_ASSIGN_SET_MSIX_ENTRY, &msix_entry); +} + +int kvm_device_msix_assign(KVMState *s, uint32_t dev_id) +{ + return kvm_assign_irq_internal(s, dev_id, KVM_DEV_IRQ_HOST_MSIX | + KVM_DEV_IRQ_GUEST_MSIX, 0); +} + +int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id) +{ + return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_MSIX | + KVM_DEV_IRQ_HOST_MSIX); +} diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h index b82bbf401..f6ab82f93 100644 --- a/target-i386/kvm_i386.h +++ b/target-i386/kvm_i386.h @@ -11,6 +11,28 @@ #ifndef QEMU_KVM_I386_H #define QEMU_KVM_I386_H +#include "kvm.h" + bool kvm_allows_irq0_override(void); +int kvm_device_pci_assign(KVMState *s, PCIHostDeviceAddress *dev_addr, + uint32_t flags, uint32_t *dev_id); +int kvm_device_pci_deassign(KVMState *s, uint32_t dev_id); + +int kvm_device_intx_assign(KVMState *s, uint32_t dev_id, + bool use_host_msi, uint32_t guest_irq); +int kvm_device_intx_set_mask(KVMState *s, uint32_t dev_id, bool masked); +int kvm_device_intx_deassign(KVMState *s, uint32_t dev_id, bool use_host_msi); + +int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, int virq); +int kvm_device_msi_deassign(KVMState *s, uint32_t dev_id); + +bool kvm_device_msix_supported(KVMState *s); +int kvm_device_msix_init_vectors(KVMState *s, uint32_t dev_id, + uint32_t nr_vectors); +int kvm_device_msix_set_vector(KVMState *s, uint32_t dev_id, uint32_t vector, + int virq); +int kvm_device_msix_assign(KVMState *s, uint32_t dev_id); +int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id); + #endif -- cgit v1.2.3 From c3ebd3ba786e1be5449527e47001eded6b59322b Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 30 Aug 2012 20:30:00 +0200 Subject: kvm: i386: Add classic PCI device assignment This adds PCI device assignment for i386 targets using the classic KVM interfaces. This version is 100% identical to what is being maintained in qemu-kvm for several years and is supported by libvirt as well. It is expected to remain relevant for another couple of years until kernels without full-features and performance-wise equivalent VFIO support are obsolete. A refactoring to-do that should be done in-tree is to model MSI and MSI-X support via the generic PCI layer, similar to what VFIO is already doing for MSI-X. This should improve the correctness and clean up the code from duplicate logic. Signed-off-by: Jan Kiszka Acked-by: Acked-by: Michael S. Tsirkin Signed-off-by: Avi Kivity --- hw/kvm/Makefile.objs | 2 +- hw/kvm/pci-assign.c | 1915 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/qdev-monitor.c | 1 + 3 files changed, 1917 insertions(+), 1 deletion(-) create mode 100644 hw/kvm/pci-assign.c diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs index 226497a58..f620d7ff8 100644 --- a/hw/kvm/Makefile.objs +++ b/hw/kvm/Makefile.objs @@ -1 +1 @@ -obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c new file mode 100644 index 000000000..05b93d9a5 --- /dev/null +++ b/hw/kvm/pci-assign.c @@ -0,0 +1,1915 @@ +/* + * Copyright (c) 2007, Neocleus Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * + * Assign a PCI device from the host to a guest VM. + * + * This implementation uses the classic device assignment interface of KVM + * and is only available on x86 hosts. It is expected to be obsoleted by VFIO + * based device assignment. + * + * Adapted for KVM (qemu-kvm) by Qumranet. QEMU version was based on qemu-kvm + * revision 4144fe9d48. See its repository for the history. + * + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ +#include +#include +#include +#include +#include +#include +#include "hw/hw.h" +#include "hw/pc.h" +#include "qemu-error.h" +#include "console.h" +#include "hw/loader.h" +#include "monitor.h" +#include "range.h" +#include "sysemu.h" +#include "hw/pci.h" +#include "hw/msi.h" +#include "kvm_i386.h" + +#define MSIX_PAGE_SIZE 0x1000 + +/* From linux/ioport.h */ +#define IORESOURCE_IO 0x00000100 /* Resource type */ +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 +#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */ + +//#define DEVICE_ASSIGNMENT_DEBUG + +#ifdef DEVICE_ASSIGNMENT_DEBUG +#define DEBUG(fmt, ...) \ + do { \ + fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__); \ + } while (0) +#else +#define DEBUG(fmt, ...) +#endif + +typedef struct PCIRegion { + int type; /* Memory or port I/O */ + int valid; + uint64_t base_addr; + uint64_t size; /* size of the region */ + int resource_fd; +} PCIRegion; + +typedef struct PCIDevRegions { + uint8_t bus, dev, func; /* Bus inside domain, device and function */ + int irq; /* IRQ number */ + uint16_t region_number; /* number of active regions */ + + /* Port I/O or MMIO Regions */ + PCIRegion regions[PCI_NUM_REGIONS - 1]; + int config_fd; +} PCIDevRegions; + +typedef struct AssignedDevRegion { + MemoryRegion container; + MemoryRegion real_iomem; + union { + uint8_t *r_virtbase; /* mmapped access address for memory regions */ + uint32_t r_baseport; /* the base guest port for I/O regions */ + } u; + pcibus_t e_size; /* emulated size of region in bytes */ + pcibus_t r_size; /* real size of region in bytes */ + PCIRegion *region; +} AssignedDevRegion; + +#define ASSIGNED_DEVICE_PREFER_MSI_BIT 0 +#define ASSIGNED_DEVICE_SHARE_INTX_BIT 1 + +#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT) +#define ASSIGNED_DEVICE_SHARE_INTX_MASK (1 << ASSIGNED_DEVICE_SHARE_INTX_BIT) + +typedef struct MSIXTableEntry { + uint32_t addr_lo; + uint32_t addr_hi; + uint32_t data; + uint32_t ctrl; +} MSIXTableEntry; + +typedef enum AssignedIRQType { + ASSIGNED_IRQ_NONE = 0, + ASSIGNED_IRQ_INTX_HOST_INTX, + ASSIGNED_IRQ_INTX_HOST_MSI, + ASSIGNED_IRQ_MSI, + ASSIGNED_IRQ_MSIX +} AssignedIRQType; + +typedef struct AssignedDevice { + PCIDevice dev; + PCIHostDeviceAddress host; + uint32_t dev_id; + uint32_t features; + int intpin; + AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1]; + PCIDevRegions real_device; + PCIINTxRoute intx_route; + AssignedIRQType assigned_irq_type; + struct { +#define ASSIGNED_DEVICE_CAP_MSI (1 << 0) +#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1) + uint32_t available; +#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0) +#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1) +#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2) + uint32_t state; + } cap; + uint8_t emulate_config_read[PCI_CONFIG_SPACE_SIZE]; + uint8_t emulate_config_write[PCI_CONFIG_SPACE_SIZE]; + int msi_virq_nr; + int *msi_virq; + MSIXTableEntry *msix_table; + target_phys_addr_t msix_table_addr; + uint16_t msix_max; + MemoryRegion mmio; + char *configfd_name; + int32_t bootindex; +} AssignedDevice; + +static void assigned_dev_update_irq_routing(PCIDevice *dev); + +static void assigned_dev_load_option_rom(AssignedDevice *dev); + +static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev); + +static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region, + target_phys_addr_t addr, int size, + uint64_t *data) +{ + uint64_t val = 0; + int fd = dev_region->region->resource_fd; + + if (fd >= 0) { + if (data) { + DEBUG("pwrite data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", addr="TARGET_FMT_plx"\n", *data, size, addr, addr); + if (pwrite(fd, data, size, addr) != size) { + error_report("%s - pwrite failed %s", + __func__, strerror(errno)); + } + } else { + if (pread(fd, &val, size, addr) != size) { + error_report("%s - pread failed %s", + __func__, strerror(errno)); + val = (1UL << (size * 8)) - 1; + } + DEBUG("pread val=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", addr=" TARGET_FMT_plx "\n", val, size, addr, addr); + } + } else { + uint32_t port = addr + dev_region->u.r_baseport; + + if (data) { + DEBUG("out data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", host=%x\n", *data, size, addr, port); + switch (size) { + case 1: + outb(*data, port); + break; + case 2: + outw(*data, port); + break; + case 4: + outl(*data, port); + break; + } + } else { + switch (size) { + case 1: + val = inb(port); + break; + case 2: + val = inw(port); + break; + case 4: + val = inl(port); + break; + } + DEBUG("in data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", host=%x\n", val, size, addr, port); + } + } + return val; +} + +static void assigned_dev_ioport_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + assigned_dev_ioport_rw(opaque, addr, size, &data); +} + +static uint64_t assigned_dev_ioport_read(void *opaque, + target_phys_addr_t addr, unsigned size) +{ + return assigned_dev_ioport_rw(opaque, addr, size, NULL); +} + +static uint32_t slow_bar_readb(void *opaque, target_phys_addr_t addr) +{ + AssignedDevRegion *d = opaque; + uint8_t *in = d->u.r_virtbase + addr; + uint32_t r; + + r = *in; + DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r); + + return r; +} + +static uint32_t slow_bar_readw(void *opaque, target_phys_addr_t addr) +{ + AssignedDevRegion *d = opaque; + uint16_t *in = (uint16_t *)(d->u.r_virtbase + addr); + uint32_t r; + + r = *in; + DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r); + + return r; +} + +static uint32_t slow_bar_readl(void *opaque, target_phys_addr_t addr) +{ + AssignedDevRegion *d = opaque; + uint32_t *in = (uint32_t *)(d->u.r_virtbase + addr); + uint32_t r; + + r = *in; + DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r); + + return r; +} + +static void slow_bar_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + AssignedDevRegion *d = opaque; + uint8_t *out = d->u.r_virtbase + addr; + + DEBUG("slow_bar_writeb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, val); + *out = val; +} + +static void slow_bar_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + AssignedDevRegion *d = opaque; + uint16_t *out = (uint16_t *)(d->u.r_virtbase + addr); + + DEBUG("slow_bar_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, val); + *out = val; +} + +static void slow_bar_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + AssignedDevRegion *d = opaque; + uint32_t *out = (uint32_t *)(d->u.r_virtbase + addr); + + DEBUG("slow_bar_writel addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, val); + *out = val; +} + +static const MemoryRegionOps slow_bar_ops = { + .old_mmio = { + .read = { slow_bar_readb, slow_bar_readw, slow_bar_readl, }, + .write = { slow_bar_writeb, slow_bar_writew, slow_bar_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void assigned_dev_iomem_setup(PCIDevice *pci_dev, int region_num, + pcibus_t e_size) +{ + AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + AssignedDevRegion *region = &r_dev->v_addrs[region_num]; + PCIRegion *real_region = &r_dev->real_device.regions[region_num]; + + if (e_size > 0) { + memory_region_init(®ion->container, "assigned-dev-container", + e_size); + memory_region_add_subregion(®ion->container, 0, ®ion->real_iomem); + + /* deal with MSI-X MMIO page */ + if (real_region->base_addr <= r_dev->msix_table_addr && + real_region->base_addr + real_region->size > + r_dev->msix_table_addr) { + uint64_t offset = r_dev->msix_table_addr - real_region->base_addr; + + memory_region_add_subregion_overlap(®ion->container, + offset, + &r_dev->mmio, + 1); + } + } +} + +static const MemoryRegionOps assigned_dev_ioport_ops = { + .read = assigned_dev_ioport_read, + .write = assigned_dev_ioport_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void assigned_dev_ioport_setup(PCIDevice *pci_dev, int region_num, + pcibus_t size) +{ + AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + AssignedDevRegion *region = &r_dev->v_addrs[region_num]; + + region->e_size = size; + memory_region_init(®ion->container, "assigned-dev-container", size); + memory_region_init_io(®ion->real_iomem, &assigned_dev_ioport_ops, + r_dev->v_addrs + region_num, + "assigned-dev-iomem", size); + memory_region_add_subregion(®ion->container, 0, ®ion->real_iomem); +} + +static uint32_t assigned_dev_pci_read(PCIDevice *d, int pos, int len) +{ + AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d); + uint32_t val; + ssize_t ret; + int fd = pci_dev->real_device.config_fd; + +again: + ret = pread(fd, &val, len, pos); + if (ret != len) { + if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) { + goto again; + } + + hw_error("pci read failed, ret = %zd errno = %d\n", ret, errno); + } + + return val; +} + +static uint8_t assigned_dev_pci_read_byte(PCIDevice *d, int pos) +{ + return (uint8_t)assigned_dev_pci_read(d, pos, 1); +} + +static void assigned_dev_pci_write(PCIDevice *d, int pos, uint32_t val, int len) +{ + AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d); + ssize_t ret; + int fd = pci_dev->real_device.config_fd; + +again: + ret = pwrite(fd, &val, len, pos); + if (ret != len) { + if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) { + goto again; + } + + hw_error("pci write failed, ret = %zd errno = %d\n", ret, errno); + } +} + +static void assigned_dev_emulate_config_read(AssignedDevice *dev, + uint32_t offset, uint32_t len) +{ + memset(dev->emulate_config_read + offset, 0xff, len); +} + +static void assigned_dev_direct_config_read(AssignedDevice *dev, + uint32_t offset, uint32_t len) +{ + memset(dev->emulate_config_read + offset, 0, len); +} + +static void assigned_dev_direct_config_write(AssignedDevice *dev, + uint32_t offset, uint32_t len) +{ + memset(dev->emulate_config_write + offset, 0, len); +} + +static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start) +{ + int id; + int max_cap = 48; + int pos = start ? start : PCI_CAPABILITY_LIST; + int status; + + status = assigned_dev_pci_read_byte(d, PCI_STATUS); + if ((status & PCI_STATUS_CAP_LIST) == 0) { + return 0; + } + + while (max_cap--) { + pos = assigned_dev_pci_read_byte(d, pos); + if (pos < 0x40) { + break; + } + + pos &= ~3; + id = assigned_dev_pci_read_byte(d, pos + PCI_CAP_LIST_ID); + + if (id == 0xff) { + break; + } + if (id == cap) { + return pos; + } + + pos += PCI_CAP_LIST_NEXT; + } + return 0; +} + +static int assigned_dev_register_regions(PCIRegion *io_regions, + unsigned long regions_num, + AssignedDevice *pci_dev) +{ + uint32_t i; + PCIRegion *cur_region = io_regions; + + for (i = 0; i < regions_num; i++, cur_region++) { + if (!cur_region->valid) { + continue; + } + + /* handle memory io regions */ + if (cur_region->type & IORESOURCE_MEM) { + int t = cur_region->type & IORESOURCE_PREFETCH + ? PCI_BASE_ADDRESS_MEM_PREFETCH + : PCI_BASE_ADDRESS_SPACE_MEMORY; + + /* map physical memory */ + pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size, + PROT_WRITE | PROT_READ, + MAP_SHARED, + cur_region->resource_fd, + (off_t)0); + + if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) { + pci_dev->v_addrs[i].u.r_virtbase = NULL; + error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!", + __func__, cur_region->base_addr); + return -1; + } + + pci_dev->v_addrs[i].r_size = cur_region->size; + pci_dev->v_addrs[i].e_size = 0; + + /* add offset */ + pci_dev->v_addrs[i].u.r_virtbase += + (cur_region->base_addr & 0xFFF); + + if (cur_region->size & 0xFFF) { + error_report("PCI region %d at address 0x%" PRIx64 " has " + "size 0x%" PRIx64 ", which is not a multiple of " + "4K. You might experience some performance hit " + "due to that.", + i, cur_region->base_addr, cur_region->size); + memory_region_init_io(&pci_dev->v_addrs[i].real_iomem, + &slow_bar_ops, &pci_dev->v_addrs[i], + "assigned-dev-slow-bar", + cur_region->size); + } else { + void *virtbase = pci_dev->v_addrs[i].u.r_virtbase; + char name[32]; + snprintf(name, sizeof(name), "%s.bar%d", + object_get_typename(OBJECT(pci_dev)), i); + memory_region_init_ram_ptr(&pci_dev->v_addrs[i].real_iomem, + name, cur_region->size, + virtbase); + vmstate_register_ram(&pci_dev->v_addrs[i].real_iomem, + &pci_dev->dev.qdev); + } + + assigned_dev_iomem_setup(&pci_dev->dev, i, cur_region->size); + pci_register_bar((PCIDevice *) pci_dev, i, t, + &pci_dev->v_addrs[i].container); + continue; + } else { + /* handle port io regions */ + uint32_t val; + int ret; + + /* Test kernel support for ioport resource read/write. Old + * kernels return EIO. New kernels only allow 1/2/4 byte reads + * so should return EINVAL for a 3 byte read */ + ret = pread(pci_dev->v_addrs[i].region->resource_fd, &val, 3, 0); + if (ret >= 0) { + error_report("Unexpected return from I/O port read: %d", ret); + abort(); + } else if (errno != EINVAL) { + error_report("Kernel doesn't support ioport resource " + "access, hiding this region."); + close(pci_dev->v_addrs[i].region->resource_fd); + cur_region->valid = 0; + continue; + } + + pci_dev->v_addrs[i].u.r_baseport = cur_region->base_addr; + pci_dev->v_addrs[i].r_size = cur_region->size; + pci_dev->v_addrs[i].e_size = 0; + + assigned_dev_ioport_setup(&pci_dev->dev, i, cur_region->size); + pci_register_bar((PCIDevice *) pci_dev, i, + PCI_BASE_ADDRESS_SPACE_IO, + &pci_dev->v_addrs[i].container); + } + } + + /* success */ + return 0; +} + +static int get_real_id(const char *devpath, const char *idname, uint16_t *val) +{ + FILE *f; + char name[128]; + long id; + + snprintf(name, sizeof(name), "%s%s", devpath, idname); + f = fopen(name, "r"); + if (f == NULL) { + error_report("%s: %s: %m", __func__, name); + return -1; + } + if (fscanf(f, "%li\n", &id) == 1) { + *val = id; + } else { + return -1; + } + fclose(f); + + return 0; +} + +static int get_real_vendor_id(const char *devpath, uint16_t *val) +{ + return get_real_id(devpath, "vendor", val); +} + +static int get_real_device_id(const char *devpath, uint16_t *val) +{ + return get_real_id(devpath, "device", val); +} + +static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg, + uint8_t r_bus, uint8_t r_dev, uint8_t r_func) +{ + char dir[128], name[128]; + int fd, r = 0, v; + FILE *f; + uint64_t start, end, size, flags; + uint16_t id; + PCIRegion *rp; + PCIDevRegions *dev = &pci_dev->real_device; + + dev->region_number = 0; + + snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%x/", + r_seg, r_bus, r_dev, r_func); + + snprintf(name, sizeof(name), "%sconfig", dir); + + if (pci_dev->configfd_name && *pci_dev->configfd_name) { + if (qemu_isdigit(pci_dev->configfd_name[0])) { + dev->config_fd = strtol(pci_dev->configfd_name, NULL, 0); + } else { + dev->config_fd = monitor_get_fd(cur_mon, pci_dev->configfd_name); + if (dev->config_fd < 0) { + error_report("%s: (%s) unkown", __func__, + pci_dev->configfd_name); + return 1; + } + } + } else { + dev->config_fd = open(name, O_RDWR); + + if (dev->config_fd == -1) { + error_report("%s: %s: %m", __func__, name); + return 1; + } + } +again: + r = read(dev->config_fd, pci_dev->dev.config, + pci_config_size(&pci_dev->dev)); + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) { + goto again; + } + error_report("%s: read failed, errno = %d", __func__, errno); + } + + /* Restore or clear multifunction, this is always controlled by qemu */ + if (pci_dev->dev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + pci_dev->dev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; + } else { + pci_dev->dev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + } + + /* Clear host resource mapping info. If we choose not to register a + * BAR, such as might be the case with the option ROM, we can get + * confusing, unwritable, residual addresses from the host here. */ + memset(&pci_dev->dev.config[PCI_BASE_ADDRESS_0], 0, 24); + memset(&pci_dev->dev.config[PCI_ROM_ADDRESS], 0, 4); + + snprintf(name, sizeof(name), "%sresource", dir); + + f = fopen(name, "r"); + if (f == NULL) { + error_report("%s: %s: %m", __func__, name); + return 1; + } + + for (r = 0; r < PCI_ROM_SLOT; r++) { + if (fscanf(f, "%" SCNi64 " %" SCNi64 " %" SCNi64 "\n", + &start, &end, &flags) != 3) { + break; + } + + rp = dev->regions + r; + rp->valid = 0; + rp->resource_fd = -1; + size = end - start + 1; + flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; + if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0) { + continue; + } + if (flags & IORESOURCE_MEM) { + flags &= ~IORESOURCE_IO; + } else { + flags &= ~IORESOURCE_PREFETCH; + } + snprintf(name, sizeof(name), "%sresource%d", dir, r); + fd = open(name, O_RDWR); + if (fd == -1) { + continue; + } + rp->resource_fd = fd; + + rp->type = flags; + rp->valid = 1; + rp->base_addr = start; + rp->size = size; + pci_dev->v_addrs[r].region = rp; + DEBUG("region %d size %" PRIu64 " start 0x%" PRIx64 + " type %d resource_fd %d\n", + r, rp->size, start, rp->type, rp->resource_fd); + } + + fclose(f); + + /* read and fill vendor ID */ + v = get_real_vendor_id(dir, &id); + if (v) { + return 1; + } + pci_dev->dev.config[0] = id & 0xff; + pci_dev->dev.config[1] = (id & 0xff00) >> 8; + + /* read and fill device ID */ + v = get_real_device_id(dir, &id); + if (v) { + return 1; + } + pci_dev->dev.config[2] = id & 0xff; + pci_dev->dev.config[3] = (id & 0xff00) >> 8; + + pci_word_test_and_clear_mask(pci_dev->emulate_config_write + PCI_COMMAND, + PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE); + + dev->region_number = r; + return 0; +} + +static void free_msi_virqs(AssignedDevice *dev) +{ + int i; + + for (i = 0; i < dev->msi_virq_nr; i++) { + if (dev->msi_virq[i] >= 0) { + kvm_irqchip_release_virq(kvm_state, dev->msi_virq[i]); + dev->msi_virq[i] = -1; + } + } + g_free(dev->msi_virq); + dev->msi_virq = NULL; + dev->msi_virq_nr = 0; +} + +static void free_assigned_device(AssignedDevice *dev) +{ + int i; + + if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { + assigned_dev_unregister_msix_mmio(dev); + } + for (i = 0; i < dev->real_device.region_number; i++) { + PCIRegion *pci_region = &dev->real_device.regions[i]; + AssignedDevRegion *region = &dev->v_addrs[i]; + + if (!pci_region->valid) { + continue; + } + if (pci_region->type & IORESOURCE_IO) { + if (region->u.r_baseport) { + memory_region_del_subregion(®ion->container, + ®ion->real_iomem); + memory_region_destroy(®ion->real_iomem); + memory_region_destroy(®ion->container); + } + } else if (pci_region->type & IORESOURCE_MEM) { + if (region->u.r_virtbase) { + memory_region_del_subregion(®ion->container, + ®ion->real_iomem); + + /* Remove MSI-X table subregion */ + if (pci_region->base_addr <= dev->msix_table_addr && + pci_region->base_addr + pci_region->size > + dev->msix_table_addr) { + memory_region_del_subregion(®ion->container, + &dev->mmio); + } + + memory_region_destroy(®ion->real_iomem); + memory_region_destroy(®ion->container); + if (munmap(region->u.r_virtbase, + (pci_region->size + 0xFFF) & 0xFFFFF000)) { + error_report("Failed to unmap assigned device region: %s", + strerror(errno)); + } + } + } + if (pci_region->resource_fd >= 0) { + close(pci_region->resource_fd); + } + } + + if (dev->real_device.config_fd >= 0) { + close(dev->real_device.config_fd); + } + + free_msi_virqs(dev); +} + +static void assign_failed_examine(AssignedDevice *dev) +{ + char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns; + uint16_t vendor_id, device_id; + int r; + + snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + + snprintf(name, sizeof(name), "%sdriver", dir); + + r = readlink(name, driver, sizeof(driver)); + if ((r <= 0) || r >= sizeof(driver)) { + goto fail; + } + + ns = strrchr(driver, '/'); + if (!ns) { + goto fail; + } + + ns++; + + if (get_real_vendor_id(dir, &vendor_id) || + get_real_device_id(dir, &device_id)) { + goto fail; + } + + error_report("*** The driver '%s' is occupying your device " + "%04x:%02x:%02x.%x.", + ns, dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + error_report("***"); + error_report("*** You can try the following commands to free it:"); + error_report("***"); + error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/" + "new_id", vendor_id, device_id); + error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/" + "%s/unbind", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function, ns); + error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/" + "pci-stub/bind", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub" + "/remove_id", vendor_id, device_id); + error_report("***"); + + return; + +fail: + error_report("Couldn't find out why."); +} + +static int assign_device(AssignedDevice *dev) +{ + uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU; + int r; + + /* Only pass non-zero PCI segment to capable module */ + if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) && + dev->host.domain) { + error_report("Can't assign device inside non-zero PCI segment " + "as this KVM module doesn't support it."); + return -ENODEV; + } + + if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) { + error_report("No IOMMU found. Unable to assign device \"%s\"", + dev->dev.qdev.id); + return -ENODEV; + } + + if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK && + kvm_has_intx_set_mask()) { + flags |= KVM_DEV_ASSIGN_PCI_2_3; + } + + r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id); + if (r < 0) { + error_report("Failed to assign device \"%s\" : %s", + dev->dev.qdev.id, strerror(-r)); + + switch (r) { + case -EBUSY: + assign_failed_examine(dev); + break; + default: + break; + } + } + return r; +} + +static bool check_irqchip_in_kernel(void) +{ + if (kvm_irqchip_in_kernel()) { + return true; + } + error_report("pci-assign: error: requires KVM with in-kernel irqchip " + "enabled"); + return false; +} + +static int assign_intx(AssignedDevice *dev) +{ + AssignedIRQType new_type; + PCIINTxRoute intx_route; + bool intx_host_msi; + int r; + + /* Interrupt PIN 0 means don't use INTx */ + if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) { + pci_device_set_intx_routing_notifier(&dev->dev, NULL); + return 0; + } + + if (!check_irqchip_in_kernel()) { + return -ENOTSUP; + } + + pci_device_set_intx_routing_notifier(&dev->dev, + assigned_dev_update_irq_routing); + + intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin); + assert(intx_route.mode != PCI_INTX_INVERTED); + + if (dev->intx_route.mode == intx_route.mode && + dev->intx_route.irq == intx_route.irq) { + return 0; + } + + switch (dev->assigned_irq_type) { + case ASSIGNED_IRQ_INTX_HOST_INTX: + case ASSIGNED_IRQ_INTX_HOST_MSI: + intx_host_msi = dev->assigned_irq_type == ASSIGNED_IRQ_INTX_HOST_MSI; + r = kvm_device_intx_deassign(kvm_state, dev->dev_id, intx_host_msi); + break; + case ASSIGNED_IRQ_MSI: + r = kvm_device_msi_deassign(kvm_state, dev->dev_id); + break; + case ASSIGNED_IRQ_MSIX: + r = kvm_device_msix_deassign(kvm_state, dev->dev_id); + break; + default: + r = 0; + break; + } + if (r) { + perror("assign_intx: deassignment of previous interrupt failed"); + } + dev->assigned_irq_type = ASSIGNED_IRQ_NONE; + + if (intx_route.mode == PCI_INTX_DISABLED) { + dev->intx_route = intx_route; + return 0; + } + +retry: + if (dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK && + dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + intx_host_msi = true; + new_type = ASSIGNED_IRQ_INTX_HOST_MSI; + } else { + intx_host_msi = false; + new_type = ASSIGNED_IRQ_INTX_HOST_INTX; + } + + r = kvm_device_intx_assign(kvm_state, dev->dev_id, intx_host_msi, + intx_route.irq); + if (r < 0) { + if (r == -EIO && !(dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK) && + dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + /* Retry with host-side MSI. There might be an IRQ conflict and + * either the kernel or the device doesn't support sharing. */ + error_report("Host-side INTx sharing not supported, " + "using MSI instead.\n" + "Some devices do not to work properly in this mode."); + dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK; + goto retry; + } + error_report("Failed to assign irq for \"%s\": %s", + dev->dev.qdev.id, strerror(-r)); + error_report("Perhaps you are assigning a device " + "that shares an IRQ with another device?"); + return r; + } + + dev->intx_route = intx_route; + dev->assigned_irq_type = new_type; + return r; +} + +static void deassign_device(AssignedDevice *dev) +{ + int r; + + r = kvm_device_pci_deassign(kvm_state, dev->dev_id); + assert(r == 0); +} + +/* The pci config space got updated. Check if irq numbers have changed + * for our devices + */ +static void assigned_dev_update_irq_routing(PCIDevice *dev) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, dev); + Error *err = NULL; + int r; + + r = assign_intx(assigned_dev); + if (r < 0) { + qdev_unplug(&dev->qdev, &err); + assert(!err); + } +} + +static void assigned_dev_update_msi(PCIDevice *pci_dev) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap + + PCI_MSI_FLAGS); + int r; + + /* Some guests gratuitously disable MSI even if they're not using it, + * try to catch this by only deassigning irqs if the guest is using + * MSI or intends to start. */ + if (assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSI || + (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) { + r = kvm_device_msi_deassign(kvm_state, assigned_dev->dev_id); + /* -ENXIO means no assigned irq */ + if (r && r != -ENXIO) { + perror("assigned_dev_update_msi: deassign irq"); + } + + free_msi_virqs(assigned_dev); + + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE; + pci_device_set_intx_routing_notifier(pci_dev, NULL); + } + + if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) { + uint8_t *pos = pci_dev->config + pci_dev->msi_cap; + MSIMessage msg; + int virq; + + msg.address = pci_get_long(pos + PCI_MSI_ADDRESS_LO); + msg.data = pci_get_word(pos + PCI_MSI_DATA_32); + virq = kvm_irqchip_add_msi_route(kvm_state, msg); + if (virq < 0) { + perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route"); + return; + } + + assigned_dev->msi_virq = g_malloc(sizeof(*assigned_dev->msi_virq)); + assigned_dev->msi_virq_nr = 1; + assigned_dev->msi_virq[0] = virq; + if (kvm_device_msi_assign(kvm_state, assigned_dev->dev_id, virq) < 0) { + perror("assigned_dev_update_msi: kvm_device_msi_assign"); + } + + assigned_dev->intx_route.mode = PCI_INTX_DISABLED; + assigned_dev->intx_route.irq = -1; + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI; + } else { + assign_intx(assigned_dev); + } +} + +static bool assigned_dev_msix_masked(MSIXTableEntry *entry) +{ + return (entry->ctrl & cpu_to_le32(0x1)) != 0; +} + +static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) +{ + AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint16_t entries_nr = 0; + int i, r = 0; + MSIXTableEntry *entry = adev->msix_table; + MSIMessage msg; + + /* Get the usable entry number for allocating */ + for (i = 0; i < adev->msix_max; i++, entry++) { + if (assigned_dev_msix_masked(entry)) { + continue; + } + entries_nr++; + } + + DEBUG("MSI-X entries: %d\n", entries_nr); + + /* It's valid to enable MSI-X with all entries masked */ + if (!entries_nr) { + return 0; + } + + r = kvm_device_msix_init_vectors(kvm_state, adev->dev_id, entries_nr); + if (r != 0) { + error_report("fail to set MSI-X entry number for MSIX! %s", + strerror(-r)); + return r; + } + + free_msi_virqs(adev); + + adev->msi_virq_nr = adev->msix_max; + adev->msi_virq = g_malloc(adev->msix_max * sizeof(*adev->msi_virq)); + + entry = adev->msix_table; + for (i = 0; i < adev->msix_max; i++, entry++) { + adev->msi_virq[i] = -1; + + if (assigned_dev_msix_masked(entry)) { + continue; + } + + msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32); + msg.data = entry->data; + r = kvm_irqchip_add_msi_route(kvm_state, msg); + if (r < 0) { + return r; + } + adev->msi_virq[i] = r; + + DEBUG("MSI-X vector %d, gsi %d, addr %08x_%08x, data %08x\n", i, + r, entry->addr_hi, entry->addr_lo, entry->data); + + r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i, + adev->msi_virq[i]); + if (r) { + error_report("fail to set MSI-X entry! %s", strerror(-r)); + break; + } + } + + return r; +} + +static void assigned_dev_update_msix(PCIDevice *pci_dev) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint16_t ctrl_word = pci_get_word(pci_dev->config + pci_dev->msix_cap + + PCI_MSIX_FLAGS); + int r; + + /* Some guests gratuitously disable MSIX even if they're not using it, + * try to catch this by only deassigning irqs if the guest is using + * MSIX or intends to start. */ + if ((assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSIX) || + (ctrl_word & PCI_MSIX_FLAGS_ENABLE)) { + r = kvm_device_msix_deassign(kvm_state, assigned_dev->dev_id); + /* -ENXIO means no assigned irq */ + if (r && r != -ENXIO) { + perror("assigned_dev_update_msix: deassign irq"); + } + + free_msi_virqs(assigned_dev); + + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE; + pci_device_set_intx_routing_notifier(pci_dev, NULL); + } + + if (ctrl_word & PCI_MSIX_FLAGS_ENABLE) { + if (assigned_dev_update_msix_mmio(pci_dev) < 0) { + perror("assigned_dev_update_msix_mmio"); + return; + } + + if (assigned_dev->msi_virq_nr > 0) { + if (kvm_device_msix_assign(kvm_state, assigned_dev->dev_id) < 0) { + perror("assigned_dev_enable_msix: assign irq"); + return; + } + } + assigned_dev->intx_route.mode = PCI_INTX_DISABLED; + assigned_dev->intx_route.irq = -1; + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX; + } else { + assign_intx(assigned_dev); + } +} + +static uint32_t assigned_dev_pci_read_config(PCIDevice *pci_dev, + uint32_t address, int len) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint32_t virt_val = pci_default_read_config(pci_dev, address, len); + uint32_t real_val, emulate_mask, full_emulation_mask; + + emulate_mask = 0; + memcpy(&emulate_mask, assigned_dev->emulate_config_read + address, len); + emulate_mask = le32_to_cpu(emulate_mask); + + full_emulation_mask = 0xffffffff >> (32 - len * 8); + + if (emulate_mask != full_emulation_mask) { + real_val = assigned_dev_pci_read(pci_dev, address, len); + return (virt_val & emulate_mask) | (real_val & ~emulate_mask); + } else { + return virt_val; + } +} + +static void assigned_dev_pci_write_config(PCIDevice *pci_dev, uint32_t address, + uint32_t val, int len) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint16_t old_cmd = pci_get_word(pci_dev->config + PCI_COMMAND); + uint32_t emulate_mask, full_emulation_mask; + int ret; + + pci_default_write_config(pci_dev, address, val, len); + + if (kvm_has_intx_set_mask() && + range_covers_byte(address, len, PCI_COMMAND + 1)) { + bool intx_masked = (pci_get_word(pci_dev->config + PCI_COMMAND) & + PCI_COMMAND_INTX_DISABLE); + + if (intx_masked != !!(old_cmd & PCI_COMMAND_INTX_DISABLE)) { + ret = kvm_device_intx_set_mask(kvm_state, assigned_dev->dev_id, + intx_masked); + if (ret) { + perror("assigned_dev_pci_write_config: set intx mask"); + } + } + } + if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + if (range_covers_byte(address, len, + pci_dev->msi_cap + PCI_MSI_FLAGS)) { + assigned_dev_update_msi(pci_dev); + } + } + if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { + if (range_covers_byte(address, len, + pci_dev->msix_cap + PCI_MSIX_FLAGS + 1)) { + assigned_dev_update_msix(pci_dev); + } + } + + emulate_mask = 0; + memcpy(&emulate_mask, assigned_dev->emulate_config_write + address, len); + emulate_mask = le32_to_cpu(emulate_mask); + + full_emulation_mask = 0xffffffff >> (32 - len * 8); + + if (emulate_mask != full_emulation_mask) { + if (emulate_mask) { + val &= ~emulate_mask; + val |= assigned_dev_pci_read(pci_dev, address, len) & emulate_mask; + } + assigned_dev_pci_write(pci_dev, address, val, len); + } +} + +static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset, + uint32_t len) +{ + assigned_dev_direct_config_read(dev, offset, len); + assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1); +} + +static int assigned_device_pci_cap_init(PCIDevice *pci_dev) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + PCIRegion *pci_region = dev->real_device.regions; + int ret, pos; + + /* Clear initial capabilities pointer and status copied from hw */ + pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0); + pci_set_word(pci_dev->config + PCI_STATUS, + pci_get_word(pci_dev->config + PCI_STATUS) & + ~PCI_STATUS_CAP_LIST); + + /* Expose MSI capability + * MSI capability is the 1st capability in capability config */ + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0); + if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) { + if (!check_irqchip_in_kernel()) { + return -ENOTSUP; + } + dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI; + /* Only 32-bit/no-mask currently supported */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10); + if (ret < 0) { + return ret; + } + pci_dev->msi_cap = pos; + + pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS, + pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) & + PCI_MSI_FLAGS_QMASK); + pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0); + pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0); + + /* Set writable fields */ + pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS, + PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); + pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc); + pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff); + } + /* Expose MSI-X capability */ + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0); + if (pos != 0 && kvm_device_msix_supported(kvm_state)) { + int bar_nr; + uint32_t msix_table_entry; + + if (!check_irqchip_in_kernel()) { + return -ENOTSUP; + } + dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX; + ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12); + if (ret < 0) { + return ret; + } + pci_dev->msix_cap = pos; + + pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, + pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & + PCI_MSIX_FLAGS_QSIZE); + + /* Only enable and function mask bits are writable */ + pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS, + PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL); + + msix_table_entry = pci_get_long(pci_dev->config + pos + PCI_MSIX_TABLE); + bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK; + msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK; + dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry; + dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS); + dev->msix_max &= PCI_MSIX_FLAGS_QSIZE; + dev->msix_max += 1; + } + + /* Minimal PM support, nothing writable, device appears to NAK changes */ + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PM, 0); + if (pos) { + uint16_t pmc; + + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, PCI_PM_SIZEOF); + + pmc = pci_get_word(pci_dev->config + pos + PCI_CAP_FLAGS); + pmc &= (PCI_PM_CAP_VER_MASK | PCI_PM_CAP_DSI); + pci_set_word(pci_dev->config + pos + PCI_CAP_FLAGS, pmc); + + /* assign_device will bring the device up to D0, so we don't need + * to worry about doing that ourselves here. */ + pci_set_word(pci_dev->config + pos + PCI_PM_CTRL, + PCI_PM_CTRL_NO_SOFT_RESET); + + pci_set_byte(pci_dev->config + pos + PCI_PM_PPB_EXTENSIONS, 0); + pci_set_byte(pci_dev->config + pos + PCI_PM_DATA_REGISTER, 0); + } + + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_EXP, 0); + if (pos) { + uint8_t version, size = 0; + uint16_t type, devctl, lnksta; + uint32_t devcap, lnkcap; + + version = pci_get_byte(pci_dev->config + pos + PCI_EXP_FLAGS); + version &= PCI_EXP_FLAGS_VERS; + if (version == 1) { + size = 0x14; + } else if (version == 2) { + /* + * Check for non-std size, accept reduced size to 0x34, + * which is what bcm5761 implemented, violating the + * PCIe v3.0 spec that regs should exist and be read as 0, + * not optionally provided and shorten the struct size. + */ + size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos); + if (size < 0x34) { + error_report("%s: Invalid size PCIe cap-id 0x%x", + __func__, PCI_CAP_ID_EXP); + return -EINVAL; + } else if (size != 0x3c) { + error_report("WARNING, %s: PCIe cap-id 0x%x has " + "non-standard size 0x%x; std size should be 0x3c", + __func__, PCI_CAP_ID_EXP, size); + } + } else if (version == 0) { + uint16_t vid, did; + vid = pci_get_word(pci_dev->config + PCI_VENDOR_ID); + did = pci_get_word(pci_dev->config + PCI_DEVICE_ID); + if (vid == PCI_VENDOR_ID_INTEL && did == 0x10ed) { + /* + * quirk for Intel 82599 VF with invalid PCIe capability + * version, should really be version 2 (same as PF) + */ + size = 0x3c; + } + } + + if (size == 0) { + error_report("%s: Unsupported PCI express capability version %d", + __func__, version); + return -EINVAL; + } + + ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, size); + + type = pci_get_word(pci_dev->config + pos + PCI_EXP_FLAGS); + type = (type & PCI_EXP_FLAGS_TYPE) >> 4; + if (type != PCI_EXP_TYPE_ENDPOINT && + type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) { + error_report("Device assignment only supports endpoint assignment," + " device type %d", type); + return -EINVAL; + } + + /* capabilities, pass existing read-only copy + * PCI_EXP_FLAGS_IRQ: updated by hardware, should be direct read */ + + /* device capabilities: hide FLR */ + devcap = pci_get_long(pci_dev->config + pos + PCI_EXP_DEVCAP); + devcap &= ~PCI_EXP_DEVCAP_FLR; + pci_set_long(pci_dev->config + pos + PCI_EXP_DEVCAP, devcap); + + /* device control: clear all error reporting enable bits, leaving + * only a few host values. Note, these are + * all writable, but not passed to hw. + */ + devctl = pci_get_word(pci_dev->config + pos + PCI_EXP_DEVCTL); + devctl = (devctl & (PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_PAYLOAD)) | + PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN; + pci_set_word(pci_dev->config + pos + PCI_EXP_DEVCTL, devctl); + devctl = PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_AUX_PME; + pci_set_word(pci_dev->wmask + pos + PCI_EXP_DEVCTL, ~devctl); + + /* Clear device status */ + pci_set_word(pci_dev->config + pos + PCI_EXP_DEVSTA, 0); + + /* Link capabilities, expose links and latencues, clear reporting */ + lnkcap = pci_get_long(pci_dev->config + pos + PCI_EXP_LNKCAP); + lnkcap &= (PCI_EXP_LNKCAP_SLS | PCI_EXP_LNKCAP_MLW | + PCI_EXP_LNKCAP_ASPMS | PCI_EXP_LNKCAP_L0SEL | + PCI_EXP_LNKCAP_L1EL); + pci_set_long(pci_dev->config + pos + PCI_EXP_LNKCAP, lnkcap); + + /* Link control, pass existing read-only copy. Should be writable? */ + + /* Link status, only expose current speed and width */ + lnksta = pci_get_word(pci_dev->config + pos + PCI_EXP_LNKSTA); + lnksta &= (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW); + pci_set_word(pci_dev->config + pos + PCI_EXP_LNKSTA, lnksta); + + if (version >= 2) { + /* Slot capabilities, control, status - not needed for endpoints */ + pci_set_long(pci_dev->config + pos + PCI_EXP_SLTCAP, 0); + pci_set_word(pci_dev->config + pos + PCI_EXP_SLTCTL, 0); + pci_set_word(pci_dev->config + pos + PCI_EXP_SLTSTA, 0); + + /* Root control, capabilities, status - not needed for endpoints */ + pci_set_word(pci_dev->config + pos + PCI_EXP_RTCTL, 0); + pci_set_word(pci_dev->config + pos + PCI_EXP_RTCAP, 0); + pci_set_long(pci_dev->config + pos + PCI_EXP_RTSTA, 0); + + /* Device capabilities/control 2, pass existing read-only copy */ + /* Link control 2, pass existing read-only copy */ + } + } + + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PCIX, 0); + if (pos) { + uint16_t cmd; + uint32_t status; + + /* Only expose the minimum, 8 byte capability */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, 8); + + /* Command register, clear upper bits, including extended modes */ + cmd = pci_get_word(pci_dev->config + pos + PCI_X_CMD); + cmd &= (PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO | PCI_X_CMD_MAX_READ | + PCI_X_CMD_MAX_SPLIT); + pci_set_word(pci_dev->config + pos + PCI_X_CMD, cmd); + + /* Status register, update with emulated PCI bus location, clear + * error bits, leave the rest. */ + status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS); + status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN); + status |= (pci_bus_num(pci_dev->bus) << 8) | pci_dev->devfn; + status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL | + PCI_X_STATUS_SPL_ERR); + pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status); + } + + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0); + if (pos) { + /* Direct R/W passthrough */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, 8); + + /* direct write for cap content */ + assigned_dev_direct_config_write(dev, pos + 2, 6); + } + + /* Devices can have multiple vendor capabilities, get them all */ + for (pos = 0; (pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VNDR, pos)); + pos += PCI_CAP_LIST_NEXT) { + uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS); + /* Direct R/W passthrough */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, len); + + /* direct write for cap content */ + assigned_dev_direct_config_write(dev, pos + 2, len - 2); + } + + /* If real and virtual capability list status bits differ, virtualize the + * access. */ + if ((pci_get_word(pci_dev->config + PCI_STATUS) & PCI_STATUS_CAP_LIST) != + (assigned_dev_pci_read_byte(pci_dev, PCI_STATUS) & + PCI_STATUS_CAP_LIST)) { + dev->emulate_config_read[PCI_STATUS] |= PCI_STATUS_CAP_LIST; + } + + return 0; +} + +static uint64_t +assigned_dev_msix_mmio_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + AssignedDevice *adev = opaque; + uint64_t val; + + memcpy(&val, (void *)((uint8_t *)adev->msix_table + addr), size); + + return val; +} + +static void assigned_dev_msix_mmio_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + AssignedDevice *adev = opaque; + PCIDevice *pdev = &adev->dev; + uint16_t ctrl; + MSIXTableEntry orig; + int i = addr >> 4; + + if (i >= adev->msix_max) { + return; /* Drop write */ + } + + ctrl = pci_get_word(pdev->config + pdev->msix_cap + PCI_MSIX_FLAGS); + + DEBUG("write to MSI-X table offset 0x%lx, val 0x%lx\n", addr, val); + + if (ctrl & PCI_MSIX_FLAGS_ENABLE) { + orig = adev->msix_table[i]; + } + + memcpy((uint8_t *)adev->msix_table + addr, &val, size); + + if (ctrl & PCI_MSIX_FLAGS_ENABLE) { + MSIXTableEntry *entry = &adev->msix_table[i]; + + if (!assigned_dev_msix_masked(&orig) && + assigned_dev_msix_masked(entry)) { + /* + * Vector masked, disable it + * + * XXX It's not clear if we can or should actually attempt + * to mask or disable the interrupt. KVM doesn't have + * support for pending bits and kvm_assign_set_msix_entry + * doesn't modify the device hardware mask. Interrupts + * while masked are simply not injected to the guest, so + * are lost. Can we get away with always injecting an + * interrupt on unmask? + */ + } else if (assigned_dev_msix_masked(&orig) && + !assigned_dev_msix_masked(entry)) { + /* Vector unmasked */ + if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) { + /* Previously unassigned vector, start from scratch */ + assigned_dev_update_msix(pdev); + return; + } else { + /* Update an existing, previously masked vector */ + MSIMessage msg; + int ret; + + msg.address = entry->addr_lo | + ((uint64_t)entry->addr_hi << 32); + msg.data = entry->data; + + ret = kvm_irqchip_update_msi_route(kvm_state, + adev->msi_virq[i], msg); + if (ret) { + error_report("Error updating irq routing entry (%d)", ret); + } + } + } + } +} + +static const MemoryRegionOps assigned_dev_msix_mmio_ops = { + .read = assigned_dev_msix_mmio_read, + .write = assigned_dev_msix_mmio_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +static void assigned_dev_msix_reset(AssignedDevice *dev) +{ + MSIXTableEntry *entry; + int i; + + if (!dev->msix_table) { + return; + } + + memset(dev->msix_table, 0, MSIX_PAGE_SIZE); + + for (i = 0, entry = dev->msix_table; i < dev->msix_max; i++, entry++) { + entry->ctrl = cpu_to_le32(0x1); /* Masked */ + } +} + +static int assigned_dev_register_msix_mmio(AssignedDevice *dev) +{ + dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); + if (dev->msix_table == MAP_FAILED) { + error_report("fail allocate msix_table! %s", strerror(errno)); + return -EFAULT; + } + + assigned_dev_msix_reset(dev); + + memory_region_init_io(&dev->mmio, &assigned_dev_msix_mmio_ops, dev, + "assigned-dev-msix", MSIX_PAGE_SIZE); + return 0; +} + +static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev) +{ + if (!dev->msix_table) { + return; + } + + memory_region_destroy(&dev->mmio); + + if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) { + error_report("error unmapping msix_table! %s", strerror(errno)); + } + dev->msix_table = NULL; +} + +static const VMStateDescription vmstate_assigned_device = { + .name = "pci-assign", + .unmigratable = 1, +}; + +static void reset_assigned_device(DeviceState *dev) +{ + PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev); + AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev); + char reset_file[64]; + const char reset[] = "1"; + int fd, ret; + + /* + * If a guest is reset without being shutdown, MSI/MSI-X can still + * be running. We want to return the device to a known state on + * reset, so disable those here. We especially do not want MSI-X + * enabled since it lives in MMIO space, which is about to get + * disabled. + */ + if (adev->assigned_irq_type == ASSIGNED_IRQ_MSIX) { + uint16_t ctrl = pci_get_word(pci_dev->config + + pci_dev->msix_cap + PCI_MSIX_FLAGS); + + pci_set_word(pci_dev->config + pci_dev->msix_cap + PCI_MSIX_FLAGS, + ctrl & ~PCI_MSIX_FLAGS_ENABLE); + assigned_dev_update_msix(pci_dev); + } else if (adev->assigned_irq_type == ASSIGNED_IRQ_MSI) { + uint8_t ctrl = pci_get_byte(pci_dev->config + + pci_dev->msi_cap + PCI_MSI_FLAGS); + + pci_set_byte(pci_dev->config + pci_dev->msi_cap + PCI_MSI_FLAGS, + ctrl & ~PCI_MSI_FLAGS_ENABLE); + assigned_dev_update_msi(pci_dev); + } + + snprintf(reset_file, sizeof(reset_file), + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/reset", + adev->host.domain, adev->host.bus, adev->host.slot, + adev->host.function); + + /* + * Issue a device reset via pci-sysfs. Note that we use write(2) here + * and ignore the return value because some kernels have a bug that + * returns 0 rather than bytes written on success, sending us into an + * infinite retry loop using other write mechanisms. + */ + fd = open(reset_file, O_WRONLY); + if (fd != -1) { + ret = write(fd, reset, strlen(reset)); + (void)ret; + close(fd); + } + + /* + * When a 0 is written to the bus master register, the device is logically + * disconnected from the PCI bus. This avoids further DMA transfers. + */ + assigned_dev_pci_write_config(pci_dev, PCI_COMMAND, 0, 1); +} + +static int assigned_initfn(struct PCIDevice *pci_dev) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint8_t e_intx; + int r; + + if (!kvm_enabled()) { + error_report("pci-assign: error: requires KVM support"); + return -1; + } + + if (!dev->host.domain && !dev->host.bus && !dev->host.slot && + !dev->host.function) { + error_report("pci-assign: error: no host device specified"); + return -1; + } + + /* + * Set up basic config space access control. Will be further refined during + * device initialization. + */ + assigned_dev_emulate_config_read(dev, 0, PCI_CONFIG_SPACE_SIZE); + assigned_dev_direct_config_read(dev, PCI_STATUS, 2); + assigned_dev_direct_config_read(dev, PCI_REVISION_ID, 1); + assigned_dev_direct_config_read(dev, PCI_CLASS_PROG, 3); + assigned_dev_direct_config_read(dev, PCI_CACHE_LINE_SIZE, 1); + assigned_dev_direct_config_read(dev, PCI_LATENCY_TIMER, 1); + assigned_dev_direct_config_read(dev, PCI_BIST, 1); + assigned_dev_direct_config_read(dev, PCI_CARDBUS_CIS, 4); + assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_VENDOR_ID, 2); + assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_ID, 2); + assigned_dev_direct_config_read(dev, PCI_CAPABILITY_LIST + 1, 7); + assigned_dev_direct_config_read(dev, PCI_MIN_GNT, 1); + assigned_dev_direct_config_read(dev, PCI_MAX_LAT, 1); + memcpy(dev->emulate_config_write, dev->emulate_config_read, + sizeof(dev->emulate_config_read)); + + if (get_real_device(dev, dev->host.domain, dev->host.bus, + dev->host.slot, dev->host.function)) { + error_report("pci-assign: Error: Couldn't get real device (%s)!", + dev->dev.qdev.id); + goto out; + } + + if (assigned_device_pci_cap_init(pci_dev) < 0) { + goto out; + } + + /* intercept MSI-X entry page in the MMIO */ + if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { + if (assigned_dev_register_msix_mmio(dev)) { + goto out; + } + } + + /* handle real device's MMIO/PIO BARs */ + if (assigned_dev_register_regions(dev->real_device.regions, + dev->real_device.region_number, + dev)) { + goto out; + } + + /* handle interrupt routing */ + e_intx = dev->dev.config[PCI_INTERRUPT_PIN] - 1; + dev->intpin = e_intx; + dev->intx_route.mode = PCI_INTX_DISABLED; + dev->intx_route.irq = -1; + + /* assign device to guest */ + r = assign_device(dev); + if (r < 0) { + goto out; + } + + /* assign legacy INTx to the device */ + r = assign_intx(dev); + if (r < 0) { + goto assigned_out; + } + + assigned_dev_load_option_rom(dev); + + add_boot_device_path(dev->bootindex, &pci_dev->qdev, NULL); + + return 0; + +assigned_out: + deassign_device(dev); +out: + free_assigned_device(dev); + return -1; +} + +static void assigned_exitfn(struct PCIDevice *pci_dev) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + + deassign_device(dev); + free_assigned_device(dev); +} + +static Property assigned_dev_properties[] = { + DEFINE_PROP_PCI_HOST_DEVADDR("host", AssignedDevice, host), + DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features, + ASSIGNED_DEVICE_PREFER_MSI_BIT, false), + DEFINE_PROP_BIT("share_intx", AssignedDevice, features, + ASSIGNED_DEVICE_SHARE_INTX_BIT, true), + DEFINE_PROP_INT32("bootindex", AssignedDevice, bootindex, -1), + DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void assign_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = assigned_initfn; + k->exit = assigned_exitfn; + k->config_read = assigned_dev_pci_read_config; + k->config_write = assigned_dev_pci_write_config; + dc->props = assigned_dev_properties; + dc->vmsd = &vmstate_assigned_device; + dc->reset = reset_assigned_device; + dc->desc = "KVM-based PCI passthrough"; +} + +static const TypeInfo assign_info = { + .name = "kvm-pci-assign", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(AssignedDevice), + .class_init = assign_class_init, +}; + +static void assign_register_types(void) +{ + type_register_static(&assign_info); +} + +type_init(assign_register_types) + +/* + * Scan the assigned devices for the devices that have an option ROM, and then + * load the corresponding ROM data to RAM. If an error occurs while loading an + * option ROM, we just ignore that option ROM and continue with the next one. + */ +static void assigned_dev_load_option_rom(AssignedDevice *dev) +{ + char name[32], rom_file[64]; + FILE *fp; + uint8_t val; + struct stat st; + void *ptr; + + /* If loading ROM from file, pci handles it */ + if (dev->dev.romfile || !dev->dev.rom_bar) { + return; + } + + snprintf(rom_file, sizeof(rom_file), + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + + if (stat(rom_file, &st)) { + return; + } + + if (access(rom_file, F_OK)) { + error_report("pci-assign: Insufficient privileges for %s", rom_file); + return; + } + + /* Write "1" to the ROM file to enable it */ + fp = fopen(rom_file, "r+"); + if (fp == NULL) { + return; + } + val = 1; + if (fwrite(&val, 1, 1, fp) != 1) { + goto close_rom; + } + fseek(fp, 0, SEEK_SET); + + snprintf(name, sizeof(name), "%s.rom", + object_get_typename(OBJECT(dev))); + memory_region_init_ram(&dev->dev.rom, name, st.st_size); + vmstate_register_ram(&dev->dev.rom, &dev->dev.qdev); + ptr = memory_region_get_ram_ptr(&dev->dev.rom); + memset(ptr, 0xff, st.st_size); + + if (!fread(ptr, 1, st.st_size, fp)) { + error_report("pci-assign: Cannot read from host %s\n" + "\tDevice option ROM contents are probably invalid " + "(check dmesg).\n\tSkip option ROM probe with rombar=0, " + "or load from file with romfile=", rom_file); + memory_region_destroy(&dev->dev.rom); + goto close_rom; + } + + pci_register_bar(&dev->dev, PCI_ROM_SLOT, 0, &dev->dev.rom); + dev->dev.has_rom = true; +close_rom: + /* Write "0" to disable ROM */ + fseek(fp, 0, SEEK_SET); + val = 0; + if (!fwrite(&val, 1, 1, fp)) { + DEBUG("%s\n", "Failed to disable pci-sysfs rom file"); + } + fclose(fp); +} diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index 33b7f79a9..479eecda3 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -44,6 +44,7 @@ static const QDevAlias qdev_alias_table[] = { { "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X }, { "lsi53c895a", "lsi" }, { "ich9-ahci", "ahci" }, + { "kvm-pci-assign", "pci-assign" }, { } }; -- cgit v1.2.3 From 149eeb5fe57b853081e8059575d91b8a58a4f96c Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 3 Sep 2012 22:56:00 +0200 Subject: hw/wm8750: Fix potential buffer overflow Report from smatch: hw/wm8750.c:369 wm8750_tx(12) error: buffer overflow 's->i2c_data' 2 <= 2 It looks like the preprocessor statements were simply misplaced. Replace also __FUNCTION__ by __func__ to please checkpatch.pl. Signed-off-by: Stefan Weil Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- hw/wm8750.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/wm8750.c b/hw/wm8750.c index 11bcec341..44f138fd5 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data) uint16_t value; if (s->i2c_len >= 2) { - printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len); #ifdef VERBOSE - return 1; + printf("%s: long message (%i bytes)\n", __func__, s->i2c_len); #endif + return 1; } s->i2c_data[s->i2c_len ++] = data; if (s->i2c_len != 2) -- cgit v1.2.3 From 599d64f6dc10f267a45e7abebfcafd8e7626585b Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 4 Sep 2012 07:35:57 +0200 Subject: target-arm: Fix potential buffer overflow Report from smatch: target-arm/helper.c:651 arm946_prbs_read(6) error: buffer overflow 'env->cp15.c6_region' 8 <= 8 target-arm/helper.c:661 arm946_prbs_write(6) error: buffer overflow 'env->cp15.c6_region' 8 <= 8 c7_region is an array with 8 elements, so the index must be less than 8. Signed-off-by: Stefan Weil Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index dceaa95c8..e27df9627 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -645,7 +645,7 @@ static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri, static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { - if (ri->crm > 8) { + if (ri->crm >= 8) { return EXCP_UDEF; } *value = env->cp15.c6_region[ri->crm]; @@ -655,7 +655,7 @@ static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, static int arm946_prbs_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - if (ri->crm > 8) { + if (ri->crm >= 8) { return EXCP_UDEF; } env->cp15.c6_region[ri->crm] = value; -- cgit v1.2.3 From a32354e206895400d17c3de9a8df1de96d3df289 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 4 Sep 2012 19:37:39 +0200 Subject: hw/mcf5206: Fix buffer overflow for MBAR read / write Report from smatch: mcf5206.c:384 m5206_mbar_readb(7) error: buffer overflow 'm5206_mbar_width' 128 <= 128 mcf5206.c:403 m5206_mbar_readw(8) error: buffer overflow 'm5206_mbar_width' 128 <= 128 mcf5206.c:427 m5206_mbar_readl(8) error: buffer overflow 'm5206_mbar_width' 128 <= 128 mcf5206.c:451 m5206_mbar_writeb(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128 mcf5206.c:475 m5206_mbar_writew(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128 mcf5206.c:503 m5206_mbar_writel(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128 m5206_mbar_width has 0x80 elements and supports 0 <= offset < 0x200. Signed-off-by: Stefan Weil Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- hw/mcf5206.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 539b39133..27753e271 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -378,7 +378,7 @@ static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } if (m5206_mbar_width[offset >> 2] > 1) { @@ -397,7 +397,7 @@ static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -421,7 +421,7 @@ static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -445,7 +445,7 @@ static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -469,7 +469,7 @@ static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -497,7 +497,7 @@ static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; -- cgit v1.2.3 From 8bf188aa18ef7a8355d9edbd43871d590468c4ed Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Thu, 7 Jun 2012 01:11:00 +0400 Subject: use --libexecdir instead of ignoring it first and reinventing it later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7b93fadf3a38d1ed65ea5536a52efc2772c6e3b8 "Add basic version of bridge helper" put the bridge helper executable into a fixed ${prefix}/libexec/ location, instead of using ${libexecdir} for this. At the same time, --libexecdir is being happily ignored by ./configure. Even more, the same patch sets unused $libexecdir variable in the generated config-host.mak, and uses fixed string (\${prefix}/libexecdir) for the bridge helper binary. Fix this braindamage by introducing $libexecdir variable, using it for the bridge helper binary, and recognizing --libexecdir. This patch is applicable to stable-1.1. Reviewed-by: Andreas Färber Reviewed-by: Corey Bryant Signed-off-by: Michael Tokarev Cc: Corey Bryant Cc: Richa Marwaha Cc: qemu-stable@nongnu.org Signed-off-by: Anthony Liguori --- configure | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/configure b/configure index f4de245d9..fa64d5de1 100755 --- a/configure +++ b/configure @@ -183,6 +183,7 @@ datadir="\${prefix}/share" qemu_docdir="\${prefix}/share/doc/qemu" bindir="\${prefix}/bin" libdir="\${prefix}/lib" +libexecdir="\${prefix}/libexec" includedir="\${prefix}/include" sysconfdir="\${prefix}/etc" confsuffix="/qemu" @@ -633,6 +634,8 @@ for opt do ;; --libdir=*) libdir="$optarg" ;; + --libexecdir=*) libexecdir="$optarg" + ;; --includedir=*) includedir="$optarg" ;; --datadir=*) datadir="$optarg" @@ -643,7 +646,7 @@ for opt do ;; --sysconfdir=*) sysconfdir="$optarg" ;; - --sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\ + --sbindir=*|--sharedstatedir=*|--localstatedir=*|\ --oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\ --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*) # These switches are silently ignored, for compatibility with @@ -3085,6 +3088,7 @@ echo "Install prefix $prefix" echo "BIOS directory `eval echo $qemu_datadir`" echo "binary directory `eval echo $bindir`" echo "library directory `eval echo $libdir`" +echo "libexec directory `eval echo $libexecdir`" echo "include directory `eval echo $includedir`" echo "config directory `eval echo $sysconfdir`" if test "$mingw32" = "no" ; then @@ -3188,14 +3192,14 @@ echo all: >> $config_host_mak echo "prefix=$prefix" >> $config_host_mak echo "bindir=$bindir" >> $config_host_mak echo "libdir=$libdir" >> $config_host_mak +echo "libexecdir=$libexecdir" >> $config_host_mak echo "includedir=$includedir" >> $config_host_mak echo "mandir=$mandir" >> $config_host_mak echo "sysconfdir=$sysconfdir" >> $config_host_mak echo "qemu_confdir=$qemu_confdir" >> $config_host_mak echo "qemu_datadir=$qemu_datadir" >> $config_host_mak echo "qemu_docdir=$qemu_docdir" >> $config_host_mak -echo "libexecdir=\${prefix}/libexec" >> $config_host_mak -echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak +echo "CONFIG_QEMU_HELPERDIR=\"$libexecdir\"" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak if test "$debug_tcg" = "yes" ; then -- cgit v1.2.3 From 455aa1e0818653c41fd794435b982426ce21ba2f Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 5 Sep 2012 13:52:49 -0500 Subject: socket: don't attempt to reconnect a TCP socket in server mode Commit c3767ed0eb5d0bb25fe409ae5dec06e3411ff1b6 introduced a possible SEGV when using a socket chardev with server=on because it assumes that all TCP sockets are in client mode. This patch adds a check to only reconnect when in client mode. Cc: Lei Li Reported-by: Michael Roth Signed-off-by: Anthony Liguori --- qemu-char.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index 398baf1e0..767da9386 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2148,10 +2148,12 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) TCPCharDriver *s = chr->opaque; if (s->connected) { return send_all(s->fd, buf, len); - } else { + } else if (s->listen_fd == -1) { /* (Re-)connect for unconnected writing */ tcp_chr_connect(chr); return 0; + } else { + return len; } } -- cgit v1.2.3 From bedc572eae6e250070495116f0db72607826aee5 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Thu, 2 Aug 2012 18:04:04 +0200 Subject: RTC: Remove the logic to update time format when DM bit changed Changing the DM (binary/BCD) and 24/12 control bit doesn't affect the internal registers. It only indicates what format is used for those registers. Signed-off-by: Yang Zhang Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 3777f858a..6e5b2f089 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -220,15 +220,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) rtc_set_time(s); } } - if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) && - !(data & REG_B_SET)) { - /* If the time format has changed and not in set mode, - update the registers immediately. */ - s->cmos_data[RTC_REG_B] = data; - rtc_copy_date(s); - } else { - s->cmos_data[RTC_REG_B] = data; - } + s->cmos_data[RTC_REG_B] = data; rtc_timer_update(s, qemu_get_clock_ns(rtc_clock)); break; case RTC_REG_C: -- cgit v1.2.3 From c4c18e246f968f18dc656afa3e8de7cf6b9752e8 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Thu, 2 Aug 2012 18:04:05 +0200 Subject: RTC: Rename rtc_timer_update Signed-off-by: Yang Zhang Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 6e5b2f089..b99f4d35f 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -110,7 +110,7 @@ static void rtc_coalesced_timer(void *opaque) } #endif -static void rtc_timer_update(RTCState *s, int64_t current_time) +static void periodic_timer_update(RTCState *s, int64_t current_time) { int period_code, period; int64_t cur_clock, next_irq_clock; @@ -148,7 +148,7 @@ static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; - rtc_timer_update(s, s->next_periodic_time); + periodic_timer_update(s, s->next_periodic_time); s->cmos_data[RTC_REG_C] |= REG_C_PF; if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; @@ -207,7 +207,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); - rtc_timer_update(s, qemu_get_clock_ns(rtc_clock)); + periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); break; case RTC_REG_B: if (data & REG_B_SET) { @@ -221,7 +221,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) } } s->cmos_data[RTC_REG_B] = data; - rtc_timer_update(s, qemu_get_clock_ns(rtc_clock)); + periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); break; case RTC_REG_C: case RTC_REG_D: @@ -550,7 +550,7 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data) rtc_set_date_from_host(&s->dev); s->next_second_time = now + (get_ticks_per_sec() * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); - rtc_timer_update(s, now); + periodic_timer_update(s, now); #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); -- cgit v1.2.3 From e46deabaa58b78397aeef2b04147aeecf5933794 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 2 Aug 2012 18:04:06 +0200 Subject: RTC: introduce RTC_CLOCK_RATE Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index b99f4d35f..175ddac6f 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -46,6 +46,7 @@ #endif #define RTC_REINJECT_ON_ACK_COUNT 20 +#define RTC_CLOCK_RATE 32768 typedef struct RTCState { ISADevice dev; @@ -85,7 +86,7 @@ static void rtc_coalesced_timer_update(RTCState *s) /* divide each RTC interval to 2 - 8 smaller intervals */ int c = MIN(s->irq_coalesced, 7) + 1; int64_t next_clock = qemu_get_clock_ns(rtc_clock) + - muldiv64(s->period / c, get_ticks_per_sec(), 32768); + muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE); qemu_mod_timer(s->coalesced_timer, next_clock); } } @@ -131,10 +132,10 @@ static void periodic_timer_update(RTCState *s, int64_t current_time) s->period = period; #endif /* compute 32 khz clock */ - cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec()); + cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, get_ticks_per_sec()); next_irq_clock = (cur_clock & ~(period - 1)) + period; s->next_periodic_time = - muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1; + muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1; qemu_mod_timer(s->periodic_timer, s->next_periodic_time); } else { #ifdef TARGET_I386 @@ -369,7 +370,7 @@ static void rtc_update_second(void *opaque) /* update in progress bit */ s->cmos_data[RTC_REG_A] |= REG_A_UIP; } - /* should be 244 us = 8 / 32768 seconds, but currently the + /* should be 244 us = 8 / RTC_CLOCK_RATE seconds, but currently the timers do not have the necessary resolution. */ delay = (get_ticks_per_sec() * 1) / 100; if (delay < 1) -- cgit v1.2.3 From 9324cc50c6b5df0998d46e8fca76e35f00ced6c3 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Thu, 2 Aug 2012 18:04:07 +0200 Subject: RTC: Update interrupt state when interrupts are masked/unmasked If an interrupt flag is already set when the interrupt becomes enabled, raise an interrupt immediately, and vice versa if interrupts become disabled. Signed-off-by: Yang Zhang Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 9 +++++++++ hw/mc146818rtc_regs.h | 1 + 2 files changed, 10 insertions(+) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 175ddac6f..b41eb4b94 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -221,6 +221,15 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) rtc_set_time(s); } } + /* if an interrupt flag is already set when the interrupt + * becomes enabled, raise an interrupt immediately. */ + if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) { + s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + qemu_irq_raise(s->irq); + } else { + s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF; + qemu_irq_lower(s->irq); + } s->cmos_data[RTC_REG_B] = data; periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); break; diff --git a/hw/mc146818rtc_regs.h b/hw/mc146818rtc_regs.h index 3ab37709f..fc10076ec 100644 --- a/hw/mc146818rtc_regs.h +++ b/hw/mc146818rtc_regs.h @@ -58,5 +58,6 @@ #define REG_C_IRQF 0x80 #define REG_C_PF 0x40 #define REG_C_AF 0x20 +#define REG_C_MASK 0x70 #endif -- cgit v1.2.3 From 0281518a1c7dd3577dea9ccc78869ecff954589c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 2 Aug 2012 18:04:08 +0200 Subject: vmstate: add VMSTATE_TIMER_V Also, for consistency with other occurrences, implement VMSTATE_TIMER as a special case of VMSTATE_TIMER_V rather than VMSTATE_TIMER_TEST. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- vmstate.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vmstate.h b/vmstate.h index 5bd2b762a..c9c320e62 100644 --- a/vmstate.h +++ b/vmstate.h @@ -503,8 +503,11 @@ extern const VMStateInfo vmstate_info_unused_buffer; #define VMSTATE_TIMER_TEST(_f, _s, _test) \ VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *) +#define VMSTATE_TIMER_V(_f, _s, _v) \ + VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *) + #define VMSTATE_TIMER(_f, _s) \ - VMSTATE_TIMER_TEST(_f, _s, NULL) + VMSTATE_TIMER_V(_f, _s, 0) #define VMSTATE_TIMER_ARRAY(_f, _s, _n) \ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) -- cgit v1.2.3 From 56038ef6234e5fb3d01bad1f6df37c2ccab82af9 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Thu, 2 Aug 2012 18:04:09 +0200 Subject: RTC: Update the RTC clock only when reading it Calculate guest RTC based on the time of the last update, instead of using timers. The formula is (base_rtc + guest_time_now - guest_time_last_update + offset) Base_rtc is the RTC value when the RTC was last updated. Guest_time_now is the guest time when the access happens. Guest_time_last_update was the guest time when the RTC was last updated. Offset is used when divider reset happens or the set bit is toggled. The timer is kept in order to signal interrupts, but it only needs to run when either UF or AF is cleared. When the bits are both set, the timer does not run. UIP is now synthesized when reading register A. If the timer is not set, or if there is more than one second before it (as is the case at the end of this series), the leading edge of UIP is computed and the rising edge occurs 220us later. If the update timer occurs within one second, however, the rising edge of the AF and UF bits should coincide withe the falling edge of UIP. We do not know exactly when this will happen because there could be delays in the servicing of the timer. Hence, in this case reading register A only computes for the rising edge of UIP, and latches the bit until the timer is fired and clears it. Signed-off-by: Yang Zhang Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 329 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 194 insertions(+), 135 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index b41eb4b94..54c98a53d 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -45,8 +45,11 @@ # define DPRINTF_C(format, ...) do { } while (0) #endif +#define NSEC_PER_SEC 1000000000LL + #define RTC_REINJECT_ON_ACK_COUNT 20 #define RTC_CLOCK_RATE 32768 +#define UIP_HOLD_LENGTH (8 * NSEC_PER_SEC / 32768) typedef struct RTCState { ISADevice dev; @@ -55,27 +58,40 @@ typedef struct RTCState { uint8_t cmos_index; struct tm current_tm; int32_t base_year; + uint64_t base_rtc; + uint64_t last_update; + int64_t offset; qemu_irq irq; qemu_irq sqw_irq; int it_shift; /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; - /* second update */ - int64_t next_second_time; + /* update-ended timer */ + QEMUTimer *update_timer; uint16_t irq_reinject_on_ack_count; uint32_t irq_coalesced; uint32_t period; QEMUTimer *coalesced_timer; - QEMUTimer *second_timer; - QEMUTimer *second_timer2; Notifier clock_reset_notifier; LostTickPolicy lost_tick_policy; Notifier suspend_notifier; } RTCState; static void rtc_set_time(RTCState *s); -static void rtc_copy_date(RTCState *s); +static void rtc_update_time(RTCState *s); +static void rtc_set_cmos(RTCState *s); +static inline int rtc_from_bcd(RTCState *s, int a); + +static uint64_t get_guest_rtc_ns(RTCState *s) +{ + uint64_t guest_rtc; + uint64_t guest_clock = qemu_get_clock_ns(rtc_clock); + + guest_rtc = s->base_rtc * NSEC_PER_SEC + + guest_clock - s->last_update + s->offset; + return guest_rtc; +} #ifdef TARGET_I386 static void rtc_coalesced_timer_update(RTCState *s) @@ -111,6 +127,7 @@ static void rtc_coalesced_timer(void *opaque) } #endif +/* handle periodic timer */ static void periodic_timer_update(RTCState *s, int64_t current_time) { int period_code, period; @@ -176,6 +193,100 @@ static void rtc_periodic_timer(void *opaque) } } +/* handle update-ended timer */ +static void check_update_timer(RTCState *s) +{ + uint64_t next_update_time; + uint64_t guest_nsec; + + /* From the data sheet: setting the SET bit does not prevent + * interrupts from occurring! However, it will prevent an + * alarm interrupt from occurring, because the time of day is + * not updated. + */ + if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && + (s->cmos_data[RTC_REG_B] & REG_B_SET)) { + qemu_del_timer(s->update_timer); + return; + } + if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && + (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + qemu_del_timer(s->update_timer); + return; + } + + guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC; + /* reprogram to next second */ + next_update_time = qemu_get_clock_ns(rtc_clock) + + NSEC_PER_SEC - guest_nsec; + if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) { + qemu_mod_timer(s->update_timer, next_update_time); + } +} + +static inline uint8_t convert_hour(RTCState *s, uint8_t hour) +{ + if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { + hour %= 12; + if (s->cmos_data[RTC_HOURS] & 0x80) { + hour += 12; + } + } + return hour; +} + +static uint32_t check_alarm(RTCState *s) +{ + uint8_t alarm_hour, alarm_min, alarm_sec; + uint8_t cur_hour, cur_min, cur_sec; + + alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); + alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); + alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); + alarm_hour = convert_hour(s, alarm_hour); + + cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); + cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); + cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); + cur_hour = convert_hour(s, cur_hour); + + if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 + || alarm_sec == cur_sec) && + ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 + || alarm_min == cur_min) && + ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 + || alarm_hour == cur_hour)) { + return 1; + } + return 0; + +} + +static void rtc_update_timer(void *opaque) +{ + RTCState *s = opaque; + int32_t irqs = REG_C_UF; + int32_t new_irqs; + + /* UIP might have been latched, update time and clear it. */ + rtc_update_time(s); + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + + if (check_alarm(s)) { + irqs |= REG_C_AF; + if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); + } + } + new_irqs = irqs & ~s->cmos_data[RTC_REG_C]; + s->cmos_data[RTC_REG_C] |= irqs; + if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { + s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + qemu_irq_raise(s->irq); + } + check_update_timer(s); +} + static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) { RTCState *s = opaque; @@ -190,6 +301,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: s->cmos_data[s->cmos_index] = data; + check_update_timer(s); break; case RTC_SECONDS: case RTC_MINUTES: @@ -202,6 +314,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) /* if in set mode, do not update the time */ if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { rtc_set_time(s); + check_update_timer(s); } break; case RTC_REG_A: @@ -209,15 +322,21 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + check_update_timer(s); break; case RTC_REG_B: if (data & REG_B_SET) { + /* update cmos to when the rtc was stopping */ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_update_time(s); + } /* set mode: reset UIP mode */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC; rtc_set_time(s); } } @@ -232,6 +351,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) } s->cmos_data[RTC_REG_B] = data; periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + check_update_timer(s); break; case RTC_REG_C: case RTC_REG_D: @@ -280,10 +400,13 @@ static void rtc_set_time(RTCState *s) tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; + s->base_rtc = mktimegm(tm); + s->last_update = qemu_get_clock_ns(rtc_clock); + rtc_change_mon_event(tm); } -static void rtc_copy_date(RTCState *s) +static void rtc_set_cmos(RTCState *s) { const struct tm *tm = &s->current_tm; int year; @@ -309,122 +432,41 @@ static void rtc_copy_date(RTCState *s) s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year); } -/* month is between 0 and 11. */ -static int get_days_in_month(int month, int year) +static void rtc_update_time(RTCState *s) { - static const int days_tab[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - int d; - if ((unsigned )month >= 12) - return 31; - d = days_tab[month]; - if (month == 1) { - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) - d++; - } - return d; + struct tm ret; + time_t guest_sec; + int64_t guest_nsec; + + guest_nsec = get_guest_rtc_ns(s); + guest_sec = guest_nsec / NSEC_PER_SEC; + gmtime_r(&guest_sec, &ret); + s->current_tm = ret; + rtc_set_cmos(s); } -/* update 'tm' to the next second */ -static void rtc_next_second(struct tm *tm) +static int update_in_progress(RTCState *s) { - int days_in_month; - - tm->tm_sec++; - if ((unsigned)tm->tm_sec >= 60) { - tm->tm_sec = 0; - tm->tm_min++; - if ((unsigned)tm->tm_min >= 60) { - tm->tm_min = 0; - tm->tm_hour++; - if ((unsigned)tm->tm_hour >= 24) { - tm->tm_hour = 0; - /* next day */ - tm->tm_wday++; - if ((unsigned)tm->tm_wday >= 7) - tm->tm_wday = 0; - days_in_month = get_days_in_month(tm->tm_mon, - tm->tm_year + 1900); - tm->tm_mday++; - if (tm->tm_mday < 1) { - tm->tm_mday = 1; - } else if (tm->tm_mday > days_in_month) { - tm->tm_mday = 1; - tm->tm_mon++; - if (tm->tm_mon >= 12) { - tm->tm_mon = 0; - tm->tm_year++; - } - } - } - } - } -} - - -static void rtc_update_second(void *opaque) -{ - RTCState *s = opaque; - int64_t delay; - - /* if the oscillator is not in normal operation, we do not update */ - if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { - s->next_second_time += get_ticks_per_sec(); - qemu_mod_timer(s->second_timer, s->next_second_time); - } else { - rtc_next_second(&s->current_tm); + int64_t guest_nsec; - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - /* update in progress bit */ - s->cmos_data[RTC_REG_A] |= REG_A_UIP; - } - /* should be 244 us = 8 / RTC_CLOCK_RATE seconds, but currently the - timers do not have the necessary resolution. */ - delay = (get_ticks_per_sec() * 1) / 100; - if (delay < 1) - delay = 1; - qemu_mod_timer(s->second_timer2, - s->next_second_time + delay); + if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + return 0; } -} - -static void rtc_update_second2(void *opaque) -{ - RTCState *s = opaque; - - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - rtc_copy_date(s); - } - - /* check alarm */ - if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) && - ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) && - ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) { - - s->cmos_data[RTC_REG_C] |= REG_C_AF; - if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); - qemu_irq_raise(s->irq); - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + if (qemu_timer_pending(s->update_timer)) { + int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer); + /* Latch UIP until the timer expires. */ + if (qemu_get_clock_ns(rtc_clock) >= (next_update_time - UIP_HOLD_LENGTH)) { + s->cmos_data[RTC_REG_A] |= REG_A_UIP; + return 1; } } - /* update ended interrupt */ - s->cmos_data[RTC_REG_C] |= REG_C_UF; - if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; - qemu_irq_raise(s->irq); + guest_nsec = get_guest_rtc_ns(s); + /* UIP bit will be set at last 244us of every second. */ + if ((guest_nsec % NSEC_PER_SEC) >= (NSEC_PER_SEC - UIP_HOLD_LENGTH)) { + return 1; } - - /* clear update in progress bit */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - - s->next_second_time += get_ticks_per_sec(); - qemu_mod_timer(s->second_timer, s->next_second_time); + return 0; } static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) @@ -442,15 +484,28 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_DAY_OF_MONTH: case RTC_MONTH: case RTC_YEAR: + /* if not in set mode, calibrate cmos before + * reading*/ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_update_time(s); + } ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: + if (update_in_progress(s)) { + s->cmos_data[s->cmos_index] |= REG_A_UIP; + } else { + s->cmos_data[s->cmos_index] &= ~REG_A_UIP; + } ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); s->cmos_data[RTC_REG_C] = 0x00; + if (ret & (REG_C_UF | REG_C_AF)) { + check_update_timer(s); + } #ifdef TARGET_I386 if(s->irq_coalesced && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && @@ -485,13 +540,6 @@ void rtc_set_memory(ISADevice *dev, int addr, int val) s->cmos_data[addr] = val; } -void rtc_set_date(ISADevice *dev, const struct tm *tm) -{ - RTCState *s = DO_UPCAST(RTCState, dev, dev); - s->current_tm = *tm; - rtc_copy_date(s); -} - /* PC cmos mappings */ #define REG_IBM_CENTURY_BYTE 0x32 #define REG_IBM_PS2_CENTURY_BYTE 0x37 @@ -502,9 +550,15 @@ static void rtc_set_date_from_host(ISADevice *dev) struct tm tm; int val; - /* set the CMOS date */ qemu_get_timedate(&tm, 0); - rtc_set_date(dev, &tm); + + s->base_rtc = mktimegm(&tm); + s->last_update = qemu_get_clock_ns(rtc_clock); + s->offset = 0; + + /* set the CMOS date */ + s->current_tm = tm; + rtc_set_cmos(s); val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val); @@ -513,9 +567,15 @@ static void rtc_set_date_from_host(ISADevice *dev) static int rtc_post_load(void *opaque, int version_id) { -#ifdef TARGET_I386 RTCState *s = opaque; + if (version_id <= 2) { + rtc_set_time(s); + s->offset = 0; + check_update_timer(s); + } + +#ifdef TARGET_I386 if (version_id >= 2) { if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); @@ -527,7 +587,7 @@ static int rtc_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_rtc = { .name = "mc146818rtc", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .minimum_version_id_old = 1, .post_load = rtc_post_load, @@ -543,11 +603,13 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_INT32(current_tm.tm_year, RTCState), VMSTATE_TIMER(periodic_timer, RTCState), VMSTATE_INT64(next_periodic_time, RTCState), - VMSTATE_INT64(next_second_time, RTCState), - VMSTATE_TIMER(second_timer, RTCState), - VMSTATE_TIMER(second_timer2, RTCState), + VMSTATE_UNUSED(3*8), VMSTATE_UINT32_V(irq_coalesced, RTCState, 2), VMSTATE_UINT32_V(period, RTCState, 2), + VMSTATE_UINT64_V(base_rtc, RTCState, 3), + VMSTATE_UINT64_V(last_update, RTCState, 3), + VMSTATE_INT64_V(offset, RTCState, 3), + VMSTATE_TIMER_V(update_timer, RTCState, 3), VMSTATE_END_OF_LIST() } }; @@ -558,9 +620,8 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data) int64_t now = *(int64_t *)data; rtc_set_date_from_host(&s->dev); - s->next_second_time = now + (get_ticks_per_sec() * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); periodic_timer_update(s, now); + check_update_timer(s); #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); @@ -582,6 +643,7 @@ static void rtc_reset(void *opaque) s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); + check_update_timer(s); qemu_irq_lower(s->irq); @@ -607,6 +669,7 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque, ISADevice *isa = ISA_DEVICE(obj); RTCState *s = DO_UPCAST(RTCState, dev, isa); + rtc_update_time(s); visit_start_struct(v, NULL, "struct tm", name, 0, errp); visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp); visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp); @@ -643,8 +706,8 @@ static int rtc_initfn(ISADevice *dev) #endif s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s); - s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s); - s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s); + s->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s); + check_update_timer(s); s->clock_reset_notifier.notify = rtc_notify_clock_reset; qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier); @@ -652,14 +715,10 @@ static int rtc_initfn(ISADevice *dev) s->suspend_notifier.notify = rtc_notify_suspend; qemu_register_suspend_notifier(&s->suspend_notifier); - s->next_second_time = - qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); - memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2); isa_register_ioport(dev, &s->io, base); - qdev_set_legacy_instance_id(&dev->qdev, base, 2); + qdev_set_legacy_instance_id(&dev->qdev, base, 3); qemu_register_reset(rtc_reset, s); object_property_add(OBJECT(s), "date", "struct tm", -- cgit v1.2.3 From 41a9b8b24d59acec462b0d8e0d2a7ffce6031d55 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Thu, 2 Aug 2012 18:04:10 +0200 Subject: RTC: Add divider reset support The first update cycle begins one-half seconds after divider reset is removed. This feature is useful for testing. Signed-off-by: Yang Zhang Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 54c98a53d..cb65c4f9e 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -83,6 +83,12 @@ static void rtc_update_time(RTCState *s); static void rtc_set_cmos(RTCState *s); static inline int rtc_from_bcd(RTCState *s, int a); +static inline bool rtc_running(RTCState *s) +{ + return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20); +} + static uint64_t get_guest_rtc_ns(RTCState *s) { uint64_t guest_rtc; @@ -199,11 +205,15 @@ static void check_update_timer(RTCState *s) uint64_t next_update_time; uint64_t guest_nsec; - /* From the data sheet: setting the SET bit does not prevent - * interrupts from occurring! However, it will prevent an - * alarm interrupt from occurring, because the time of day is - * not updated. + /* From the data sheet: "Holding the dividers in reset prevents + * interrupts from operating, while setting the SET bit allows" + * them to occur. However, it will prevent an alarm interrupt + * from occurring, because the time of day is not updated. */ + if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { + qemu_del_timer(s->update_timer); + return; + } if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && (s->cmos_data[RTC_REG_B] & REG_B_SET)) { qemu_del_timer(s->update_timer); @@ -268,6 +278,8 @@ static void rtc_update_timer(void *opaque) int32_t irqs = REG_C_UF; int32_t new_irqs; + assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60); + /* UIP might have been latched, update time and clear it. */ rtc_update_time(s); s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; @@ -312,12 +324,31 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_YEAR: s->cmos_data[s->cmos_index] = data; /* if in set mode, do not update the time */ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + if (rtc_running(s)) { rtc_set_time(s); check_update_timer(s); } break; case RTC_REG_A: + if ((data & 0x60) == 0x60) { + if (rtc_running(s)) { + rtc_update_time(s); + } + /* What happens to UIP when divider reset is enabled is + * unclear from the datasheet. Shouldn't matter much + * though. + */ + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) && + (data & 0x70) <= 0x20) { + /* when the divider reset is removed, the first update cycle + * begins one-half second later*/ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + s->offset = 500000000; + rtc_set_time(s); + } + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + } /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); @@ -327,7 +358,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_REG_B: if (data & REG_B_SET) { /* update cmos to when the rtc was stopping */ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + if (rtc_running(s)) { rtc_update_time(s); } /* set mode: reset UIP mode */ @@ -335,7 +366,8 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ - if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC; rtc_set_time(s); } @@ -449,7 +481,7 @@ static int update_in_progress(RTCState *s) { int64_t guest_nsec; - if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + if (!rtc_running(s)) { return 0; } if (qemu_timer_pending(s->update_timer)) { @@ -486,7 +518,7 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_YEAR: /* if not in set mode, calibrate cmos before * reading*/ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + if (rtc_running(s)) { rtc_update_time(s); } ret = s->cmos_data[s->cmos_index]; -- cgit v1.2.3 From 00cf57747db98c6a9e4219cea39ac3113dde6993 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 2 Aug 2012 18:04:11 +0200 Subject: RTC: Do not fire timer periodically to catch next alarm This patch limits further the usage of a periodic timer. It computes the time of the next alarm, and uses it to skip all intermediate occurrences of the timer. Cc: Yang Zhang Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 14 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index cb65c4f9e..9d530a8a1 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -46,6 +46,11 @@ #endif #define NSEC_PER_SEC 1000000000LL +#define SEC_PER_MIN 60 +#define MIN_PER_HOUR 60 +#define SEC_PER_HOUR 3600 +#define HOUR_PER_DAY 24 +#define SEC_PER_DAY 86400 #define RTC_REINJECT_ON_ACK_COUNT 20 #define RTC_CLOCK_RATE 32768 @@ -69,6 +74,7 @@ typedef struct RTCState { int64_t next_periodic_time; /* update-ended timer */ QEMUTimer *update_timer; + uint64_t next_alarm_time; uint16_t irq_reinject_on_ack_count; uint32_t irq_coalesced; uint32_t period; @@ -82,6 +88,7 @@ static void rtc_set_time(RTCState *s); static void rtc_update_time(RTCState *s); static void rtc_set_cmos(RTCState *s); static inline int rtc_from_bcd(RTCState *s, int a); +static uint64_t get_next_alarm(RTCState *s); static inline bool rtc_running(RTCState *s) { @@ -204,6 +211,7 @@ static void check_update_timer(RTCState *s) { uint64_t next_update_time; uint64_t guest_nsec; + int next_alarm_sec; /* From the data sheet: "Holding the dividers in reset prevents * interrupts from operating, while setting the SET bit allows" @@ -226,9 +234,21 @@ static void check_update_timer(RTCState *s) } guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC; - /* reprogram to next second */ + /* if UF is clear, reprogram to next second */ next_update_time = qemu_get_clock_ns(rtc_clock) + NSEC_PER_SEC - guest_nsec; + + /* Compute time of next alarm. One second is already accounted + * for in next_update_time. + */ + next_alarm_sec = get_next_alarm(s); + s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NSEC_PER_SEC; + + if (s->cmos_data[RTC_REG_C] & REG_C_UF) { + /* UF is set, but AF is clear. Program the timer to target + * the alarm time. */ + next_update_time = s->next_alarm_time; + } if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) { qemu_mod_timer(s->update_timer, next_update_time); } @@ -245,31 +265,95 @@ static inline uint8_t convert_hour(RTCState *s, uint8_t hour) return hour; } -static uint32_t check_alarm(RTCState *s) +static uint64_t get_next_alarm(RTCState *s) { - uint8_t alarm_hour, alarm_min, alarm_sec; - uint8_t cur_hour, cur_min, cur_sec; + int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec; + int32_t hour, min, sec; + + rtc_update_time(s); alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); - alarm_hour = convert_hour(s, alarm_hour); + alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour); cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); cur_hour = convert_hour(s, cur_hour); - if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 - || alarm_sec == cur_sec) && - ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 - || alarm_min == cur_min) && - ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 - || alarm_hour == cur_hour)) { - return 1; + if (alarm_hour == -1) { + alarm_hour = cur_hour; + if (alarm_min == -1) { + alarm_min = cur_min; + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } else if (cur_sec > alarm_sec) { + alarm_min++; + } + } else if (cur_min == alarm_min) { + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } else { + if (cur_sec > alarm_sec) { + alarm_hour++; + } + } + if (alarm_sec == SEC_PER_MIN) { + /* wrap to next hour, minutes is not in don't care mode */ + alarm_sec = 0; + alarm_hour++; + } + } else if (cur_min > alarm_min) { + alarm_hour++; + } + } else if (cur_hour == alarm_hour) { + if (alarm_min == -1) { + alarm_min = cur_min; + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } else if (cur_sec > alarm_sec) { + alarm_min++; + } + + if (alarm_sec == SEC_PER_MIN) { + alarm_sec = 0; + alarm_min++; + } + /* wrap to next day, hour is not in don't care mode */ + alarm_min %= MIN_PER_HOUR; + } else if (cur_min == alarm_min) { + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } + /* wrap to next day, hours+minutes not in don't care mode */ + alarm_sec %= SEC_PER_MIN; + } } - return 0; + /* values that are still don't care fire at the next min/sec */ + if (alarm_min == -1) { + alarm_min = 0; + } + if (alarm_sec == -1) { + alarm_sec = 0; + } + + /* keep values in range */ + if (alarm_sec == SEC_PER_MIN) { + alarm_sec = 0; + alarm_min++; + } + if (alarm_min == MIN_PER_HOUR) { + alarm_min = 0; + alarm_hour++; + } + alarm_hour %= HOUR_PER_DAY; + + hour = alarm_hour - cur_hour; + min = hour * MIN_PER_HOUR + alarm_min - cur_min; + sec = min * SEC_PER_MIN + alarm_sec - cur_sec; + return sec <= 0 ? sec + SEC_PER_DAY : sec; } static void rtc_update_timer(void *opaque) @@ -284,12 +368,13 @@ static void rtc_update_timer(void *opaque) rtc_update_time(s); s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - if (check_alarm(s)) { + if (qemu_get_clock_ns(rtc_clock) >= s->next_alarm_time) { irqs |= REG_C_AF; if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); } } + new_irqs = irqs & ~s->cmos_data[RTC_REG_C]; s->cmos_data[RTC_REG_C] |= irqs; if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { @@ -407,6 +492,9 @@ static inline int rtc_to_bcd(RTCState *s, int a) static inline int rtc_from_bcd(RTCState *s, int a) { + if ((a & 0xc0) == 0xc0) { + return -1; + } if (s->cmos_data[RTC_REG_B] & REG_B_DM) { return a; } else { @@ -642,6 +730,7 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_UINT64_V(last_update, RTCState, 3), VMSTATE_INT64_V(offset, RTCState, 3), VMSTATE_TIMER_V(update_timer, RTCState, 3), + VMSTATE_UINT64_V(next_alarm_time, RTCState, 3), VMSTATE_END_OF_LIST() } }; -- cgit v1.2.3 From e2826cf4a8c89d64cdf8304f861910293f046aa8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 2 Aug 2012 18:04:12 +0200 Subject: RTC: Get and set time without going through s->current_tm This patch makes rtc_set_time and rtc_set_cmos work without reading s->current_tm. In the case of rtc_set_time I introduce a new function that retrieves the time and stores into a given struct tm (not hard-coded to s->current_tm). In the case of rtc_set_cmos, the current time is similarly taken from a struct tm rather than s->current_tm. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 9d530a8a1..a609f721a 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -86,7 +86,7 @@ typedef struct RTCState { static void rtc_set_time(RTCState *s); static void rtc_update_time(RTCState *s); -static void rtc_set_cmos(RTCState *s); +static void rtc_set_cmos(RTCState *s, const struct tm *tm); static inline int rtc_from_bcd(RTCState *s, int a); static uint64_t get_next_alarm(RTCState *s); @@ -502,10 +502,8 @@ static inline int rtc_from_bcd(RTCState *s, int a) } } -static void rtc_set_time(RTCState *s) +static void rtc_get_time(RTCState *s, struct tm *tm) { - struct tm *tm = &s->current_tm; - tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); @@ -519,16 +517,22 @@ static void rtc_set_time(RTCState *s) tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; +} + +static void rtc_set_time(RTCState *s) +{ + struct tm tm; - s->base_rtc = mktimegm(tm); + rtc_get_time(s, &tm); + s->current_tm = tm; + s->base_rtc = mktimegm(&tm); s->last_update = qemu_get_clock_ns(rtc_clock); - rtc_change_mon_event(tm); + rtc_change_mon_event(&tm); } -static void rtc_set_cmos(RTCState *s) +static void rtc_set_cmos(RTCState *s, const struct tm *tm) { - const struct tm *tm = &s->current_tm; int year; s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec); @@ -561,8 +565,8 @@ static void rtc_update_time(RTCState *s) guest_nsec = get_guest_rtc_ns(s); guest_sec = guest_nsec / NSEC_PER_SEC; gmtime_r(&guest_sec, &ret); + rtc_set_cmos(s, &ret); s->current_tm = ret; - rtc_set_cmos(s); } static int update_in_progress(RTCState *s) @@ -677,8 +681,8 @@ static void rtc_set_date_from_host(ISADevice *dev) s->offset = 0; /* set the CMOS date */ + rtc_set_cmos(s, &tm); s->current_tm = tm; - rtc_set_cmos(s); val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val); @@ -789,15 +793,17 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque, { ISADevice *isa = ISA_DEVICE(obj); RTCState *s = DO_UPCAST(RTCState, dev, isa); + struct tm current_tm; rtc_update_time(s); + rtc_get_time(s, ¤t_tm); visit_start_struct(v, NULL, "struct tm", name, 0, errp); - visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp); - visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp); - visit_type_int32(v, &s->current_tm.tm_mday, "tm_mday", errp); - visit_type_int32(v, &s->current_tm.tm_hour, "tm_hour", errp); - visit_type_int32(v, &s->current_tm.tm_min, "tm_min", errp); - visit_type_int32(v, &s->current_tm.tm_sec, "tm_sec", errp); + visit_type_int32(v, ¤t_tm.tm_year, "tm_year", errp); + visit_type_int32(v, ¤t_tm.tm_mon, "tm_mon", errp); + visit_type_int32(v, ¤t_tm.tm_mday, "tm_mday", errp); + visit_type_int32(v, ¤t_tm.tm_hour, "tm_hour", errp); + visit_type_int32(v, ¤t_tm.tm_min, "tm_min", errp); + visit_type_int32(v, ¤t_tm.tm_sec, "tm_sec", errp); visit_end_struct(v, errp); } -- cgit v1.2.3 From 89166459065353c6a49456794f840ffe57016020 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 2 Aug 2012 18:04:13 +0200 Subject: RTC: Remove the current_tm field This is not used anymore and only written to. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/mc146818rtc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index a609f721a..d63554f89 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -61,7 +61,6 @@ typedef struct RTCState { MemoryRegion io; uint8_t cmos_data[128]; uint8_t cmos_index; - struct tm current_tm; int32_t base_year; uint64_t base_rtc; uint64_t last_update; @@ -524,7 +523,6 @@ static void rtc_set_time(RTCState *s) struct tm tm; rtc_get_time(s, &tm); - s->current_tm = tm; s->base_rtc = mktimegm(&tm); s->last_update = qemu_get_clock_ns(rtc_clock); @@ -566,7 +564,6 @@ static void rtc_update_time(RTCState *s) guest_sec = guest_nsec / NSEC_PER_SEC; gmtime_r(&guest_sec, &ret); rtc_set_cmos(s, &ret); - s->current_tm = ret; } static int update_in_progress(RTCState *s) @@ -682,7 +679,6 @@ static void rtc_set_date_from_host(ISADevice *dev) /* set the CMOS date */ rtc_set_cmos(s, &tm); - s->current_tm = tm; val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val); @@ -718,13 +714,7 @@ static const VMStateDescription vmstate_rtc = { .fields = (VMStateField []) { VMSTATE_BUFFER(cmos_data, RTCState), VMSTATE_UINT8(cmos_index, RTCState), - VMSTATE_INT32(current_tm.tm_sec, RTCState), - VMSTATE_INT32(current_tm.tm_min, RTCState), - VMSTATE_INT32(current_tm.tm_hour, RTCState), - VMSTATE_INT32(current_tm.tm_wday, RTCState), - VMSTATE_INT32(current_tm.tm_mday, RTCState), - VMSTATE_INT32(current_tm.tm_mon, RTCState), - VMSTATE_INT32(current_tm.tm_year, RTCState), + VMSTATE_UNUSED(7*4), VMSTATE_TIMER(periodic_timer, RTCState), VMSTATE_INT64(next_periodic_time, RTCState), VMSTATE_UNUSED(3*8), -- cgit v1.2.3 From 66d5499b3754b83c09487259c08fe2ce73188a59 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 10 Sep 2012 12:27:21 +0100 Subject: Add ability to disable build of all targets Allow passing of '--target-list=' to configure to request that all targets are to be disabled. This allows for doing a very fast tools-only build of things like qemu-img, qemu-io, qemu-nbd. Signed-off-by: Daniel P. Berrange Signed-off-by: Anthony Liguori --- configure | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 2e4a3b00f..76289bcc1 100755 --- a/configure +++ b/configure @@ -127,7 +127,7 @@ cc_i386=i386-pc-linux-gnu-gcc libs_qga="" debug_info="yes" -target_list="" +target_list="DEFAULT" # Default value for a variable defining feature "foo". # * foo="no" feature will only be used if --enable-foo arg is given @@ -1317,15 +1317,10 @@ if ! "$python" -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_ exit 1 fi -if test -z "$target_list" ; then - target_list="$default_target_list" -else - target_list=`echo "$target_list" | sed -e 's/,/ /g'` -fi -if test -z "$target_list" ; then - echo "No targets enabled" - exit 1 +if test "$target_list" = "DEFAULT" ; then + target_list=`echo "$default_target_list" | sed -e 's/,/ /g'` fi + # see if system emulation was really requested case " $target_list " in *"-softmmu "*) softmmu=yes -- cgit v1.2.3 From 4b1c11fd20e8901f04a2d9c225cd10fc05a762ff Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 10 Sep 2012 12:26:29 +0100 Subject: Add ability to force enable/disable of tools build The qemu-img, qemu-nbd and qemu-io tools are built conditionally based on whether any softmmu target is enabled. These are useful self-contained tools which can be used in many other scenarios. Add new --enable-tools/--disable-tools args to configure to allow the user to explicitly turn on / off their build. The default behaviour is now to build these tools are all times, regardless of whether any softmmu target is enabled Signed-off-by: Daniel P. Berrange Signed-off-by: Anthony Liguori --- configure | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 76289bcc1..30be78488 100755 --- a/configure +++ b/configure @@ -217,6 +217,7 @@ usb_redir="" opengl="" zlib="yes" guest_agent="yes" +want_tools="yes" libiscsi="" coroutine="" seccomp="" @@ -868,6 +869,10 @@ for opt do ;; --disable-guest-agent) guest_agent="no" ;; + --enable-tools) want_tools="yes" + ;; + --disable-tools) want_tools="no" + ;; --enable-seccomp) seccomp="yes" ;; --disable-seccomp) seccomp="no" @@ -3043,9 +3048,14 @@ fi qemu_confdir=$sysconfdir$confsuffix qemu_datadir=$datadir$confsuffix -tools= -if test "$softmmu" = yes ; then +tools="" +if test "$want_tools" = "yes" ; then tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" + if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then + tools="qemu-nbd\$(EXESUF) $tools" + fi +fi +if test "$softmmu" = yes ; then if test "$virtfs" != no ; then if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then virtfs=yes @@ -3059,14 +3069,13 @@ if test "$softmmu" = yes ; then fi fi if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then - tools="qemu-nbd\$(EXESUF) $tools" if [ "$guest_agent" = "yes" ]; then tools="qemu-ga\$(EXESUF) $tools" fi fi -fi -if test "$smartcard_nss" = "yes" ; then - tools="vscclient\$(EXESUF) $tools" + if test "$smartcard_nss" = "yes" ; then + tools="vscclient\$(EXESUF) $tools" + fi fi # Mac OS X ships with a broken assembler -- cgit v1.2.3