diff options
769 files changed, 16881 insertions, 8706 deletions
diff --git a/.gitignore b/.gitignore index 0fe114d251..d2c5c2f6b8 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,10 @@ qemu-bridge-helper qemu-monitor.texi vscclient QMP/qmp-commands.txt +test-bitops test-coroutine +test-int128 +test-opts-visitor test-qmp-input-visitor test-qmp-output-visitor test-string-input-visitor @@ -2,7 +2,7 @@ # into proper addresses so that they are counted properly in git shortlog output. # Andrzej Zaborowski <balrogg@gmail.com> balrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162> -Anthony Liguori <aliguori@us.ibm.com> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> +Anthony Liguori <anthony@codemonkey.ws> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> Aurelien Jarno <aurelien@aurel32.net> aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> Blue Swirl <blauwirbel@gmail.com> blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> Edgar E. Iglesias <edgar.iglesias@gmail.com> edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> @@ -1,16 +1,21 @@ The following points clarify the QEMU license: -1) QEMU as a whole is released under the GNU General Public License +1) QEMU as a whole is released under the GNU General Public License, +version 2. 2) Parts of QEMU have specific licenses which are compatible with the -GNU General Public License. Hence each source file contains its own -licensing information. +GNU General Public License, version 2. Hence each source file contains +its own licensing information. Source files with no licensing information +are released under the GNU General Public License, version 2 or (at your +option) any later version. -Many hardware device emulation sources are released under the BSD license. +As of July 2013, contributions under version 2 of the GNU General Public +License (and no later version) are only accepted for the following files +or directories: bsd-user/, linux-user/, hw/misc/vfio.c, hw/xen/xen_pt*. 3) The Tiny Code Generator (TCG) is released under the BSD license (see license headers in files). 4) QEMU is a trademark of Fabrice Bellard. -Fabrice Bellard. +Fabrice Bellard and the QEMU team diff --git a/MAINTAINERS b/MAINTAINERS index 93ad19d90e..d128ed035a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -50,7 +50,7 @@ Descriptions of section entries: General Project Administration ------------------------------ -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> M: Paul Brook <paul@codesourcery.com> Guest CPU cores (TCG): @@ -80,6 +80,7 @@ M: Michael Walle <michael@walle.cc> S: Maintained F: target-lm32/ F: hw/lm32/ +F: hw/char/lm32_* M68K M: Paul Brook <paul@codesourcery.com> @@ -224,7 +225,7 @@ ARM Machines Exynos M: Evgeny Voevodin <e.voevodin@samsung.com> M: Maksim Kozlov <m.kozlov@samsung.com> -M: Igor Mitsyanko <i.mitsyanko@samsung.com> +M: Igor Mitsyanko <i.mitsyanko@gmail.com> M: Dmitry Solodkiy <d.solodkiy@samsung.com> S: Maintained F: hw/*/exynos* @@ -508,7 +509,7 @@ F: hw/unicore32/ X86 Machines ------------ PC -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> S: Supported F: hw/i386/pc.[ch] F: hw/i386/pc_piix.c @@ -592,7 +593,7 @@ S: Supported F: hw/*/*vhost* virtio -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> S: Supported F: hw/*/virtio* @@ -650,7 +651,7 @@ F: block/ F: hw/block/ Character Devices -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> S: Maintained F: qemu-char.c @@ -688,7 +689,7 @@ F: audio/spiceaudio.c F: hw/display/qxl* Graphics -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> S: Maintained F: ui/ @@ -698,7 +699,7 @@ S: Odd Fixes F: ui/cocoa.m Main loop -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> S: Supported F: vl.c @@ -710,7 +711,7 @@ F: hmp.c F: hmp-commands.hx Network device layer -M: Anthony Liguori <aliguori@us.ibm.com> +M: Anthony Liguori <anthony@codemonkey.ws> M: Stefan Hajnoczi <stefanha@redhat.com> S: Maintained F: net/ @@ -851,8 +852,9 @@ S: Orphan Stable 0.15 L: qemu-stable@nongnu.org +M: Andreas Färber <afaerber@suse.de> T: git git://git.qemu.org/qemu-stable-0.15.git -S: Orphan +S: Supported Stable 0.14 L: qemu-stable@nongnu.org @@ -167,11 +167,10 @@ recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -version.o: $(SRC_PATH)/version.rc config-host.h | version.lo -version.lo: $(SRC_PATH)/version.rc config-host.h - -version-obj-$(CONFIG_WIN32) += version.o -version-lobj-$(CONFIG_WIN32) += version.lo +$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo + $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o") +$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h + $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.lo") Makefile: $(version-obj-y) $(version-lobj-y) @@ -437,6 +436,61 @@ qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \ qemu-img.texi qemu-nbd.texi qemu-options.texi \ qemu-monitor.texi qemu-img-cmds.texi +ifdef CONFIG_WIN32 + +INSTALLER = qemu-setup-$(VERSION)$(EXESUF) + +nsisflags = -V2 -NOCD + +ifneq ($(wildcard $(SRC_PATH)/dll),) +ifeq ($(ARCH),x86_64) +# 64 bit executables +DLL_PATH = $(SRC_PATH)/dll/w64 +nsisflags += -DW64 +else +# 32 bit executables +DLL_PATH = $(SRC_PATH)/dll/w32 +endif +endif + +.PHONY: installer +installer: $(INSTALLER) + +INSTDIR=/tmp/qemu-nsis + +$(INSTALLER): $(SRC_PATH)/qemu.nsi + make install prefix=${INSTDIR} +ifdef SIGNCODE + (cd ${INSTDIR}; \ + for i in *.exe; do \ + $(SIGNCODE) $${i}; \ + done \ + ) +endif # SIGNCODE + (cd ${INSTDIR}; \ + for i in qemu-system-*.exe; do \ + arch=$${i%.exe}; \ + arch=$${arch#qemu-system-}; \ + echo Section \"$$arch\" Section_$$arch; \ + echo SetOutPath \"\$$INSTDIR\"; \ + echo File \"\$${BINDIR}\\$$i\"; \ + echo SectionEnd; \ + done \ + ) >${INSTDIR}/system-emulations.nsh + makensis $(nsisflags) \ + $(if $(BUILD_DOCS),-DCONFIG_DOCUMENTATION="y") \ + $(if $(CONFIG_GTK),-DCONFIG_GTK="y") \ + -DBINDIR="${INSTDIR}" \ + $(if $(DLL_PATH),-DDLLDIR="$(DLL_PATH)") \ + -DSRCDIR="$(SRC_PATH)" \ + -DOUTFILE="$(INSTALLER)" \ + $(SRC_PATH)/qemu.nsi + rm -r ${INSTDIR} +ifdef SIGNCODE + $(SIGNCODE) $(INSTALLER) +endif # SIGNCODE +endif # CONFIG_WIN + # Add a dependency on the generated files, so that they are always # rebuilt before other object files ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) diff --git a/Makefile.objs b/Makefile.objs index 9928542cdf..f46a4cdd6a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -99,6 +99,11 @@ common-obj-y += qom/ common-obj-y += disas/ ###################################################################### +# Resource file for Windows executables +version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o +version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo + +###################################################################### # guest agent # FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed @@ -1 +1 @@ -1.5.50 +1.6.50 diff --git a/aio-posix.c b/aio-posix.c index b68eccd40c..bd06f33c78 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -23,7 +23,6 @@ struct AioHandler GPollFD pfd; IOHandler *io_read; IOHandler *io_write; - AioFlushHandler *io_flush; int deleted; int pollfds_idx; void *opaque; @@ -47,7 +46,6 @@ void aio_set_fd_handler(AioContext *ctx, int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque) { AioHandler *node; @@ -84,7 +82,6 @@ void aio_set_fd_handler(AioContext *ctx, /* Update handler with latest information */ node->io_read = io_read; node->io_write = io_write; - node->io_flush = io_flush; node->opaque = opaque; node->pollfds_idx = -1; @@ -97,12 +94,10 @@ void aio_set_fd_handler(AioContext *ctx, void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush) + EventNotifierHandler *io_read) { aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), - (IOHandler *)io_read, NULL, - (AioFlushHandler *)io_flush, notifier); + (IOHandler *)io_read, NULL, notifier); } bool aio_pending(AioContext *ctx) @@ -147,7 +142,11 @@ static bool aio_dispatch(AioContext *ctx) (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) && node->io_read) { node->io_read(node->opaque); - progress = true; + + /* aio_notify() does not count as progress */ + if (node->opaque != &ctx->notifier) { + progress = true; + } } if (!node->deleted && (revents & (G_IO_OUT | G_IO_ERR)) && @@ -166,6 +165,10 @@ static bool aio_dispatch(AioContext *ctx) g_free(tmp); } } + + /* Run our timers */ + progress |= timerlistgroup_run_timers(&ctx->tlg); + return progress; } @@ -173,7 +176,7 @@ bool aio_poll(AioContext *ctx, bool blocking) { AioHandler *node; int ret; - bool busy, progress; + bool progress; progress = false; @@ -200,20 +203,8 @@ bool aio_poll(AioContext *ctx, bool blocking) g_array_set_size(ctx->pollfds, 0); /* fill pollfds */ - busy = false; QLIST_FOREACH(node, &ctx->aio_handlers, node) { node->pollfds_idx = -1; - - /* If there aren't pending AIO operations, don't invoke callbacks. - * Otherwise, if there are no AIO requests, qemu_aio_wait() would - * wait indefinitely. - */ - if (!node->deleted && node->io_flush) { - if (node->io_flush(node->opaque) == 0) { - continue; - } - busy = true; - } if (!node->deleted && node->pfd.events) { GPollFD pfd = { .fd = node->pfd.fd, @@ -226,15 +217,15 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers--; - /* No AIO operations? Get us out of here */ - if (!busy) { + /* early return if we only have the aio_notify() fd */ + if (ctx->pollfds->len == 1) { return progress; } /* wait until next event */ - ret = g_poll((GPollFD *)ctx->pollfds->data, - ctx->pollfds->len, - blocking ? -1 : 0); + ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data, + ctx->pollfds->len, + blocking ? timerlistgroup_deadline_ns(&ctx->tlg) : 0); /* if we have any readable fds, dispatch event */ if (ret > 0) { @@ -245,11 +236,12 @@ bool aio_poll(AioContext *ctx, bool blocking) node->pfd.revents = pfd->revents; } } - if (aio_dispatch(ctx)) { - progress = true; - } } - assert(progress || busy); - return true; + /* Run dispatch even if there were no readable fds to run timers */ + if (aio_dispatch(ctx)) { + progress = true; + } + + return progress; } diff --git a/aio-win32.c b/aio-win32.c index 38723bf1d3..f9cfbb75ac 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -23,7 +23,6 @@ struct AioHandler { EventNotifier *e; EventNotifierHandler *io_notify; - AioFlushEventNotifierHandler *io_flush; GPollFD pfd; int deleted; QLIST_ENTRY(AioHandler) node; @@ -31,8 +30,7 @@ struct AioHandler { void aio_set_event_notifier(AioContext *ctx, EventNotifier *e, - EventNotifierHandler *io_notify, - AioFlushEventNotifierHandler *io_flush) + EventNotifierHandler *io_notify) { AioHandler *node; @@ -73,7 +71,6 @@ void aio_set_event_notifier(AioContext *ctx, } /* Update handler with latest information */ node->io_notify = io_notify; - node->io_flush = io_flush; } aio_notify(ctx); @@ -96,8 +93,9 @@ bool aio_poll(AioContext *ctx, bool blocking) { AioHandler *node; HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; - bool busy, progress; + bool progress; int count; + int timeout; progress = false; @@ -111,6 +109,9 @@ bool aio_poll(AioContext *ctx, bool blocking) progress = true; } + /* Run timers */ + progress |= timerlistgroup_run_timers(&ctx->tlg); + /* * Then dispatch any pending callbacks from the GSource. * @@ -126,7 +127,11 @@ bool aio_poll(AioContext *ctx, bool blocking) if (node->pfd.revents && node->io_notify) { node->pfd.revents = 0; node->io_notify(node->e); - progress = true; + + /* aio_notify() does not count as progress */ + if (node->e != &ctx->notifier) { + progress = true; + } } tmp = node; @@ -147,19 +152,8 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers++; /* fill fd sets */ - busy = false; count = 0; QLIST_FOREACH(node, &ctx->aio_handlers, node) { - /* If there aren't pending AIO operations, don't invoke callbacks. - * Otherwise, if there are no AIO requests, qemu_aio_wait() would - * wait indefinitely. - */ - if (!node->deleted && node->io_flush) { - if (node->io_flush(node->e) == 0) { - continue; - } - busy = true; - } if (!node->deleted && node->io_notify) { events[count++] = event_notifier_get_handle(node->e); } @@ -167,15 +161,18 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers--; - /* No AIO operations? Get us out of here */ - if (!busy) { + /* early return if we only have the aio_notify() fd */ + if (count == 1) { return progress; } /* wait until next event */ while (count > 0) { - int timeout = blocking ? INFINITE : 0; - int ret = WaitForMultipleObjects(count, events, FALSE, timeout); + int ret; + + timeout = blocking ? + qemu_timeout_ns_to_ms(timerlistgroup_deadline_ns(&ctx->tlg)) : 0; + ret = WaitForMultipleObjects(count, events, FALSE, timeout); /* if we have any signaled events, dispatch event */ if ((DWORD) (ret - WAIT_OBJECT_0) >= count) { @@ -196,7 +193,11 @@ bool aio_poll(AioContext *ctx, bool blocking) event_notifier_get_handle(node->e) == events[ret - WAIT_OBJECT_0] && node->io_notify) { node->io_notify(node->e); - progress = true; + + /* aio_notify() does not count as progress */ + if (node->e != &ctx->notifier) { + progress = true; + } } tmp = node; @@ -214,6 +215,14 @@ bool aio_poll(AioContext *ctx, bool blocking) events[ret - WAIT_OBJECT_0] = events[--count]; } - assert(progress || busy); - return true; + if (blocking) { + /* Run the timers a second time. We do this because otherwise aio_wait + * will not note progress - and will stop a drain early - if we have + * a timer that was not ready to run entering g_poll but is ready + * after g_poll. This will only do anything if a timer has expired. + */ + progress |= timerlistgroup_run_timers(&ctx->tlg); + } + + return progress; } diff --git a/arch_init.c b/arch_init.c index 68a7ab784f..0471cd5a6b 100644 --- a/arch_init.c +++ b/arch_init.c @@ -342,7 +342,8 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr, { unsigned long base = mr->ram_addr >> TARGET_PAGE_BITS; unsigned long nr = base + (start >> TARGET_PAGE_BITS); - unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS); + uint64_t mr_size = TARGET_PAGE_ALIGN(memory_region_size(mr)); + unsigned long size = base + (mr_size >> TARGET_PAGE_BITS); unsigned long next; @@ -392,7 +393,7 @@ static void migration_bitmap_sync(void) } if (!start_time) { - start_time = qemu_get_clock_ms(rt_clock); + start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); } trace_migration_bitmap_sync_start(); @@ -410,7 +411,7 @@ static void migration_bitmap_sync(void) trace_migration_bitmap_sync_end(migration_dirty_pages - num_dirty_pages_init); num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init; - end_time = qemu_get_clock_ms(rt_clock); + end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); /* more than 1 second = 1000 millisecons */ if (end_time > start_time + 1000) { @@ -672,7 +673,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) ram_control_before_iterate(f, RAM_CONTROL_ROUND); - t0 = qemu_get_clock_ns(rt_clock); + t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); i = 0; while ((ret = qemu_file_rate_limit(f)) == 0) { int bytes_sent; @@ -691,7 +692,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) iterations */ if ((i & 63) == 0) { - uint64_t t1 = (qemu_get_clock_ns(rt_clock) - t0) / 1000000; + uint64_t t1 = (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - t0) / 1000000; if (t1 > MAX_WAIT) { DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n", t1, i); @@ -1125,8 +1126,8 @@ void do_acpitable_option(const QemuOpts *opts) acpi_table_add(opts, &err); if (err) { - fprintf(stderr, "Wrong acpi table provided: %s\n", - error_get_pretty(err)); + error_report("Wrong acpi table provided: %s", + error_get_pretty(err)); error_free(err); exit(1); } @@ -1217,11 +1218,11 @@ static void check_guest_throttling(void) } if (!t0) { - t0 = qemu_get_clock_ns(rt_clock); + t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); return; } - t1 = qemu_get_clock_ns(rt_clock); + t1 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); /* If it has been more than 40 ms since the last time the guest * was throttled then do it again. @@ -150,7 +150,10 @@ aio_ctx_prepare(GSource *source, gint *timeout) { AioContext *ctx = (AioContext *) source; QEMUBH *bh; + int deadline; + /* We assume there is no timeout already supplied */ + *timeout = -1; for (bh = ctx->first_bh; bh; bh = bh->next) { if (!bh->deleted && bh->scheduled) { if (bh->idle) { @@ -166,6 +169,14 @@ aio_ctx_prepare(GSource *source, gint *timeout) } } + deadline = qemu_timeout_ns_to_ms(timerlistgroup_deadline_ns(&ctx->tlg)); + if (deadline == 0) { + *timeout = 0; + return true; + } else { + *timeout = qemu_soonest_timeout(*timeout, deadline); + } + return false; } @@ -180,7 +191,7 @@ aio_ctx_check(GSource *source) return true; } } - return aio_pending(ctx); + return aio_pending(ctx) || (timerlistgroup_deadline_ns(&ctx->tlg) == 0); } static gboolean @@ -201,10 +212,11 @@ aio_ctx_finalize(GSource *source) AioContext *ctx = (AioContext *) source; thread_pool_free(ctx->thread_pool); - aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL); + aio_set_event_notifier(ctx, &ctx->notifier, NULL); event_notifier_cleanup(&ctx->notifier); qemu_mutex_destroy(&ctx->bh_lock); g_array_free(ctx->pollfds, TRUE); + timerlistgroup_deinit(&ctx->tlg); } static GSourceFuncs aio_source_funcs = { @@ -233,6 +245,11 @@ void aio_notify(AioContext *ctx) event_notifier_set(&ctx->notifier); } +static void aio_timerlist_notify(void *opaque) +{ + aio_notify(opaque); +} + AioContext *aio_context_new(void) { AioContext *ctx; @@ -243,7 +260,8 @@ AioContext *aio_context_new(void) event_notifier_init(&ctx->notifier, false); aio_set_event_notifier(ctx, &ctx->notifier, (EventNotifierHandler *) - event_notifier_test_and_clear, NULL); + event_notifier_test_and_clear); + timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx); return ctx; } diff --git a/audio/audio.c b/audio/audio.c index 02bb8861f8..af4cdf60e7 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1124,10 +1124,10 @@ static int audio_is_timer_needed (void) static void audio_reset_timer (AudioState *s) { if (audio_is_timer_needed ()) { - qemu_mod_timer (s->ts, qemu_get_clock_ns (vm_clock) + 1); + timer_mod (s->ts, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1); } else { - qemu_del_timer (s->ts); + timer_del (s->ts); } } @@ -1834,7 +1834,7 @@ static void audio_init (void) QLIST_INIT (&s->cap_head); atexit (audio_atexit); - s->ts = qemu_new_timer_ns (vm_clock, audio_timer, s); + s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); if (!s->ts) { hw_error("Could not create audio timer\n"); } diff --git a/audio/noaudio.c b/audio/noaudio.c index 9f23aa2cb3..cb386620ae 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -46,7 +46,7 @@ static int no_run_out (HWVoiceOut *hw, int live) int64_t ticks; int64_t bytes; - now = qemu_get_clock_ns (vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ticks = now - no->old_ticks; bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ()); bytes = audio_MIN (bytes, INT_MAX); @@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw) int samples = 0; if (dead) { - int64_t now = qemu_get_clock_ns (vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t ticks = now - no->old_ticks; int64_t bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ()); diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index bc24557de4..5af436c31d 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -81,7 +81,7 @@ static void spice_audio_fini (void *opaque) static void rate_start (SpiceRateCtl *rate) { memset (rate, 0, sizeof (*rate)); - rate->start_ticks = qemu_get_clock_ns (vm_clock); + rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) @@ -91,7 +91,7 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) int64_t bytes; int64_t samples; - now = qemu_get_clock_ns (vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ticks = now - rate->start_ticks; bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ()); samples = (bytes - rate->bytes_sent) >> info->shift; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 950fa8f19c..6846a1a9f7 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -52,7 +52,7 @@ static int wav_run_out (HWVoiceOut *hw, int live) int rpos, decr, samples; uint8_t *dst; struct st_sample *src; - int64_t now = qemu_get_clock_ns (vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t ticks = now - wav->old_ticks; int64_t bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ()); diff --git a/backends/baum.c b/backends/baum.c index 62aa784436..1132899026 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -314,9 +314,9 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) return 0; \ if (*cur++ != ESC) { \ DPRINTF("Broken packet %#2x, tossing\n", req); \ - if (qemu_timer_pending(baum->cellCount_timer)) { \ - qemu_del_timer(baum->cellCount_timer); \ - baum_cellCount_timer_cb(baum); \ + if (timer_pending(baum->cellCount_timer)) { \ + timer_del(baum->cellCount_timer); \ + baum_cellCount_timer_cb(baum); \ } \ return (cur - 2 - buf); \ } \ @@ -334,7 +334,7 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) int i; /* Allow 100ms to complete the DisplayData packet */ - qemu_mod_timer(baum->cellCount_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() / 10); for (i = 0; i < baum->x * baum->y ; i++) { EAT(c); @@ -348,7 +348,7 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) c = '?'; text[i] = c; } - qemu_del_timer(baum->cellCount_timer); + timer_del(baum->cellCount_timer); memset(zero, 0, sizeof(zero)); @@ -553,7 +553,7 @@ static void baum_close(struct CharDriverState *chr) { BaumDriverState *baum = chr->opaque; - qemu_free_timer(baum->cellCount_timer); + timer_free(baum->cellCount_timer); if (baum->brlapi) { brlapi__closeConnection(baum->brlapi); g_free(baum->brlapi); @@ -588,7 +588,7 @@ CharDriverState *chr_baum_init(void) goto fail_handle; } - baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum); + baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum); if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) { brlapi_perror("baum_init: brlapi_getDisplaySize"); @@ -614,7 +614,7 @@ CharDriverState *chr_baum_init(void) return chr; fail: - qemu_free_timer(baum->cellCount_timer); + timer_free(baum->cellCount_timer); brlapi__closeConnection(handle); fail_handle: g_free(handle); @@ -127,11 +127,11 @@ void bdrv_io_limits_disable(BlockDriverState *bs) { bs->io_limits_enabled = false; - while (qemu_co_queue_next(&bs->throttled_reqs)); + do {} while (qemu_co_enter_next(&bs->throttled_reqs)); if (bs->block_timer) { - qemu_del_timer(bs->block_timer); - qemu_free_timer(bs->block_timer); + timer_del(bs->block_timer); + timer_free(bs->block_timer); bs->block_timer = NULL; } @@ -143,13 +143,12 @@ static void bdrv_block_timer(void *opaque) { BlockDriverState *bs = opaque; - qemu_co_queue_next(&bs->throttled_reqs); + qemu_co_enter_next(&bs->throttled_reqs); } void bdrv_io_limits_enable(BlockDriverState *bs) { - qemu_co_queue_init(&bs->throttled_reqs); - bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs); + bs->block_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, bdrv_block_timer, bs); bs->io_limits_enabled = true; } @@ -181,8 +180,8 @@ static void bdrv_io_limits_intercept(BlockDriverState *bs, */ while (bdrv_exceed_io_limits(bs, nb_sectors, is_write, &wait_time)) { - qemu_mod_timer(bs->block_timer, - wait_time + qemu_get_clock_ns(vm_clock)); + timer_mod(bs->block_timer, + wait_time + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); qemu_co_queue_wait_insert_head(&bs->throttled_reqs); } @@ -306,6 +305,7 @@ BlockDriverState *bdrv_new(const char *device_name) bdrv_iostatus_disable(bs); notifier_list_init(&bs->close_notifiers); notifier_with_return_list_init(&bs->before_write_notifiers); + qemu_co_queue_init(&bs->throttled_reqs); return bs; } @@ -706,6 +706,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bs->open_flags = flags; bs->buffer_alignment = 512; + bs->zero_beyond_eof = true; open_flags = bdrv_open_flags(bs, flags); bs->read_only = !(open_flags & BDRV_O_RDWR); @@ -970,6 +971,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, char tmp_filename[PATH_MAX + 1]; BlockDriverState *file = NULL; QDict *file_options = NULL; + const char *drvname; /* NULL means an empty set of options */ if (options == NULL) { @@ -1059,6 +1061,12 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } /* Find the right image format driver */ + drvname = qdict_get_try_str(options, "driver"); + if (drvname) { + drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR)); + qdict_del(options, "driver"); + } + if (!drv) { ret = find_image_format(file, filename, &drv); } @@ -1395,6 +1403,7 @@ void bdrv_close(BlockDriverState *bs) bs->valid_key = 0; bs->sg = 0; bs->growable = 0; + bs->zero_beyond_eof = false; QDECREF(bs->options); bs->options = NULL; @@ -1421,6 +1430,35 @@ void bdrv_close_all(void) } } +/* Check if any requests are in-flight (including throttled requests) */ +static bool bdrv_requests_pending(BlockDriverState *bs) +{ + if (!QLIST_EMPTY(&bs->tracked_requests)) { + return true; + } + if (!qemu_co_queue_empty(&bs->throttled_reqs)) { + return true; + } + if (bs->file && bdrv_requests_pending(bs->file)) { + return true; + } + if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) { + return true; + } + return false; +} + +static bool bdrv_requests_pending_all(void) +{ + BlockDriverState *bs; + QTAILQ_FOREACH(bs, &bdrv_states, list) { + if (bdrv_requests_pending(bs)) { + return true; + } + } + return false; +} + /* * Wait for pending requests to complete across all BlockDriverStates * @@ -1435,27 +1473,22 @@ void bdrv_close_all(void) */ void bdrv_drain_all(void) { + /* Always run first iteration so any pending completion BHs run */ + bool busy = true; BlockDriverState *bs; - bool busy; - - do { - busy = qemu_aio_wait(); + while (busy) { /* FIXME: We do not have timer support here, so this is effectively * a busy wait. */ QTAILQ_FOREACH(bs, &bdrv_states, list) { - if (!qemu_co_queue_empty(&bs->throttled_reqs)) { - qemu_co_queue_restart_all(&bs->throttled_reqs); + while (qemu_co_enter_next(&bs->throttled_reqs)) { busy = true; } } - } while (busy); - /* If requests are still pending there is a bug somewhere */ - QTAILQ_FOREACH(bs, &bdrv_states, list) { - assert(QLIST_EMPTY(&bs->tracked_requests)); - assert(qemu_co_queue_empty(&bs->throttled_reqs)); + busy = bdrv_requests_pending_all(); + busy |= aio_poll(qemu_get_aio_context(), busy); } } @@ -1600,11 +1633,11 @@ void bdrv_delete(BlockDriverState *bs) assert(!bs->job); assert(!bs->in_use); + bdrv_close(bs); + /* remove from list, if necessary */ bdrv_make_anon(bs); - bdrv_close(bs); - g_free(bs); } @@ -2538,7 +2571,35 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, } } - ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov); + if (!(bs->zero_beyond_eof && bs->growable)) { + ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov); + } else { + /* Read zeros after EOF of growable BDSes */ + int64_t len, total_sectors, max_nb_sectors; + + len = bdrv_getlength(bs); + if (len < 0) { + ret = len; + goto out; + } + + total_sectors = len >> BDRV_SECTOR_BITS; + max_nb_sectors = MAX(0, total_sectors - sector_num); + if (max_nb_sectors > 0) { + ret = drv->bdrv_co_readv(bs, sector_num, + MIN(nb_sectors, max_nb_sectors), qiov); + } else { + ret = 0; + } + + /* Reading beyond end of file is supposed to produce zeroes */ + if (ret == 0 && total_sectors < sector_num + nb_sectors) { + uint64_t offset = MAX(0, total_sectors - sector_num); + uint64_t bytes = (sector_num + nb_sectors - offset) * + BDRV_SECTOR_SIZE; + qemu_iovec_memset(qiov, offset * BDRV_SECTOR_SIZE, 0, bytes); + } + } out: tracked_request_end(&req); @@ -3686,7 +3747,7 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors, double elapsed_time; int bps_ret, iops_ret; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (now > bs->slice_end) { bs->slice_start = now; bs->slice_end = now + BLOCK_IO_SLICE_TIME; @@ -3706,7 +3767,7 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors, *wait = max_wait; } - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (bs->slice_end < now + max_wait) { bs->slice_end = now + max_wait; } diff --git a/block/backup.c b/block/backup.c index 16105d40b1..e12b3b1461 100644 --- a/block/backup.c +++ b/block/backup.c @@ -37,6 +37,7 @@ typedef struct CowRequest { typedef struct BackupBlockJob { BlockJob common; BlockDriverState *target; + MirrorSyncMode sync_mode; RateLimit limit; BlockdevOnError on_source_error; BlockdevOnError on_target_error; @@ -247,40 +248,83 @@ static void coroutine_fn backup_run(void *opaque) bdrv_add_before_write_notifier(bs, &before_write); - for (; start < end; start++) { - bool error_is_read; - - if (block_job_is_cancelled(&job->common)) { - break; + if (job->sync_mode == MIRROR_SYNC_MODE_NONE) { + while (!block_job_is_cancelled(&job->common)) { + /* Yield until the job is cancelled. We just let our before_write + * notify callback service CoW requests. */ + job->common.busy = false; + qemu_coroutine_yield(); + job->common.busy = true; } + } else { + /* Both FULL and TOP SYNC_MODE's require copying.. */ + for (; start < end; start++) { + bool error_is_read; - /* we need to yield so that qemu_aio_flush() returns. - * (without, VM does not reboot) - */ - if (job->common.speed) { - uint64_t delay_ns = ratelimit_calculate_delay( - &job->limit, job->sectors_read); - job->sectors_read = 0; - block_job_sleep_ns(&job->common, rt_clock, delay_ns); - } else { - block_job_sleep_ns(&job->common, rt_clock, 0); - } + if (block_job_is_cancelled(&job->common)) { + break; + } - if (block_job_is_cancelled(&job->common)) { - break; - } + /* we need to yield so that qemu_aio_flush() returns. + * (without, VM does not reboot) + */ + if (job->common.speed) { + uint64_t delay_ns = ratelimit_calculate_delay( + &job->limit, job->sectors_read); + job->sectors_read = 0; + block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns); + } else { + block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0); + } - ret = backup_do_cow(bs, start * BACKUP_SECTORS_PER_CLUSTER, - BACKUP_SECTORS_PER_CLUSTER, &error_is_read); - if (ret < 0) { - /* Depending on error action, fail now or retry cluster */ - BlockErrorAction action = - backup_error_action(job, error_is_read, -ret); - if (action == BDRV_ACTION_REPORT) { + if (block_job_is_cancelled(&job->common)) { break; - } else { - start--; - continue; + } + + if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { + int i, n; + int alloced = 0; + + /* Check to see if these blocks are already in the + * backing file. */ + + for (i = 0; i < BACKUP_SECTORS_PER_CLUSTER;) { + /* bdrv_co_is_allocated() only returns true/false based + * on the first set of sectors it comes accross that + * are are all in the same state. + * For that reason we must verify each sector in the + * backup cluster length. We end up copying more than + * needed but at some point that is always the case. */ + alloced = + bdrv_co_is_allocated(bs, + start * BACKUP_SECTORS_PER_CLUSTER + i, + BACKUP_SECTORS_PER_CLUSTER - i, &n); + i += n; + + if (alloced == 1) { + break; + } + } + + /* If the above loop never found any sectors that are in + * the topmost image, skip this backup. */ + if (alloced == 0) { + continue; + } + } + /* FULL sync mode we copy the whole drive. */ + ret = backup_do_cow(bs, start * BACKUP_SECTORS_PER_CLUSTER, + BACKUP_SECTORS_PER_CLUSTER, &error_is_read); + if (ret < 0) { + /* Depending on error action, fail now or retry cluster */ + BlockErrorAction action = + backup_error_action(job, error_is_read, -ret); + if (action == BDRV_ACTION_REPORT) { + break; + } else { + start--; + continue; + } } } } @@ -300,7 +344,7 @@ static void coroutine_fn backup_run(void *opaque) } void backup_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, + int64_t speed, MirrorSyncMode sync_mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, @@ -335,6 +379,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, job->on_source_error = on_source_error; job->on_target_error = on_target_error; job->target = target; + job->sync_mode = sync_mode; job->common.len = len; job->common.co = qemu_coroutine_create(backup_run); qemu_coroutine_enter(job->common.co, job); diff --git a/block/commit.c b/block/commit.c index 2227fc2e6c..51a1ab3678 100644 --- a/block/commit.c +++ b/block/commit.c @@ -103,7 +103,7 @@ wait: /* Note that even when no rate limit is applied we need to yield * with no pending I/O here so that bdrv_drain_all() returns. */ - block_job_sleep_ns(&s->common, rt_clock, delay_ns); + block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); if (block_job_is_cancelled(&s->common)) { break; } diff --git a/block/curl.c b/block/curl.c index 82d39ff53f..e566855f76 100644 --- a/block/curl.c +++ b/block/curl.c @@ -86,7 +86,6 @@ typedef struct BDRVCURLState { static void curl_clean_state(CURLState *s); static void curl_multi_do(void *arg); -static int curl_aio_flush(void *opaque); static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, void *s, void *sp) @@ -94,17 +93,16 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd); switch (action) { case CURL_POLL_IN: - qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, s); + qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s); break; case CURL_POLL_OUT: - qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s); + qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s); break; case CURL_POLL_INOUT: - qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, - curl_aio_flush, s); + qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s); break; case CURL_POLL_REMOVE: - qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(fd, NULL, NULL, NULL); break; } @@ -495,21 +493,6 @@ out_noclean: return -EINVAL; } -static int curl_aio_flush(void *opaque) -{ - BDRVCURLState *s = opaque; - int i, j; - - for (i=0; i < CURL_NUM_STATES; i++) { - for(j=0; j < CURL_NUM_ACB; j++) { - if (s->states[i].acb[j]) { - return 1; - } - } - } - return 0; -} - static void curl_aio_cancel(BlockDriverAIOCB *blockacb) { // Do we have to implement canceling? Seems to work without... diff --git a/block/gluster.c b/block/gluster.c index 6de418c0bd..46f36f8cd6 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -32,7 +32,6 @@ typedef struct BDRVGlusterState { struct glfs *glfs; int fds[2]; struct glfs_fd *fd; - int qemu_aio_count; int event_reader_pos; GlusterAIOCB *event_acb; } BDRVGlusterState; @@ -247,7 +246,6 @@ static void qemu_gluster_complete_aio(GlusterAIOCB *acb, BDRVGlusterState *s) ret = -EIO; /* Partial read/write - fail it */ } - s->qemu_aio_count--; qemu_aio_release(acb); cb(opaque, ret); if (finished) { @@ -275,13 +273,6 @@ static void qemu_gluster_aio_event_reader(void *opaque) } while (ret < 0 && errno == EINTR); } -static int qemu_gluster_aio_flush_cb(void *opaque) -{ - BDRVGlusterState *s = opaque; - - return (s->qemu_aio_count > 0); -} - /* TODO Convert to fine grained options */ static QemuOptsList runtime_opts = { .name = "gluster", @@ -348,7 +339,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, } fcntl(s->fds[GLUSTER_FD_READ], F_SETFL, O_NONBLOCK); qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], - qemu_gluster_aio_event_reader, NULL, qemu_gluster_aio_flush_cb, s); + qemu_gluster_aio_event_reader, NULL, s); out: qemu_opts_del(opts); @@ -445,11 +436,9 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg) qemu_mutex_lock_iothread(); /* We are in gluster thread context */ acb->common.cb(acb->common.opaque, -EIO); qemu_aio_release(acb); - s->qemu_aio_count--; close(s->fds[GLUSTER_FD_READ]); close(s->fds[GLUSTER_FD_WRITE]); - qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL, - NULL); + qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL); bs->drv = NULL; /* Make the disk inaccessible */ qemu_mutex_unlock_iothread(); } @@ -467,7 +456,6 @@ static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs, offset = sector_num * BDRV_SECTOR_SIZE; size = nb_sectors * BDRV_SECTOR_SIZE; - s->qemu_aio_count++; acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque); acb->size = size; @@ -488,11 +476,23 @@ static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs, return &acb->common; out: - s->qemu_aio_count--; qemu_aio_release(acb); return NULL; } +static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset) +{ + int ret; + BDRVGlusterState *s = bs->opaque; + + ret = glfs_ftruncate(s->fd, offset); + if (ret < 0) { + return -errno; + } + + return 0; +} + static BlockDriverAIOCB *qemu_gluster_aio_readv(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) @@ -518,7 +518,6 @@ static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs, acb->size = 0; acb->ret = 0; acb->finished = NULL; - s->qemu_aio_count++; ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb); if (ret < 0) { @@ -527,7 +526,6 @@ static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs, return &acb->common; out: - s->qemu_aio_count--; qemu_aio_release(acb); return NULL; } @@ -550,7 +548,6 @@ static BlockDriverAIOCB *qemu_gluster_aio_discard(BlockDriverState *bs, acb->size = 0; acb->ret = 0; acb->finished = NULL; - s->qemu_aio_count++; ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb); if (ret < 0) { @@ -559,7 +556,6 @@ static BlockDriverAIOCB *qemu_gluster_aio_discard(BlockDriverState *bs, return &acb->common; out: - s->qemu_aio_count--; qemu_aio_release(acb); return NULL; } @@ -598,7 +594,7 @@ static void qemu_gluster_close(BlockDriverState *bs) close(s->fds[GLUSTER_FD_READ]); close(s->fds[GLUSTER_FD_WRITE]); - qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL); if (s->fd) { glfs_close(s->fd); @@ -631,6 +627,7 @@ static BlockDriver bdrv_gluster = { .bdrv_create = qemu_gluster_create, .bdrv_getlength = qemu_gluster_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_truncate = qemu_gluster_truncate, .bdrv_aio_readv = qemu_gluster_aio_readv, .bdrv_aio_writev = qemu_gluster_aio_writev, .bdrv_aio_flush = qemu_gluster_aio_flush, @@ -650,6 +647,7 @@ static BlockDriver bdrv_gluster_tcp = { .bdrv_create = qemu_gluster_create, .bdrv_getlength = qemu_gluster_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_truncate = qemu_gluster_truncate, .bdrv_aio_readv = qemu_gluster_aio_readv, .bdrv_aio_writev = qemu_gluster_aio_writev, .bdrv_aio_flush = qemu_gluster_aio_flush, @@ -669,6 +667,7 @@ static BlockDriver bdrv_gluster_unix = { .bdrv_create = qemu_gluster_create, .bdrv_getlength = qemu_gluster_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_truncate = qemu_gluster_truncate, .bdrv_aio_readv = qemu_gluster_aio_readv, .bdrv_aio_writev = qemu_gluster_aio_writev, .bdrv_aio_flush = qemu_gluster_aio_flush, @@ -688,6 +687,7 @@ static BlockDriver bdrv_gluster_rdma = { .bdrv_create = qemu_gluster_create, .bdrv_getlength = qemu_gluster_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_truncate = qemu_gluster_truncate, .bdrv_aio_readv = qemu_gluster_aio_readv, .bdrv_aio_writev = qemu_gluster_aio_writev, .bdrv_aio_flush = qemu_gluster_aio_flush, diff --git a/block/iscsi.c b/block/iscsi.c index 5f28c6a2ea..2bbee1f6e5 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -146,13 +146,6 @@ static const AIOCBInfo iscsi_aiocb_info = { static void iscsi_process_read(void *arg); static void iscsi_process_write(void *arg); -static int iscsi_process_flush(void *arg) -{ - IscsiLun *iscsilun = arg; - - return iscsi_queue_length(iscsilun->iscsi) > 0; -} - static void iscsi_set_events(IscsiLun *iscsilun) { @@ -166,7 +159,6 @@ iscsi_set_events(IscsiLun *iscsilun) qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read, (ev & POLLOUT) ? iscsi_process_write : NULL, - iscsi_process_flush, iscsilun); } @@ -247,7 +239,9 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors, { if ((sector_num * BDRV_SECTOR_SIZE) % iscsilun->block_size || (nb_sectors * BDRV_SECTOR_SIZE) % iscsilun->block_size) { - error_report("iSCSI misaligned request: iscsilun->block_size %u, sector_num %ld, nb_sectors %d", + error_report("iSCSI misaligned request: " + "iscsilun->block_size %u, sector_num %" PRIi64 + ", nb_sectors %d", iscsilun->block_size, sector_num, nb_sectors); return 0; } @@ -966,7 +960,7 @@ static void iscsi_nop_timed_event(void *opaque) return; } - qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL); + timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); iscsi_set_events(iscsilun); } #endif @@ -1179,8 +1173,8 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags) #if defined(LIBISCSI_FEATURE_NOP_COUNTER) /* Set up a timer for sending out iSCSI NOPs */ - iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun); - qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL); + iscsilun->nop_timer = timer_new_ms(QEMU_CLOCK_REALTIME, iscsi_nop_timed_event, iscsilun); + timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); #endif out: @@ -1210,10 +1204,10 @@ static void iscsi_close(BlockDriverState *bs) struct iscsi_context *iscsi = iscsilun->iscsi; if (iscsilun->nop_timer) { - qemu_del_timer(iscsilun->nop_timer); - qemu_free_timer(iscsilun->nop_timer); + timer_del(iscsilun->nop_timer); + timer_free(iscsilun->nop_timer); } - qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL); iscsi_destroy_context(iscsi); memset(iscsilun, 0, sizeof(IscsiLun)); } @@ -1273,8 +1267,8 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) goto out; } if (iscsilun->nop_timer) { - qemu_del_timer(iscsilun->nop_timer); - qemu_free_timer(iscsilun->nop_timer); + timer_del(iscsilun->nop_timer); + timer_free(iscsilun->nop_timer); } if (iscsilun->type != TYPE_DISK) { ret = -ENODEV; diff --git a/block/linux-aio.c b/block/linux-aio.c index ee0f8d10c9..53434e2df5 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -39,7 +39,6 @@ struct qemu_laiocb { struct qemu_laio_state { io_context_t ctx; EventNotifier e; - int count; }; static inline ssize_t io_event_ret(struct io_event *ev) @@ -55,8 +54,6 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s, { int ret; - s->count--; - ret = laiocb->ret; if (ret != -ECANCELED) { if (ret == laiocb->nbytes) { @@ -101,13 +98,6 @@ static void qemu_laio_completion_cb(EventNotifier *e) } } -static int qemu_laio_flush_cb(EventNotifier *e) -{ - struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e); - - return (s->count > 0) ? 1 : 0; -} - static void laio_cancel(BlockDriverAIOCB *blockacb) { struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb; @@ -177,14 +167,11 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, goto out_free_aiocb; } io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e)); - s->count++; if (io_submit(s->ctx, 1, &iocbs) < 0) - goto out_dec_count; + goto out_free_aiocb; return &laiocb->common; -out_dec_count: - s->count--; out_free_aiocb: qemu_aio_release(laiocb); return NULL; @@ -203,8 +190,7 @@ void *laio_init(void) goto out_close_efd; } - qemu_aio_set_event_notifier(&s->e, qemu_laio_completion_cb, - qemu_laio_flush_cb); + qemu_aio_set_event_notifier(&s->e, qemu_laio_completion_cb); return s; diff --git a/block/mirror.c b/block/mirror.c index bed4a7eadd..86de4582b4 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -356,7 +356,7 @@ static void coroutine_fn mirror_run(void *opaque) } bdrv_dirty_iter_init(bs, &s->hbi); - last_pause_ns = qemu_get_clock_ns(rt_clock); + last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); for (;;) { uint64_t delay_ns; int64_t cnt; @@ -374,7 +374,7 @@ static void coroutine_fn mirror_run(void *opaque) * We do so every SLICE_TIME nanoseconds, or when there is an error, * or when the source is clean, whichever comes first. */ - if (qemu_get_clock_ns(rt_clock) - last_pause_ns < SLICE_TIME && + if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - last_pause_ns < SLICE_TIME && s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { if (s->in_flight == MAX_IN_FLIGHT || s->buf_free_count == 0 || (cnt == 0 && s->in_flight > 0)) { @@ -439,13 +439,13 @@ static void coroutine_fn mirror_run(void *opaque) delay_ns = 0; } - block_job_sleep_ns(&s->common, rt_clock, delay_ns); + block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); if (block_job_is_cancelled(&s->common)) { break; } } else if (!should_complete) { delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); - block_job_sleep_ns(&s->common, rt_clock, delay_ns); + block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); } else if (cnt == 0) { /* The two disks are in sync. Exit and report successful * completion. @@ -454,7 +454,7 @@ static void coroutine_fn mirror_run(void *opaque) s->common.cancelled = false; break; } - last_pause_ns = qemu_get_clock_ns(rt_clock); + last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); } immediate_exit: diff --git a/block/nbd.c b/block/nbd.c index 9c480b8f26..691066f726 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -279,13 +279,6 @@ static void nbd_coroutine_start(BDRVNBDState *s, struct nbd_request *request) request->handle = INDEX_TO_HANDLE(s, i); } -static int nbd_have_request(void *opaque) -{ - BDRVNBDState *s = opaque; - - return s->in_flight > 0; -} - static void nbd_reply_ready(void *opaque) { BDRVNBDState *s = opaque; @@ -341,8 +334,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request, qemu_co_mutex_lock(&s->send_mutex); s->send_coroutine = qemu_coroutine_self(); - qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write, - nbd_have_request, s); + qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write, s); if (qiov) { if (!s->is_unix) { socket_set_cork(s->sock, 1); @@ -361,8 +353,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request, } else { rc = nbd_send_request(s->sock, request); } - qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, - nbd_have_request, s); + qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, s); s->send_coroutine = NULL; qemu_co_mutex_unlock(&s->send_mutex); return rc; @@ -438,8 +429,7 @@ static int nbd_establish_connection(BlockDriverState *bs) /* Now that we're connected, set the socket to be non-blocking and * kick the reply mechanism. */ qemu_set_nonblock(sock); - qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, - nbd_have_request, s); + qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, s); s->sock = sock; s->size = size; @@ -459,7 +449,7 @@ static void nbd_teardown_connection(BlockDriverState *bs) request.len = 0; nbd_send_request(s->sock, &request); - qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL); closesocket(s->sock); } diff --git a/block/qcow2.c b/block/qcow2.c index 0eceefe2cd..78097e5173 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -291,7 +291,7 @@ static QemuOptsList qcow2_runtime_opts = { .head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head), .desc = { { - .name = "lazy_refcounts", + .name = QCOW2_OPT_LAZY_REFCOUNTS, .type = QEMU_OPT_BOOL, .help = "Postpone refcount updates", }, @@ -1402,7 +1402,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options) int flags = 0; size_t cluster_size = DEFAULT_CLUSTER_SIZE; int prealloc = 0; - int version = 2; + int version = 3; /* Read out options */ while (options && options->name) { @@ -1722,12 +1722,15 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf, { BDRVQcowState *s = bs->opaque; int growable = bs->growable; + bool zero_beyond_eof = bs->zero_beyond_eof; int ret; BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD); bs->growable = 1; + bs->zero_beyond_eof = false; ret = bdrv_pread(bs, qcow2_vm_state_offset(s) + pos, buf, size); bs->growable = growable; + bs->zero_beyond_eof = zero_beyond_eof; return ret; } diff --git a/block/qcow2.h b/block/qcow2.h index 3b2d5cda71..dba9771419 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -59,10 +59,10 @@ #define DEFAULT_CLUSTER_SIZE 65536 -#define QCOW2_OPT_LAZY_REFCOUNTS "lazy_refcounts" -#define QCOW2_OPT_DISCARD_REQUEST "pass_discard_request" -#define QCOW2_OPT_DISCARD_SNAPSHOT "pass_discard_snapshot" -#define QCOW2_OPT_DISCARD_OTHER "pass_discard_other" +#define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" +#define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" +#define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot" +#define QCOW2_OPT_DISCARD_OTHER "pass-discard-other" typedef struct QCowHeader { uint32_t magic; diff --git a/block/qed.c b/block/qed.c index f767b0528c..cc904c4834 100644 --- a/block/qed.c +++ b/block/qed.c @@ -353,10 +353,10 @@ static void qed_start_need_check_timer(BDRVQEDState *s) { trace_qed_start_need_check_timer(s); - /* Use vm_clock so we don't alter the image file while suspended for + /* Use QEMU_CLOCK_VIRTUAL so we don't alter the image file while suspended for * migration. */ - qemu_mod_timer(s->need_check_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(s->need_check_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * QED_NEED_CHECK_TIMEOUT); } @@ -364,7 +364,7 @@ static void qed_start_need_check_timer(BDRVQEDState *s) static void qed_cancel_need_check_timer(BDRVQEDState *s) { trace_qed_cancel_need_check_timer(s); - qemu_del_timer(s->need_check_timer); + timer_del(s->need_check_timer); } static void bdrv_qed_rebind(BlockDriverState *bs) @@ -494,7 +494,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags) } } - s->need_check_timer = qemu_new_timer_ns(vm_clock, + s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, qed_need_check_timer_cb, s); out: @@ -518,7 +518,7 @@ static void bdrv_qed_close(BlockDriverState *bs) BDRVQEDState *s = bs->opaque; qed_cancel_need_check_timer(s); - qemu_free_timer(s->need_check_timer); + timer_free(s->need_check_timer); /* Ensure writes reach stable storage */ bdrv_flush(bs->file); diff --git a/block/raw.c b/block/raw.c index f1682d4f32..47518253fe 100644 --- a/block/raw.c +++ b/block/raw.c @@ -1,3 +1,26 @@ +/* + * Block driver for RAW format + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "qemu-common.h" #include "block/block_int.h" diff --git a/block/rbd.c b/block/rbd.c index cb71751218..e798e19f81 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -100,7 +100,6 @@ typedef struct BDRVRBDState { rados_ioctx_t io_ctx; rbd_image_t image; char name[RBD_MAX_IMAGE_NAME_SIZE]; - int qemu_aio_count; char *snap; int event_reader_pos; RADOSCB *event_rcb; @@ -428,19 +427,11 @@ static void qemu_rbd_aio_event_reader(void *opaque) if (s->event_reader_pos == sizeof(s->event_rcb)) { s->event_reader_pos = 0; qemu_rbd_complete_aio(s->event_rcb); - s->qemu_aio_count--; } } } while (ret < 0 && errno == EINTR); } -static int qemu_rbd_aio_flush_cb(void *opaque) -{ - BDRVRBDState *s = opaque; - - return (s->qemu_aio_count > 0); -} - /* TODO Convert to fine grained options */ static QemuOptsList runtime_opts = { .name = "rbd", @@ -554,7 +545,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags) fcntl(s->fds[0], F_SETFL, O_NONBLOCK); fcntl(s->fds[1], F_SETFL, O_NONBLOCK); qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader, - NULL, qemu_rbd_aio_flush_cb, s); + NULL, s); qemu_opts_del(opts); @@ -578,7 +569,7 @@ static void qemu_rbd_close(BlockDriverState *bs) close(s->fds[0]); close(s->fds[1]); - qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL); rbd_close(s->image); rados_ioctx_destroy(s->io_ctx); @@ -741,8 +732,6 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs, off = sector_num * BDRV_SECTOR_SIZE; size = nb_sectors * BDRV_SECTOR_SIZE; - s->qemu_aio_count++; /* All the RADOSCB */ - rcb = g_malloc(sizeof(RADOSCB)); rcb->done = 0; rcb->acb = acb; @@ -779,7 +768,6 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs, failed: g_free(rcb); - s->qemu_aio_count--; qemu_aio_release(acb); return NULL; } diff --git a/block/sheepdog.c b/block/sheepdog.c index 6a41ad9b3c..1ad4d070e7 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -242,14 +242,14 @@ static inline bool is_snapshot(struct SheepdogInode *inode) return !!inode->snap_ctime; } -#undef dprintf +#undef DPRINTF #ifdef DEBUG_SDOG -#define dprintf(fmt, args...) \ +#define DPRINTF(fmt, args...) \ do { \ fprintf(stdout, "%s %d: " fmt, __func__, __LINE__, ##args); \ } while (0) #else -#define dprintf(fmt, args...) +#define DPRINTF(fmt, args...) #endif typedef struct SheepdogAIOCB SheepdogAIOCB; @@ -509,13 +509,6 @@ static void restart_co_req(void *opaque) qemu_coroutine_enter(co, NULL); } -static int have_co_req(void *opaque) -{ - /* this handler is set only when there is a pending request, so - * always returns 1. */ - return 1; -} - typedef struct SheepdogReqCo { int sockfd; SheepdogReq *hdr; @@ -538,14 +531,14 @@ static coroutine_fn void do_co_req(void *opaque) unsigned int *rlen = srco->rlen; co = qemu_coroutine_self(); - qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, have_co_req, co); + qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, co); ret = send_co_req(sockfd, hdr, data, wlen); if (ret < 0) { goto out; } - qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, have_co_req, co); + qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, co); ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr)); if (ret < sizeof(*hdr)) { @@ -570,7 +563,7 @@ static coroutine_fn void do_co_req(void *opaque) out: /* there is at most one request for this sockfd, so it is safe to * set each handler to NULL. */ - qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL); srco->ret = ret; srco->finished = true; @@ -729,7 +722,7 @@ static void coroutine_fn aio_read_response(void *opaque) break; case AIOCB_FLUSH_CACHE: if (rsp.result == SD_RES_INVALID_PARMS) { - dprintf("disable cache since the server doesn't support it\n"); + DPRINTF("disable cache since the server doesn't support it\n"); s->cache_flags = SD_FLAG_CMD_DIRECT; rsp.result = SD_RES_SUCCESS; } @@ -796,14 +789,6 @@ static void co_write_request(void *opaque) qemu_coroutine_enter(s->co_send, NULL); } -static int aio_flush_request(void *opaque) -{ - BDRVSheepdogState *s = opaque; - - return !QLIST_EMPTY(&s->inflight_aio_head) || - !QLIST_EMPTY(&s->pending_aio_head); -} - /* * Return a socket discriptor to read/write objects. * @@ -819,7 +804,7 @@ static int get_sheep_fd(BDRVSheepdogState *s) return fd; } - qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s); + qemu_aio_set_fd_handler(fd, co_read_response, NULL, s); return fd; } @@ -1069,8 +1054,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, qemu_co_mutex_lock(&s->lock); s->co_send = qemu_coroutine_self(); - qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request, - aio_flush_request, s); + qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request, s); socket_set_cork(s->fd, 1); /* send a header */ @@ -1091,8 +1075,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, } socket_set_cork(s->fd, 0); - qemu_aio_set_fd_handler(s->fd, co_read_response, NULL, - aio_flush_request, s); + qemu_aio_set_fd_handler(s->fd, co_read_response, NULL, s); qemu_co_mutex_unlock(&s->lock); return 0; @@ -1229,7 +1212,7 @@ static int coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req) * the same object */ QLIST_FOREACH(areq, &s->inflight_aio_head, aio_siblings) { if (areq != aio_req && areq->oid == aio_req->oid) { - dprintf("simultaneous CoW to %" PRIx64 "\n", aio_req->oid); + DPRINTF("simultaneous CoW to %" PRIx64 "\n", aio_req->oid); QLIST_REMOVE(aio_req, aio_siblings); QLIST_INSERT_HEAD(&s->pending_aio_head, aio_req, aio_siblings); return SD_RES_SUCCESS; @@ -1319,7 +1302,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags) s->discard_supported = true; if (snapid || tag[0] != '\0') { - dprintf("%" PRIx32 " snapshot inode was open.\n", vid); + DPRINTF("%" PRIx32 " snapshot inode was open.\n", vid); s->is_snapshot = true; } @@ -1350,7 +1333,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags) g_free(buf); return 0; out: - qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL); if (s->fd >= 0) { closesocket(s->fd); } @@ -1554,7 +1537,7 @@ static void sd_close(BlockDriverState *bs) unsigned int wlen, rlen = 0; int fd, ret; - dprintf("%s\n", s->name); + DPRINTF("%s\n", s->name); fd = connect_to_sdog(s); if (fd < 0) { @@ -1578,7 +1561,7 @@ static void sd_close(BlockDriverState *bs) error_report("%s, %s", sd_strerror(rsp->result), s->name); } - qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL); closesocket(s->fd); g_free(s->host_spec); } @@ -1714,7 +1697,7 @@ static int sd_create_branch(BDRVSheepdogState *s) char *buf; bool deleted; - dprintf("%" PRIx32 " is snapshot.\n", s->inode.vdi_id); + DPRINTF("%" PRIx32 " is snapshot.\n", s->inode.vdi_id); buf = g_malloc(SD_INODE_SIZE); @@ -1730,7 +1713,7 @@ static int sd_create_branch(BDRVSheepdogState *s) goto out; } - dprintf("%" PRIx32 " is created.\n", vid); + DPRINTF("%" PRIx32 " is created.\n", vid); fd = connect_to_sdog(s); if (fd < 0) { @@ -1751,7 +1734,7 @@ static int sd_create_branch(BDRVSheepdogState *s) s->is_snapshot = false; ret = 0; - dprintf("%" PRIx32 " was newly created.\n", s->inode.vdi_id); + DPRINTF("%" PRIx32 " was newly created.\n", s->inode.vdi_id); out: g_free(buf); @@ -1841,11 +1824,11 @@ static int coroutine_fn sd_co_rw_vector(void *p) } if (create) { - dprintf("update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld\n", + DPRINTF("update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld\n", inode->vdi_id, oid, vid_to_data_oid(inode->data_vdi_id[idx], idx), idx); oid = vid_to_data_oid(inode->vdi_id, idx); - dprintf("new oid %" PRIx64 "\n", oid); + DPRINTF("new oid %" PRIx64 "\n", oid); } aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, old_oid, done); @@ -1978,7 +1961,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) SheepdogInode *inode; unsigned int datalen; - dprintf("sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " " + DPRINTF("sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " " "is_snapshot %d\n", sn_info->name, sn_info->id_str, s->name, sn_info->vm_state_size, s->is_snapshot); @@ -1989,7 +1972,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) return -EINVAL; } - dprintf("%s %s\n", sn_info->name, sn_info->id_str); + DPRINTF("%s %s\n", sn_info->name, sn_info->id_str); s->inode.vm_state_size = sn_info->vm_state_size; s->inode.vm_clock_nsec = sn_info->vm_clock_nsec; @@ -2033,7 +2016,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) } memcpy(&s->inode, inode, datalen); - dprintf("s->inode: name %s snap_id %x oid %x\n", + DPRINTF("s->inode: name %s snap_id %x oid %x\n", s->inode.name, s->inode.snap_id, s->inode.vdi_id); cleanup: @@ -2347,6 +2330,7 @@ static BlockDriver bdrv_sheepdog = { .bdrv_file_open = sd_open, .bdrv_close = sd_close, .bdrv_create = sd_create, + .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_getlength = sd_getlength, .bdrv_truncate = sd_truncate, @@ -2374,6 +2358,7 @@ static BlockDriver bdrv_sheepdog_tcp = { .bdrv_file_open = sd_open, .bdrv_close = sd_close, .bdrv_create = sd_create, + .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_getlength = sd_getlength, .bdrv_truncate = sd_truncate, diff --git a/block/ssh.c b/block/ssh.c index d7e7bf8dd2..27691b4ad5 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -740,14 +740,6 @@ static void restart_coroutine(void *opaque) qemu_coroutine_enter(co, NULL); } -/* Always true because when we have called set_fd_handler there is - * always a request being processed. - */ -static int return_true(void *opaque) -{ - return 1; -} - static coroutine_fn void set_fd_handler(BDRVSSHState *s) { int r; @@ -766,13 +758,13 @@ static coroutine_fn void set_fd_handler(BDRVSSHState *s) DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock, rd_handler, wr_handler); - qemu_aio_set_fd_handler(s->sock, rd_handler, wr_handler, return_true, co); + qemu_aio_set_fd_handler(s->sock, rd_handler, wr_handler, co); } static coroutine_fn void clear_fd_handler(BDRVSSHState *s) { DPRINTF("s->sock=%d", s->sock); - qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL); + qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL); } /* A non-blocking call returned EAGAIN, so yield, ensuring the diff --git a/block/stream.c b/block/stream.c index 7fe9e486bf..99821252b1 100644 --- a/block/stream.c +++ b/block/stream.c @@ -57,6 +57,11 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base, BlockDriverState *intermediate; intermediate = top->backing_hd; + /* Must assign before bdrv_delete() to prevent traversing dangling pointer + * while we delete backing image instances. + */ + top->backing_hd = base; + while (intermediate) { BlockDriverState *unused; @@ -70,7 +75,6 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base, unused->backing_hd = NULL; bdrv_delete(unused); } - top->backing_hd = base; } static void coroutine_fn stream_run(void *opaque) @@ -110,7 +114,7 @@ wait: /* Note that even when no rate limit is applied we need to yield * with no pending I/O here so that bdrv_drain_all() returns. */ - block_job_sleep_ns(&s->common, rt_clock, delay_ns); + block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); if (block_job_is_cancelled(&s->common)) { break; } diff --git a/block/vhdx.h b/block/vhdx.h index c3b64c6ff6..fb687ed2d6 100644 --- a/block/vhdx.h +++ b/block/vhdx.h @@ -168,7 +168,7 @@ typedef struct QEMU_PACKED VHDXLogEntryHeader { vhdx_header. If not found in vhdx_header, it is invalid */ uint64_t flushed_file_offset; /* see spec for full details - this - sould be vhdx file size in bytes */ + should be vhdx file size in bytes */ uint64_t last_file_offset; /* size in bytes that all allocated file structures fit into */ } VHDXLogEntryHeader; diff --git a/block/vmdk.c b/block/vmdk.c index 3756333c60..63b489d29e 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -62,19 +62,20 @@ typedef struct { uint32_t cylinders; uint32_t heads; uint32_t sectors_per_track; -} VMDK3Header; +} QEMU_PACKED VMDK3Header; typedef struct { uint32_t version; uint32_t flags; - int64_t capacity; - int64_t granularity; - int64_t desc_offset; - int64_t desc_size; - int32_t num_gtes_per_gte; - int64_t rgd_offset; - int64_t gd_offset; - int64_t grain_offset; + uint64_t capacity; + uint64_t granularity; + uint64_t desc_offset; + uint64_t desc_size; + /* Number of GrainTableEntries per GrainTable */ + uint32_t num_gtes_per_gt; + uint64_t rgd_offset; + uint64_t gd_offset; + uint64_t grain_offset; char filler[1]; char check_bytes[4]; uint16_t compressAlgorithm; @@ -109,7 +110,7 @@ typedef struct VmdkExtent { typedef struct BDRVVmdkState { CoMutex lock; - int desc_offset; + uint64_t desc_offset; bool cid_updated; uint32_t parent_cid; int num_extents; @@ -131,7 +132,7 @@ typedef struct VmdkGrainMarker { uint64_t lba; uint32_t size; uint8_t data[0]; -} VmdkGrainMarker; +} QEMU_PACKED VmdkGrainMarker; enum { MARKER_END_OF_STREAM = 0, @@ -385,15 +386,30 @@ static int vmdk_parent_open(BlockDriverState *bs) /* Create and append extent to the extent array. Return the added VmdkExtent * address. return NULL if allocation failed. */ -static VmdkExtent *vmdk_add_extent(BlockDriverState *bs, +static int vmdk_add_extent(BlockDriverState *bs, BlockDriverState *file, bool flat, int64_t sectors, int64_t l1_offset, int64_t l1_backup_offset, uint32_t l1_size, - int l2_size, unsigned int cluster_sectors) + int l2_size, uint64_t cluster_sectors, + VmdkExtent **new_extent) { VmdkExtent *extent; BDRVVmdkState *s = bs->opaque; + if (cluster_sectors > 0x200000) { + /* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */ + error_report("invalid granularity, image may be corrupt"); + return -EINVAL; + } + if (l1_size > 512 * 1024 * 1024) { + /* Although with big capacity and small l1_entry_sectors, we can get a + * big l1_size, we don't want unbounded value to allocate the table. + * Limit it to 512M, which is 16PB for default cluster and L2 table + * size */ + error_report("L1 size too big"); + return -EFBIG; + } + s->extents = g_realloc(s->extents, (s->num_extents + 1) * sizeof(VmdkExtent)); extent = &s->extents[s->num_extents]; @@ -416,7 +432,10 @@ static VmdkExtent *vmdk_add_extent(BlockDriverState *bs, extent->end_sector = extent->sectors; } bs->total_sectors = extent->end_sector; - return extent; + if (new_extent) { + *new_extent = extent; + } + return 0; } static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent) @@ -462,9 +481,9 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent) return ret; } -static int vmdk_open_vmdk3(BlockDriverState *bs, - BlockDriverState *file, - int flags) +static int vmdk_open_vmfs_sparse(BlockDriverState *bs, + BlockDriverState *file, + int flags) { int ret; uint32_t magic; @@ -475,12 +494,17 @@ static int vmdk_open_vmdk3(BlockDriverState *bs, if (ret < 0) { return ret; } - extent = vmdk_add_extent(bs, - bs->file, false, - le32_to_cpu(header.disk_sectors), - le32_to_cpu(header.l1dir_offset) << 9, - 0, 1 << 6, 1 << 9, - le32_to_cpu(header.granularity)); + ret = vmdk_add_extent(bs, file, false, + le32_to_cpu(header.disk_sectors), + le32_to_cpu(header.l1dir_offset) << 9, + 0, + le32_to_cpu(header.l1dir_size), + 4096, + le32_to_cpu(header.granularity), + &extent); + if (ret < 0) { + return ret; + } ret = vmdk_init_tables(bs, extent); if (ret) { /* free extent allocated by vmdk_add_extent */ @@ -490,7 +514,7 @@ static int vmdk_open_vmdk3(BlockDriverState *bs, } static int vmdk_open_desc_file(BlockDriverState *bs, int flags, - int64_t desc_offset); + uint64_t desc_offset); static int vmdk_open_vmdk4(BlockDriverState *bs, BlockDriverState *file, @@ -508,7 +532,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, return ret; } if (header.capacity == 0) { - int64_t desc_offset = le64_to_cpu(header.desc_offset); + uint64_t desc_offset = le64_to_cpu(header.desc_offset); if (desc_offset) { return vmdk_open_desc_file(bs, flags, desc_offset << 9); } @@ -570,7 +594,12 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, return -ENOTSUP; } - l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte) + if (le32_to_cpu(header.num_gtes_per_gt) > 512) { + error_report("L2 table size too big"); + return -EINVAL; + } + + l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) * le64_to_cpu(header.granularity); if (l1_entry_sectors == 0) { return -EINVAL; @@ -580,13 +609,17 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; } - extent = vmdk_add_extent(bs, file, false, + ret = vmdk_add_extent(bs, file, false, le64_to_cpu(header.capacity), le64_to_cpu(header.gd_offset) << 9, l1_backup_offset, l1_size, - le32_to_cpu(header.num_gtes_per_gte), - le64_to_cpu(header.granularity)); + le32_to_cpu(header.num_gtes_per_gt), + le64_to_cpu(header.granularity), + &extent); + if (ret < 0) { + return ret; + } extent->compressed = le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; @@ -641,7 +674,7 @@ static int vmdk_open_sparse(BlockDriverState *bs, magic = be32_to_cpu(magic); switch (magic) { case VMDK3_MAGIC: - return vmdk_open_vmdk3(bs, file, flags); + return vmdk_open_vmfs_sparse(bs, file, flags); break; case VMDK4_MAGIC: return vmdk_open_vmdk4(bs, file, flags); @@ -685,7 +718,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, } if (sectors <= 0 || - (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) || + (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && + strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || (strcmp(access, "RW"))) { goto next_line; } @@ -698,15 +732,18 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, } /* save to extents array */ - if (!strcmp(type, "FLAT")) { + if (!strcmp(type, "FLAT") || !strcmp(type, "VMFS")) { /* FLAT extent */ VmdkExtent *extent; - extent = vmdk_add_extent(bs, extent_file, true, sectors, - 0, 0, 0, 0, sectors); + ret = vmdk_add_extent(bs, extent_file, true, sectors, + 0, 0, 0, 0, sectors, &extent); + if (ret < 0) { + return ret; + } extent->flat_start_offset = flat_offset << 9; - } else if (!strcmp(type, "SPARSE")) { - /* SPARSE extent */ + } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { + /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ ret = vmdk_open_sparse(bs, extent_file, bs->open_flags); if (ret) { bdrv_delete(extent_file); @@ -728,7 +765,7 @@ next_line: } static int vmdk_open_desc_file(BlockDriverState *bs, int flags, - int64_t desc_offset) + uint64_t desc_offset) { int ret; char *buf = NULL; @@ -753,6 +790,8 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, goto exit; } if (strcmp(ct, "monolithicFlat") && + strcmp(ct, "vmfs") && + strcmp(ct, "vmfsSparse") && strcmp(ct, "twoGbMaxExtentSparse") && strcmp(ct, "twoGbMaxExtentFlat")) { fprintf(stderr, @@ -807,16 +846,17 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t offset, bool allocate) { - /* 128 sectors * 512 bytes each = grain size 64KB */ - uint8_t whole_grain[extent->cluster_sectors * 512]; + int ret = VMDK_OK; + uint8_t *whole_grain = NULL; /* we will be here if it's first write on non-exist grain(cluster). * try to read from parent image, if exist */ if (bs->backing_hd) { - int ret; - + whole_grain = + qemu_blockalign(bs, extent->cluster_sectors << BDRV_SECTOR_BITS); if (!vmdk_is_cid_valid(bs)) { - return VMDK_ERROR; + ret = VMDK_ERROR; + goto exit; } /* floor offset to cluster */ @@ -824,17 +864,21 @@ static int get_whole_cluster(BlockDriverState *bs, ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain, extent->cluster_sectors); if (ret < 0) { - return VMDK_ERROR; + ret = VMDK_ERROR; + goto exit; } /* Write grain only into the active image */ ret = bdrv_write(extent->file, cluster_offset, whole_grain, extent->cluster_sectors); if (ret < 0) { - return VMDK_ERROR; + ret = VMDK_ERROR; + goto exit; } } - return VMDK_OK; +exit: + qemu_vfree(whole_grain); + return ret; } static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data) @@ -1200,8 +1244,10 @@ static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, /** * vmdk_write: * @zeroed: buf is ignored (data is zero), use zeroed_grain GTE feature - * if possible, otherwise return -ENOTSUP. - * @zero_dry_run: used for zeroed == true only, don't update L2 table, just + * if possible, otherwise return -ENOTSUP. + * @zero_dry_run: used for zeroed == true only, don't update L2 table, just try + * with each cluster. By dry run we can find if the zero write + * is possible without modifying image data. * * Returns: error code with 0 for success. */ @@ -1328,6 +1374,8 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, int ret; BDRVVmdkState *s = bs->opaque; qemu_co_mutex_lock(&s->lock); + /* write zeroes could fail if sectors not aligned to cluster, test it with + * dry_run == true before really updating image */ ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true); if (!ret) { ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false); @@ -1336,7 +1384,6 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, return ret; } - static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat, bool compress, bool zeroed_grain) { @@ -1367,12 +1414,12 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; header.capacity = filesize / 512; header.granularity = 128; - header.num_gtes_per_gte = 512; + header.num_gtes_per_gt = 512; grains = (filesize / 512 + header.granularity - 1) / header.granularity; - gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9; + gt_size = ((header.num_gtes_per_gt * sizeof(uint32_t)) + 511) >> 9; gt_count = - (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte; + (grains + header.num_gtes_per_gt - 1) / header.num_gtes_per_gt; gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9; header.desc_offset = 1; @@ -1388,7 +1435,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, header.flags = cpu_to_le32(header.flags); header.capacity = cpu_to_le64(header.capacity); header.granularity = cpu_to_le64(header.granularity); - header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte); + header.num_gtes_per_gt = cpu_to_le32(header.num_gtes_per_gt); header.desc_offset = cpu_to_le64(header.desc_offset); header.desc_size = cpu_to_le64(header.desc_size); header.rgd_offset = cpu_to_le64(header.rgd_offset); diff --git a/block/win32-aio.c b/block/win32-aio.c index fcb7c754da..5d1d199b61 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -105,13 +105,6 @@ static void win32_aio_completion_cb(EventNotifier *e) } } -static int win32_aio_flush_cb(EventNotifier *e) -{ - QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e); - - return (s->count > 0) ? 1 : 0; -} - static void win32_aio_cancel(BlockDriverAIOCB *blockacb) { QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb; @@ -201,8 +194,7 @@ QEMUWin32AIOState *win32_aio_init(void) goto out_close_efd; } - qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb, - win32_aio_flush_cb); + qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb); return s; diff --git a/blockdev.c b/blockdev.c index c5abd65182..121520ecbc 100644 --- a/blockdev.c +++ b/blockdev.c @@ -46,6 +46,7 @@ static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); extern QemuOptsList qemu_common_drive_opts; +extern QemuOptsList qemu_old_drive_opts; static const char *const if_name[IF_COUNT] = { [IF_NONE] = "none", @@ -312,7 +313,8 @@ static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp) return true; } -DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) +static DriveInfo *blockdev_init(QemuOpts *all_opts, + BlockInterfaceType block_default_type) { const char *buf; const char *file = NULL; @@ -322,7 +324,6 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) enum { MEDIA_DISK, MEDIA_CDROM } media; int bus_id, unit_id; int cyls, heads, secs, translation; - BlockDriver *drv = NULL; int max_devs; int index; int ro = 0; @@ -338,6 +339,8 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) QemuOpts *opts; QDict *bs_opts; const char *id; + bool has_driver_specific_opts; + BlockDriver *drv = NULL; translation = BIOS_ATA_TRANSLATION_AUTO; media = MEDIA_DISK; @@ -365,6 +368,8 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) qdict_del(bs_opts, "id"); } + has_driver_specific_opts = !!qdict_size(bs_opts); + /* extract parameters */ bus_id = qemu_opt_get_number(opts, "bus", 0); unit_id = qemu_opt_get_number(opts, "unit", -1); @@ -375,7 +380,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) secs = qemu_opt_get_number(opts, "secs", 0); snapshot = qemu_opt_get_bool(opts, "snapshot", 0); - ro = qemu_opt_get_bool(opts, "readonly", 0); + ro = qemu_opt_get_bool(opts, "read-only", 0); copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false); file = qemu_opt_get(opts, "file"); @@ -449,12 +454,14 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) } } - bdrv_flags |= BDRV_O_CACHE_WB; - if ((buf = qemu_opt_get(opts, "cache")) != NULL) { - if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) { - error_report("invalid cache option"); - return NULL; - } + if (qemu_opt_get_bool(opts, "cache.writeback", true)) { + bdrv_flags |= BDRV_O_CACHE_WB; + } + if (qemu_opt_get_bool(opts, "cache.direct", false)) { + bdrv_flags |= BDRV_O_NOCACHE; + } + if (qemu_opt_get_bool(opts, "cache.no-flush", true)) { + bdrv_flags |= BDRV_O_NO_FLUSH; } #ifdef CONFIG_LINUX_AIO @@ -477,26 +484,31 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) error_printf("\n"); return NULL; } + drv = bdrv_find_whitelisted_format(buf, ro); if (!drv) { - error_report("'%s' invalid format", buf); + if (!ro && bdrv_find_whitelisted_format(buf, !ro)) { + error_report("'%s' can be only used as read-only device.", buf); + } else { + error_report("'%s' invalid format", buf); + } return NULL; } } /* disk I/O throttling */ io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = - qemu_opt_get_number(opts, "bps", 0); + qemu_opt_get_number(opts, "throttling.bps-total", 0); io_limits.bps[BLOCK_IO_LIMIT_READ] = - qemu_opt_get_number(opts, "bps_rd", 0); + qemu_opt_get_number(opts, "throttling.bps-read", 0); io_limits.bps[BLOCK_IO_LIMIT_WRITE] = - qemu_opt_get_number(opts, "bps_wr", 0); + qemu_opt_get_number(opts, "throttling.bps-write", 0); io_limits.iops[BLOCK_IO_LIMIT_TOTAL] = - qemu_opt_get_number(opts, "iops", 0); + qemu_opt_get_number(opts, "throttling.iops-total", 0); io_limits.iops[BLOCK_IO_LIMIT_READ] = - qemu_opt_get_number(opts, "iops_rd", 0); + qemu_opt_get_number(opts, "throttling.iops-read", 0); io_limits.iops[BLOCK_IO_LIMIT_WRITE] = - qemu_opt_get_number(opts, "iops_wr", 0); + qemu_opt_get_number(opts, "throttling.iops-write", 0); if (!do_check_io_limits(&io_limits, &error)) { error_report("%s", error_get_pretty(error)); @@ -658,7 +670,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) abort(); } if (!file || !*file) { - if (qdict_size(bs_opts)) { + if (has_driver_specific_opts) { file = NULL; } else { return dinfo; @@ -684,7 +696,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) } else if (ro == 1) { if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE && type != IF_PFLASH) { - error_report("readonly not supported by this bus type"); + error_report("read-only not supported by this bus type"); goto err; } } @@ -692,16 +704,17 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) bdrv_flags |= ro ? 0 : BDRV_O_RDWR; if (ro && copy_on_read) { - error_report("warning: disabling copy_on_read on readonly drive"); + error_report("warning: disabling copy_on_read on read-only drive"); } + QINCREF(bs_opts); ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv); - bs_opts = NULL; if (ret < 0) { if (ret == -EMEDIUMTYPE) { error_report("could not open disk image %s: not in %s format", - file ?: dinfo->id, drv->format_name); + file ?: dinfo->id, drv ? drv->format_name : + qdict_get_str(bs_opts, "driver")); } else { error_report("could not open disk image %s: %s", file ?: dinfo->id, strerror(-ret)); @@ -712,6 +725,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) if (bdrv_key_required(dinfo->bdrv)) autostart = 0; + QDECREF(bs_opts); qemu_opts_del(opts); return dinfo; @@ -726,6 +740,80 @@ err: return NULL; } +static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to) +{ + const char *value; + + value = qemu_opt_get(opts, from); + if (value) { + qemu_opt_set(opts, to, value); + qemu_opt_unset(opts, from); + } +} + +DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) +{ + const char *value; + + /* + * Check that only old options are used by copying into a QemuOpts with + * stricter checks. Going through a QDict seems to be the easiest way to + * achieve this... + */ + QemuOpts* check_opts; + QDict *qdict; + Error *local_err = NULL; + + qdict = qemu_opts_to_qdict(all_opts, NULL); + check_opts = qemu_opts_from_qdict(&qemu_old_drive_opts, qdict, &local_err); + QDECREF(qdict); + + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + return NULL; + } + qemu_opts_del(check_opts); + + /* Change legacy command line options into QMP ones */ + qemu_opt_rename(all_opts, "iops", "throttling.iops-total"); + qemu_opt_rename(all_opts, "iops_rd", "throttling.iops-read"); + qemu_opt_rename(all_opts, "iops_wr", "throttling.iops-write"); + + qemu_opt_rename(all_opts, "bps", "throttling.bps-total"); + qemu_opt_rename(all_opts, "bps_rd", "throttling.bps-read"); + qemu_opt_rename(all_opts, "bps_wr", "throttling.bps-write"); + + qemu_opt_rename(all_opts, "readonly", "read-only"); + + value = qemu_opt_get(all_opts, "cache"); + if (value) { + int flags = 0; + + if (bdrv_parse_cache_flags(value, &flags) != 0) { + error_report("invalid cache option"); + return NULL; + } + + /* Specific options take precedence */ + if (!qemu_opt_get(all_opts, "cache.writeback")) { + qemu_opt_set_bool(all_opts, "cache.writeback", + !!(flags & BDRV_O_CACHE_WB)); + } + if (!qemu_opt_get(all_opts, "cache.direct")) { + qemu_opt_set_bool(all_opts, "cache.direct", + !!(flags & BDRV_O_NOCACHE)); + } + if (!qemu_opt_get(all_opts, "cache.no-flush")) { + qemu_opt_set_bool(all_opts, "cache.no-flush", + !!(flags & BDRV_O_NO_FLUSH)); + } + qemu_opt_unset(all_opts, "cache"); + } + + return blockdev_init(all_opts, block_default_type); +} + void do_commit(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -971,7 +1059,7 @@ static void abort_prepare(BlkTransactionState *common, Error **errp) static void abort_commit(BlkTransactionState *common) { - assert(false); /* this action never succeeds */ + g_assert_not_reached(); /* this action never succeeds */ } static const BdrvActionOps actions[] = { @@ -1211,7 +1299,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, bdrv_io_limits_disable(bs); } else { if (bs->block_timer) { - qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock)); + timer_mod(bs->block_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } } } @@ -1431,16 +1519,13 @@ void qmp_drive_backup(const char *device, const char *target, { BlockDriverState *bs; BlockDriverState *target_bs; + BlockDriverState *source = NULL; BlockDriver *drv = NULL; Error *local_err = NULL; int flags; int64_t size; int ret; - if (sync != MIRROR_SYNC_MODE_FULL) { - error_setg(errp, "only sync mode 'full' is currently supported"); - return; - } if (!has_speed) { speed = 0; } @@ -1483,6 +1568,18 @@ void qmp_drive_backup(const char *device, const char *target, flags = bs->open_flags | BDRV_O_RDWR; + /* See if we have a backing HD we can use to create our new image + * on top of. */ + if (sync == MIRROR_SYNC_MODE_TOP) { + source = bs->backing_hd; + if (!source) { + sync = MIRROR_SYNC_MODE_FULL; + } + } + if (sync == MIRROR_SYNC_MODE_NONE) { + source = bs; + } + size = bdrv_getlength(bs); if (size < 0) { error_setg_errno(errp, -size, "bdrv_getlength failed"); @@ -1491,8 +1588,14 @@ void qmp_drive_backup(const char *device, const char *target, if (mode != NEW_IMAGE_MODE_EXISTING) { assert(format && drv); - bdrv_img_create(target, format, - NULL, NULL, NULL, size, flags, &local_err, false); + if (source) { + bdrv_img_create(target, format, source->filename, + source->drv->format_name, NULL, + size, flags, &local_err, false); + } else { + bdrv_img_create(target, format, NULL, NULL, NULL, + size, flags, &local_err, false); + } } if (error_is_set(&local_err)) { @@ -1508,7 +1611,7 @@ void qmp_drive_backup(const char *device, const char *target, return; } - backup_start(bs, target_bs, speed, on_source_error, on_target_error, + backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error, block_job_cb, bs, &local_err); if (local_err != NULL) { bdrv_delete(target_bs); @@ -1822,6 +1925,135 @@ QemuOptsList qemu_common_drive_opts = { .type = QEMU_OPT_STRING, .help = "discard operation (ignore/off, unmap/on)", },{ + .name = "cache.writeback", + .type = QEMU_OPT_BOOL, + .help = "enables writeback mode for any caches", + },{ + .name = "cache.direct", + .type = QEMU_OPT_BOOL, + .help = "enables use of O_DIRECT (bypass the host page cache)", + },{ + .name = "cache.no-flush", + .type = QEMU_OPT_BOOL, + .help = "ignore any flush requests for the device", + },{ + .name = "aio", + .type = QEMU_OPT_STRING, + .help = "host AIO implementation (threads, native)", + },{ + .name = "format", + .type = QEMU_OPT_STRING, + .help = "disk format (raw, qcow2, ...)", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "disk serial number", + },{ + .name = "rerror", + .type = QEMU_OPT_STRING, + .help = "read error action", + },{ + .name = "werror", + .type = QEMU_OPT_STRING, + .help = "write error action", + },{ + .name = "addr", + .type = QEMU_OPT_STRING, + .help = "pci address (virtio only)", + },{ + .name = "read-only", + .type = QEMU_OPT_BOOL, + .help = "open drive file as read-only", + },{ + .name = "throttling.iops-total", + .type = QEMU_OPT_NUMBER, + .help = "limit total I/O operations per second", + },{ + .name = "throttling.iops-read", + .type = QEMU_OPT_NUMBER, + .help = "limit read operations per second", + },{ + .name = "throttling.iops-write", + .type = QEMU_OPT_NUMBER, + .help = "limit write operations per second", + },{ + .name = "throttling.bps-total", + .type = QEMU_OPT_NUMBER, + .help = "limit total bytes per second", + },{ + .name = "throttling.bps-read", + .type = QEMU_OPT_NUMBER, + .help = "limit read bytes per second", + },{ + .name = "throttling.bps-write", + .type = QEMU_OPT_NUMBER, + .help = "limit write bytes per second", + },{ + .name = "copy-on-read", + .type = QEMU_OPT_BOOL, + .help = "copy read data from backing file into image file", + },{ + .name = "boot", + .type = QEMU_OPT_BOOL, + .help = "(deprecated, ignored)", + }, + { /* end of list */ } + }, +}; + +QemuOptsList qemu_old_drive_opts = { + .name = "drive", + .head = QTAILQ_HEAD_INITIALIZER(qemu_old_drive_opts.head), + .desc = { + { + .name = "bus", + .type = QEMU_OPT_NUMBER, + .help = "bus number", + },{ + .name = "unit", + .type = QEMU_OPT_NUMBER, + .help = "unit number (i.e. lun for scsi)", + },{ + .name = "if", + .type = QEMU_OPT_STRING, + .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)", + },{ + .name = "index", + .type = QEMU_OPT_NUMBER, + .help = "index number", + },{ + .name = "cyls", + .type = QEMU_OPT_NUMBER, + .help = "number of cylinders (ide disk geometry)", + },{ + .name = "heads", + .type = QEMU_OPT_NUMBER, + .help = "number of heads (ide disk geometry)", + },{ + .name = "secs", + .type = QEMU_OPT_NUMBER, + .help = "number of sectors (ide disk geometry)", + },{ + .name = "trans", + .type = QEMU_OPT_STRING, + .help = "chs translation (auto, lba. none)", + },{ + .name = "media", + .type = QEMU_OPT_STRING, + .help = "media type (disk, cdrom)", + },{ + .name = "snapshot", + .type = QEMU_OPT_BOOL, + .help = "enable/disable snapshot mode", + },{ + .name = "file", + .type = QEMU_OPT_STRING, + .help = "disk image", + },{ + .name = "discard", + .type = QEMU_OPT_STRING, + .help = "discard operation (ignore/off, unmap/on)", + },{ .name = "cache", .type = QEMU_OPT_STRING, .help = "host cache usage (none, writeback, writethrough, " diff --git a/blockjob.c b/blockjob.c index ca80df1d0e..7edc945119 100644 --- a/blockjob.c +++ b/blockjob.c @@ -187,7 +187,7 @@ int block_job_cancel_sync(BlockJob *job) return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret; } -void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns) +void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns) { assert(job->busy); @@ -200,7 +200,7 @@ void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns) if (block_job_is_paused(job)) { qemu_coroutine_yield(); } else { - co_sleep_ns(clock, ns); + co_sleep_ns(type, ns); } job->busy = true; } @@ -155,7 +155,6 @@ curl="" curses="" docs="" fdt="" -nptl="" pixman="" sdl="" virtfs="" @@ -232,7 +231,7 @@ libusb="" usb_redir="" glx="" zlib="yes" -guest_agent="yes" +guest_agent="" want_tools="yes" libiscsi="" coroutine="" @@ -856,10 +855,6 @@ for opt do ;; --enable-fdt) fdt="yes" ;; - --disable-nptl) nptl="no" - ;; - --enable-nptl) nptl="yes" - ;; --enable-mixemu) mixemu="yes" ;; --disable-linux-aio) linux_aio="no" @@ -1103,8 +1098,6 @@ echo " --enable-kvm enable KVM acceleration support" echo " --disable-rdma disable RDMA-based migration support" echo " --enable-rdma enable RDMA-based migration support" echo " --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)" -echo " --disable-nptl disable usermode NPTL support" -echo " --enable-nptl enable usermode NPTL support" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-user enable supported user emulation targets" @@ -1439,7 +1432,7 @@ fi ########################################## # NPTL probe -if test "$nptl" != "no" ; then +if test "$linux_user" = "yes"; then cat > $TMPC <<EOF #include <sched.h> #include <linux/futex.h> @@ -1450,14 +1443,8 @@ int main(void) { return 0; } EOF - - if compile_object ; then - nptl=yes - else - if test "$nptl" = "yes" ; then - feature_not_found "nptl" - fi - nptl=no + if ! compile_object ; then + feature_not_found "nptl" fi fi @@ -1482,7 +1469,7 @@ libs_softmmu="$libs_softmmu -lz" # libseccomp check if test "$seccomp" != "no" ; then - if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then + if $pkg_config --atleast-version=2.1.0 libseccomp --modversion >/dev/null 2>&1; then libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`" QEMU_CFLAGS="$QEMU_CFLAGS `$pkg_config --cflags libseccomp`" seccomp="yes" @@ -2831,6 +2818,37 @@ if compile_prog "" "" ; then dup3=yes fi +# check for ppoll support +ppoll=no +cat > $TMPC << EOF +#include <poll.h> + +int main(void) +{ + struct pollfd pfd = { .fd = 0, .events = 0, .revents = 0 }; + ppoll(&pfd, 1, 0, 0); + return 0; +} +EOF +if compile_prog "" "" ; then + ppoll=yes +fi + +# check for prctl(PR_SET_TIMERSLACK , ... ) support +prctl_pr_set_timerslack=no +cat > $TMPC << EOF +#include <sys/prctl.h> + +int main(void) +{ + prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); + return 0; +} +EOF +if compile_prog "" "" ; then + prctl_pr_set_timerslack=yes +fi + # check for epoll support epoll=no cat > $TMPC << EOF @@ -3457,10 +3475,15 @@ if test "$softmmu" = yes ; then virtfs=no fi fi +fi +if [ "$guest_agent" != "no" ]; then if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then - if [ "$guest_agent" = "yes" ]; then tools="qemu-ga\$(EXESUF) $tools" - fi + guest_agent=yes + elif [ "$guest_agent" != yes ]; then + guest_agent=no + else + error_exit "Guest agent is not supported on this platform" fi fi @@ -3581,7 +3604,6 @@ echo "bluez support $bluez" echo "Documentation $docs" [ ! -z "$uname_release" ] && \ echo "uname -r $uname_release" -echo "NPTL support $nptl" echo "GUEST_BASE $guest_base" echo "PIE $pie" echo "vde support $vde" @@ -3659,7 +3681,7 @@ echo "libs_softmmu=$libs_softmmu" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak case "$cpu" in - arm|i386|x86_64|ppc) + arm|i386|x86_64|ppc|aarch64) # The TCG interpreter currently does not support ld/st optimization. if test "$tcg_interpreter" = "no" ; then echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_host_mak @@ -3823,6 +3845,12 @@ fi if test "$dup3" = "yes" ; then echo "CONFIG_DUP3=y" >> $config_host_mak fi +if test "$ppoll" = "yes" ; then + echo "CONFIG_PPOLL=y" >> $config_host_mak +fi +if test "$prctl_pr_set_timerslack" = "yes" ; then + echo "CONFIG_PRCTL_PR_SET_TIMERSLACK=y" >> $config_host_mak +fi if test "$epoll" = "yes" ; then echo "CONFIG_EPOLL=y" >> $config_host_mak fi @@ -4216,7 +4244,6 @@ mkdir -p $target_dir echo "# Automatically generated by configure - do not modify" > $config_target_mak bflt="no" -target_nptl="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_name/g"` gdb_xml_files="" @@ -4231,16 +4258,13 @@ case "$target_name" in TARGET_BASE_ARCH=i386 ;; alpha) - target_nptl="yes" ;; arm|armeb) TARGET_ARCH=arm bflt="yes" - target_nptl="yes" gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" ;; cris) - target_nptl="yes" ;; lm32) ;; @@ -4251,12 +4275,10 @@ case "$target_name" in microblaze|microblazeel) TARGET_ARCH=microblaze bflt="yes" - target_nptl="yes" ;; mips|mipsel) TARGET_ARCH=mips echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak - target_nptl="yes" ;; mipsn32|mipsn32el) TARGET_ARCH=mips64 @@ -4277,13 +4299,11 @@ case "$target_name" in ;; ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_nptl="yes" ;; ppcemb) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_nptl="yes" ;; ppc64) TARGET_BASE_ARCH=ppc @@ -4300,7 +4320,6 @@ case "$target_name" in sh4|sh4eb) TARGET_ARCH=sh4 bflt="yes" - target_nptl="yes" ;; sparc) ;; @@ -4314,7 +4333,6 @@ case "$target_name" in echo "TARGET_ABI32=y" >> $config_target_mak ;; s390x) - target_nptl="yes" ;; unicore32) ;; @@ -4396,10 +4414,6 @@ fi if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then echo "TARGET_HAS_BFLT=y" >> $config_target_mak fi -if test "$target_user_only" = "yes" \ - -a "$nptl" = "yes" -a "$target_nptl" = "yes"; then - echo "CONFIG_USE_NPTL=y" >> $config_target_mak -fi if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then echo "CONFIG_USE_GUEST_BASE=y" >> $config_target_mak fi @@ -4530,13 +4544,13 @@ if [ "$dtc_internal" = "yes" ]; then fi # build tree in object directory in case the source is not in the current directory -DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos" +DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS qapi-generated" FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -FILES="$FILES tests/tcg/lm32/Makefile po/Makefile" +FILES="$FILES tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES pc-bios/s390-ccw/Makefile" @@ -62,12 +62,17 @@ static CPUState *next_cpu; +bool cpu_is_stopped(CPUState *cpu) +{ + return cpu->stopped || !runstate_is_running(); +} + static bool cpu_thread_is_idle(CPUState *cpu) { if (cpu->stop || cpu->queued_work_first) { return false; } - if (cpu->stopped || !runstate_is_running()) { + if (cpu_is_stopped(cpu)) { return true; } if (!cpu->halted || qemu_cpu_has_work(cpu) || @@ -112,7 +117,7 @@ typedef struct TimersState { int64_t dummy; } TimersState; -TimersState timers_state; +static TimersState timers_state; /* Return the virtual CPU time, based on the instruction counter. */ int64_t cpu_get_icount(void) @@ -202,7 +207,7 @@ static void icount_adjust(void) return; } cur_time = cpu_get_clock(); - cur_icount = qemu_get_clock_ns(vm_clock); + cur_icount = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); delta = cur_icount - cur_time; /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ if (delta > 0 @@ -223,15 +228,16 @@ static void icount_adjust(void) static void icount_adjust_rt(void *opaque) { - qemu_mod_timer(icount_rt_timer, - qemu_get_clock_ms(rt_clock) + 1000); + timer_mod(icount_rt_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); icount_adjust(); } static void icount_adjust_vm(void *opaque) { - qemu_mod_timer(icount_vm_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); + timer_mod(icount_vm_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + get_ticks_per_sec() / 10); icount_adjust(); } @@ -247,22 +253,22 @@ static void icount_warp_rt(void *opaque) } if (runstate_is_running()) { - int64_t clock = qemu_get_clock_ns(rt_clock); + int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); int64_t warp_delta = clock - vm_clock_warp_start; if (use_icount == 1) { qemu_icount_bias += warp_delta; } else { /* - * In adaptive mode, do not let the vm_clock run too + * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too * far ahead of real time. */ int64_t cur_time = cpu_get_clock(); - int64_t cur_icount = qemu_get_clock_ns(vm_clock); + int64_t cur_icount = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t delta = cur_time - cur_icount; qemu_icount_bias += MIN(warp_delta, delta); } - if (qemu_clock_expired(vm_clock)) { - qemu_notify_event(); + if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } } vm_clock_warp_start = -1; @@ -270,19 +276,19 @@ static void icount_warp_rt(void *opaque) void qtest_clock_warp(int64_t dest) { - int64_t clock = qemu_get_clock_ns(vm_clock); + int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); assert(qtest_enabled()); while (clock < dest) { - int64_t deadline = qemu_clock_deadline(vm_clock); + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); int64_t warp = MIN(dest - clock, deadline); qemu_icount_bias += warp; - qemu_run_timers(vm_clock); - clock = qemu_get_clock_ns(vm_clock); + qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); + clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } - qemu_notify_event(); + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } -void qemu_clock_warp(QEMUClock *clock) +void qemu_clock_warp(QEMUClockType type) { int64_t deadline; @@ -291,20 +297,20 @@ void qemu_clock_warp(QEMUClock *clock) * applicable to other clocks. But a clock argument removes the * need for if statements all over the place. */ - if (clock != vm_clock || !use_icount) { + if (type != QEMU_CLOCK_VIRTUAL || !use_icount) { return; } /* - * If the CPUs have been sleeping, advance the vm_clock timer now. This - * ensures that the deadline for the timer is computed correctly below. + * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. + * This ensures that the deadline for the timer is computed correctly below. * This also makes sure that the insn counter is synchronized before the * CPU starts running, in case the CPU is woken by an event other than - * the earliest vm_clock timer. + * the earliest QEMU_CLOCK_VIRTUAL timer. */ icount_warp_rt(NULL); - if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) { - qemu_del_timer(icount_warp_timer); + if (!all_cpu_threads_idle() || !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL)) { + timer_del(icount_warp_timer); return; } @@ -313,28 +319,40 @@ void qemu_clock_warp(QEMUClock *clock) return; } - vm_clock_warp_start = qemu_get_clock_ns(rt_clock); - deadline = qemu_clock_deadline(vm_clock); + vm_clock_warp_start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + /* We want to use the earliest deadline from ALL vm_clocks */ + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + + /* Maintain prior (possibly buggy) behaviour where if no deadline + * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than + * INT32_MAX nanoseconds ahead, we still use INT32_MAX + * nanoseconds. + */ + if ((deadline < 0) || (deadline > INT32_MAX)) { + deadline = INT32_MAX; + } + if (deadline > 0) { /* - * Ensure the vm_clock proceeds even when the virtual CPU goes to + * Ensure QEMU_CLOCK_VIRTUAL proceeds even when the virtual CPU goes to * sleep. Otherwise, the CPU might be waiting for a future timer * interrupt to wake it up, but the interrupt never comes because * the vCPU isn't running any insns and thus doesn't advance the - * vm_clock. + * QEMU_CLOCK_VIRTUAL. * * An extreme solution for this problem would be to never let VCPUs - * sleep in icount mode if there is a pending vm_clock timer; rather - * time could just advance to the next vm_clock event. Instead, we - * do stop VCPUs and only advance vm_clock after some "real" time, - * (related to the time left until the next event) has passed. This - * rt_clock timer will do this. This avoids that the warps are too - * visible externally---for example, you will not be sending network - * packets continuously instead of every 100ms. + * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL + * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL + * event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL + * after some e"real" time, (related to the time left until the next + * event) has passed. The QEMU_CLOCK_REALTIME timer will do this. + * This avoids that the warps are visible externally; for example, + * you will not be sending network packets continuously instead of + * every 100ms. */ - qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline); - } else { - qemu_notify_event(); + timer_mod(icount_warp_timer, vm_clock_warp_start + deadline); + } else if (deadline == 0) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } } @@ -358,7 +376,8 @@ void configure_icount(const char *option) return; } - icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL); + icount_warp_timer = timer_new_ns(QEMU_CLOCK_REALTIME, + icount_warp_rt, NULL); if (strcmp(option, "auto") != 0) { icount_time_shift = strtol(option, NULL, 0); use_icount = 1; @@ -376,12 +395,15 @@ void configure_icount(const char *option) the virtual time trigger catches emulated time passing too fast. Realtime triggers occur even when idle, so use them less frequently than VM triggers. */ - icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL); - qemu_mod_timer(icount_rt_timer, - qemu_get_clock_ms(rt_clock) + 1000); - icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL); - qemu_mod_timer(icount_vm_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); + icount_rt_timer = timer_new_ms(QEMU_CLOCK_REALTIME, + icount_adjust_rt, NULL); + timer_mod(icount_rt_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); + icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + icount_adjust_vm, NULL); + timer_mod(icount_vm_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + get_ticks_per_sec() / 10); } /***********************************************************/ @@ -429,11 +451,6 @@ void cpu_synchronize_all_post_init(void) } } -bool cpu_is_stopped(CPUState *cpu) -{ - return !runstate_is_running() || cpu->stopped; -} - static int do_vm_stop(RunState state) { int ret = 0; @@ -457,7 +474,7 @@ static bool cpu_can_run(CPUState *cpu) if (cpu->stop) { return false; } - if (cpu->stopped || !runstate_is_running()) { + if (cpu_is_stopped(cpu)) { return false; } return true; @@ -735,7 +752,7 @@ static void qemu_tcg_wait_io_event(void) while (all_cpu_threads_idle()) { /* Start accounting real time to the virtual clock if the CPUs are idle. */ - qemu_clock_warp(vm_clock); + qemu_clock_warp(QEMU_CLOCK_VIRTUAL); qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex); } @@ -866,8 +883,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { tcg_exec_all(); - if (use_icount && qemu_clock_deadline(vm_clock) <= 0) { - qemu_notify_event(); + + if (use_icount) { + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + + if (deadline == 0) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } } qemu_tcg_wait_io_event(); } @@ -985,7 +1007,7 @@ void pause_all_vcpus(void) { CPUState *cpu = first_cpu; - qemu_clock_enable(vm_clock, false); + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false); while (cpu) { cpu->stop = true; qemu_cpu_kick(cpu); @@ -1026,7 +1048,7 @@ void resume_all_vcpus(void) { CPUState *cpu = first_cpu; - qemu_clock_enable(vm_clock, true); + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); while (cpu) { cpu_resume(cpu); cpu = cpu->next_cpu; @@ -1145,11 +1167,23 @@ static int tcg_cpu_exec(CPUArchState *env) #endif if (use_icount) { int64_t count; + int64_t deadline; int decr; qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 0; env->icount_extra = 0; - count = qemu_icount_round(qemu_clock_deadline(vm_clock)); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + + /* Maintain prior (possibly buggy) behaviour where if no deadline + * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than + * INT32_MAX nanoseconds ahead, we still use INT32_MAX + * nanoseconds. + */ + if ((deadline < 0) || (deadline > INT32_MAX)) { + deadline = INT32_MAX; + } + + count = qemu_icount_round(deadline); qemu_icount += count; decr = (count > 0xffff) ? 0xffff : count; count -= decr; @@ -1175,8 +1209,8 @@ static void tcg_exec_all(void) { int r; - /* Account partial waits to the vm_clock. */ - qemu_clock_warp(vm_clock); + /* Account partial waits to QEMU_CLOCK_VIRTUAL. */ + qemu_clock_warp(QEMU_CLOCK_VIRTUAL); if (next_cpu == NULL) { next_cpu = first_cpu; @@ -1185,7 +1219,7 @@ static void tcg_exec_all(void) CPUState *cpu = next_cpu; CPUArchState *env = cpu->env_ptr; - qemu_clock_enable(vm_clock, + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0); if (cpu_can_run(cpu)) { diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak index 18e5337a77..bc07600f96 100644 --- a/default-configs/alpha-softmmu.mak +++ b/default-configs/alpha-softmmu.mak @@ -14,3 +14,4 @@ CONFIG_VMWARE_VGA=y CONFIG_IDE_CMD646=y CONFIG_I8259=y CONFIG_MC146818RTC=y +CONFIG_ISA_TESTDEV=y diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 27cbe3d088..ac0815d663 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -34,9 +34,9 @@ CONFIG_PFLASH_CFI02=y CONFIG_MICRODRIVE=y CONFIG_USB_MUSB=y -CONFIG_ARM9MPCORE=y CONFIG_ARM11MPCORE=y -CONFIG_ARM15MPCORE=y +CONFIG_A9MPCORE=y +CONFIG_A15MPCORE=y CONFIG_ARM_GIC=y CONFIG_ARM_GIC_KVM=$(CONFIG_KVM) diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 4a0fc9c293..37ef90f585 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -33,7 +33,6 @@ CONFIG_MC146818RTC=y CONFIG_PAM=y CONFIG_PCI_PIIX=y CONFIG_WDT_IB700=y -CONFIG_PC_SYSFW=y CONFIG_XEN_I386=$(CONFIG_XEN) CONFIG_ISA_DEBUG=y CONFIG_ISA_TESTDEV=y diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index b443702b87..71177efdff 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -3,7 +3,6 @@ include pci.mak include sound.mak include usb.mak -CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y CONFIG_VGA_PCI=y @@ -34,3 +33,5 @@ CONFIG_I8259=y CONFIG_JAZZ_LED=y CONFIG_MC146818RTC=y CONFIG_VT82C686=y +CONFIG_ISA_TESTDEV=y +CONFIG_EMPTY_SLOT=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index d63895792b..617301b753 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -3,7 +3,6 @@ include pci.mak include sound.mak include usb.mak -CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y CONFIG_VGA_PCI=y @@ -34,3 +33,5 @@ CONFIG_I8259=y CONFIG_JAZZ_LED=y CONFIG_MC146818RTC=y CONFIG_VT82C686=y +CONFIG_ISA_TESTDEV=y +CONFIG_EMPTY_SLOT=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index c9be3f49ca..317b151361 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -3,7 +3,6 @@ include pci.mak include sound.mak include usb.mak -CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y CONFIG_VGA_PCI=y @@ -36,3 +35,5 @@ CONFIG_I8259=y CONFIG_JAZZ_LED=y CONFIG_MC146818RTC=y CONFIG_VT82C686=y +CONFIG_ISA_TESTDEV=y +CONFIG_EMPTY_SLOT=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index 4f4a449408..532a9aefbd 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -3,7 +3,6 @@ include pci.mak include sound.mak include usb.mak -CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y CONFIG_VGA_PCI=y @@ -34,3 +33,5 @@ CONFIG_I8259=y CONFIG_JAZZ_LED=y CONFIG_MC146818RTC=y CONFIG_VT82C686=y +CONFIG_ISA_TESTDEV=y +CONFIG_EMPTY_SLOT=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 73e4cc5f63..eac0b28fb9 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -46,3 +46,4 @@ CONFIG_E500=y CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) # For PReP CONFIG_MC146818RTC=y +CONFIG_ISA_TESTDEV=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index 6d1933bbf9..7831c2bf57 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -48,4 +48,11 @@ CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) # For pSeries CONFIG_XICS=$(CONFIG_PSERIES) # For PReP +CONFIG_I82378=y +CONFIG_I8259=y +CONFIG_I8254=y +CONFIG_PCSPK=y +CONFIG_I82374=y +CONFIG_I8257=y CONFIG_MC146818RTC=y +CONFIG_ISA_TESTDEV=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index e3b5e50360..86080a7574 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -41,3 +41,4 @@ CONFIG_E500=y CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) # For PReP CONFIG_MC146818RTC=y +CONFIG_ISA_TESTDEV=y diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak index f6bf62d1c2..8e00390d4f 100644 --- a/default-configs/sh4-softmmu.mak +++ b/default-configs/sh4-softmmu.mak @@ -5,7 +5,14 @@ include usb.mak CONFIG_SERIAL=y CONFIG_PTIMER=y CONFIG_PFLASH_CFI02=y -CONFIG_ISA_MMIO=y CONFIG_SH4=y CONFIG_IDE_MMIO=y CONFIG_SM501=y +CONFIG_ISA_TESTDEV=y +CONFIG_I82378=y +CONFIG_I8259=y +CONFIG_I8254=y +CONFIG_PCSPK=y +CONFIG_I82374=y +CONFIG_I8257=y +CONFIG_MC146818RTC=y diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak index c1d513d099..efdd05842f 100644 --- a/default-configs/sh4eb-softmmu.mak +++ b/default-configs/sh4eb-softmmu.mak @@ -5,7 +5,14 @@ include usb.mak CONFIG_SERIAL=y CONFIG_PTIMER=y CONFIG_PFLASH_CFI02=y -CONFIG_ISA_MMIO=y CONFIG_SH4=y CONFIG_IDE_MMIO=y CONFIG_SM501=y +CONFIG_ISA_TESTDEV=y +CONFIG_I82378=y +CONFIG_I8259=y +CONFIG_I8254=y +CONFIG_PCSPK=y +CONFIG_I82374=y +CONFIG_I8257=y +CONFIG_MC146818RTC=y diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak index 9b08ee8a20..299c97b715 100644 --- a/default-configs/sparc64-softmmu.mak +++ b/default-configs/sparc64-softmmu.mak @@ -15,3 +15,4 @@ CONFIG_IDE_ISA=y CONFIG_IDE_CMD646=y CONFIG_PCI_APB=y CONFIG_MC146818RTC=y +CONFIG_ISA_TESTDEV=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 10bb0c621c..31bddce4f4 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -33,7 +33,6 @@ CONFIG_MC146818RTC=y CONFIG_PAM=y CONFIG_PCI_PIIX=y CONFIG_WDT_IB700=y -CONFIG_PC_SYSFW=y CONFIG_XEN_I386=$(CONFIG_XEN) CONFIG_ISA_DEBUG=y CONFIG_ISA_TESTDEV=y @@ -158,6 +158,35 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) } #endif +static int print_insn_objdump(bfd_vma pc, disassemble_info *info, + const char *prefix) +{ + int i, n = info->buffer_length; + uint8_t *buf = g_malloc(n); + + info->read_memory_func(pc, buf, n, info); + + for (i = 0; i < n; ++i) { + if (i % 32 == 0) { + info->fprintf_func(info->stream, "\n%s: ", prefix); + } + info->fprintf_func(info->stream, "%02x", buf[i]); + } + + g_free(buf); + return n; +} + +static int print_insn_od_host(bfd_vma pc, disassemble_info *info) +{ + return print_insn_objdump(pc, info, "OBJD-H"); +} + +static int print_insn_od_target(bfd_vma pc, disassemble_info *info) +{ + return print_insn_objdump(pc, info, "OBJD-T"); +} + /* Disassemble this for me please... (debugging). 'flags' has the following values: i386 - 1 means 16 bit code, 2 means 64 bit code @@ -171,7 +200,7 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code, target_ulong pc; int count; CPUDebug s; - int (*print_insn)(bfd_vma pc, disassemble_info *info); + int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL; INIT_DISASSEMBLE_INFO(s.info, out, fprintf); @@ -263,11 +292,10 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code, #elif defined(TARGET_LM32) s.info.mach = bfd_mach_lm32; print_insn = print_insn_lm32; -#else - fprintf(out, "0x" TARGET_FMT_lx - ": Asm output not supported on this arch\n", code); - return; #endif + if (print_insn == NULL) { + print_insn = print_insn_od_target; + } for (pc = code; size > 0; pc += count, size -= count) { fprintf(out, "0x" TARGET_FMT_lx ": ", pc); @@ -303,7 +331,7 @@ void disas(FILE *out, void *code, unsigned long size) uintptr_t pc; int count; CPUDebug s; - int (*print_insn)(bfd_vma pc, disassemble_info *info); + int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL; INIT_DISASSEMBLE_INFO(s.info, out, fprintf); s.info.print_address_func = generic_print_host_address; @@ -347,11 +375,10 @@ void disas(FILE *out, void *code, unsigned long size) print_insn = print_insn_hppa; #elif defined(__ia64__) print_insn = print_insn_ia64; -#else - fprintf(out, "0x%lx: Asm output not supported on this arch\n", - (long) code); - return; #endif + if (print_insn == NULL) { + print_insn = print_insn_od_host; + } for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) { fprintf(out, "0x%08" PRIxPTR ": ", pc); count = print_insn(pc, &s.info); diff --git a/dma-helpers.c b/dma-helpers.c index 499550fc23..c9620a5bbd 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -11,6 +11,7 @@ #include "trace.h" #include "qemu/range.h" #include "qemu/thread.h" +#include "qemu/main-loop.h" /* #define DEBUG_IOMMU */ diff --git a/docs/q35-chipset.cfg b/docs/q35-chipset.cfg index 1b6efc0f2c..e4ddb7d9cc 100644 --- a/docs/q35-chipset.cfg +++ b/docs/q35-chipset.cfg @@ -91,6 +91,29 @@ port = "4" chassis = "4" +## +# Example PCIe switch with two downstream ports +# +#[device "pcie-switch-upstream-port-1"] +# driver = "x3130-upstream" +# bus = "ich9-pcie-port-4" +# addr = "00.0" +# +#[device "pcie-switch-downstream-port-1-1"] +# driver = "xio3130-downstream" +# multifunction = "on" +# bus = "pcie-switch-upstream-port-1" +# addr = "00.0" +# port = "1" +# chassis = "5" +# +#[device "pcie-switch-downstream-port-1-2"] +# driver = "xio3130-downstream" +# multifunction = "on" +# bus = "pcie-switch-upstream-port-1" +# addr = "00.1" +# port = "1" +# chassis = "6" [device "ich9-ehci-1"] driver = "ich9-usb-ehci1" diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index cccb11e562..0ce045c0b3 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -34,9 +34,15 @@ OrderedDicts so that ordering is preserved. There are two basic syntaxes used, type definitions and command definitions. The first syntax defines a type and is represented by a dictionary. There are -two kinds of types that are supported: complex user-defined types, and enums. +three kinds of user-defined types that are supported: complex types, +enumeration types and union types. -A complex type is a dictionary containing a single key who's value is a +Generally speaking, types definitions should always use CamelCase for the type +names. Command names should be all lower case with words separated by a hyphen. + +=== Complex types === + +A complex type is a dictionary containing a single key whose value is a dictionary. This corresponds to a struct in C or an Object in JSON. An example of a complex type is: @@ -47,13 +53,104 @@ The use of '*' as a prefix to the name means the member is optional. Optional members should always be added to the end of the dictionary to preserve backwards compatibility. -An enumeration type is a dictionary containing a single key who's value is a +=== Enumeration types === + +An enumeration type is a dictionary containing a single key whose value is a list of strings. An example enumeration is: { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] } -Generally speaking, complex types and enums should always use CamelCase for -the type names. +=== Union types === + +Union types are used to let the user choose between several different data +types. A union type is defined using a dictionary as explained in the +following paragraphs. + + +A simple union type defines a mapping from discriminator values to data types +like in this example: + + { 'type': 'FileOptions', 'data': { 'filename': 'str' } } + { 'type': 'Qcow2Options', + 'data': { 'backing-file': 'str', 'lazy-refcounts': 'bool' } } + + { 'union': 'BlockdevOptions', + 'data': { 'file': 'FileOptions', + 'qcow2': 'Qcow2Options' } } + +In the QMP wire format, a simple union is represented by a dictionary that +contains the 'type' field as a discriminator, and a 'data' field that is of the +specified data type corresponding to the discriminator value: + + { "type": "qcow2", "data" : { "backing-file": "/some/place/my-image", + "lazy-refcounts": true } } + + +A union definition can specify a complex type as its base. In this case, the +fields of the complex type are included as top-level fields of the union +dictionary in the QMP wire format. An example definition is: + + { 'type': 'BlockdevCommonOptions', 'data': { 'readonly': 'bool' } } + { 'union': 'BlockdevOptions', + 'base': 'BlockdevCommonOptions', + 'data': { 'raw': 'RawOptions', + 'qcow2': 'Qcow2Options' } } + +And it looks like this on the wire: + + { "type": "qcow2", + "readonly": false, + "data" : { "backing-file": "/some/place/my-image", + "lazy-refcounts": true } } + + +Flat union types avoid the nesting on the wire. They are used whenever a +specific field of the base type is declared as the discriminator ('type' is +then no longer generated). The discriminator must always be a string field. +The above example can then be modified as follows: + + { 'type': 'BlockdevCommonOptions', + 'data': { 'driver': 'str', 'readonly': 'bool' } } + { 'union': 'BlockdevOptions', + 'base': 'BlockdevCommonOptions', + 'discriminator': 'driver', + 'data': { 'raw': 'RawOptions', + 'qcow2': 'Qcow2Options' } } + +Resulting in this JSON object: + + { "driver": "qcow2", + "readonly": false, + "backing-file": "/some/place/my-image", + "lazy-refcounts": true } + + +A special type of unions are anonymous unions. They don't form a dictionary in +the wire format but allow the direct use of different types in their place. As +they aren't structured, they don't have any explicit discriminator but use +the (QObject) data type of their value as an implicit discriminator. This means +that they are restricted to using only one discriminator value per QObject +type. For example, you cannot have two different complex types in an anonymous +union, or two different integer types. + +Anonymous unions are declared using an empty dictionary as their discriminator. +The discriminator values never appear on the wire, they are only used in the +generated C code. Anonymous unions cannot have a base type. + + { 'union': 'BlockRef', + 'discriminator': {}, + 'data': { 'definition': 'BlockdevOptions', + 'reference': 'str' } } + +This example allows using both of the following example objects: + + { "file": "my_existing_block_device_id" } + { "file": { "driver": "file", + "readonly": false, + 'filename': "/tmp/mydisk.qcow2" } } + + +=== Commands === Commands are defined by using a list containing three members. The first member is the command name, the second member is a dictionary containing @@ -65,8 +162,6 @@ An example command is: 'data': { 'arg1': 'str', '*arg2': 'str' }, 'returns': 'str' } -Command names should be all lower case with words separated by a hyphen. - == Code generation == diff --git a/docs/rdma.txt b/docs/rdma.txt index 45d1c8aab8..8d1e003f92 100644 --- a/docs/rdma.txt +++ b/docs/rdma.txt @@ -199,7 +199,7 @@ Version #1 requires that all server implementations of the protocol must check this field and register all requests found in the array of commands located in the data portion and return an equal number of results in the response. The maximum number of repeats is hard-coded to 4096. This is a conservative -limit based on the maximum size of a SEND message along with emperical +limit based on the maximum size of a SEND message along with empirical observations on the maximum future benefit of simultaneous page registrations. The 'type' field has 12 different command values: @@ -59,6 +59,7 @@ static uint64_t cpu_convert_to_target64(uint64_t val, int endian) } typedef struct DumpState { + GuestPhysBlockList guest_phys_blocks; ArchDumpInfo dump_info; MemoryMappingList list; uint16_t phdr_num; @@ -69,7 +70,7 @@ typedef struct DumpState { hwaddr memory_offset; int fd; - RAMBlock *block; + GuestPhysBlock *next_block; ram_addr_t start; bool has_filter; int64_t begin; @@ -81,6 +82,7 @@ static int dump_cleanup(DumpState *s) { int ret = 0; + guest_phys_blocks_free(&s->guest_phys_blocks); memory_mapping_list_free(&s->list); if (s->fd != -1) { close(s->fd); @@ -187,7 +189,8 @@ static int write_elf32_header(DumpState *s) } static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, - int phdr_index, hwaddr offset) + int phdr_index, hwaddr offset, + hwaddr filesz) { Elf64_Phdr phdr; int ret; @@ -197,15 +200,12 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); phdr.p_offset = cpu_convert_to_target64(offset, endian); phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian); - if (offset == -1) { - /* When the memory is not stored into vmcore, offset will be -1 */ - phdr.p_filesz = 0; - } else { - phdr.p_filesz = cpu_convert_to_target64(memory_mapping->length, endian); - } + phdr.p_filesz = cpu_convert_to_target64(filesz, endian); phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian); phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian); + assert(memory_mapping->length >= filesz); + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); if (ret < 0) { dump_error(s, "dump: failed to write program header table.\n"); @@ -216,7 +216,8 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, } static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, - int phdr_index, hwaddr offset) + int phdr_index, hwaddr offset, + hwaddr filesz) { Elf32_Phdr phdr; int ret; @@ -226,15 +227,12 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); phdr.p_offset = cpu_convert_to_target32(offset, endian); phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian); - if (offset == -1) { - /* When the memory is not stored into vmcore, offset will be -1 */ - phdr.p_filesz = 0; - } else { - phdr.p_filesz = cpu_convert_to_target32(memory_mapping->length, endian); - } + phdr.p_filesz = cpu_convert_to_target32(filesz, endian); phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian); phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian); + assert(memory_mapping->length >= filesz); + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); if (ret < 0) { dump_error(s, "dump: failed to write program header table.\n"); @@ -393,14 +391,14 @@ static int write_data(DumpState *s, void *buf, int length) } /* write the memroy to vmcore. 1 page per I/O. */ -static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, +static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, int64_t size) { int64_t i; int ret; for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { - ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); if (ret < 0) { return ret; @@ -408,7 +406,7 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, } if ((size % TARGET_PAGE_SIZE) != 0) { - ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, size % TARGET_PAGE_SIZE); if (ret < 0) { return ret; @@ -418,57 +416,71 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, return 0; } -/* get the memory's offset in the vmcore */ -static hwaddr get_offset(hwaddr phys_addr, - DumpState *s) +/* get the memory's offset and size in the vmcore */ +static void get_offset_range(hwaddr phys_addr, + ram_addr_t mapping_length, + DumpState *s, + hwaddr *p_offset, + hwaddr *p_filesz) { - RAMBlock *block; + GuestPhysBlock *block; hwaddr offset = s->memory_offset; int64_t size_in_block, start; + /* When the memory is not stored into vmcore, offset will be -1 */ + *p_offset = -1; + *p_filesz = 0; + if (s->has_filter) { if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { - return -1; + return; } } - QTAILQ_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { if (s->has_filter) { - if (block->offset >= s->begin + s->length || - block->offset + block->length <= s->begin) { + if (block->target_start >= s->begin + s->length || + block->target_end <= s->begin) { /* This block is out of the range */ continue; } - if (s->begin <= block->offset) { - start = block->offset; + if (s->begin <= block->target_start) { + start = block->target_start; } else { start = s->begin; } - size_in_block = block->length - (start - block->offset); - if (s->begin + s->length < block->offset + block->length) { - size_in_block -= block->offset + block->length - - (s->begin + s->length); + size_in_block = block->target_end - start; + if (s->begin + s->length < block->target_end) { + size_in_block -= block->target_end - (s->begin + s->length); } } else { - start = block->offset; - size_in_block = block->length; + start = block->target_start; + size_in_block = block->target_end - block->target_start; } if (phys_addr >= start && phys_addr < start + size_in_block) { - return phys_addr - start + offset; + *p_offset = phys_addr - start + offset; + + /* The offset range mapped from the vmcore file must not spill over + * the GuestPhysBlock, clamp it. The rest of the mapping will be + * zero-filled in memory at load time; see + * <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>. + */ + *p_filesz = phys_addr + mapping_length <= start + size_in_block ? + mapping_length : + size_in_block - (phys_addr - start); + return; } offset += size_in_block; } - - return -1; } static int write_elf_loads(DumpState *s) { - hwaddr offset; + hwaddr offset, filesz; MemoryMapping *memory_mapping; uint32_t phdr_index = 1; int ret; @@ -481,11 +493,15 @@ static int write_elf_loads(DumpState *s) } QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { - offset = get_offset(memory_mapping->phys_addr, s); + get_offset_range(memory_mapping->phys_addr, + memory_mapping->length, + s, &offset, &filesz); if (s->dump_info.d_class == ELFCLASS64) { - ret = write_elf64_load(s, memory_mapping, phdr_index++, offset); + ret = write_elf64_load(s, memory_mapping, phdr_index++, offset, + filesz); } else { - ret = write_elf32_load(s, memory_mapping, phdr_index++, offset); + ret = write_elf32_load(s, memory_mapping, phdr_index++, offset, + filesz); } if (ret < 0) { @@ -596,7 +612,7 @@ static int dump_completed(DumpState *s) return 0; } -static int get_next_block(DumpState *s, RAMBlock *block) +static int get_next_block(DumpState *s, GuestPhysBlock *block) { while (1) { block = QTAILQ_NEXT(block, next); @@ -606,16 +622,16 @@ static int get_next_block(DumpState *s, RAMBlock *block) } s->start = 0; - s->block = block; + s->next_block = block; if (s->has_filter) { - if (block->offset >= s->begin + s->length || - block->offset + block->length <= s->begin) { + if (block->target_start >= s->begin + s->length || + block->target_end <= s->begin) { /* This block is out of the range */ continue; } - if (s->begin > block->offset) { - s->start = s->begin - block->offset; + if (s->begin > block->target_start) { + s->start = s->begin - block->target_start; } } @@ -626,18 +642,18 @@ static int get_next_block(DumpState *s, RAMBlock *block) /* write all memory to vmcore */ static int dump_iterate(DumpState *s) { - RAMBlock *block; + GuestPhysBlock *block; int64_t size; int ret; while (1) { - block = s->block; + block = s->next_block; - size = block->length; + size = block->target_end - block->target_start; if (s->has_filter) { size -= s->start; - if (s->begin + s->length < block->offset + block->length) { - size -= block->offset + block->length - (s->begin + s->length); + if (s->begin + s->length < block->target_end) { + size -= block->target_end - (s->begin + s->length); } } ret = write_memory(s, block, s->start, size); @@ -672,23 +688,23 @@ static int create_vmcore(DumpState *s) static ram_addr_t get_start_block(DumpState *s) { - RAMBlock *block; + GuestPhysBlock *block; if (!s->has_filter) { - s->block = QTAILQ_FIRST(&ram_list.blocks); + s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head); return 0; } - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - if (block->offset >= s->begin + s->length || - block->offset + block->length <= s->begin) { + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + if (block->target_start >= s->begin + s->length || + block->target_end <= s->begin) { /* This block is out of the range */ continue; } - s->block = block; - if (s->begin > block->offset) { - s->start = s->begin - block->offset; + s->next_block = block; + if (s->begin > block->target_start) { + s->start = s->begin - block->target_start; } else { s->start = 0; } @@ -713,32 +729,35 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, s->resume = false; } + /* If we use KVM, we should synchronize the registers before we get dump + * info or physmap info. + */ + cpu_synchronize_all_states(); + nr_cpus = 0; + for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + nr_cpus++; + } + s->errp = errp; s->fd = fd; s->has_filter = has_filter; s->begin = begin; s->length = length; + + guest_phys_blocks_init(&s->guest_phys_blocks); + guest_phys_blocks_append(&s->guest_phys_blocks); + s->start = get_start_block(s); if (s->start == -1) { error_set(errp, QERR_INVALID_PARAMETER, "begin"); goto cleanup; } - /* - * get dump info: endian, class and architecture. + /* get dump info: endian, class and architecture. * If the target architecture is not supported, cpu_get_dump_info() will * return -1. - * - * If we use KVM, we should synchronize the registers before we get dump - * info. */ - cpu_synchronize_all_states(); - nr_cpus = 0; - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - nr_cpus++; - } - - ret = cpu_get_dump_info(&s->dump_info); + ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks); if (ret < 0) { error_set(errp, QERR_UNSUPPORTED); goto cleanup; @@ -754,13 +773,13 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, /* get memory mapping */ memory_mapping_list_init(&s->list); if (paging) { - qemu_get_guest_memory_mapping(&s->list, &err); + qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); if (err != NULL) { error_propagate(errp, err); goto cleanup; } } else { - qemu_get_guest_simple_memory_mapping(&s->list); + qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks); } if (s->has_filter) { @@ -812,6 +831,8 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, return 0; cleanup: + guest_phys_blocks_free(&s->guest_phys_blocks); + if (s->resume) { vm_start(); } @@ -859,7 +880,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, return; } - s = g_malloc(sizeof(DumpState)); + s = g_malloc0(sizeof(DumpState)); ret = dump_init(s, fd, paging, has_begin, begin, length, errp); if (ret < 0) { @@ -402,11 +402,14 @@ void cpu_exec_init(CPUArchState *env) #if defined(CONFIG_USER_ONLY) cpu_list_unlock(); #endif - vmstate_register(NULL, cpu_index, &vmstate_cpu_common, cpu); + if (qdev_get_vmsd(DEVICE(cpu)) == NULL) { + vmstate_register(NULL, cpu_index, &vmstate_cpu_common, cpu); + } #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION, cpu_save, cpu_load, env); assert(cc->vmsd == NULL); + assert(qdev_get_vmsd(DEVICE(cpu)) == NULL); #endif if (cc->vmsd != NULL) { vmstate_register(NULL, cpu_index, cc->vmsd, cpu); @@ -590,15 +593,14 @@ void cpu_breakpoint_remove_all(CPUArchState *env, int mask) void cpu_single_step(CPUState *cpu, int enabled) { #if defined(TARGET_HAS_ICE) - CPUArchState *env = cpu->env_ptr; - if (cpu->singlestep_enabled != enabled) { cpu->singlestep_enabled = enabled; if (kvm_enabled()) { - kvm_update_guest_debug(env, 0); + kvm_update_guest_debug(cpu, 0); } else { /* must flush all the translated code to avoid inconsistencies */ /* XXX: only flush what is necessary */ + CPUArchState *env = cpu->env_ptr; tb_flush(env); } } @@ -646,6 +648,10 @@ CPUArchState *cpu_copy(CPUArchState *env) CPUWatchpoint *wp; #endif + /* Reset non arch specific state */ + cpu_reset(ENV_GET_CPU(new_env)); + + /* Copy arch specific state into the new CPU */ memcpy(new_env, env, sizeof(CPUArchState)); /* Clone all break/watchpoints. @@ -40,7 +40,6 @@ #include "cpu.h" #include "qemu/sockets.h" #include "sysemu/kvm.h" -#include "qemu/bitops.h" static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr, uint8_t *buf, int len, bool is_write) @@ -316,10 +315,7 @@ static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER; static GDBState *gdbserver_state; -/* This is an ugly hack to cope with both new and old gdb. - If gdb sends qXfer:features:read then assume we're talking to a newish - gdb that understands target descriptions. */ -static int gdb_has_xml; +bool gdb_has_xml; #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ @@ -489,1319 +485,6 @@ static int put_packet(GDBState *s, const char *buf) return put_packet_binary(s, buf, strlen(buf)); } -/* The GDB remote protocol transfers values in target byte order. This means - we can use the raw memory access routines to access the value buffer. - Conveniently, these also handle the case where the buffer is mis-aligned. - */ -#define GET_REG8(val) do { \ - stb_p(mem_buf, val); \ - return 1; \ - } while(0) -#define GET_REG16(val) do { \ - stw_p(mem_buf, val); \ - return 2; \ - } while(0) -#define GET_REG32(val) do { \ - stl_p(mem_buf, val); \ - return 4; \ - } while(0) -#define GET_REG64(val) do { \ - stq_p(mem_buf, val); \ - return 8; \ - } while(0) - -#if TARGET_LONG_BITS == 64 -#define GET_REGL(val) GET_REG64(val) -#define ldtul_p(addr) ldq_p(addr) -#else -#define GET_REGL(val) GET_REG32(val) -#define ldtul_p(addr) ldl_p(addr) -#endif - -#if defined(TARGET_I386) - -#ifdef TARGET_X86_64 -static const int gpr_map[16] = { - R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP, - 8, 9, 10, 11, 12, 13, 14, 15 -}; -#else -#define gpr_map gpr_map32 -#endif -static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - -#define NUM_CORE_REGS (CPU_NB_REGS * 2 + 25) - -#define IDX_IP_REG CPU_NB_REGS -#define IDX_FLAGS_REG (IDX_IP_REG + 1) -#define IDX_SEG_REGS (IDX_FLAGS_REG + 1) -#define IDX_FP_REGS (IDX_SEG_REGS + 6) -#define IDX_XMM_REGS (IDX_FP_REGS + 16) -#define IDX_MXCSR_REG (IDX_XMM_REGS + CPU_NB_REGS) - -static int cpu_gdb_read_register(CPUX86State *env, uint8_t *mem_buf, int n) -{ - if (n < CPU_NB_REGS) { - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - GET_REG64(env->regs[gpr_map[n]]); - } else if (n < CPU_NB_REGS32) { - GET_REG32(env->regs[gpr_map32[n]]); - } - } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { -#ifdef USE_X86LDOUBLE - /* FIXME: byteswap float values - after fixing fpregs layout. */ - memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10); -#else - memset(mem_buf, 0, 10); -#endif - return 10; - } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { - n -= IDX_XMM_REGS; - if (n < CPU_NB_REGS32 || - (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { - stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0)); - stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1)); - return 16; - } - } else { - switch (n) { - case IDX_IP_REG: - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - GET_REG64(env->eip); - } else { - GET_REG32(env->eip); - } - case IDX_FLAGS_REG: GET_REG32(env->eflags); - - case IDX_SEG_REGS: GET_REG32(env->segs[R_CS].selector); - case IDX_SEG_REGS + 1: GET_REG32(env->segs[R_SS].selector); - case IDX_SEG_REGS + 2: GET_REG32(env->segs[R_DS].selector); - case IDX_SEG_REGS + 3: GET_REG32(env->segs[R_ES].selector); - case IDX_SEG_REGS + 4: GET_REG32(env->segs[R_FS].selector); - case IDX_SEG_REGS + 5: GET_REG32(env->segs[R_GS].selector); - - case IDX_FP_REGS + 8: GET_REG32(env->fpuc); - case IDX_FP_REGS + 9: GET_REG32((env->fpus & ~0x3800) | - (env->fpstt & 0x7) << 11); - case IDX_FP_REGS + 10: GET_REG32(0); /* ftag */ - case IDX_FP_REGS + 11: GET_REG32(0); /* fiseg */ - case IDX_FP_REGS + 12: GET_REG32(0); /* fioff */ - case IDX_FP_REGS + 13: GET_REG32(0); /* foseg */ - case IDX_FP_REGS + 14: GET_REG32(0); /* fooff */ - case IDX_FP_REGS + 15: GET_REG32(0); /* fop */ - - case IDX_MXCSR_REG: GET_REG32(env->mxcsr); - } - } - return 0; -} - -static int cpu_x86_gdb_load_seg(CPUX86State *env, int sreg, uint8_t *mem_buf) -{ - uint16_t selector = ldl_p(mem_buf); - - if (selector != env->segs[sreg].selector) { -#if defined(CONFIG_USER_ONLY) - cpu_x86_load_seg(env, sreg, selector); -#else - unsigned int limit, flags; - target_ulong base; - - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { - base = selector << 4; - limit = 0xffff; - flags = 0; - } else { - if (!cpu_x86_get_descr_debug(env, selector, &base, &limit, &flags)) - return 4; - } - cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags); -#endif - } - return 4; -} - -static int cpu_gdb_write_register(CPUX86State *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - if (n < CPU_NB_REGS) { - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - env->regs[gpr_map[n]] = ldtul_p(mem_buf); - return sizeof(target_ulong); - } else if (n < CPU_NB_REGS32) { - n = gpr_map32[n]; - env->regs[n] &= ~0xffffffffUL; - env->regs[n] |= (uint32_t)ldl_p(mem_buf); - return 4; - } - } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { -#ifdef USE_X86LDOUBLE - /* FIXME: byteswap float values - after fixing fpregs layout. */ - memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10); -#endif - return 10; - } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { - n -= IDX_XMM_REGS; - if (n < CPU_NB_REGS32 || - (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { - env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf); - env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8); - return 16; - } - } else { - switch (n) { - case IDX_IP_REG: - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - env->eip = ldq_p(mem_buf); - return 8; - } else { - env->eip &= ~0xffffffffUL; - env->eip |= (uint32_t)ldl_p(mem_buf); - return 4; - } - case IDX_FLAGS_REG: - env->eflags = ldl_p(mem_buf); - return 4; - - case IDX_SEG_REGS: return cpu_x86_gdb_load_seg(env, R_CS, mem_buf); - case IDX_SEG_REGS + 1: return cpu_x86_gdb_load_seg(env, R_SS, mem_buf); - case IDX_SEG_REGS + 2: return cpu_x86_gdb_load_seg(env, R_DS, mem_buf); - case IDX_SEG_REGS + 3: return cpu_x86_gdb_load_seg(env, R_ES, mem_buf); - case IDX_SEG_REGS + 4: return cpu_x86_gdb_load_seg(env, R_FS, mem_buf); - case IDX_SEG_REGS + 5: return cpu_x86_gdb_load_seg(env, R_GS, mem_buf); - - case IDX_FP_REGS + 8: - env->fpuc = ldl_p(mem_buf); - return 4; - case IDX_FP_REGS + 9: - tmp = ldl_p(mem_buf); - env->fpstt = (tmp >> 11) & 7; - env->fpus = tmp & ~0x3800; - return 4; - case IDX_FP_REGS + 10: /* ftag */ return 4; - case IDX_FP_REGS + 11: /* fiseg */ return 4; - case IDX_FP_REGS + 12: /* fioff */ return 4; - case IDX_FP_REGS + 13: /* foseg */ return 4; - case IDX_FP_REGS + 14: /* fooff */ return 4; - case IDX_FP_REGS + 15: /* fop */ return 4; - - case IDX_MXCSR_REG: - env->mxcsr = ldl_p(mem_buf); - return 4; - } - } - /* Unrecognised register. */ - return 0; -} - -#elif defined (TARGET_PPC) - -/* Old gdb always expects FP registers. Newer (xml-aware) gdb only - expects whatever the target description contains. Due to a - historical mishap the FP registers appear in between core integer - regs and PC, MSR, CR, and so forth. We hack round this by giving the - FP regs zero size when talking to a newer gdb. */ -#define NUM_CORE_REGS 71 -#if defined (TARGET_PPC64) -#define GDB_CORE_XML "power64-core.xml" -#else -#define GDB_CORE_XML "power-core.xml" -#endif - -static int cpu_gdb_read_register(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - /* gprs */ - GET_REGL(env->gpr[n]); - } else if (n < 64) { - /* fprs */ - if (gdb_has_xml) - return 0; - stfq_p(mem_buf, env->fpr[n-32]); - return 8; - } else { - switch (n) { - case 64: GET_REGL(env->nip); - case 65: GET_REGL(env->msr); - case 66: - { - uint32_t cr = 0; - int i; - for (i = 0; i < 8; i++) - cr |= env->crf[i] << (32 - ((i + 1) * 4)); - GET_REG32(cr); - } - case 67: GET_REGL(env->lr); - case 68: GET_REGL(env->ctr); - case 69: GET_REGL(env->xer); - case 70: - { - if (gdb_has_xml) - return 0; - GET_REG32(env->fpscr); - } - } - } - return 0; -} - -static int cpu_gdb_write_register(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - /* gprs */ - env->gpr[n] = ldtul_p(mem_buf); - return sizeof(target_ulong); - } else if (n < 64) { - /* fprs */ - if (gdb_has_xml) - return 0; - env->fpr[n-32] = ldfq_p(mem_buf); - return 8; - } else { - switch (n) { - case 64: - env->nip = ldtul_p(mem_buf); - return sizeof(target_ulong); - case 65: - ppc_store_msr(env, ldtul_p(mem_buf)); - return sizeof(target_ulong); - case 66: - { - uint32_t cr = ldl_p(mem_buf); - int i; - for (i = 0; i < 8; i++) - env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF; - return 4; - } - case 67: - env->lr = ldtul_p(mem_buf); - return sizeof(target_ulong); - case 68: - env->ctr = ldtul_p(mem_buf); - return sizeof(target_ulong); - case 69: - env->xer = ldtul_p(mem_buf); - return sizeof(target_ulong); - case 70: - /* fpscr */ - if (gdb_has_xml) - return 0; - store_fpscr(env, ldtul_p(mem_buf), 0xffffffff); - return sizeof(target_ulong); - } - } - return 0; -} - -#elif defined (TARGET_SPARC) - -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) -#define NUM_CORE_REGS 86 -#else -#define NUM_CORE_REGS 72 -#endif - -#ifdef TARGET_ABI32 -#define GET_REGA(val) GET_REG32(val) -#else -#define GET_REGA(val) GET_REGL(val) -#endif - -static int cpu_gdb_read_register(CPUSPARCState *env, uint8_t *mem_buf, int n) -{ - if (n < 8) { - /* g0..g7 */ - GET_REGA(env->gregs[n]); - } - if (n < 32) { - /* register window */ - GET_REGA(env->regwptr[n - 8]); - } -#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64) - if (n < 64) { - /* fprs */ - if (n & 1) { - GET_REG32(env->fpr[(n - 32) / 2].l.lower); - } else { - GET_REG32(env->fpr[(n - 32) / 2].l.upper); - } - } - /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ - switch (n) { - case 64: GET_REGA(env->y); - case 65: GET_REGA(cpu_get_psr(env)); - case 66: GET_REGA(env->wim); - case 67: GET_REGA(env->tbr); - case 68: GET_REGA(env->pc); - case 69: GET_REGA(env->npc); - case 70: GET_REGA(env->fsr); - case 71: GET_REGA(0); /* csr */ - default: GET_REGA(0); - } -#else - if (n < 64) { - /* f0-f31 */ - if (n & 1) { - GET_REG32(env->fpr[(n - 32) / 2].l.lower); - } else { - GET_REG32(env->fpr[(n - 32) / 2].l.upper); - } - } - if (n < 80) { - /* f32-f62 (double width, even numbers only) */ - GET_REG64(env->fpr[(n - 32) / 2].ll); - } - switch (n) { - case 80: GET_REGL(env->pc); - case 81: GET_REGL(env->npc); - case 82: GET_REGL((cpu_get_ccr(env) << 32) | - ((env->asi & 0xff) << 24) | - ((env->pstate & 0xfff) << 8) | - cpu_get_cwp64(env)); - case 83: GET_REGL(env->fsr); - case 84: GET_REGL(env->fprs); - case 85: GET_REGL(env->y); - } -#endif - return 0; -} - -static int cpu_gdb_write_register(CPUSPARCState *env, uint8_t *mem_buf, int n) -{ -#if defined(TARGET_ABI32) - abi_ulong tmp; - - tmp = ldl_p(mem_buf); -#else - target_ulong tmp; - - tmp = ldtul_p(mem_buf); -#endif - - if (n < 8) { - /* g0..g7 */ - env->gregs[n] = tmp; - } else if (n < 32) { - /* register window */ - env->regwptr[n - 8] = tmp; - } -#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64) - else if (n < 64) { - /* fprs */ - /* f0-f31 */ - if (n & 1) { - env->fpr[(n - 32) / 2].l.lower = tmp; - } else { - env->fpr[(n - 32) / 2].l.upper = tmp; - } - } else { - /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ - switch (n) { - case 64: env->y = tmp; break; - case 65: cpu_put_psr(env, tmp); break; - case 66: env->wim = tmp; break; - case 67: env->tbr = tmp; break; - case 68: env->pc = tmp; break; - case 69: env->npc = tmp; break; - case 70: env->fsr = tmp; break; - default: return 0; - } - } - return 4; -#else - else if (n < 64) { - /* f0-f31 */ - tmp = ldl_p(mem_buf); - if (n & 1) { - env->fpr[(n - 32) / 2].l.lower = tmp; - } else { - env->fpr[(n - 32) / 2].l.upper = tmp; - } - return 4; - } else if (n < 80) { - /* f32-f62 (double width, even numbers only) */ - env->fpr[(n - 32) / 2].ll = tmp; - } else { - switch (n) { - case 80: env->pc = tmp; break; - case 81: env->npc = tmp; break; - case 82: - cpu_put_ccr(env, tmp >> 32); - env->asi = (tmp >> 24) & 0xff; - env->pstate = (tmp >> 8) & 0xfff; - cpu_put_cwp64(env, tmp & 0xff); - break; - case 83: env->fsr = tmp; break; - case 84: env->fprs = tmp; break; - case 85: env->y = tmp; break; - default: return 0; - } - } - return 8; -#endif -} -#elif defined (TARGET_ARM) - -/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect - whatever the target description contains. Due to a historical mishap - the FPA registers appear in between core integer regs and the CPSR. - We hack round this by giving the FPA regs zero size when talking to a - newer gdb. */ -#define NUM_CORE_REGS 26 -#define GDB_CORE_XML "arm-core.xml" - -static int cpu_gdb_read_register(CPUARMState *env, uint8_t *mem_buf, int n) -{ - if (n < 16) { - /* Core integer register. */ - GET_REG32(env->regs[n]); - } - if (n < 24) { - /* FPA registers. */ - if (gdb_has_xml) - return 0; - memset(mem_buf, 0, 12); - return 12; - } - switch (n) { - case 24: - /* FPA status register. */ - if (gdb_has_xml) - return 0; - GET_REG32(0); - case 25: - /* CPSR */ - GET_REG32(cpsr_read(env)); - } - /* Unknown register. */ - return 0; -} - -static int cpu_gdb_write_register(CPUARMState *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - tmp = ldl_p(mem_buf); - - /* Mask out low bit of PC to workaround gdb bugs. This will probably - cause problems if we ever implement the Jazelle DBX extensions. */ - if (n == 15) - tmp &= ~1; - - if (n < 16) { - /* Core integer register. */ - env->regs[n] = tmp; - return 4; - } - if (n < 24) { /* 16-23 */ - /* FPA registers (ignored). */ - if (gdb_has_xml) - return 0; - return 12; - } - switch (n) { - case 24: - /* FPA status register (ignored). */ - if (gdb_has_xml) - return 0; - return 4; - case 25: - /* CPSR */ - cpsr_write (env, tmp, 0xffffffff); - return 4; - } - /* Unknown register. */ - return 0; -} - -#elif defined (TARGET_M68K) - -#define NUM_CORE_REGS 18 - -#define GDB_CORE_XML "cf-core.xml" - -static int cpu_gdb_read_register(CPUM68KState *env, uint8_t *mem_buf, int n) -{ - if (n < 8) { - /* D0-D7 */ - GET_REG32(env->dregs[n]); - } else if (n < 16) { - /* A0-A7 */ - GET_REG32(env->aregs[n - 8]); - } else { - switch (n) { - case 16: GET_REG32(env->sr); - case 17: GET_REG32(env->pc); - } - } - /* FP registers not included here because they vary between - ColdFire and m68k. Use XML bits for these. */ - return 0; -} - -static int cpu_gdb_write_register(CPUM68KState *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - tmp = ldl_p(mem_buf); - - if (n < 8) { - /* D0-D7 */ - env->dregs[n] = tmp; - } else if (n < 16) { - /* A0-A7 */ - env->aregs[n - 8] = tmp; - } else { - switch (n) { - case 16: env->sr = tmp; break; - case 17: env->pc = tmp; break; - default: return 0; - } - } - return 4; -} -#elif defined (TARGET_MIPS) - -#define NUM_CORE_REGS 73 - -static int cpu_gdb_read_register(CPUMIPSState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - GET_REGL(env->active_tc.gpr[n]); - } - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - if (n >= 38 && n < 70) { - if (env->CP0_Status & (1 << CP0St_FR)) - GET_REGL(env->active_fpu.fpr[n - 38].d); - else - GET_REGL(env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]); - } - switch (n) { - case 70: GET_REGL((int32_t)env->active_fpu.fcr31); - case 71: GET_REGL((int32_t)env->active_fpu.fcr0); - } - } - switch (n) { - case 32: GET_REGL((int32_t)env->CP0_Status); - case 33: GET_REGL(env->active_tc.LO[0]); - case 34: GET_REGL(env->active_tc.HI[0]); - case 35: GET_REGL(env->CP0_BadVAddr); - case 36: GET_REGL((int32_t)env->CP0_Cause); - case 37: GET_REGL(env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16)); - case 72: GET_REGL(0); /* fp */ - case 89: GET_REGL((int32_t)env->CP0_PRid); - } - if (n >= 73 && n <= 88) { - /* 16 embedded regs. */ - GET_REGL(0); - } - - return 0; -} - -/* convert MIPS rounding mode in FCR31 to IEEE library */ -static unsigned int ieee_rm[] = - { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down - }; -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) - -static int cpu_gdb_write_register(CPUMIPSState *env, uint8_t *mem_buf, int n) -{ - target_ulong tmp; - - tmp = ldtul_p(mem_buf); - - if (n < 32) { - env->active_tc.gpr[n] = tmp; - return sizeof(target_ulong); - } - if (env->CP0_Config1 & (1 << CP0C1_FP) - && n >= 38 && n < 73) { - if (n < 70) { - if (env->CP0_Status & (1 << CP0St_FR)) - env->active_fpu.fpr[n - 38].d = tmp; - else - env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; - } - switch (n) { - case 70: - env->active_fpu.fcr31 = tmp & 0xFF83FFFF; - /* set rounding mode */ - RESTORE_ROUNDING_MODE; - break; - case 71: env->active_fpu.fcr0 = tmp; break; - } - return sizeof(target_ulong); - } - switch (n) { - case 32: env->CP0_Status = tmp; break; - case 33: env->active_tc.LO[0] = tmp; break; - case 34: env->active_tc.HI[0] = tmp; break; - case 35: env->CP0_BadVAddr = tmp; break; - case 36: env->CP0_Cause = tmp; break; - case 37: - env->active_tc.PC = tmp & ~(target_ulong)1; - if (tmp & 1) { - env->hflags |= MIPS_HFLAG_M16; - } else { - env->hflags &= ~(MIPS_HFLAG_M16); - } - break; - case 72: /* fp, ignored */ break; - default: - if (n > 89) - return 0; - /* Other registers are readonly. Ignore writes. */ - break; - } - - return sizeof(target_ulong); -} -#elif defined(TARGET_OPENRISC) - -#define NUM_CORE_REGS (32 + 3) - -static int cpu_gdb_read_register(CPUOpenRISCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - GET_REG32(env->gpr[n]); - } else { - switch (n) { - case 32: /* PPC */ - GET_REG32(env->ppc); - break; - - case 33: /* NPC */ - GET_REG32(env->npc); - break; - - case 34: /* SR */ - GET_REG32(env->sr); - break; - - default: - break; - } - } - return 0; -} - -static int cpu_gdb_write_register(CPUOpenRISCState *env, - uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - if (n > NUM_CORE_REGS) { - return 0; - } - - tmp = ldl_p(mem_buf); - - if (n < 32) { - env->gpr[n] = tmp; - } else { - switch (n) { - case 32: /* PPC */ - env->ppc = tmp; - break; - - case 33: /* NPC */ - env->npc = tmp; - break; - - case 34: /* SR */ - env->sr = tmp; - break; - - default: - break; - } - } - return 4; -} -#elif defined (TARGET_SH4) - -/* Hint: Use "set architecture sh4" in GDB to see fpu registers */ -/* FIXME: We should use XML for this. */ - -#define NUM_CORE_REGS 59 - -static int cpu_gdb_read_register(CPUSH4State *env, uint8_t *mem_buf, int n) -{ - switch (n) { - case 0 ... 7: - if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { - GET_REGL(env->gregs[n + 16]); - } else { - GET_REGL(env->gregs[n]); - } - case 8 ... 15: - GET_REGL(env->gregs[n]); - case 16: - GET_REGL(env->pc); - case 17: - GET_REGL(env->pr); - case 18: - GET_REGL(env->gbr); - case 19: - GET_REGL(env->vbr); - case 20: - GET_REGL(env->mach); - case 21: - GET_REGL(env->macl); - case 22: - GET_REGL(env->sr); - case 23: - GET_REGL(env->fpul); - case 24: - GET_REGL(env->fpscr); - case 25 ... 40: - if (env->fpscr & FPSCR_FR) { - stfl_p(mem_buf, env->fregs[n - 9]); - } else { - stfl_p(mem_buf, env->fregs[n - 25]); - } - return 4; - case 41: - GET_REGL(env->ssr); - case 42: - GET_REGL(env->spc); - case 43 ... 50: - GET_REGL(env->gregs[n - 43]); - case 51 ... 58: - GET_REGL(env->gregs[n - (51 - 16)]); - } - - return 0; -} - -static int cpu_gdb_write_register(CPUSH4State *env, uint8_t *mem_buf, int n) -{ - switch (n) { - case 0 ... 7: - if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { - env->gregs[n + 16] = ldl_p(mem_buf); - } else { - env->gregs[n] = ldl_p(mem_buf); - } - break; - case 8 ... 15: - env->gregs[n] = ldl_p(mem_buf); - break; - case 16: - env->pc = ldl_p(mem_buf); - break; - case 17: - env->pr = ldl_p(mem_buf); - break; - case 18: - env->gbr = ldl_p(mem_buf); - break; - case 19: - env->vbr = ldl_p(mem_buf); - break; - case 20: - env->mach = ldl_p(mem_buf); - break; - case 21: - env->macl = ldl_p(mem_buf); - break; - case 22: - env->sr = ldl_p(mem_buf); - break; - case 23: - env->fpul = ldl_p(mem_buf); - break; - case 24: - env->fpscr = ldl_p(mem_buf); - break; - case 25 ... 40: - if (env->fpscr & FPSCR_FR) { - env->fregs[n - 9] = ldfl_p(mem_buf); - } else { - env->fregs[n - 25] = ldfl_p(mem_buf); - } - break; - case 41: - env->ssr = ldl_p(mem_buf); - break; - case 42: - env->spc = ldl_p(mem_buf); - break; - case 43 ... 50: - env->gregs[n - 43] = ldl_p(mem_buf); - break; - case 51 ... 58: - env->gregs[n - (51 - 16)] = ldl_p(mem_buf); - break; - default: return 0; - } - - return 4; -} -#elif defined (TARGET_MICROBLAZE) - -#define NUM_CORE_REGS (32 + 5) - -static int cpu_gdb_read_register(CPUMBState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - GET_REG32(env->regs[n]); - } else { - GET_REG32(env->sregs[n - 32]); - } - return 0; -} - -static int cpu_gdb_write_register(CPUMBState *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - if (n > NUM_CORE_REGS) - return 0; - - tmp = ldl_p(mem_buf); - - if (n < 32) { - env->regs[n] = tmp; - } else { - env->sregs[n - 32] = tmp; - } - return 4; -} -#elif defined (TARGET_CRIS) - -#define NUM_CORE_REGS 49 - -static int -read_register_crisv10(CPUCRISState *env, uint8_t *mem_buf, int n) -{ - if (n < 15) { - GET_REG32(env->regs[n]); - } - - if (n == 15) { - GET_REG32(env->pc); - } - - if (n < 32) { - switch (n) { - case 16: - GET_REG8(env->pregs[n - 16]); - break; - case 17: - GET_REG8(env->pregs[n - 16]); - break; - case 20: - case 21: - GET_REG16(env->pregs[n - 16]); - break; - default: - if (n >= 23) { - GET_REG32(env->pregs[n - 16]); - } - break; - } - } - return 0; -} - -static int cpu_gdb_read_register(CPUCRISState *env, uint8_t *mem_buf, int n) -{ - uint8_t srs; - - if (env->pregs[PR_VR] < 32) - return read_register_crisv10(env, mem_buf, n); - - srs = env->pregs[PR_SRS]; - if (n < 16) { - GET_REG32(env->regs[n]); - } - - if (n >= 21 && n < 32) { - GET_REG32(env->pregs[n - 16]); - } - if (n >= 33 && n < 49) { - GET_REG32(env->sregs[srs][n - 33]); - } - switch (n) { - case 16: GET_REG8(env->pregs[0]); - case 17: GET_REG8(env->pregs[1]); - case 18: GET_REG32(env->pregs[2]); - case 19: GET_REG8(srs); - case 20: GET_REG16(env->pregs[4]); - case 32: GET_REG32(env->pc); - } - - return 0; -} - -static int cpu_gdb_write_register(CPUCRISState *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - if (n > 49) - return 0; - - tmp = ldl_p(mem_buf); - - if (n < 16) { - env->regs[n] = tmp; - } - - if (n >= 21 && n < 32) { - env->pregs[n - 16] = tmp; - } - - /* FIXME: Should support function regs be writable? */ - switch (n) { - case 16: return 1; - case 17: return 1; - case 18: env->pregs[PR_PID] = tmp; break; - case 19: return 1; - case 20: return 2; - case 32: env->pc = tmp; break; - } - - return 4; -} -#elif defined (TARGET_ALPHA) - -#define NUM_CORE_REGS 67 - -static int cpu_gdb_read_register(CPUAlphaState *env, uint8_t *mem_buf, int n) -{ - uint64_t val; - CPU_DoubleU d; - - switch (n) { - case 0 ... 30: - val = env->ir[n]; - break; - case 32 ... 62: - d.d = env->fir[n - 32]; - val = d.ll; - break; - case 63: - val = cpu_alpha_load_fpcr(env); - break; - case 64: - val = env->pc; - break; - case 66: - val = env->unique; - break; - case 31: - case 65: - /* 31 really is the zero register; 65 is unassigned in the - gdb protocol, but is still required to occupy 8 bytes. */ - val = 0; - break; - default: - return 0; - } - GET_REGL(val); -} - -static int cpu_gdb_write_register(CPUAlphaState *env, uint8_t *mem_buf, int n) -{ - target_ulong tmp = ldtul_p(mem_buf); - CPU_DoubleU d; - - switch (n) { - case 0 ... 30: - env->ir[n] = tmp; - break; - case 32 ... 62: - d.ll = tmp; - env->fir[n - 32] = d.d; - break; - case 63: - cpu_alpha_store_fpcr(env, tmp); - break; - case 64: - env->pc = tmp; - break; - case 66: - env->unique = tmp; - break; - case 31: - case 65: - /* 31 really is the zero register; 65 is unassigned in the - gdb protocol, but is still required to occupy 8 bytes. */ - break; - default: - return 0; - } - return 8; -} -#elif defined (TARGET_S390X) - -#define NUM_CORE_REGS S390_NUM_REGS - -static int cpu_gdb_read_register(CPUS390XState *env, uint8_t *mem_buf, int n) -{ - uint64_t val; - int cc_op; - - switch (n) { - case S390_PSWM_REGNUM: - cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); - val = deposit64(env->psw.mask, 44, 2, cc_op); - GET_REGL(val); - break; - case S390_PSWA_REGNUM: - GET_REGL(env->psw.addr); - break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - GET_REGL(env->regs[n-S390_R0_REGNUM]); - break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - GET_REG32(env->aregs[n-S390_A0_REGNUM]); - break; - case S390_FPC_REGNUM: - GET_REG32(env->fpc); - break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - GET_REG64(env->fregs[n-S390_F0_REGNUM].ll); - break; - } - - return 0; -} - -static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n) -{ - target_ulong tmpl; - uint32_t tmp32; - int r = 8; - tmpl = ldtul_p(mem_buf); - tmp32 = ldl_p(mem_buf); - - switch (n) { - case S390_PSWM_REGNUM: - env->psw.mask = tmpl; - env->cc_op = extract64(tmpl, 44, 2); - break; - case S390_PSWA_REGNUM: - env->psw.addr = tmpl; - break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - env->regs[n-S390_R0_REGNUM] = tmpl; - break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - env->aregs[n-S390_A0_REGNUM] = tmp32; - r = 4; - break; - case S390_FPC_REGNUM: - env->fpc = tmp32; - r = 4; - break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - env->fregs[n-S390_F0_REGNUM].ll = tmpl; - break; - default: - return 0; - } - return r; -} -#elif defined (TARGET_LM32) - -#include "hw/lm32/lm32_pic.h" -#define NUM_CORE_REGS (32 + 7) - -static int cpu_gdb_read_register(CPULM32State *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - GET_REG32(env->regs[n]); - } else { - switch (n) { - case 32: - GET_REG32(env->pc); - break; - /* FIXME: put in right exception ID */ - case 33: - GET_REG32(0); - break; - case 34: - GET_REG32(env->eba); - break; - case 35: - GET_REG32(env->deba); - break; - case 36: - GET_REG32(env->ie); - break; - case 37: - GET_REG32(lm32_pic_get_im(env->pic_state)); - break; - case 38: - GET_REG32(lm32_pic_get_ip(env->pic_state)); - break; - } - } - return 0; -} - -static int cpu_gdb_write_register(CPULM32State *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - - if (n > NUM_CORE_REGS) { - return 0; - } - - tmp = ldl_p(mem_buf); - - if (n < 32) { - env->regs[n] = tmp; - } else { - switch (n) { - case 32: - env->pc = tmp; - break; - case 34: - env->eba = tmp; - break; - case 35: - env->deba = tmp; - break; - case 36: - env->ie = tmp; - break; - case 37: - lm32_pic_set_im(env->pic_state, tmp); - break; - case 38: - lm32_pic_set_ip(env->pic_state, tmp); - break; - } - } - return 4; -} -#elif defined(TARGET_XTENSA) - -/* Use num_core_regs to see only non-privileged registers in an unmodified gdb. - * Use num_regs to see all registers. gdb modification is required for that: - * reset bit 0 in the 'flags' field of the registers definitions in the - * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. - */ -#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs) -#define num_g_regs NUM_CORE_REGS - -static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n) -{ - const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; - - if (n < 0 || n >= env->config->gdb_regmap.num_regs) { - return 0; - } - - switch (reg->type) { - case 9: /*pc*/ - GET_REG32(env->pc); - break; - - case 1: /*ar*/ - xtensa_sync_phys_from_window(env); - GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]); - break; - - case 2: /*SR*/ - GET_REG32(env->sregs[reg->targno & 0xff]); - break; - - case 3: /*UR*/ - GET_REG32(env->uregs[reg->targno & 0xff]); - break; - - case 4: /*f*/ - GET_REG32(float32_val(env->fregs[reg->targno & 0x0f])); - break; - - case 8: /*a*/ - GET_REG32(env->regs[reg->targno & 0x0f]); - break; - - default: - qemu_log("%s from reg %d of unsupported type %d\n", - __func__, n, reg->type); - return 0; - } -} - -static int cpu_gdb_write_register(CPUXtensaState *env, uint8_t *mem_buf, int n) -{ - uint32_t tmp; - const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; - - if (n < 0 || n >= env->config->gdb_regmap.num_regs) { - return 0; - } - - tmp = ldl_p(mem_buf); - - switch (reg->type) { - case 9: /*pc*/ - env->pc = tmp; - break; - - case 1: /*ar*/ - env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp; - xtensa_sync_window_from_phys(env); - break; - - case 2: /*SR*/ - env->sregs[reg->targno & 0xff] = tmp; - break; - - case 3: /*UR*/ - env->uregs[reg->targno & 0xff] = tmp; - break; - - case 4: /*f*/ - env->fregs[reg->targno & 0x0f] = make_float32(tmp); - break; - - case 8: /*a*/ - env->regs[reg->targno & 0x0f] = tmp; - break; - - default: - qemu_log("%s to reg %d of unsupported type %d\n", - __func__, n, reg->type); - return 0; - } - - return 4; -} -#else - -#define NUM_CORE_REGS 0 - -static int cpu_gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int n) -{ - return 0; -} - -static int cpu_gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int n) -{ - return 0; -} - -#endif - -#if !defined(TARGET_XTENSA) -static int num_g_regs = NUM_CORE_REGS; -#endif - -#ifdef GDB_CORE_XML /* Encode data using the encoding for 'x' packets. */ static int memtox(char *buf, const char *mem, int len) { @@ -1823,7 +506,8 @@ static int memtox(char *buf, const char *mem, int len) return p - buf; } -static const char *get_feature_xml(const char *p, const char **newp) +static const char *get_feature_xml(const char *p, const char **newp, + CPUClass *cc) { size_t len; int i; @@ -1847,7 +531,7 @@ static const char *get_feature_xml(const char *p, const char **newp) "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">" "<target>" "<xi:include href=\"%s\"/>", - GDB_CORE_XML); + cc->gdb_core_xml_file); for (r = cpu->gdb_regs; r; r = r->next) { pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\""); @@ -1865,15 +549,16 @@ static const char *get_feature_xml(const char *p, const char **newp) } return name ? xml_builtin[i][1] : NULL; } -#endif static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg) { + CPUClass *cc = CPU_GET_CLASS(cpu); CPUArchState *env = cpu->env_ptr; GDBRegisterState *r; - if (reg < NUM_CORE_REGS) - return cpu_gdb_read_register(env, mem_buf, reg); + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_read_register(cpu, mem_buf, reg); + } for (r = cpu->gdb_regs; r; r = r->next) { if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { @@ -1885,11 +570,13 @@ static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg) static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) { + CPUClass *cc = CPU_GET_CLASS(cpu); CPUArchState *env = cpu->env_ptr; GDBRegisterState *r; - if (reg < NUM_CORE_REGS) - return cpu_gdb_write_register(env, mem_buf, reg); + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_write_register(cpu, mem_buf, reg); + } for (r = cpu->gdb_regs; r; r = r->next) { if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { @@ -1899,7 +586,6 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) return 0; } -#if !defined(TARGET_XTENSA) /* Register a supplemental set of CPU registers. If g_pos is nonzero it specifies the first register number and these registers are included in a standard "g" packet. Direction is relative to gdb, i.e. get_reg is @@ -1912,7 +598,6 @@ void gdb_register_coprocessor(CPUState *cpu, { GDBRegisterState *s; GDBRegisterState **p; - static int last_reg = NUM_CORE_REGS; p = &cpu->gdb_regs; while (*p) { @@ -1923,25 +608,24 @@ void gdb_register_coprocessor(CPUState *cpu, } s = g_new0(GDBRegisterState, 1); - s->base_reg = last_reg; + s->base_reg = cpu->gdb_num_regs; s->num_regs = num_regs; s->get_reg = get_reg; s->set_reg = set_reg; s->xml = xml; /* Add to end of list. */ - last_reg += num_regs; + cpu->gdb_num_regs += num_regs; *p = s; if (g_pos) { if (g_pos != s->base_reg) { fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n" "Expected %d got %d\n", xml, g_pos, s->base_reg); } else { - num_g_regs = last_reg; + cpu->gdb_num_g_regs = cpu->gdb_num_regs; } } } -#endif #ifndef CONFIG_USER_ONLY static const int xlat_gdb_type[] = { @@ -2071,10 +755,8 @@ static CPUState *find_cpu(uint32_t thread_id) static int gdb_handle_packet(GDBState *s, const char *line_buf) { -#ifdef TARGET_XTENSA - CPUArchState *env; -#endif CPUState *cpu; + CPUClass *cc; const char *p; uint32_t thread; int ch, reg_size, type, res; @@ -2221,11 +903,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; case 'g': cpu_synchronize_state(s->g_cpu); -#ifdef TARGET_XTENSA - env = s->g_cpu->env_ptr; -#endif len = 0; - for (addr = 0; addr < num_g_regs; addr++) { + for (addr = 0; addr < s->g_cpu->gdb_num_g_regs; addr++) { reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr); len += reg_size; } @@ -2234,13 +913,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; case 'G': cpu_synchronize_state(s->g_cpu); -#ifdef TARGET_XTENSA - env = s->g_cpu->env_ptr; -#endif registers = mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); - for (addr = 0; addr < num_g_regs && len > 0; addr++) { + for (addr = 0; addr < s->g_cpu->gdb_num_g_regs && len > 0; addr++) { reg_size = gdb_write_register(s->g_cpu, registers, addr); len -= reg_size; registers += reg_size; @@ -2443,20 +1119,25 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) #endif /* !CONFIG_USER_ONLY */ if (strncmp(p, "Supported", 9) == 0) { snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH); -#ifdef GDB_CORE_XML - pstrcat(buf, sizeof(buf), ";qXfer:features:read+"); -#endif + cc = CPU_GET_CLASS(first_cpu); + if (cc->gdb_core_xml_file != NULL) { + pstrcat(buf, sizeof(buf), ";qXfer:features:read+"); + } put_packet(s, buf); break; } -#ifdef GDB_CORE_XML if (strncmp(p, "Xfer:features:read:", 19) == 0) { const char *xml; target_ulong total_len; - gdb_has_xml = 1; + cc = CPU_GET_CLASS(first_cpu); + if (cc->gdb_core_xml_file == NULL) { + goto unknown_command; + } + + gdb_has_xml = true; p += 19; - xml = get_feature_xml(p, &p); + xml = get_feature_xml(p, &p, cc); if (!xml) { snprintf(buf, sizeof(buf), "E00"); put_packet(s, buf); @@ -2488,7 +1169,6 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) put_packet_binary(s, buf, len + 1); break; } -#endif /* Unrecognised 'q' command. */ goto unknown_command; @@ -2863,7 +1543,7 @@ static void gdb_accept(void) s->c_cpu = first_cpu; s->g_cpu = first_cpu; s->fd = fd; - gdb_has_xml = 0; + gdb_has_xml = false; gdbserver_state = s; @@ -2949,7 +1629,7 @@ static void gdb_chr_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: vm_stop(RUN_STATE_PAUSED); - gdb_has_xml = 0; + gdb_has_xml = false; break; default: break; @@ -1195,13 +1195,13 @@ static void hmp_migrate_status_cb(void *opaque) monitor_flush(status->mon); } - qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock) + 1000); + timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); } else { if (status->is_block_migration) { monitor_printf(status->mon, "\n"); } monitor_resume(status->mon); - qemu_del_timer(status->timer); + timer_del(status->timer); g_free(status); } @@ -1235,9 +1235,9 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) status = g_malloc0(sizeof(*status)); status->mon = mon; status->is_block_migration = blk || inc; - status->timer = qemu_new_timer_ms(rt_clock, hmp_migrate_status_cb, + status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb, status); - qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock)); + timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); } } diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 35e2af47b2..f0ffbe8c0d 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -61,6 +61,8 @@ static int virtio_9p_device_init(VirtIODevice *vdev) s->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); + v9fs_path_init(&path); + fse = get_fsdev_fsentry(s->fsconf.fsdev_id); if (!fse) { @@ -111,7 +113,6 @@ static int virtio_9p_device_init(VirtIODevice *vdev) * call back to do that. Since we are in the init path, we don't * use co-routines here. */ - v9fs_path_init(&path); if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { fprintf(stderr, "error in converting name to path %s", strerror(errno)); @@ -149,6 +150,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_9p_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = virtio_9p_device_init; vdc->get_features = virtio_9p_get_features; vdc->get_config = virtio_9p_get_config; diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index 8ba2959dbb..5f44bb758b 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -1153,10 +1153,12 @@ static int proxy_init(FsContext *ctx) sock_id = atoi(ctx->fs_root); if (sock_id < 0) { fprintf(stderr, "socket descriptor not initialized\n"); + g_free(proxy); return -1; } } g_free(ctx->fs_root); + ctx->fs_root = NULL; proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; diff --git a/hw/acpi/core.c b/hw/acpi/core.c index b07fedac59..7467b88e27 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -433,9 +433,9 @@ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable) if (enable) { expire_time = muldiv64(ar->tmr.overflow_time, get_ticks_per_sec(), PM_TIMER_FREQUENCY); - qemu_mod_timer(ar->tmr.timer, expire_time); + timer_mod(ar->tmr.timer, expire_time); } else { - qemu_del_timer(ar->tmr.timer); + timer_del(ar->tmr.timer); } } @@ -481,7 +481,7 @@ void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, MemoryRegion *parent) { ar->tmr.update_sci = update_sci; - ar->tmr.timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, ar); + ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); memory_region_add_subregion(parent, 8, &ar->tmr.io); @@ -490,7 +490,7 @@ void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, void acpi_pm_tmr_reset(ACPIREGS *ar) { ar->tmr.overflow_time = 0; - qemu_del_timer(ar->tmr.timer); + timer_del(ar->tmr.timer); } /* ACPI PM1aCNT */ diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index c88569061c..613d98736a 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -263,7 +263,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) return ret; } - qemu_get_timer(f, s->ar.tmr.timer); + timer_get(f, s->ar.tmr.timer); qemu_get_sbe64s(f, &s->ar.tmr.overflow_time); qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts); diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index b7fb04406c..aac9a32e0c 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -26,9 +26,9 @@ typedef struct TyphoonCchip { } TyphoonCchip; typedef struct TyphoonWindow { - uint32_t base_addr; - uint32_t mask; - uint32_t translated_base_pfn; + uint64_t wba; + uint64_t wsm; + uint64_t tba; } TyphoonWindow; typedef struct TyphoonPchip { @@ -37,6 +37,10 @@ typedef struct TyphoonPchip { MemoryRegion reg_mem; MemoryRegion reg_io; MemoryRegion reg_conf; + + AddressSpace iommu_as; + MemoryRegion iommu; + uint64_t ctl; TyphoonWindow win[4]; } TyphoonPchip; @@ -209,53 +213,53 @@ static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) switch (addr) { case 0x0000: /* WSBA0: Window Space Base Address Register. */ - ret = s->pchip.win[0].base_addr; + ret = s->pchip.win[0].wba; break; case 0x0040: /* WSBA1 */ - ret = s->pchip.win[1].base_addr; + ret = s->pchip.win[1].wba; break; case 0x0080: /* WSBA2 */ - ret = s->pchip.win[2].base_addr; + ret = s->pchip.win[2].wba; break; case 0x00c0: /* WSBA3 */ - ret = s->pchip.win[3].base_addr; + ret = s->pchip.win[3].wba; break; case 0x0100: /* WSM0: Window Space Mask Register. */ - ret = s->pchip.win[0].mask; + ret = s->pchip.win[0].wsm; break; case 0x0140: /* WSM1 */ - ret = s->pchip.win[1].mask; + ret = s->pchip.win[1].wsm; break; case 0x0180: /* WSM2 */ - ret = s->pchip.win[2].mask; + ret = s->pchip.win[2].wsm; break; case 0x01c0: /* WSM3 */ - ret = s->pchip.win[3].mask; + ret = s->pchip.win[3].wsm; break; case 0x0200: /* TBA0: Translated Base Address Register. */ - ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10; + ret = s->pchip.win[0].tba; break; case 0x0240: /* TBA1 */ - ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10; + ret = s->pchip.win[1].tba; break; case 0x0280: /* TBA2 */ - ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10; + ret = s->pchip.win[2].tba; break; case 0x02c0: /* TBA3 */ - ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10; + ret = s->pchip.win[3].tba; break; case 0x0300: @@ -458,53 +462,53 @@ static void pchip_write(void *opaque, hwaddr addr, switch (addr) { case 0x0000: /* WSBA0: Window Space Base Address Register. */ - s->pchip.win[0].base_addr = val; + s->pchip.win[0].wba = val & 0xfff00003u; break; case 0x0040: /* WSBA1 */ - s->pchip.win[1].base_addr = val; + s->pchip.win[1].wba = val & 0xfff00003u; break; case 0x0080: /* WSBA2 */ - s->pchip.win[2].base_addr = val; + s->pchip.win[2].wba = val & 0xfff00003u; break; case 0x00c0: /* WSBA3 */ - s->pchip.win[3].base_addr = val; + s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2; break; case 0x0100: /* WSM0: Window Space Mask Register. */ - s->pchip.win[0].mask = val; + s->pchip.win[0].wsm = val & 0xfff00000u; break; case 0x0140: /* WSM1 */ - s->pchip.win[1].mask = val; + s->pchip.win[1].wsm = val & 0xfff00000u; break; case 0x0180: /* WSM2 */ - s->pchip.win[2].mask = val; + s->pchip.win[2].wsm = val & 0xfff00000u; break; case 0x01c0: /* WSM3 */ - s->pchip.win[3].mask = val; + s->pchip.win[3].wsm = val & 0xfff00000u; break; case 0x0200: /* TBA0: Translated Base Address Register. */ - s->pchip.win[0].translated_base_pfn = val >> 10; + s->pchip.win[0].tba = val & 0x7fffffc00ull; break; case 0x0240: /* TBA1 */ - s->pchip.win[1].translated_base_pfn = val >> 10; + s->pchip.win[1].tba = val & 0x7fffffc00ull; break; case 0x0280: /* TBA2 */ - s->pchip.win[2].translated_base_pfn = val >> 10; + s->pchip.win[2].tba = val & 0x7fffffc00ull; break; case 0x02c0: /* TBA3 */ - s->pchip.win[3].translated_base_pfn = val >> 10; + s->pchip.win[3].tba = val & 0x7fffffc00ull; break; case 0x0300: @@ -512,7 +516,6 @@ static void pchip_write(void *opaque, hwaddr addr, oldval = s->pchip.ctl; oldval &= ~0x00001cff0fc7ffull; /* RW fields */ oldval |= val & 0x00001cff0fc7ffull; - s->pchip.ctl = oldval; break; @@ -593,6 +596,140 @@ static const MemoryRegionOps pchip_ops = { }, }; +/* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry + using the given translated address and mask. */ +static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret) +{ + *ret = (IOMMUTLBEntry) { + .target_as = &address_space_memory, + .translated_addr = taddr, + .addr_mask = mask, + .perm = IOMMU_RW, + }; + return true; +} + +/* A subroutine of typhoon_translate_iommu that handles scatter-gather + translation, given the address of the PTE. */ +static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret) +{ + uint64_t pte = ldq_phys(pte_addr); + + /* Check valid bit. */ + if ((pte & 1) == 0) { + return false; + } + + return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret); +} + +/* A subroutine of typhoon_translate_iommu that handles one of the + four single-address-cycle translation windows. */ +static bool window_translate(TyphoonWindow *win, hwaddr addr, + IOMMUTLBEntry *ret) +{ + uint32_t wba = win->wba; + uint64_t wsm = win->wsm; + uint64_t tba = win->tba; + uint64_t wsm_ext = wsm | 0xfffff; + + /* Check for window disabled. */ + if ((wba & 1) == 0) { + return false; + } + + /* Check for window hit. */ + if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) { + return false; + } + + if (wba & 2) { + /* Scatter-gather translation. */ + hwaddr pte_addr; + + /* See table 10-6, Generating PTE address for PCI DMA Address. */ + pte_addr = tba & ~(wsm >> 10); + pte_addr |= (addr & (wsm | 0xfe000)) >> 10; + return pte_translate(pte_addr, ret); + } else { + /* Direct-mapped translation. */ + return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret); + } +} + +/* Handle PCI-to-system address translation. */ +/* TODO: A translation failure here ought to set PCI error codes on the + Pchip and generate a machine check interrupt. */ +static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr) +{ + TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu); + IOMMUTLBEntry ret; + int i; + + if (addr <= 0xffffffffu) { + /* Single-address cycle. */ + + /* Check for the Window Hole, inhibiting matching. */ + if ((pchip->ctl & 0x20) + && addr >= 0x80000 + && addr <= 0xfffff) { + goto failure; + } + + /* Check the first three windows. */ + for (i = 0; i < 3; ++i) { + if (window_translate(&pchip->win[i], addr, &ret)) { + goto success; + } + } + + /* Check the fourth window for DAC disable. */ + if ((pchip->win[3].wba & 0x80000000000ull) == 0 + && window_translate(&pchip->win[3], addr, &ret)) { + goto success; + } + } else { + /* Double-address cycle. */ + + if (addr >= 0x10000000000ull && addr < 0x20000000000ull) { + /* Check for the DMA monster window. */ + if (pchip->ctl & 0x40) { + /* See 10.1.4.4; in particular <39:35> is ignored. */ + make_iommu_tlbe(0, 0x007ffffffffull, &ret); + goto success; + } + } + + if (addr >= 0x80000000000 && addr <= 0xfffffffffff) { + /* Check the fourth window for DAC enable and window enable. */ + if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) { + uint64_t pte_addr; + + pte_addr = pchip->win[3].tba & 0x7ffc00000ull; + pte_addr |= (addr & 0xffffe000u) >> 10; + if (pte_translate(pte_addr, &ret)) { + goto success; + } + } + } + } + + failure: + ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE }; + success: + return ret; +} + +static const MemoryRegionIOMMUOps typhoon_iommu_ops = { + .translate = typhoon_translate_iommu, +}; + +static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) +{ + TyphoonState *s = opaque; + return &s->pchip.iommu_as; +} + static void typhoon_set_irq(void *opaque, int irq, int level) { TyphoonState *s = opaque; @@ -688,12 +825,15 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, s = TYPHOON_PCI_HOST_BRIDGE(dev); phb = PCI_HOST_BRIDGE(dev); + s->cchip.misc = 0x800000000ull; /* Revision: Typhoon. */ + s->pchip.win[3].wba = 2; /* Window 3 SG always enabled. */ + /* Remember the CPUs so that we can deliver interrupts to them. */ for (i = 0; i < 4; i++) { AlphaCPU *cpu = cpus[i]; s->cchip.cpu[i] = cpu; if (cpu != NULL) { - cpu->alarm_timer = qemu_new_timer_ns(vm_clock, + cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, typhoon_alarm_timer, (void *)((uintptr_t)s + i)); } @@ -746,6 +886,12 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, 0, 64, TYPE_PCI_BUS); phb->bus = b; + /* Host memory as seen from the PCI side, via the IOMMU. */ + memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops, + "iommu-typhoon", UINT64_MAX); + address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci"); + pci_setup_iommu(b, typhoon_pci_dma_iommu, s); + /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, b, "pci0-iack", 64*MB); diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 9e3a06fc18..3671b42738 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,6 +1,6 @@ obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o -obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o +obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 5b22e847a8..89a9015de7 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -114,15 +114,21 @@ static const MemoryRegionOps bitband_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +#define TYPE_BITBAND "ARM,bitband-memory" +#define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND) + typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t base; } BitBandState; static int bitband_init(SysBusDevice *dev) { - BitBandState *s = FROM_SYSBUS(BitBandState, dev); + BitBandState *s = BITBAND(dev); memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base, "bitband", 0x02000000); @@ -134,12 +140,12 @@ static void armv7m_bitband_init(void) { DeviceState *dev; - dev = qdev_create(NULL, "ARM,bitband-memory"); + dev = qdev_create(NULL, TYPE_BITBAND); qdev_prop_set_uint32(dev, "base", 0x20000000); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000); - dev = qdev_create(NULL, "ARM,bitband-memory"); + dev = qdev_create(NULL, TYPE_BITBAND); qdev_prop_set_uint32(dev, "base", 0x40000000); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000); @@ -167,7 +173,6 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, DeviceState *nvic; /* FIXME: make this local state. */ static qemu_irq pic[64]; - qemu_irq *cpu_pic; int image_size; uint64_t entry; uint64_t lowaddr; @@ -215,8 +220,8 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, nvic = qdev_create(NULL, "armv7m_nvic"); env->nvic = nvic; qdev_init_nofail(nvic); - cpu_pic = arm_pic_init_cpu(cpu); - sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); + sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); for (i = 0; i < 64; i++) { pic[i] = qdev_get_gpio_in(nvic, i); } @@ -270,7 +275,7 @@ static void bitband_class_init(ObjectClass *klass, void *data) } static const TypeInfo bitband_info = { - .name = "ARM,bitband-memory", + .name = TYPE_BITBAND, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BitBandState), .class_init = bitband_class_init, diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 216b9b77d9..4ebb9381b0 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -137,10 +137,8 @@ void exynos4210_write_secondary(ARMCPU *cpu, Exynos4210State *exynos4210_init(MemoryRegion *system_mem, unsigned long ram_size) { - qemu_irq cpu_irq[EXYNOS4210_NCPUS]; int i, n; Exynos4210State *s = g_new(Exynos4210State, 1); - qemu_irq *irqp; qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; unsigned long mem_size; DeviceState *dev; @@ -152,15 +150,6 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, fprintf(stderr, "Unable to find CPU %d definition\n", n); exit(1); } - - /* Create PIC controller for each processor instance */ - irqp = arm_pic_init_cpu(s->cpu[n]); - - /* - * Get GICs gpio_in cpu_irq to connect a combiner to them later. - * Use only IRQ for a while. - */ - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } /*** IRQs ***/ @@ -178,8 +167,9 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, } busdev = SYS_BUS_DEVICE(dev); - /* Connect IRQ Gate output to cpu_irq */ - sysbus_connect_irq(busdev, 0, cpu_irq[i]); + /* Connect IRQ Gate output to CPU's IRQ line */ + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ)); } /* Private memory region and Internal GIC */ diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index be264d3eb3..f733a6cba7 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -116,8 +116,15 @@ static const MemoryRegionOps hb_mem_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +#define TYPE_HIGHBANK_REGISTERS "highbank-regs" +#define HIGHBANK_REGISTERS(obj) \ + OBJECT_CHECK(HighbankRegsState, (obj), TYPE_HIGHBANK_REGISTERS) + typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion *iomem; uint32_t regs[NUM_REGS]; } HighbankRegsState; @@ -135,8 +142,7 @@ static VMStateDescription vmstate_highbank_regs = { static void highbank_regs_reset(DeviceState *dev) { - SysBusDevice *sys_dev = SYS_BUS_DEVICE(dev); - HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev); + HighbankRegsState *s = HIGHBANK_REGISTERS(dev); s->regs[0x40] = 0x05F20121; s->regs[0x41] = 0x2; @@ -146,7 +152,7 @@ static void highbank_regs_reset(DeviceState *dev) static int highbank_regs_init(SysBusDevice *dev) { - HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev); + HighbankRegsState *s = HIGHBANK_REGISTERS(dev); s->iomem = g_new(MemoryRegion, 1); memory_region_init_io(s->iomem, OBJECT(s), &hb_mem_ops, s->regs, @@ -168,7 +174,7 @@ static void highbank_regs_class_init(ObjectClass *klass, void *data) } static const TypeInfo highbank_regs_info = { - .name = "highbank-regs", + .name = TYPE_HIGHBANK_REGISTERS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HighbankRegsState), .class_init = highbank_regs_class_init, @@ -203,7 +209,6 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) const char *initrd_filename = args->initrd_filename; DeviceState *dev = NULL; SysBusDevice *busdev; - qemu_irq *irqp; qemu_irq pic[128]; int n; qemu_irq cpu_irq[4]; @@ -233,8 +238,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) /* This will become a QOM property eventually */ cpu->reset_cbar = GIC_BASE_ADDR; - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); } sysmem = get_system_memory(); diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 249a43025e..59c37262c3 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -15,8 +15,15 @@ #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_INTEGRATOR_CM "integrator_core" +#define INTEGRATOR_CM(obj) \ + OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM) + +typedef struct IntegratorCMState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t memsz; MemoryRegion flash; @@ -31,7 +38,7 @@ typedef struct { uint32_t int_level; uint32_t irq_enabled; uint32_t fiq_enabled; -} integratorcm_state; +} IntegratorCMState; static uint8_t integrator_spd[128] = { 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, @@ -41,7 +48,7 @@ static uint8_t integrator_spd[128] = { static uint64_t integratorcm_read(void *opaque, hwaddr offset, unsigned size) { - integratorcm_state *s = (integratorcm_state *)opaque; + IntegratorCMState *s = opaque; if (offset >= 0x100 && offset < 0x200) { /* CM_SPD */ if (offset >= 0x180) @@ -108,7 +115,7 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, } } -static void integratorcm_do_remap(integratorcm_state *s) +static void integratorcm_do_remap(IntegratorCMState *s) { /* Sync memory region state with CM_CTRL REMAP bit: * bit 0 => flash at address 0; bit 1 => RAM @@ -116,7 +123,7 @@ static void integratorcm_do_remap(integratorcm_state *s) memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4)); } -static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) +static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value) { if (value & 8) { qemu_system_reset_request(); @@ -133,7 +140,7 @@ static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) integratorcm_do_remap(s); } -static void integratorcm_update(integratorcm_state *s) +static void integratorcm_update(IntegratorCMState *s) { /* ??? The CPU irq/fiq is raised when either the core module or base PIC are active. */ @@ -144,7 +151,7 @@ static void integratorcm_update(integratorcm_state *s) static void integratorcm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - integratorcm_state *s = (integratorcm_state *)opaque; + IntegratorCMState *s = opaque; switch (offset >> 2) { case 2: /* CM_OSC */ if (s->cm_lock == 0xa05f) @@ -226,7 +233,7 @@ static const MemoryRegionOps integratorcm_ops = { static int integratorcm_init(SysBusDevice *dev) { - integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev); + IntegratorCMState *s = INTEGRATOR_CM(dev); s->cm_osc = 0x01000048; /* ??? What should the high bits of this value be? */ @@ -264,15 +271,21 @@ static int integratorcm_init(SysBusDevice *dev) /* Integrator/CP hardware emulation. */ /* Primary interrupt controller. */ -typedef struct icp_pic_state -{ - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t level; - uint32_t irq_enabled; - uint32_t fiq_enabled; - qemu_irq parent_irq; - qemu_irq parent_fiq; +#define TYPE_INTEGRATOR_PIC "integrator_pic" +#define INTEGRATOR_PIC(obj) \ + OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC) + +typedef struct icp_pic_state { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion iomem; + uint32_t level; + uint32_t irq_enabled; + uint32_t fiq_enabled; + qemu_irq parent_irq; + qemu_irq parent_fiq; } icp_pic_state; static void icp_pic_update(icp_pic_state *s) @@ -367,16 +380,17 @@ static const MemoryRegionOps icp_pic_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int icp_pic_init(SysBusDevice *dev) +static int icp_pic_init(SysBusDevice *sbd) { - icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev); + DeviceState *dev = DEVICE(sbd); + icp_pic_state *s = INTEGRATOR_PIC(dev); - qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32); - sysbus_init_irq(dev, &s->parent_irq); - sysbus_init_irq(dev, &s->parent_fiq); + qdev_init_gpio_in(dev, icp_pic_set_irq, 32); + sysbus_init_irq(sbd, &s->parent_irq); + sysbus_init_irq(sbd, &s->parent_fiq); memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s, "icp-pic", 0x00800000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -451,7 +465,6 @@ static void integratorcp_init(QEMUMachineInitArgs *args) MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); qemu_irq pic[32]; - qemu_irq *cpu_pic; DeviceState *dev; int i; @@ -474,19 +487,19 @@ static void integratorcp_init(QEMUMachineInitArgs *args) memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size); memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); - dev = qdev_create(NULL, "integrator_core"); + dev = qdev_create(NULL, TYPE_INTEGRATOR_CM); qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); qdev_init_nofail(dev); sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); - cpu_pic = arm_pic_init_cpu(cpu); - dev = sysbus_create_varargs("integrator_pic", 0x14000000, - cpu_pic[ARM_PIC_CPU_IRQ], - cpu_pic[ARM_PIC_CPU_FIQ], NULL); + dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000, + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), + NULL); for (i = 0; i < 32; i++) { pic[i] = qdev_get_gpio_in(dev, i); } - sysbus_create_simple("integrator_pic", 0xca000000, pic[26]); + sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]); sysbus_create_varargs("integrator_pit", 0x13000000, pic[5], pic[6], pic[7], NULL); sysbus_create_simple("pl031", 0x15000000, pic[8]); @@ -524,7 +537,7 @@ static void integratorcp_machine_init(void) machine_init(integratorcp_machine_init); static Property core_properties[] = { - DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0), + DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -538,9 +551,9 @@ static void core_class_init(ObjectClass *klass, void *data) } static const TypeInfo core_info = { - .name = "integrator_core", + .name = TYPE_INTEGRATOR_CM, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(integratorcm_state), + .instance_size = sizeof(IntegratorCMState), .class_init = core_class_init, }; @@ -552,7 +565,7 @@ static void icp_pic_class_init(ObjectClass *klass, void *data) } static const TypeInfo icp_pic_info = { - .name = "integrator_pic", + .name = TYPE_INTEGRATOR_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pic_state), .class_init = icp_pic_class_init, diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index bd6c05ce1b..a248bf0dc7 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -82,7 +82,6 @@ static void kzm_init(QEMUMachineInitArgs *args) MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - qemu_irq *cpu_pic; DeviceState *dev; DeviceState *ccm; @@ -108,11 +107,10 @@ static void kzm_init(QEMUMachineInitArgs *args) memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000); memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram); - cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("imx_avic", 0x68000000, - cpu_pic[ARM_PIC_CPU_IRQ], - cpu_pic[ARM_PIC_CPU_FIQ], NULL); - + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), + NULL); imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45)); imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32)); diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index b06d4426ee..4404b8dd03 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -146,8 +146,15 @@ typedef struct mv88w8618_rx_desc { uint32_t next; } mv88w8618_rx_desc; +#define TYPE_MV88W8618_ETH "mv88w8618_eth" +#define MV88W8618_ETH(obj) \ + OBJECT_CHECK(mv88w8618_eth_state, (obj), TYPE_MV88W8618_ETH) + typedef struct mv88w8618_eth_state { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; qemu_irq irq; uint32_t smir; @@ -382,16 +389,17 @@ static NetClientInfo net_mv88w8618_info = { .cleanup = eth_cleanup, }; -static int mv88w8618_eth_init(SysBusDevice *dev) +static int mv88w8618_eth_init(SysBusDevice *sbd) { - mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev); + DeviceState *dev = DEVICE(sbd); + mv88w8618_eth_state *s = MV88W8618_ETH(dev); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_eth_ops, s, "mv88w8618-eth", MP_ETH_SIZE); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -429,7 +437,7 @@ static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) } static const TypeInfo mv88w8618_eth_info = { - .name = "mv88w8618_eth", + .name = TYPE_MV88W8618_ETH, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_eth_state), .class_init = mv88w8618_eth_class_init, @@ -454,8 +462,15 @@ static const TypeInfo mv88w8618_eth_info = { #define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */ +#define TYPE_MUSICPAL_LCD "musicpal_lcd" +#define MUSICPAL_LCD(obj) \ + OBJECT_CHECK(musicpal_lcd_state, (obj), TYPE_MUSICPAL_LCD) + typedef struct musicpal_lcd_state { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t brightness; uint32_t mode; @@ -534,7 +549,7 @@ static void lcd_invalidate(void *opaque) { } -static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) +static void musicpal_lcd_gpio_brightness_in(void *opaque, int irq, int level) { musicpal_lcd_state *s = opaque; s->brightness &= ~(1 << irq); @@ -606,20 +621,21 @@ static const GraphicHwOps musicpal_gfx_ops = { .gfx_update = lcd_refresh, }; -static int musicpal_lcd_init(SysBusDevice *dev) +static int musicpal_lcd_init(SysBusDevice *sbd) { - musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); + DeviceState *dev = DEVICE(sbd); + musicpal_lcd_state *s = MUSICPAL_LCD(dev); s->brightness = 7; memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_lcd_ops, s, "musicpal-lcd", MP_LCD_SIZE); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); - s->con = graphic_console_init(DEVICE(dev), &musicpal_gfx_ops, s); + s->con = graphic_console_init(dev, &musicpal_gfx_ops, s); qemu_console_resize(s->con, 128*3, 64*3); - qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); + qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3); return 0; } @@ -650,7 +666,7 @@ static void musicpal_lcd_class_init(ObjectClass *klass, void *data) } static const TypeInfo musicpal_lcd_info = { - .name = "musicpal_lcd", + .name = TYPE_MUSICPAL_LCD, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_lcd_state), .class_init = musicpal_lcd_class_init, @@ -661,9 +677,15 @@ static const TypeInfo musicpal_lcd_info = { #define MP_PIC_ENABLE_SET 0x08 #define MP_PIC_ENABLE_CLR 0x0C -typedef struct mv88w8618_pic_state -{ - SysBusDevice busdev; +#define TYPE_MV88W8618_PIC "mv88w8618_pic" +#define MV88W8618_PIC(obj) \ + OBJECT_CHECK(mv88w8618_pic_state, (obj), TYPE_MV88W8618_PIC) + +typedef struct mv88w8618_pic_state { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t level; uint32_t enabled; @@ -721,8 +743,7 @@ static void mv88w8618_pic_write(void *opaque, hwaddr offset, static void mv88w8618_pic_reset(DeviceState *d) { - mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, - SYS_BUS_DEVICE(d)); + mv88w8618_pic_state *s = MV88W8618_PIC(d); s->level = 0; s->enabled = 0; @@ -736,9 +757,9 @@ static const MemoryRegionOps mv88w8618_pic_ops = { static int mv88w8618_pic_init(SysBusDevice *dev) { - mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev); + mv88w8618_pic_state *s = MV88W8618_PIC(dev); - qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32); + qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32); sysbus_init_irq(dev, &s->parent_irq); memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pic_ops, s, "musicpal-pic", MP_PIC_SIZE); @@ -769,7 +790,7 @@ static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) } static const TypeInfo mv88w8618_pic_info = { - .name = "mv88w8618_pic", + .name = TYPE_MV88W8618_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_pic_state), .class_init = mv88w8618_pic_class_init, @@ -795,8 +816,15 @@ typedef struct mv88w8618_timer_state { qemu_irq irq; } mv88w8618_timer_state; +#define TYPE_MV88W8618_PIT "mv88w8618_pit" +#define MV88W8618_PIT(obj) \ + OBJECT_CHECK(mv88w8618_pit_state, (obj), TYPE_MV88W8618_PIT) + typedef struct mv88w8618_pit_state { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; mv88w8618_timer_state timer[4]; } mv88w8618_pit_state; @@ -878,8 +906,7 @@ static void mv88w8618_pit_write(void *opaque, hwaddr offset, static void mv88w8618_pit_reset(DeviceState *d) { - mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, - SYS_BUS_DEVICE(d)); + mv88w8618_pit_state *s = MV88W8618_PIT(d); int i; for (i = 0; i < 4; i++) { @@ -896,7 +923,7 @@ static const MemoryRegionOps mv88w8618_pit_ops = { static int mv88w8618_pit_init(SysBusDevice *dev) { - mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev); + mv88w8618_pit_state *s = MV88W8618_PIT(dev); int i; /* Letting them all run at 1 MHz is likely just a pragmatic @@ -946,7 +973,7 @@ static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) } static const TypeInfo mv88w8618_pit_info = { - .name = "mv88w8618_pit", + .name = TYPE_MV88W8618_PIT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_pit_state), .class_init = mv88w8618_pit_class_init, @@ -955,8 +982,15 @@ static const TypeInfo mv88w8618_pit_info = { /* Flash config register offsets */ #define MP_FLASHCFG_CFGR0 0x04 +#define TYPE_MV88W8618_FLASHCFG "mv88w8618_flashcfg" +#define MV88W8618_FLASHCFG(obj) \ + OBJECT_CHECK(mv88w8618_flashcfg_state, (obj), TYPE_MV88W8618_FLASHCFG) + typedef struct mv88w8618_flashcfg_state { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t cfgr0; } mv88w8618_flashcfg_state; @@ -996,7 +1030,7 @@ static const MemoryRegionOps mv88w8618_flashcfg_ops = { static int mv88w8618_flashcfg_init(SysBusDevice *dev) { - mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev); + mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev); s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_flashcfg_ops, s, @@ -1026,7 +1060,7 @@ static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) } static const TypeInfo mv88w8618_flashcfg_info = { - .name = "mv88w8618_flashcfg", + .name = TYPE_MV88W8618_FLASHCFG, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_flashcfg_state), .class_init = mv88w8618_flashcfg_class_init, @@ -1149,8 +1183,15 @@ static int mv88w8618_wlan_init(SysBusDevice *dev) /* LCD brightness bits in GPIO_OE_HI */ #define MP_OE_LCD_BRIGHTNESS 0x0007 +#define TYPE_MUSICPAL_GPIO "musicpal_gpio" +#define MUSICPAL_GPIO(obj) \ + OBJECT_CHECK(musicpal_gpio_state, (obj), TYPE_MUSICPAL_GPIO) + typedef struct musicpal_gpio_state { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t lcd_brightness; uint32_t out_state; @@ -1310,8 +1351,7 @@ static const MemoryRegionOps musicpal_gpio_ops = { static void musicpal_gpio_reset(DeviceState *d) { - musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, - SYS_BUS_DEVICE(d)); + musicpal_gpio_state *s = MUSICPAL_GPIO(d); s->lcd_brightness = 0; s->out_state = 0; @@ -1321,19 +1361,20 @@ static void musicpal_gpio_reset(DeviceState *d) s->isr = 0; } -static int musicpal_gpio_init(SysBusDevice *dev) +static int musicpal_gpio_init(SysBusDevice *sbd) { - musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev); + DeviceState *dev = DEVICE(sbd); + musicpal_gpio_state *s = MUSICPAL_GPIO(dev); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_gpio_ops, s, "musicpal-gpio", MP_GPIO_SIZE); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); - qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); + qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out)); - qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32); + qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32); return 0; } @@ -1365,7 +1406,7 @@ static void musicpal_gpio_class_init(ObjectClass *klass, void *data) } static const TypeInfo musicpal_gpio_info = { - .name = "musicpal_gpio", + .name = TYPE_MUSICPAL_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_gpio_state), .class_init = musicpal_gpio_class_init, @@ -1395,8 +1436,15 @@ static const TypeInfo musicpal_gpio_info = { #define MP_KEY_BTN_VOLUME (1 << 6) #define MP_KEY_BTN_NAVIGATION (1 << 7) +#define TYPE_MUSICPAL_KEY "musicpal_key" +#define MUSICPAL_KEY(obj) \ + OBJECT_CHECK(musicpal_key_state, (obj), TYPE_MUSICPAL_KEY) + typedef struct musicpal_key_state { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t kbd_extended; uint32_t pressed_keys; @@ -1480,17 +1528,18 @@ static void musicpal_key_event(void *opaque, int keycode) s->kbd_extended = 0; } -static int musicpal_key_init(SysBusDevice *dev) +static int musicpal_key_init(SysBusDevice *sbd) { - musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev); + DeviceState *dev = DEVICE(sbd); + musicpal_key_state *s = MUSICPAL_KEY(dev); memory_region_init(&s->iomem, OBJECT(s), "dummy", 0); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); s->kbd_extended = 0; s->pressed_keys = 0; - qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); + qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out)); qemu_add_kbd_event_handler(musicpal_key_event, s); @@ -1519,7 +1568,7 @@ static void musicpal_key_class_init(ObjectClass *klass, void *data) } static const TypeInfo musicpal_key_info = { - .name = "musicpal_key", + .name = TYPE_MUSICPAL_KEY, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_key_state), .class_init = musicpal_key_class_init, @@ -1537,7 +1586,6 @@ static void musicpal_init(QEMUMachineInitArgs *args) const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; - qemu_irq *cpu_pic; qemu_irq pic[32]; DeviceState *dev; DeviceState *i2c_dev; @@ -1561,7 +1609,6 @@ static void musicpal_init(QEMUMachineInitArgs *args) fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - cpu_pic = arm_pic_init_cpu(cpu); /* For now we use a fixed - the original - RAM size */ memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE); @@ -1572,12 +1619,12 @@ static void musicpal_init(QEMUMachineInitArgs *args) vmstate_register_ram_global(sram); memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram); - dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE, - cpu_pic[ARM_PIC_CPU_IRQ]); + dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE, + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); for (i = 0; i < 32; i++) { pic[i] = qdev_get_gpio_in(dev, i); } - sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ], + sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, pic[MP_TIMER1_IRQ], pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ], pic[MP_TIMER4_IRQ], NULL); @@ -1624,10 +1671,10 @@ static void musicpal_init(QEMUMachineInitArgs *args) #endif } - sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL); + sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL); qemu_check_nic_model(&nd_table[0], "mv88w8618"); - dev = qdev_create(NULL, "mv88w8618_eth"); + dev = qdev_create(NULL, TYPE_MV88W8618_ETH); qdev_set_nic_properties(dev, &nd_table[0]); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); @@ -1637,12 +1684,13 @@ static void musicpal_init(QEMUMachineInitArgs *args) sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL); - dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); + dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE, + pic[MP_GPIO_IRQ]); i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); - lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); - key_dev = sysbus_create_simple("musicpal_key", -1, NULL); + lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL); + key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL); /* I2C read data */ qdev_connect_gpio_out(i2c_dev, 0, diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 19be5fcd01..47511d2cae 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -99,7 +99,7 @@ struct omap_mpu_timer_s { static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) { - uint64_t distance = qemu_get_clock_ns(vm_clock) - timer->time; + uint64_t distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time; if (timer->st && timer->enable && timer->rate) return timer->val - muldiv64(distance >> (timer->ptv + 1), @@ -111,7 +111,7 @@ static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) { timer->val = omap_timer_read(timer); - timer->time = qemu_get_clock_ns(vm_clock); + timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } static inline void omap_timer_update(struct omap_mpu_timer_s *timer) @@ -130,11 +130,11 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer) * in a busy loop when it wants to sleep just a couple of CPU * ticks. */ if (expires > (get_ticks_per_sec() >> 10) || timer->ar) - qemu_mod_timer(timer->timer, timer->time + expires); + timer_mod(timer->timer, timer->time + expires); else qemu_bh_schedule(timer->tick); } else - qemu_del_timer(timer->timer); + timer_del(timer->timer); } static void omap_timer_fire(void *opaque) @@ -240,7 +240,7 @@ static const MemoryRegionOps omap_mpu_timer_ops = { static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) { - qemu_del_timer(s->timer); + timer_del(s->timer); s->enable = 0; s->reset_val = 31337; s->val = 0; @@ -259,7 +259,7 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, s->irq = irq; s->clk = clk; - s->timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, s); s->tick = qemu_bh_new(omap_timer_fire, s); omap_mpu_timer_reset(s); omap_timer_clk_setup(s); @@ -363,7 +363,7 @@ static const MemoryRegionOps omap_wd_timer_ops = { static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) { - qemu_del_timer(s->timer.timer); + timer_del(s->timer.timer); if (!s->mode) omap_clk_get(s->timer.clk); s->mode = 1; @@ -388,7 +388,7 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, s->timer.irq = irq; s->timer.clk = clk; - s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer); + s->timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, &s->timer); omap_wd_timer_reset(s); omap_timer_clk_setup(&s->timer); @@ -475,7 +475,7 @@ static const MemoryRegionOps omap_os_timer_ops = { static void omap_os_timer_reset(struct omap_32khz_timer_s *s) { - qemu_del_timer(s->timer.timer); + timer_del(s->timer.timer); s->timer.enable = 0; s->timer.it_ena = 0; s->timer.reset_val = 0x00ffffff; @@ -494,7 +494,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, s->timer.irq = irq; s->timer.clk = clk; - s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer); + s->timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, &s->timer); omap_os_timer_reset(s); omap_timer_clk_setup(&s->timer); @@ -600,7 +600,7 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, case 0x10: /* GAUGING_CTRL */ /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) { - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (value & 1) s->ulpd_gauge_start = now; @@ -2881,7 +2881,7 @@ static void omap_rtc_tick(void *opaque) if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) s->tick += s->comp_reg * 1000 / 32768; - qemu_mod_timer(s->clk, s->tick); + timer_mod(s->clk, s->tick); } static void omap_rtc_reset(struct omap_rtc_s *s) @@ -2894,7 +2894,7 @@ static void omap_rtc_reset(struct omap_rtc_s *s) s->pm_am = 0; s->auto_comp = 0; s->round = 0; - s->tick = qemu_get_clock_ms(rtc_clock); + s->tick = qemu_clock_get_ms(rtc_clock); memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); s->alarm_tm.tm_mday = 0x01; s->status = 1 << 7; @@ -2915,7 +2915,7 @@ static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, s->irq = timerirq; s->alarm = alarmirq; - s->clk = qemu_new_timer_ms(rtc_clock, omap_rtc_tick, s); + s->clk = timer_new_ms(rtc_clock, omap_rtc_tick, s); omap_rtc_reset(s); @@ -3009,7 +3009,7 @@ static void omap_mcbsp_source_tick(void *opaque) s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; omap_mcbsp_rx_newdata(s); - qemu_mod_timer(s->source_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(s->source_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec()); } @@ -3025,7 +3025,7 @@ static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) { - qemu_del_timer(s->source_timer); + timer_del(s->source_timer); } static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) @@ -3055,7 +3055,7 @@ static void omap_mcbsp_sink_tick(void *opaque) s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; omap_mcbsp_tx_newdata(s); - qemu_mod_timer(s->sink_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(s->sink_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec()); } @@ -3082,7 +3082,7 @@ static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) { s->tx_req = 0; omap_mcbsp_tx_done(s); - qemu_del_timer(s->sink_timer); + timer_del(s->sink_timer); } static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) @@ -3432,8 +3432,8 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s) s->rx_req = 0; s->tx_rate = 0; s->rx_rate = 0; - qemu_del_timer(s->source_timer); - qemu_del_timer(s->sink_timer); + timer_del(s->source_timer); + timer_del(s->sink_timer); } static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, @@ -3448,8 +3448,8 @@ static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, s->rxirq = rxirq; s->txdrq = dma[0]; s->rxdrq = dma[1]; - s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s); - s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s); + s->sink_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_mcbsp_sink_tick, s); + s->source_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_mcbsp_source_tick, s); omap_mcbsp_reset(s); memory_region_init_io(&s->iomem, NULL, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800); @@ -3503,9 +3503,9 @@ static void omap_lpg_tick(void *opaque) struct omap_lpg_s *s = opaque; if (s->cycle) - qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->period - s->on); + timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->period - s->on); else - qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->on); + timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->on); s->cycle = !s->cycle; printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); @@ -3527,7 +3527,7 @@ static void omap_lpg_update(struct omap_lpg_s *s) per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ } - qemu_del_timer(s->tm); + timer_del(s->tm); if (on == period && s->on < s->period) printf("%s: LED is on\n", __FUNCTION__); else if (on == 0 && s->on) @@ -3623,7 +3623,7 @@ static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, struct omap_lpg_s *s = (struct omap_lpg_s *) g_malloc0(sizeof(struct omap_lpg_s)); - s->tm = qemu_new_timer_ms(vm_clock, omap_lpg_tick, s); + s->tm = timer_new_ms(QEMU_CLOCK_VIRTUAL, omap_lpg_tick, s); omap_lpg_reset(s); @@ -3827,7 +3827,6 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, int i; struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) g_malloc0(sizeof(struct omap_mpu_state_s)); - qemu_irq *cpu_irq; qemu_irq dma_irqs[6]; DriveInfo *dinfo; SysBusDevice *busdev; @@ -3860,14 +3859,15 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); - cpu_irq = arm_pic_init_cpu(s->cpu); s->ih[0] = qdev_create(NULL, "omap-intc"); qdev_prop_set_uint32(s->ih[0], "size", 0x100); qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck")); qdev_init_nofail(s->ih[0]); busdev = SYS_BUS_DEVICE(s->ih[0]); - sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); - sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); + sysbus_connect_irq(busdev, 1, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); sysbus_mmio_map(busdev, 0, 0xfffecb00); s->ih[1] = qdev_create(NULL, "omap-intc"); qdev_prop_set_uint32(s->ih[1], "size", 0x800); diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index ec9610b7d5..36efde0d64 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -2244,7 +2244,6 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) g_malloc0(sizeof(struct omap_mpu_state_s)); - qemu_irq *cpu_irq; qemu_irq dma_irqs[4]; DriveInfo *dinfo; int i; @@ -2277,15 +2276,16 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ - cpu_irq = arm_pic_init_cpu(s->cpu); s->ih[0] = qdev_create(NULL, "omap2-intc"); qdev_prop_set_uint8(s->ih[0], "revision", 0x21); qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk")); qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk")); qdev_init_nofail(s->ih[0]); busdev = SYS_BUS_DEVICE(s->ih[0]); - sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); - sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); + sysbus_connect_irq(busdev, 1, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); sysbus_mmio_map(busdev, 0, 0x480fe000); s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3), qdev_get_gpio_in(s->ih[0], diff --git a/hw/arm/pic_cpu.c b/hw/arm/pic_cpu.c deleted file mode 100644 index 875280aa97..0000000000 --- a/hw/arm/pic_cpu.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Generic ARM Programmable Interrupt Controller support. - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the LGPL - */ - -#include "hw/hw.h" -#include "hw/arm/arm.h" -#include "sysemu/kvm.h" - -/* Input 0 is IRQ and input 1 is FIQ. */ -static void arm_pic_cpu_handler(void *opaque, int irq, int level) -{ - ARMCPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - switch (irq) { - case ARM_PIC_CPU_IRQ: - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } - break; - case ARM_PIC_CPU_FIQ: - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_FIQ); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ); - } - break; - default: - hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq); - } -} - -static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level) -{ -#ifdef CONFIG_KVM - ARMCPU *cpu = opaque; - CPUState *cs = CPU(cpu); - int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT; - - switch (irq) { - case ARM_PIC_CPU_IRQ: - kvm_irq |= KVM_ARM_IRQ_CPU_IRQ; - break; - case ARM_PIC_CPU_FIQ: - kvm_irq |= KVM_ARM_IRQ_CPU_FIQ; - break; - default: - hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq); - } - kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT; - kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0); -#endif -} - -qemu_irq *arm_pic_init_cpu(ARMCPU *cpu) -{ - if (kvm_enabled()) { - return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2); - } - return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2); -} diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 3c520d7f2e..02b7016a04 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -335,7 +335,7 @@ static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri, { PXA2xxState *s = (PXA2xxState *)ri->opaque; if (s->pmnc & 1) { - *value = qemu_get_clock_ns(vm_clock); + *value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } else { *value = 0; } @@ -457,9 +457,16 @@ static const VMStateDescription vmstate_pxa2xx_mm = { } }; +#define TYPE_PXA2XX_SSP "pxa2xx-ssp" +#define PXA2XX_SSP(obj) \ + OBJECT_CHECK(PXA2xxSSPState, (obj), TYPE_PXA2XX_SSP) + /* Synchronous Serial Ports */ typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; qemu_irq irq; int enable; @@ -757,19 +764,20 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static int pxa2xx_ssp_init(SysBusDevice *dev) +static int pxa2xx_ssp_init(SysBusDevice *sbd) { - PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev); + DeviceState *dev = DEVICE(sbd); + PXA2xxSSPState *s = PXA2XX_SSP(dev); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0, + sysbus_init_mmio(sbd, &s->iomem); + register_savevm(dev, "pxa2xx_ssp", -1, 0, pxa2xx_ssp_save, pxa2xx_ssp_load, s); - s->bus = ssi_create_bus(&dev->qdev, "ssi"); + s->bus = ssi_create_bus(dev, "ssi"); return 0; } @@ -790,8 +798,15 @@ static int pxa2xx_ssp_init(SysBusDevice *dev) #define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */ #define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */ +#define TYPE_PXA2XX_RTC "pxa2xx_rtc" +#define PXA2XX_RTC(obj) \ + OBJECT_CHECK(PXA2xxRTCState, (obj), TYPE_PXA2XX_RTC) + typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; uint32_t rttr; uint32_t rtsr; @@ -827,7 +842,7 @@ static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s) static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) { - int64_t rt = qemu_get_clock_ms(rtc_clock); + int64_t rt = qemu_clock_get_ms(rtc_clock); s->last_rcnr += ((rt - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); s->last_rdcr += ((rt - s->last_hz) << 15) / @@ -837,7 +852,7 @@ static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) { - int64_t rt = qemu_get_clock_ms(rtc_clock); + int64_t rt = qemu_clock_get_ms(rtc_clock); if (s->rtsr & (1 << 12)) s->last_swcr += (rt - s->last_sw) / 10; s->last_sw = rt; @@ -845,7 +860,7 @@ static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s) { - int64_t rt = qemu_get_clock_ms(rtc_clock); + int64_t rt = qemu_clock_get_ms(rtc_clock); if (s->rtsr & (1 << 15)) s->last_swcr += rt - s->last_pi; s->last_pi = rt; @@ -855,43 +870,43 @@ static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s, uint32_t rtsr) { if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0))) - qemu_mod_timer(s->rtc_hz, s->last_hz + + timer_mod(s->rtc_hz, s->last_hz + (((s->rtar - s->last_rcnr) * 1000 * ((s->rttr & 0xffff) + 1)) >> 15)); else - qemu_del_timer(s->rtc_hz); + timer_del(s->rtc_hz); if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4))) - qemu_mod_timer(s->rtc_rdal1, s->last_hz + + timer_mod(s->rtc_rdal1, s->last_hz + (((s->rdar1 - s->last_rdcr) * 1000 * ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ else - qemu_del_timer(s->rtc_rdal1); + timer_del(s->rtc_rdal1); if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6))) - qemu_mod_timer(s->rtc_rdal2, s->last_hz + + timer_mod(s->rtc_rdal2, s->last_hz + (((s->rdar2 - s->last_rdcr) * 1000 * ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ else - qemu_del_timer(s->rtc_rdal2); + timer_del(s->rtc_rdal2); if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8))) - qemu_mod_timer(s->rtc_swal1, s->last_sw + + timer_mod(s->rtc_swal1, s->last_sw + (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */ else - qemu_del_timer(s->rtc_swal1); + timer_del(s->rtc_swal1); if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10))) - qemu_mod_timer(s->rtc_swal2, s->last_sw + + timer_mod(s->rtc_swal2, s->last_sw + (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */ else - qemu_del_timer(s->rtc_swal2); + timer_del(s->rtc_swal2); if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13))) - qemu_mod_timer(s->rtc_pi, s->last_pi + + timer_mod(s->rtc_pi, s->last_pi + (s->piar & 0xffff) - s->last_rtcpicr); else - qemu_del_timer(s->rtc_pi); + timer_del(s->rtc_pi); } static inline void pxa2xx_rtc_hz_tick(void *opaque) @@ -971,16 +986,19 @@ static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr, case PIAR: return s->piar; case RCNR: - return s->last_rcnr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); + return s->last_rcnr + + ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); case RDCR: - return s->last_rdcr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); + return s->last_rdcr + + ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); case RYCR: return s->last_rycr; case SWCR: if (s->rtsr & (1 << 12)) - return s->last_swcr + (qemu_get_clock_ms(rtc_clock) - s->last_sw) / 10; + return s->last_swcr + + (qemu_clock_get_ms(rtc_clock) - s->last_sw) / 10; else return s->last_swcr; default: @@ -1102,7 +1120,7 @@ static const MemoryRegionOps pxa2xx_rtc_ops = { static int pxa2xx_rtc_init(SysBusDevice *dev) { - PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev); + PXA2xxRTCState *s = PXA2XX_RTC(dev); struct tm tm; int wom; @@ -1120,14 +1138,14 @@ static int pxa2xx_rtc_init(SysBusDevice *dev) s->last_swcr = (tm.tm_hour << 19) | (tm.tm_min << 13) | (tm.tm_sec << 7); s->last_rtcpicr = 0; - s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rtc_clock); + s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock); - s->rtc_hz = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); - s->rtc_rdal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); - s->rtc_rdal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); - s->rtc_swal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); - s->rtc_swal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); - s->rtc_pi = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); + s->rtc_hz = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); + s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); + s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); + s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); + s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); + s->rtc_pi = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); sysbus_init_irq(dev, &s->rtc_irq); @@ -1197,7 +1215,7 @@ static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) } static const TypeInfo pxa2xx_rtc_sysbus_info = { - .name = "pxa2xx_rtc", + .name = TYPE_PXA2XX_RTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxRTCState), .class_init = pxa2xx_rtc_sysbus_class_init, @@ -1209,8 +1227,15 @@ typedef struct { PXA2xxI2CState *host; } PXA2xxI2CSlaveState; +#define TYPE_PXA2XX_I2C "pxa2xx_i2c" +#define PXA2XX_I2C(obj) \ + OBJECT_CHECK(PXA2xxI2CState, (obj), TYPE_PXA2XX_I2C) + struct PXA2xxI2CState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; PXA2xxI2CSlaveState *slave; i2c_bus *bus; @@ -1457,35 +1482,38 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, DeviceState *dev; SysBusDevice *i2c_dev; PXA2xxI2CState *s; + i2c_bus *i2cbus; - i2c_dev = SYS_BUS_DEVICE(qdev_create(NULL, "pxa2xx_i2c")); - qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1); - qdev_prop_set_uint32(&i2c_dev->qdev, "offset", base & region_size); - - qdev_init_nofail(&i2c_dev->qdev); + dev = qdev_create(NULL, TYPE_PXA2XX_I2C); + qdev_prop_set_uint32(dev, "size", region_size + 1); + qdev_prop_set_uint32(dev, "offset", base & region_size); + qdev_init_nofail(dev); + i2c_dev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(i2c_dev, 0, base & ~region_size); sysbus_connect_irq(i2c_dev, 0, irq); - s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev); + s = PXA2XX_I2C(i2c_dev); /* FIXME: Should the slave device really be on a separate bus? */ - dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0); + i2cbus = i2c_init_bus(dev, "dummy"); + dev = i2c_create_slave(i2cbus, "pxa2xx-i2c-slave", 0); s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE(dev)); s->slave->host = s; return s; } -static int pxa2xx_i2c_initfn(SysBusDevice *dev) +static int pxa2xx_i2c_initfn(SysBusDevice *sbd) { - PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev); + DeviceState *dev = DEVICE(sbd); + PXA2xxI2CState *s = PXA2XX_I2C(dev); - s->bus = i2c_init_bus(&dev->qdev, "i2c"); + s->bus = i2c_init_bus(dev, "i2c"); memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_i2c_ops, s, "pxa2xx-i2c", s->region_size); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); return 0; } @@ -1513,7 +1541,7 @@ static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) } static const TypeInfo pxa2xx_i2c_info = { - .name = "pxa2xx_i2c", + .name = TYPE_PXA2XX_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxI2CState), .class_init = pxa2xx_i2c_class_init, @@ -2107,7 +2135,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); for (i = 0; pxa27x_ssp[i].io_base; i ++) { DeviceState *dev; - dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base, + dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base, qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn)); s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } @@ -2120,7 +2148,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); - sysbus_create_simple("pxa2xx_rtc", 0x40900000, + sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); s->i2c[0] = pxa2xx_i2c_init(0x40301600, @@ -2238,7 +2266,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); for (i = 0; pxa255_ssp[i].io_base; i ++) { DeviceState *dev; - dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base, + dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base, qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn)); s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } @@ -2251,7 +2279,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); - sysbus_create_simple("pxa2xx_rtc", 0x40900000, + sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); s->i2c[0] = pxa2xx_i2c_init(0x40301600, @@ -2278,7 +2306,7 @@ static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) } static const TypeInfo pxa2xx_ssp_info = { - .name = "pxa2xx-ssp", + .name = TYPE_PXA2XX_SSP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxSSPState), .class_init = pxa2xx_ssp_class_init, diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index f8c3ee073f..ca77f56c9f 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -13,9 +13,16 @@ #define PXA2XX_GPIO_BANKS 4 +#define TYPE_PXA2XX_GPIO "pxa2xx-gpio" +#define PXA2XX_GPIO(obj) \ + OBJECT_CHECK(PXA2xxGPIOInfo, (obj), TYPE_PXA2XX_GPIO) + typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo; struct PXA2xxGPIOInfo { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; qemu_irq irq0, irq1, irqX; int lines; @@ -256,7 +263,7 @@ DeviceState *pxa2xx_gpio_init(hwaddr base, CPUState *cs = CPU(cpu); DeviceState *dev; - dev = qdev_create(NULL, "pxa2xx-gpio"); + dev = qdev_create(NULL, TYPE_PXA2XX_GPIO); qdev_prop_set_int32(dev, "lines", lines); qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); qdev_init_nofail(dev); @@ -272,22 +279,21 @@ DeviceState *pxa2xx_gpio_init(hwaddr base, return dev; } -static int pxa2xx_gpio_initfn(SysBusDevice *dev) +static int pxa2xx_gpio_initfn(SysBusDevice *sbd) { - PXA2xxGPIOInfo *s; - - s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); + DeviceState *dev = DEVICE(sbd); + PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev); s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu)); - qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); - qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); + qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines); + qdev_init_gpio_out(dev, s->handler, s->lines); memory_region_init_io(&s->iomem, OBJECT(s), &pxa_gpio_ops, s, "pxa2xx-gpio", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq0); - sysbus_init_irq(dev, &s->irq1); - sysbus_init_irq(dev, &s->irqX); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq0); + sysbus_init_irq(sbd, &s->irq1); + sysbus_init_irq(sbd, &s->irqX); return 0; } @@ -298,7 +304,8 @@ static int pxa2xx_gpio_initfn(SysBusDevice *dev) */ void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler) { - PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, SYS_BUS_DEVICE(dev)); + PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev); + s->read_notify = handler; } @@ -337,7 +344,7 @@ static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) } static const TypeInfo pxa2xx_gpio_info = { - .name = "pxa2xx-gpio", + .name = TYPE_PXA2XX_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxGPIOInfo), .class_init = pxa2xx_gpio_class_init, diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 8929b6db41..46d337cf84 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -31,8 +31,15 @@ #define PXA2XX_PIC_SRCS 40 +#define TYPE_PXA2XX_PIC "pxa2xx_pic" +#define PXA2XX_PIC(obj) \ + OBJECT_CHECK(PXA2xxPICState, (obj), TYPE_PXA2XX_PIC) + typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; ARMCPU *cpu; uint32_t int_enabled[2]; @@ -260,9 +267,8 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id) DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) { - CPUARMState *env = &cpu->env; - DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); - PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, SYS_BUS_DEVICE(dev)); + DeviceState *dev = qdev_create(NULL, TYPE_PXA2XX_PIC); + PXA2xxPICState *s = PXA2XX_PIC(dev); s->cpu = cpu; @@ -284,7 +290,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); /* Enable IC coprocessor access. */ - define_arm_cp_regs_with_opaque(arm_env_get_cpu(env), pxa_pic_cp_reginfo, s); + define_arm_cp_regs_with_opaque(cpu, pxa_pic_cp_reginfo, s); return dev; } @@ -321,7 +327,7 @@ static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) } static const TypeInfo pxa2xx_pic_info = { - .name = "pxa2xx_pic", + .name = TYPE_PXA2XX_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxPICState), .class_init = pxa2xx_pic_class_init, diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 3060f48f77..82ec02d118 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -56,7 +56,6 @@ static void realview_init(QEMUMachineInitArgs *args, MemoryRegion *ram_hack = g_new(MemoryRegion, 1); DeviceState *dev, *sysctl, *gpio2, *pl041; SysBusDevice *busdev; - qemu_irq *irqp; qemu_irq pic[64]; qemu_irq mmc_irq[2]; PCIBus *pci_bus = NULL; @@ -92,8 +91,7 @@ static void realview_init(QEMUMachineInitArgs *args, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); } env = &cpu->env; if (arm_feature(env, ARM_FEATURE_V7)) { diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 593b75e55b..9b9ce95c5a 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -50,8 +50,12 @@ #define FLASHCTL_RYBY (1 << 5) #define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) +#define TYPE_SL_NAND "sl-nand" +#define SL_NAND(obj) OBJECT_CHECK(SLNANDState, (obj), TYPE_SL_NAND) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; DeviceState *nand; uint8_t ctl; @@ -147,7 +151,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size) { DeviceState *dev; - dev = qdev_create(NULL, "sl-nand"); + dev = qdev_create(NULL, TYPE_SL_NAND); qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG); if (size == FLASH_128M) @@ -159,12 +163,11 @@ static void sl_flash_register(PXA2xxState *cpu, int size) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); } -static int sl_nand_init(SysBusDevice *dev) { - SLNANDState *s; +static int sl_nand_init(SysBusDevice *dev) +{ + SLNANDState *s = SL_NAND(dev); DriveInfo *nand; - s = FROM_SYSBUS(SLNANDState, dev); - s->ctl = 0; nand = drive_get(IF_MTD, 0, 0); s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id); @@ -212,8 +215,13 @@ static const int spitz_gpiomap[5] = { SPITZ_GPIO_SWA, SPITZ_GPIO_SWB, }; +#define TYPE_SPITZ_KEYBOARD "spitz-keyboard" +#define SPITZ_KEYBOARD(obj) \ + OBJECT_CHECK(SpitzKeyboardState, (obj), TYPE_SPITZ_KEYBOARD) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + qemu_irq sense[SPITZ_KEY_SENSE_NUM]; qemu_irq gpiomap[5]; int keymap[0x80]; @@ -385,7 +393,7 @@ static void spitz_keyboard_tick(void *opaque) s->fifopos = 0; } - qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) + + timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() / 32); } @@ -458,8 +466,8 @@ static void spitz_keyboard_register(PXA2xxState *cpu) DeviceState *dev; SpitzKeyboardState *s; - dev = sysbus_create_simple("spitz-keyboard", -1, NULL); - s = FROM_SYSBUS(SpitzKeyboardState, SYS_BUS_DEVICE(dev)); + dev = sysbus_create_simple(TYPE_SPITZ_KEYBOARD, -1, NULL); + s = SPITZ_KEYBOARD(dev); for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i])); @@ -477,18 +485,17 @@ static void spitz_keyboard_register(PXA2xxState *cpu) qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i], qdev_get_gpio_in(dev, i)); - qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock)); + timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); qemu_add_kbd_event_handler(spitz_keyboard_handler, s); } -static int spitz_keyboard_init(SysBusDevice *dev) +static int spitz_keyboard_init(SysBusDevice *sbd) { - SpitzKeyboardState *s; + DeviceState *dev = DEVICE(sbd); + SpitzKeyboardState *s = SPITZ_KEYBOARD(dev); int i, j; - s = FROM_SYSBUS(SpitzKeyboardState, dev); - for (i = 0; i < 0x80; i ++) s->keymap[i] = -1; for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++) @@ -498,9 +505,9 @@ static int spitz_keyboard_init(SysBusDevice *dev) spitz_keyboard_pre_map(s); - s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s); - qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); - qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM); + s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s); + qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); + qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM); return 0; } @@ -1027,7 +1034,7 @@ static void sl_nand_class_init(ObjectClass *klass, void *data) } static const TypeInfo sl_nand_info = { - .name = "sl-nand", + .name = TYPE_SL_NAND, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLNANDState), .class_init = sl_nand_class_init, @@ -1062,7 +1069,7 @@ static void spitz_keyboard_class_init(ObjectClass *klass, void *data) } static const TypeInfo spitz_keyboard_info = { - .name = "spitz-keyboard", + .name = TYPE_SPITZ_KEYBOARD, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpitzKeyboardState), .class_init = spitz_keyboard_class_init, diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index a2b6b1724d..3237b30260 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -43,8 +43,13 @@ typedef const struct { /* General purpose timer module. */ +#define TYPE_STELLARIS_GPTM "stellaris-gptm" +#define STELLARIS_GPTM(obj) \ + OBJECT_CHECK(gptm_state, (obj), TYPE_STELLARIS_GPTM) + typedef struct gptm_state { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t config; uint32_t mode[2]; @@ -73,14 +78,14 @@ static void gptm_update_irq(gptm_state *s) static void gptm_stop(gptm_state *s, int n) { - qemu_del_timer(s->timer[n]); + timer_del(s->timer[n]); } static void gptm_reload(gptm_state *s, int n, int reset) { int64_t tick; if (reset) - tick = qemu_get_clock_ns(vm_clock); + tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); else tick = s->tick[n]; @@ -98,7 +103,7 @@ static void gptm_reload(gptm_state *s, int n, int reset) hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); } s->tick[n] = tick; - qemu_mod_timer(s->timer[n], tick); + timer_mod(s->timer[n], tick); } static void gptm_tick(void *opaque) @@ -300,21 +305,22 @@ static const VMStateDescription vmstate_stellaris_gptm = { } }; -static int stellaris_gptm_init(SysBusDevice *dev) +static int stellaris_gptm_init(SysBusDevice *sbd) { - gptm_state *s = FROM_SYSBUS(gptm_state, dev); + DeviceState *dev = DEVICE(sbd); + gptm_state *s = STELLARIS_GPTM(dev); - sysbus_init_irq(dev, &s->irq); - qdev_init_gpio_out(&dev->qdev, &s->trigger, 1); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_out(dev, &s->trigger, 1); memory_region_init_io(&s->iomem, OBJECT(s), &gptm_ops, s, "gptm", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); s->opaque[0] = s->opaque[1] = s; - s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]); - s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]); - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s); + s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]); + s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]); + vmstate_register(dev, -1, &vmstate_stellaris_gptm, s); return 0; } @@ -679,8 +685,13 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq, /* I2C controller. */ +#define TYPE_STELLARIS_I2C "stellaris-i2c" +#define STELLARIS_I2C(obj) \ + OBJECT_CHECK(stellaris_i2c_state, (obj), TYPE_STELLARIS_I2C) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + i2c_bus *bus; qemu_irq irq; MemoryRegion iomem; @@ -853,21 +864,22 @@ static const VMStateDescription vmstate_stellaris_i2c = { } }; -static int stellaris_i2c_init(SysBusDevice * dev) +static int stellaris_i2c_init(SysBusDevice *sbd) { - stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev); + DeviceState *dev = DEVICE(sbd); + stellaris_i2c_state *s = STELLARIS_I2C(dev); i2c_bus *bus; - sysbus_init_irq(dev, &s->irq); - bus = i2c_init_bus(&dev->qdev, "i2c"); + sysbus_init_irq(sbd, &s->irq); + bus = i2c_init_bus(dev, "i2c"); s->bus = bus; memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_i2c_ops, s, "i2c", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); /* ??? For now we only implement the master interface. */ stellaris_i2c_reset(s); - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s); + vmstate_register(dev, -1, &vmstate_stellaris_i2c, s); return 0; } @@ -885,9 +897,13 @@ static int stellaris_i2c_init(SysBusDevice * dev) #define STELLARIS_ADC_FIFO_EMPTY 0x0100 #define STELLARIS_ADC_FIFO_FULL 0x1000 -typedef struct -{ - SysBusDevice busdev; +#define TYPE_STELLARIS_ADC "stellaris-adc" +#define STELLARIS_ADC(obj) \ + OBJECT_CHECK(stellaris_adc_state, (obj), TYPE_STELLARIS_ADC) + +typedef struct StellarisADCState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t actss; uint32_t ris; @@ -1136,21 +1152,22 @@ static const VMStateDescription vmstate_stellaris_adc = { } }; -static int stellaris_adc_init(SysBusDevice *dev) +static int stellaris_adc_init(SysBusDevice *sbd) { - stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev); + DeviceState *dev = DEVICE(sbd); + stellaris_adc_state *s = STELLARIS_ADC(dev); int n; for (n = 0; n < 4; n++) { - sysbus_init_irq(dev, &s->irq[n]); + sysbus_init_irq(sbd, &s->irq[n]); } memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_adc_ops, s, "adc", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); stellaris_adc_reset(s); - qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1); - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s); + qdev_init_gpio_in(dev, stellaris_adc_trigger, 1); + vmstate_register(dev, -1, &vmstate_stellaris_adc, s); return 0; } @@ -1207,7 +1224,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, flash_size, sram_size, kernel_filename, cpu_model); if (board->dc1 & (1 << 16)) { - dev = sysbus_create_varargs("stellaris-adc", 0x40038000, + dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000, pic[14], pic[15], pic[16], pic[17], NULL); adc = qdev_get_gpio_in(dev, 0); } else { @@ -1215,7 +1232,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } for (i = 0; i < 4; i++) { if (board->dc2 & (0x10000 << i)) { - dev = sysbus_create_simple("stellaris-gptm", + dev = sysbus_create_simple(TYPE_STELLARIS_GPTM, 0x40030000 + i * 0x1000, pic[timer_irq[i]]); /* TODO: This is incorrect, but we get away with it because @@ -1238,7 +1255,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } if (board->dc2 & (1 << 12)) { - dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]); + dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, pic[8]); i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); if (board->peripherals & BP_OLED_I2C) { i2c_create_slave(i2c, "ssd0303", 0x3d); @@ -1357,7 +1374,7 @@ static void stellaris_i2c_class_init(ObjectClass *klass, void *data) } static const TypeInfo stellaris_i2c_info = { - .name = "stellaris-i2c", + .name = TYPE_STELLARIS_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_i2c_state), .class_init = stellaris_i2c_class_init, @@ -1371,7 +1388,7 @@ static void stellaris_gptm_class_init(ObjectClass *klass, void *data) } static const TypeInfo stellaris_gptm_info = { - .name = "stellaris-gptm", + .name = TYPE_STELLARIS_GPTM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(gptm_state), .class_init = stellaris_gptm_class_init, @@ -1385,7 +1402,7 @@ static void stellaris_adc_class_init(ObjectClass *klass, void *data) } static const TypeInfo stellaris_adc_info = { - .name = "stellaris-adc", + .name = TYPE_STELLARIS_ADC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_adc_state), .class_init = stellaris_adc_class_init, diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index feaaf45082..170d0ce267 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -70,8 +70,14 @@ static struct { }; /* Interrupt Controller */ -typedef struct { - SysBusDevice busdev; + +#define TYPE_STRONGARM_PIC "strongarm_pic" +#define STRONGARM_PIC(obj) \ + OBJECT_CHECK(StrongARMPICState, (obj), TYPE_STRONGARM_PIC) + +typedef struct StrongARMPICState { + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; qemu_irq fiq; @@ -168,16 +174,17 @@ static const MemoryRegionOps strongarm_pic_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int strongarm_pic_initfn(SysBusDevice *dev) +static int strongarm_pic_initfn(SysBusDevice *sbd) { - StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev); + DeviceState *dev = DEVICE(sbd); + StrongARMPICState *s = STRONGARM_PIC(dev); - qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS); + qdev_init_gpio_in(dev, strongarm_pic_set_irq, SA_PIC_SRCS); memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_pic_ops, s, "pic", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - sysbus_init_irq(dev, &s->fiq); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->fiq); return 0; } @@ -214,7 +221,7 @@ static void strongarm_pic_class_init(ObjectClass *klass, void *data) } static const TypeInfo strongarm_pic_info = { - .name = "strongarm_pic", + .name = TYPE_STRONGARM_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPICState), .class_init = strongarm_pic_class_init, @@ -235,8 +242,13 @@ static const TypeInfo strongarm_pic_info = { * trim delete isn't emulated, so * f = 32 768 / (RTTR_trim + 1) */ -typedef struct { - SysBusDevice busdev; +#define TYPE_STRONGARM_RTC "strongarm-rtc" +#define STRONGARM_RTC(obj) \ + OBJECT_CHECK(StrongARMRTCState, (obj), TYPE_STRONGARM_RTC) + +typedef struct StrongARMRTCState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t rttr; uint32_t rtsr; @@ -257,7 +269,7 @@ static inline void strongarm_rtc_int_update(StrongARMRTCState *s) static void strongarm_rtc_hzupdate(StrongARMRTCState *s) { - int64_t rt = qemu_get_clock_ms(rtc_clock); + int64_t rt = qemu_clock_get_ms(rtc_clock); s->last_rcnr += ((rt - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); s->last_hz = rt; @@ -266,17 +278,17 @@ static void strongarm_rtc_hzupdate(StrongARMRTCState *s) static inline void strongarm_rtc_timer_update(StrongARMRTCState *s) { if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) { - qemu_mod_timer(s->rtc_hz, s->last_hz + 1000); + timer_mod(s->rtc_hz, s->last_hz + 1000); } else { - qemu_del_timer(s->rtc_hz); + timer_del(s->rtc_hz); } if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) { - qemu_mod_timer(s->rtc_alarm, s->last_hz + + timer_mod(s->rtc_alarm, s->last_hz + (((s->rtar - s->last_rcnr) * 1000 * ((s->rttr & 0xffff) + 1)) >> 15)); } else { - qemu_del_timer(s->rtc_alarm); + timer_del(s->rtc_alarm); } } @@ -310,7 +322,7 @@ static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr, return s->rtar; case RCNR: return s->last_rcnr + - ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / + ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); default: printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); @@ -367,7 +379,7 @@ static const MemoryRegionOps strongarm_rtc_ops = { static int strongarm_rtc_init(SysBusDevice *dev) { - StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev); + StrongARMRTCState *s = STRONGARM_RTC(dev); struct tm tm; s->rttr = 0x0; @@ -376,10 +388,10 @@ static int strongarm_rtc_init(SysBusDevice *dev) qemu_get_timedate(&tm, 0); s->last_rcnr = (uint32_t) mktimegm(&tm); - s->last_hz = qemu_get_clock_ms(rtc_clock); + s->last_hz = qemu_clock_get_ms(rtc_clock); - s->rtc_alarm = qemu_new_timer_ms(rtc_clock, strongarm_rtc_alarm_tick, s); - s->rtc_hz = qemu_new_timer_ms(rtc_clock, strongarm_rtc_hz_tick, s); + s->rtc_alarm = timer_new_ms(rtc_clock, strongarm_rtc_alarm_tick, s); + s->rtc_hz = timer_new_ms(rtc_clock, strongarm_rtc_hz_tick, s); sysbus_init_irq(dev, &s->rtc_irq); sysbus_init_irq(dev, &s->rtc_hz_irq); @@ -436,7 +448,7 @@ static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) } static const TypeInfo strongarm_rtc_sysbus_info = { - .name = "strongarm-rtc", + .name = TYPE_STRONGARM_RTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMRTCState), .class_init = strongarm_rtc_sysbus_class_init, @@ -452,6 +464,10 @@ static const TypeInfo strongarm_rtc_sysbus_info = { #define GEDR 0x18 #define GAFR 0x1c +#define TYPE_STRONGARM_GPIO "strongarm-gpio" +#define STRONGARM_GPIO(obj) \ + OBJECT_CHECK(StrongARMGPIOInfo, (obj), TYPE_STRONGARM_GPIO) + typedef struct StrongARMGPIOInfo StrongARMGPIOInfo; struct StrongARMGPIOInfo { SysBusDevice busdev; @@ -618,7 +634,7 @@ static DeviceState *strongarm_gpio_init(hwaddr base, DeviceState *dev; int i; - dev = qdev_create(NULL, "strongarm-gpio"); + dev = qdev_create(NULL, TYPE_STRONGARM_GPIO); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); @@ -629,24 +645,23 @@ static DeviceState *strongarm_gpio_init(hwaddr base, return dev; } -static int strongarm_gpio_initfn(SysBusDevice *dev) +static int strongarm_gpio_initfn(SysBusDevice *sbd) { - StrongARMGPIOInfo *s; + DeviceState *dev = DEVICE(sbd); + StrongARMGPIOInfo *s = STRONGARM_GPIO(dev); int i; - s = FROM_SYSBUS(StrongARMGPIOInfo, dev); - - qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28); - qdev_init_gpio_out(&dev->qdev, s->handler, 28); + qdev_init_gpio_in(dev, strongarm_gpio_set, 28); + qdev_init_gpio_out(dev, s->handler, 28); memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_gpio_ops, s, "gpio", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); for (i = 0; i < 11; i++) { - sysbus_init_irq(dev, &s->irqs[i]); + sysbus_init_irq(sbd, &s->irqs[i]); } - sysbus_init_irq(dev, &s->irqX); + sysbus_init_irq(sbd, &s->irqX); return 0; } @@ -678,7 +693,7 @@ static void strongarm_gpio_class_init(ObjectClass *klass, void *data) } static const TypeInfo strongarm_gpio_info = { - .name = "strongarm-gpio", + .name = TYPE_STRONGARM_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMGPIOInfo), .class_init = strongarm_gpio_class_init, @@ -691,9 +706,14 @@ static const TypeInfo strongarm_gpio_info = { #define PSDR 0x0c #define PPFR 0x10 +#define TYPE_STRONGARM_PPC "strongarm-ppc" +#define STRONGARM_PPC(obj) \ + OBJECT_CHECK(StrongARMPPCInfo, (obj), TYPE_STRONGARM_PPC) + typedef struct StrongARMPPCInfo StrongARMPPCInfo; struct StrongARMPPCInfo { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq handler[28]; @@ -802,19 +822,18 @@ static const MemoryRegionOps strongarm_ppc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int strongarm_ppc_init(SysBusDevice *dev) +static int strongarm_ppc_init(SysBusDevice *sbd) { - StrongARMPPCInfo *s; - - s = FROM_SYSBUS(StrongARMPPCInfo, dev); + DeviceState *dev = DEVICE(sbd); + StrongARMPPCInfo *s = STRONGARM_PPC(dev); - qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22); - qdev_init_gpio_out(&dev->qdev, s->handler, 22); + qdev_init_gpio_in(dev, strongarm_ppc_set, 22); + qdev_init_gpio_out(dev, s->handler, 22); memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ppc_ops, s, "ppc", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -845,7 +864,7 @@ static void strongarm_ppc_class_init(ObjectClass *klass, void *data) } static const TypeInfo strongarm_ppc_info = { - .name = "strongarm-ppc", + .name = TYPE_STRONGARM_PPC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPPCInfo), .class_init = strongarm_ppc_class_init, @@ -889,8 +908,13 @@ static const TypeInfo strongarm_ppc_info = { #define RX_FIFO_FRE (1 << 9) #define RX_FIFO_ROR (1 << 10) -typedef struct { - SysBusDevice busdev; +#define TYPE_STRONGARM_UART "strongarm-uart" +#define STRONGARM_UART(obj) \ + OBJECT_CHECK(StrongARMUARTState, (obj), TYPE_STRONGARM_UART) + +typedef struct StrongARMUARTState { + SysBusDevice parent_obj; + MemoryRegion iomem; CharDriverState *chr; qemu_irq irq; @@ -1061,8 +1085,8 @@ static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size) } /* call the timeout receive callback in 3 char transmit time */ - qemu_mod_timer(s->rx_timeout_timer, - qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3); + timer_mod(s->rx_timeout_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3); strongarm_uart_update_status(s); strongarm_uart_update_int_status(s); @@ -1083,7 +1107,7 @@ static void strongarm_uart_event(void *opaque, int event) static void strongarm_uart_tx(void *opaque) { StrongARMUARTState *s = opaque; - uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); + uint64_t new_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (s->utcr3 & UTCR3_LBM) /* loopback */ { strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1); @@ -1094,7 +1118,7 @@ static void strongarm_uart_tx(void *opaque) s->tx_start = (s->tx_start + 1) % 8; s->tx_len--; if (s->tx_len) { - qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time); + timer_mod(s->tx_timer, new_xmit_ts + s->char_transmit_time); } strongarm_uart_update_status(s); strongarm_uart_update_int_status(s); @@ -1206,15 +1230,15 @@ static const MemoryRegionOps strongarm_uart_ops = { static int strongarm_uart_init(SysBusDevice *dev) { - StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); + StrongARMUARTState *s = STRONGARM_UART(dev); memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_uart_ops, s, "uart", 0x10000); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); - s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s); - s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); + s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s); + s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s); if (s->chr) { qemu_chr_add_handlers(s->chr, @@ -1229,7 +1253,7 @@ static int strongarm_uart_init(SysBusDevice *dev) static void strongarm_uart_reset(DeviceState *dev) { - StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev); + StrongARMUARTState *s = STRONGARM_UART(dev); s->utcr0 = UTCR0_DSS; /* 8 data, no parity */ s->brd = 23; /* 9600 */ @@ -1258,8 +1282,8 @@ static int strongarm_uart_post_load(void *opaque, int version_id) /* restart rx timeout timer */ if (s->rx_len) { - qemu_mod_timer(s->rx_timeout_timer, - qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3); + timer_mod(s->rx_timeout_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3); } return 0; @@ -1305,15 +1329,21 @@ static void strongarm_uart_class_init(ObjectClass *klass, void *data) } static const TypeInfo strongarm_uart_info = { - .name = "strongarm-uart", + .name = TYPE_STRONGARM_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMUARTState), .class_init = strongarm_uart_class_init, }; /* Synchronous Serial Ports */ -typedef struct { - SysBusDevice busdev; + +#define TYPE_STRONGARM_SSP "strongarm-ssp" +#define STRONGARM_SSP(obj) \ + OBJECT_CHECK(StrongARMSSPState, (obj), TYPE_STRONGARM_SSP) + +typedef struct StrongARMSSPState { + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; SSIBus *bus; @@ -1495,23 +1525,25 @@ static int strongarm_ssp_post_load(void *opaque, int version_id) return 0; } -static int strongarm_ssp_init(SysBusDevice *dev) +static int strongarm_ssp_init(SysBusDevice *sbd) { - StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev); + DeviceState *dev = DEVICE(sbd); + StrongARMSSPState *s = STRONGARM_SSP(dev); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ssp_ops, s, "ssp", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); - s->bus = ssi_create_bus(&dev->qdev, "ssi"); + s->bus = ssi_create_bus(dev, "ssi"); return 0; } static void strongarm_ssp_reset(DeviceState *dev) { - StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev); + StrongARMSSPState *s = STRONGARM_SSP(dev); + s->sssr = 0x03; /* 3 bit data, SPI, disabled */ s->rx_start = 0; s->rx_level = 0; @@ -1545,7 +1577,7 @@ static void strongarm_ssp_class_init(ObjectClass *klass, void *data) } static const TypeInfo strongarm_ssp_info = { - .name = "strongarm-ssp", + .name = TYPE_STRONGARM_SSP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMSSPState), .class_init = strongarm_ssp_class_init, @@ -1556,7 +1588,6 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, unsigned int sdram_size, const char *rev) { StrongARMState *s; - qemu_irq *pic; int i; s = g_malloc0(sizeof(StrongARMState)); @@ -1581,9 +1612,10 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, vmstate_register_ram_global(&s->sdram); memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram); - pic = arm_pic_init_cpu(s->cpu); s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, - pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL); + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ), + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ), + NULL); sysbus_create_varargs("pxa25x-timer", 0x90000000, qdev_get_gpio_in(s->pic, SA_PIC_OSTC0), @@ -1592,15 +1624,15 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, qdev_get_gpio_in(s->pic, SA_PIC_OSTC3), NULL); - sysbus_create_simple("strongarm-rtc", 0x90010000, + sysbus_create_simple(TYPE_STRONGARM_RTC, 0x90010000, qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM)); s->gpio = strongarm_gpio_init(0x90040000, s->pic); - s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL); + s->ppc = sysbus_create_varargs(TYPE_STRONGARM_PPC, 0x90060000, NULL); for (i = 0; sa_serial[i].io_base; i++) { - DeviceState *dev = qdev_create(NULL, "strongarm-uart"); + DeviceState *dev = qdev_create(NULL, TYPE_STRONGARM_UART); qdev_prop_set_chr(dev, "chardev", serial_hds[i]); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, @@ -1609,7 +1641,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, qdev_get_gpio_in(s->pic, sa_serial[i].irq)); } - s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000, + s->ssp = sysbus_create_varargs(TYPE_STRONGARM_SSP, 0x80070000, qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL); s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi"); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 725f60fc5e..4a6fceeeaa 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -25,15 +25,19 @@ /* Primary interrupt controller. */ -typedef struct vpb_sic_state -{ - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t level; - uint32_t mask; - uint32_t pic_enable; - qemu_irq parent[32]; - int irq; +#define TYPE_VERSATILE_PB_SIC "versatilepb_sic" +#define VERSATILE_PB_SIC(obj) \ + OBJECT_CHECK(vpb_sic_state, (obj), TYPE_VERSATILE_PB_SIC) + +typedef struct vpb_sic_state { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint32_t level; + uint32_t mask; + uint32_t pic_enable; + qemu_irq parent[32]; + int irq; } vpb_sic_state; static const VMStateDescription vmstate_vpb_sic = { @@ -144,19 +148,20 @@ static const MemoryRegionOps vpb_sic_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int vpb_sic_init(SysBusDevice *dev) +static int vpb_sic_init(SysBusDevice *sbd) { - vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev); + DeviceState *dev = DEVICE(sbd); + vpb_sic_state *s = VERSATILE_PB_SIC(dev); int i; - qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32); + qdev_init_gpio_in(dev, vpb_sic_set_irq, 32); for (i = 0; i < 32; i++) { - sysbus_init_irq(dev, &s->parent[i]); + sysbus_init_irq(sbd, &s->parent[i]); } s->irq = 31; memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s, "vpb-sic", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -173,7 +178,6 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) ARMCPU *cpu; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - qemu_irq *cpu_pic; qemu_irq pic[32]; qemu_irq sic[32]; DeviceState *dev, *sysctl; @@ -206,14 +210,14 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) qdev_init_nofail(sysctl); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); - cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, - cpu_pic[ARM_PIC_CPU_IRQ], - cpu_pic[ARM_PIC_CPU_FIQ], NULL); + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), + NULL); for (n = 0; n < 32; n++) { pic[n] = qdev_get_gpio_in(dev, n); } - dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL); for (n = 0; n < 32; n++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]); sic[n] = qdev_get_gpio_in(dev, n); @@ -393,7 +397,7 @@ static void vpb_sic_class_init(ObjectClass *klass, void *data) } static const TypeInfo vpb_sic_info = { - .name = "versatilepb_sic", + .name = TYPE_VERSATILE_PB_SIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(vpb_sic_state), .class_init = vpb_sic_class_init, diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 9586e3880e..fbd71a7b49 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -183,7 +183,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, MemoryRegion *lowram = g_new(MemoryRegion, 1); DeviceState *dev; SysBusDevice *busdev; - qemu_irq *irqp; int n; qemu_irq cpu_irq[4]; ram_addr_t low_ram_size; @@ -198,8 +197,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); } if (ram_size > 0x40000000) { @@ -312,15 +310,13 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, for (n = 0; n < smp_cpus; n++) { ARMCPU *cpu; - qemu_irq *irqp; cpu = cpu_arm_init(cpu_model); if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); } { diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 3444823f3f..0f18c852c4 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -108,11 +108,9 @@ static void zynq_init(QEMUMachineInitArgs *args) MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); DeviceState *dev; SysBusDevice *busdev; - qemu_irq *irqp; qemu_irq pic[64]; NICInfo *nd; int n; - qemu_irq cpu_irq; if (!cpu_model) { cpu_model = "cortex-a9"; @@ -123,8 +121,6 @@ static void zynq_init(QEMUMachineInitArgs *args) fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(cpu); - cpu_irq = irqp[ARM_PIC_CPU_IRQ]; /* max 2GB ram */ if (ram_size > 0x80000000) { @@ -159,7 +155,8 @@ static void zynq_init(QEMUMachineInitArgs *args) qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xF8F00000); - sysbus_connect_irq(busdev, 0, cpu_irq); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); for (n = 0; n < 64; n++) { pic[n] = qdev_get_gpio_in(dev, n); diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 365b2f1864..01b4dfbc67 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1420,6 +1420,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5; k->revision = 0x01; k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Intel 82801AA AC97 Audio"; dc->vmsd = &vmstate_ac97; dc->props = ac97_properties; diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index f72e6ee372..0c792475d1 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -173,7 +173,7 @@ static void timer_handler (int c, double interval_Sec) s->ticking[n] = 1; #ifdef DEBUG interval = get_ticks_per_sec () * interval_Sec; - exp = qemu_get_clock_ns (vm_clock) + interval; + exp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + interval; s->exp[n] = exp; #endif @@ -364,6 +364,7 @@ static void adlib_class_initfn (ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS (klass); dc->realize = adlib_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = ADLIB_DESC; dc->props = adlib_properties; } diff --git a/hw/audio/cs4231.c b/hw/audio/cs4231.c index fabe9e64a0..d19195afc1 100644 --- a/hw/audio/cs4231.c +++ b/hw/audio/cs4231.c @@ -33,8 +33,13 @@ #define CS_DREGS 32 #define CS_MAXDREG (CS_DREGS - 1) +#define TYPE_CS4231 "SUNW,CS4231" +#define CS4231(obj) \ + OBJECT_CHECK(CSState, (obj), TYPE_CS4231) + typedef struct CSState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; uint32_t regs[CS_REGS]; @@ -47,7 +52,7 @@ typedef struct CSState { static void cs_reset(DeviceState *d) { - CSState *s = container_of(d, CSState, busdev.qdev); + CSState *s = CS4231(d); memset(s->regs, 0, CS_REGS * 4); memset(s->dregs, 0, CS_DREGS); @@ -111,7 +116,7 @@ static void cs_mem_write(void *opaque, hwaddr addr, break; case 4: if (val & 1) { - cs_reset(&s->busdev.qdev); + cs_reset(DEVICE(s)); } val &= 0x7f; s->regs[saddr] = val; @@ -142,7 +147,7 @@ static const VMStateDescription vmstate_cs4231 = { static int cs4231_init1(SysBusDevice *dev) { - CSState *s = FROM_SYSBUS(CSState, dev); + CSState *s = CS4231(dev); memory_region_init_io(&s->iomem, OBJECT(s), &cs_mem_ops, s, "cs4321", CS_SIZE); @@ -168,7 +173,7 @@ static void cs4231_class_init(ObjectClass *klass, void *data) } static const TypeInfo cs4231_info = { - .name = "SUNW,CS4231", + .name = TYPE_CS4231, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CSState), .class_init = cs4231_class_init, diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 7365c3c1de..666096be07 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -685,6 +685,7 @@ static void cs4231a_class_initfn (ObjectClass *klass, void *data) dc->realize = cs4231a_realizefn; dc->reset = cs4231a_reset; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Crystal Semiconductor CS4231A"; dc->vmsd = &vmstate_cs4231a; dc->props = cs4231a_properties; diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index f2c40daec1..adb66ced71 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -1069,6 +1069,7 @@ static void es1370_class_init (ObjectClass *klass, void *data) k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; k->subsystem_vendor_id = 0x4942; k->subsystem_id = 0x4c4c; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "ENSONIQ AudioPCI ES1370"; dc->vmsd = &vmstate_es1370; } diff --git a/hw/audio/gus.c b/hw/audio/gus.c index f45ed0b0e9..71be3c6ba5 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -315,6 +315,7 @@ static void gus_class_initfn (ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS (klass); dc->realize = gus_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Gravis Ultrasound GF1"; dc->vmsd = &vmstate_gus; dc->props = gus_properties; diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index 362d8c0cc0..9550c97e65 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -1034,6 +1034,7 @@ static void hda_audio_output_class_init(ObjectClass *klass, void *data) k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, output-only (line-out)"; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; @@ -1055,6 +1056,7 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, duplex (line-out, line-in)"; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; @@ -1076,6 +1078,7 @@ static void hda_audio_micro_class_init(ObjectClass *klass, void *data) k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, duplex (speaker, microphone)"; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 58984dc738..78f9d282e0 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -526,7 +526,7 @@ static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg) { int64_t ns; - ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns; + ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - d->wall_base_ns; d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */ } @@ -1111,7 +1111,7 @@ static void intel_hda_reset(DeviceState *dev) HDACodecDevice *cdev; intel_hda_regs_reset(d); - d->wall_base_ns = qemu_get_clock_ns(vm_clock); + d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* reset codecs */ QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { @@ -1258,6 +1258,7 @@ static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) k->device_id = 0x2668; k->revision = 1; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Intel HD Audio Controller (ich6)"; } @@ -1268,6 +1269,7 @@ static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) k->device_id = 0x293e; k->revision = 3; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Intel HD Audio Controller (ich9)"; } @@ -1296,6 +1298,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data) DeviceClass *k = DEVICE_CLASS(klass); k->init = hda_codec_dev_init; k->exit = hda_codec_dev_exit; + set_bit(DEVICE_CATEGORY_SOUND, k->categories); k->bus_type = TYPE_HDA_BUS; k->props = hda_props; } diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index b40ea43c6c..97194ce7ad 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -36,8 +36,13 @@ #define MP_AUDIO_CLOCK_24MHZ (1 << 9) #define MP_AUDIO_MONO (1 << 14) +#define TYPE_MV88W8618_AUDIO "mv88w8618_audio" +#define MV88W8618_AUDIO(obj) \ + OBJECT_CHECK(mv88w8618_audio_state, (obj), TYPE_MV88W8618_AUDIO) + typedef struct mv88w8618_audio_state { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; uint32_t playback_mode; @@ -219,8 +224,7 @@ static void mv88w8618_audio_write(void *opaque, hwaddr offset, static void mv88w8618_audio_reset(DeviceState *d) { - mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, - SYS_BUS_DEVICE(d)); + mv88w8618_audio_state *s = MV88W8618_AUDIO(d); s->playback_mode = 0; s->status = 0; @@ -238,7 +242,7 @@ static const MemoryRegionOps mv88w8618_audio_ops = { static int mv88w8618_audio_init(SysBusDevice *dev) { - mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, dev); + mv88w8618_audio_state *s = MV88W8618_AUDIO(dev); sysbus_init_irq(dev, &s->irq); @@ -287,7 +291,7 @@ static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) } static const TypeInfo mv88w8618_audio_info = { - .name = "mv88w8618_audio", + .name = TYPE_MV88W8618_AUDIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_audio_state), .class_init = mv88w8618_audio_class_init, diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c index 133de4e74c..9c0f7a092d 100644 --- a/hw/audio/milkymist-ac97.c +++ b/hw/audio/milkymist-ac97.c @@ -51,8 +51,13 @@ enum { CTRL_EN = (1<<0), }; +#define TYPE_MILKYMIST_AC97 "milkymist-ac97" +#define MILKYMIST_AC97(obj) \ + OBJECT_CHECK(MilkymistAC97State, (obj), TYPE_MILKYMIST_AC97) + struct MilkymistAC97State { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; QEMUSoundCard card; @@ -258,7 +263,7 @@ static void ac97_out_cb(void *opaque, int free_b) static void milkymist_ac97_reset(DeviceState *d) { - MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev); + MilkymistAC97State *s = MILKYMIST_AC97(d); int i; for (i = 0; i < R_MAX; i++) { @@ -280,7 +285,7 @@ static int ac97_post_load(void *opaque, int version_id) static int milkymist_ac97_init(SysBusDevice *dev) { - MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistAC97State *s = MILKYMIST_AC97(dev); struct audsettings as; sysbus_init_irq(dev, &s->crrequest_irq); @@ -330,7 +335,7 @@ static void milkymist_ac97_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_ac97_info = { - .name = "milkymist-ac97", + .name = TYPE_MILKYMIST_AC97, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistAC97State), .class_init = milkymist_ac97_class_init, diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 7ad59a13e4..9004ce3d1f 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -191,6 +191,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = pcspk_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->no_user = 1; dc->props = pcspk_properties; } diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c index 7d331b9577..5393b520b7 100644 --- a/hw/audio/pl041.c +++ b/hw/audio/pl041.c @@ -70,8 +70,12 @@ typedef struct { uint8_t rx_sample_size; } pl041_channel; -typedef struct { - SysBusDevice busdev; +#define TYPE_PL041 "pl041" +#define PL041(obj) OBJECT_CHECK(PL041State, (obj), TYPE_PL041) + +typedef struct PL041State { + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; @@ -80,7 +84,7 @@ typedef struct { pl041_regfile regs; pl041_channel fifo1; lm4549_state codec; -} pl041_state; +} PL041State; static const unsigned char pl041_default_id[8] = { @@ -107,7 +111,7 @@ static const char *get_reg_name(hwaddr offset) } #endif -static uint8_t pl041_compute_periphid3(pl041_state *s) +static uint8_t pl041_compute_periphid3(PL041State *s) { uint8_t id3 = 1; /* One channel */ @@ -142,7 +146,7 @@ static uint8_t pl041_compute_periphid3(pl041_state *s) return id3; } -static void pl041_reset(pl041_state *s) +static void pl041_reset(PL041State *s) { DBG_L1("pl041_reset\n"); @@ -156,7 +160,7 @@ static void pl041_reset(pl041_state *s) } -static void pl041_fifo1_write(pl041_state *s, uint32_t value) +static void pl041_fifo1_write(PL041State *s, uint32_t value) { pl041_channel *channel = &s->fifo1; pl041_fifo *fifo = &s->fifo1.tx_fifo; @@ -239,7 +243,7 @@ static void pl041_fifo1_write(pl041_state *s, uint32_t value) DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1); } -static void pl041_fifo1_transmit(pl041_state *s) +static void pl041_fifo1_transmit(PL041State *s) { pl041_channel *channel = &s->fifo1; pl041_fifo *fifo = &s->fifo1.tx_fifo; @@ -291,7 +295,7 @@ static void pl041_fifo1_transmit(pl041_state *s) } } -static void pl041_isr1_update(pl041_state *s) +static void pl041_isr1_update(PL041State *s) { /* Update ISR1 */ if (s->regs.sr1 & TXUNDERRUN) { @@ -320,7 +324,7 @@ static void pl041_isr1_update(pl041_state *s) static void pl041_request_data(void *opaque) { - pl041_state *s = (pl041_state *)opaque; + PL041State *s = (PL041State *)opaque; /* Trigger pending transfers */ pl041_fifo1_transmit(s); @@ -330,7 +334,7 @@ static void pl041_request_data(void *opaque) static uint64_t pl041_read(void *opaque, hwaddr offset, unsigned size) { - pl041_state *s = (pl041_state *)opaque; + PL041State *s = (PL041State *)opaque; int value; if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) { @@ -364,7 +368,7 @@ static uint64_t pl041_read(void *opaque, hwaddr offset, static void pl041_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl041_state *s = (pl041_state *)opaque; + PL041State *s = (PL041State *)opaque; uint16_t control, data; uint32_t result; @@ -504,7 +508,7 @@ static void pl041_write(void *opaque, hwaddr offset, static void pl041_device_reset(DeviceState *d) { - pl041_state *s = DO_UPCAST(pl041_state, busdev.qdev, d); + PL041State *s = PL041(d); pl041_reset(s); } @@ -517,7 +521,7 @@ static const MemoryRegionOps pl041_ops = { static int pl041_init(SysBusDevice *dev) { - pl041_state *s = FROM_SYSBUS(pl041_state, dev); + PL041State *s = PL041(dev); DBG_L1("pl041_init 0x%08x\n", (uint32_t)s); @@ -603,12 +607,12 @@ static const VMStateDescription vmstate_pl041 = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(fifo_depth, pl041_state), - VMSTATE_STRUCT(regs, pl041_state, 0, + VMSTATE_UINT32(fifo_depth, PL041State), + VMSTATE_STRUCT(regs, PL041State, 0, vmstate_pl041_regfile, pl041_regfile), - VMSTATE_STRUCT(fifo1, pl041_state, 0, + VMSTATE_STRUCT(fifo1, PL041State, 0, vmstate_pl041_channel, pl041_channel), - VMSTATE_STRUCT(codec, pl041_state, 0, + VMSTATE_STRUCT(codec, PL041State, 0, vmstate_lm4549_state, lm4549_state), VMSTATE_END_OF_LIST() } @@ -616,7 +620,8 @@ static const VMStateDescription vmstate_pl041 = { static Property pl041_device_properties[] = { /* Non-compact FIFO depth property */ - DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH), + DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth, + DEFAULT_FIFO_DEPTH), DEFINE_PROP_END_OF_LIST(), }; @@ -626,6 +631,7 @@ static void pl041_device_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pl041_init; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->no_user = 1; dc->reset = pl041_device_reset; dc->vmsd = &vmstate_pl041; @@ -633,9 +639,9 @@ static void pl041_device_class_init(ObjectClass *klass, void *data) } static const TypeInfo pl041_device_info = { - .name = "pl041", + .name = TYPE_PL041, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl041_state), + .instance_size = sizeof(PL041State), .class_init = pl041_device_class_init, }; diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index e697bc1498..db79131cf1 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -768,9 +768,9 @@ static void complete (SB16State *s) } else { if (s->aux_ts) { - qemu_mod_timer ( + timer_mod ( s->aux_ts, - qemu_get_clock_ns (vm_clock) + ticks + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks ); } } @@ -1378,7 +1378,7 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) s->csp_regs[9] = 0xf8; reset_mixer (s); - s->aux_ts = qemu_new_timer_ns (vm_clock, aux_timer, s); + s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s); if (!s->aux_ts) { dolog ("warning: Could not create auxiliary timer\n"); } @@ -1412,6 +1412,7 @@ static void sb16_class_initfn (ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS (klass); dc->realize = sb16_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Creative Sound Blaster 16"; dc->vmsd = &vmstate_sb16; dc->props = sb16_properties; diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index 25acc6722d..bf46f03b7e 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -7,7 +7,6 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o common-obj-$(CONFIG_XEN_BACKEND) += xen_disk.o common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ONENAND) += onenand.o -common-obj-$(CONFIG_PC_SYSFW) += pc_sysfw.o common-obj-$(CONFIG_NVME_PCI) += nvme.o obj-$(CONFIG_SH4) += tc58128.o diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 2faed43127..5a96ccd416 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -18,7 +18,6 @@ #include "qemu/error-report.h" #include "hw/virtio/dataplane/vring.h" #include "ioq.h" -#include "migration/migration.h" #include "block/block.h" #include "hw/virtio/virtio-blk.h" #include "virtio-blk.h" @@ -69,8 +68,6 @@ struct VirtIOBlockDataPlane { queue */ unsigned int num_reqs; - - Error *migration_blocker; }; /* Raise an interrupt to signal guest, if necessary */ @@ -264,11 +261,6 @@ static int process_request(IOQueue *ioq, struct iovec iov[], } } -static int flush_true(EventNotifier *e) -{ - return true; -} - static void handle_notify(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, @@ -348,14 +340,6 @@ static void handle_notify(EventNotifier *e) } } -static int flush_io(EventNotifier *e) -{ - VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, - io_notifier); - - return s->num_reqs > 0; -} - static void handle_io(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, @@ -379,9 +363,9 @@ static void *data_plane_thread(void *opaque) { VirtIOBlockDataPlane *s = opaque; - do { + while (!s->stopping || s->num_reqs > 0) { aio_poll(s->ctx, true); - } while (!s->stopping || s->num_reqs > 0); + } return NULL; } @@ -418,6 +402,14 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, return false; } + /* If dataplane is (re-)enabled while the guest is running there could be + * block jobs that can conflict. + */ + if (bdrv_in_use(blk->conf.bs)) { + error_report("cannot start dataplane thread while device is in use"); + return false; + } + fd = raw_get_aio_fd(blk->conf.bs); if (fd < 0) { error_report("drive is incompatible with x-data-plane, " @@ -433,10 +425,6 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, /* Prevent block operations that conflict with data plane thread */ bdrv_set_in_use(blk->conf.bs, 1); - error_setg(&s->migration_blocker, - "x-data-plane does not support migration"); - migrate_add_blocker(s->migration_blocker); - *dataplane = s; return true; } @@ -448,8 +436,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) } virtio_blk_data_plane_stop(s); - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); bdrv_set_in_use(s->blk->conf.bs, 0); g_free(s); } @@ -486,7 +472,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) exit(1); } s->host_notifier = *virtio_queue_get_host_notifier(vq); - aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify, flush_true); + aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify); /* Set up ioqueue */ ioq_init(&s->ioqueue, s->fd, REQ_MAX); @@ -494,7 +480,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); } s->io_notifier = *ioq_get_notifier(&s->ioqueue); - aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io, flush_io); + aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io); s->started = true; trace_virtio_blk_data_plane_start(s); @@ -526,10 +512,10 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) qemu_thread_join(&s->thread); } - aio_set_event_notifier(s->ctx, &s->io_notifier, NULL, NULL); + aio_set_event_notifier(s->ctx, &s->io_notifier, NULL); ioq_cleanup(&s->ioqueue); - aio_set_event_notifier(s->ctx, &s->host_notifier, NULL, NULL); + aio_set_event_notifier(s->ctx, &s->host_notifier, NULL); k->set_host_notifier(qbus->parent, 0, false); aio_context_unref(s->ctx); diff --git a/hw/block/fdc.c b/hw/block/fdc.c index d32f6ba411..c5a6c21215 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -544,7 +544,7 @@ struct FDCtrl { uint8_t timer1; }; -#define TYPE_SYSBUS_FDC "sysbus-fdc" +#define TYPE_SYSBUS_FDC "base-sysbus-fdc" #define SYSBUS_FDC(obj) OBJECT_CHECK(FDCtrlSysBus, (obj), TYPE_SYSBUS_FDC) typedef struct FDCtrlSysBus { @@ -1647,8 +1647,8 @@ static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction) FDrive *cur_drv = get_cur_drv(fdctrl); cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - qemu_mod_timer(fdctrl->result_timer, - qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50)); + timer_mod(fdctrl->result_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / 50)); } static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction) @@ -2055,7 +2055,7 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, SysBusDevice *sbd; FDCtrlSysBus *sys; - dev = qdev_create(NULL, TYPE_SYSBUS_FDC); + dev = qdev_create(NULL, "sysbus-fdc"); sys = SYSBUS_FDC(dev); fdctrl = &sys->state; fdctrl->dma_chann = dma_chann; /* FIXME */ @@ -2108,7 +2108,7 @@ static void fdctrl_realize_common(FDCtrl *fdctrl, Error **errp) FLOPPY_DPRINTF("init controller\n"); fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN); fdctrl->fifo_size = 512; - fdctrl->result_timer = qemu_new_timer_ns(vm_clock, + fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, fdctrl_result_timer, fdctrl); fdctrl->version = 0x90; /* Intel 82078 controller */ @@ -2153,60 +2153,49 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp) static void sysbus_fdc_initfn(Object *obj) { + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); FDCtrlSysBus *sys = SYSBUS_FDC(obj); FDCtrl *fdctrl = &sys->state; + fdctrl->dma_chann = -1; + memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_ops, fdctrl, "fdc", 0x08); + sysbus_init_mmio(sbd, &fdctrl->iomem); } -static void sysbus_fdc_realize(DeviceState *dev, Error **errp) +static void sun4m_fdc_initfn(Object *obj) { - FDCtrlSysBus *sys = SYSBUS_FDC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + FDCtrlSysBus *sys = SYSBUS_FDC(obj); FDCtrl *fdctrl = &sys->state; - SysBusDevice *b = SYS_BUS_DEVICE(dev); - Error *err = NULL; - sysbus_init_mmio(b, &fdctrl->iomem); - sysbus_init_irq(b, &fdctrl->irq); - qdev_init_gpio_in(dev, fdctrl_handle_tc, 1); - fdctrl->dma_chann = -1; + fdctrl->sun4m = 1; - qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */ - fdctrl_realize_common(fdctrl, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } + memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops, + fdctrl, "fdctrl", 0x08); + sysbus_init_mmio(sbd, &fdctrl->iomem); } -static void sun4m_fdc_initfn(Object *obj) +static void sysbus_fdc_common_initfn(Object *obj) { + DeviceState *dev = DEVICE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); FDCtrlSysBus *sys = SYSBUS_FDC(obj); FDCtrl *fdctrl = &sys->state; - memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops, - fdctrl, "fdctrl", 0x08); + qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */ + + sysbus_init_irq(sbd, &fdctrl->irq); + qdev_init_gpio_in(dev, fdctrl_handle_tc, 1); } -static void sun4m_fdc_realize(DeviceState *dev, Error **errp) +static void sysbus_fdc_common_realize(DeviceState *dev, Error **errp) { FDCtrlSysBus *sys = SYSBUS_FDC(dev); FDCtrl *fdctrl = &sys->state; - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - Error *err = NULL; - sysbus_init_mmio(sbd, &fdctrl->iomem); - sysbus_init_irq(sbd, &fdctrl->irq); - qdev_init_gpio_in(dev, fdctrl_handle_tc, 1); - - fdctrl->sun4m = 1; - qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */ - fdctrl_realize_common(fdctrl, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } + fdctrl_realize_common(fdctrl, errp); } FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i) @@ -2249,6 +2238,7 @@ static void isabus_fdc_class_init(ObjectClass *klass, void *data) dc->reset = fdctrl_external_reset_isa; dc->vmsd = &vmstate_isa_fdc; dc->props = isa_fdc_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo isa_fdc_info = { @@ -2278,16 +2268,13 @@ static void sysbus_fdc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = sysbus_fdc_realize; - dc->reset = fdctrl_external_reset_sysbus; - dc->vmsd = &vmstate_sysbus_fdc; dc->props = sysbus_fdc_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sysbus_fdc_info = { - .name = TYPE_SYSBUS_FDC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(FDCtrlSysBus), + .name = "sysbus-fdc", + .parent = TYPE_SYSBUS_FDC, .instance_init = sysbus_fdc_initfn, .class_init = sysbus_fdc_class_init, }; @@ -2301,23 +2288,39 @@ static void sun4m_fdc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = sun4m_fdc_realize; - dc->reset = fdctrl_external_reset_sysbus; - dc->vmsd = &vmstate_sysbus_fdc; dc->props = sun4m_fdc_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sun4m_fdc_info = { .name = "SUNW,fdtwo", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(FDCtrlSysBus), + .parent = TYPE_SYSBUS_FDC, .instance_init = sun4m_fdc_initfn, .class_init = sun4m_fdc_class_init, }; +static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sysbus_fdc_common_realize; + dc->reset = fdctrl_external_reset_sysbus; + dc->vmsd = &vmstate_sysbus_fdc; +} + +static const TypeInfo sysbus_fdc_type_info = { + .name = TYPE_SYSBUS_FDC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FDCtrlSysBus), + .instance_init = sysbus_fdc_common_initfn, + .abstract = true, + .class_init = sysbus_fdc_common_class_init, +}; + static void fdc_register_types(void) { type_register_static(&isa_fdc_info); + type_register_static(&sysbus_fdc_type_info); type_register_static(&sysbus_fdc_info); type_register_static(&sun4m_fdc_info); } diff --git a/hw/block/nvme.c b/hw/block/nvme.c index f15f04a33c..5dee229734 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -187,7 +187,7 @@ static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req) assert(cq->cqid == req->sq->cqid); QTAILQ_REMOVE(&req->sq->out_req_list, req, entry); QTAILQ_INSERT_TAIL(&cq->req_list, req, entry); - qemu_mod_timer(cq->timer, qemu_get_clock_ns(vm_clock) + 500); + timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); } static void nvme_rw_cb(void *opaque, int ret) @@ -264,8 +264,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) static void nvme_free_sq(NvmeSQueue *sq, NvmeCtrl *n) { n->sq[sq->sqid] = NULL; - qemu_del_timer(sq->timer); - qemu_free_timer(sq->timer); + timer_del(sq->timer); + timer_free(sq->timer); g_free(sq->io_req); if (sq->sqid) { g_free(sq); @@ -327,7 +327,7 @@ static void nvme_init_sq(NvmeSQueue *sq, NvmeCtrl *n, uint64_t dma_addr, sq->io_req[i].sq = sq; QTAILQ_INSERT_TAIL(&(sq->req_list), &sq->io_req[i], entry); } - sq->timer = qemu_new_timer_ns(vm_clock, nvme_process_sq, sq); + sq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_process_sq, sq); assert(n->cq[cqid]); cq = n->cq[cqid]; @@ -369,8 +369,8 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd) static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n) { n->cq[cq->cqid] = NULL; - qemu_del_timer(cq->timer); - qemu_free_timer(cq->timer); + timer_del(cq->timer); + timer_free(cq->timer); msix_vector_unuse(&n->parent_obj, cq->vector); if (cq->cqid) { g_free(cq); @@ -410,7 +410,7 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr, QTAILQ_INIT(&cq->sq_list); msix_vector_use(&n->parent_obj, cq->vector); n->cq[cqid] = cq; - cq->timer = qemu_new_timer_ns(vm_clock, nvme_post_cqes, cq); + cq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_post_cqes, cq); } static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) @@ -691,9 +691,9 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) if (start_sqs) { NvmeSQueue *sq; QTAILQ_FOREACH(sq, &cq->sq_list, entry) { - qemu_mod_timer(sq->timer, qemu_get_clock_ns(vm_clock) + 500); + timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); } - qemu_mod_timer(cq->timer, qemu_get_clock_ns(vm_clock) + 500); + timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); } if (cq->tail != cq->head) { @@ -714,7 +714,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) } sq->tail = new_tail; - qemu_mod_timer(sq->timer, qemu_get_clock_ns(vm_clock) + 500); + timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); } } @@ -866,6 +866,7 @@ static void nvme_class_init(ObjectClass *oc, void *data) pc->revision = 1; pc->is_express = 1; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "Non-Volatile Memory Express"; dc->props = nvme_props; dc->vmsd = &nvme_vmstate; diff --git a/hw/block/onenand.c b/hw/block/onenand.c index 2776f64686..aae9ee7536 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -34,8 +34,12 @@ /* Fixed */ #define BLOCK_SHIFT (PAGE_SHIFT + 6) -typedef struct { - SysBusDevice busdev; +#define TYPE_ONE_NAND "onenand" +#define ONE_NAND(obj) OBJECT_CHECK(OneNANDState, (obj), TYPE_ONE_NAND) + +typedef struct OneNANDState { + SysBusDevice parent_obj; + struct { uint16_t man; uint16_t dev; @@ -226,7 +230,9 @@ static void onenand_reset(OneNANDState *s, int cold) static void onenand_system_reset(DeviceState *dev) { - onenand_reset(FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(dev)), 1); + OneNANDState *s = ONE_NAND(dev); + + onenand_reset(s, 1); } static inline int onenand_load_main(OneNANDState *s, int sec, int secn, @@ -757,11 +763,13 @@ static const MemoryRegionOps onenand_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int onenand_initfn(SysBusDevice *dev) +static int onenand_initfn(SysBusDevice *sbd) { - OneNANDState *s = (OneNANDState *)dev; + DeviceState *dev = DEVICE(sbd); + OneNANDState *s = ONE_NAND(dev); uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7)); void *ram; + s->base = (hwaddr)-1; s->rdy = NULL; s->blocks = size >> BLOCK_SHIFT; @@ -794,9 +802,9 @@ static int onenand_initfn(SysBusDevice *dev) s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift); s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift); onenand_mem_setup(s); - sysbus_init_irq(dev, &s->intr); - sysbus_init_mmio(dev, &s->container); - vmstate_register(&dev->qdev, + sysbus_init_irq(sbd, &s->intr); + sysbus_init_mmio(sbd, &s->container); + vmstate_register(dev, ((s->shift & 0x7f) << 24) | ((s->id.man & 0xff) << 16) | ((s->id.dev & 0xff) << 8) @@ -825,7 +833,7 @@ static void onenand_class_init(ObjectClass *klass, void *data) } static const TypeInfo onenand_info = { - .name = "onenand", + .name = TYPE_ONE_NAND, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OneNANDState), .class_init = onenand_class_init, @@ -838,7 +846,9 @@ static void onenand_register_types(void) void *onenand_raw_otp(DeviceState *onenand_device) { - return FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(onenand_device))->otp; + OneNANDState *s = ONE_NAND(onenand_device); + + return s->otp; } type_init(onenand_register_types) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 2bcd7318bc..018a9677ba 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -192,6 +192,9 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, case 0xe8: /* Write block */ /* Status register read */ ret = pfl->status; + if (width > 2) { + ret |= pfl->status << 16; + } DPRINTF("%s: status %x\n", __func__, ret); break; case 0x90: @@ -610,7 +613,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->ro = 0; } - pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl); + pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->wcycle = 0; pfl->cmd = 0; pfl->status = 0; @@ -720,6 +723,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) dc->realize = pflash_cfi01_realize; dc->props = pflash_cfi01_properties; dc->vmsd = &vmstate_pflash; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 9fc02e3d64..99445b09b9 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -430,8 +430,8 @@ static void pflash_write (pflash_t *pfl, hwaddr offset, } pfl->status = 0x00; /* Let's wait 5 seconds before chip erase is done */ - qemu_mod_timer(pfl->timer, - qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5)); + timer_mod(pfl->timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() * 5)); break; case 0x30: /* Sector erase */ @@ -445,8 +445,8 @@ static void pflash_write (pflash_t *pfl, hwaddr offset, } pfl->status = 0x00; /* Let's wait 1/2 second before sector erase is done */ - qemu_mod_timer(pfl->timer, - qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2)); + timer_mod(pfl->timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / 2)); break; default: DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd); @@ -633,7 +633,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) pfl->ro = 0; } - pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl); + pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->wcycle = 0; pfl->cmd = 0; pfl->status = 0; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index cf12469b50..e2f55cc946 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -19,6 +19,7 @@ #include "hw/virtio/virtio-blk.h" #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE # include "dataplane/virtio-blk.h" +# include "migration/migration.h" #endif #include "block/scsi.h" #ifdef __linux__ @@ -628,6 +629,34 @@ void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk) memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf)); } +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE +/* Disable dataplane thread during live migration since it does not + * update the dirty memory bitmap yet. + */ +static void virtio_blk_migration_state_changed(Notifier *notifier, void *data) +{ + VirtIOBlock *s = container_of(notifier, VirtIOBlock, + migration_state_notifier); + MigrationState *mig = data; + + if (migration_in_setup(mig)) { + if (!s->dataplane) { + return; + } + virtio_blk_data_plane_destroy(s->dataplane); + s->dataplane = NULL; + } else if (migration_has_finished(mig) || + migration_has_failed(mig)) { + if (s->dataplane) { + return; + } + bdrv_drain_all(); /* complete in-flight non-dataplane requests */ + virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->blk, + &s->dataplane); + } +} +#endif /* CONFIG_VIRTIO_BLK_DATA_PLANE */ + static int virtio_blk_device_init(VirtIODevice *vdev) { DeviceState *qdev = DEVICE(vdev); @@ -664,6 +693,8 @@ static int virtio_blk_device_init(VirtIODevice *vdev) virtio_cleanup(vdev); return -1; } + s->migration_state_notifier.notify = virtio_blk_migration_state_changed; + add_migration_state_change_notifier(&s->migration_state_notifier); #endif s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); @@ -683,6 +714,7 @@ static int virtio_blk_device_exit(DeviceState *dev) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + remove_migration_state_change_notifier(&s->migration_state_notifier); virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; #endif @@ -704,6 +736,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_blk_device_exit; dc->props = virtio_blk_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = virtio_blk_device_init; vdc->get_config = virtio_blk_update_config; vdc->set_config = virtio_blk_set_config; diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 247f32f4ee..727f4331c0 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -93,6 +93,7 @@ struct XenBlkDev { char *type; char *dev; char *devtype; + bool directiosafe; const char *fileproto; const char *filename; int ring_ref; @@ -701,6 +702,7 @@ static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); int info = 0; + char *directiosafe = NULL; /* read xenstore entries */ if (blkdev->params == NULL) { @@ -733,6 +735,8 @@ static int blk_init(struct XenDevice *xendev) if (blkdev->devtype == NULL) { blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type"); } + directiosafe = xenstore_read_be_str(&blkdev->xendev, "direct-io-safe"); + blkdev->directiosafe = (directiosafe && atoi(directiosafe)); /* do we have all we need? */ if (blkdev->params == NULL || @@ -760,6 +764,8 @@ static int blk_init(struct XenDevice *xendev) xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1); xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); xenstore_write_be_int(&blkdev->xendev, "info", info); + + g_free(directiosafe); return 0; out_error: @@ -773,6 +779,8 @@ out_error: blkdev->dev = NULL; g_free(blkdev->devtype); blkdev->devtype = NULL; + g_free(directiosafe); + blkdev->directiosafe = false; return -1; } @@ -783,7 +791,11 @@ static int blk_connect(struct XenDevice *xendev) bool readonly = true; /* read-only ? */ - qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO; + if (blkdev->directiosafe) { + qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO; + } else { + qflags = BDRV_O_CACHE_WB; + } if (strcmp(blkdev->mode, "w") == 0) { qflags |= BDRV_O_RDWR; readonly = false; diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c index 16a25cb349..7b9b91608a 100644 --- a/hw/bt/hci-csr.c +++ b/hw/bt/hci-csr.c @@ -87,7 +87,7 @@ static inline void csrhci_fifo_wake(struct csrhci_s *s) } if (s->out_len) - qemu_mod_timer(s->out_tm, qemu_get_clock_ns(vm_clock) + s->baud_delay); + timer_mod(s->out_tm, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->baud_delay); } #define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len) @@ -446,7 +446,7 @@ CharDriverState *uart_hci_init(qemu_irq wakeup) s->hci->evt_recv = csrhci_out_hci_packet_event; s->hci->acl_recv = csrhci_out_hci_packet_acl; - s->out_tm = qemu_new_timer_ns(vm_clock, csrhci_out_tick, s); + s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s); s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins); csrhci_reset(s); diff --git a/hw/bt/hci.c b/hw/bt/hci.c index b53cd5dea2..d1c0604a9b 100644 --- a/hw/bt/hci.c +++ b/hw/bt/hci.c @@ -576,7 +576,7 @@ static void bt_hci_inquiry_result(struct bt_hci_s *hci, static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period) { - qemu_mod_timer(timer, qemu_get_clock_ns(vm_clock) + + timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(period << 7, get_ticks_per_sec(), 100)); } @@ -657,7 +657,7 @@ static void bt_hci_lmp_link_establish(struct bt_hci_s *hci, if (master) { link->acl_mode = acl_active; hci->lm.handle[hci->lm.last_handle].acl_mode_timer = - qemu_new_timer_ns(vm_clock, bt_hci_mode_tick, link); + timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_mode_tick, link); } } @@ -667,8 +667,8 @@ static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle) hci->lm.handle[handle].link = NULL; if (bt_hci_role_master(hci, handle)) { - qemu_del_timer(hci->lm.handle[handle].acl_mode_timer); - qemu_free_timer(hci->lm.handle[handle].acl_mode_timer); + timer_del(hci->lm.handle[handle].acl_mode_timer); + timer_free(hci->lm.handle[handle].acl_mode_timer); } } @@ -1080,7 +1080,7 @@ static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle, bt_hci_event_status(hci, HCI_SUCCESS); - qemu_mod_timer(link->acl_mode_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(link->acl_mode_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(interval * 625, get_ticks_per_sec(), 1000000)); bt_hci_lmp_mode_change_master(hci, link->link, mode, interval); @@ -1103,7 +1103,7 @@ static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode) bt_hci_event_status(hci, HCI_SUCCESS); - qemu_del_timer(link->acl_mode_timer); + timer_del(link->acl_mode_timer); bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0); return 0; @@ -1146,10 +1146,10 @@ static void bt_hci_reset(struct bt_hci_s *hci) hci->psb_handle = 0x000; hci->asb_handle = 0x000; - /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */ - qemu_del_timer(hci->lm.inquiry_done); - qemu_del_timer(hci->lm.inquiry_next); - qemu_del_timer(hci->conn_accept_timer); + /* XXX: timer_del(sl->acl_mode_timer); for all links */ + timer_del(hci->lm.inquiry_done); + timer_del(hci->lm.inquiry_next); + timer_del(hci->conn_accept_timer); } static void bt_hci_read_local_version_rp(struct bt_hci_s *hci) @@ -1514,7 +1514,7 @@ static void bt_submit_hci(struct HCIInfo *info, } hci->lm.inquire = 0; - qemu_del_timer(hci->lm.inquiry_done); + timer_del(hci->lm.inquiry_done); bt_hci_event_complete_status(hci, HCI_SUCCESS); break; @@ -1552,8 +1552,8 @@ static void bt_submit_hci(struct HCIInfo *info, break; } hci->lm.inquire = 0; - qemu_del_timer(hci->lm.inquiry_done); - qemu_del_timer(hci->lm.inquiry_next); + timer_del(hci->lm.inquiry_done); + timer_del(hci->lm.inquiry_next); bt_hci_event_complete_status(hci, HCI_SUCCESS); break; @@ -2141,10 +2141,10 @@ struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net) { struct bt_hci_s *s = g_malloc0(sizeof(struct bt_hci_s)); - s->lm.inquiry_done = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_done, s); - s->lm.inquiry_next = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_next, s); + s->lm.inquiry_done = timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_inquiry_done, s); + s->lm.inquiry_next = timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_inquiry_next, s); s->conn_accept_timer = - qemu_new_timer_ns(vm_clock, bt_hci_conn_accept_timeout, s); + timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_conn_accept_timeout, s); s->evt_packet = bt_hci_evt_packet; s->evt_submit = bt_hci_evt_submit; @@ -2209,9 +2209,9 @@ static void bt_hci_done(struct HCIInfo *info) * s->device.lmp_connection_complete to free the remaining bits once * hci->lm.awaiting_bdaddr[] is empty. */ - qemu_free_timer(hci->lm.inquiry_done); - qemu_free_timer(hci->lm.inquiry_next); - qemu_free_timer(hci->conn_accept_timer); + timer_free(hci->lm.inquiry_done); + timer_free(hci->lm.inquiry_next); + timer_free(hci->conn_accept_timer); g_free(hci); } diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c index 521587a112..2301d6f87f 100644 --- a/hw/bt/l2cap.c +++ b/hw/bt/l2cap.c @@ -166,9 +166,9 @@ static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch) { #if 0 if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit) - qemu_mod_timer(ch->retransmission_timer); + timer_mod(ch->retransmission_timer); else - qemu_del_timer(ch->retransmission_timer); + timer_del(ch->retransmission_timer); #endif } @@ -176,9 +176,9 @@ static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch) { #if 0 if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit) - qemu_mod_timer(ch->monitor_timer); + timer_mod(ch->monitor_timer); else - qemu_del_timer(ch->monitor_timer); + timer_del(ch->monitor_timer); #endif } diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 4d457f8c65..f8ccbdd13a 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -106,8 +106,12 @@ #define R_MAX (R_TTRIG + 1) +#define TYPE_CADENCE_UART "cadence_uart" +#define CADENCE_UART(obj) OBJECT_CHECK(UartState, (obj), TYPE_CADENCE_UART) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t r[R_MAX]; uint8_t r_fifo[RX_FIFO_SIZE]; @@ -137,9 +141,9 @@ static void fifo_trigger_update(void *opaque) static void uart_tx_redo(UartState *s) { - uint64_t new_tx_time = qemu_get_clock_ns(vm_clock); + uint64_t new_tx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - qemu_mod_timer(s->tx_time_handle, new_tx_time + s->char_tx_time); + timer_mod(s->tx_time_handle, new_tx_time + s->char_tx_time); s->r[R_SR] |= UART_SR_INTR_TEMPTY; @@ -261,7 +265,7 @@ static void uart_ctrl_update(UartState *s) static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) { UartState *s = (UartState *)opaque; - uint64_t new_rx_time = qemu_get_clock_ns(vm_clock); + uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int i; if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { @@ -287,7 +291,7 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) s->r[R_SR] |= UART_SR_INTR_RTRIG; } } - qemu_mod_timer(s->fifo_trigger_handle, new_rx_time + + timer_mod(s->fifo_trigger_handle, new_rx_time + (s->char_tx_time * 4)); } uart_update_status(s); @@ -442,16 +446,16 @@ static void cadence_uart_reset(UartState *s) static int cadence_uart_init(SysBusDevice *dev) { - UartState *s = FROM_SYSBUS(UartState, dev); + UartState *s = CADENCE_UART(dev); memory_region_init_io(&s->iomem, OBJECT(s), &uart_ops, s, "uart", 0x1000); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); - s->fifo_trigger_handle = qemu_new_timer_ns(vm_clock, + s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *)fifo_trigger_update, s); - s->tx_time_handle = qemu_new_timer_ns(vm_clock, + s->tx_time_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *)uart_tx_write, s); s->char_tx_time = (get_ticks_per_sec() / 9600) * 10; @@ -504,7 +508,7 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data) } static const TypeInfo cadence_uart_info = { - .name = "cadence_uart", + .name = TYPE_CADENCE_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UartState), .class_init = cadence_uart_class_init, diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c index 03db12fda8..02d0d57a79 100644 --- a/hw/char/debugcon.c +++ b/hw/char/debugcon.c @@ -122,6 +122,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) dc->realize = debugcon_isa_realizefn; dc->props = debugcon_isa_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo debugcon_isa_info = { diff --git a/hw/char/escc.c b/hw/char/escc.c index 4c42198cbe..6397f6f282 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -96,8 +96,11 @@ typedef struct ChannelState { uint8_t rx, tx; } ChannelState; +#define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC) + typedef struct ESCCState { - SysBusDevice busdev; + SysBusDevice parent_obj; + struct ChannelState chn[2]; uint32_t it_shift; MemoryRegion mmio; @@ -309,7 +312,7 @@ static void escc_reset_chn(ChannelState *s) static void escc_reset(DeviceState *d) { - ESCCState *s = container_of(d, ESCCState, busdev.qdev); + ESCCState *s = ESCC(d); escc_reset_chn(&s->chn[0]); escc_reset_chn(&s->chn[1]); @@ -534,7 +537,7 @@ static void escc_mem_write(void *opaque, hwaddr addr, escc_reset_chn(&serial->chn[1]); return; case MINTR_RST_ALL: - escc_reset(&serial->busdev.qdev); + escc_reset(DEVICE(serial)); return; } break; @@ -691,7 +694,7 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, SysBusDevice *s; ESCCState *d; - dev = qdev_create(NULL, "escc"); + dev = qdev_create(NULL, TYPE_ESCC); qdev_prop_set_uint32(dev, "disabled", 0); qdev_prop_set_uint32(dev, "frequency", clock); qdev_prop_set_uint32(dev, "it_shift", it_shift); @@ -707,7 +710,7 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, sysbus_mmio_map(s, 0, base); } - d = FROM_SYSBUS(ESCCState, s); + d = ESCC(s); return &d->mmio; } @@ -852,7 +855,7 @@ void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "escc"); + dev = qdev_create(NULL, TYPE_ESCC); qdev_prop_set_uint32(dev, "disabled", disabled); qdev_prop_set_uint32(dev, "frequency", clock); qdev_prop_set_uint32(dev, "it_shift", it_shift); @@ -869,7 +872,7 @@ void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, static int escc_init1(SysBusDevice *dev) { - ESCCState *s = FROM_SYSBUS(ESCCState, dev); + ESCCState *s = ESCC(dev); unsigned int i; s->chn[0].disabled = s->disabled; @@ -924,7 +927,7 @@ static void escc_class_init(ObjectClass *klass, void *data) } static const TypeInfo escc_info = { - .name = "escc", + .name = TYPE_ESCC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ESCCState), .class_init = escc_class_init, diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c index d19af000a3..460094e79e 100644 --- a/hw/char/etraxfs_ser.c +++ b/hw/char/etraxfs_ser.c @@ -44,9 +44,13 @@ #define STAT_TR_IDLE 22 #define STAT_TR_RDY 24 -struct etrax_serial -{ - SysBusDevice busdev; +#define TYPE_ETRAX_FS_SERIAL "etraxfs,serial" +#define ETRAX_SERIAL(obj) \ + OBJECT_CHECK(ETRAXSerial, (obj), TYPE_ETRAX_FS_SERIAL) + +typedef struct ETRAXSerial { + SysBusDevice parent_obj; + MemoryRegion mmio; CharDriverState *chr; qemu_irq irq; @@ -59,9 +63,9 @@ struct etrax_serial /* Control registers. */ uint32_t regs[R_MAX]; -}; +} ETRAXSerial; -static void ser_update_irq(struct etrax_serial *s) +static void ser_update_irq(ETRAXSerial *s) { if (s->rx_fifo_len) { @@ -77,7 +81,7 @@ static void ser_update_irq(struct etrax_serial *s) static uint64_t ser_read(void *opaque, hwaddr addr, unsigned int size) { - struct etrax_serial *s = opaque; + ETRAXSerial *s = opaque; uint32_t r = 0; addr >>= 2; @@ -112,7 +116,7 @@ static void ser_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct etrax_serial *s = opaque; + ETRAXSerial *s = opaque; uint32_t value = val64; unsigned char ch = val64; @@ -156,7 +160,7 @@ static const MemoryRegionOps ser_ops = { static void serial_receive(void *opaque, const uint8_t *buf, int size) { - struct etrax_serial *s = opaque; + ETRAXSerial *s = opaque; int i; /* Got a byte. */ @@ -177,7 +181,7 @@ static void serial_receive(void *opaque, const uint8_t *buf, int size) static int serial_can_receive(void *opaque) { - struct etrax_serial *s = opaque; + ETRAXSerial *s = opaque; int r; /* Is the receiver enabled? */ @@ -196,7 +200,7 @@ static void serial_event(void *opaque, int event) static void etraxfs_ser_reset(DeviceState *d) { - struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev); + ETRAXSerial *s = ETRAX_SERIAL(d); /* transmitter begins ready and idle. */ s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY); @@ -208,7 +212,7 @@ static void etraxfs_ser_reset(DeviceState *d) static int etraxfs_ser_init(SysBusDevice *dev) { - struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); + ETRAXSerial *s = ETRAX_SERIAL(dev); sysbus_init_irq(dev, &s->irq); memory_region_init_io(&s->mmio, OBJECT(s), &ser_ops, s, @@ -216,10 +220,11 @@ static int etraxfs_ser_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->mmio); s->chr = qemu_char_get_next_serial(); - if (s->chr) + if (s->chr) { qemu_chr_add_handlers(s->chr, - serial_can_receive, serial_receive, - serial_event, s); + serial_can_receive, serial_receive, + serial_event, s); + } return 0; } @@ -233,9 +238,9 @@ static void etraxfs_ser_class_init(ObjectClass *klass, void *data) } static const TypeInfo etraxfs_ser_info = { - .name = "etraxfs,serial", + .name = TYPE_ETRAX_FS_SERIAL, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct etrax_serial), + .instance_size = sizeof(ETRAXSerial), .class_init = etraxfs_ser_class_init, }; diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 855ce7a2e4..eef23a0ccc 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -166,8 +166,13 @@ typedef struct { uint32_t size; } Exynos4210UartFIFO; -typedef struct { - SysBusDevice busdev; +#define TYPE_EXYNOS4210_UART "exynos4210.uart" +#define EXYNOS4210_UART(obj) \ + OBJECT_CHECK(Exynos4210UartState, (obj), TYPE_EXYNOS4210_UART) + +typedef struct Exynos4210UartState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)]; @@ -538,8 +543,7 @@ static void exynos4210_uart_event(void *opaque, int event) static void exynos4210_uart_reset(DeviceState *dev) { - Exynos4210UartState *s = - container_of(dev, Exynos4210UartState, busdev.qdev); + Exynos4210UartState *s = EXYNOS4210_UART(dev); int regs_number = sizeof(exynos4210_uart_regs)/sizeof(Exynos4210UartReg); int i; @@ -582,10 +586,10 @@ static const VMStateDescription vmstate_exynos4210_uart = { }; DeviceState *exynos4210_uart_create(hwaddr addr, - int fifo_size, - int channel, - CharDriverState *chr, - qemu_irq irq) + int fifo_size, + int channel, + CharDriverState *chr, + qemu_irq irq) { DeviceState *dev; SysBusDevice *bus; @@ -593,7 +597,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr, const char chr_name[] = "serial"; char label[ARRAY_SIZE(chr_name) + 1]; - dev = qdev_create(NULL, "exynos4210.uart"); + dev = qdev_create(NULL, TYPE_EXYNOS4210_UART); if (!chr) { if (channel >= MAX_SERIAL_PORTS) { @@ -627,7 +631,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr, static int exynos4210_uart_init(SysBusDevice *dev) { - Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev); + Exynos4210UartState *s = EXYNOS4210_UART(dev); /* memory mapping */ memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s, @@ -662,7 +666,7 @@ static void exynos4210_uart_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_uart_info = { - .name = "exynos4210.uart", + .name = TYPE_EXYNOS4210_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210UartState), .class_init = exynos4210_uart_class_init, diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c index 82e1b95bcd..35ef661771 100644 --- a/hw/char/grlib_apbuart.c +++ b/hw/char/grlib_apbuart.c @@ -67,8 +67,13 @@ #define FIFO_LENGTH 1024 +#define TYPE_GRLIB_APB_UART "grlib,apbuart" +#define GRLIB_APB_UART(obj) \ + OBJECT_CHECK(UART, (obj), TYPE_GRLIB_APB_UART) + typedef struct UART { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; @@ -232,7 +237,7 @@ static const MemoryRegionOps grlib_apbuart_ops = { static int grlib_apbuart_init(SysBusDevice *dev) { - UART *uart = FROM_SYSBUS(typeof(*uart), dev); + UART *uart = GRLIB_APB_UART(dev); qemu_chr_add_handlers(uart->chr, grlib_apbuart_can_receive, @@ -252,7 +257,7 @@ static int grlib_apbuart_init(SysBusDevice *dev) static void grlib_apbuart_reset(DeviceState *d) { - UART *uart = container_of(d, UART, busdev.qdev); + UART *uart = GRLIB_APB_UART(d); /* Transmitter FIFO and shift registers are always empty in QEMU */ uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY; @@ -279,7 +284,7 @@ static void grlib_apbuart_class_init(ObjectClass *klass, void *data) } static const TypeInfo grlib_apbuart_info = { - .name = "grlib,apbuart", + .name = TYPE_GRLIB_APB_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UART), .class_init = grlib_apbuart_class_init, diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 69b9ed2c4d..7f16835aeb 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -43,8 +43,12 @@ do { printf("imx_serial: " fmt , ##args); } while (0) # define IPRINTF(fmt, args...) do {} while (0) #endif -typedef struct { - SysBusDevice busdev; +#define TYPE_IMX_SERIAL "imx-serial" +#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL) + +typedef struct IMXSerialState { + SysBusDevice parent_obj; + MemoryRegion iomem; int32_t readbuff; @@ -169,7 +173,7 @@ static void imx_serial_reset(IMXSerialState *s) static void imx_serial_reset_at_boot(DeviceState *dev) { - IMXSerialState *s = container_of(dev, IMXSerialState, busdev.qdev); + IMXSerialState *s = IMX_SERIAL(dev); imx_serial_reset(s); @@ -383,7 +387,7 @@ static const struct MemoryRegionOps imx_serial_ops = { static int imx_serial_init(SysBusDevice *dev) { - IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev); + IMXSerialState *s = IMX_SERIAL(dev); memory_region_init_io(&s->iomem, OBJECT(s), &imx_serial_ops, s, @@ -410,7 +414,7 @@ void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq) const char chr_name[] = "serial"; char label[ARRAY_SIZE(chr_name) + 1]; - dev = qdev_create(NULL, "imx-serial"); + dev = qdev_create(NULL, TYPE_IMX_SERIAL); if (uart >= MAX_SERIAL_PORTS) { hw_error("Cannot assign uart %d: QEMU supports only %d ports\n", @@ -449,12 +453,13 @@ static void imx_serial_class_init(ObjectClass *klass, void *data) k->init = imx_serial_init; dc->vmsd = &vmstate_imx_serial; dc->reset = imx_serial_reset_at_boot; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "i.MX series UART"; dc->props = imx32_serial_properties; } static const TypeInfo imx_serial_info = { - .name = "imx-serial", + .name = TYPE_IMX_SERIAL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXSerialState), .class_init = imx_serial_class_init, diff --git a/hw/char/ipack.c b/hw/char/ipack.c index e15540d5cd..f890471db5 100644 --- a/hw/char/ipack.c +++ b/hw/char/ipack.c @@ -74,6 +74,7 @@ static Property ipack_device_props[] = { static void ipack_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_INPUT, k->categories); k->bus_type = TYPE_IPACK_BUS; k->init = ipack_device_dev_init; k->exit = ipack_device_dev_exit; diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index c9698a6bc4..88e2ccae75 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -585,6 +585,7 @@ static void ipoctal_class_init(ObjectClass *klass, void *data) ic->mem_read8 = mem_read8; ic->mem_write8 = mem_write8; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "GE IP-Octal 232 8-channel RS-232 IndustryPack"; dc->props = ipoctal_properties; dc->vmsd = &vmstate_ipoctal; diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c index 839f3ebfe7..252fe46daf 100644 --- a/hw/char/lm32_juart.c +++ b/hw/char/lm32_juart.c @@ -22,7 +22,7 @@ #include "trace.h" #include "sysemu/char.h" -#include "hw/lm32/lm32_juart.h" +#include "hw/char/lm32_juart.h" enum { LM32_JUART_MIN_SAVE_VERSION = 0, @@ -38,8 +38,11 @@ enum { JRX_FULL = (1<<8), }; +#define LM32_JUART(obj) OBJECT_CHECK(LM32JuartState, (obj), TYPE_LM32_JUART) + struct LM32JuartState { - SysBusDevice busdev; + SysBusDevice parent_obj; + CharDriverState *chr; uint32_t jtx; @@ -49,7 +52,7 @@ typedef struct LM32JuartState LM32JuartState; uint32_t lm32_juart_get_jtx(DeviceState *d) { - LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev); + LM32JuartState *s = LM32_JUART(d); trace_lm32_juart_get_jtx(s->jtx); return s->jtx; @@ -57,7 +60,7 @@ uint32_t lm32_juart_get_jtx(DeviceState *d) uint32_t lm32_juart_get_jrx(DeviceState *d) { - LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev); + LM32JuartState *s = LM32_JUART(d); trace_lm32_juart_get_jrx(s->jrx); return s->jrx; @@ -65,7 +68,7 @@ uint32_t lm32_juart_get_jrx(DeviceState *d) void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) { - LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev); + LM32JuartState *s = LM32_JUART(d); unsigned char ch = jtx & 0xff; trace_lm32_juart_set_jtx(s->jtx); @@ -78,7 +81,7 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx) { - LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev); + LM32JuartState *s = LM32_JUART(d); trace_lm32_juart_set_jrx(s->jrx); s->jrx &= ~JRX_FULL; @@ -104,7 +107,7 @@ static void juart_event(void *opaque, int event) static void juart_reset(DeviceState *d) { - LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev); + LM32JuartState *s = LM32_JUART(d); s->jtx = 0; s->jrx = 0; @@ -112,7 +115,7 @@ static void juart_reset(DeviceState *d) static int lm32_juart_init(SysBusDevice *dev) { - LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev); + LM32JuartState *s = LM32_JUART(dev); s->chr = qemu_char_get_next_serial(); if (s->chr) { @@ -145,7 +148,7 @@ static void lm32_juart_class_init(ObjectClass *klass, void *data) } static const TypeInfo lm32_juart_info = { - .name = "lm32-juart", + .name = TYPE_LM32_JUART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32JuartState), .class_init = lm32_juart_class_init, diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c index 37b38ba4ed..85d726508b 100644 --- a/hw/char/lm32_uart.c +++ b/hw/char/lm32_uart.c @@ -89,8 +89,12 @@ enum { MSR_DCD = (1<<7), }; +#define TYPE_LM32_UART "lm32-uart" +#define LM32_UART(obj) OBJECT_CHECK(LM32UartState, (obj), TYPE_LM32_UART) + struct LM32UartState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; CharDriverState *chr; qemu_irq irq; @@ -233,7 +237,7 @@ static void uart_event(void *opaque, int event) static void uart_reset(DeviceState *d) { - LM32UartState *s = container_of(d, LM32UartState, busdev.qdev); + LM32UartState *s = LM32_UART(d); int i; for (i = 0; i < R_MAX; i++) { @@ -246,7 +250,7 @@ static void uart_reset(DeviceState *d) static int lm32_uart_init(SysBusDevice *dev) { - LM32UartState *s = FROM_SYSBUS(typeof(*s), dev); + LM32UartState *s = LM32_UART(dev); sysbus_init_irq(dev, &s->irq); @@ -284,7 +288,7 @@ static void lm32_uart_class_init(ObjectClass *klass, void *data) } static const TypeInfo lm32_uart_info = { - .name = "lm32-uart", + .name = TYPE_LM32_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32UartState), .class_init = lm32_uart_class_init, diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c index 46deab2c51..2e4b5c58b0 100644 --- a/hw/char/milkymist-uart.c +++ b/hw/char/milkymist-uart.c @@ -52,8 +52,13 @@ enum { DBG_BREAK_EN = (1<<0), }; +#define TYPE_MILKYMIST_UART "milkymist-uart" +#define MILKYMIST_UART(obj) \ + OBJECT_CHECK(MilkymistUartState, (obj), TYPE_MILKYMIST_UART) + struct MilkymistUartState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; CharDriverState *chr; qemu_irq irq; @@ -179,7 +184,7 @@ static void uart_event(void *opaque, int event) static void milkymist_uart_reset(DeviceState *d) { - MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev); + MilkymistUartState *s = MILKYMIST_UART(d); int i; for (i = 0; i < R_MAX; i++) { @@ -192,12 +197,12 @@ static void milkymist_uart_reset(DeviceState *d) static int milkymist_uart_init(SysBusDevice *dev) { - MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistUartState *s = MILKYMIST_UART(dev); sysbus_init_irq(dev, &s->irq); memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, - "milkymist-uart", R_MAX * 4); + "milkymist-uart", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); s->chr = qemu_char_get_next_serial(); @@ -230,7 +235,7 @@ static void milkymist_uart_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_uart_info = { - .name = "milkymist-uart", + .name = TYPE_MILKYMIST_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistUartState), .class_init = milkymist_uart_class_init, diff --git a/hw/char/parallel.c b/hw/char/parallel.c index ad96ea59c6..7a3b2647cf 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -607,6 +607,7 @@ static void parallel_isa_class_initfn(ObjectClass *klass, void *data) dc->realize = parallel_isa_realizefn; dc->props = parallel_isa_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo parallel_isa_info = { diff --git a/hw/char/pl011.c b/hw/char/pl011.c index ebec64f952..a8ae6f4706 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -10,8 +10,12 @@ #include "hw/sysbus.h" #include "sysemu/char.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_PL011 "pl011" +#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) + +typedef struct PL011State { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t readbuff; uint32_t flags; @@ -31,7 +35,7 @@ typedef struct { CharDriverState *chr; qemu_irq irq; const unsigned char *id; -} pl011_state; +} PL011State; #define PL011_INT_TX 0x20 #define PL011_INT_RX 0x10 @@ -46,7 +50,7 @@ static const unsigned char pl011_id_arm[8] = static const unsigned char pl011_id_luminary[8] = { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; -static void pl011_update(pl011_state *s) +static void pl011_update(PL011State *s) { uint32_t flags; @@ -57,7 +61,7 @@ static void pl011_update(pl011_state *s) static uint64_t pl011_read(void *opaque, hwaddr offset, unsigned size) { - pl011_state *s = (pl011_state *)opaque; + PL011State *s = (PL011State *)opaque; uint32_t c; if (offset >= 0xfe0 && offset < 0x1000) { @@ -113,7 +117,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, } } -static void pl011_set_read_trigger(pl011_state *s) +static void pl011_set_read_trigger(PL011State *s) { #if 0 /* The docs say the RX interrupt is triggered when the FIFO exceeds @@ -130,7 +134,7 @@ static void pl011_set_read_trigger(pl011_state *s) static void pl011_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl011_state *s = (pl011_state *)opaque; + PL011State *s = (PL011State *)opaque; unsigned char ch; switch (offset >> 2) { @@ -191,7 +195,7 @@ static void pl011_write(void *opaque, hwaddr offset, static int pl011_can_receive(void *opaque) { - pl011_state *s = (pl011_state *)opaque; + PL011State *s = (PL011State *)opaque; if (s->lcr & 0x10) return s->read_count < 16; @@ -201,7 +205,7 @@ static int pl011_can_receive(void *opaque) static void pl011_put_fifo(void *opaque, uint32_t value) { - pl011_state *s = (pl011_state *)opaque; + PL011State *s = (PL011State *)opaque; int slot; slot = s->read_pos + s->read_count; @@ -242,83 +246,81 @@ static const VMStateDescription vmstate_pl011 = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(readbuff, pl011_state), - VMSTATE_UINT32(flags, pl011_state), - VMSTATE_UINT32(lcr, pl011_state), - VMSTATE_UINT32(cr, pl011_state), - VMSTATE_UINT32(dmacr, pl011_state), - VMSTATE_UINT32(int_enabled, pl011_state), - VMSTATE_UINT32(int_level, pl011_state), - VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16), - VMSTATE_UINT32(ilpr, pl011_state), - VMSTATE_UINT32(ibrd, pl011_state), - VMSTATE_UINT32(fbrd, pl011_state), - VMSTATE_UINT32(ifl, pl011_state), - VMSTATE_INT32(read_pos, pl011_state), - VMSTATE_INT32(read_count, pl011_state), - VMSTATE_INT32(read_trigger, pl011_state), + VMSTATE_UINT32(readbuff, PL011State), + VMSTATE_UINT32(flags, PL011State), + VMSTATE_UINT32(lcr, PL011State), + VMSTATE_UINT32(cr, PL011State), + VMSTATE_UINT32(dmacr, PL011State), + VMSTATE_UINT32(int_enabled, PL011State), + VMSTATE_UINT32(int_level, PL011State), + VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16), + VMSTATE_UINT32(ilpr, PL011State), + VMSTATE_UINT32(ibrd, PL011State), + VMSTATE_UINT32(fbrd, PL011State), + VMSTATE_UINT32(ifl, PL011State), + VMSTATE_INT32(read_pos, PL011State), + VMSTATE_INT32(read_count, PL011State), + VMSTATE_INT32(read_trigger, PL011State), VMSTATE_END_OF_LIST() } }; -static int pl011_init(SysBusDevice *dev, const unsigned char *id) +static void pl011_init(Object *obj) { - pl011_state *s = FROM_SYSBUS(pl011_state, dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + PL011State *s = PL011(obj); memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - s->id = id; - s->chr = qemu_char_get_next_serial(); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); s->read_trigger = 1; s->ifl = 0x12; s->cr = 0x300; s->flags = 0x90; - if (s->chr) { - qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, - pl011_event, s); - } - vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); - return 0; -} -static int pl011_arm_init(SysBusDevice *dev) -{ - return pl011_init(dev, pl011_id_arm); + s->id = pl011_id_arm; } -static int pl011_luminary_init(SysBusDevice *dev) +static void pl011_realize(DeviceState *dev, Error **errp) { - return pl011_init(dev, pl011_id_luminary); + PL011State *s = PL011(dev); + + s->chr = qemu_char_get_next_serial(); + + if (s->chr) { + qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, + pl011_event, s); + } } -static void pl011_arm_class_init(ObjectClass *klass, void *data) +static void pl011_class_init(ObjectClass *oc, void *data) { - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(oc); - sdc->init = pl011_arm_init; + dc->realize = pl011_realize; + dc->vmsd = &vmstate_pl011; } static const TypeInfo pl011_arm_info = { - .name = "pl011", + .name = TYPE_PL011, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl011_state), - .class_init = pl011_arm_class_init, + .instance_size = sizeof(PL011State), + .instance_init = pl011_init, + .class_init = pl011_class_init, }; -static void pl011_luminary_class_init(ObjectClass *klass, void *data) +static void pl011_luminary_init(Object *obj) { - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + PL011State *s = PL011(obj); - sdc->init = pl011_luminary_init; + s->id = pl011_id_luminary; } static const TypeInfo pl011_luminary_info = { .name = "pl011_luminary", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl011_state), - .class_init = pl011_luminary_class_init, + .parent = TYPE_PL011, + .instance_init = pl011_luminary_init, }; static void pl011_register_types(void) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index bcc7893230..eb3988c2e4 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -184,8 +184,6 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, size_t len) { - ssize_t ret = 0; - const uint8_t *iov_offset; SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); if (!scon->chr) { @@ -193,21 +191,7 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, return len; } - iov_offset = buf; - while (len > 0) { - ret = qemu_chr_fe_write(scon->chr, buf, len); - if (ret == 0) { - /* a pty doesn't seem to be connected - no error */ - len = 0; - } else if (ret == -EAGAIN || (ret > 0 && ret < len)) { - len -= ret; - iov_offset += ret; - } else { - len = 0; - } - } - - return ret; + return qemu_chr_fe_write_all(scon->chr, buf, len); } static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index cea8212428..5cb77b311a 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -102,6 +102,7 @@ static void serial_isa_class_initfn(ObjectClass *klass, void *data) dc->realize = serial_isa_realizefn; dc->vmsd = &vmstate_isa_serial; dc->props = serial_isa_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_isa_info = { diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index a17c702624..aec6705a01 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -205,6 +205,7 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data) pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_serial; dc->props = serial_pci_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) @@ -219,6 +220,7 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_multi_serial; dc->props = multi_2x_serial_pci_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) @@ -233,6 +235,7 @@ static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_multi_serial; dc->props = multi_4x_serial_pci_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_pci_info = { diff --git a/hw/char/serial.c b/hw/char/serial.c index 602559254e..27dab7d9d6 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -27,6 +27,7 @@ #include "sysemu/char.h" #include "qemu/timer.h" #include "exec/address-spaces.h" +#include "qemu/error-report.h" //#define DEBUG_SERIAL @@ -188,7 +189,7 @@ static void serial_update_msl(SerialState *s) uint8_t omsr; int flags; - qemu_del_timer(s->modem_status_poll); + timer_del(s->modem_status_poll); if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) { s->poll_msl = -1; @@ -215,7 +216,7 @@ static void serial_update_msl(SerialState *s) We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */ if (s->poll_msl) - qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100); + timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() / 100); } static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) @@ -252,7 +253,7 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) s->tsr_retry = 0; } - s->last_xmit_ts = qemu_get_clock_ns(vm_clock); + s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (s->lsr & UART_LSR_THRE) { s->lsr |= UART_LSR_TEMT; @@ -306,7 +307,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, s->poll_msl = 1; serial_update_msl(s); } else { - qemu_del_timer(s->modem_status_poll); + timer_del(s->modem_status_poll); s->poll_msl = 0; } } @@ -329,7 +330,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, /* FIFO clear */ if (val & UART_FCR_RFR) { - qemu_del_timer(s->fifo_timeout_timer); + timer_del(s->fifo_timeout_timer); s->timeout_ipending=0; fifo8_reset(&s->recv_fifo); } @@ -397,7 +398,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); /* Update the modem status after a one-character-send wait-time, since there may be a response from the device/computer at the other end of the serial line */ - qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time); + timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time); } } break; @@ -429,7 +430,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) if (s->recv_fifo.num == 0) { s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); } else { - qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4); + timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4); } s->timeout_ipending = 0; } else { @@ -556,7 +557,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) } s->lsr |= UART_LSR_DR; /* call the timeout receive callback in 4 char transmit time */ - qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4); + timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4); } else { if (s->lsr & UART_LSR_DR) s->lsr |= UART_LSR_OE; @@ -635,7 +636,7 @@ static void serial_reset(void *opaque) fifo8_reset(&s->recv_fifo); fifo8_reset(&s->xmit_fifo); - s->last_xmit_ts = qemu_get_clock_ns(vm_clock); + s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->thr_ipending = 0; s->last_break_enable = 0; @@ -649,9 +650,9 @@ void serial_realize_core(SerialState *s, Error **errp) return; } - s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s); + s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s); - s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); + s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s); qemu_register_reset(serial_reset, s); qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, @@ -696,7 +697,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase, s->chr = chr; serial_realize_core(s, &err); if (err != NULL) { - fprintf(stderr, "%s\n", error_get_pretty(err)); + error_report("%s", error_get_pretty(err)); error_free(err); exit(1); } @@ -760,7 +761,7 @@ SerialState *serial_mm_init(MemoryRegion *address_space, serial_realize_core(s, &err); if (err != NULL) { - fprintf(stderr, "%s\n", error_get_pretty(err)); + error_report("%s", error_get_pretty(err)); error_free(err); exit(1); } diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 2993848889..a7997213b6 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -142,6 +142,21 @@ static Property spapr_vty_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_vty = { + .name = "spapr_vty", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice), + + VMSTATE_UINT32(in, VIOsPAPRVTYDevice), + VMSTATE_UINT32(out, VIOsPAPRVTYDevice), + VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice), + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_vty_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -152,6 +167,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data) k->dt_type = "serial"; k->dt_compatible = "hvterm1"; dc->props = spapr_vty_properties; + dc->vmsd = &vmstate_spapr_vty; } static const TypeInfo spapr_vty_info = { diff --git a/hw/char/tpci200.c b/hw/char/tpci200.c index a199e57525..d9e17b2956 100644 --- a/hw/char/tpci200.c +++ b/hw/char/tpci200.c @@ -652,6 +652,7 @@ static void tpci200_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_OTHER; k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS; k->subsystem_id = 0x300A; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "TEWS TPCI200 IndustryPack carrier"; dc->vmsd = &vmstate_tpci200; } diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 6759e514a6..2e00ad2a7c 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -185,6 +185,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data) VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); k->init = virtconsole_initfn; + k->exit = virtconsole_exitfn; k->have_data = flush_buf; k->set_guest_connected = set_guest_connected; dc->props = virtserialport_properties; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index cc3d1dd27a..f23f555dde 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -603,7 +603,7 @@ static void virtio_serial_post_load_timer_cb(void *opaque) } } g_free(s->post_load->connected); - qemu_free_timer(s->post_load->timer); + timer_free(s->post_load->timer); g_free(s->post_load); s->post_load = NULL; } @@ -618,7 +618,7 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id, s->post_load->connected = g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports); - s->post_load->timer = qemu_new_timer_ns(vm_clock, + s->post_load->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_serial_post_load_timer_cb, s); @@ -660,7 +660,7 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id, } } } - qemu_mod_timer(s->post_load->timer, 1); + timer_mod(s->post_load->timer, 1); return 0; } @@ -971,6 +971,7 @@ static void virtio_serial_port_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = virtser_port_qdev_init; + set_bit(DEVICE_CATEGORY_INPUT, k->categories); k->bus_type = TYPE_VIRTIO_SERIAL_BUS; k->exit = virtser_port_qdev_exit; k->unplug = qdev_simple_unplug_cb; @@ -998,8 +999,8 @@ static int virtio_serial_device_exit(DeviceState *dev) g_free(vser->ports_map); if (vser->post_load) { g_free(vser->post_load->connected); - qemu_del_timer(vser->post_load->timer); - qemu_free_timer(vser->post_load->timer); + timer_del(vser->post_load->timer); + timer_free(vser->post_load->timer); g_free(vser->post_load); } virtio_cleanup(vdev); @@ -1017,6 +1018,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_serial_device_exit; dc->props = virtio_serial_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); vdc->init = virtio_serial_device_init; vdc->get_features = get_features; vdc->get_config = get_config; diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c index feca497f52..b0d1d04af7 100644 --- a/hw/char/xilinx_uartlite.c +++ b/hw/char/xilinx_uartlite.c @@ -46,9 +46,13 @@ #define CONTROL_RST_RX 0x02 #define CONTROL_IE 0x10 -struct xlx_uartlite -{ - SysBusDevice busdev; +#define TYPE_XILINX_UARTLITE "xlnx.xps-uartlite" +#define XILINX_UARTLITE(obj) \ + OBJECT_CHECK(XilinxUARTLite, (obj), TYPE_XILINX_UARTLITE) + +typedef struct XilinxUARTLite { + SysBusDevice parent_obj; + MemoryRegion mmio; CharDriverState *chr; qemu_irq irq; @@ -58,9 +62,9 @@ struct xlx_uartlite unsigned int rx_fifo_len; uint32_t regs[R_MAX]; -}; +} XilinxUARTLite; -static void uart_update_irq(struct xlx_uartlite *s) +static void uart_update_irq(XilinxUARTLite *s) { unsigned int irq; @@ -71,7 +75,7 @@ static void uart_update_irq(struct xlx_uartlite *s) qemu_set_irq(s->irq, irq); } -static void uart_update_status(struct xlx_uartlite *s) +static void uart_update_status(XilinxUARTLite *s) { uint32_t r; @@ -86,7 +90,7 @@ static void uart_update_status(struct xlx_uartlite *s) static uint64_t uart_read(void *opaque, hwaddr addr, unsigned int size) { - struct xlx_uartlite *s = opaque; + XilinxUARTLite *s = opaque; uint32_t r = 0; addr >>= 2; switch (addr) @@ -113,7 +117,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct xlx_uartlite *s = opaque; + XilinxUARTLite *s = opaque; uint32_t value = val64; unsigned char ch = value; @@ -164,7 +168,7 @@ static const MemoryRegionOps uart_ops = { static void uart_rx(void *opaque, const uint8_t *buf, int size) { - struct xlx_uartlite *s = opaque; + XilinxUARTLite *s = opaque; /* Got a byte. */ if (s->rx_fifo_len >= 8) { @@ -182,7 +186,7 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size) static int uart_can_rx(void *opaque) { - struct xlx_uartlite *s = opaque; + XilinxUARTLite *s = opaque; return s->rx_fifo_len < sizeof(s->rx_fifo); } @@ -194,7 +198,7 @@ static void uart_event(void *opaque, int event) static int xilinx_uartlite_init(SysBusDevice *dev) { - struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); + XilinxUARTLite *s = XILINX_UARTLITE(dev); sysbus_init_irq(dev, &s->irq); @@ -217,9 +221,9 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) } static const TypeInfo xilinx_uartlite_info = { - .name = "xlnx.xps-uartlite", + .name = TYPE_XILINX_UARTLITE, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof (struct xlx_uartlite), + .instance_size = sizeof(XilinxUARTLite), .class_init = xilinx_uartlite_class_init, }; diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c index e6249912c5..612b1093aa 100644 --- a/hw/core/empty_slot.c +++ b/hw/core/empty_slot.c @@ -22,8 +22,12 @@ #define DPRINTF(fmt, ...) do {} while (0) #endif +#define TYPE_EMPTY_SLOT "empty_slot" +#define EMPTY_SLOT(obj) OBJECT_CHECK(EmptySlot, (obj), TYPE_EMPTY_SLOT) + typedef struct EmptySlot { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint64_t size; } EmptySlot; @@ -55,9 +59,9 @@ void empty_slot_init(hwaddr addr, uint64_t slot_size) SysBusDevice *s; EmptySlot *e; - dev = qdev_create(NULL, "empty_slot"); + dev = qdev_create(NULL, TYPE_EMPTY_SLOT); s = SYS_BUS_DEVICE(dev); - e = FROM_SYSBUS(EmptySlot, s); + e = EMPTY_SLOT(dev); e->size = slot_size; qdev_init_nofail(dev); @@ -68,7 +72,7 @@ void empty_slot_init(hwaddr addr, uint64_t slot_size) static int empty_slot_init1(SysBusDevice *dev) { - EmptySlot *s = FROM_SYSBUS(EmptySlot, dev); + EmptySlot *s = EMPTY_SLOT(dev); memory_region_init_io(&s->iomem, OBJECT(s), &empty_slot_ops, s, "empty-slot", s->size); @@ -84,7 +88,7 @@ static void empty_slot_class_init(ObjectClass *klass, void *data) } static const TypeInfo empty_slot_info = { - .name = "empty_slot", + .name = TYPE_EMPTY_SLOT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(EmptySlot), .class_init = empty_slot_class_init, diff --git a/hw/core/loader.c b/hw/core/loader.c index c3c28cf6af..7b3d3ee6a0 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -54,6 +54,8 @@ #include <zlib.h> +bool rom_file_in_ram = true; + static int roms_loaded; /* return the size or -1 if error */ @@ -576,6 +578,7 @@ struct Rom { size_t datasize; uint8_t *data; + MemoryRegion *mr; int isrom; char *fw_dir; char *fw_file; @@ -605,6 +608,21 @@ static void rom_insert(Rom *rom) QTAILQ_INSERT_TAIL(&roms, rom, next); } +static void *rom_set_mr(Rom *rom, Object *owner, const char *name) +{ + void *data; + + rom->mr = g_malloc(sizeof(*rom->mr)); + memory_region_init_ram(rom->mr, owner, name, rom->datasize); + memory_region_set_readonly(rom->mr, true); + vmstate_register_ram_global(rom->mr); + + data = memory_region_get_ram_ptr(rom->mr); + memcpy(data, rom->data, rom->datasize); + + return data; +} + int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex) { @@ -646,6 +664,7 @@ int rom_add_file(const char *file, const char *fw_dir, if (rom->fw_file && fw_cfg) { const char *basename; char fw_file_name[56]; + void *data; basename = strrchr(rom->fw_file, '/'); if (basename) { @@ -655,8 +674,15 @@ int rom_add_file(const char *file, const char *fw_dir, } snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir, basename); - fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize); snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); + + if (rom_file_in_ram) { + data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); + } else { + data = rom->data; + } + + fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize); } else { snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr); } @@ -731,7 +757,12 @@ static void rom_reset(void *unused) if (rom->data == NULL) { continue; } - cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); + if (rom->mr) { + void *host = memory_region_get_ram_ptr(rom->mr); + memcpy(host, rom->data, rom->datasize); + } else { + cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); + } if (rom->isrom) { /* rom needs to be written only once */ g_free(rom->data); @@ -781,6 +812,9 @@ static Rom *find_rom(hwaddr addr) if (rom->fw_file) { continue; } + if (rom->mr) { + continue; + } if (rom->addr > addr) { continue; } @@ -808,15 +842,15 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) if (rom->fw_file) { continue; } + if (rom->mr) { + continue; + } if (rom->addr + rom->romsize < addr) { continue; } if (rom->addr > end) { break; } - if (!rom->data) { - continue; - } d = dest + (rom->addr - addr); s = rom->data; @@ -826,7 +860,9 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) l = dest - d; } - memcpy(d, s, l); + if (l > 0) { + memcpy(d, s, l); + } if (rom->romsize > rom->datasize) { /* If datasize is less than romsize, it means that we didn't @@ -867,7 +903,13 @@ void do_info_roms(Monitor *mon, const QDict *qdict) Rom *rom; QTAILQ_FOREACH(rom, &roms, next) { - if (!rom->fw_file) { + if (rom->mr) { + monitor_printf(mon, "%s" + " size=0x%06zx name=\"%s\"\n", + rom->mr->name, + rom->romsize, + rom->name); + } else if (!rom->fw_file) { monitor_printf(mon, "addr=" TARGET_FMT_plx " size=0x%06zx mem=%s name=\"%s\"\n", rom->addr, rom->romsize, diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 4bc96c9fa2..3036bde1f3 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -48,7 +48,7 @@ static void ptimer_reload(ptimer_state *s) if (s->period_frac) { s->next_event += ((int64_t)s->period_frac * s->delta) >> 32; } - qemu_mod_timer(s->timer, s->next_event); + timer_mod(s->timer, s->next_event); } static void ptimer_tick(void *opaque) @@ -69,7 +69,7 @@ uint64_t ptimer_get_count(ptimer_state *s) uint64_t counter; if (s->enabled) { - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Figure out the current counter value. */ if (now - s->next_event > 0 || s->period == 0) { @@ -123,7 +123,7 @@ void ptimer_set_count(ptimer_state *s, uint64_t count) { s->delta = count; if (s->enabled) { - s->next_event = qemu_get_clock_ns(vm_clock); + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ptimer_reload(s); } } @@ -138,7 +138,7 @@ void ptimer_run(ptimer_state *s, int oneshot) return; } s->enabled = oneshot ? 2 : 1; - s->next_event = qemu_get_clock_ns(vm_clock); + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ptimer_reload(s); } @@ -150,7 +150,7 @@ void ptimer_stop(ptimer_state *s) return; s->delta = ptimer_get_count(s); - qemu_del_timer(s->timer); + timer_del(s->timer); s->enabled = 0; } @@ -160,7 +160,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period) s->period = period; s->period_frac = 0; if (s->enabled) { - s->next_event = qemu_get_clock_ns(vm_clock); + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ptimer_reload(s); } } @@ -171,7 +171,7 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq) s->period = 1000000000ll / freq; s->period_frac = (1000000000ll << 32) / freq; if (s->enabled) { - s->next_event = qemu_get_clock_ns(vm_clock); + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ptimer_reload(s); } } @@ -197,7 +197,7 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) if (reload) s->delta = limit; if (s->enabled && reload) { - s->next_event = qemu_get_clock_ns(vm_clock); + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ptimer_reload(s); } } @@ -226,6 +226,6 @@ ptimer_state *ptimer_init(QEMUBH *bh) s = (ptimer_state *)g_malloc0(sizeof(ptimer_state)); s->bh = bh; - s->timer = qemu_new_timer_ns(vm_clock, ptimer_tick, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s); return s; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 3a324fb0c3..dc8ae6958c 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -74,13 +74,14 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) } } -static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) +static int prop_print_bit(DeviceState *dev, Property *prop, char *dest, + size_t len) { uint32_t *p = qdev_get_prop_ptr(dev, prop); return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); } -static void get_bit(Object *obj, Visitor *v, void *opaque, +static void prop_get_bit(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); @@ -91,7 +92,7 @@ static void get_bit(Object *obj, Visitor *v, void *opaque, visit_type_bool(v, &value, name, errp); } -static void set_bit(Object *obj, Visitor *v, void *opaque, +static void prop_set_bit(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); @@ -115,9 +116,9 @@ static void set_bit(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_bit = { .name = "boolean", .legacy_name = "on/off", - .print = print_bit, - .get = get_bit, - .set = set_bit, + .print = prop_print_bit, + .get = prop_get_bit, + .set = prop_set_bit, }; /* --- bool --- */ @@ -1134,3 +1135,64 @@ void qdev_prop_set_globals(DeviceState *dev, Error **errp) class = object_class_get_parent(class); } while (class); } + +/* --- 64bit unsigned int 'size' type --- */ + +static void get_size(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_size(v, ptr, name, errp); +} + +static void set_size(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_size(v, ptr, name, errp); +} + +static int parse_size(DeviceState *dev, Property *prop, const char *str) +{ + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + Error *errp = NULL; + + if (str != NULL) { + parse_option_size(prop->name, str, ptr, &errp); + } + assert_no_error(errp); + return 0; +} + +static int print_size(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + static const char suffixes[] = { 'B', 'K', 'M', 'G', 'T' }; + uint64_t div, val = *(uint64_t *)qdev_get_prop_ptr(dev, prop); + int i; + + /* Compute floor(log2(val)). */ + i = 64 - clz64(val); + + /* Find the power of 1024 that we'll display as the units. */ + i /= 10; + if (i >= ARRAY_SIZE(suffixes)) { + i = ARRAY_SIZE(suffixes) - 1; + } + div = 1ULL << (i * 10); + + return snprintf(dest, len, "%0.03f%c", (double)val/div, suffixes[i]); +} + +PropertyInfo qdev_prop_size = { + .name = "size", + .parse = parse_size, + .print = print_size, + .get = get_size, + .set = set_size, +}; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 9190a7ee76..758de9fccc 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -752,7 +752,6 @@ static void device_initfn(Object *obj) } class = object_class_get_parent(class); } while (class != object_class_by_name(TYPE_DEVICE)); - qdev_prop_set_globals(dev, &err); if (err != NULL) { qerror_report_err(err); error_free(err); @@ -764,6 +763,15 @@ static void device_initfn(Object *obj) assert_no_error(err); } +static void device_post_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + Error *err = NULL; + + qdev_prop_set_globals(dev, &err); + assert_no_error(err); +} + /* Unlink device from bus and free the structure. */ static void device_finalize(Object *obj) { @@ -853,6 +861,7 @@ static const TypeInfo device_type_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(DeviceState), .instance_init = device_initfn, + .instance_post_init = device_post_init, .instance_finalize = device_finalize, .class_base_init = device_class_base_init, .class_init = device_class_init, diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs index 4461eceee8..df287c1d8c 100644 --- a/hw/cpu/Makefile.objs +++ b/hw/cpu/Makefile.objs @@ -1,5 +1,5 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o -obj-$(CONFIG_ARM9MPCORE) += a9mpcore.o -obj-$(CONFIG_ARM15MPCORE) += a15mpcore.o +obj-$(CONFIG_A9MPCORE) += a9mpcore.o +obj-$(CONFIG_A15MPCORE) += a15mpcore.o obj-$(CONFIG_ICC_BUS) += icc_bus.o diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index c736257f24..af182da4ee 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -23,8 +23,15 @@ /* A15MP private memory region. */ +#define TYPE_A15MPCORE_PRIV "a15mpcore_priv" +#define A15MPCORE_PRIV(obj) \ + OBJECT_CHECK(A15MPPrivState, (obj), TYPE_A15MPCORE_PRIV) + typedef struct A15MPPrivState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t num_cpu; uint32_t num_irq; MemoryRegion container; @@ -39,9 +46,11 @@ static void a15mp_priv_set_irq(void *opaque, int irq, int level) static int a15mp_priv_init(SysBusDevice *dev) { - A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev); + A15MPPrivState *s = A15MPCORE_PRIV(dev); SysBusDevice *busdev; const char *gictype = "arm_gic"; + int i; + CPUState *cpu; if (kvm_irqchip_in_kernel()) { gictype = "kvm-arm-gic"; @@ -58,7 +67,23 @@ static int a15mp_priv_init(SysBusDevice *dev) sysbus_pass_irq(dev, busdev); /* Pass through inbound GPIO lines to the GIC */ - qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32); + qdev_init_gpio_in(DEVICE(dev), a15mp_priv_set_irq, s->num_irq - 32); + + /* Wire the outputs from each CPU's generic timer to the + * appropriate GIC PPI inputs + */ + for (i = 0, cpu = first_cpu; i < s->num_cpu; i++, cpu = cpu->next_cpu) { + DeviceState *cpudev = DEVICE(cpu); + int ppibase = s->num_irq - 32 + i * 32; + /* physical timer; we wire it up to the non-secure timer's ID, + * since a real A15 always has TrustZone but QEMU doesn't. + */ + qdev_connect_gpio_out(cpudev, 0, + qdev_get_gpio_in(s->gic, ppibase + 30)); + /* virtual timer */ + qdev_connect_gpio_out(cpudev, 1, + qdev_get_gpio_in(s->gic, ppibase + 27)); + } /* Memory map (addresses are offsets from PERIPHBASE): * 0x0000-0x0fff -- reserved @@ -101,7 +126,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data) } static const TypeInfo a15mp_priv_info = { - .name = "a15mpcore_priv", + .name = TYPE_A15MPCORE_PRIV, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(A15MPPrivState), .class_init = a15mp_priv_class_init, diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index 6c00a59faf..3e675e3941 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -10,8 +10,15 @@ #include "hw/sysbus.h" +#define TYPE_A9MPCORE_PRIV "a9mpcore_priv" +#define A9MPCORE_PRIV(obj) \ + OBJECT_CHECK(A9MPPrivState, (obj), TYPE_A9MPCORE_PRIV) + typedef struct A9MPPrivState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t num_cpu; MemoryRegion container; DeviceState *mptimer; @@ -29,7 +36,7 @@ static void a9mp_priv_set_irq(void *opaque, int irq, int level) static int a9mp_priv_init(SysBusDevice *dev) { - A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev); + A9MPPrivState *s = A9MPCORE_PRIV(dev); SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev, *scubusdev; int i; @@ -43,7 +50,7 @@ static int a9mp_priv_init(SysBusDevice *dev) sysbus_pass_irq(dev, gicbusdev); /* Pass through inbound GPIO lines to the GIC */ - qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32); + qdev_init_gpio_in(DEVICE(dev), a9mp_priv_set_irq, s->num_irq - 32); s->scu = qdev_create(NULL, "a9-scu"); qdev_prop_set_uint32(s->scu, "num-cpu", s->num_cpu); @@ -124,7 +131,7 @@ static void a9mp_priv_class_init(ObjectClass *klass, void *data) } static const TypeInfo a9mp_priv_info = { - .name = "a9mpcore_priv", + .name = TYPE_A9MPCORE_PRIV, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(A9MPPrivState), .class_init = a9mp_priv_class_init, diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c index 8eeb53e60c..a786c628dd 100644 --- a/hw/cpu/arm11mpcore.c +++ b/hw/cpu/arm11mpcore.c @@ -12,8 +12,13 @@ /* MPCore private memory region. */ +#define TYPE_ARM11MPCORE_PRIV "arm11mpcore_priv" +#define ARM11MPCORE_PRIV(obj) \ + OBJECT_CHECK(ARM11MPCorePriveState, (obj), TYPE_ARM11MPCORE_PRIV) + typedef struct ARM11MPCorePriveState { - SysBusDevice busdev; + SysBusDevice parent_obj; + uint32_t scu_control; int iomemtype; uint32_t old_timer_status[8]; @@ -125,9 +130,10 @@ static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) } } -static int mpcore_priv_init(SysBusDevice *dev) +static int mpcore_priv_init(SysBusDevice *sbd) { - ARM11MPCorePriveState *s = FROM_SYSBUS(ARM11MPCorePriveState, dev); + DeviceState *dev = DEVICE(sbd); + ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(dev); s->gic = qdev_create(NULL, "arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); @@ -137,10 +143,10 @@ static int mpcore_priv_init(SysBusDevice *dev) qdev_init_nofail(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(dev, SYS_BUS_DEVICE(s->gic)); + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(s->gic)); /* Pass through inbound GPIO lines to the GIC */ - qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32); + qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); @@ -151,15 +157,20 @@ static int mpcore_priv_init(SysBusDevice *dev) qdev_init_nofail(s->wdtimer); mpcore_priv_map_setup(s); - sysbus_init_mmio(dev, &s->container); + sysbus_init_mmio(sbd, &s->container); return 0; } +#define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore" +#define REALVIEW_MPCORE_RIRQ(obj) \ + OBJECT_CHECK(mpcore_rirq_state, (obj), TYPE_REALVIEW_MPCORE_RIRQ) + /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ controllers. The output of these, plus some of the raw input lines are fed into a single SMP-aware interrupt controller on the CPU. */ typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + SysBusDevice *priv; qemu_irq cpuic[32]; qemu_irq rvic[4][64]; @@ -190,19 +201,20 @@ static void mpcore_rirq_set_irq(void *opaque, int irq, int level) } } -static int realview_mpcore_init(SysBusDevice *dev) +static int realview_mpcore_init(SysBusDevice *sbd) { - mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); + DeviceState *dev = DEVICE(sbd); + mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(dev); DeviceState *gic; DeviceState *priv; int n; int i; - priv = qdev_create(NULL, "arm11mpcore_priv"); + priv = qdev_create(NULL, TYPE_ARM11MPCORE_PRIV); qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); qdev_init_nofail(priv); s->priv = SYS_BUS_DEVICE(priv); - sysbus_pass_irq(dev, s->priv); + sysbus_pass_irq(sbd, s->priv); for (i = 0; i < 32; i++) { s->cpuic[i] = qdev_get_gpio_in(priv, i); } @@ -214,8 +226,8 @@ static int realview_mpcore_init(SysBusDevice *dev) s->rvic[n][i] = qdev_get_gpio_in(gic, i); } } - qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64); - sysbus_init_mmio(dev, sysbus_mmio_get_region(s->priv, 0)); + qdev_init_gpio_in(dev, mpcore_rirq_set_irq, 64); + sysbus_init_mmio(sbd, sysbus_mmio_get_region(s->priv, 0)); return 0; } @@ -234,7 +246,7 @@ static void mpcore_rirq_class_init(ObjectClass *klass, void *data) } static const TypeInfo mpcore_rirq_info = { - .name = "realview_mpcore", + .name = TYPE_REALVIEW_MPCORE_RIRQ, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mpcore_rirq_state), .class_init = mpcore_rirq_class_init, @@ -264,7 +276,7 @@ static void mpcore_priv_class_init(ObjectClass *klass, void *data) } static const TypeInfo mpcore_priv_info = { - .name = "arm11mpcore_priv", + .name = TYPE_ARM11MPCORE_PRIV, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ARM11MPCorePriveState), .class_init = mpcore_priv_class_init, diff --git a/hw/cpu/icc_bus.c b/hw/cpu/icc_bus.c index 8788144b98..8748cc5046 100644 --- a/hw/cpu/icc_bus.c +++ b/hw/cpu/icc_bus.c @@ -101,11 +101,19 @@ static void icc_bridge_init(Object *obj) s->icc_bus.apic_address_space = &s->apic_container; } +static void icc_bridge_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + static const TypeInfo icc_bridge_info = { .name = TYPE_ICC_BRIDGE, .parent = TYPE_SYS_BUS_DEVICE, .instance_init = icc_bridge_init, .instance_size = sizeof(ICCBridgeState), + .class_init = icc_bridge_class_init, }; diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index a440575def..dbd1f4a47b 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2937,6 +2937,7 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cirrus_vga; dc->realize = isa_cirrus_vga_realizefn; dc->props = isa_cirrus_vga_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo isa_cirrus_vga_info = { @@ -3002,6 +3003,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_CIRRUS; k->device_id = CIRRUS_ID_CLGD5446; k->class_id = PCI_CLASS_DISPLAY_VGA; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "Cirrus CLGD 54xx VGA"; dc->vmsd = &vmstate_pci_cirrus_vga; dc->props = pci_vga_cirrus_properties; diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index eb168eaf11..65cca1d707 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -292,8 +292,13 @@ struct Exynos4210fimdWindow { hwaddr fb_len; /* Framebuffer length */ }; +#define TYPE_EXYNOS4210_FIMD "exynos4210.fimd" +#define EXYNOS4210_FIMD(obj) \ + OBJECT_CHECK(Exynos4210fimdState, (obj), TYPE_EXYNOS4210_FIMD) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; QemuConsole *console; qemu_irq irq[3]; @@ -1108,6 +1113,7 @@ static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w) * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) { + SysBusDevice *sbd = SYS_BUS_DEVICE(s); Exynos4210fimdWindow *w = &s->window[win]; hwaddr fb_start_addr, fb_mapped_len; @@ -1131,8 +1137,8 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) * does not support hot-unplug. */ memory_region_unref(w->mem_section.mr); - w->mem_section = memory_region_find(sysbus_address_space(&s->busdev), - fb_start_addr, w->fb_len); + w->mem_section = memory_region_find(sysbus_address_space(sbd), + fb_start_addr, w->fb_len); assert(w->mem_section.mr); assert(w->mem_section.offset_within_address_space == fb_start_addr); DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n", @@ -1328,7 +1334,7 @@ static void exynos4210_fimd_update(void *opaque) static void exynos4210_fimd_reset(DeviceState *d) { - Exynos4210fimdState *s = DO_UPCAST(Exynos4210fimdState, busdev.qdev, d); + Exynos4210fimdState *s = EXYNOS4210_FIMD(d); unsigned w; DPRINT_TRACE("Display controller reset\n"); @@ -1900,7 +1906,7 @@ static const GraphicHwOps exynos4210_fimd_ops = { static int exynos4210_fimd_init(SysBusDevice *dev) { - Exynos4210fimdState *s = FROM_SYSBUS(Exynos4210fimdState, dev); + Exynos4210fimdState *s = EXYNOS4210_FIMD(dev); s->ifb = NULL; @@ -1927,7 +1933,7 @@ static void exynos4210_fimd_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_fimd_info = { - .name = "exynos4210.fimd", + .name = TYPE_EXYNOS4210_FIMD, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210fimdState), .class_init = exynos4210_fimd_class_init, diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 79a0a5063e..7082171b82 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -493,26 +493,33 @@ static void g364fb_init(DeviceState *dev, G364State *s) memory_region_set_coalescing(&s->mem_vram); } +#define TYPE_G364 "sysbus-g364" +#define G364(obj) OBJECT_CHECK(G364SysBusState, (obj), TYPE_G364) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + G364State g364; } G364SysBusState; -static int g364fb_sysbus_init(SysBusDevice *dev) +static int g364fb_sysbus_init(SysBusDevice *sbd) { - G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364; + DeviceState *dev = DEVICE(sbd); + G364SysBusState *sbs = G364(dev); + G364State *s = &sbs->g364; - g364fb_init(&dev->qdev, s); - sysbus_init_irq(dev, &s->irq); - sysbus_init_mmio(dev, &s->mem_ctrl); - sysbus_init_mmio(dev, &s->mem_vram); + g364fb_init(dev, s); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_mmio(sbd, &s->mem_ctrl); + sysbus_init_mmio(sbd, &s->mem_vram); return 0; } static void g364fb_sysbus_reset(DeviceState *d) { - G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d); + G364SysBusState *s = G364(d); + g364fb_reset(&s->g364); } @@ -528,6 +535,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = g364fb_sysbus_init; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "G364 framebuffer"; dc->reset = g364fb_sysbus_reset; dc->vmsd = &vmstate_g364fb; @@ -535,7 +543,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) } static const TypeInfo g364fb_sysbus_info = { - .name = "sysbus-g364", + .name = TYPE_G364, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(G364SysBusState), .class_init = g364fb_sysbus_class_init, diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index 7f82037d99..8407e6c2ef 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -32,8 +32,12 @@ typedef enum { REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, } screen_state_t; +#define TYPE_JAZZ_LED "jazz-led" +#define JAZZ_LED(obj) OBJECT_CHECK(LedState, (obj), TYPE_JAZZ_LED) + typedef struct LedState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint8_t segments; QemuConsole *con; @@ -262,7 +266,7 @@ static const GraphicHwOps jazz_led_ops = { static int jazz_led_init(SysBusDevice *dev) { - LedState *s = FROM_SYSBUS(LedState, dev); + LedState *s = JAZZ_LED(dev); memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1); sysbus_init_mmio(dev, &s->iomem); @@ -274,7 +278,7 @@ static int jazz_led_init(SysBusDevice *dev) static void jazz_led_reset(DeviceState *d) { - LedState *s = DO_UPCAST(LedState, busdev.qdev, d); + LedState *s = JAZZ_LED(d); s->segments = 0; s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; @@ -293,7 +297,7 @@ static void jazz_led_class_init(ObjectClass *klass, void *data) } static const TypeInfo jazz_led_info = { - .name = "jazz-led", + .name = TYPE_JAZZ_LED, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LedState), .class_init = jazz_led_class_init, diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index efda0824fe..b2a5fba0ff 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -75,8 +75,13 @@ struct vertex { int y; } QEMU_PACKED; +#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2" +#define MILKYMIST_TMU2(obj) \ + OBJECT_CHECK(MilkymistTMU2State, (obj), TYPE_MILKYMIST_TMU2) + struct MilkymistTMU2State { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; CharDriverState *chr; qemu_irq irq; @@ -429,7 +434,7 @@ static const MemoryRegionOps tmu2_mmio_ops = { static void milkymist_tmu2_reset(DeviceState *d) { - MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev); + MilkymistTMU2State *s = MILKYMIST_TMU2(d); int i; for (i = 0; i < R_MAX; i++) { @@ -439,7 +444,7 @@ static void milkymist_tmu2_reset(DeviceState *d) static int milkymist_tmu2_init(SysBusDevice *dev) { - MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistTMU2State *s = MILKYMIST_TMU2(dev); if (tmu2_glx_init(s)) { return 1; @@ -476,7 +481,7 @@ static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_tmu2_info = { - .name = "milkymist-tmu2", + .name = TYPE_MILKYMIST_TMU2, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistTMU2State), .class_init = milkymist_tmu2_class_init, diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c index 870b339581..5150cb48b7 100644 --- a/hw/display/milkymist-vgafb.c +++ b/hw/display/milkymist-vgafb.c @@ -63,8 +63,13 @@ enum { CTRL_RESET = (1<<0), }; +#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb" +#define MILKYMIST_VGAFB(obj) \ + OBJECT_CHECK(MilkymistVgafbState, (obj), TYPE_MILKYMIST_VGAFB) + struct MilkymistVgafbState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; QemuConsole *con; @@ -84,6 +89,7 @@ static int vgafb_enabled(MilkymistVgafbState *s) static void vgafb_update_display(void *opaque) { MilkymistVgafbState *s = opaque; + SysBusDevice *sbd; DisplaySurface *surface = qemu_console_surface(s->con); int first = 0; int last = 0; @@ -93,6 +99,7 @@ static void vgafb_update_display(void *opaque) return; } + sbd = SYS_BUS_DEVICE(s); int dest_width = s->regs[R_HRES]; switch (surface_bits_per_pixel(surface)) { @@ -122,7 +129,7 @@ static void vgafb_update_display(void *opaque) break; } - framebuffer_update_display(surface, sysbus_address_space(&s->busdev), + framebuffer_update_display(surface, sysbus_address_space(sbd), s->regs[R_BASEADDRESS] + s->fb_offset, s->regs[R_HRES], s->regs[R_VRES], @@ -256,7 +263,7 @@ static const MemoryRegionOps vgafb_mmio_ops = { static void milkymist_vgafb_reset(DeviceState *d) { - MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev); + MilkymistVgafbState *s = MILKYMIST_VGAFB(d); int i; for (i = 0; i < R_MAX; i++) { @@ -277,7 +284,7 @@ static const GraphicHwOps vgafb_ops = { static int milkymist_vgafb_init(SysBusDevice *dev) { - MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistVgafbState *s = MILKYMIST_VGAFB(dev); memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s, "milkymist-vgafb", R_MAX * 4); @@ -324,7 +331,7 @@ static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_vgafb_info = { - .name = "milkymist-vgafb", + .name = TYPE_MILKYMIST_VGAFB, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistVgafbState), .class_init = milkymist_vgafb_class_init, diff --git a/hw/display/pl110.c b/hw/display/pl110.c index 60afcf39e1..e79ab4bbdd 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -39,8 +39,12 @@ enum pl110_version PL111 }; -typedef struct { - SysBusDevice busdev; +#define TYPE_PL110 "pl110" +#define PL110(obj) OBJECT_CHECK(PL110State, (obj), TYPE_PL110) + +typedef struct PL110State { + SysBusDevice parent_obj; + MemoryRegion iomem; QemuConsole *con; @@ -59,7 +63,7 @@ typedef struct { uint32_t palette[256]; uint32_t raw_palette[128]; qemu_irq irq; -} pl110_state; +} PL110State; static int vmstate_pl110_post_load(void *opaque, int version_id); @@ -69,20 +73,20 @@ static const VMStateDescription vmstate_pl110 = { .minimum_version_id = 1, .post_load = vmstate_pl110_post_load, .fields = (VMStateField[]) { - VMSTATE_INT32(version, pl110_state), - VMSTATE_UINT32_ARRAY(timing, pl110_state, 4), - VMSTATE_UINT32(cr, pl110_state), - VMSTATE_UINT32(upbase, pl110_state), - VMSTATE_UINT32(lpbase, pl110_state), - VMSTATE_UINT32(int_status, pl110_state), - VMSTATE_UINT32(int_mask, pl110_state), - VMSTATE_INT32(cols, pl110_state), - VMSTATE_INT32(rows, pl110_state), - VMSTATE_UINT32(bpp, pl110_state), - VMSTATE_INT32(invalidate, pl110_state), - VMSTATE_UINT32_ARRAY(palette, pl110_state, 256), - VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128), - VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2), + VMSTATE_INT32(version, PL110State), + VMSTATE_UINT32_ARRAY(timing, PL110State, 4), + VMSTATE_UINT32(cr, PL110State), + VMSTATE_UINT32(upbase, PL110State), + VMSTATE_UINT32(lpbase, PL110State), + VMSTATE_UINT32(int_status, PL110State), + VMSTATE_UINT32(int_mask, PL110State), + VMSTATE_INT32(cols, PL110State), + VMSTATE_INT32(rows, PL110State), + VMSTATE_UINT32(bpp, PL110State), + VMSTATE_INT32(invalidate, PL110State), + VMSTATE_UINT32_ARRAY(palette, PL110State, 256), + VMSTATE_UINT32_ARRAY(raw_palette, PL110State, 128), + VMSTATE_UINT32_V(mux_ctrl, PL110State, 2), VMSTATE_END_OF_LIST() } }; @@ -121,14 +125,15 @@ static const unsigned char *idregs[] = { #define BITS 32 #include "pl110_template.h" -static int pl110_enabled(pl110_state *s) +static int pl110_enabled(PL110State *s) { return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR); } static void pl110_update_display(void *opaque) { - pl110_state *s = (pl110_state *)opaque; + PL110State *s = (PL110State *)opaque; + SysBusDevice *sbd; DisplaySurface *surface = qemu_console_surface(s->con); drawfn* fntable; drawfn fn; @@ -138,8 +143,11 @@ static void pl110_update_display(void *opaque) int first; int last; - if (!pl110_enabled(s)) + if (!pl110_enabled(s)) { return; + } + + sbd = SYS_BUS_DEVICE(s); switch (surface_bits_per_pixel(surface)) { case 0: @@ -232,7 +240,7 @@ static void pl110_update_display(void *opaque) } dest_width *= s->cols; first = 0; - framebuffer_update_display(surface, sysbus_address_space(&s->busdev), + framebuffer_update_display(surface, sysbus_address_space(sbd), s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, @@ -246,14 +254,14 @@ static void pl110_update_display(void *opaque) static void pl110_invalidate_display(void * opaque) { - pl110_state *s = (pl110_state *)opaque; + PL110State *s = (PL110State *)opaque; s->invalidate = 1; if (pl110_enabled(s)) { qemu_console_resize(s->con, s->cols, s->rows); } } -static void pl110_update_palette(pl110_state *s, int n) +static void pl110_update_palette(PL110State *s, int n) { DisplaySurface *surface = qemu_console_surface(s->con); int i; @@ -289,7 +297,7 @@ static void pl110_update_palette(pl110_state *s, int n) } } -static void pl110_resize(pl110_state *s, int width, int height) +static void pl110_resize(PL110State *s, int width, int height) { if (width != s->cols || height != s->rows) { if (pl110_enabled(s)) { @@ -301,7 +309,7 @@ static void pl110_resize(pl110_state *s, int width, int height) } /* Update interrupts. */ -static void pl110_update(pl110_state *s) +static void pl110_update(PL110State *s) { /* TODO: Implement interrupts. */ } @@ -309,7 +317,7 @@ static void pl110_update(pl110_state *s) static uint64_t pl110_read(void *opaque, hwaddr offset, unsigned size) { - pl110_state *s = (pl110_state *)opaque; + PL110State *s = (PL110State *)opaque; if (offset >= 0xfe0 && offset < 0x1000) { return idregs[s->version][(offset - 0xfe0) >> 2]; @@ -359,7 +367,7 @@ static uint64_t pl110_read(void *opaque, hwaddr offset, static void pl110_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { - pl110_state *s = (pl110_state *)opaque; + PL110State *s = (PL110State *)opaque; int n; /* For simplicity invalidate the display whenever a control register @@ -432,13 +440,13 @@ static const MemoryRegionOps pl110_ops = { static void pl110_mux_ctrl_set(void *opaque, int line, int level) { - pl110_state *s = (pl110_state *)opaque; + PL110State *s = (PL110State *)opaque; s->mux_ctrl = level; } static int vmstate_pl110_post_load(void *opaque, int version_id) { - pl110_state *s = opaque; + PL110State *s = opaque; /* Make sure we redraw, and at the right size */ pl110_invalidate_display(s); return 0; @@ -449,30 +457,38 @@ static const GraphicHwOps pl110_gfx_ops = { .gfx_update = pl110_update_display, }; -static int pl110_init(SysBusDevice *dev) +static int pl110_initfn(SysBusDevice *sbd) { - pl110_state *s = FROM_SYSBUS(pl110_state, dev); + DeviceState *dev = DEVICE(sbd); + PL110State *s = PL110(dev); memory_region_init_io(&s->iomem, OBJECT(s), &pl110_ops, s, "pl110", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1); - s->con = graphic_console_init(DEVICE(dev), &pl110_gfx_ops, s); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1); + s->con = graphic_console_init(dev, &pl110_gfx_ops, s); return 0; } -static int pl110_versatile_init(SysBusDevice *dev) +static void pl110_init(Object *obj) +{ + PL110State *s = PL110(obj); + + s->version = PL110; +} + +static void pl110_versatile_init(Object *obj) { - pl110_state *s = FROM_SYSBUS(pl110_state, dev); + PL110State *s = PL110(obj); + s->version = PL110_VERSATILE; - return pl110_init(dev); } -static int pl111_init(SysBusDevice *dev) +static void pl111_init(Object *obj) { - pl110_state *s = FROM_SYSBUS(pl110_state, dev); + PL110State *s = PL110(obj); + s->version = PL111; - return pl110_init(dev); } static void pl110_class_init(ObjectClass *klass, void *data) @@ -480,50 +496,30 @@ static void pl110_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = pl110_init; + k->init = pl110_initfn; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->no_user = 1; dc->vmsd = &vmstate_pl110; } static const TypeInfo pl110_info = { - .name = "pl110", + .name = TYPE_PL110, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl110_state), + .instance_size = sizeof(PL110State), + .instance_init = pl110_init, .class_init = pl110_class_init, }; -static void pl110_versatile_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pl110_versatile_init; - dc->no_user = 1; - dc->vmsd = &vmstate_pl110; -} - static const TypeInfo pl110_versatile_info = { .name = "pl110_versatile", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl110_state), - .class_init = pl110_versatile_class_init, + .parent = TYPE_PL110, + .instance_init = pl110_versatile_init, }; -static void pl111_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pl111_init; - dc->no_user = 1; - dc->vmsd = &vmstate_pl110; -} - static const TypeInfo pl111_info = { .name = "pl111", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl110_state), - .class_init = pl111_class_init, + .parent = TYPE_PL110, + .instance_init = pl111_init, }; static void pl110_register_types(void) diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c index 3cd85d9b97..c900c2ca4f 100644 --- a/hw/display/qxl-logger.c +++ b/hw/display/qxl-logger.c @@ -242,7 +242,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) if (!qxl->cmdlog) { return 0; } - fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock), + fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), qxl->id, ring); fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data, qxl_name(qxl_type, ext->cmd.type), diff --git a/hw/display/qxl.c b/hw/display/qxl.c index ddefa0668a..7649f2b1f4 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1596,7 +1596,7 @@ async_common: trace_qxl_io_log(d->id, d->ram->log_buf); if (d->guestdebug) { fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, - qemu_get_clock_ns(vm_clock), d->ram->log_buf); + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), d->ram->log_buf); } break; case QXL_IO_RESET: @@ -2323,6 +2323,7 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data) k->vendor_id = REDHAT_PCI_VENDOR_ID; k->device_id = QXL_DEVICE_ID_STABLE; k->class_id = PCI_CLASS_DISPLAY_VGA; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "Spice QXL GPU (primary, vga compatible)"; dc->reset = qxl_reset_handler; dc->vmsd = &qxl_vmstate; @@ -2345,6 +2346,7 @@ static void qxl_secondary_class_init(ObjectClass *klass, void *data) k->vendor_id = REDHAT_PCI_VENDOR_ID; k->device_id = QXL_DEVICE_ID_STABLE; k->class_id = PCI_CLASS_DISPLAY_OTHER; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "Spice QXL GPU (secondary)"; dc->reset = qxl_reset_handler; dc->vmsd = &qxl_vmstate; diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 9fd48b5f8b..24876d33ef 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -34,8 +34,12 @@ #define TCX_THC_NREGS_24 0x1000 #define TCX_TEC_NREGS 0x1000 +#define TYPE_TCX "SUNW,tcx" +#define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) + typedef struct TCXState { - SysBusDevice busdev; + SysBusDevice parent_obj; + QemuConsole *con; uint8_t *vram; uint32_t *vram24, *cplane; @@ -423,7 +427,7 @@ static const VMStateDescription vmstate_tcx = { static void tcx_reset(DeviceState *d) { - TCXState *s = container_of(d, TCXState, busdev.qdev); + TCXState *s = TCX(d); /* Initialize palette */ memset(s->r, 0, 256); @@ -523,7 +527,7 @@ static const GraphicHwOps tcx24_ops = { static int tcx_init1(SysBusDevice *dev) { - TCXState *s = FROM_SYSBUS(TCXState, dev); + TCXState *s = TCX(dev); ram_addr_t vram_offset = 0; int size; uint8_t *vram_base; @@ -609,7 +613,7 @@ static void tcx_class_init(ObjectClass *klass, void *data) } static const TypeInfo tcx_info = { - .name = "SUNW,tcx", + .name = TYPE_TCX, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TCXState), .class_init = tcx_class_init, diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 8d560ecef0..c2a19ad6ba 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -87,6 +87,7 @@ static void vga_isa_class_initfn(ObjectClass *klass, void *data) dc->reset = vga_isa_reset; dc->vmsd = &vmstate_vga_common; dc->props = vga_isa_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo vga_isa_info = { diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 3e150abe8d..b3a45c81da 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -198,6 +198,7 @@ static void vga_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_DISPLAY_VGA; dc->vmsd = &vmstate_vga_pci; dc->props = vga_pci_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo vga_info = { diff --git a/hw/display/vga.c b/hw/display/vga.c index 06f44a808c..7b91d9c54e 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -318,7 +318,7 @@ static uint8_t vga_precise_retrace(VGACommonState *s) int cur_line, cur_line_char, cur_char; int64_t cur_tick; - cur_tick = qemu_get_clock_ns(vm_clock); + cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); cur_char = (cur_tick / r->ticks_per_char) % r->total_chars; cur_line = cur_char / r->htotal; @@ -1304,7 +1304,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) uint32_t *ch_attr_ptr; vga_draw_glyph8_func *vga_draw_glyph8; vga_draw_glyph9_func *vga_draw_glyph9; - int64_t now = qemu_get_clock_ms(vm_clock); + int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); /* compute font data address (in plane 2) */ v = s->sr[VGA_SEQ_CHARACTER_MAP]; @@ -1907,7 +1907,7 @@ static void vga_update_display(void *opaque) } if (graphic_mode != s->graphic_mode) { s->graphic_mode = graphic_mode; - s->cursor_blink_time = qemu_get_clock_ms(vm_clock); + s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); full_update = 1; } switch(graphic_mode) { diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 3536cded92..a6a8cdc2e1 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1306,6 +1306,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data) dc->reset = vmsvga_reset; dc->vmsd = &vmstate_vmware_vga; dc->props = vga_vmware_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo vmsvga_info = { diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 7937c3ecf0..35b90155a2 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -35,8 +35,12 @@ typedef struct { uint32_t conf; } pl080_channel; -typedef struct { - SysBusDevice busdev; +#define TYPE_PL080 "pl080" +#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080) + +typedef struct PL080State { + SysBusDevice parent_obj; + MemoryRegion iomem; uint8_t tc_int; uint8_t tc_mask; @@ -51,7 +55,7 @@ typedef struct { /* Flag to avoid recursive DMA invocations. */ int running; qemu_irq irq; -} pl080_state; +} PL080State; static const VMStateDescription vmstate_pl080_channel = { .name = "pl080_channel", @@ -72,20 +76,20 @@ static const VMStateDescription vmstate_pl080 = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT8(tc_int, pl080_state), - VMSTATE_UINT8(tc_mask, pl080_state), - VMSTATE_UINT8(err_int, pl080_state), - VMSTATE_UINT8(err_mask, pl080_state), - VMSTATE_UINT32(conf, pl080_state), - VMSTATE_UINT32(sync, pl080_state), - VMSTATE_UINT32(req_single, pl080_state), - VMSTATE_UINT32(req_burst, pl080_state), - VMSTATE_UINT8(tc_int, pl080_state), - VMSTATE_UINT8(tc_int, pl080_state), - VMSTATE_UINT8(tc_int, pl080_state), - VMSTATE_STRUCT_ARRAY(chan, pl080_state, PL080_MAX_CHANNELS, + VMSTATE_UINT8(tc_int, PL080State), + VMSTATE_UINT8(tc_mask, PL080State), + VMSTATE_UINT8(err_int, PL080State), + VMSTATE_UINT8(err_mask, PL080State), + VMSTATE_UINT32(conf, PL080State), + VMSTATE_UINT32(sync, PL080State), + VMSTATE_UINT32(req_single, PL080State), + VMSTATE_UINT32(req_burst, PL080State), + VMSTATE_UINT8(tc_int, PL080State), + VMSTATE_UINT8(tc_int, PL080State), + VMSTATE_UINT8(tc_int, PL080State), + VMSTATE_STRUCT_ARRAY(chan, PL080State, PL080_MAX_CHANNELS, 1, vmstate_pl080_channel, pl080_channel), - VMSTATE_INT32(running, pl080_state), + VMSTATE_INT32(running, PL080State), VMSTATE_END_OF_LIST() } }; @@ -96,7 +100,7 @@ static const unsigned char pl080_id[] = static const unsigned char pl081_id[] = { 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; -static void pl080_update(pl080_state *s) +static void pl080_update(PL080State *s) { if ((s->tc_int & s->tc_mask) || (s->err_int & s->err_mask)) @@ -105,7 +109,7 @@ static void pl080_update(pl080_state *s) qemu_irq_lower(s->irq); } -static void pl080_run(pl080_state *s) +static void pl080_run(PL080State *s) { int c; int flow; @@ -221,7 +225,7 @@ again: static uint64_t pl080_read(void *opaque, hwaddr offset, unsigned size) { - pl080_state *s = (pl080_state *)opaque; + PL080State *s = (PL080State *)opaque; uint32_t i; uint32_t mask; @@ -290,7 +294,7 @@ static uint64_t pl080_read(void *opaque, hwaddr offset, static void pl080_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl080_state *s = (pl080_state *)opaque; + PL080State *s = (PL080State *)opaque; int i; if (offset >= 0x100 && offset < 0x200) { @@ -355,59 +359,44 @@ static const MemoryRegionOps pl080_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int pl08x_init(SysBusDevice *dev, int nchannels) +static void pl080_init(Object *obj) { - pl080_state *s = FROM_SYSBUS(pl080_state, dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + PL080State *s = PL080(obj); memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - s->nchannels = nchannels; - return 0; + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + s->nchannels = 8; } -static int pl080_init(SysBusDevice *dev) +static void pl081_init(Object *obj) { - return pl08x_init(dev, 8); -} + PL080State *s = PL080(obj); -static int pl081_init(SysBusDevice *dev) -{ - return pl08x_init(dev, 2); + s->nchannels = 2; } -static void pl080_class_init(ObjectClass *klass, void *data) +static void pl080_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(oc); - k->init = pl080_init; dc->no_user = 1; dc->vmsd = &vmstate_pl080; } static const TypeInfo pl080_info = { - .name = "pl080", + .name = TYPE_PL080, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl080_state), + .instance_size = sizeof(PL080State), + .instance_init = pl080_init, .class_init = pl080_class_init, }; -static void pl081_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pl081_init; - dc->no_user = 1; - dc->vmsd = &vmstate_pl080; -} - static const TypeInfo pl081_info = { .name = "pl081", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl080_state), - .class_init = pl081_class_init, + .parent = TYPE_PL080, + .instance_init = pl081_init, }; /* The PL080 and PL081 are the same except for the number of channels diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index ddcc4135d7..401399d330 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -1256,7 +1256,7 @@ static void pl330_dma_stop_irq(void *opaque, int irq, int level) if (s->periph_busy[irq] != level) { s->periph_busy[irq] = level; - qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock)); + timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } } @@ -1519,7 +1519,7 @@ static void pl330_reset(DeviceState *d) s->periph_busy[i] = 0; } - qemu_del_timer(s->timer); + timer_del(s->timer); } static void pl330_realize(DeviceState *dev, Error **errp) @@ -1532,7 +1532,7 @@ static void pl330_realize(DeviceState *dev, Error **errp) "dma", PL330_IOMEM_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - s->timer = qemu_new_timer_ns(vm_clock, pl330_exec_cycle_timer, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pl330_exec_cycle_timer, s); s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) | (s->num_periph_req > 0 ? 1 : 0) | diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c index 36004ae48a..101bd7f8af 100644 --- a/hw/dma/puv3_dma.c +++ b/hw/dma/puv3_dma.c @@ -18,8 +18,12 @@ #define PUV3_DMA_CH_MASK (0xff) #define PUV3_DMA_CH(offset) ((offset) >> 8) -typedef struct { - SysBusDevice busdev; +#define TYPE_PUV3_DMA "puv3_dma" +#define PUV3_DMA(obj) OBJECT_CHECK(PUV3DMAState, (obj), TYPE_PUV3_DMA) + +typedef struct PUV3DMAState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t reg_CFG[PUV3_DMA_CH_NR]; } PUV3DMAState; @@ -73,7 +77,7 @@ static const MemoryRegionOps puv3_dma_ops = { static int puv3_dma_init(SysBusDevice *dev) { - PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev); + PUV3DMAState *s = PUV3_DMA(dev); int i; for (i = 0; i < PUV3_DMA_CH_NR; i++) { @@ -95,7 +99,7 @@ static void puv3_dma_class_init(ObjectClass *klass, void *data) } static const TypeInfo puv3_dma_info = { - .name = "puv3_dma", + .name = TYPE_PUV3_DMA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PUV3DMAState), .class_init = puv3_dma_class_init, diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index bc7bf4c5e0..c013abb313 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -26,8 +26,12 @@ typedef struct { int request; } PXA2xxDMAChannel; +#define TYPE_PXA2XX_DMA "pxa2xx-dma" +#define PXA2XX_DMA(obj) OBJECT_CHECK(PXA2xxDMAState, (obj), TYPE_PXA2XX_DMA) + typedef struct PXA2xxDMAState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; @@ -445,11 +449,11 @@ static void pxa2xx_dma_request(void *opaque, int req_num, int on) } } -static int pxa2xx_dma_init(SysBusDevice *dev) +static int pxa2xx_dma_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); + PXA2xxDMAState *s = PXA2XX_DMA(dev); int i; - PXA2xxDMAState *s; - s = FROM_SYSBUS(PXA2xxDMAState, dev); if (s->channels <= 0) { return -1; @@ -463,12 +467,12 @@ static int pxa2xx_dma_init(SysBusDevice *dev) memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS); - qdev_init_gpio_in(&dev->qdev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS); + qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS); memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_dma_ops, s, "pxa2xx.dma", 0x00010000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); return 0; } @@ -560,7 +564,7 @@ static void pxa2xx_dma_class_init(ObjectClass *klass, void *data) } static const TypeInfo pxa2xx_dma_info = { - .name = "pxa2xx-dma", + .name = TYPE_PXA2XX_DMA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxDMAState), .class_init = pxa2xx_dma_class_init, diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 4ec433f957..af2663256e 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -107,7 +107,7 @@ static void set_next_tick(rc4030State *s) tm_hz = 1000 / (s->itr + 1); - qemu_mod_timer(s->periodic_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(s->periodic_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() / tm_hz); } @@ -806,7 +806,7 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16); *dmas = rc4030_allocate_dmas(s, 4); - s->periodic_timer = qemu_new_timer_ns(vm_clock, rc4030_periodic_timer, s); + s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s); s->timer_irq = timer; s->jazz_bus_irq = jazz_bus; diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c index 5e3491d373..c06aabb406 100644 --- a/hw/dma/soc_dma.c +++ b/hw/dma/soc_dma.c @@ -84,10 +84,10 @@ struct dma_s { static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes) { - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); struct dma_s *dma = (struct dma_s *) ch->dma; - qemu_mod_timer(ch->timer, now + delay_bytes / dma->channel_freq); + timer_mod(ch->timer, now + delay_bytes / dma->channel_freq); } static void soc_dma_ch_run(void *opaque) @@ -217,7 +217,7 @@ void soc_dma_set_request(struct soc_dma_ch_s *ch, int level) ch->enable = level; if (!ch->enable) - qemu_del_timer(ch->timer); + timer_del(ch->timer); else if (!ch->running) soc_dma_ch_run(ch); else @@ -246,7 +246,7 @@ struct soc_dma_s *soc_dma_init(int n) for (i = 0; i < n; i ++) { s->ch[i].dma = &s->soc; s->ch[i].num = i; - s->ch[i].timer = qemu_new_timer_ns(vm_clock, soc_dma_ch_run, &s->ch[i]); + s->ch[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, soc_dma_ch_run, &s->ch[i]); } soc_dma_reset(&s->soc); diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index be6275fea5..2a92ffb82e 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -60,10 +60,14 @@ /* XXX SCSI and ethernet should have different read-only bit masks */ #define DMA_CSR_RO_MASK 0xfe000007 +#define TYPE_SPARC32_DMA "sparc32_dma" +#define SPARC32_DMA(obj) OBJECT_CHECK(DMAState, (obj), TYPE_SPARC32_DMA) + typedef struct DMAState DMAState; struct DMAState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t dmaregs[DMA_REGS]; qemu_irq irq; @@ -249,7 +253,7 @@ static const MemoryRegionOps dma_mem_ops = { static void dma_reset(DeviceState *d) { - DMAState *s = container_of(d, DMAState, busdev.qdev); + DMAState *s = SPARC32_DMA(d); memset(s->dmaregs, 0, DMA_SIZE); s->dmaregs[0] = DMA_VER; @@ -266,20 +270,21 @@ static const VMStateDescription vmstate_dma = { } }; -static int sparc32_dma_init1(SysBusDevice *dev) +static int sparc32_dma_init1(SysBusDevice *sbd) { - DMAState *s = FROM_SYSBUS(DMAState, dev); + DeviceState *dev = DEVICE(sbd); + DMAState *s = SPARC32_DMA(dev); int reg_size; - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE; memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s, "dma", reg_size); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); - qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1); - qdev_init_gpio_out(&dev->qdev, s->gpio, 2); + qdev_init_gpio_in(dev, dma_set_irq, 1); + qdev_init_gpio_out(dev, s->gpio, 2); return 0; } @@ -302,7 +307,7 @@ static void sparc32_dma_class_init(ObjectClass *klass, void *data) } static const TypeInfo sparc32_dma_info = { - .name = "sparc32_dma", + .name = TYPE_SPARC32_DMA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(DMAState), .class_init = sparc32_dma_class_init, diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c index edb93f36ac..a04409a273 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/dma/sun4m_iommu.c @@ -126,8 +126,12 @@ #define IOMMU_PAGE_SIZE (1 << IOMMU_PAGE_SHIFT) #define IOMMU_PAGE_MASK ~(IOMMU_PAGE_SIZE - 1) +#define TYPE_SUN4M_IOMMU "iommu" +#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) + typedef struct IOMMUState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t regs[IOMMU_NREGS]; hwaddr iostart; @@ -332,7 +336,7 @@ static const VMStateDescription vmstate_iommu = { static void iommu_reset(DeviceState *d) { - IOMMUState *s = container_of(d, IOMMUState, busdev.qdev); + IOMMUState *s = SUN4M_IOMMU(d); memset(s->regs, 0, IOMMU_NREGS * 4); s->iostart = 0; @@ -345,7 +349,7 @@ static void iommu_reset(DeviceState *d) static int iommu_init1(SysBusDevice *dev) { - IOMMUState *s = FROM_SYSBUS(IOMMUState, dev); + IOMMUState *s = SUN4M_IOMMU(dev); sysbus_init_irq(dev, &s->irq); @@ -373,7 +377,7 @@ static void iommu_class_init(ObjectClass *klass, void *data) } static const TypeInfo iommu_info = { - .name = "iommu", + .name = TYPE_SUN4M_IOMMU, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOMMUState), .class_init = iommu_class_init, diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index a48e3baa99..59e8e35a4c 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -27,6 +27,7 @@ #include "hw/ptimer.h" #include "qemu/log.h" #include "qapi/qmp/qerror.h" +#include "qemu/main-loop.h" #include "hw/stream.h" diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index 855afae6bb..b8f572bb70 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -35,8 +35,13 @@ struct omap_gpio_s { uint16_t pins; }; +#define TYPE_OMAP1_GPIO "omap-gpio" +#define OMAP1_GPIO(obj) \ + OBJECT_CHECK(struct omap_gpif_s, (obj), TYPE_OMAP1_GPIO) + struct omap_gpif_s { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; int mpu_model; void *clk; @@ -203,8 +208,13 @@ struct omap2_gpio_s { uint8_t delay; }; +#define TYPE_OMAP2_GPIO "omap2-gpio" +#define OMAP2_GPIO(obj) \ + OBJECT_CHECK(struct omap2_gpif_s, (obj), TYPE_OMAP2_GPIO) + struct omap2_gpif_s { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; int mpu_model; void *iclk; @@ -587,16 +597,16 @@ static const MemoryRegionOps omap2_gpio_module_ops = { static void omap_gpif_reset(DeviceState *dev) { - struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, - SYS_BUS_DEVICE(dev)); + struct omap_gpif_s *s = OMAP1_GPIO(dev); + omap_gpio_reset(&s->omap1); } static void omap2_gpif_reset(DeviceState *dev) { + struct omap2_gpif_s *s = OMAP2_GPIO(dev); int i; - struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, - SYS_BUS_DEVICE(dev)); + for (i = 0; i < s->modulecount; i++) { omap2_gpio_module_reset(&s->modules[i]); } @@ -648,7 +658,7 @@ static void omap2_gpif_top_write(void *opaque, hwaddr addr, case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ if (value & (1 << 1)) /* SOFTRESET */ - omap2_gpif_reset(&s->busdev.qdev); + omap2_gpif_reset(DEVICE(s)); s->autoidle = value & 1; break; @@ -668,25 +678,29 @@ static const MemoryRegionOps omap2_gpif_top_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int omap_gpio_init(SysBusDevice *dev) +static int omap_gpio_init(SysBusDevice *sbd) { - struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev); + DeviceState *dev = DEVICE(sbd); + struct omap_gpif_s *s = OMAP1_GPIO(dev); + if (!s->clk) { hw_error("omap-gpio: clk not connected\n"); } - qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16); - qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16); - sysbus_init_irq(dev, &s->omap1.irq); + qdev_init_gpio_in(dev, omap_gpio_set, 16); + qdev_init_gpio_out(dev, s->omap1.handler, 16); + sysbus_init_irq(sbd, &s->omap1.irq); memory_region_init_io(&s->iomem, OBJECT(s), &omap_gpio_ops, &s->omap1, "omap.gpio", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } -static int omap2_gpio_init(SysBusDevice *dev) +static int omap2_gpio_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); + struct omap2_gpif_s *s = OMAP2_GPIO(dev); int i; - struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev); + if (!s->iclk) { hw_error("omap2-gpio: iclk not connected\n"); } @@ -694,14 +708,14 @@ static int omap2_gpio_init(SysBusDevice *dev) s->modulecount = (s->mpu_model < omap2430) ? 4 : 5; memory_region_init_io(&s->iomem, OBJECT(s), &omap2_gpif_top_ops, s, "omap2.gpio", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); } else { s->modulecount = 6; } s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s)); s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq)); - qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32); - qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32); + qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32); + qdev_init_gpio_out(dev, s->handler, s->modulecount * 32); for (i = 0; i < s->modulecount; i++) { struct omap2_gpio_s *m = &s->modules[i]; if (!s->fclk[i]) { @@ -709,12 +723,12 @@ static int omap2_gpio_init(SysBusDevice *dev) } m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25; m->handler = &s->handler[i * 32]; - sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */ - sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */ - sysbus_init_irq(dev, &m->wkup); + sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */ + sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */ + sysbus_init_irq(sbd, &m->wkup); memory_region_init_io(&m->iomem, OBJECT(s), &omap2_gpio_module_ops, m, "omap.gpio-module", 0x1000); - sysbus_init_mmio(dev, &m->iomem); + sysbus_init_mmio(sbd, &m->iomem); } return 0; } @@ -748,7 +762,7 @@ static void omap_gpio_class_init(ObjectClass *klass, void *data) } static const TypeInfo omap_gpio_info = { - .name = "omap-gpio", + .name = TYPE_OMAP1_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_gpif_s), .class_init = omap_gpio_class_init, @@ -777,7 +791,7 @@ static void omap2_gpio_class_init(ObjectClass *klass, void *data) } static const TypeInfo omap2_gpio_info = { - .name = "omap2-gpio", + .name = TYPE_OMAP2_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap2_gpif_s), .class_init = omap2_gpio_class_init, diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index a0bbf08542..dd4ea293e2 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -28,8 +28,12 @@ static const uint8_t pl061_id[12] = static const uint8_t pl061_id_luminary[12] = { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; -typedef struct { - SysBusDevice busdev; +#define TYPE_PL061 "pl061" +#define PL061(obj) OBJECT_CHECK(PL061State, (obj), TYPE_PL061) + +typedef struct PL061State { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t locked; uint32_t data; @@ -55,39 +59,39 @@ typedef struct { qemu_irq irq; qemu_irq out[8]; const unsigned char *id; -} pl061_state; +} PL061State; static const VMStateDescription vmstate_pl061 = { .name = "pl061", .version_id = 2, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(locked, pl061_state), - VMSTATE_UINT32(data, pl061_state), - VMSTATE_UINT32(old_data, pl061_state), - VMSTATE_UINT32(dir, pl061_state), - VMSTATE_UINT32(isense, pl061_state), - VMSTATE_UINT32(ibe, pl061_state), - VMSTATE_UINT32(iev, pl061_state), - VMSTATE_UINT32(im, pl061_state), - VMSTATE_UINT32(istate, pl061_state), - VMSTATE_UINT32(afsel, pl061_state), - VMSTATE_UINT32(dr2r, pl061_state), - VMSTATE_UINT32(dr4r, pl061_state), - VMSTATE_UINT32(dr8r, pl061_state), - VMSTATE_UINT32(odr, pl061_state), - VMSTATE_UINT32(pur, pl061_state), - VMSTATE_UINT32(pdr, pl061_state), - VMSTATE_UINT32(slr, pl061_state), - VMSTATE_UINT32(den, pl061_state), - VMSTATE_UINT32(cr, pl061_state), - VMSTATE_UINT32(float_high, pl061_state), - VMSTATE_UINT32_V(amsel, pl061_state, 2), + VMSTATE_UINT32(locked, PL061State), + VMSTATE_UINT32(data, PL061State), + VMSTATE_UINT32(old_data, PL061State), + VMSTATE_UINT32(dir, PL061State), + VMSTATE_UINT32(isense, PL061State), + VMSTATE_UINT32(ibe, PL061State), + VMSTATE_UINT32(iev, PL061State), + VMSTATE_UINT32(im, PL061State), + VMSTATE_UINT32(istate, PL061State), + VMSTATE_UINT32(afsel, PL061State), + VMSTATE_UINT32(dr2r, PL061State), + VMSTATE_UINT32(dr4r, PL061State), + VMSTATE_UINT32(dr8r, PL061State), + VMSTATE_UINT32(odr, PL061State), + VMSTATE_UINT32(pur, PL061State), + VMSTATE_UINT32(pdr, PL061State), + VMSTATE_UINT32(slr, PL061State), + VMSTATE_UINT32(den, PL061State), + VMSTATE_UINT32(cr, PL061State), + VMSTATE_UINT32(float_high, PL061State), + VMSTATE_UINT32_V(amsel, PL061State, 2), VMSTATE_END_OF_LIST() } }; -static void pl061_update(pl061_state *s) +static void pl061_update(PL061State *s) { uint8_t changed; uint8_t mask; @@ -116,7 +120,7 @@ static void pl061_update(pl061_state *s) static uint64_t pl061_read(void *opaque, hwaddr offset, unsigned size) { - pl061_state *s = (pl061_state *)opaque; + PL061State *s = (PL061State *)opaque; if (offset >= 0xfd0 && offset < 0x1000) { return s->id[(offset - 0xfd0) >> 2]; @@ -173,7 +177,7 @@ static uint64_t pl061_read(void *opaque, hwaddr offset, static void pl061_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl061_state *s = (pl061_state *)opaque; + PL061State *s = (PL061State *)opaque; uint8_t mask; if (offset < 0x400) { @@ -246,7 +250,7 @@ static void pl061_write(void *opaque, hwaddr offset, pl061_update(s); } -static void pl061_reset(pl061_state *s) +static void pl061_reset(PL061State *s) { s->locked = 1; s->cr = 0xff; @@ -254,7 +258,7 @@ static void pl061_reset(pl061_state *s) static void pl061_set_irq(void * opaque, int irq, int level) { - pl061_state *s = (pl061_state *)opaque; + PL061State *s = (PL061State *)opaque; uint8_t mask; mask = 1 << irq; @@ -272,27 +276,32 @@ static const MemoryRegionOps pl061_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int pl061_init(SysBusDevice *dev, const unsigned char *id) +static int pl061_initfn(SysBusDevice *sbd) { - pl061_state *s = FROM_SYSBUS(pl061_state, dev); - s->id = id; + DeviceState *dev = DEVICE(sbd); + PL061State *s = PL061(dev); + memory_region_init_io(&s->iomem, OBJECT(s), &pl061_ops, s, "pl061", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8); - qdev_init_gpio_out(&dev->qdev, s->out, 8); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_in(dev, pl061_set_irq, 8); + qdev_init_gpio_out(dev, s->out, 8); pl061_reset(s); return 0; } -static int pl061_init_luminary(SysBusDevice *dev) +static void pl061_luminary_init(Object *obj) { - return pl061_init(dev, pl061_id_luminary); + PL061State *s = PL061(obj); + + s->id = pl061_id_luminary; } -static int pl061_init_arm(SysBusDevice *dev) +static void pl061_init(Object *obj) { - return pl061_init(dev, pl061_id); + PL061State *s = PL061(obj); + + s->id = pl061_id; } static void pl061_class_init(ObjectClass *klass, void *data) @@ -300,31 +309,22 @@ static void pl061_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = pl061_init_arm; + k->init = pl061_initfn; dc->vmsd = &vmstate_pl061; } static const TypeInfo pl061_info = { - .name = "pl061", + .name = TYPE_PL061, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl061_state), + .instance_size = sizeof(PL061State), + .instance_init = pl061_init, .class_init = pl061_class_init, }; -static void pl061_luminary_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pl061_init_luminary; - dc->vmsd = &vmstate_pl061; -} - static const TypeInfo pl061_luminary_info = { .name = "pl061_luminary", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl061_state), - .class_init = pl061_luminary_class_init, + .parent = TYPE_PL061, + .instance_init = pl061_luminary_init, }; static void pl061_register_types(void) diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c index 18671eba9e..39840aa73c 100644 --- a/hw/gpio/puv3_gpio.c +++ b/hw/gpio/puv3_gpio.c @@ -14,8 +14,12 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_PUV3_GPIO "puv3_gpio" +#define PUV3_GPIO(obj) OBJECT_CHECK(PUV3GPIOState, (obj), TYPE_PUV3_GPIO) + +typedef struct PUV3GPIOState { + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq[9]; @@ -96,7 +100,7 @@ static const MemoryRegionOps puv3_gpio_ops = { static int puv3_gpio_init(SysBusDevice *dev) { - PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev); + PUV3GPIOState *s = PUV3_GPIO(dev); s->reg_GPLR = 0; s->reg_GPDR = 0; @@ -127,7 +131,7 @@ static void puv3_gpio_class_init(ObjectClass *klass, void *data) } static const TypeInfo puv3_gpio_info = { - .name = "puv3_gpio", + .name = TYPE_PUV3_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PUV3GPIOState), .class_init = puv3_gpio_class_init, diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index c235c3e188..dc79a8baa6 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -24,9 +24,13 @@ /* SCOOP devices */ +#define TYPE_SCOOP "scoop" +#define SCOOP(obj) OBJECT_CHECK(ScoopInfo, (obj), TYPE_SCOOP) + typedef struct ScoopInfo ScoopInfo; struct ScoopInfo { - SysBusDevice busdev; + SysBusDevice parent_obj; + qemu_irq handler[16]; MemoryRegion iomem; uint16_t status; @@ -162,16 +166,17 @@ static void scoop_gpio_set(void *opaque, int line, int level) s->gpio_level &= ~(1 << line); } -static int scoop_init(SysBusDevice *dev) +static int scoop_init(SysBusDevice *sbd) { - ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev); + DeviceState *dev = DEVICE(sbd); + ScoopInfo *s = SCOOP(dev); s->status = 0x02; - qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16); - qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16); + qdev_init_gpio_out(dev, s->handler, 16); + qdev_init_gpio_in(dev, scoop_gpio_set, 16); memory_region_init_io(&s->iomem, OBJECT(s), &scoop_ops, s, "scoop", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -237,7 +242,7 @@ static void scoop_sysbus_class_init(ObjectClass *klass, void *data) } static const TypeInfo scoop_sysbus_info = { - .name = "scoop", + .name = TYPE_SCOOP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ScoopInfo), .class_init = scoop_sysbus_class_init, diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index 5f8b97291a..ca59456d16 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -185,8 +185,13 @@ bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus) } /* GPIO interface. */ -typedef struct { - SysBusDevice busdev; + +#define TYPE_GPIO_I2C "gpio_i2c" +#define GPIO_I2C(obj) OBJECT_CHECK(GPIOI2CState, (obj), TYPE_GPIO_I2C) + +typedef struct GPIOI2CState { + SysBusDevice parent_obj; + MemoryRegion dummy_iomem; bitbang_i2c_interface *bitbang; int last_level; @@ -204,19 +209,20 @@ static void bitbang_i2c_gpio_set(void *opaque, int irq, int level) } } -static int gpio_i2c_init(SysBusDevice *dev) +static int gpio_i2c_init(SysBusDevice *sbd) { - GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev); + DeviceState *dev = DEVICE(sbd); + GPIOI2CState *s = GPIO_I2C(dev); i2c_bus *bus; memory_region_init(&s->dummy_iomem, OBJECT(s), "gpio_i2c", 0); - sysbus_init_mmio(dev, &s->dummy_iomem); + sysbus_init_mmio(sbd, &s->dummy_iomem); - bus = i2c_init_bus(&dev->qdev, "i2c"); + bus = i2c_init_bus(dev, "i2c"); s->bitbang = bitbang_i2c_init(bus); - qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2); - qdev_init_gpio_out(&dev->qdev, &s->out, 1); + qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2); + qdev_init_gpio_out(dev, &s->out, 1); return 0; } @@ -227,11 +233,12 @@ static void gpio_i2c_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = gpio_i2c_init; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Virtual GPIO to I2C bridge"; } static const TypeInfo gpio_i2c_info = { - .name = "gpio_i2c", + .name = TYPE_GPIO_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPIOI2CState), .class_init = gpio_i2c_class_init, diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 22ef3b9617..c97e7f7dc0 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -224,6 +224,7 @@ static void i2c_slave_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = i2c_slave_qdev_init; + set_bit(DEVICE_CATEGORY_MISC, k->categories); k->bus_type = TYPE_I2C_BUS; k->props = i2c_props; } diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c index 42f5e89496..ce5f849c77 100644 --- a/hw/i2c/exynos4210_i2c.c +++ b/hw/i2c/exynos4210_i2c.c @@ -80,7 +80,8 @@ static const char *exynos4_i2c_get_regname(unsigned offset) #endif typedef struct Exynos4210I2CState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; i2c_bus *bus; qemu_irq irq; @@ -297,15 +298,16 @@ static void exynos4210_i2c_reset(DeviceState *d) s->scl_free = true; } -static int exynos4210_i2c_realize(SysBusDevice *dev) +static int exynos4210_i2c_realize(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); Exynos4210I2CState *s = EXYNOS4_I2C(dev); memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C, EXYNOS4_I2C_MEM_SIZE); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - s->bus = i2c_init_bus(&dev->qdev, "i2c"); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + s->bus = i2c_init_bus(dev, "i2c"); return 0; } diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c index f0eb4489c7..f528b2b38e 100644 --- a/hw/i2c/omap_i2c.c +++ b/hw/i2c/omap_i2c.c @@ -21,9 +21,12 @@ #include "hw/arm/omap.h" #include "hw/sysbus.h" +#define TYPE_OMAP_I2C "omap_i2c" +#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C) typedef struct OMAPI2CState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq; qemu_irq drq[2]; @@ -130,8 +133,8 @@ static void omap_i2c_fifo_run(OMAPI2CState *s) static void omap_i2c_reset(DeviceState *dev) { - OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, - SYS_BUS_DEVICE(dev)); + OMAPI2CState *s = OMAP_I2C(dev); + s->mask = 0; s->stat = 0; s->dma = 0; @@ -316,15 +319,17 @@ static void omap_i2c_write(void *opaque, hwaddr addr, return; } - if (value & 2) - omap_i2c_reset(&s->busdev.qdev); + if (value & 2) { + omap_i2c_reset(DEVICE(s)); + } break; case 0x24: /* I2C_CON */ s->control = value & 0xcf87; if (~value & (1 << 15)) { /* I2C_EN */ - if (s->revision < OMAP2_INTR_REV) - omap_i2c_reset(&s->busdev.qdev); + if (s->revision < OMAP2_INTR_REV) { + omap_i2c_reset(DEVICE(s)); + } break; } if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */ @@ -434,9 +439,10 @@ static const MemoryRegionOps omap_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int omap_i2c_init(SysBusDevice *dev) +static int omap_i2c_init(SysBusDevice *sbd) { - OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev); + DeviceState *dev = DEVICE(sbd); + OMAPI2CState *s = OMAP_I2C(dev); if (!s->fclk) { hw_error("omap_i2c: fclk not connected\n"); @@ -445,13 +451,13 @@ static int omap_i2c_init(SysBusDevice *dev) /* Note that OMAP1 doesn't have a separate interface clock */ hw_error("omap_i2c: iclk not connected\n"); } - sysbus_init_irq(dev, &s->irq); - sysbus_init_irq(dev, &s->drq[0]); - sysbus_init_irq(dev, &s->drq[1]); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->drq[0]); + sysbus_init_irq(sbd, &s->drq[1]); memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c", (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000); - sysbus_init_mmio(dev, &s->iomem); - s->bus = i2c_init_bus(&dev->qdev, NULL); + sysbus_init_mmio(sbd, &s->iomem); + s->bus = i2c_init_bus(dev, NULL); return 0; } @@ -472,7 +478,7 @@ static void omap_i2c_class_init(ObjectClass *klass, void *data) } static const TypeInfo omap_i2c_info = { - .name = "omap_i2c", + .name = TYPE_OMAP_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OMAPI2CState), .class_init = omap_i2c_class_init, @@ -485,7 +491,7 @@ static void omap_i2c_register_types(void) i2c_bus *omap_i2c_bus(DeviceState *omap_i2c) { - OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, SYS_BUS_DEVICE(omap_i2c)); + OMAPI2CState *s = OMAP_I2C(omap_i2c); return s->bus; } diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 204dd3d532..02e9f171b9 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -24,8 +24,13 @@ #include "hw/sysbus.h" #include "bitbang_i2c.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_VERSATILE_I2C "versatile_i2c" +#define VERSATILE_I2C(obj) \ + OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C) + +typedef struct VersatileI2CState { + SysBusDevice parent_obj; + MemoryRegion iomem; bitbang_i2c_interface *bitbang; int out; @@ -72,16 +77,17 @@ static const MemoryRegionOps versatile_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int versatile_i2c_init(SysBusDevice *dev) +static int versatile_i2c_init(SysBusDevice *sbd) { - VersatileI2CState *s = FROM_SYSBUS(VersatileI2CState, dev); + DeviceState *dev = DEVICE(sbd); + VersatileI2CState *s = VERSATILE_I2C(dev); i2c_bus *bus; - bus = i2c_init_bus(&dev->qdev, "i2c"); + bus = i2c_init_bus(dev, "i2c"); s->bitbang = bitbang_i2c_init(bus); memory_region_init_io(&s->iomem, OBJECT(s), &versatile_i2c_ops, s, "versatile_i2c", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -93,7 +99,7 @@ static void versatile_i2c_class_init(ObjectClass *klass, void *data) } static const TypeInfo versatile_i2c_info = { - .name = "versatile_i2c", + .name = TYPE_VERSATILE_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(VersatileI2CState), .class_init = versatile_i2c_class_init, diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 205d22e4aa..45e61655e9 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,6 +1,7 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += multiboot.o smbios.o obj-y += pc.o pc_piix.o pc_q35.o +obj-y += pc_sysfw.o obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o obj-y += kvmvapic.o diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 179b806d96..5609063120 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -79,7 +79,7 @@ void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic) v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); s->count_shift = (v + 1) & 7; - s->initial_count_load_time = qemu_get_clock_ns(vm_clock); + s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); apic_next_timer(s, s->initial_count_load_time); } diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c index c1f40948f9..20b6457fbd 100644 --- a/hw/i386/kvm/i8254.c +++ b/hw/i386/kvm/i8254.c @@ -65,12 +65,12 @@ static void kvm_pit_update_clock_offset(KVMPITState *s) /* * Measure the delta between CLOCK_MONOTONIC, the base used for - * kvm_pit_channel_state::count_load_time, and vm_clock. Take the + * kvm_pit_channel_state::count_load_time, and QEMU_CLOCK_VIRTUAL. Take the * minimum of several samples to filter out scheduling noise. */ clock_offset = INT64_MAX; for (i = 0; i < CALIBRATION_ROUNDS; i++) { - offset = qemu_get_clock_ns(vm_clock); + offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); clock_gettime(CLOCK_MONOTONIC, &ts); offset -= ts.tv_nsec; offset -= (int64_t)ts.tv_sec * 1000000000; @@ -194,7 +194,7 @@ static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val) case 5: if (sc->gate < val) { /* restart counting on rising edge */ - sc->count_load_time = qemu_get_clock_ns(vm_clock); + sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } break; } diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index 688cb5cab3..f11a540825 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -112,7 +112,7 @@ static void kvm_ioapic_put(IOAPICCommonState *s) static void kvm_ioapic_reset(DeviceState *dev) { - IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev); + IOAPICCommonState *s = IOAPIC_COMMON(dev); ioapic_reset_common(dev); kvm_ioapic_put(s); @@ -131,7 +131,7 @@ static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no) { memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000); - qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS); + qdev_init_gpio_in(DEVICE(s), kvm_ioapic_set_irq, IOAPIC_NUM_PINS); } static Property kvm_ioapic_properties[] = { diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index 73941b2950..011764fbf6 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -1855,6 +1855,7 @@ static void assign_class_init(ObjectClass *klass, void *data) dc->props = assigned_dev_properties; dc->vmsd = &vmstate_assigned_device; dc->reset = reset_assigned_device; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "KVM-based PCI passthrough"; } diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index a4506bcf42..15beb8044e 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -456,7 +456,7 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip, TPRAccess access) { - VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); + VAPICROMState *s = VAPIC(dev); X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -508,7 +508,7 @@ static void vapic_enable_tpr_reporting(bool enable) static void vapic_reset(DeviceState *dev) { - VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); + VAPICROMState *s = VAPIC(dev); if (s->state == VAPIC_ACTIVE) { s->state = VAPIC_STANDBY; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2a8756321b..3a620a1856 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -55,6 +55,7 @@ #include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" #include "hw/boards.h" +#include "hw/pci/pci_host.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -75,8 +76,6 @@ #define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) #define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4) -#define IO_APIC_DEFAULT_ADDRESS 0xfec00000 - #define E820_NR_ENTRIES 16 struct e820_entry { @@ -913,20 +912,19 @@ static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, X86CPU *cpu; Error *local_err = NULL; - cpu = cpu_x86_create(cpu_model, icc_bridge, errp); - if (!cpu) { - return cpu; + cpu = cpu_x86_create(cpu_model, icc_bridge, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return NULL; } object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err); object_property_set_bool(OBJECT(cpu), true, "realized", &local_err); if (local_err) { - if (cpu != NULL) { - object_unref(OBJECT(cpu)); - cpu = NULL; - } error_propagate(errp, local_err); + object_unref(OBJECT(cpu)); + cpu = NULL; } return cpu; } @@ -980,7 +978,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i), icc_bridge, &error); if (error) { - fprintf(stderr, "%s\n", error_get_pretty(error)); + error_report("%s", error_get_pretty(error)); error_free(error); exit(1); } @@ -1005,15 +1003,27 @@ typedef struct PcRomPciInfo { static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info) { PcRomPciInfo *info; + Object *pci_info; + bool ambiguous = false; + if (!guest_info->has_pci_info || !guest_info->fw_cfg) { return; } + pci_info = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous); + g_assert(!ambiguous); + if (!pci_info) { + return; + } info = g_malloc(sizeof *info); - info->w32_min = cpu_to_le64(guest_info->pci_info.w32.begin); - info->w32_max = cpu_to_le64(guest_info->pci_info.w32.end); - info->w64_min = cpu_to_le64(guest_info->pci_info.w64.begin); - info->w64_max = cpu_to_le64(guest_info->pci_info.w64.end); + info->w32_min = cpu_to_le64(object_property_get_int(pci_info, + PCI_HOST_PROP_PCI_HOLE_START, NULL)); + info->w32_max = cpu_to_le64(object_property_get_int(pci_info, + PCI_HOST_PROP_PCI_HOLE_END, NULL)); + info->w64_min = cpu_to_le64(object_property_get_int(pci_info, + PCI_HOST_PROP_PCI_HOLE64_START, NULL)); + info->w64_max = cpu_to_le64(object_property_get_int(pci_info, + PCI_HOST_PROP_PCI_HOLE64_END, NULL)); /* Pass PCI hole info to guest via a side channel. * Required so guest PCI enumeration does the right thing. */ fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info); @@ -1039,29 +1049,28 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); PcGuestInfo *guest_info = &guest_info_state->info; - guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS; - if (sizeof(hwaddr) == 4) { - guest_info->pci_info.w64.begin = 0; - guest_info->pci_info.w64.end = 0; - } else { - /* - * BIOS does not set MTRR entries for the 64 bit window, so no need to - * align address to power of two. Align address at 1G, this makes sure - * it can be exactly covered with a PAT entry even when using huge - * pages. - */ - guest_info->pci_info.w64.begin = - ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30); - guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin + - (0x1ULL << 62); - assert(guest_info->pci_info.w64.begin <= guest_info->pci_info.w64.end); - } - guest_info_state->machine_done.notify = pc_guest_info_machine_done; qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); return guest_info; } +void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start, + uint64_t pci_hole64_size) +{ + if ((sizeof(hwaddr) == 4) || (!pci_hole64_size)) { + return; + } + /* + * BIOS does not set MTRR entries for the 64 bit window, so no need to + * align address to power of two. Align address at 1G, this makes sure + * it can be exactly covered with a PAT entry even when using huge + * pages. + */ + pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30); + pci_info->w64.end = pci_info->w64.begin + pci_hole64_size; + assert(pci_info->w64.begin <= pci_info->w64.end); +} + void pc_acpi_init(const char *default_dsdt) { char *filename; @@ -1087,8 +1096,8 @@ void pc_acpi_init(const char *default_dsdt) acpi_table_add(opts, &err); if (err) { - fprintf(stderr, "WARNING: failed to load %s: %s\n", filename, - error_get_pretty(err)); + error_report("WARNING: failed to load %s: %s", filename, + error_get_pretty(err)); error_free(err); } g_free(arg); @@ -1136,7 +1145,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory, /* Initialize PC system firmware */ - pc_system_firmware_init(rom_memory); + pc_system_firmware_init(rom_memory, guest_info->isapc_ram_fw); option_rom_mr = g_malloc(sizeof(*option_rom_mr)); memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index b58c25596d..3c36a2a1c3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -25,6 +25,7 @@ #include <glib.h> #include "hw/hw.h" +#include "hw/loader.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" #include "hw/pci/pci.h" @@ -56,21 +57,16 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; -static bool has_pvpanic = true; +static bool has_pvpanic; static bool has_pci_info = true; /* PC hardware initialisation */ -static void pc_init1(MemoryRegion *system_memory, - MemoryRegion *system_io, - ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model, +static void pc_init1(QEMUMachineInitArgs *args, int pci_enabled, int kvmclock_enabled) { + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *system_io = get_system_io(); int i; ram_addr_t below_4g_mem_size, above_4g_mem_size; PCIBus *pci_bus; @@ -102,19 +98,18 @@ static void pc_init1(MemoryRegion *system_memory, object_property_add_child(qdev_get_machine(), "icc-bridge", OBJECT(icc_bridge), NULL); - pc_cpus_init(cpu_model, icc_bridge); - pc_acpi_init("acpi-dsdt.aml"); + pc_cpus_init(args->cpu_model, icc_bridge); if (kvm_enabled() && kvmclock_enabled) { kvmclock_create(); } - if (ram_size >= 0xe0000000 ) { - above_4g_mem_size = ram_size - 0xe0000000; + if (args->ram_size >= 0xe0000000) { + above_4g_mem_size = args->ram_size - 0xe0000000; below_4g_mem_size = 0xe0000000; } else { above_4g_mem_size = 0; - below_4g_mem_size = ram_size; + below_4g_mem_size = args->ram_size; } if (pci_enabled) { @@ -128,20 +123,13 @@ static void pc_init1(MemoryRegion *system_memory, guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); guest_info->has_pci_info = has_pci_info; - - /* Set PCI window size the way seabios has always done it. */ - /* Power of 2 so bios can cover it with a single MTRR */ - if (ram_size <= 0x80000000) - guest_info->pci_info.w32.begin = 0x80000000; - else if (ram_size <= 0xc0000000) - guest_info->pci_info.w32.begin = 0xc0000000; - else - guest_info->pci_info.w32.begin = 0xe0000000; + guest_info->isapc_ram_fw = !pci_enabled; /* allocate ram and load rom/bios */ if (!xen_enabled()) { fw_cfg = pc_memory_init(system_memory, - kernel_filename, kernel_cmdline, initrd_filename, + args->kernel_filename, args->kernel_cmdline, + args->initrd_filename, below_4g_mem_size, above_4g_mem_size, rom_memory, &ram_memory, guest_info); } @@ -157,13 +145,10 @@ static void pc_init1(MemoryRegion *system_memory, if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, - system_memory, system_io, ram_size, + system_memory, system_io, args->ram_size, below_4g_mem_size, 0x100000000ULL - below_4g_mem_size, - 0x100000000ULL + above_4g_mem_size, - (sizeof(hwaddr) == 4 - ? 0 - : ((uint64_t)1 << 62)), + above_4g_mem_size, pci_memory, ram_memory); } else { pci_bus = NULL; @@ -219,7 +204,7 @@ static void pc_init1(MemoryRegion *system_memory, } } - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_device, floppy, idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled(false)) { @@ -248,90 +233,91 @@ static void pc_init1(MemoryRegion *system_memory, static void pc_init_pci(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - pc_init1(get_system_memory(), - get_system_io(), - ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 1, 1); + pc_init1(args, 1, 1); } -static void pc_init_pci_1_5(QEMUMachineInitArgs *args) +static void pc_compat_1_6(QEMUMachineInitArgs *args) { has_pci_info = false; - pc_init_pci(args); + rom_file_in_ram = false; } -static void pc_init_pci_1_4(QEMUMachineInitArgs *args) +static void pc_compat_1_5(QEMUMachineInitArgs *args) { + pc_compat_1_6(args); + has_pvpanic = true; +} + +static void pc_compat_1_4(QEMUMachineInitArgs *args) +{ + pc_compat_1_5(args); has_pvpanic = false; x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); - pc_init_pci_1_5(args); + x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } -static void pc_init_pci_1_3(QEMUMachineInitArgs *args) +static void pc_compat_1_3(QEMUMachineInitArgs *args) { + pc_compat_1_4(args); enable_compat_apic_id_mode(); - pc_init_pci_1_4(args); } -/* PC machine init function for pc-1.1 to pc-1.2 */ -static void pc_init_pci_1_2(QEMUMachineInitArgs *args) +/* PC compat function for pc-0.14 to pc-1.2 */ +static void pc_compat_1_2(QEMUMachineInitArgs *args) { + pc_compat_1_3(args); disable_kvm_pv_eoi(); - pc_init_pci_1_3(args); } -/* PC machine init function for pc-0.14 to pc-1.0 */ -static void pc_init_pci_1_0(QEMUMachineInitArgs *args) +static void pc_init_pci_1_6(QEMUMachineInitArgs *args) +{ + pc_compat_1_6(args); + pc_init_pci(args); +} + +static void pc_init_pci_1_5(QEMUMachineInitArgs *args) +{ + pc_compat_1_5(args); + pc_init_pci(args); +} + +static void pc_init_pci_1_4(QEMUMachineInitArgs *args) +{ + pc_compat_1_4(args); + pc_init_pci(args); +} + +static void pc_init_pci_1_3(QEMUMachineInitArgs *args) { - pc_init_pci_1_2(args); + pc_compat_1_3(args); + pc_init_pci(args); +} + +/* PC machine init function for pc-0.14 to pc-1.2 */ +static void pc_init_pci_1_2(QEMUMachineInitArgs *args) +{ + pc_compat_1_2(args); + pc_init_pci(args); } /* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - has_pvpanic = false; has_pci_info = false; disable_kvm_pv_eoi(); enable_compat_apic_id_mode(); - pc_init1(get_system_memory(), - get_system_io(), - ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 1, 0); + pc_init1(args, 1, 0); } static void pc_init_isa(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - has_pvpanic = false; has_pci_info = false; - if (cpu_model == NULL) - cpu_model = "486"; + if (!args->cpu_model) { + args->cpu_model = "486"; + } disable_kvm_pv_eoi(); enable_compat_apic_id_mode(); - pc_init1(get_system_memory(), - get_system_io(), - ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 0, 1); + pc_init1(args, 0, 1); } #ifdef CONFIG_XEN @@ -352,7 +338,7 @@ static QEMUMachine pc_i440fx_machine_v1_6 = { .name = "pc-i440fx-1.6", .alias = "pc", .desc = "Standard PC (i440FX + PIIX, 1996)", - .init = pc_init_pci, + .init = pc_init_pci_1_6, .hot_add_cpu = pc_hot_add_cpu, .max_cpus = 255, .is_default = 1, @@ -503,10 +489,6 @@ static QEMUMachine pc_machine_v1_1 = { #define PC_COMPAT_1_0 \ PC_COMPAT_1_1,\ {\ - .driver = "pc-sysfw",\ - .property = "rom_only",\ - .value = stringify(1),\ - }, {\ .driver = TYPE_ISA_FDC,\ .property = "check_media_rate",\ .value = "off",\ @@ -527,7 +509,7 @@ static QEMUMachine pc_machine_v1_1 = { static QEMUMachine pc_machine_v1_0 = { .name = "pc-1.0", .desc = "Standard PC", - .init = pc_init_pci_1_0, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_0, @@ -543,7 +525,7 @@ static QEMUMachine pc_machine_v1_0 = { static QEMUMachine pc_machine_v0_15 = { .name = "pc-0.15", .desc = "Standard PC", - .init = pc_init_pci_1_0, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_0_15, @@ -576,7 +558,7 @@ static QEMUMachine pc_machine_v0_15 = { static QEMUMachine pc_machine_v0_14 = { .name = "pc-0.14", .desc = "Standard PC", - .init = pc_init_pci_1_0, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_0_14, @@ -753,16 +735,6 @@ static QEMUMachine isapc_machine = { .init = pc_init_isa, .max_cpus = 1, .compat_props = (GlobalProperty[]) { - { - .driver = "pc-sysfw", - .property = "rom_only", - .value = stringify(1), - }, - { - .driver = "pc-sysfw", - .property = "isapc_ram_fw", - .value = stringify(1), - }, { /* end of list */ } }, DEFAULT_MACHINE_OPTIONS, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0b1d2e32f7..198c7851b3 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -28,6 +28,7 @@ * THE SOFTWARE. */ #include "hw/hw.h" +#include "hw/loader.h" #include "sysemu/arch_init.h" #include "hw/i2c/smbus.h" #include "hw/boards.h" @@ -46,18 +47,12 @@ /* ICH9 AHCI has 6 ports */ #define MAX_SATA_PORTS 6 -static bool has_pvpanic = true; +static bool has_pvpanic; static bool has_pci_info = true; /* PC hardware initialisation */ static void pc_q35_init(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; ram_addr_t below_4g_mem_size, above_4g_mem_size; Q35PCIHost *q35_host; PCIHostState *phb; @@ -85,17 +80,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args) object_property_add_child(qdev_get_machine(), "icc-bridge", OBJECT(icc_bridge), NULL); - pc_cpus_init(cpu_model, icc_bridge); + pc_cpus_init(args->cpu_model, icc_bridge); pc_acpi_init("q35-acpi-dsdt.aml"); kvmclock_create(); - if (ram_size >= 0xb0000000) { - above_4g_mem_size = ram_size - 0xb0000000; + if (args->ram_size >= 0xb0000000) { + above_4g_mem_size = args->ram_size - 0xb0000000; below_4g_mem_size = 0xb0000000; } else { above_4g_mem_size = 0; - below_4g_mem_size = ram_size; + below_4g_mem_size = args->ram_size; } /* pci enabled */ @@ -110,11 +105,14 @@ static void pc_q35_init(QEMUMachineInitArgs *args) guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); guest_info->has_pci_info = has_pci_info; + guest_info->isapc_ram_fw = false; /* allocate ram and load rom/bios */ if (!xen_enabled()) { - pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline, - initrd_filename, below_4g_mem_size, above_4g_mem_size, + pc_memory_init(get_system_memory(), + args->kernel_filename, args->kernel_cmdline, + args->initrd_filename, + below_4g_mem_size, above_4g_mem_size, rom_memory, &ram_memory, guest_info); } @@ -131,6 +129,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) /* create pci host bus */ q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); + object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host), NULL); q35_host->mch.ram_memory = ram_memory; q35_host->mch.pci_address_space = pci_memory; q35_host->mch.system_memory = get_system_memory(); @@ -201,7 +200,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) 0xb100), 8, NULL, 0); - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_device, floppy, idebus[0], idebus[1], rtc_state); /* the rest devices to which pci devfn is automatically assigned */ @@ -216,24 +215,49 @@ static void pc_q35_init(QEMUMachineInitArgs *args) } } -static void pc_q35_init_1_5(QEMUMachineInitArgs *args) +static void pc_compat_1_6(QEMUMachineInitArgs *args) { has_pci_info = false; - pc_q35_init(args); + rom_file_in_ram = false; } -static void pc_q35_init_1_4(QEMUMachineInitArgs *args) +static void pc_compat_1_5(QEMUMachineInitArgs *args) +{ + pc_compat_1_6(args); + has_pvpanic = true; +} + +static void pc_compat_1_4(QEMUMachineInitArgs *args) { + pc_compat_1_5(args); has_pvpanic = false; x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); - pc_q35_init_1_5(args); + x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); +} + +static void pc_q35_init_1_6(QEMUMachineInitArgs *args) +{ + pc_compat_1_6(args); + pc_q35_init(args); +} + +static void pc_q35_init_1_5(QEMUMachineInitArgs *args) +{ + pc_compat_1_5(args); + pc_q35_init(args); +} + +static void pc_q35_init_1_4(QEMUMachineInitArgs *args) +{ + pc_compat_1_4(args); + pc_q35_init(args); } static QEMUMachine pc_q35_machine_v1_6 = { .name = "pc-q35-1.6", .alias = "q35", .desc = "Standard PC (Q35 + ICH9, 2009)", - .init = pc_q35_init, + .init = pc_q35_init_1_6, .hot_add_cpu = pc_hot_add_cpu, .max_cpus = 255, DEFAULT_MACHINE_OPTIONS, diff --git a/hw/block/pc_sysfw.c b/hw/i386/pc_sysfw.c index 0669410cfc..8246a1bdd4 100644 --- a/hw/block/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -38,7 +38,6 @@ typedef struct PcSysFwDevice { SysBusDevice busdev; - uint8_t rom_only; uint8_t isapc_ram_fw; } PcSysFwDevice; @@ -76,39 +75,6 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory, memory_region_set_readonly(isa_bios, true); } -static void pc_fw_add_pflash_drv(void) -{ - QemuOpts *opts; - QEMUMachine *machine; - char *filename; - - if (bios_name == NULL) { - bios_name = BIOS_FILENAME; - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (!filename) { - error_report("Can't open BIOS image %s", bios_name); - exit(1); - } - - opts = drive_add(IF_PFLASH, -1, filename, "readonly=on"); - - g_free(filename); - - if (opts == NULL) { - return; - } - - machine = find_default_machine(); - if (machine == NULL) { - return; - } - - if (!drive_init(opts, machine->block_default_type)) { - qemu_opts_del(opts); - } -} - static void pc_system_flash_init(MemoryRegion *rom_memory, DriveInfo *pflash_drv) { @@ -199,109 +165,24 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) bios); } -/* - * Bug-compatible flash vs. ROM selection enabled? - * A few older machines enable this. - */ -bool pc_sysfw_flash_vs_rom_bug_compatible; - -void pc_system_firmware_init(MemoryRegion *rom_memory) +void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw) { DriveInfo *pflash_drv; - PcSysFwDevice *sysfw_dev; - - /* - * TODO This device exists only so that users can switch between - * use of flash and ROM for the BIOS. The ability to switch was - * created because flash doesn't work with KVM. Once it does, we - * should drop this device. - */ - sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw"); - - qdev_init_nofail(DEVICE(sysfw_dev)); pflash_drv = drive_get(IF_PFLASH, 0, 0); - if (pc_sysfw_flash_vs_rom_bug_compatible) { - /* - * This is a Bad Idea, because it makes enabling/disabling KVM - * guest-visible. Do it only in bug-compatibility mode. - */ - if (kvm_enabled()) { - if (pflash_drv != NULL) { - fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n"); - exit(1); - } else { - /* In old pc_sysfw_flash_vs_rom_bug_compatible mode, we assume - * that KVM cannot execute from device memory. In this case, we - * use old rom based firmware initialization for KVM. But, since - * this is different from non-kvm mode, this behavior is - * undesirable */ - sysfw_dev->rom_only = 1; - } - } - } else if (pflash_drv == NULL) { + if (isapc_ram_fw || pflash_drv == NULL) { /* When a pflash drive is not found, use rom-mode */ - sysfw_dev->rom_only = 1; - } else if (kvm_enabled() && !kvm_readonly_mem_enabled()) { - /* Older KVM cannot execute from device memory. So, flash memory - * cannot be used unless the readonly memory kvm capability is present. */ - fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n"); - exit(1); - } - - /* If rom-mode is active, use the old pc system rom initialization. */ - if (sysfw_dev->rom_only) { - old_pc_system_rom_init(rom_memory, sysfw_dev->isapc_ram_fw); + old_pc_system_rom_init(rom_memory, isapc_ram_fw); return; } - /* If a pflash drive is not found, then create one using - the bios filename. */ - if (pflash_drv == NULL) { - pc_fw_add_pflash_drv(); - pflash_drv = drive_get(IF_PFLASH, 0, 0); - } - - if (pflash_drv != NULL) { - pc_system_flash_init(rom_memory, pflash_drv); - } else { - fprintf(stderr, "qemu: PC system firmware (pflash) not available\n"); + if (kvm_enabled() && !kvm_readonly_mem_enabled()) { + /* Older KVM cannot execute from device memory. So, flash memory + * cannot be used unless the readonly memory kvm capability is present. */ + fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n"); exit(1); } -} -static Property pcsysfw_properties[] = { - DEFINE_PROP_UINT8("isapc_ram_fw", PcSysFwDevice, isapc_ram_fw, 0), - DEFINE_PROP_UINT8("rom_only", PcSysFwDevice, rom_only, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static int pcsysfw_init(DeviceState *dev) -{ - return 0; -} - -static void pcsysfw_class_init (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - - dc->desc = "PC System Firmware"; - dc->init = pcsysfw_init; - dc->props = pcsysfw_properties; + pc_system_flash_init(rom_memory, pflash_drv); } - -static const TypeInfo pcsysfw_info = { - .name = "pc-sysfw", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof (PcSysFwDevice), - .class_init = pcsysfw_class_init, -}; - -static void pcsysfw_register (void) -{ - type_register_static (&pcsysfw_info); -} - -type_init (pcsysfw_register); - diff --git a/hw/i386/xen_domainbuild.c b/hw/i386/xen_domainbuild.c index 4e2cf95ae5..c0ab7537df 100644 --- a/hw/i386/xen_domainbuild.c +++ b/hw/i386/xen_domainbuild.c @@ -148,7 +148,7 @@ static void xen_domain_poll(void *opaque) goto quit; } - qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); + timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); return; quit: @@ -290,8 +290,8 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk, goto err; } - xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL); - qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); + xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL); + timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); return 0; err: diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 419adde0ea..bba150fd74 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1338,6 +1338,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sysbus_ahci; dc->props = sysbus_ahci_properties; dc->reset = sysbus_ahci_reset; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sysbus_ahci_info = { diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 33be3867a0..d6ef7992d4 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -127,7 +127,7 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) { BMDMAState *bm = opaque; - PCIIDEState *pci_dev = bm->pci_dev; + PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); uint32_t val; if (size != 1) { @@ -139,16 +139,16 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr, val = bm->cmd; break; case 1: - val = pci_dev->dev.config[MRDMODE]; + val = pci_dev->config[MRDMODE]; break; case 2: val = bm->status; break; case 3: - if (bm == &pci_dev->bmdma[0]) { - val = pci_dev->dev.config[UDIDETCR0]; + if (bm == &bm->pci_dev->bmdma[0]) { + val = pci_dev->config[UDIDETCR0]; } else { - val = pci_dev->dev.config[UDIDETCR1]; + val = pci_dev->config[UDIDETCR1]; } break; default: @@ -165,7 +165,7 @@ static void bmdma_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { BMDMAState *bm = opaque; - PCIIDEState *pci_dev = bm->pci_dev; + PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); if (size != 1) { return; @@ -179,18 +179,19 @@ static void bmdma_write(void *opaque, hwaddr addr, bmdma_cmd_writeb(bm, val); break; case 1: - pci_dev->dev.config[MRDMODE] = - (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); - cmd646_update_irq(pci_dev); + pci_dev->config[MRDMODE] = + (pci_dev->config[MRDMODE] & ~0x30) | (val & 0x30); + cmd646_update_irq(bm->pci_dev); break; case 2: bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); break; case 3: - if (bm == &pci_dev->bmdma[0]) - pci_dev->dev.config[UDIDETCR0] = val; - else - pci_dev->dev.config[UDIDETCR1] = val; + if (bm == &bm->pci_dev->bmdma[0]) { + pci_dev->config[UDIDETCR0] = val; + } else { + pci_dev->config[UDIDETCR1] = val; + } break; } } @@ -222,25 +223,29 @@ static void bmdma_setup_bar(PCIIDEState *d) registers */ static void cmd646_update_irq(PCIIDEState *d) { + PCIDevice *pd = PCI_DEVICE(d); int pci_level; - pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) && - !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) || - ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) && - !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1)); - qemu_set_irq(d->dev.irq[0], pci_level); + + pci_level = ((pd->config[MRDMODE] & MRDMODE_INTR_CH0) && + !(pd->config[MRDMODE] & MRDMODE_BLK_CH0)) || + ((pd->config[MRDMODE] & MRDMODE_INTR_CH1) && + !(pd->config[MRDMODE] & MRDMODE_BLK_CH1)); + qemu_set_irq(pd->irq[0], pci_level); } /* the PCI irq level is the logical OR of the two channels */ static void cmd646_set_irq(void *opaque, int channel, int level) { PCIIDEState *d = opaque; + PCIDevice *pd = PCI_DEVICE(d); int irq_mask; irq_mask = MRDMODE_INTR_CH0 << channel; - if (level) - d->dev.config[MRDMODE] |= irq_mask; - else - d->dev.config[MRDMODE] &= ~irq_mask; + if (level) { + pd->config[MRDMODE] |= irq_mask; + } else { + pd->config[MRDMODE] &= ~irq_mask; + } cmd646_update_irq(d); } @@ -257,8 +262,8 @@ static void cmd646_reset(void *opaque) /* CMD646 PCI IDE controller */ static int pci_cmd646_ide_initfn(PCIDevice *dev) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); - uint8_t *pci_conf = d->dev.config; + PCIIDEState *d = PCI_IDE(dev); + uint8_t *pci_conf = dev->config; qemu_irq *irq; int i; @@ -284,7 +289,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev) irq = qemu_allocate_irqs(cmd646_set_irq, d, 2); for (i = 0; i < 2; i++) { - ide_bus_new(&d->bus[i], &d->dev.qdev, i, 2); + ide_bus_new(&d->bus[i], DEVICE(dev), i, 2); ide_init2(&d->bus[i], irq[i]); bmdma_init(&d->bus[i], &d->bmdma[i], d); @@ -293,14 +298,14 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev) &d->bmdma[i].dma); } - vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d); + vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d); qemu_register_reset(cmd646_reset, d); return 0; } static void pci_cmd646_ide_exitfn(PCIDevice *dev) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); + PCIIDEState *d = PCI_IDE(dev); unsigned i; for (i = 0; i < 2; ++i) { @@ -347,8 +352,7 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data) static const TypeInfo cmd646_ide_info = { .name = "cmd646-ide", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIIDEState), + .parent = TYPE_PCI_IDE, .class_init = cmd646_ide_class_init, }; diff --git a/hw/ide/core.c b/hw/ide/core.c index a73af7252a..399b1bae68 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -768,8 +768,8 @@ static void ide_sector_write_cb(void *opaque, int ret) that at the expense of slower write performances. Use this option _only_ to install Windows 2000. You must disable it for normal use. */ - qemu_mod_timer(s->sector_write_timer, - qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 1000)); + timer_mod(s->sector_write_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / 1000)); } else { ide_set_irq(s->bus); } @@ -2163,7 +2163,7 @@ static void ide_init1(IDEBus *bus, int unit) s->smart_selftest_data = qemu_blockalign(s->bs, 512); memset(s->smart_selftest_data, 0, 512); - s->sector_write_timer = qemu_new_timer_ns(vm_clock, + s->sector_write_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ide_sector_write_timer_cb, s); } diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 4eb5488993..bff952bf6a 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -160,6 +160,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_STORAGE_SATA; dc->vmsd = &vmstate_ich9_ahci; dc->reset = pci_ich9_reset; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo ich_ahci_info = { diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 7243c82c0f..bbc8c6b9c9 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -118,6 +118,7 @@ static void isa_ide_class_initfn(ObjectClass *klass, void *data) dc->fw_name = "ide"; dc->reset = isa_ide_reset; dc->props = isa_ide_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo isa_ide_info = { diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 38ad92423d..ef4ba2b2c5 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -131,7 +131,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) int sector_num = (s->lba << 2) + (s->io_buffer_index >> 9); int nsector = io->len >> 9; - MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n", + MACIO_DPRINTF("precopying unaligned %d bytes to %#" HWADDR_PRIx "\n", unaligned, io->addr + io->len - unaligned); bdrv_read(s->bs, sector_num + nsector, io->remainder, 1); @@ -212,14 +212,15 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->nsector -= n; } - MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d sector_num: %ld\n", + MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d " + "sector_num: %" PRId64 "\n", io->remainder_len, io->len, s->nsector, sector_num); if (io->remainder_len && io->len) { /* guest wants the rest of its previous transfer */ int remainder_len = MIN(io->remainder_len, io->len); uint8_t *p = &io->remainder[0x200 - remainder_len]; - MACIO_DPRINTF("copying remainder %d bytes at %#lx\n", + MACIO_DPRINTF("copying remainder %d bytes at %#" HWADDR_PRIx "\n", remainder_len, io->addr); switch (s->dma_cmd) { @@ -261,7 +262,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) if (unaligned) { int nsector = io->len >> 9; - MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n", + MACIO_DPRINTF("precopying unaligned %d bytes to %#" HWADDR_PRIx "\n", unaligned, io->addr + io->len - unaligned); switch (s->dma_cmd) { diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 635a364dd8..91151fc85e 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -56,13 +56,14 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); IDEState *s = bmdma_active_if(bm); + PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); struct { uint32_t addr; uint32_t size; } prd; int l, len; - pci_dma_sglist_init(&s->sg, &bm->pci_dev->dev, + pci_dma_sglist_init(&s->sg, pci_dev, s->nsector / (BMDMA_PAGE_SIZE / 512) + 1); s->io_buffer_size = 0; for(;;) { @@ -71,7 +72,7 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write) if (bm->cur_prd_last || (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) return s->io_buffer_size != 0; - pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, &prd, 8); + pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); bm->cur_addr += 8; prd.addr = le32_to_cpu(prd.addr); prd.size = le32_to_cpu(prd.size); @@ -98,6 +99,7 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); IDEState *s = bmdma_active_if(bm); + PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); struct { uint32_t addr; uint32_t size; @@ -113,7 +115,7 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write) if (bm->cur_prd_last || (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) return 0; - pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, &prd, 8); + pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); bm->cur_addr += 8; prd.addr = le32_to_cpu(prd.addr); prd.size = le32_to_cpu(prd.size); @@ -128,10 +130,10 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write) l = bm->cur_prd_len; if (l > 0) { if (is_write) { - pci_dma_write(&bm->pci_dev->dev, bm->cur_prd_addr, + pci_dma_write(pci_dev, bm->cur_prd_addr, s->io_buffer + s->io_buffer_index, l); } else { - pci_dma_read(&bm->pci_dev->dev, bm->cur_prd_addr, + pci_dma_read(pci_dev, bm->cur_prd_addr, s->io_buffer + s->io_buffer_index, l); } bm->cur_prd_addr += l; @@ -480,7 +482,7 @@ const VMStateDescription vmstate_ide_pci = { .minimum_version_id_old = 0, .post_load = ide_pci_post_load, .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(dev, PCIIDEState), + VMSTATE_PCI_DEVICE(parent_obj, PCIIDEState), VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, vmstate_bmdma, BMDMAState), VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), @@ -492,7 +494,7 @@ const VMStateDescription vmstate_ide_pci = { void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); + PCIIDEState *d = PCI_IDE(dev); static const int bus[4] = { 0, 0, 1, 1 }; static const int unit[4] = { 0, 1, 0, 1 }; int i; @@ -531,3 +533,17 @@ void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d) bus->irq = *irq; bm->pci_dev = d; } + +static const TypeInfo pci_ide_type_info = { + .name = TYPE_PCI_IDE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .abstract = true, +}; + +static void pci_ide_register_types(void) +{ + type_register_static(&pci_ide_type_info); +} + +type_init(pci_ide_register_types) diff --git a/hw/ide/pci.h b/hw/ide/pci.h index a694e546d7..2428275c8d 100644 --- a/hw/ide/pci.h +++ b/hw/ide/pci.h @@ -37,8 +37,14 @@ typedef struct CMD646BAR { struct PCIIDEState *pci_dev; } CMD646BAR; +#define TYPE_PCI_IDE "pci-ide" +#define PCI_IDE(obj) OBJECT_CHECK(PCIIDEState, (obj), TYPE_PCI_IDE) + typedef struct PCIIDEState { - PCIDevice dev; + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + IDEBus bus[2]; BMDMAState bmdma[2]; uint32_t secondary; /* used only for cmd646 */ diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 58532fe09b..e6e6c0bb7a 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -106,7 +106,8 @@ static void bmdma_setup_bar(PCIIDEState *d) static void piix3_reset(void *opaque) { PCIIDEState *d = opaque; - uint8_t *pci_conf = d->dev.config; + PCIDevice *pd = PCI_DEVICE(d); + uint8_t *pci_conf = pd->config; int i; for (i = 0; i < 2; i++) { @@ -135,7 +136,7 @@ static void pci_piix_init_ports(PCIIDEState *d) { int i; for (i = 0; i < 2; i++) { - ide_bus_new(&d->bus[i], &d->dev.qdev, i, 2); + ide_bus_new(&d->bus[i], DEVICE(d), i, 2); ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase, port_info[i].iobase2); ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq)); @@ -149,17 +150,17 @@ static void pci_piix_init_ports(PCIIDEState *d) { static int pci_piix_ide_initfn(PCIDevice *dev) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); - uint8_t *pci_conf = d->dev.config; + PCIIDEState *d = PCI_IDE(dev); + uint8_t *pci_conf = dev->config; pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode qemu_register_reset(piix3_reset, d); bmdma_setup_bar(d); - pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar); + pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar); - vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d); + vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d); pci_piix_init_ports(d); @@ -168,13 +169,11 @@ static int pci_piix_ide_initfn(PCIDevice *dev) static int pci_piix3_xen_ide_unplug(DeviceState *dev) { - PCIDevice *pci_dev; PCIIDEState *pci_ide; DriveInfo *di; int i = 0; - pci_dev = DO_UPCAST(PCIDevice, qdev, dev); - pci_ide = DO_UPCAST(PCIIDEState, dev, pci_dev); + pci_ide = PCI_IDE(dev); for (; i < 3; i++) { di = drive_get_by_index(IF_IDE, i); @@ -188,7 +187,7 @@ static int pci_piix3_xen_ide_unplug(DeviceState *dev) drive_put_ref(di); } } - qdev_reset_all(&(pci_ide->dev.qdev)); + qdev_reset_all(DEVICE(dev)); return 0; } @@ -203,7 +202,7 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) static void pci_piix_ide_exitfn(PCIDevice *dev) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); + PCIIDEState *d = PCI_IDE(dev); unsigned i; for (i = 0; i < 2; ++i) { @@ -248,13 +247,13 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; } static const TypeInfo piix3_ide_info = { .name = "piix3-ide", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIIDEState), + .parent = TYPE_PCI_IDE, .class_init = piix3_ide_class_init, }; @@ -267,14 +266,14 @@ static void piix3_ide_xen_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; dc->unplug = pci_piix3_xen_ide_unplug; } static const TypeInfo piix3_ide_xen_info = { .name = "piix3-ide-xen", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIIDEState), + .parent = TYPE_PCI_IDE, .class_init = piix3_ide_xen_class_init, }; @@ -289,13 +288,13 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371AB; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; } static const TypeInfo piix4_ide_info = { .name = "piix4-ide", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIIDEState), + .parent = TYPE_PCI_IDE, .class_init = piix4_ide_class_init, }; diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 6a272b046d..1d84e15378 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -282,6 +282,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = ide_qdev_init; + set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_IDE_BUS; k->props = ide_props; } diff --git a/hw/ide/via.c b/hw/ide/via.c index 5a831916f1..e5fb2970e1 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -108,7 +108,8 @@ static void bmdma_setup_bar(PCIIDEState *d) static void via_reset(void *opaque) { PCIIDEState *d = opaque; - uint8_t *pci_conf = d->dev.config; + PCIDevice *pd = PCI_DEVICE(d); + uint8_t *pci_conf = pd->config; int i; for (i = 0; i < 2; i++) { @@ -158,7 +159,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) { int i; for (i = 0; i < 2; i++) { - ide_bus_new(&d->bus[i], &d->dev.qdev, i, 2); + ide_bus_new(&d->bus[i], DEVICE(d), i, 2); ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase, port_info[i].iobase2); ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq)); @@ -173,17 +174,17 @@ static void vt82c686b_init_ports(PCIIDEState *d) { /* via ide func */ static int vt82c686b_ide_initfn(PCIDevice *dev) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); - uint8_t *pci_conf = d->dev.config; + PCIIDEState *d = PCI_IDE(dev); + uint8_t *pci_conf = dev->config; pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */ pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); qemu_register_reset(via_reset, d); bmdma_setup_bar(d); - pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar); + pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar); - vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d); + vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d); vt82c686b_init_ports(d); @@ -192,7 +193,7 @@ static int vt82c686b_ide_initfn(PCIDevice *dev) static void vt82c686b_ide_exitfn(PCIDevice *dev) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); + PCIIDEState *d = PCI_IDE(dev); unsigned i; for (i = 0; i < 2; ++i) { @@ -223,13 +224,13 @@ static void via_ide_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIA_IDE; k->revision = 0x06; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; } static const TypeInfo via_ide_info = { .name = "via-ide", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIIDEState), + .parent = TYPE_PCI_IDE, .class_init = via_ide_class_init, }; diff --git a/hw/input/hid.c b/hw/input/hid.c index 14b3125956..bb0fa6a619 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -85,8 +85,8 @@ static void hid_idle_timer(void *opaque) static void hid_del_idle_timer(HIDState *hs) { if (hs->idle_timer) { - qemu_del_timer(hs->idle_timer); - qemu_free_timer(hs->idle_timer); + timer_del(hs->idle_timer); + timer_free(hs->idle_timer); hs->idle_timer = NULL; } } @@ -94,12 +94,12 @@ static void hid_del_idle_timer(HIDState *hs) void hid_set_next_idle(HIDState *hs) { if (hs->idle) { - uint64_t expire_time = qemu_get_clock_ns(vm_clock) + + uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * hs->idle * 4 / 1000; if (!hs->idle_timer) { - hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs); + hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); } - qemu_mod_timer_ns(hs->idle_timer, expire_time); + timer_mod_ns(hs->idle_timer, expire_time); } else { hid_del_idle_timer(hs); } diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index bacbeb2343..f583cf0279 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -365,7 +365,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value) break; } - qemu_del_timer(s->pwm.tm[(value & 3) - 1]); + timer_del(s->pwm.tm[(value & 3) - 1]); break; case LM832x_GENERAL_ERROR: @@ -463,9 +463,9 @@ static int lm8323_init(I2CSlave *i2c) LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c); s->model = 0x8323; - s->pwm.tm[0] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm0_tick, s); - s->pwm.tm[1] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm1_tick, s); - s->pwm.tm[2] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm2_tick, s); + s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s); + s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s); + s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s); qdev_init_gpio_out(&i2c->qdev, &s->nirq, 1); lm_kbd_reset(s); diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c index 942cb79717..ecde33cb95 100644 --- a/hw/input/milkymist-softusb.c +++ b/hw/input/milkymist-softusb.c @@ -44,8 +44,13 @@ enum { #define COMLOC_KEVT_PRODUCE 0x1142 #define COMLOC_KEVT_BASE 0x1143 +#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb" +#define MILKYMIST_SOFTUSB(obj) \ + OBJECT_CHECK(MilkymistSoftUsbState, (obj), TYPE_MILKYMIST_SOFTUSB) + struct MilkymistSoftUsbState { - SysBusDevice busdev; + SysBusDevice parent_obj; + HIDState hid_kbd; HIDState hid_mouse; @@ -242,8 +247,7 @@ static void softusb_mouse_hid_datain(HIDState *hs) static void milkymist_softusb_reset(DeviceState *d) { - MilkymistSoftUsbState *s = - container_of(d, MilkymistSoftUsbState, busdev.qdev); + MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d); int i; for (i = 0; i < R_MAX; i++) { @@ -261,7 +265,7 @@ static void milkymist_softusb_reset(DeviceState *d) static int milkymist_softusb_init(SysBusDevice *dev) { - MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev); sysbus_init_irq(dev, &s->irq); @@ -320,7 +324,7 @@ static void milkymist_softusb_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_softusb_info = { - .name = "milkymist-softusb", + .name = TYPE_MILKYMIST_SOFTUSB, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSoftUsbState), .class_init = milkymist_softusb_class_init, diff --git a/hw/input/pl050.c b/hw/input/pl050.c index 2312ffc50a..c1b08d5a40 100644 --- a/hw/input/pl050.c +++ b/hw/input/pl050.c @@ -10,8 +10,12 @@ #include "hw/sysbus.h" #include "hw/input/ps2.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_PL050 "pl050" +#define PL050(obj) OBJECT_CHECK(PL050State, (obj), TYPE_PL050) + +typedef struct PL050State { + SysBusDevice parent_obj; + MemoryRegion iomem; void *dev; uint32_t cr; @@ -19,18 +23,18 @@ typedef struct { uint32_t last; int pending; qemu_irq irq; - int is_mouse; -} pl050_state; + bool is_mouse; +} PL050State; static const VMStateDescription vmstate_pl050 = { .name = "pl050", .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { - VMSTATE_UINT32(cr, pl050_state), - VMSTATE_UINT32(clk, pl050_state), - VMSTATE_UINT32(last, pl050_state), - VMSTATE_INT32(pending, pl050_state), + VMSTATE_UINT32(cr, PL050State), + VMSTATE_UINT32(clk, PL050State), + VMSTATE_UINT32(last, PL050State), + VMSTATE_INT32(pending, PL050State), VMSTATE_END_OF_LIST() } }; @@ -48,7 +52,7 @@ static const unsigned char pl050_id[] = static void pl050_update(void *opaque, int level) { - pl050_state *s = (pl050_state *)opaque; + PL050State *s = (PL050State *)opaque; int raise; s->pending = level; @@ -60,7 +64,7 @@ static void pl050_update(void *opaque, int level) static uint64_t pl050_read(void *opaque, hwaddr offset, unsigned size) { - pl050_state *s = (pl050_state *)opaque; + PL050State *s = (PL050State *)opaque; if (offset >= 0xfe0 && offset < 0x1000) return pl050_id[(offset - 0xfe0) >> 2]; @@ -103,7 +107,7 @@ static uint64_t pl050_read(void *opaque, hwaddr offset, static void pl050_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl050_state *s = (pl050_state *)opaque; + PL050State *s = (PL050State *)opaque; switch (offset >> 2) { case 0: /* KMICR */ s->cr = value; @@ -133,65 +137,67 @@ static const MemoryRegionOps pl050_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int pl050_init(SysBusDevice *dev, int is_mouse) +static int pl050_initfn(SysBusDevice *dev) { - pl050_state *s = FROM_SYSBUS(pl050_state, dev); + PL050State *s = PL050(dev); memory_region_init_io(&s->iomem, OBJECT(s), &pl050_ops, s, "pl050", 0x1000); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); - s->is_mouse = is_mouse; - if (s->is_mouse) + if (s->is_mouse) { s->dev = ps2_mouse_init(pl050_update, s); - else + } else { s->dev = ps2_kbd_init(pl050_update, s); + } return 0; } -static int pl050_init_keyboard(SysBusDevice *dev) +static void pl050_keyboard_init(Object *obj) { - return pl050_init(dev, 0); -} + PL050State *s = PL050(obj); -static int pl050_init_mouse(SysBusDevice *dev) -{ - return pl050_init(dev, 1); + s->is_mouse = false; } -static void pl050_kbd_class_init(ObjectClass *klass, void *data) +static void pl050_mouse_init(Object *obj) { - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + PL050State *s = PL050(obj); - k->init = pl050_init_keyboard; - dc->vmsd = &vmstate_pl050; + s->is_mouse = true; } static const TypeInfo pl050_kbd_info = { .name = "pl050_keyboard", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl050_state), - .class_init = pl050_kbd_class_init, + .parent = TYPE_PL050, + .instance_init = pl050_keyboard_init, }; -static void pl050_mouse_class_init(ObjectClass *klass, void *data) +static const TypeInfo pl050_mouse_info = { + .name = "pl050_mouse", + .parent = TYPE_PL050, + .instance_init = pl050_mouse_init, +}; + +static void pl050_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(oc); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc); - k->init = pl050_init_mouse; + sdc->init = pl050_initfn; dc->vmsd = &vmstate_pl050; } -static const TypeInfo pl050_mouse_info = { - .name = "pl050_mouse", +static const TypeInfo pl050_type_info = { + .name = TYPE_PL050, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl050_state), - .class_init = pl050_mouse_class_init, + .instance_size = sizeof(PL050State), + .abstract = true, + .class_init = pl050_class_init, }; static void pl050_register_types(void) { + type_register_static(&pl050_type_info); type_register_static(&pl050_kbd_info); type_register_static(&pl050_mouse_info); } diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c index a771cd5e52..21d4f4dbbd 100644 --- a/hw/input/tsc2005.c +++ b/hw/input/tsc2005.c @@ -201,7 +201,7 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data) fprintf(stderr, "%s: touchscreen sense %sabled\n", __FUNCTION__, s->enabled ? "en" : "dis"); if (s->busy && !s->enabled) - qemu_del_timer(s->timer); + timer_del(s->timer); s->busy &= s->enabled; } s->nextprecision = (data >> 13) & 1; @@ -290,8 +290,8 @@ static void tsc2005_pin_update(TSC2005State *s) s->precision = s->nextprecision; s->function = s->nextfunction; s->pdst = !s->pnd0; /* Synchronised on internal clock */ - expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 7); - qemu_mod_timer(s->timer, expires); + expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() >> 7); + timer_mod(s->timer, expires); } static void tsc2005_reset(TSC2005State *s) @@ -337,7 +337,7 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value) fprintf(stderr, "%s: touchscreen sense %sabled\n", __FUNCTION__, s->enabled ? "en" : "dis"); if (s->busy && !s->enabled) - qemu_del_timer(s->timer); + timer_del(s->timer); s->busy &= s->enabled; } tsc2005_pin_update(s); @@ -449,7 +449,7 @@ static void tsc2005_save(QEMUFile *f, void *opaque) qemu_put_be16s(f, &s->dav); qemu_put_be16s(f, &s->data); - qemu_put_timer(f, s->timer); + timer_put(f, s->timer); qemu_put_byte(f, s->enabled); qemu_put_byte(f, s->host_mode); qemu_put_byte(f, s->function); @@ -490,7 +490,7 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &s->dav); qemu_get_be16s(f, &s->data); - qemu_get_timer(f, s->timer); + timer_get(f, s->timer); s->enabled = qemu_get_byte(f); s->host_mode = qemu_get_byte(f); s->function = qemu_get_byte(f); @@ -513,7 +513,7 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id) for (i = 0; i < 8; i ++) s->tr[i] = qemu_get_be32(f); - s->busy = qemu_timer_pending(s->timer); + s->busy = timer_pending(s->timer); tsc2005_pin_update(s); return 0; @@ -529,7 +529,7 @@ void *tsc2005_init(qemu_irq pintdav) s->y = 240; s->pressure = 0; s->precision = s->nextprecision = 0; - s->timer = qemu_new_timer_ns(vm_clock, tsc2005_timer_tick, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s); s->pint = pintdav; s->model = 0x2005; diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index 9b854e77dd..485c9e5753 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -503,9 +503,9 @@ static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg) l_ch = 1; r_ch = 1; if (s->softstep && !(s->dac_power & (1 << 10))) { - l_ch = (qemu_get_clock_ns(vm_clock) > + l_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > s->volume_change + TSC_SOFTSTEP_DELAY); - r_ch = (qemu_get_clock_ns(vm_clock) > + r_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > s->volume_change + TSC_SOFTSTEP_DELAY); } @@ -514,7 +514,7 @@ static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg) case 0x05: /* Stereo DAC Power Control */ return 0x2aa0 | s->dac_power | (((s->dac_power & (1 << 10)) && - (qemu_get_clock_ns(vm_clock) > + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > s->powerdown + TSC_POWEROFF_DELAY)) << 6); case 0x06: /* Audio Control 3 */ @@ -594,7 +594,7 @@ static void tsc2102_control_register_write( s->host_mode = value >> 15; s->enabled = !(value & 0x4000); if (s->busy && !s->enabled) - qemu_del_timer(s->timer); + timer_del(s->timer); s->busy &= s->enabled; s->nextfunction = (value >> 10) & 0xf; s->nextprecision = (value >> 8) & 3; @@ -629,7 +629,7 @@ static void tsc2102_control_register_write( case 0x04: /* Reset */ if (value == 0xbb00) { if (s->busy) - qemu_del_timer(s->timer); + timer_del(s->timer); tsc210x_reset(s); #ifdef TSC_VERBOSE } else { @@ -695,7 +695,7 @@ static void tsc2102_audio_register_write( case 0x02: /* DAC Volume Control */ s->volume = value; - s->volume_change = qemu_get_clock_ns(vm_clock); + s->volume_change = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); return; case 0x03: @@ -717,7 +717,7 @@ static void tsc2102_audio_register_write( case 0x05: /* Stereo DAC Power Control */ if ((value & ~s->dac_power) & (1 << 10)) - s->powerdown = qemu_get_clock_ns(vm_clock); + s->powerdown = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->dac_power = value & 0x9543; #ifdef TSC_VERBOSE @@ -864,8 +864,8 @@ static void tsc210x_pin_update(TSC210xState *s) s->busy = 1; s->precision = s->nextprecision; s->function = s->nextfunction; - expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10); - qemu_mod_timer(s->timer, expires); + expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() >> 10); + timer_mod(s->timer, expires); } static uint16_t tsc210x_read(TSC210xState *s) @@ -1005,7 +1005,7 @@ static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out) static void tsc210x_save(QEMUFile *f, void *opaque) { TSC210xState *s = (TSC210xState *) opaque; - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int i; qemu_put_be16(f, s->x); @@ -1020,7 +1020,7 @@ static void tsc210x_save(QEMUFile *f, void *opaque) qemu_put_byte(f, s->irq); qemu_put_be16s(f, &s->dav); - qemu_put_timer(f, s->timer); + timer_put(f, s->timer); qemu_put_byte(f, s->enabled); qemu_put_byte(f, s->host_mode); qemu_put_byte(f, s->function); @@ -1051,7 +1051,7 @@ static void tsc210x_save(QEMUFile *f, void *opaque) static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) { TSC210xState *s = (TSC210xState *) opaque; - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int i; s->x = qemu_get_be16(f); @@ -1066,7 +1066,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) s->irq = qemu_get_byte(f); qemu_get_be16s(f, &s->dav); - qemu_get_timer(f, s->timer); + timer_get(f, s->timer); s->enabled = qemu_get_byte(f); s->host_mode = qemu_get_byte(f); s->function = qemu_get_byte(f); @@ -1093,7 +1093,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) for (i = 0; i < 0x14; i ++) qemu_get_be16s(f, &s->filter_data[i]); - s->busy = qemu_timer_pending(s->timer); + s->busy = timer_pending(s->timer); qemu_set_irq(s->pint, !s->irq); qemu_set_irq(s->davint, !s->dav); @@ -1111,7 +1111,7 @@ uWireSlave *tsc2102_init(qemu_irq pint) s->y = 160; s->pressure = 0; s->precision = s->nextprecision = 0; - s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s); s->pint = pint; s->model = 0x2102; s->name = "tsc2102"; @@ -1160,7 +1160,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav) s->y = 240; s->pressure = 0; s->precision = s->nextprecision = 0; - s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s); s->pint = penirq; s->kbint = kbirq; s->davint = dav; diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 5e3b96e4db..a913186ed0 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -606,7 +606,7 @@ static uint32_t apic_get_current_count(APICCommonState *s) { int64_t d; uint32_t val; - d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >> + d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { /* periodic */ @@ -623,9 +623,9 @@ static uint32_t apic_get_current_count(APICCommonState *s) static void apic_timer_update(APICCommonState *s, int64_t current_time) { if (apic_next_timer(s, current_time)) { - qemu_mod_timer(s->timer, s->next_time); + timer_mod(s->timer, s->next_time); } else { - qemu_del_timer(s->timer); + timer_del(s->timer); } } @@ -822,7 +822,7 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) int n = index - 0x32; s->lvt[n] = val; if (n == APIC_LVT_TIMER) { - apic_timer_update(s, qemu_get_clock_ns(vm_clock)); + apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) { apic_update_irq(s); } @@ -830,7 +830,7 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) break; case 0x38: s->initial_count = val; - s->initial_count_load_time = qemu_get_clock_ns(vm_clock); + s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); apic_timer_update(s, s->initial_count_load_time); break; case 0x39: @@ -857,9 +857,9 @@ static void apic_pre_save(APICCommonState *s) static void apic_post_load(APICCommonState *s) { if (s->timer_expiry != -1) { - qemu_mod_timer(s->timer, s->timer_expiry); + timer_mod(s->timer, s->timer_expiry); } else { - qemu_del_timer(s->timer); + timer_del(s->timer); } } @@ -876,7 +876,7 @@ static void apic_init(APICCommonState *s) memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi", APIC_SPACE_SIZE); - s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s); local_apics[s->idx] = s; msi_supported = true; diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index b03e904a7a..a0beb10863 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -198,7 +198,7 @@ void apic_init_reset(DeviceState *d) s->wait_for_sipi = 1; if (s->timer) { - qemu_del_timer(s->timer); + timer_del(s->timer); } s->timer_expiry = -1; } diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 8e340049c3..d431b7a881 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -639,6 +639,7 @@ static const MemoryRegionOps gic_cpu_ops = { void gic_init_irqs_and_distributor(GICState *s, int num_irq) { + SysBusDevice *sbd = SYS_BUS_DEVICE(s); int i; i = s->num_irq - GIC_INTERNAL; @@ -652,9 +653,9 @@ void gic_init_irqs_and_distributor(GICState *s, int num_irq) if (s->revision != REV_NVIC) { i += (GIC_INTERNAL * s->num_cpu); } - qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i); + qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); for (i = 0; i < NUM_CPU(s); i++) { - sysbus_init_irq(&s->busdev, &s->parent_irq[i]); + sysbus_init_irq(sbd, &s->parent_irq[i]); } memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, "gic_dist", 0x1000); diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 08560f23a3..709b5c2984 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -110,7 +110,7 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp) static void arm_gic_common_reset(DeviceState *dev) { - GICState *s = FROM_SYSBUS(GICState, SYS_BUS_DEVICE(dev)); + GICState *s = ARM_GIC_COMMON(dev); int i; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 178344b5a3..6066fa6838 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -78,9 +78,9 @@ static inline int64_t systick_scale(nvic_state *s) static void systick_reload(nvic_state *s, int reset) { if (reset) - s->systick.tick = qemu_get_clock_ns(vm_clock); + s->systick.tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->systick.tick += (s->systick.reload + 1) * systick_scale(s); - qemu_mod_timer(s->systick.timer, s->systick.tick); + timer_mod(s->systick.timer, s->systick.tick); } static void systick_timer_tick(void * opaque) @@ -103,7 +103,7 @@ static void systick_reset(nvic_state *s) s->systick.control = 0; s->systick.reload = 0; s->systick.tick = 0; - qemu_del_timer(s->systick.timer); + timer_del(s->systick.timer); } /* The external routines use the hardware vector numbering, ie. the first @@ -158,7 +158,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) int64_t t; if ((s->systick.control & SYSTICK_ENABLE) == 0) return 0; - t = qemu_get_clock_ns(vm_clock); + t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (t >= s->systick.tick) return 0; val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1; @@ -290,16 +290,16 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) s->systick.control &= 0xfffffff8; s->systick.control |= value & 7; if ((oldval ^ value) & SYSTICK_ENABLE) { - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (value & SYSTICK_ENABLE) { if (s->systick.tick) { s->systick.tick += now; - qemu_mod_timer(s->systick.timer, s->systick.tick); + timer_mod(s->systick.timer, s->systick.tick); } else { systick_reload(s, 1); } } else { - qemu_del_timer(s->systick.timer); + timer_del(s->systick.timer); s->systick.tick -= now; if (s->systick.tick < 0) s->systick.tick = 0; @@ -511,7 +511,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) * by the v7M architecture. */ memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container); - s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); + s->systick.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s); } static void armv7m_nvic_instance_init(Object *obj) diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c index ce3a3f6eb3..e02da533cb 100644 --- a/hw/intc/etraxfs_pic.c +++ b/hw/intc/etraxfs_pic.c @@ -36,9 +36,14 @@ #define R_R_GURU 4 #define R_MAX 5 +#define TYPE_ETRAX_FS_PIC "etraxfs,pic" +#define ETRAX_FS_PIC(obj) \ + OBJECT_CHECK(struct etrax_pic, (obj), TYPE_ETRAX_FS_PIC) + struct etrax_pic { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mmio; void *interrupt_vector; qemu_irq parent_irq; @@ -138,17 +143,18 @@ static void irq_handler(void *opaque, int irq, int level) pic_update(fs); } -static int etraxfs_pic_init(SysBusDevice *dev) +static int etraxfs_pic_init(SysBusDevice *sbd) { - struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev); + DeviceState *dev = DEVICE(sbd); + struct etrax_pic *s = ETRAX_FS_PIC(dev); - qdev_init_gpio_in(&dev->qdev, irq_handler, 32); - sysbus_init_irq(dev, &s->parent_irq); - sysbus_init_irq(dev, &s->parent_nmi); + qdev_init_gpio_in(dev, irq_handler, 32); + sysbus_init_irq(sbd, &s->parent_irq); + sysbus_init_irq(sbd, &s->parent_nmi); memory_region_init_io(&s->mmio, OBJECT(s), &pic_ops, s, "etraxfs-pic", R_MAX * 4); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); return 0; } @@ -167,7 +173,7 @@ static void etraxfs_pic_class_init(ObjectClass *klass, void *data) } static const TypeInfo etraxfs_pic_info = { - .name = "etraxfs,pic", + .name = TYPE_ETRAX_FS_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct etrax_pic), .class_init = etraxfs_pic_class_init, diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index 3b40976827..ef5e8eb22f 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -56,8 +56,13 @@ typedef struct CombinerGroupState { uint8_t src_pending; /* Pending source interrupts before masking */ } CombinerGroupState; +#define TYPE_EXYNOS4210_COMBINER "exynos4210.combiner" +#define EXYNOS4210_COMBINER(obj) \ + OBJECT_CHECK(Exynos4210CombinerState, (obj), TYPE_EXYNOS4210_COMBINER) + typedef struct Exynos4210CombinerState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; struct CombinerGroupState group[IIC_NGRP]; @@ -402,24 +407,24 @@ static const MemoryRegionOps exynos4210_combiner_ops = { /* * Internal Combiner initialization. */ -static int exynos4210_combiner_init(SysBusDevice *dev) +static int exynos4210_combiner_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); + Exynos4210CombinerState *s = EXYNOS4210_COMBINER(dev); unsigned int i; - struct Exynos4210CombinerState *s = - FROM_SYSBUS(struct Exynos4210CombinerState, dev); /* Allocate general purpose input signals and connect a handler to each of * them */ - qdev_init_gpio_in(&s->busdev.qdev, exynos4210_combiner_handler, IIC_NIRQ); + qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ); /* Connect SysBusDev irqs to device specific irqs */ for (i = 0; i < IIC_NIRQ; i++) { - sysbus_init_irq(dev, &s->output_irq[i]); + sysbus_init_irq(sbd, &s->output_irq[i]); } memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_combiner_ops, s, - "exynos4210-combiner", IIC_REGION_SIZE); - sysbus_init_mmio(dev, &s->iomem); + "exynos4210-combiner", IIC_REGION_SIZE); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -441,7 +446,7 @@ static void exynos4210_combiner_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_combiner_info = { - .name = "exynos4210.combiner", + .name = TYPE_EXYNOS4210_COMBINER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210CombinerState), .class_init = exynos4210_combiner_class_init, diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 6147f04bce..5b913f786e 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -260,8 +260,13 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) /********* GIC part *********/ +#define TYPE_EXYNOS4210_GIC "exynos4210.gic" +#define EXYNOS4210_GIC(obj) \ + OBJECT_CHECK(Exynos4210GicState, (obj), TYPE_EXYNOS4210_GIC) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion cpu_container; MemoryRegion dist_container; MemoryRegion cpu_alias[EXYNOS4210_NCPUS]; @@ -276,9 +281,10 @@ static void exynos4210_gic_set_irq(void *opaque, int irq, int level) qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } -static int exynos4210_gic_init(SysBusDevice *dev) +static int exynos4210_gic_init(SysBusDevice *sbd) { - Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev); + DeviceState *dev = DEVICE(sbd); + Exynos4210GicState *s = EXYNOS4210_GIC(dev); uint32_t i; const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; const char dist_prefix[] = "exynos4210-gic-alias_dist"; @@ -293,10 +299,10 @@ static int exynos4210_gic_init(SysBusDevice *dev) busdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(dev, busdev); + sysbus_pass_irq(sbd, busdev); /* Pass through inbound GPIO lines to the GIC */ - qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq, + qdev_init_gpio_in(dev, exynos4210_gic_set_irq, EXYNOS4210_GIC_NIRQ - 32); memory_region_init(&s->cpu_container, OBJECT(s), "exynos4210-cpu-container", @@ -326,8 +332,8 @@ static int exynos4210_gic_init(SysBusDevice *dev) EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]); } - sysbus_init_mmio(dev, &s->cpu_container); - sysbus_init_mmio(dev, &s->dist_container); + sysbus_init_mmio(sbd, &s->cpu_container); + sysbus_init_mmio(sbd, &s->dist_container); return 0; } @@ -347,7 +353,7 @@ static void exynos4210_gic_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_gic_info = { - .name = "exynos4210.gic", + .name = TYPE_EXYNOS4210_GIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210GicState), .class_init = exynos4210_gic_class_init, @@ -366,8 +372,13 @@ type_init(exynos4210_gic_register_types) * output sysbus IRQ line. The output IRQ level is formed as OR between all * gpio inputs. */ -typedef struct { - SysBusDevice busdev; + +#define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate" +#define EXYNOS4210_IRQ_GATE(obj) \ + OBJECT_CHECK(Exynos4210IRQGateState, (obj), TYPE_EXYNOS4210_IRQ_GATE) + +typedef struct Exynos4210IRQGateState { + SysBusDevice parent_obj; uint32_t n_in; /* inputs amount */ uint32_t *level; /* input levels */ @@ -412,8 +423,7 @@ static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) static void exynos4210_irq_gate_reset(DeviceState *d) { - Exynos4210IRQGateState *s = - DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d); + Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d); memset(s->level, 0, s->n_in * sizeof(*s->level)); } @@ -421,17 +431,18 @@ static void exynos4210_irq_gate_reset(DeviceState *d) /* * IRQ Gate initialization. */ -static int exynos4210_irq_gate_init(SysBusDevice *dev) +static int exynos4210_irq_gate_init(SysBusDevice *sbd) { - Exynos4210IRQGateState *s = FROM_SYSBUS(Exynos4210IRQGateState, dev); + DeviceState *dev = DEVICE(sbd); + Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev); /* Allocate general purpose input signals and connect a handler to each of * them */ - qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, s->n_in); + qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in); s->level = g_malloc0(s->n_in * sizeof(*s->level)); - sysbus_init_irq(dev, &s->out); + sysbus_init_irq(sbd, &s->out); return 0; } @@ -448,7 +459,7 @@ static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_irq_gate_info = { - .name = "exynos4210.irq_gate", + .name = TYPE_EXYNOS4210_IRQ_GATE, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210IRQGateState), .class_init = exynos4210_irq_gate_class_init, diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 99a3bc362b..14264373fe 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -70,7 +70,10 @@ typedef struct gic_irq_state { } gic_irq_state; typedef struct GICState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + qemu_irq parent_irq[NCPU]; bool enabled; bool cpu_enabled[NCPU]; diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 181f61429a..42e00bc4b8 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -45,10 +45,14 @@ #define FORCE_OFFSET 0x80 #define EXTENDED_OFFSET 0xC0 +#define TYPE_GRLIB_IRQMP "grlib,irqmp" +#define GRLIB_IRQMP(obj) OBJECT_CHECK(IRQMP, (obj), TYPE_GRLIB_IRQMP) + typedef struct IRQMPState IRQMPState; typedef struct IRQMP { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; void *set_pil_in; @@ -102,19 +106,10 @@ static void grlib_irqmp_check_irqs(IRQMPState *state) void grlib_irqmp_ack(DeviceState *dev, int intno) { - SysBusDevice *sdev; - IRQMP *irqmp; + IRQMP *irqmp = GRLIB_IRQMP(dev); IRQMPState *state; uint32_t mask; - assert(dev != NULL); - - sdev = SYS_BUS_DEVICE(dev); - assert(sdev != NULL); - - irqmp = FROM_SYSBUS(typeof(*irqmp), sdev); - assert(irqmp != NULL); - state = irqmp->state; assert(state != NULL); @@ -132,15 +127,10 @@ void grlib_irqmp_ack(DeviceState *dev, int intno) void grlib_irqmp_set_irq(void *opaque, int irq, int level) { - IRQMP *irqmp; + IRQMP *irqmp = GRLIB_IRQMP(opaque); IRQMPState *s; int i = 0; - assert(opaque != NULL); - - irqmp = FROM_SYSBUS(typeof(*irqmp), SYS_BUS_DEVICE(opaque)); - assert(irqmp != NULL); - s = irqmp->state; assert(s != NULL); assert(s->parent != NULL); @@ -325,8 +315,7 @@ static const MemoryRegionOps grlib_irqmp_ops = { static void grlib_irqmp_reset(DeviceState *d) { - IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev); - assert(irqmp != NULL); + IRQMP *irqmp = GRLIB_IRQMP(d); assert(irqmp->state != NULL); memset(irqmp->state, 0, sizeof *irqmp->state); @@ -335,9 +324,7 @@ static void grlib_irqmp_reset(DeviceState *d) static int grlib_irqmp_init(SysBusDevice *dev) { - IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev); - - assert(irqmp != NULL); + IRQMP *irqmp = GRLIB_IRQMP(dev); /* Check parameters */ if (irqmp->set_pil_in == NULL) { @@ -371,7 +358,7 @@ static void grlib_irqmp_class_init(ObjectClass *klass, void *data) } static const TypeInfo grlib_irqmp_info = { - .name = "grlib,irqmp", + .name = TYPE_GRLIB_IRQMP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IRQMP), .class_init = grlib_irqmp_class_init, diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index 1415bda93f..c6f248b145 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -150,7 +150,7 @@ static void pic_set_irq(void *opaque, int irq, int level) #endif #ifdef DEBUG_IRQ_LATENCY if (level) { - irq_time[irq_index] = qemu_get_clock_ns(vm_clock); + irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } #endif @@ -228,7 +228,7 @@ int pic_read_irq(DeviceState *d) #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, - (double)(qemu_get_clock_ns(vm_clock) - + (double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - irq_time[irq]) * 1000000.0 / get_ticks_per_sec()); #endif DPRINTF("pic_interrupt: irq=%d\n", irq); diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index 75c8ffde29..fb00e910f6 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -55,8 +55,13 @@ do { printf("imx_avic: " fmt , ##args); } while (0) #define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4) #define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD) -typedef struct { - SysBusDevice busdev; +#define TYPE_IMX_AVIC "imx_avic" +#define IMX_AVIC(obj) \ + OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC) + +typedef struct IMXAVICState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint64_t pending; uint64_t enabled; @@ -359,7 +364,8 @@ static const MemoryRegionOps imx_avic_ops = { static void imx_avic_reset(DeviceState *dev) { - IMXAVICState *s = container_of(dev, IMXAVICState, busdev.qdev); + IMXAVICState *s = IMX_AVIC(dev); + s->pending = 0; s->enabled = 0; s->is_fiq = 0; @@ -368,17 +374,18 @@ static void imx_avic_reset(DeviceState *dev) memset(s->prio, 0, sizeof s->prio); } -static int imx_avic_init(SysBusDevice *dev) +static int imx_avic_init(SysBusDevice *sbd) { - IMXAVICState *s = FROM_SYSBUS(IMXAVICState, dev); + DeviceState *dev = DEVICE(sbd); + IMXAVICState *s = IMX_AVIC(dev); memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s, "imx_avic", 0x1000); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); - qdev_init_gpio_in(&dev->qdev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS); - sysbus_init_irq(dev, &s->irq); - sysbus_init_irq(dev, &s->fiq); + qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->fiq); return 0; } @@ -395,7 +402,7 @@ static void imx_avic_class_init(ObjectClass *klass, void *data) } static const TypeInfo imx_avic_info = { - .name = "imx_avic", + .name = TYPE_IMX_AVIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXAVICState), .class_init = imx_avic_class_init, diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 5d064fe3a6..d866e00297 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -230,7 +230,7 @@ static void ioapic_init(IOAPICCommonState *s, int instance_no) memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, "ioapic", 0x1000); - qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS); + qdev_init_gpio_in(DEVICE(s), ioapic_set_irq, IOAPIC_NUM_PINS); ioapics[instance_no] = s; } diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index b4e80c8d8c..32d009f678 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -26,8 +26,12 @@ #include "trace.h" #include "hw/lm32/lm32_pic.h" +#define TYPE_LM32_PIC "lm32-pic" +#define LM32_PIC(obj) OBJECT_CHECK(LM32PicState, (obj), TYPE_LM32_PIC) + struct LM32PicState { - SysBusDevice busdev; + SysBusDevice parent_obj; + qemu_irq parent_irq; uint32_t im; /* interrupt mask */ uint32_t ip; /* interrupt pending */ @@ -99,7 +103,7 @@ static void irq_handler(void *opaque, int irq, int level) void lm32_pic_set_im(DeviceState *d, uint32_t im) { - LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); + LM32PicState *s = LM32_PIC(d); trace_lm32_pic_set_im(im); s->im = im; @@ -109,7 +113,7 @@ void lm32_pic_set_im(DeviceState *d, uint32_t im) void lm32_pic_set_ip(DeviceState *d, uint32_t ip) { - LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); + LM32PicState *s = LM32_PIC(d); trace_lm32_pic_set_ip(ip); @@ -121,7 +125,7 @@ void lm32_pic_set_ip(DeviceState *d, uint32_t ip) uint32_t lm32_pic_get_im(DeviceState *d) { - LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); + LM32PicState *s = LM32_PIC(d); trace_lm32_pic_get_im(s->im); return s->im; @@ -129,7 +133,7 @@ uint32_t lm32_pic_get_im(DeviceState *d) uint32_t lm32_pic_get_ip(DeviceState *d) { - LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); + LM32PicState *s = LM32_PIC(d); trace_lm32_pic_get_ip(s->ip); return s->ip; @@ -137,7 +141,7 @@ uint32_t lm32_pic_get_ip(DeviceState *d) static void pic_reset(DeviceState *d) { - LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); + LM32PicState *s = LM32_PIC(d); int i; s->im = 0; @@ -148,12 +152,13 @@ static void pic_reset(DeviceState *d) } } -static int lm32_pic_init(SysBusDevice *dev) +static int lm32_pic_init(SysBusDevice *sbd) { - LM32PicState *s = FROM_SYSBUS(typeof(*s), dev); + DeviceState *dev = DEVICE(sbd); + LM32PicState *s = LM32_PIC(dev); - qdev_init_gpio_in(&dev->qdev, irq_handler, 32); - sysbus_init_irq(dev, &s->parent_irq); + qdev_init_gpio_in(dev, irq_handler, 32); + sysbus_init_irq(sbd, &s->parent_irq); pic = s; @@ -185,7 +190,7 @@ static void lm32_pic_class_init(ObjectClass *klass, void *data) } static const TypeInfo lm32_pic_info = { - .name = "lm32-pic", + .name = TYPE_LM32_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32PicState), .class_init = lm32_pic_class_init, diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c index bca8585284..7dd63da802 100644 --- a/hw/intc/omap_intc.c +++ b/hw/intc/omap_intc.c @@ -32,8 +32,13 @@ struct omap_intr_handler_bank_s { unsigned char priority[32]; }; +#define TYPE_OMAP_INTC "common-omap-intc" +#define OMAP_INTC(obj) \ + OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC) + struct omap_intr_handler_s { - SysBusDevice busdev; + SysBusDevice parent_obj; + qemu_irq *pins; qemu_irq parent_intr[2]; MemoryRegion mmio; @@ -328,8 +333,7 @@ static const MemoryRegionOps omap_inth_mem_ops = { static void omap_inth_reset(DeviceState *dev) { - struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s, - SYS_BUS_DEVICE(dev)); + struct omap_intr_handler_s *s = OMAP_INTC(dev); int i; for (i = 0; i < s->nbanks; ++i){ @@ -356,20 +360,21 @@ static void omap_inth_reset(DeviceState *dev) qemu_set_irq(s->parent_intr[1], 0); } -static int omap_intc_init(SysBusDevice *dev) +static int omap_intc_init(SysBusDevice *sbd) { - struct omap_intr_handler_s *s; - s = FROM_SYSBUS(struct omap_intr_handler_s, dev); + DeviceState *dev = DEVICE(sbd); + struct omap_intr_handler_s *s = OMAP_INTC(dev); + if (!s->iclk) { hw_error("omap-intc: clk not connected\n"); } s->nbanks = 1; - sysbus_init_irq(dev, &s->parent_intr[0]); - sysbus_init_irq(dev, &s->parent_intr[1]); - qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32); + sysbus_init_irq(sbd, &s->parent_intr[0]); + sysbus_init_irq(sbd, &s->parent_intr[1]); + qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32); memory_region_init_io(&s->mmio, OBJECT(s), &omap_inth_mem_ops, s, "omap-intc", s->size); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); return 0; } @@ -391,8 +396,7 @@ static void omap_intc_class_init(ObjectClass *klass, void *data) static const TypeInfo omap_intc_info = { .name = "omap-intc", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct omap_intr_handler_s), + .parent = TYPE_OMAP_INTC, .class_init = omap_intc_class_init, }; @@ -500,8 +504,9 @@ static void omap2_inth_write(void *opaque, hwaddr addr, case 0x10: /* INTC_SYSCONFIG */ s->autoidle &= 4; s->autoidle |= (value & 1) << 2; - if (value & 2) /* SOFTRESET */ - omap_inth_reset(&s->busdev.qdev); + if (value & 2) { /* SOFTRESET */ + omap_inth_reset(DEVICE(s)); + } return; case 0x48: /* INTC_CONTROL */ @@ -594,10 +599,11 @@ static const MemoryRegionOps omap2_inth_mem_ops = { }, }; -static int omap2_intc_init(SysBusDevice *dev) +static int omap2_intc_init(SysBusDevice *sbd) { - struct omap_intr_handler_s *s; - s = FROM_SYSBUS(struct omap_intr_handler_s, dev); + DeviceState *dev = DEVICE(sbd); + struct omap_intr_handler_s *s = OMAP_INTC(dev); + if (!s->iclk) { hw_error("omap2-intc: iclk not connected\n"); } @@ -606,12 +612,12 @@ static int omap2_intc_init(SysBusDevice *dev) } s->level_only = 1; s->nbanks = 3; - sysbus_init_irq(dev, &s->parent_intr[0]); - sysbus_init_irq(dev, &s->parent_intr[1]); - qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32); + sysbus_init_irq(sbd, &s->parent_intr[0]); + sysbus_init_irq(sbd, &s->parent_intr[1]); + qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32); memory_region_init_io(&s->mmio, OBJECT(s), &omap2_inth_mem_ops, s, "omap2-intc", 0x1000); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); return 0; } @@ -635,13 +641,20 @@ static void omap2_intc_class_init(ObjectClass *klass, void *data) static const TypeInfo omap2_intc_info = { .name = "omap2-intc", + .parent = TYPE_OMAP_INTC, + .class_init = omap2_intc_class_init, +}; + +static const TypeInfo omap_intc_type_info = { + .name = TYPE_OMAP_INTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_intr_handler_s), - .class_init = omap2_intc_class_init, + .abstract = true, }; static void omap_intc_register_types(void) { + type_register_static(&omap_intc_type_info); type_register_static(&omap_intc_info); type_register_static(&omap2_intc_info); } diff --git a/hw/intc/pl190.c b/hw/intc/pl190.c index fdb29d7ed5..329680da3a 100644 --- a/hw/intc/pl190.c +++ b/hw/intc/pl190.c @@ -15,8 +15,12 @@ #define PL190_NUM_PRIO 17 -typedef struct { - SysBusDevice busdev; +#define TYPE_PL190 "pl190" +#define PL190(obj) OBJECT_CHECK(PL190State, (obj), TYPE_PL190) + +typedef struct PL190State { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t level; uint32_t soft_level; @@ -32,18 +36,18 @@ typedef struct { int prev_prio[PL190_NUM_PRIO]; qemu_irq irq; qemu_irq fiq; -} pl190_state; +} PL190State; static const unsigned char pl190_id[] = { 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 }; -static inline uint32_t pl190_irq_level(pl190_state *s) +static inline uint32_t pl190_irq_level(PL190State *s) { return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select; } /* Update interrupts. */ -static void pl190_update(pl190_state *s) +static void pl190_update(PL190State *s) { uint32_t level = pl190_irq_level(s); int set; @@ -56,7 +60,7 @@ static void pl190_update(pl190_state *s) static void pl190_set_irq(void *opaque, int irq, int level) { - pl190_state *s = (pl190_state *)opaque; + PL190State *s = (PL190State *)opaque; if (level) s->level |= 1u << irq; @@ -65,7 +69,7 @@ static void pl190_set_irq(void *opaque, int irq, int level) pl190_update(s); } -static void pl190_update_vectors(pl190_state *s) +static void pl190_update_vectors(PL190State *s) { uint32_t mask; int i; @@ -88,7 +92,7 @@ static void pl190_update_vectors(pl190_state *s) static uint64_t pl190_read(void *opaque, hwaddr offset, unsigned size) { - pl190_state *s = (pl190_state *)opaque; + PL190State *s = (PL190State *)opaque; int i; if (offset >= 0xfe0 && offset < 0x1000) { @@ -152,7 +156,7 @@ static uint64_t pl190_read(void *opaque, hwaddr offset, static void pl190_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { - pl190_state *s = (pl190_state *)opaque; + PL190State *s = (PL190State *)opaque; if (offset >= 0x100 && offset < 0x140) { s->vect_addr[(offset - 0x100) >> 2] = val; @@ -218,29 +222,29 @@ static const MemoryRegionOps pl190_ops = { static void pl190_reset(DeviceState *d) { - pl190_state *s = DO_UPCAST(pl190_state, busdev.qdev, d); - int i; + PL190State *s = PL190(d); + int i; - for (i = 0; i < 16; i++) - { - s->vect_addr[i] = 0; - s->vect_control[i] = 0; + for (i = 0; i < 16; i++) { + s->vect_addr[i] = 0; + s->vect_control[i] = 0; } - s->vect_addr[16] = 0; - s->prio_mask[17] = 0xffffffff; - s->priority = PL190_NUM_PRIO; - pl190_update_vectors(s); + s->vect_addr[16] = 0; + s->prio_mask[17] = 0xffffffff; + s->priority = PL190_NUM_PRIO; + pl190_update_vectors(s); } -static int pl190_init(SysBusDevice *dev) +static int pl190_init(SysBusDevice *sbd) { - pl190_state *s = FROM_SYSBUS(pl190_state, dev); + DeviceState *dev = DEVICE(sbd); + PL190State *s = PL190(dev); memory_region_init_io(&s->iomem, OBJECT(s), &pl190_ops, s, "pl190", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32); - sysbus_init_irq(dev, &s->irq); - sysbus_init_irq(dev, &s->fiq); + sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_in(dev, pl190_set_irq, 32); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->fiq); return 0; } @@ -249,16 +253,16 @@ static const VMStateDescription vmstate_pl190 = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(level, pl190_state), - VMSTATE_UINT32(soft_level, pl190_state), - VMSTATE_UINT32(irq_enable, pl190_state), - VMSTATE_UINT32(fiq_select, pl190_state), - VMSTATE_UINT8_ARRAY(vect_control, pl190_state, 16), - VMSTATE_UINT32_ARRAY(vect_addr, pl190_state, PL190_NUM_PRIO), - VMSTATE_UINT32_ARRAY(prio_mask, pl190_state, PL190_NUM_PRIO+1), - VMSTATE_INT32(protected, pl190_state), - VMSTATE_INT32(priority, pl190_state), - VMSTATE_INT32_ARRAY(prev_prio, pl190_state, PL190_NUM_PRIO), + VMSTATE_UINT32(level, PL190State), + VMSTATE_UINT32(soft_level, PL190State), + VMSTATE_UINT32(irq_enable, PL190State), + VMSTATE_UINT32(fiq_select, PL190State), + VMSTATE_UINT8_ARRAY(vect_control, PL190State, 16), + VMSTATE_UINT32_ARRAY(vect_addr, PL190State, PL190_NUM_PRIO), + VMSTATE_UINT32_ARRAY(prio_mask, PL190State, PL190_NUM_PRIO+1), + VMSTATE_INT32(protected, PL190State), + VMSTATE_INT32(priority, PL190State), + VMSTATE_INT32_ARRAY(prev_prio, PL190State, PL190_NUM_PRIO), VMSTATE_END_OF_LIST() } }; @@ -275,9 +279,9 @@ static void pl190_class_init(ObjectClass *klass, void *data) } static const TypeInfo pl190_info = { - .name = "pl190", + .name = TYPE_PL190, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl190_state), + .instance_size = sizeof(PL190State), .class_init = pl190_class_init, }; diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c index 44b66517f9..c2803d07d5 100644 --- a/hw/intc/puv3_intc.c +++ b/hw/intc/puv3_intc.c @@ -13,8 +13,12 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_PUV3_INTC "puv3_intc" +#define PUV3_INTC(obj) OBJECT_CHECK(PUV3INTCState, (obj), TYPE_PUV3_INTC) + +typedef struct PUV3INTCState { + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq parent_irq; @@ -96,19 +100,20 @@ static const MemoryRegionOps puv3_intc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int puv3_intc_init(SysBusDevice *dev) +static int puv3_intc_init(SysBusDevice *sbd) { - PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev); + DeviceState *dev = DEVICE(sbd); + PUV3INTCState *s = PUV3_INTC(dev); - qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR); - sysbus_init_irq(&s->busdev, &s->parent_irq); + qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR); + sysbus_init_irq(sbd, &s->parent_irq); s->reg_ICMR = 0; s->reg_ICPR = 0; memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc", - PUV3_REGS_OFFSET); - sysbus_init_mmio(dev, &s->iomem); + PUV3_REGS_OFFSET); + sysbus_init_mmio(sbd, &s->iomem); return 0; } @@ -121,7 +126,7 @@ static void puv3_intc_class_init(ObjectClass *klass, void *data) } static const TypeInfo puv3_intc_info = { - .name = "puv3_intc", + .name = TYPE_PUV3_INTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PUV3INTCState), .class_init = puv3_intc_class_init, diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c index e122c2c810..ce8044780a 100644 --- a/hw/intc/realview_gic.c +++ b/hw/intc/realview_gic.c @@ -9,8 +9,13 @@ #include "hw/sysbus.h" +#define TYPE_REALVIEW_GIC "realview_gic" +#define REALVIEW_GIC(obj) \ + OBJECT_CHECK(RealViewGICState, (obj), TYPE_REALVIEW_GIC) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + DeviceState *gic; MemoryRegion container; } RealViewGICState; @@ -21,9 +26,10 @@ static void realview_gic_set_irq(void *opaque, int irq, int level) qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } -static int realview_gic_init(SysBusDevice *dev) +static int realview_gic_init(SysBusDevice *sbd) { - RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev); + DeviceState *dev = DEVICE(sbd); + RealViewGICState *s = REALVIEW_GIC(dev); SysBusDevice *busdev; /* The GICs on the RealView boards have a fixed nonconfigurable * number of interrupt lines, so we don't need to expose this as @@ -38,10 +44,10 @@ static int realview_gic_init(SysBusDevice *dev) busdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(dev, busdev); + sysbus_pass_irq(sbd, busdev); /* Pass through inbound GPIO lines to the GIC */ - qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32); + qdev_init_gpio_in(dev, realview_gic_set_irq, numirq - 32); memory_region_init(&s->container, OBJECT(s), "realview-gic-container", 0x2000); @@ -49,7 +55,7 @@ static int realview_gic_init(SysBusDevice *dev) sysbus_mmio_get_region(busdev, 1)); memory_region_add_subregion(&s->container, 0x1000, sysbus_mmio_get_region(busdev, 0)); - sysbus_init_mmio(dev, &s->container); + sysbus_init_mmio(sbd, &s->container); return 0; } @@ -61,7 +67,7 @@ static void realview_gic_class_init(ObjectClass *klass, void *data) } static const TypeInfo realview_gic_info = { - .name = "realview_gic", + .name = TYPE_REALVIEW_GIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RealViewGICState), .class_init = realview_gic_class_init, diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index b47d0f0a9e..41a1672800 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -53,8 +53,13 @@ typedef struct SLAVIO_CPUINTCTLState { uint32_t irl_out; } SLAVIO_CPUINTCTLState; +#define TYPE_SLAVIO_INTCTL "slavio_intctl" +#define SLAVIO_INTCTL(obj) \ + OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL) + typedef struct SLAVIO_INTCTLState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; #ifdef DEBUG_IRQ_COUNT uint64_t irq_count[32]; @@ -206,12 +211,9 @@ static const MemoryRegionOps slavio_intctlm_mem_ops = { void slavio_pic_info(Monitor *mon, DeviceState *dev) { - SysBusDevice *sd; - SLAVIO_INTCTLState *s; + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); int i; - sd = SYS_BUS_DEVICE(dev); - s = FROM_SYSBUS(SLAVIO_INTCTLState, sd); for (i = 0; i < MAX_CPUS; i++) { monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, s->slaves[i].intreg_pending); @@ -225,13 +227,11 @@ void slavio_irq_info(Monitor *mon, DeviceState *dev) #ifndef DEBUG_IRQ_COUNT monitor_printf(mon, "irq statistic code not compiled.\n"); #else - SysBusDevice *sd; - SLAVIO_INTCTLState *s; + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); int i; int64_t count; - sd = SYS_BUS_DEVICE(dev); - s = FROM_SYSBUS(SLAVIO_INTCTLState, sd); + s = SLAVIO_INTCTL(dev); monitor_printf(mon, "IRQ statistics:\n"); for (i = 0; i < 32; i++) { count = s->irq_count[i]; @@ -406,7 +406,7 @@ static const VMStateDescription vmstate_intctl = { static void slavio_intctl_reset(DeviceState *d) { - SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev); + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d); int i; for (i = 0; i < MAX_CPUS; i++) { @@ -419,27 +419,28 @@ static void slavio_intctl_reset(DeviceState *d) slavio_check_interrupts(s, 0); } -static int slavio_intctl_init1(SysBusDevice *dev) +static int slavio_intctl_init1(SysBusDevice *sbd) { - SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev); + DeviceState *dev = DEVICE(sbd); + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); unsigned int i, j; char slave_name[45]; - qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS); + qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS); memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s, "master-interrupt-controller", INTCTLM_SIZE); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); for (i = 0; i < MAX_CPUS; i++) { snprintf(slave_name, sizeof(slave_name), "slave-interrupt-controller-%i", i); for (j = 0; j < MAX_PILS; j++) { - sysbus_init_irq(dev, &s->cpu_irqs[i][j]); + sysbus_init_irq(sbd, &s->cpu_irqs[i][j]); } memory_region_init_io(&s->slaves[i].iomem, OBJECT(s), &slavio_intctl_mem_ops, &s->slaves[i], slave_name, INTCTL_SIZE); - sysbus_init_mmio(dev, &s->slaves[i].iomem); + sysbus_init_mmio(sbd, &s->slaves[i].iomem); s->slaves[i].cpu = i; s->slaves[i].master = s; } @@ -458,7 +459,7 @@ static void slavio_intctl_class_init(ObjectClass *klass, void *data) } static const TypeInfo slavio_intctl_info = { - .name = "slavio_intctl", + .name = TYPE_SLAVIO_INTCTL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_INTCTLState), .class_init = slavio_intctl_class_init, diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 091912e2ca..6b3c071588 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -34,34 +34,19 @@ * ICP: Presentation layer */ -struct icp_server_state { - uint32_t xirr; - uint8_t pending_priority; - uint8_t mfrr; - qemu_irq output; -}; - #define XISR_MASK 0x00ffffff #define CPPR_MASK 0xff000000 #define XISR(ss) (((ss)->xirr) & XISR_MASK) #define CPPR(ss) (((ss)->xirr) >> 24) -struct ics_state; - -struct icp_state { - long nr_servers; - struct icp_server_state *ss; - struct ics_state *ics; -}; - -static void ics_reject(struct ics_state *ics, int nr); -static void ics_resend(struct ics_state *ics); -static void ics_eoi(struct ics_state *ics, int nr); +static void ics_reject(ICSState *ics, int nr); +static void ics_resend(ICSState *ics); +static void ics_eoi(ICSState *ics, int nr); -static void icp_check_ipi(struct icp_state *icp, int server) +static void icp_check_ipi(XICSState *icp, int server) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { return; @@ -78,9 +63,9 @@ static void icp_check_ipi(struct icp_state *icp, int server) qemu_irq_raise(ss->output); } -static void icp_resend(struct icp_state *icp, int server) +static void icp_resend(XICSState *icp, int server) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; if (ss->mfrr < CPPR(ss)) { icp_check_ipi(icp, server); @@ -88,9 +73,9 @@ static void icp_resend(struct icp_state *icp, int server) ics_resend(icp->ics); } -static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) +static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; uint8_t old_cppr; uint32_t old_xisr; @@ -112,9 +97,9 @@ static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) } } -static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) +static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { @@ -122,7 +107,7 @@ static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) } } -static uint32_t icp_accept(struct icp_server_state *ss) +static uint32_t icp_accept(ICPState *ss) { uint32_t xirr = ss->xirr; @@ -135,9 +120,9 @@ static uint32_t icp_accept(struct icp_server_state *ss) return xirr; } -static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) +static void icp_eoi(XICSState *icp, int server, uint32_t xirr) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); @@ -148,9 +133,9 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) } } -static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) +static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; trace_xics_icp_irq(server, nr, priority); @@ -168,39 +153,59 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) } } -/* - * ICS: Source layer - */ - -struct ics_irq_state { - int server; - uint8_t priority; - uint8_t saved_priority; -#define XICS_STATUS_ASSERTED 0x1 -#define XICS_STATUS_SENT 0x2 -#define XICS_STATUS_REJECTED 0x4 -#define XICS_STATUS_MASKED_PENDING 0x8 - uint8_t status; +static const VMStateDescription vmstate_icp_server = { + .name = "icp/server", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32(xirr, ICPState), + VMSTATE_UINT8(pending_priority, ICPState), + VMSTATE_UINT8(mfrr, ICPState), + VMSTATE_END_OF_LIST() + }, }; -struct ics_state { - int nr_irqs; - int offset; - qemu_irq *qirqs; - bool *islsi; - struct ics_irq_state *irqs; - struct icp_state *icp; +static void icp_reset(DeviceState *dev) +{ + ICPState *icp = ICP(dev); + + icp->xirr = 0; + icp->pending_priority = 0xff; + icp->mfrr = 0xff; + + /* Make all outputs are deasserted */ + qemu_set_irq(icp->output, 0); +} + +static void icp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = icp_reset; + dc->vmsd = &vmstate_icp_server; +} + +static TypeInfo icp_info = { + .name = TYPE_ICP, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ICPState), + .class_init = icp_class_init, }; -static int ics_valid_irq(struct ics_state *ics, uint32_t nr) +/* + * ICS: Source layer + */ +static int ics_valid_irq(ICSState *ics, uint32_t nr) { return (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs)); } -static void resend_msi(struct ics_state *ics, int srcno) +static void resend_msi(ICSState *ics, int srcno) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; /* FIXME: filter by server#? */ if (irq->status & XICS_STATUS_REJECTED) { @@ -212,9 +217,9 @@ static void resend_msi(struct ics_state *ics, int srcno) } } -static void resend_lsi(struct ics_state *ics, int srcno) +static void resend_lsi(ICSState *ics, int srcno) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; if ((irq->priority != 0xff) && (irq->status & XICS_STATUS_ASSERTED) @@ -224,9 +229,9 @@ static void resend_lsi(struct ics_state *ics, int srcno) } } -static void set_irq_msi(struct ics_state *ics, int srcno, int val) +static void set_irq_msi(ICSState *ics, int srcno, int val) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; trace_xics_set_irq_msi(srcno, srcno + ics->offset); @@ -240,9 +245,9 @@ static void set_irq_msi(struct ics_state *ics, int srcno, int val) } } -static void set_irq_lsi(struct ics_state *ics, int srcno, int val) +static void set_irq_lsi(ICSState *ics, int srcno, int val) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; trace_xics_set_irq_lsi(srcno, srcno + ics->offset); if (val) { @@ -255,7 +260,7 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val) static void ics_set_irq(void *opaque, int srcno, int val) { - struct ics_state *ics = (struct ics_state *)opaque; + ICSState *ics = (ICSState *)opaque; if (ics->islsi[srcno]) { set_irq_lsi(ics, srcno, val); @@ -264,9 +269,9 @@ static void ics_set_irq(void *opaque, int srcno, int val) } } -static void write_xive_msi(struct ics_state *ics, int srcno) +static void write_xive_msi(ICSState *ics, int srcno) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; if (!(irq->status & XICS_STATUS_MASKED_PENDING) || (irq->priority == 0xff)) { @@ -277,16 +282,16 @@ static void write_xive_msi(struct ics_state *ics, int srcno) icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } -static void write_xive_lsi(struct ics_state *ics, int srcno) +static void write_xive_lsi(ICSState *ics, int srcno) { resend_lsi(ics, srcno); } -static void ics_write_xive(struct ics_state *ics, int nr, int server, +static void ics_write_xive(ICSState *ics, int nr, int server, uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; irq->server = server; irq->priority = priority; @@ -301,16 +306,16 @@ static void ics_write_xive(struct ics_state *ics, int nr, int server, } } -static void ics_reject(struct ics_state *ics, int nr) +static void ics_reject(ICSState *ics, int nr) { - struct ics_irq_state *irq = ics->irqs + nr - ics->offset; + ICSIRQState *irq = ics->irqs + nr - ics->offset; trace_xics_ics_reject(nr, nr - ics->offset); irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ } -static void ics_resend(struct ics_state *ics) +static void ics_resend(ICSState *ics) { int i; @@ -324,10 +329,10 @@ static void ics_resend(struct ics_state *ics) } } -static void ics_eoi(struct ics_state *ics, int nr) +static void ics_eoi(ICSState *ics, int nr) { int srcno = nr - ics->offset; - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; trace_xics_ics_eoi(nr); @@ -336,11 +341,92 @@ static void ics_eoi(struct ics_state *ics, int nr) } } +static void ics_reset(DeviceState *dev) +{ + ICSState *ics = ICS(dev); + int i; + + memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs); + for (i = 0; i < ics->nr_irqs; i++) { + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } +} + +static int ics_post_load(void *opaque, int version_id) +{ + int i; + ICSState *ics = opaque; + + for (i = 0; i < ics->icp->nr_servers; i++) { + icp_resend(ics->icp, i); + } + + return 0; +} + +static const VMStateDescription vmstate_ics_irq = { + .name = "ics/irq", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(server, ICSIRQState), + VMSTATE_UINT8(priority, ICSIRQState), + VMSTATE_UINT8(saved_priority, ICSIRQState), + VMSTATE_UINT8(status, ICSIRQState), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_ics = { + .name = "ics", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ics_post_load, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32_EQUAL(nr_irqs, ICSState), + + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, + vmstate_ics_irq, ICSIRQState), + VMSTATE_END_OF_LIST() + }, +}; + +static int ics_realize(DeviceState *dev) +{ + ICSState *ics = ICS(dev); + + ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); + ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool)); + ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); + + return 0; +} + +static void ics_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->init = ics_realize; + dc->vmsd = &vmstate_ics; + dc->reset = ics_reset; +} + +static TypeInfo ics_info = { + .name = TYPE_ICS, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ICSState), + .class_init = ics_class_init, +}; + /* * Exported functions */ -qemu_irq xics_get_qirq(struct icp_state *icp, int irq) +qemu_irq xics_get_qirq(XICSState *icp, int irq) { if (!ics_valid_irq(icp->ics, irq)) { return NULL; @@ -349,13 +435,17 @@ qemu_irq xics_get_qirq(struct icp_state *icp, int irq) return icp->ics->qirqs[irq - icp->ics->offset]; } -void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) +void xics_set_irq_type(XICSState *icp, int irq, bool lsi) { assert(ics_valid_irq(icp->ics, irq)); icp->ics->islsi[irq - icp->ics->offset] = lsi; } +/* + * Guest interfaces + */ + static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -405,7 +495,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr, server, priority; if ((nargs != 3) || (nret != 1)) { @@ -433,7 +523,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr; if ((nargs != 1) || (nret != 3)) { @@ -458,7 +548,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr; if ((nargs != 1) || (nret != 1)) { @@ -484,7 +574,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr; if ((nargs != 1) || (nret != 1)) { @@ -506,32 +596,27 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, rtas_st(rets, 0, 0); /* Success */ } -static void xics_reset(void *opaque) +/* + * XICS + */ + +static void xics_reset(DeviceState *d) { - struct icp_state *icp = (struct icp_state *)opaque; - struct ics_state *ics = icp->ics; + XICSState *icp = XICS(d); int i; for (i = 0; i < icp->nr_servers; i++) { - icp->ss[i].xirr = 0; - icp->ss[i].pending_priority = 0xff; - icp->ss[i].mfrr = 0xff; - /* Make all outputs are deasserted */ - qemu_set_irq(icp->ss[i].output, 0); + device_reset(DEVICE(&icp->ss[i])); } - memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs); - for (i = 0; i < ics->nr_irqs; i++) { - ics->irqs[i].priority = 0xff; - ics->irqs[i].saved_priority = 0xff; - } + device_reset(DEVICE(icp->ics)); } -void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu) +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - struct icp_server_state *ss = &icp->ss[cs->cpu_index]; + ICPState *ss = &icp->ss[cs->cpu_index]; assert(cs->cpu_index < icp->nr_servers); @@ -551,37 +636,73 @@ void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu) } } -struct icp_state *xics_system_init(int nr_servers, int nr_irqs) +static void xics_realize(DeviceState *dev, Error **errp) { - struct icp_state *icp; - struct ics_state *ics; - - icp = g_malloc0(sizeof(*icp)); - icp->nr_servers = nr_servers; - icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); + XICSState *icp = XICS(dev); + ICSState *ics = icp->ics; + int i; - ics = g_malloc0(sizeof(*ics)); - ics->nr_irqs = nr_irqs; + ics->nr_irqs = icp->nr_irqs; ics->offset = XICS_IRQ_BASE; - ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state)); - ics->islsi = g_malloc0(nr_irqs * sizeof(bool)); - - icp->ics = ics; ics->icp = icp; + qdev_init_nofail(DEVICE(ics)); - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); + icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); + for (i = 0; i < icp->nr_servers; i++) { + char buffer[32]; + object_initialize(&icp->ss[i], TYPE_ICP); + snprintf(buffer, sizeof(buffer), "icp[%d]", i); + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), NULL); + qdev_init_nofail(DEVICE(&icp->ss[i])); + } +} - spapr_register_hypercall(H_CPPR, h_cppr); - spapr_register_hypercall(H_IPI, h_ipi); - spapr_register_hypercall(H_XIRR, h_xirr); - spapr_register_hypercall(H_EOI, h_eoi); +static void xics_initfn(Object *obj) +{ + XICSState *xics = XICS(obj); + + xics->ics = ICS(object_new(TYPE_ICS)); + object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); +} + +static Property xics_properties[] = { + DEFINE_PROP_UINT32("nr_servers", XICSState, nr_servers, -1), + DEFINE_PROP_UINT32("nr_irqs", XICSState, nr_irqs, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xics_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = xics_realize; + dc->props = xics_properties; + dc->reset = xics_reset; spapr_rtas_register("ibm,set-xive", rtas_set_xive); spapr_rtas_register("ibm,get-xive", rtas_get_xive); spapr_rtas_register("ibm,int-off", rtas_int_off); spapr_rtas_register("ibm,int-on", rtas_int_on); - qemu_register_reset(xics_reset, icp); + spapr_register_hypercall(H_CPPR, h_cppr); + spapr_register_hypercall(H_IPI, h_ipi); + spapr_register_hypercall(H_XIRR, h_xirr); + spapr_register_hypercall(H_EOI, h_eoi); +} + +static const TypeInfo xics_info = { + .name = TYPE_XICS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XICSState), + .class_init = xics_class_init, + .instance_init = xics_initfn, +}; - return icp; +static void xics_register_types(void) +{ + type_register_static(&xics_info); + type_register_static(&ics_info); + type_register_static(&icp_info); } + +type_init(xics_register_types) diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index 25d2057d78..4a103988f3 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -37,9 +37,13 @@ #define R_MER 7 #define R_MAX 8 +#define TYPE_XILINX_INTC "xlnx.xps-intc" +#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC) + struct xlx_pic { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mmio; qemu_irq parent_irq; @@ -153,16 +157,17 @@ static void irq_handler(void *opaque, int irq, int level) update_irq(p); } -static int xilinx_intc_init(SysBusDevice *dev) +static int xilinx_intc_init(SysBusDevice *sbd) { - struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev); + DeviceState *dev = DEVICE(sbd); + struct xlx_pic *p = XILINX_INTC(dev); - qdev_init_gpio_in(&dev->qdev, irq_handler, 32); - sysbus_init_irq(dev, &p->parent_irq); + qdev_init_gpio_in(dev, irq_handler, 32); + sysbus_init_irq(sbd, &p->parent_irq); memory_region_init_io(&p->mmio, OBJECT(p), &pic_ops, p, "xlnx.xps-intc", R_MAX * 4); - sysbus_init_mmio(dev, &p->mmio); + sysbus_init_mmio(sbd, &p->mmio); return 0; } @@ -181,7 +186,7 @@ static void xilinx_intc_class_init(ObjectClass *klass, void *data) } static const TypeInfo xilinx_intc_info = { - .name = "xlnx.xps-intc", + .name = TYPE_XILINX_INTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_pic), .class_init = xilinx_intc_class_init, diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs index 193746a73e..9164556a4d 100644 --- a/hw/isa/Makefile.objs +++ b/hw/isa/Makefile.objs @@ -1,7 +1,6 @@ common-obj-y += isa-bus.o common-obj-$(CONFIG_APM) += apm.o common-obj-$(CONFIG_I82378) += i82378.o -common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o common-obj-$(CONFIG_PC87312) += pc87312.o common-obj-$(CONFIG_PIIX4) += piix4.o common-obj-$(CONFIG_VT82C686) += vt82c686.o diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index b25ed04af3..a7d9aa6da1 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -22,135 +22,28 @@ #include "hw/timer/i8254.h" #include "hw/audio/pcspk.h" -//#define DEBUG_I82378 - -#ifdef DEBUG_I82378 -#define DPRINTF(fmt, ...) \ -do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ -do {} while (0) -#endif - -#define BADF(fmt, ...) \ -do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0) +#define TYPE_I82378 "i82378" +#define I82378(obj) \ + OBJECT_CHECK(I82378State, (obj), TYPE_I82378) typedef struct I82378State { + PCIDevice parent_obj; + qemu_irq out[2]; qemu_irq *i8259; MemoryRegion io; - MemoryRegion mem; } I82378State; -typedef struct PCIi82378State { - PCIDevice pci_dev; - uint32_t isa_io_base; - uint32_t isa_mem_base; - I82378State state; -} PCIi82378State; - -static const VMStateDescription vmstate_pci_i82378 = { +static const VMStateDescription vmstate_i82378 = { .name = "pci-i82378", .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(pci_dev, PCIi82378State), + VMSTATE_PCI_DEVICE(parent_obj, I82378State), VMSTATE_END_OF_LIST() }, }; -static void i82378_io_write(void *opaque, hwaddr addr, - uint64_t value, unsigned int size) -{ - switch (size) { - case 1: - DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__, - addr, value); - cpu_outb(addr, value); - break; - case 2: - DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__, - addr, value); - cpu_outw(addr, value); - break; - case 4: - DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__, - addr, value); - cpu_outl(addr, value); - break; - default: - abort(); - } -} - -static uint64_t i82378_io_read(void *opaque, hwaddr addr, - unsigned int size) -{ - DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); - switch (size) { - case 1: - return cpu_inb(addr); - case 2: - return cpu_inw(addr); - case 4: - return cpu_inl(addr); - default: - abort(); - } -} - -static const MemoryRegionOps i82378_io_ops = { - .read = i82378_io_read, - .write = i82378_io_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void i82378_mem_write(void *opaque, hwaddr addr, - uint64_t value, unsigned int size) -{ - switch (size) { - case 1: - DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__, - addr, value); - cpu_outb(addr, value); - break; - case 2: - DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__, - addr, value); - cpu_outw(addr, value); - break; - case 4: - DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__, - addr, value); - cpu_outl(addr, value); - break; - default: - abort(); - } -} - -static uint64_t i82378_mem_read(void *opaque, hwaddr addr, - unsigned int size) -{ - DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); - switch (size) { - case 1: - return cpu_inb(addr); - case 2: - return cpu_inw(addr); - case 4: - return cpu_inl(addr); - default: - abort(); - } -} - -static const MemoryRegionOps i82378_mem_ops = { - .read = i82378_mem_read, - .write = i82378_mem_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - static void i82378_request_out0_irq(void *opaque, int irq, int level) { I82378State *s = opaque; @@ -160,19 +53,30 @@ static void i82378_request_out0_irq(void *opaque, int irq, int level) static void i82378_request_pic_irq(void *opaque, int irq, int level) { DeviceState *dev = opaque; - PCIDevice *pci = DO_UPCAST(PCIDevice, qdev, dev); - PCIi82378State *s = DO_UPCAST(PCIi82378State, pci_dev, pci); + I82378State *s = I82378(dev); - qemu_set_irq(s->state.i8259[irq], level); + qemu_set_irq(s->i8259[irq], level); } -static void i82378_init(DeviceState *dev, I82378State *s) +static int i82378_initfn(PCIDevice *pci) { - ISABus *isabus = ISA_BUS(qdev_get_child_bus(dev, "isa.0")); - ISADevice *pit; + DeviceState *dev = DEVICE(pci); + I82378State *s = I82378(dev); + uint8_t *pci_conf; + ISABus *isabus; ISADevice *isa; qemu_irq *out0_irq; + pci_conf = pci->config; + pci_set_word(pci_conf + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pci_set_word(pci_conf + PCI_STATUS, + PCI_STATUS_DEVSEL_MEDIUM); + + pci_config_set_interrupt_pin(pci_conf, 1); /* interrupt pin 0 */ + + isabus = isa_bus_new(dev, pci_address_space_io(pci)); + /* This device has: 2 82C59 (irq) 1 82C54 (pit) @@ -183,9 +87,6 @@ static void i82378_init(DeviceState *dev, I82378State *s) All devices accept byte access only, except timer */ - qdev_init_gpio_out(dev, s->out, 2); - qdev_init_gpio_in(dev, i82378_request_pic_irq, 16); - /* Workaround the fact that i8259 is not qdev'ified... */ out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1); @@ -194,10 +95,10 @@ static void i82378_init(DeviceState *dev, I82378State *s) isa_bus_irqs(isabus, s->i8259); /* 1 82C54 (pit) */ - pit = pit_init(isabus, 0x40, 0, NULL); + isa = pit_init(isabus, 0x40, 0, NULL); /* speaker */ - pcspk_init(isabus, pit); + pcspk_init(isabus, isa); /* 2 82C37 (dma) */ isa = isa_create_simple(isabus, "i82374"); @@ -205,75 +106,44 @@ static void i82378_init(DeviceState *dev, I82378State *s) /* timer */ isa_create_simple(isabus, "mc146818rtc"); + + return 0; } -static int pci_i82378_init(PCIDevice *dev) +static void i82378_init(Object *obj) { - PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, dev); - I82378State *s = &pci->state; - uint8_t *pci_conf; + DeviceState *dev = DEVICE(obj); + I82378State *s = I82378(obj); - pci_conf = dev->config; - pci_set_word(pci_conf + PCI_COMMAND, - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - pci_set_word(pci_conf + PCI_STATUS, - PCI_STATUS_DEVSEL_MEDIUM); - - pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */ - - memory_region_init_io(&s->io, OBJECT(pci), &i82378_io_ops, s, - "i82378-io", 0x00010000); - pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io); - - memory_region_init_io(&s->mem, OBJECT(pci), &i82378_mem_ops, s, - "i82378-mem", 0x01000000); - pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); - - /* Make I/O address read only */ - pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL); - pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0); - pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base); - - isa_mem_base = pci->isa_mem_base; - isa_bus_new(&dev->qdev, pci_address_space_io(dev)); - - i82378_init(&dev->qdev, s); - - return 0; + qdev_init_gpio_out(dev, s->out, 2); + qdev_init_gpio_in(dev, i82378_request_pic_irq, 16); } -static Property i82378_properties[] = { - DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000), - DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000), - DEFINE_PROP_END_OF_LIST() -}; - -static void pci_i82378_class_init(ObjectClass *klass, void *data) +static void i82378_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->init = pci_i82378_init; + k->init = i82378_initfn; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82378; k->revision = 0x03; k->class_id = PCI_CLASS_BRIDGE_ISA; - k->subsystem_vendor_id = 0x0; - k->subsystem_id = 0x0; - dc->vmsd = &vmstate_pci_i82378; - dc->props = i82378_properties; + dc->vmsd = &vmstate_i82378; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } -static const TypeInfo pci_i82378_info = { - .name = "i82378", +static const TypeInfo i82378_type_info = { + .name = TYPE_I82378, .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIi82378State), - .class_init = pci_i82378_class_init, + .instance_size = sizeof(I82378State), + .instance_init = i82378_init, + .class_init = i82378_class_init, }; static void i82378_register_types(void) { - type_register_static(&pci_i82378_info); + type_register_static(&i82378_type_info); } type_init(i82378_register_types) diff --git a/hw/isa/isa_mmio.c b/hw/isa/isa_mmio.c deleted file mode 100644 index 00ae8ebc2e..0000000000 --- a/hw/isa/isa_mmio.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Memory mapped access to ISA IO space. - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/isa/isa.h" -#include "exec/address-spaces.h" - -static void isa_mmio_writeb (void *opaque, hwaddr addr, - uint32_t val) -{ - cpu_outb(addr & IOPORTS_MASK, val); -} - -static void isa_mmio_writew(void *opaque, hwaddr addr, - uint32_t val) -{ - cpu_outw(addr & IOPORTS_MASK, val); -} - -static void isa_mmio_writel(void *opaque, hwaddr addr, - uint32_t val) -{ - cpu_outl(addr & IOPORTS_MASK, val); -} - -static uint32_t isa_mmio_readb (void *opaque, hwaddr addr) -{ - return cpu_inb(addr & IOPORTS_MASK); -} - -static uint32_t isa_mmio_readw(void *opaque, hwaddr addr) -{ - return cpu_inw(addr & IOPORTS_MASK); -} - -static uint32_t isa_mmio_readl(void *opaque, hwaddr addr) -{ - return cpu_inl(addr & IOPORTS_MASK); -} - -static const MemoryRegionOps isa_mmio_ops = { - .old_mmio = { - .write = { isa_mmio_writeb, isa_mmio_writew, isa_mmio_writel }, - .read = { isa_mmio_readb, isa_mmio_readw, isa_mmio_readl, }, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void isa_mmio_setup(MemoryRegion *mr, hwaddr size) -{ - memory_region_init_io(mr, NULL, &isa_mmio_ops, NULL, "isa-mmio", size); -} - -void isa_mmio_init(hwaddr base, hwaddr size) -{ - MemoryRegion *mr = g_malloc(sizeof(*mr)); - - isa_mmio_setup(mr, size); - memory_region_add_subregion(get_system_memory(), base, mr); -} diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index d1921aa635..5633d08b62 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -600,6 +600,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = ich9_lpc_reset; k->init = ich9_lpc_initfn; dc->vmsd = &vmstate_ich9_lpc; diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 2174eaaf87..8fe4fcb4a1 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -281,6 +281,7 @@ static void via_ac97_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIA_AC97; k->revision = 0x50; k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "AC97"; } @@ -322,6 +323,7 @@ static void via_mc97_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIA_MC97; k->class_id = PCI_CLASS_COMMUNICATION_OTHER; k->revision = 0x30; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "MC97"; } @@ -401,6 +403,7 @@ static void via_pm_class_init(ObjectClass *klass, void *data) k->revision = 0x40; dc->desc = "PM"; dc->vmsd = &vmstate_acpi; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = via_pm_properties; } diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h index 236686ef2b..18aa6fdc15 100644 --- a/hw/lm32/lm32.h +++ b/hw/lm32/lm32.h @@ -1,8 +1,7 @@ #ifndef HW_LM32_H #define HW_LM32_H 1 - -#include "qemu-common.h" +#include "hw/char/lm32_juart.h" static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) { @@ -21,7 +20,7 @@ static inline DeviceState *lm32_juart_init(void) { DeviceState *dev; - dev = qdev_create(NULL, "lm32-juart"); + dev = qdev_create(NULL, TYPE_LM32_JUART); qdev_init_nofail(dev); return dev; diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c index e0266bf15a..c8b4b000cd 100644 --- a/hw/mips/cputimer.c +++ b/hw/mips/cputimer.c @@ -47,11 +47,11 @@ static void cpu_mips_timer_update(CPUMIPSState *env) uint64_t now, next; uint32_t wait; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); wait = env->CP0_Compare - env->CP0_Count - (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec()); next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); - qemu_mod_timer(env->timer, next); + timer_mod(env->timer, next); } /* Expire the timer. */ @@ -71,9 +71,9 @@ uint32_t cpu_mips_get_count (CPUMIPSState *env) } else { uint64_t now; - now = qemu_get_clock_ns(vm_clock); - if (qemu_timer_pending(env->timer) - && qemu_timer_expired(env->timer, now)) { + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (timer_pending(env->timer) + && timer_expired(env->timer, now)) { /* The timer has already expired. */ cpu_mips_timer_expire(env); } @@ -90,7 +90,7 @@ void cpu_mips_store_count (CPUMIPSState *env, uint32_t count) else { /* Store new count register */ env->CP0_Count = - count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock), + count - (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), TIMER_FREQ, get_ticks_per_sec()); /* Update timer timer */ cpu_mips_timer_update(env); @@ -115,7 +115,7 @@ void cpu_mips_start_count(CPUMIPSState *env) void cpu_mips_stop_count(CPUMIPSState *env) { /* Store the current value */ - env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock), + env->CP0_Count += (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), TIMER_FREQ, get_ticks_per_sec()); } @@ -141,7 +141,7 @@ static void mips_timer_cb (void *opaque) void cpu_mips_clock_init (CPUMIPSState *env) { - env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env); + env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env); env->CP0_Compare = 0; cpu_mips_store_count(env, 1); } diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 5843417567..3da2e67098 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -304,7 +304,8 @@ static void gt64120_pci_mapping(GT64120State *s) s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; isa_mem_base = s->PCI0IO_start; if (s->PCI0IO_length) { - isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length); + memory_region_init_alias(&s->PCI0IO_mem, OBJECT(s), "isa_mmio", + get_system_io(), 0, s->PCI0IO_length); memory_region_add_subregion(get_system_memory(), s->PCI0IO_start, &s->PCI0IO_mem); } diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 9e305d2878..e8d5dd0980 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -43,6 +43,8 @@ #include "hw/timer/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" +#include "sysemu/qtest.h" +#include "qemu/error-report.h" #define DEBUG_FULONG2E_INIT @@ -126,7 +128,7 @@ static int64_t load_kernel (CPUMIPSState *env) if (loaderparams.initrd_filename) { initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", @@ -332,8 +334,9 @@ static void mips_fulong2e_init(QEMUMachineInitArgs *args) bios_size = -1; } - if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { - fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name); + if ((bios_size < 0 || bios_size > BIOS_SIZE) && + !kernel_filename && !qtest_enabled()) { + error_report("Could not load MIPS bios '%s'", bios_name); exit(1); } } diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 31e138b056..d748ded7eb 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -42,6 +42,8 @@ #include "sysemu/blockdev.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" +#include "sysemu/qtest.h" +#include "qemu/error-report.h" enum jazz_model_e { @@ -119,6 +121,7 @@ static void mips_jazz_init(MemoryRegion *address_space, qemu_irq *rc4030, *i8259; rc4030_dma *dmas; void* rc4030_opaque; + MemoryRegion *isa = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); @@ -175,9 +178,8 @@ static void mips_jazz_init(MemoryRegion *address_space, } else { bios_size = -1; } - if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) { - fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", - bios_name); + if ((bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) && !qtest_enabled()) { + error_report("Could not load MIPS bios '%s'", bios_name); exit(1); } @@ -201,7 +203,9 @@ static void mips_jazz_init(MemoryRegion *address_space, pcspk_init(isa_bus, pit); /* ISA IO space at 0x90000000 */ - isa_mmio_init(0x90000000, 0x01000000); + memory_region_init_alias(isa, NULL, "isa_mmio", + get_system_io(), 0, 0x01000000); + memory_region_add_subregion(address_space, 0x90000000, isa); isa_mem_base = 0x11000000; /* Video card */ diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index de87241e9c..f8d064cec3 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -47,6 +47,10 @@ #include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "hw/sysbus.h" /* SysBusDevice */ +#include "qemu/host-utils.h" +#include "sysemu/qtest.h" +#include "qemu/error-report.h" +#include "hw/empty_slot.h" //#define DEBUG_BOARD_INIT @@ -79,8 +83,12 @@ typedef struct { SerialState *uart; } MaltaFPGAState; +#define TYPE_MIPS_MALTA "mips-malta" +#define MIPS_MALTA(obj) OBJECT_CHECK(MaltaState, (obj), TYPE_MIPS_MALTA) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + qemu_irq *i8259; } MaltaState; @@ -144,12 +152,12 @@ struct _eeprom24c0x_t { typedef struct _eeprom24c0x_t eeprom24c0x_t; -static eeprom24c0x_t eeprom = { +static eeprom24c0x_t spd_eeprom = { .contents = { - /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00, + /* 00000000: */ 0x80,0x08,0xFF,0x0D,0x0A,0xFF,0x40,0x00, /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01, - /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00, - /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40, + /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x00,0x00, + /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0xFF, /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00, /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, @@ -165,69 +173,157 @@ static eeprom24c0x_t eeprom = { }, }; -static uint8_t eeprom24c0x_read(void) +static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size) +{ + enum { SDR = 0x4, DDR2 = 0x8 } type; + uint8_t *spd = spd_eeprom.contents; + uint8_t nbanks = 0; + uint16_t density = 0; + int i; + + /* work in terms of MB */ + ram_size >>= 20; + + while ((ram_size >= 4) && (nbanks <= 2)) { + int sz_log2 = MIN(31 - clz32(ram_size), 14); + nbanks++; + density |= 1 << (sz_log2 - 2); + ram_size -= 1 << sz_log2; + } + + /* split to 2 banks if possible */ + if ((nbanks == 1) && (density > 1)) { + nbanks++; + density >>= 1; + } + + if (density & 0xff00) { + density = (density & 0xe0) | ((density >> 8) & 0x1f); + type = DDR2; + } else if (!(density & 0x1f)) { + type = DDR2; + } else { + type = SDR; + } + + if (ram_size) { + fprintf(stderr, "Warning: SPD cannot represent final %dMB" + " of SDRAM\n", (int)ram_size); + } + + /* fill in SPD memory information */ + spd[2] = type; + spd[5] = nbanks; + spd[31] = density; + + /* checksum */ + spd[63] = 0; + for (i = 0; i < 63; i++) { + spd[63] += spd[i]; + } + + /* copy for SMBUS */ + memcpy(eeprom, spd, sizeof(spd_eeprom.contents)); +} + +static void generate_eeprom_serial(uint8_t *eeprom) +{ + int i, pos = 0; + uint8_t mac[6] = { 0x00 }; + uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 }; + + /* version */ + eeprom[pos++] = 0x01; + + /* count */ + eeprom[pos++] = 0x02; + + /* MAC address */ + eeprom[pos++] = 0x01; /* MAC */ + eeprom[pos++] = 0x06; /* length */ + memcpy(&eeprom[pos], mac, sizeof(mac)); + pos += sizeof(mac); + + /* serial number */ + eeprom[pos++] = 0x02; /* serial */ + eeprom[pos++] = 0x05; /* length */ + memcpy(&eeprom[pos], sn, sizeof(sn)); + pos += sizeof(sn); + + /* checksum */ + eeprom[pos] = 0; + for (i = 0; i < pos; i++) { + eeprom[pos] += eeprom[i]; + } +} + +static uint8_t eeprom24c0x_read(eeprom24c0x_t *eeprom) { logout("%u: scl = %u, sda = %u, data = 0x%02x\n", - eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data); - return eeprom.sda; + eeprom->tick, eeprom->scl, eeprom->sda, eeprom->data); + return eeprom->sda; } -static void eeprom24c0x_write(int scl, int sda) +static void eeprom24c0x_write(eeprom24c0x_t *eeprom, int scl, int sda) { - if (eeprom.scl && scl && (eeprom.sda != sda)) { + if (eeprom->scl && scl && (eeprom->sda != sda)) { logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n", - eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start"); + eeprom->tick, eeprom->scl, scl, eeprom->sda, sda, + sda ? "stop" : "start"); if (!sda) { - eeprom.tick = 1; - eeprom.command = 0; + eeprom->tick = 1; + eeprom->command = 0; } - } else if (eeprom.tick == 0 && !eeprom.ack) { + } else if (eeprom->tick == 0 && !eeprom->ack) { /* Waiting for start. */ logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n", - eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); - } else if (!eeprom.scl && scl) { + eeprom->tick, eeprom->scl, scl, eeprom->sda, sda); + } else if (!eeprom->scl && scl) { logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n", - eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); - if (eeprom.ack) { + eeprom->tick, eeprom->scl, scl, eeprom->sda, sda); + if (eeprom->ack) { logout("\ti2c ack bit = 0\n"); sda = 0; - eeprom.ack = 0; - } else if (eeprom.sda == sda) { + eeprom->ack = 0; + } else if (eeprom->sda == sda) { uint8_t bit = (sda != 0); logout("\ti2c bit = %d\n", bit); - if (eeprom.tick < 9) { - eeprom.command <<= 1; - eeprom.command += bit; - eeprom.tick++; - if (eeprom.tick == 9) { - logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write"); - eeprom.ack = 1; + if (eeprom->tick < 9) { + eeprom->command <<= 1; + eeprom->command += bit; + eeprom->tick++; + if (eeprom->tick == 9) { + logout("\tcommand 0x%04x, %s\n", eeprom->command, + bit ? "read" : "write"); + eeprom->ack = 1; } - } else if (eeprom.tick < 17) { - if (eeprom.command & 1) { - sda = ((eeprom.data & 0x80) != 0); + } else if (eeprom->tick < 17) { + if (eeprom->command & 1) { + sda = ((eeprom->data & 0x80) != 0); } - eeprom.address <<= 1; - eeprom.address += bit; - eeprom.tick++; - eeprom.data <<= 1; - if (eeprom.tick == 17) { - eeprom.data = eeprom.contents[eeprom.address]; - logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data); - eeprom.ack = 1; - eeprom.tick = 0; + eeprom->address <<= 1; + eeprom->address += bit; + eeprom->tick++; + eeprom->data <<= 1; + if (eeprom->tick == 17) { + eeprom->data = eeprom->contents[eeprom->address]; + logout("\taddress 0x%04x, data 0x%02x\n", + eeprom->address, eeprom->data); + eeprom->ack = 1; + eeprom->tick = 0; } - } else if (eeprom.tick >= 17) { + } else if (eeprom->tick >= 17) { sda = 0; } } else { logout("\tsda changed with raising scl\n"); } } else { - logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom->tick, eeprom->scl, + scl, eeprom->sda, sda); } - eeprom.scl = scl; - eeprom.sda = sda; + eeprom->scl = scl; + eeprom->sda = sda; } static uint64_t malta_fpga_read(void *opaque, hwaddr addr, @@ -290,7 +386,7 @@ static uint64_t malta_fpga_read(void *opaque, hwaddr addr, /* I2CINP Register */ case 0x00b00: - val = ((s->i2cin & ~1) | eeprom24c0x_read()); + val = ((s->i2cin & ~1) | eeprom24c0x_read(&spd_eeprom)); break; /* I2COE Register */ @@ -386,7 +482,7 @@ static void malta_fpga_write(void *opaque, hwaddr addr, /* I2COUT Register */ case 0x00b10: - eeprom24c0x_write(val & 0x02, val & 0x01); + eeprom24c0x_write(&spd_eeprom, val & 0x02, val & 0x01); s->i2cout = val; break; @@ -699,7 +795,7 @@ static int64_t load_kernel (void) if (loaderparams.initrd_filename) { initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", @@ -789,8 +885,10 @@ void mips_malta_init(QEMUMachineInitArgs *args) pflash_t *fl; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1); + MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1); target_long bios_size = FLASH_SIZE; + const size_t smbus_eeprom_size = 8 * 256; + uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size); int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; @@ -808,8 +906,13 @@ void mips_malta_init(QEMUMachineInitArgs *args) int fl_sectors = bios_size >> 16; int be; - DeviceState *dev = qdev_create(NULL, "mips-malta"); - MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev); + DeviceState *dev = qdev_create(NULL, TYPE_MIPS_MALTA); + MaltaState *s = MIPS_MALTA(dev); + + /* The whole address space decoded by the GT-64120A doesn't generate + exception when accessing invalid memory. Create an empty slot to + emulate this feature. */ + empty_slot_init(0, 0x20000000); qdev_init_nofail(dev); @@ -858,6 +961,10 @@ void mips_malta_init(QEMUMachineInitArgs *args) vmstate_register_ram_global(ram); memory_region_add_subregion(system_memory, 0, ram); + /* generate SPD EEPROM data */ + generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); + generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]); + #ifdef TARGET_WORDS_BIGENDIAN be = 1; #else @@ -906,10 +1013,10 @@ void mips_malta_init(QEMUMachineInitArgs *args) } else { bios_size = -1; } - if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { - fprintf(stderr, - "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", - bios_name); + if ((bios_size < 0 || bios_size > BIOS_SIZE) && + !kernel_filename && !qtest_enabled()) { + error_report("Could not load MIPS bios '%s', and no " + "-kernel argument was specified", bios_name); exit(1); } } @@ -917,8 +1024,11 @@ void mips_malta_init(QEMUMachineInitArgs *args) a neat trick which allows bi-endian firmware. */ #ifndef TARGET_WORDS_BIGENDIAN { - uint32_t *addr = memory_region_get_ram_ptr(bios); - uint32_t *end = addr + bios_size; + uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS); + if (!addr) { + addr = memory_region_get_ram_ptr(bios); + } + end = (void *)addr + MIN(bios_size, 0x3e0000); while (addr < end) { bswap32s(addr); addr++; @@ -927,14 +1037,23 @@ void mips_malta_init(QEMUMachineInitArgs *args) #endif } - /* Map the BIOS at a 2nd physical location, as on the real board. */ - memory_region_init_alias(bios_alias, NULL, "bios.1fc", bios, 0, BIOS_SIZE); - memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias); + /* + * Map the BIOS at a 2nd physical location, as on the real board. + * Copy it so that we can patch in the MIPS revision, which cannot be + * handled by an overlapping region as the resulting ROM code subpage + * regions are not executable. + */ + memory_region_init_ram(bios_copy, NULL, "bios.1fc", BIOS_SIZE); + if (!rom_copy(memory_region_get_ram_ptr(bios_copy), + FLASH_ADDRESS, BIOS_SIZE)) { + memcpy(memory_region_get_ram_ptr(bios_copy), + memory_region_get_ram_ptr(bios), BIOS_SIZE); + } + memory_region_set_readonly(bios_copy, true); + memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_copy); - /* Board ID = 0x420 (Malta Board with CoreLV) - XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should - map to the board ID. */ - stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420); + /* Board ID = 0x420 (Malta Board with CoreLV) */ + stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420); /* Init internal devices */ cpu_mips_irq_init_cpu(env); @@ -966,8 +1085,8 @@ void mips_malta_init(QEMUMachineInitArgs *args) pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci"); smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(NULL, 9), NULL, 0, NULL); - /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_init(smbus, 8, NULL, 0); + smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); + g_free(smbus_eeprom_buf); pit = pit_init(isa_bus, 0x40, 0, NULL); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); @@ -1005,7 +1124,7 @@ static void mips_malta_class_init(ObjectClass *klass, void *data) } static const TypeInfo mips_malta_device = { - .name = "mips-malta", + .name = TYPE_MIPS_MALTA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MaltaState), .class_init = mips_malta_class_init, diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c index a10cf13a92..297f01e268 100644 --- a/hw/mips/mips_mipssim.c +++ b/hw/mips/mips_mipssim.c @@ -37,6 +37,7 @@ #include "elf.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" +#include "qemu/error-report.h" static struct _loaderparams { int ram_size; @@ -83,7 +84,7 @@ static int64_t load_kernel(void) if (loaderparams.initrd_filename) { initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > loaderparams.ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", @@ -140,6 +141,7 @@ mips_mipssim_init(QEMUMachineInitArgs *args) const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *isa = g_new(MemoryRegion, 1); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); MIPSCPU *cpu; @@ -190,9 +192,8 @@ mips_mipssim_init(QEMUMachineInitArgs *args) } if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { /* Bail out if we have neither a kernel image nor boot vector code. */ - fprintf(stderr, - "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", - filename); + error_report("Could not load MIPS bios '%s', and no " + "-kernel argument was specified", filename); exit(1); } else { /* We have a boot vector start address. */ @@ -212,7 +213,9 @@ mips_mipssim_init(QEMUMachineInitArgs *args) cpu_mips_clock_init(env); /* Register 64 KB of ISA IO space at 0x1fd00000. */ - isa_mmio_init(0x1fd00000, 0x00010000); + memory_region_init_alias(isa, NULL, "isa_mmio", + get_system_io(), 0, 0x00010000); + memory_region_add_subregion(get_system_memory(), 0x1fd00000, isa); /* A single 16450 sits at offset 0x3f8. It is attached to MIPS CPU INT2, which is interrupt 4. */ diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 22beb0a67c..044f232de0 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -26,6 +26,7 @@ #include "hw/timer/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" +#include "sysemu/qtest.h" #define MAX_IDE_BUS 2 @@ -102,7 +103,7 @@ static int64_t load_kernel(void) if (loaderparams.initrd_filename) { initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", @@ -164,6 +165,7 @@ void mips_r4k_init(QEMUMachineInitArgs *args) MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios; MemoryRegion *iomem = g_new(MemoryRegion, 1); + MemoryRegion *isa = g_new(MemoryRegion, 1); int bios_size; MIPSCPU *cpu; CPUMIPSState *env; @@ -243,8 +245,7 @@ void mips_r4k_init(QEMUMachineInitArgs *args) 4, 0, 0, 0, 0, be)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); } - } - else { + } else if (!qtest_enabled()) { /* not fatal */ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", bios_name); @@ -273,7 +274,10 @@ void mips_r4k_init(QEMUMachineInitArgs *args) rtc_init(isa_bus, 2000, NULL); /* Register 64 KB of ISA IO space at 0x14000000 */ - isa_mmio_init(0x14000000, 0x00010000); + memory_region_init_alias(isa, NULL, "isa_mmio", + get_system_io(), 0, 0x00010000); + memory_region_add_subregion(get_system_memory(), 0x14000000, isa); + isa_mem_base = 0x10000000; pit = pit_init(isa_bus, 0x40, 0, NULL); diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index bfafa518e1..1e8d183e7f 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -263,6 +263,7 @@ static void qdev_applesmc_class_init(ObjectClass *klass, void *data) dc->realize = applesmc_isa_realize; dc->reset = qdev_applesmc_isa_reset; dc->props = applesmc_isa_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo applesmc_isa_info = { diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c index 3d6acee695..8e192cdf83 100644 --- a/hw/misc/arm_l2x0.c +++ b/hw/misc/arm_l2x0.c @@ -23,8 +23,12 @@ /* L2C-310 r3p2 */ #define CACHE_ID 0x410000c8 -typedef struct l2x0_state { - SysBusDevice busdev; +#define TYPE_ARM_L2X0 "l2x0" +#define ARM_L2X0(obj) OBJECT_CHECK(L2x0State, (obj), TYPE_ARM_L2X0) + +typedef struct L2x0State { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t cache_type; uint32_t ctrl; @@ -33,19 +37,19 @@ typedef struct l2x0_state { uint32_t tag_ctrl; uint32_t filter_start; uint32_t filter_end; -} l2x0_state; +} L2x0State; static const VMStateDescription vmstate_l2x0 = { .name = "l2x0", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(ctrl, l2x0_state), - VMSTATE_UINT32(aux_ctrl, l2x0_state), - VMSTATE_UINT32(data_ctrl, l2x0_state), - VMSTATE_UINT32(tag_ctrl, l2x0_state), - VMSTATE_UINT32(filter_start, l2x0_state), - VMSTATE_UINT32(filter_end, l2x0_state), + VMSTATE_UINT32(ctrl, L2x0State), + VMSTATE_UINT32(aux_ctrl, L2x0State), + VMSTATE_UINT32(data_ctrl, L2x0State), + VMSTATE_UINT32(tag_ctrl, L2x0State), + VMSTATE_UINT32(filter_start, L2x0State), + VMSTATE_UINT32(filter_end, L2x0State), VMSTATE_END_OF_LIST() } }; @@ -55,7 +59,7 @@ static uint64_t l2x0_priv_read(void *opaque, hwaddr offset, unsigned size) { uint32_t cache_data; - l2x0_state *s = (l2x0_state *)opaque; + L2x0State *s = (L2x0State *)opaque; offset &= 0xfff; if (offset >= 0x730 && offset < 0x800) { return 0; /* cache ops complete */ @@ -97,7 +101,7 @@ static uint64_t l2x0_priv_read(void *opaque, hwaddr offset, static void l2x0_priv_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - l2x0_state *s = (l2x0_state *)opaque; + L2x0State *s = (L2x0State *)opaque; offset &= 0xfff; if (offset >= 0x730 && offset < 0x800) { /* ignore */ @@ -137,7 +141,7 @@ static void l2x0_priv_write(void *opaque, hwaddr offset, static void l2x0_priv_reset(DeviceState *dev) { - l2x0_state *s = DO_UPCAST(l2x0_state, busdev.qdev, dev); + L2x0State *s = ARM_L2X0(dev); s->ctrl = 0; s->aux_ctrl = 0x02020000; @@ -155,7 +159,7 @@ static const MemoryRegionOps l2x0_mem_ops = { static int l2x0_priv_init(SysBusDevice *dev) { - l2x0_state *s = FROM_SYSBUS(l2x0_state, dev); + L2x0State *s = ARM_L2X0(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &l2x0_mem_ops, s, "l2x0_cc", 0x1000); @@ -164,7 +168,7 @@ static int l2x0_priv_init(SysBusDevice *dev) } static Property l2x0_properties[] = { - DEFINE_PROP_UINT32("cache-type", l2x0_state, cache_type, 0x1c100100), + DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100), DEFINE_PROP_END_OF_LIST(), }; @@ -181,9 +185,9 @@ static void l2x0_class_init(ObjectClass *klass, void *data) } static const TypeInfo l2x0_info = { - .name = "l2x0", + .name = TYPE_ARM_L2X0, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(l2x0_state), + .instance_size = sizeof(L2x0State), .class_init = l2x0_class_init, }; diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index 5906ae5869..0fc26d29a5 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -16,8 +16,13 @@ #define LOCK_VALUE 0xa05f +#define TYPE_ARM_SYSCTL "realview_sysctl" +#define ARM_SYSCTL(obj) \ + OBJECT_CHECK(arm_sysctl_state, (obj), TYPE_ARM_SYSCTL) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq pl110_mux_ctrl; @@ -85,7 +90,7 @@ static int board_id(arm_sysctl_state *s) static void arm_sysctl_reset(DeviceState *d) { - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + arm_sysctl_state *s = ARM_SYSCTL(d); int i; s->leds = 0; @@ -165,7 +170,7 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, case 0x58: /* BOOTCS */ return 0; case 0x5c: /* 24MHz */ - return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec()); + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24000000, get_ticks_per_sec()); case 0x60: /* MISC */ return 0; case 0x84: /* PROCID0 */ @@ -587,7 +592,7 @@ static void arm_sysctl_init(Object *obj) { DeviceState *dev = DEVICE(obj); SysBusDevice *sd = SYS_BUS_DEVICE(obj); - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd); + arm_sysctl_state *s = ARM_SYSCTL(obj); memory_region_init_io(&s->iomem, OBJECT(dev), &arm_sysctl_ops, s, "arm-sysctl", 0x1000); @@ -598,14 +603,15 @@ static void arm_sysctl_init(Object *obj) static void arm_sysctl_realize(DeviceState *d, Error **errp) { - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + arm_sysctl_state *s = ARM_SYSCTL(d); + s->db_clock = g_new0(uint32_t, s->db_num_clocks); } static void arm_sysctl_finalize(Object *obj) { - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); + arm_sysctl_state *s = ARM_SYSCTL(obj); + g_free(s->db_voltage); g_free(s->db_clock); g_free(s->db_clock_reset); @@ -634,7 +640,7 @@ static void arm_sysctl_class_init(ObjectClass *klass, void *data) } static const TypeInfo arm_sysctl_info = { - .name = "realview_sysctl", + .name = TYPE_ARM_SYSCTL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_sysctl_state), .instance_init = arm_sysctl_init, diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c index d754cf1f2e..9db5680015 100644 --- a/hw/misc/debugexit.c +++ b/hw/misc/debugexit.c @@ -58,6 +58,7 @@ static void debug_exit_class_initfn(ObjectClass *klass, void *data) dc->realize = debug_exit_realizefn; dc->props = debug_exit_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo debug_exit_info = { diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c index 3de9675f64..96a69d4e5c 100644 --- a/hw/misc/eccmemctl.c +++ b/hw/misc/eccmemctl.c @@ -120,8 +120,12 @@ #define ECC_DIAG_SIZE 4 #define ECC_DIAG_MASK (ECC_DIAG_SIZE - 1) +#define TYPE_ECC_MEMCTL "eccmemctl" +#define ECC_MEMCTL(obj) OBJECT_CHECK(ECCState, (obj), TYPE_ECC_MEMCTL) + typedef struct ECCState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem, iomem_diag; qemu_irq irq; uint32_t regs[ECC_NREGS]; @@ -273,13 +277,14 @@ static const VMStateDescription vmstate_ecc = { static void ecc_reset(DeviceState *d) { - ECCState *s = container_of(d, ECCState, busdev.qdev); + ECCState *s = ECC_MEMCTL(d); - if (s->version == ECC_MCC) + if (s->version == ECC_MCC) { s->regs[ECC_MER] &= ECC_MER_REU; - else + } else { s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR | ECC_MER_DCI); + } s->regs[ECC_MDR] = 0x20; s->regs[ECC_MFSR] = 0; s->regs[ECC_VCR] = 0; @@ -292,7 +297,7 @@ static void ecc_reset(DeviceState *d) static int ecc_init1(SysBusDevice *dev) { - ECCState *s = FROM_SYSBUS(ECCState, dev); + ECCState *s = ECC_MEMCTL(dev); sysbus_init_irq(dev, &s->irq); s->regs[0] = s->version; @@ -325,7 +330,7 @@ static void ecc_class_init(ObjectClass *klass, void *data) } static const TypeInfo ecc_info = { - .name = "eccmemctl", + .name = TYPE_ECC_MEMCTL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ECCState), .class_init = ecc_class_init, diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index 28395bae4b..cbf0795c0a 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -386,8 +386,13 @@ static const Exynos4210PmuReg exynos4210_pmu_regs[] = { #define PMU_NUM_OF_REGISTERS \ (sizeof(exynos4210_pmu_regs) / sizeof(Exynos4210PmuReg)) +#define TYPE_EXYNOS4210_PMU "exynos4210.pmu" +#define EXYNOS4210_PMU(obj) \ + OBJECT_CHECK(Exynos4210PmuState, (obj), TYPE_EXYNOS4210_PMU) + typedef struct Exynos4210PmuState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t reg[PMU_NUM_OF_REGISTERS]; } Exynos4210PmuState; @@ -443,8 +448,7 @@ static const MemoryRegionOps exynos4210_pmu_ops = { static void exynos4210_pmu_reset(DeviceState *dev) { - Exynos4210PmuState *s = - container_of(dev, Exynos4210PmuState, busdev.qdev); + Exynos4210PmuState *s = EXYNOS4210_PMU(dev); unsigned i; /* Set default values for registers */ @@ -455,7 +459,7 @@ static void exynos4210_pmu_reset(DeviceState *dev) static int exynos4210_pmu_init(SysBusDevice *dev) { - Exynos4210PmuState *s = FROM_SYSBUS(Exynos4210PmuState, dev); + Exynos4210PmuState *s = EXYNOS4210_PMU(dev); /* memory mapping */ memory_region_init_io(&s->iomem, OBJECT(dev), &exynos4210_pmu_ops, s, @@ -485,7 +489,7 @@ static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_pmu_info = { - .name = "exynos4210.pmu", + .name = TYPE_EXYNOS4210_PMU, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PmuState), .class_init = exynos4210_pmu_class_init, diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 816d5e8331..63e33a41da 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -29,8 +29,12 @@ do { printf("imx_ccm: " fmt , ##args); } while (0) static int imx_ccm_post_load(void *opaque, int version_id); -typedef struct { - SysBusDevice busdev; +#define TYPE_IMX_CCM "imx_ccm" +#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM) + +typedef struct IMXCCMState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t ccmr; @@ -108,7 +112,7 @@ static const VMStateDescription vmstate_imx_ccm = { uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock) { - IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev); + IMXCCMState *s = IMX_CCM(dev); switch (clock) { case NOCLK: @@ -178,7 +182,7 @@ static void update_clocks(IMXCCMState *s) static void imx_ccm_reset(DeviceState *dev) { - IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev); + IMXCCMState *s = IMX_CCM(dev); s->ccmr = 0x074b0b7b; s->pdr0 = 0xff870b48; @@ -279,7 +283,7 @@ static const struct MemoryRegionOps imx_ccm_ops = { static int imx_ccm_init(SysBusDevice *dev) { - IMXCCMState *s = FROM_SYSBUS(typeof(*s), dev); + IMXCCMState *s = IMX_CCM(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s, "imx_ccm", 0x1000); @@ -308,7 +312,7 @@ static void imx_ccm_class_init(ObjectClass *klass, void *data) } static const TypeInfo imx_ccm_info = { - .name = "imx_ccm", + .name = TYPE_IMX_CCM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXCCMState), .class_init = imx_ccm_class_init, diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 4a74856c95..2838866f45 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -821,6 +821,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_MEMORY_RAM; dc->reset = ivshmem_reset; dc->props = ivshmem_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo ivshmem_info = { diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c index 060a5bf9b3..9bdb78162f 100644 --- a/hw/misc/lm32_sys.c +++ b/hw/misc/lm32_sys.c @@ -44,8 +44,12 @@ enum { #define MAX_TESTNAME_LEN 16 +#define TYPE_LM32_SYS "lm32-sys" +#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS) + struct LM32SysState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t base; uint32_t regs[R_MAX]; @@ -104,7 +108,7 @@ static const MemoryRegionOps sys_ops = { static void sys_reset(DeviceState *d) { - LM32SysState *s = container_of(d, LM32SysState, busdev.qdev); + LM32SysState *s = LM32_SYS(d); int i; for (i = 0; i < R_MAX; i++) { @@ -115,7 +119,7 @@ static void sys_reset(DeviceState *d) static int lm32_sys_init(SysBusDevice *dev) { - LM32SysState *s = FROM_SYSBUS(typeof(*s), dev); + LM32SysState *s = LM32_SYS(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &sys_ops , s, "sys", R_MAX * 4); @@ -158,7 +162,7 @@ static void lm32_sys_class_init(ObjectClass *klass, void *data) } static const TypeInfo lm32_sys_info = { - .name = "lm32-sys", + .name = TYPE_LM32_SYS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32SysState), .class_init = lm32_sys_class_init, diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index c0fd7da118..c811b9519b 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -128,7 +128,7 @@ static unsigned int get_counter(CUDATimer *s) int64_t d; unsigned int counter; - d = muldiv64(qemu_get_clock_ns(vm_clock) - s->load_time, + d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->load_time, CUDA_TIMER_FREQ, get_ticks_per_sec()); if (s->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ @@ -147,7 +147,7 @@ static unsigned int get_counter(CUDATimer *s) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val); - ti->load_time = qemu_get_clock_ns(vm_clock); + ti->load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ti->counter_value = val; cuda_timer_update(s, ti, ti->load_time); } @@ -191,10 +191,10 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti, if (!ti->timer) return; if ((s->acr & T1MODE) != T1MODE_CONT) { - qemu_del_timer(ti->timer); + timer_del(ti->timer); } else { ti->next_irq_time = get_next_irq_time(ti, current_time); - qemu_mod_timer(ti->timer, ti->next_irq_time); + timer_mod(ti->timer, ti->next_irq_time); } } @@ -304,7 +304,7 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) break; case 4: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; - cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock)); + cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; case 5: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); @@ -313,12 +313,12 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) break; case 6: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; - cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock)); + cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; case 7: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); s->ifr &= ~T1_INT; - cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock)); + cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; case 8: s->timers[1].latch = val; @@ -332,7 +332,7 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) break; case 11: s->acr = val; - cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock)); + cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); cuda_update(s); break; case 12: @@ -463,8 +463,8 @@ static void cuda_adb_poll(void *opaque) obuf[1] = 0x40; /* polled data */ cuda_send_packet_to_host(s, obuf, olen + 2); } - qemu_mod_timer(s->adb_poll_timer, - qemu_get_clock_ns(vm_clock) + + timer_mod(s->adb_poll_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ)); } @@ -481,11 +481,11 @@ static void cuda_receive_packet(CUDAState *s, if (autopoll != s->autopoll) { s->autopoll = autopoll; if (autopoll) { - qemu_mod_timer(s->adb_poll_timer, - qemu_get_clock_ns(vm_clock) + + timer_mod(s->adb_poll_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ)); } else { - qemu_del_timer(s->adb_poll_timer); + timer_del(s->adb_poll_timer); } } obuf[0] = CUDA_PACKET; @@ -494,14 +494,14 @@ static void cuda_receive_packet(CUDAState *s, break; case CUDA_SET_TIME: ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4]; - s->tick_offset = ti - (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec()); + s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec()); obuf[0] = CUDA_PACKET; obuf[1] = 0; obuf[2] = 0; cuda_send_packet_to_host(s, obuf, 3); break; case CUDA_GET_TIME: - ti = s->tick_offset + (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec()); + ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec()); obuf[0] = CUDA_PACKET; obuf[1] = 0; obuf[2] = 0; @@ -689,12 +689,12 @@ static void cuda_realizefn(DeviceState *dev, Error **errp) CUDAState *s = CUDA(dev); struct tm tm; - s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s); + s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s); qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; - s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s); + s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s); } static void cuda_initfn(Object *obj) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index c0d0bf7287..9cc33d8f96 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -245,10 +245,10 @@ static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) switch (addr) { case 0x38: - value = qemu_get_clock_ns(vm_clock); + value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); break; case 0x3c: - value = qemu_get_clock_ns(vm_clock) >> 32; + value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 32; break; } diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c index a498881190..aef135e572 100644 --- a/hw/misc/milkymist-hpdmc.c +++ b/hw/misc/milkymist-hpdmc.c @@ -40,8 +40,13 @@ enum { IODELAY_PLL2_LOCKED = (1<<7), }; +#define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc" +#define MILKYMIST_HPDMC(obj) \ + OBJECT_CHECK(MilkymistHpdmcState, (obj), TYPE_MILKYMIST_HPDMC) + struct MilkymistHpdmcState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; uint32_t regs[R_MAX]; @@ -111,7 +116,7 @@ static const MemoryRegionOps hpdmc_mmio_ops = { static void milkymist_hpdmc_reset(DeviceState *d) { - MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev); + MilkymistHpdmcState *s = MILKYMIST_HPDMC(d); int i; for (i = 0; i < R_MAX; i++) { @@ -125,7 +130,7 @@ static void milkymist_hpdmc_reset(DeviceState *d) static int milkymist_hpdmc_init(SysBusDevice *dev) { - MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev); memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s, "milkymist-hpdmc", R_MAX * 4); @@ -156,7 +161,7 @@ static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_hpdmc_info = { - .name = "milkymist-hpdmc", + .name = TYPE_MILKYMIST_HPDMC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistHpdmcState), .class_init = milkymist_hpdmc_class_init, diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c index 2b64ee77d8..b3b2143d51 100644 --- a/hw/misc/milkymist-pfpu.c +++ b/hw/misc/milkymist-pfpu.c @@ -116,8 +116,13 @@ static const char *opcode_to_str[] = { }; #endif +#define TYPE_MILKYMIST_PFPU "milkymist-pfpu" +#define MILKYMIST_PFPU(obj) \ + OBJECT_CHECK(MilkymistPFPUState, (obj), TYPE_MILKYMIST_PFPU) + struct MilkymistPFPUState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; CharDriverState *chr; qemu_irq irq; @@ -473,7 +478,7 @@ static const MemoryRegionOps pfpu_mmio_ops = { static void milkymist_pfpu_reset(DeviceState *d) { - MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev); + MilkymistPFPUState *s = MILKYMIST_PFPU(d); int i; for (i = 0; i < R_MAX; i++) { @@ -493,7 +498,7 @@ static void milkymist_pfpu_reset(DeviceState *d) static int milkymist_pfpu_init(SysBusDevice *dev) { - MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistPFPUState *s = MILKYMIST_PFPU(dev); sysbus_init_irq(dev, &s->irq); @@ -530,7 +535,7 @@ static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_pfpu_info = { - .name = "milkymist-pfpu", + .name = TYPE_MILKYMIST_PFPU, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistPFPUState), .class_init = milkymist_pfpu_class_init, diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c index 604be5eafe..c96810fec1 100644 --- a/hw/misc/mst_fpga.c +++ b/hw/misc/mst_fpga.c @@ -35,25 +35,30 @@ #define MST_PCMCIA_CD0_IRQ 9 #define MST_PCMCIA_CD1_IRQ 13 +#define TYPE_MAINSTONE_FPGA "mainstone-fpga" +#define MAINSTONE_FPGA(obj) \ + OBJECT_CHECK(mst_irq_state, (obj), TYPE_MAINSTONE_FPGA) + typedef struct mst_irq_state{ - SysBusDevice busdev; - MemoryRegion iomem; - - qemu_irq parent; - - uint32_t prev_level; - uint32_t leddat1; - uint32_t leddat2; - uint32_t ledctrl; - uint32_t gpswr; - uint32_t mscwr1; - uint32_t mscwr2; - uint32_t mscwr3; - uint32_t mscrd; - uint32_t intmskena; - uint32_t intsetclr; - uint32_t pcmcia0; - uint32_t pcmcia1; + SysBusDevice parent_obj; + + MemoryRegion iomem; + + qemu_irq parent; + + uint32_t prev_level; + uint32_t leddat1; + uint32_t leddat2; + uint32_t ledctrl; + uint32_t gpswr; + uint32_t mscwr1; + uint32_t mscwr2; + uint32_t mscwr3; + uint32_t mscrd; + uint32_t intmskena; + uint32_t intsetclr; + uint32_t pcmcia0; + uint32_t pcmcia1; }mst_irq_state; static void @@ -194,24 +199,23 @@ static int mst_fpga_post_load(void *opaque, int version_id) return 0; } -static int mst_fpga_init(SysBusDevice *dev) +static int mst_fpga_init(SysBusDevice *sbd) { - mst_irq_state *s; - - s = FROM_SYSBUS(mst_irq_state, dev); + DeviceState *dev = DEVICE(sbd); + mst_irq_state *s = MAINSTONE_FPGA(dev); - s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; - s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; + s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; + s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; - sysbus_init_irq(dev, &s->parent); + sysbus_init_irq(sbd, &s->parent); - /* alloc the external 16 irqs */ - qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS); + /* alloc the external 16 irqs */ + qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS); - memory_region_init_io(&s->iomem, OBJECT(s), &mst_fpga_ops, s, - "fpga", 0x00100000); - sysbus_init_mmio(dev, &s->iomem); - return 0; + memory_region_init_io(&s->iomem, OBJECT(s), &mst_fpga_ops, s, + "fpga", 0x00100000); + sysbus_init_mmio(sbd, &s->iomem); + return 0; } static VMStateDescription vmstate_mst_fpga_regs = { @@ -249,7 +253,7 @@ static void mst_fpga_class_init(ObjectClass *klass, void *data) } static const TypeInfo mst_fpga_info = { - .name = "mainstone-fpga", + .name = TYPE_MAINSTONE_FPGA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mst_irq_state), .class_init = mst_fpga_class_init, diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c index 699a16ffbe..18e94e07b1 100644 --- a/hw/misc/pc-testdev.c +++ b/hw/misc/pc-testdev.c @@ -49,6 +49,7 @@ typedef struct PCTestdev { ISADevice parent_obj; MemoryRegion ioport; + MemoryRegion ioport_byte; MemoryRegion flush; MemoryRegion irq; MemoryRegion iomem; @@ -80,13 +81,20 @@ static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, unsigned len) { PCTestdev *dev = opaque; - dev->ioport_data = data; + int bits = len * 8; + int start_bit = (addr & 3) * 8; + uint32_t mask = ((uint32_t)-1 >> (32 - bits)) << start_bit; + dev->ioport_data &= ~mask; + dev->ioport_data |= data << start_bit; } static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) { PCTestdev *dev = opaque; - return dev->ioport_data; + int bits = len * 8; + int start_bit = (addr & 3) * 8; + uint32_t mask = ((uint32_t)-1 >> (32 - bits)) << start_bit; + return (dev->ioport_data & mask) >> start_bit; } static const MemoryRegionOps test_ioport_ops = { @@ -95,6 +103,16 @@ static const MemoryRegionOps test_ioport_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static const MemoryRegionOps test_ioport_byte_ops = { + .read = test_ioport_read, + .write = test_ioport_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, unsigned len) { @@ -122,7 +140,6 @@ static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) PCTestdev *dev = opaque; uint64_t ret = 0; memcpy(&ret, &dev->iomem_buf[addr], len); - ret = le64_to_cpu(ret); return ret; } @@ -131,7 +148,6 @@ static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { PCTestdev *dev = opaque; - val = cpu_to_le64(val); memcpy(&dev->iomem_buf[addr], &val, len); dev->iomem_buf[addr] = val; } @@ -151,6 +167,9 @@ static void testdev_realizefn(DeviceState *d, Error **errp) memory_region_init_io(&dev->ioport, OBJECT(dev), &test_ioport_ops, dev, "pc-testdev-ioport", 4); + memory_region_init_io(&dev->ioport_byte, OBJECT(dev), + &test_ioport_byte_ops, dev, + "pc-testdev-ioport-byte", 4); memory_region_init_io(&dev->flush, OBJECT(dev), &test_flush_ops, dev, "pc-testdev-flush-page", 4); memory_region_init_io(&dev->irq, OBJECT(dev), &test_irq_ops, dev, @@ -160,6 +179,7 @@ static void testdev_realizefn(DeviceState *d, Error **errp) memory_region_add_subregion(io, 0xe0, &dev->ioport); memory_region_add_subregion(io, 0xe4, &dev->flush); + memory_region_add_subregion(io, 0xe8, &dev->ioport_byte); memory_region_add_subregion(io, 0x2000, &dev->irq); memory_region_add_subregion(mem, 0xff000000, &dev->iomem); } @@ -168,6 +188,7 @@ static void testdev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->realize = testdev_realizefn; } diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index d69ff3364d..ca53b3f500 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -315,6 +315,7 @@ static void pci_testdev_class_init(ObjectClass *klass, void *data) k->revision = 0x00; k->class_id = PCI_CLASS_OTHERS; dc->desc = "PCI Test Device"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->reset = qdev_pci_testdev_reset; } diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c index 5592560014..37f23695d8 100644 --- a/hw/misc/puv3_pm.c +++ b/hw/misc/puv3_pm.c @@ -14,8 +14,12 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" -typedef struct { - SysBusDevice busdev; +#define TYPE_PUV3_PM "puv3_pm" +#define PUV3_PM(obj) OBJECT_CHECK(PUV3PMState, (obj), TYPE_PUV3_PM) + +typedef struct PUV3PMState { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t reg_PMCR; @@ -116,7 +120,7 @@ static const MemoryRegionOps puv3_pm_ops = { static int puv3_pm_init(SysBusDevice *dev) { - PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev); + PUV3PMState *s = PUV3_PM(dev); s->reg_PCGR = 0x0; @@ -135,7 +139,7 @@ static void puv3_pm_class_init(ObjectClass *klass, void *data) } static const TypeInfo puv3_pm_info = { - .name = "puv3_pm", + .name = TYPE_PUV3_PM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PUV3PMState), .class_init = puv3_pm_class_init, diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 7bb49a574f..b64e3bb7b4 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -97,29 +97,24 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp) { ISADevice *d = ISA_DEVICE(dev); PVPanicState *s = ISA_PVPANIC_DEVICE(dev); + FWCfgState *fw_cfg = fw_cfg_find(); + uint16_t *pvpanic_port; - isa_register_ioport(d, &s->io, s->ioport); -} + if (!fw_cfg) { + return; + } -static void pvpanic_fw_cfg(ISADevice *dev, FWCfgState *fw_cfg) -{ - PVPanicState *s = ISA_PVPANIC_DEVICE(dev); - uint16_t *pvpanic_port = g_malloc(sizeof(*pvpanic_port)); + pvpanic_port = g_malloc(sizeof(*pvpanic_port)); *pvpanic_port = cpu_to_le16(s->ioport); - fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port, sizeof(*pvpanic_port)); + + isa_register_ioport(d, &s->io, s->ioport); } void pvpanic_init(ISABus *bus) { - ISADevice *dev; - FWCfgState *fw_cfg = fw_cfg_find(); - if (!fw_cfg) { - return; - } - dev = isa_create_simple (bus, TYPE_ISA_PVPANIC_DEVICE); - pvpanic_fw_cfg(dev, fw_cfg); + isa_create_simple(bus, TYPE_ISA_PVPANIC_DEVICE); } static Property pvpanic_isa_properties[] = { @@ -132,8 +127,8 @@ static void pvpanic_isa_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = pvpanic_isa_realizefn; - dc->no_user = 1; dc->props = pvpanic_isa_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static TypeInfo pvpanic_isa_info = { diff --git a/hw/misc/sga.c b/hw/misc/sga.c index 08803e7ddc..83d2fd9d3d 100644 --- a/hw/misc/sga.c +++ b/hw/misc/sga.c @@ -47,6 +47,7 @@ static void sga_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->realize = sga_realizefn; dc->desc = "Serial Graphics Adapter"; } diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c index 00d9542c0b..767544eca1 100644 --- a/hw/misc/slavio_misc.c +++ b/hw/misc/slavio_misc.c @@ -34,8 +34,12 @@ * This also includes the PMC CPU idle controller. */ +#define TYPE_SLAVIO_MISC "slavio_misc" +#define SLAVIO_MISC(obj) OBJECT_CHECK(MiscState, (obj), TYPE_SLAVIO_MISC) + typedef struct MiscState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion cfg_iomem; MemoryRegion diag_iomem; MemoryRegion mdm_iomem; @@ -53,8 +57,12 @@ typedef struct MiscState { uint16_t leds; } MiscState; +#define TYPE_APC "apc" +#define APC(obj) OBJECT_CHECK(APCState, (obj), TYPE_APC) + typedef struct APCState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq cpu_halt; } APCState; @@ -88,7 +96,7 @@ static void slavio_misc_update_irq(void *opaque) static void slavio_misc_reset(DeviceState *d) { - MiscState *s = container_of(d, MiscState, busdev.qdev); + MiscState *s = SLAVIO_MISC(d); // Diagnostic and system control registers not cleared in reset s->config = s->aux1 = s->aux2 = s->mctrl = 0; @@ -407,7 +415,7 @@ static const VMStateDescription vmstate_misc = { static int apc_init1(SysBusDevice *dev) { - APCState *s = FROM_SYSBUS(APCState, dev); + APCState *s = APC(dev); sysbus_init_irq(dev, &s->cpu_halt); @@ -418,52 +426,53 @@ static int apc_init1(SysBusDevice *dev) return 0; } -static int slavio_misc_init1(SysBusDevice *dev) +static int slavio_misc_init1(SysBusDevice *sbd) { - MiscState *s = FROM_SYSBUS(MiscState, dev); + DeviceState *dev = DEVICE(sbd); + MiscState *s = SLAVIO_MISC(dev); - sysbus_init_irq(dev, &s->irq); - sysbus_init_irq(dev, &s->fdc_tc); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->fdc_tc); /* 8 bit registers */ /* Slavio control */ memory_region_init_io(&s->cfg_iomem, OBJECT(s), &slavio_cfg_mem_ops, s, "configuration", MISC_SIZE); - sysbus_init_mmio(dev, &s->cfg_iomem); + sysbus_init_mmio(sbd, &s->cfg_iomem); /* Diagnostics */ memory_region_init_io(&s->diag_iomem, OBJECT(s), &slavio_diag_mem_ops, s, "diagnostic", MISC_SIZE); - sysbus_init_mmio(dev, &s->diag_iomem); + sysbus_init_mmio(sbd, &s->diag_iomem); /* Modem control */ memory_region_init_io(&s->mdm_iomem, OBJECT(s), &slavio_mdm_mem_ops, s, "modem", MISC_SIZE); - sysbus_init_mmio(dev, &s->mdm_iomem); + sysbus_init_mmio(sbd, &s->mdm_iomem); /* 16 bit registers */ /* ss600mp diag LEDs */ memory_region_init_io(&s->led_iomem, OBJECT(s), &slavio_led_mem_ops, s, "leds", MISC_SIZE); - sysbus_init_mmio(dev, &s->led_iomem); + sysbus_init_mmio(sbd, &s->led_iomem); /* 32 bit registers */ /* System control */ memory_region_init_io(&s->sysctrl_iomem, OBJECT(s), &slavio_sysctrl_mem_ops, s, "system-control", MISC_SIZE); - sysbus_init_mmio(dev, &s->sysctrl_iomem); + sysbus_init_mmio(sbd, &s->sysctrl_iomem); /* AUX 1 (Misc System Functions) */ memory_region_init_io(&s->aux1_iomem, OBJECT(s), &slavio_aux1_mem_ops, s, "misc-system-functions", MISC_SIZE); - sysbus_init_mmio(dev, &s->aux1_iomem); + sysbus_init_mmio(sbd, &s->aux1_iomem); /* AUX 2 (Software Powerdown Control) */ memory_region_init_io(&s->aux2_iomem, OBJECT(s), &slavio_aux2_mem_ops, s, "software-powerdown-control", MISC_SIZE); - sysbus_init_mmio(dev, &s->aux2_iomem); + sysbus_init_mmio(sbd, &s->aux2_iomem); - qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1); + qdev_init_gpio_in(dev, slavio_set_power_fail, 1); return 0; } @@ -479,7 +488,7 @@ static void slavio_misc_class_init(ObjectClass *klass, void *data) } static const TypeInfo slavio_misc_info = { - .name = "slavio_misc", + .name = TYPE_SLAVIO_MISC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MiscState), .class_init = slavio_misc_class_init, @@ -493,7 +502,7 @@ static void apc_class_init(ObjectClass *klass, void *data) } static const TypeInfo apc_info = { - .name = "apc", + .name = TYPE_APC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MiscState), .class_init = apc_class_init, diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index 54af34a707..a1c08fb74e 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -276,8 +276,8 @@ static void vfio_intx_mmap_enable(void *opaque) VFIODevice *vdev = opaque; if (vdev->intx.pending) { - qemu_mod_timer(vdev->intx.mmap_timer, - qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout); + timer_mod(vdev->intx.mmap_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vdev->intx.mmap_timeout); return; } @@ -300,8 +300,8 @@ static void vfio_intx_interrupt(void *opaque) qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 1); vfio_mmap_set_enabled(vdev, false); if (vdev->intx.mmap_timeout) { - qemu_mod_timer(vdev->intx.mmap_timer, - qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout); + timer_mod(vdev->intx.mmap_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vdev->intx.mmap_timeout); } } @@ -543,7 +543,7 @@ static void vfio_disable_intx(VFIODevice *vdev) { int fd; - qemu_del_timer(vdev->intx.mmap_timer); + timer_del(vdev->intx.mmap_timer); vfio_disable_intx_kvm(vdev); vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; @@ -3176,7 +3176,7 @@ static int vfio_initfn(PCIDevice *pdev) } if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { - vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock, + vdev->intx.mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, vfio_intx_mmap_enable, vdev); pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_update_irq); ret = vfio_enable_intx(vdev); @@ -3210,7 +3210,7 @@ static void vfio_exitfn(PCIDevice *pdev) pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); vfio_disable_interrupts(vdev); if (vdev->intx.mmap_timer) { - qemu_free_timer(vdev->intx.mmap_timer); + timer_free(vdev->intx.mmap_timer); } vfio_teardown_msi(vdev); vfio_unmap_bars(vdev); @@ -3299,6 +3299,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) dc->props = vfio_pci_dev_properties; dc->vmsd = &vfio_pci_vmstate; dc->desc = "VFIO-based PCI device assignment"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); pdc->init = vfio_initfn; pdc->exit = vfio_exitfn; pdc->config_read = vfio_pci_read_config; diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index fc7a85f0dd..e42a5b04ab 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -114,8 +114,12 @@ typedef enum { RESET_MAX } ResetValues; -typedef struct { - SysBusDevice busdev; +#define TYPE_ZYNQ_SLCR "xilinx,zynq_slcr" +#define ZYNQ_SLCR(obj) OBJECT_CHECK(ZynqSLCRState, (obj), TYPE_ZYNQ_SLCR) + +typedef struct ZynqSLCRState { + SysBusDevice parent_obj; + MemoryRegion iomem; union { @@ -158,9 +162,8 @@ typedef struct { static void zynq_slcr_reset(DeviceState *d) { + ZynqSLCRState *s = ZYNQ_SLCR(d); int i; - ZynqSLCRState *s = - FROM_SYSBUS(ZynqSLCRState, SYS_BUS_DEVICE(d)); DB_PRINT("RESET\n"); @@ -492,7 +495,7 @@ static const MemoryRegionOps slcr_ops = { static int zynq_slcr_init(SysBusDevice *dev) { - ZynqSLCRState *s = FROM_SYSBUS(ZynqSLCRState, dev); + ZynqSLCRState *s = ZYNQ_SLCR(dev); memory_region_init_io(&s->iomem, OBJECT(s), &slcr_ops, s, "slcr", 0x1000); sysbus_init_mmio(dev, &s->iomem); @@ -523,7 +526,7 @@ static void zynq_slcr_class_init(ObjectClass *klass, void *data) static const TypeInfo zynq_slcr_info = { .class_init = zynq_slcr_class_init, - .name = "xilinx,zynq_slcr", + .name = TYPE_ZYNQ_SLCR, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ZynqSLCRState), }; diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index ac929cba6b..4a355bbbef 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -315,8 +315,12 @@ static inline void rx_desc_set_length(unsigned *desc, unsigned len) desc[1] |= len; } -typedef struct { - SysBusDevice busdev; +#define TYPE_CADENCE_GEM "cadence_gem" +#define GEM(obj) OBJECT_CHECK(GemState, (obj), TYPE_CADENCE_GEM) + +typedef struct GemState { + SysBusDevice parent_obj; + MemoryRegion iomem; NICState *nic; NICConf conf; @@ -945,7 +949,7 @@ static void gem_phy_reset(GemState *s) static void gem_reset(DeviceState *d) { - GemState *s = FROM_SYSBUS(GemState, SYS_BUS_DEVICE(d)); + GemState *s = GEM(d); DB_PRINT("\n"); @@ -1155,22 +1159,22 @@ static NetClientInfo net_gem_info = { .link_status_changed = gem_set_link, }; -static int gem_init(SysBusDevice *dev) +static int gem_init(SysBusDevice *sbd) { - GemState *s; + DeviceState *dev = DEVICE(sbd); + GemState *s = GEM(dev); DB_PRINT("\n"); - s = FROM_SYSBUS(GemState, dev); gem_init_register_masks(s); memory_region_init_io(&s->iomem, OBJECT(s), &gem_ops, s, "enet", sizeof(s->regs)); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_gem_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); return 0; } @@ -1206,10 +1210,10 @@ static void gem_class_init(ObjectClass *klass, void *data) } static const TypeInfo gem_info = { - .class_init = gem_class_init, - .name = "cadence_gem", + .name = TYPE_CADENCE_GEM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GemState), + .class_init = gem_class_init, }; static void gem_register_types(void) diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 049aa704c1..789d385743 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -274,7 +274,7 @@ static void do_read_rra(dp8393xState *s) static void do_software_reset(dp8393xState *s) { - qemu_del_timer(s->watchdog); + timer_del(s->watchdog); s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX); s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS; @@ -286,14 +286,14 @@ static void set_next_tick(dp8393xState *s) int64_t delay; if (s->regs[SONIC_CR] & SONIC_CR_STP) { - qemu_del_timer(s->watchdog); + timer_del(s->watchdog); return; } ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; - s->wt_last_update = qemu_get_clock_ns(vm_clock); + s->wt_last_update = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); delay = get_ticks_per_sec() * ticks / 5000000; - qemu_mod_timer(s->watchdog, s->wt_last_update + delay); + timer_mod(s->watchdog, s->wt_last_update + delay); } static void update_wt_regs(dp8393xState *s) @@ -302,11 +302,11 @@ static void update_wt_regs(dp8393xState *s) uint32_t val; if (s->regs[SONIC_CR] & SONIC_CR_STP) { - qemu_del_timer(s->watchdog); + timer_del(s->watchdog); return; } - elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock); + elapsed = s->wt_last_update - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; val -= elapsed / 5000000; s->regs[SONIC_WT1] = (val >> 16) & 0xffff; @@ -838,7 +838,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) static void nic_reset(void *opaque) { dp8393xState *s = opaque; - qemu_del_timer(s->watchdog); + timer_del(s->watchdog); s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS; s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); @@ -866,8 +866,8 @@ static void nic_cleanup(NetClientState *nc) memory_region_del_subregion(s->address_space, &s->mmio); memory_region_destroy(&s->mmio); - qemu_del_timer(s->watchdog); - qemu_free_timer(s->watchdog); + timer_del(s->watchdog); + timer_free(s->watchdog); g_free(s); } @@ -896,7 +896,7 @@ void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, s->memory_rw = memory_rw; s->it_shift = it_shift; s->irq = irq; - s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s); + s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ s->conf.macaddr = nd->macaddr; diff --git a/hw/net/e1000.c b/hw/net/e1000.c index b952d8d0f3..f5ebed46ab 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -190,7 +190,7 @@ set_phy_ctrl(E1000State *s, int index, uint16_t val) e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; DBGOUT(PHY, "Start link auto negotiation\n"); - qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500); + timer_mod(s->autoneg_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); } } @@ -306,7 +306,7 @@ static void e1000_reset(void *opaque) uint8_t *macaddr = d->conf.macaddr.a; int i; - qemu_del_timer(d->autoneg_timer); + timer_del(d->autoneg_timer); memset(d->phy_reg, 0, sizeof d->phy_reg); memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init); memset(d->mac_reg, 0, sizeof d->mac_reg); @@ -1184,7 +1184,7 @@ static int e1000_post_load(void *opaque, int version_id) s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG && !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { nc->link_down = false; - qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500); + timer_mod(s->autoneg_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); } return 0; @@ -1314,8 +1314,8 @@ pci_e1000_uninit(PCIDevice *dev) { E1000State *d = E1000(dev); - qemu_del_timer(d->autoneg_timer); - qemu_free_timer(d->autoneg_timer); + timer_del(d->autoneg_timer); + timer_free(d->autoneg_timer); memory_region_destroy(&d->mmio); memory_region_destroy(&d->io); qemu_del_nic(d->nic); @@ -1370,7 +1370,7 @@ static int pci_e1000_init(PCIDevice *pci_dev) add_boot_device_path(d->conf.bootindex, dev, "/ethernet-phy@0"); - d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d); + d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d); return 0; } @@ -1400,6 +1400,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) k->device_id = E1000_DEVID; k->revision = 0x03; k->class_id = PCI_CLASS_NETWORK_ETHERNET; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Intel Gigabit Ethernet"; dc->reset = qdev_e1000_reset; dc->vmsd = &vmstate_e1000; diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index e0befb2590..ffa60d5c96 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -47,6 +47,7 @@ #include "hw/nvram/eeprom93xx.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" +#include "qemu/bitops.h" /* QEMU sends frames smaller than 60 bytes to ethernet nics. * Such frames are rejected by real nics and their emulations. @@ -105,7 +106,6 @@ #define PCI_IO_SIZE 64 #define PCI_FLASH_SIZE (128 * KiB) -#define BIT(n) (1 << (n)) #define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m) /* The SCB accepts the following controls for the Tx and Rx units: */ @@ -2083,6 +2083,7 @@ static void eepro100_class_init(ObjectClass *klass, void *data) info = eepro100_get_class_by_name(object_class_get_name(klass)); + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->props = e100_properties; dc->desc = info->desc; k->vendor_id = PCI_VENDOR_ID_INTEL; diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c index ab9a215253..78ebbbca72 100644 --- a/hw/net/etraxfs_eth.c +++ b/hw/net/etraxfs_eth.c @@ -322,9 +322,14 @@ static void mdio_cycle(struct qemu_mdio *bus) #define R_STAT 0x0b #define FS_ETH_MAX_REGS 0x17 -struct fs_eth +#define TYPE_ETRAX_FS_ETH "etraxfs-eth" +#define ETRAX_FS_ETH(obj) \ + OBJECT_CHECK(ETRAXFSEthState, (obj), TYPE_ETRAX_FS_ETH) + +typedef struct ETRAXFSEthState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mmio; NICState *nic; NICConf conf; @@ -349,9 +354,9 @@ struct fs_eth /* PHY. */ struct qemu_phy phy; -}; +} ETRAXFSEthState; -static void eth_validate_duplex(struct fs_eth *eth) +static void eth_validate_duplex(ETRAXFSEthState *eth) { struct qemu_phy *phy; unsigned int phy_duplex; @@ -382,7 +387,7 @@ static void eth_validate_duplex(struct fs_eth *eth) static uint64_t eth_read(void *opaque, hwaddr addr, unsigned int size) { - struct fs_eth *eth = opaque; + ETRAXFSEthState *eth = opaque; uint32_t r = 0; addr >>= 2; @@ -399,7 +404,7 @@ eth_read(void *opaque, hwaddr addr, unsigned int size) return r; } -static void eth_update_ma(struct fs_eth *eth, int ma) +static void eth_update_ma(ETRAXFSEthState *eth, int ma) { int reg; int i = 0; @@ -428,7 +433,7 @@ static void eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct fs_eth *eth = opaque; + ETRAXFSEthState *eth = opaque; uint32_t value = val64; addr >>= 2; @@ -472,7 +477,7 @@ eth_write(void *opaque, hwaddr addr, /* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom filter dropping group addresses we have not joined. The filter has 64 bits (m). The has function is a simple nible xor of the group addr. */ -static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) +static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa) { unsigned int hsh; int m_individual = eth->regs[RW_REC_CTRL] & 4; @@ -523,7 +528,7 @@ static int eth_can_receive(NetClientState *nc) static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = qemu_get_nic_opaque(nc); + ETRAXFSEthState *eth = qemu_get_nic_opaque(nc); int use_ma0 = eth->regs[RW_REC_CTRL] & 1; int use_ma1 = eth->regs[RW_REC_CTRL] & 2; int r_bcast = eth->regs[RW_REC_CTRL] & 8; @@ -547,12 +552,12 @@ static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* FIXME: Find another way to pass on the fake csum. */ etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); - return size; + return size; } static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) { - struct fs_eth *eth = opaque; + ETRAXFSEthState *eth = opaque; D(printf("%s buf=%p len=%d\n", __func__, buf, len)); qemu_send_packet(qemu_get_queue(eth->nic), buf, len); @@ -561,7 +566,7 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) static void eth_set_link(NetClientState *nc) { - struct fs_eth *eth = qemu_get_nic_opaque(nc); + ETRAXFSEthState *eth = qemu_get_nic_opaque(nc); D(printf("%s %d\n", __func__, nc->link_down)); eth->phy.link = !nc->link_down; } @@ -578,7 +583,7 @@ static const MemoryRegionOps eth_ops = { static void eth_cleanup(NetClientState *nc) { - struct fs_eth *eth = qemu_get_nic_opaque(nc); + ETRAXFSEthState *eth = qemu_get_nic_opaque(nc); /* Disconnect the client. */ eth->dma_out->client.push = NULL; @@ -597,9 +602,10 @@ static NetClientInfo net_etraxfs_info = { .link_status_changed = eth_set_link, }; -static int fs_eth_init(SysBusDevice *dev) +static int fs_eth_init(SysBusDevice *sbd) { - struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); + DeviceState *dev = DEVICE(sbd); + ETRAXFSEthState *s = ETRAX_FS_ETH(dev); if (!s->dma_out || !s->dma_in) { hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); @@ -612,11 +618,11 @@ static int fs_eth_init(SysBusDevice *dev) memory_region_init_io(&s->mmio, OBJECT(dev), ð_ops, s, "etraxfs-eth", 0x5c); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, - object_get_typename(OBJECT(s)), dev->qdev.id, s); + object_get_typename(OBJECT(s)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); @@ -626,10 +632,10 @@ static int fs_eth_init(SysBusDevice *dev) } static Property etraxfs_eth_properties[] = { - DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1), - DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out), - DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in), - DEFINE_NIC_PROPERTIES(struct fs_eth, conf), + DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1), + DEFINE_PROP_PTR("dma_out", ETRAXFSEthState, vdma_out), + DEFINE_PROP_PTR("dma_in", ETRAXFSEthState, vdma_in), + DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf), DEFINE_PROP_END_OF_LIST(), }; @@ -643,9 +649,9 @@ static void etraxfs_eth_class_init(ObjectClass *klass, void *data) } static const TypeInfo etraxfs_eth_info = { - .name = "etraxfs-eth", + .name = TYPE_ETRAX_FS_ETH, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct fs_eth), + .instance_size = sizeof(ETRAXFSEthState), .class_init = etraxfs_eth_class_init, }; diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 3323f48d97..2315f996d4 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -170,8 +170,12 @@ static const VMStateDescription vmstate_lan9118_packet = { } }; +#define TYPE_LAN9118 "lan9118" +#define LAN9118(obj) OBJECT_CHECK(lan9118_state, (obj), TYPE_LAN9118) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + NICState *nic; NICConf conf; qemu_irq irq; @@ -401,7 +405,8 @@ static void phy_reset(lan9118_state *s) static void lan9118_reset(DeviceState *d) { - lan9118_state *s = FROM_SYSBUS(lan9118_state, SYS_BUS_DEVICE(d)); + lan9118_state *s = LAN9118(d); + s->irq_cfg &= (IRQ_TYPE | IRQ_POL); s->int_sts = 0; s->int_en = 0; @@ -434,7 +439,7 @@ static void lan9118_reset(DeviceState *d) s->afc_cfg = 0; s->e2p_cmd = 0; s->e2p_data = 0; - s->free_timer_start = qemu_get_clock_ns(vm_clock) / 40; + s->free_timer_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40; ptimer_stop(s->timer); ptimer_set_count(s->timer, 0xffff); @@ -1053,7 +1058,7 @@ static void lan9118_writel(void *opaque, hwaddr offset, case CSR_HW_CFG: if (val & 1) { /* SRST */ - lan9118_reset(&s->busdev.qdev); + lan9118_reset(DEVICE(s)); } else { s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4); } @@ -1231,7 +1236,7 @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset, case CSR_WORD_SWAP: return s->word_swap; case CSR_FREE_RUN: - return (qemu_get_clock_ns(vm_clock) / 40) - s->free_timer_start; + return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40) - s->free_timer_start; case CSR_RX_DROP: /* TODO: Implement dropped frames counter. */ return 0; @@ -1320,9 +1325,10 @@ static NetClientInfo net_lan9118_info = { .link_status_changed = lan9118_set_link, }; -static int lan9118_init1(SysBusDevice *dev) +static int lan9118_init1(SysBusDevice *sbd) { - lan9118_state *s = FROM_SYSBUS(lan9118_state, dev); + DeviceState *dev = DEVICE(sbd); + lan9118_state *s = LAN9118(dev); QEMUBH *bh; int i; const MemoryRegionOps *mem_ops = @@ -1330,12 +1336,12 @@ static int lan9118_init1(SysBusDevice *dev) memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s, "lan9118-mmio", 0x100); - sysbus_init_mmio(dev, &s->mmio); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_lan9118_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->eeprom[0] = 0xa5; for (i = 0; i < 6; i++) { @@ -1370,7 +1376,7 @@ static void lan9118_class_init(ObjectClass *klass, void *data) } static const TypeInfo lan9118_info = { - .name = "lan9118", + .name = TYPE_LAN9118, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(lan9118_state), .class_init = lan9118_class_init, @@ -1389,7 +1395,7 @@ void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq) SysBusDevice *s; qemu_check_nic_model(nd, "lan9118"); - dev = qdev_create(NULL, "lan9118"); + dev = qdev_create(NULL, TYPE_LAN9118); qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); diff --git a/hw/net/lance.c b/hw/net/lance.c index 98bcdfce8b..e339f029b7 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -43,8 +43,13 @@ #include "pcnet.h" #include "trace.h" +#define TYPE_LANCE "lance" +#define SYSBUS_PCNET(obj) \ + OBJECT_CHECK(SysBusPCNetState, (obj), TYPE_LANCE) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + PCNetState state; } SysBusPCNetState; @@ -112,28 +117,29 @@ static const VMStateDescription vmstate_lance = { } }; -static int lance_init(SysBusDevice *dev) +static int lance_init(SysBusDevice *sbd) { - SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev); + DeviceState *dev = DEVICE(sbd); + SysBusPCNetState *d = SYSBUS_PCNET(dev); PCNetState *s = &d->state; memory_region_init_io(&s->mmio, OBJECT(d), &lance_mem_ops, d, "lance-mmio", 4); - qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1); + qdev_init_gpio_in(dev, parent_lance_reset, 1); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); s->phys_mem_read = ledma_memory_read; s->phys_mem_write = ledma_memory_write; - return pcnet_common_init(&dev->qdev, s, &net_lance_info); + return pcnet_common_init(dev, s, &net_lance_info); } static void lance_reset(DeviceState *dev) { - SysBusPCNetState *d = DO_UPCAST(SysBusPCNetState, busdev.qdev, dev); + SysBusPCNetState *d = SYSBUS_PCNET(dev); pcnet_h_reset(&d->state); } @@ -150,6 +156,7 @@ static void lance_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = lance_init; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "ethernet"; dc->reset = lance_reset; dc->vmsd = &vmstate_lance; @@ -157,7 +164,7 @@ static void lance_class_init(ObjectClass *klass, void *data) } static const TypeInfo lance_info = { - .name = "lance", + .name = TYPE_LANCE, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusPCNetState), .class_init = lance_class_init, diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index becd26c5d5..1e9237984d 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -90,8 +90,13 @@ struct MilkymistMinimac2MdioState { }; typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState; +#define TYPE_MILKYMIST_MINIMAC2 "milkymist-minimac2" +#define MILKYMIST_MINIMAC2(obj) \ + OBJECT_CHECK(MilkymistMinimac2State, (obj), TYPE_MILKYMIST_MINIMAC2) + struct MilkymistMinimac2State { - SysBusDevice busdev; + SysBusDevice parent_obj; + NICState *nic; NICConf conf; char *phy_model; @@ -429,8 +434,7 @@ static void minimac2_cleanup(NetClientState *nc) static void milkymist_minimac2_reset(DeviceState *d) { - MilkymistMinimac2State *s = - container_of(d, MilkymistMinimac2State, busdev.qdev); + MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d); int i; for (i = 0; i < R_MAX; i++) { @@ -453,17 +457,18 @@ static NetClientInfo net_milkymist_minimac2_info = { .cleanup = minimac2_cleanup, }; -static int milkymist_minimac2_init(SysBusDevice *dev) +static int milkymist_minimac2_init(SysBusDevice *sbd) { - MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev); + DeviceState *dev = DEVICE(sbd); + MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev); size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE); - sysbus_init_irq(dev, &s->rx_irq); - sysbus_init_irq(dev, &s->tx_irq); + sysbus_init_irq(sbd, &s->rx_irq); + sysbus_init_irq(sbd, &s->tx_irq); memory_region_init_io(&s->regs_region, OBJECT(dev), &minimac2_ops, s, "milkymist-minimac2", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); + sysbus_init_mmio(sbd, &s->regs_region); /* register buffers memory */ memory_region_init_ram(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers", @@ -473,11 +478,11 @@ static int milkymist_minimac2_init(SysBusDevice *dev) s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE; s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE; - sysbus_init_mmio(dev, &s->buffers); + sysbus_init_mmio(sbd, &s->buffers); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); return 0; @@ -532,7 +537,7 @@ static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_minimac2_info = { - .name = "milkymist-minimac2", + .name = TYPE_MILKYMIST_MINIMAC2, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistMinimac2State), .class_init = milkymist_minimac2_class_init, diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index 908085073a..e421b867e7 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -19,8 +19,11 @@ #define MAX_ETH_FRAME_SIZE 1514 +#define TYPE_MIPS_NET "mipsnet" +#define MIPS_NET(obj) OBJECT_CHECK(MIPSnetState, (obj), TYPE_MIPS_NET) + typedef struct MIPSnetState { - SysBusDevice busdev; + SysBusDevice parent_obj; uint32_t busy; uint32_t rx_count; @@ -231,17 +234,18 @@ static const MemoryRegionOps mipsnet_ioport_ops = { .impl.max_access_size = 4, }; -static int mipsnet_sysbus_init(SysBusDevice *dev) +static int mipsnet_sysbus_init(SysBusDevice *sbd) { - MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev); + DeviceState *dev = DEVICE(sbd); + MIPSnetState *s = MIPS_NET(dev); memory_region_init_io(&s->io, OBJECT(dev), &mipsnet_ioport_ops, s, "mipsnet-io", 36); - sysbus_init_mmio(dev, &s->io); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->io); + sysbus_init_irq(sbd, &s->irq); s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); return 0; @@ -249,7 +253,7 @@ static int mipsnet_sysbus_init(SysBusDevice *dev) static void mipsnet_sysbus_reset(DeviceState *dev) { - MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev); + MIPSnetState *s = MIPS_NET(dev); mipsnet_reset(s); } @@ -264,6 +268,7 @@ static void mipsnet_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = mipsnet_sysbus_init; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "MIPS Simulator network device"; dc->reset = mipsnet_sysbus_reset; dc->vmsd = &vmstate_mipsnet; @@ -271,7 +276,7 @@ static void mipsnet_class_init(ObjectClass *klass, void *data) } static const TypeInfo mipsnet_info = { - .name = "mipsnet", + .name = TYPE_MIPS_NET, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MIPSnetState), .class_init = mipsnet_class_init, diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index e3c8076382..26b83cef0d 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -98,6 +98,7 @@ static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) dc->realize = isa_ne2000_realizefn; dc->props = ne2000_isa_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo ne2000_isa_info = { diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 8d43fd9afe..31afd28c7c 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -772,6 +772,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_NETWORK_ETHERNET; dc->vmsd = &vmstate_pci_ne2000; dc->props = ne2000_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo ne2000_info = { diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 46375574e4..4118d54ac8 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -267,8 +267,12 @@ typedef struct desc { #define DEFAULT_PHY 1 +#define TYPE_OPEN_ETH "open_eth" +#define OPEN_ETH(obj) OBJECT_CHECK(OpenEthState, (obj), TYPE_OPEN_ETH) + typedef struct OpenEthState { - SysBusDevice dev; + SysBusDevice parent_obj; + NICState *nic; NICConf conf; MemoryRegion reg_io; @@ -677,28 +681,30 @@ static const MemoryRegionOps open_eth_desc_ops = { .write = open_eth_desc_write, }; -static int sysbus_open_eth_init(SysBusDevice *dev) +static int sysbus_open_eth_init(SysBusDevice *sbd) { - OpenEthState *s = DO_UPCAST(OpenEthState, dev, dev); + DeviceState *dev = DEVICE(sbd); + OpenEthState *s = OPEN_ETH(dev); memory_region_init_io(&s->reg_io, OBJECT(dev), &open_eth_reg_ops, s, "open_eth.regs", 0x54); - sysbus_init_mmio(dev, &s->reg_io); + sysbus_init_mmio(sbd, &s->reg_io); memory_region_init_io(&s->desc_io, OBJECT(dev), &open_eth_desc_ops, s, "open_eth.desc", 0x400); - sysbus_init_mmio(dev, &s->desc_io); + sysbus_init_mmio(sbd, &s->desc_io); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); s->nic = qemu_new_nic(&net_open_eth_info, &s->conf, - object_get_typename(OBJECT(s)), s->dev.qdev.id, s); + object_get_typename(OBJECT(s)), dev->id, s); return 0; } static void qdev_open_eth_reset(DeviceState *dev) { - OpenEthState *d = DO_UPCAST(OpenEthState, dev.qdev, dev); + OpenEthState *d = OPEN_ETH(dev); + open_eth_reset(d); } @@ -713,13 +719,14 @@ static void open_eth_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = sysbus_open_eth_init; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Opencores 10/100 Mbit Ethernet"; dc->reset = qdev_open_eth_reset; dc->props = open_eth_properties; } static const TypeInfo open_eth_info = { - .name = "open_eth", + .name = TYPE_OPEN_ETH, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenEthState), .class_init = open_eth_class_init, diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 6ef28f77a2..a8931652b3 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -284,8 +284,8 @@ static void pci_pcnet_uninit(PCIDevice *dev) memory_region_destroy(&d->state.mmio); memory_region_destroy(&d->io_bar); - qemu_del_timer(d->state.poll_timer); - qemu_free_timer(d->state.poll_timer); + timer_del(d->state.poll_timer); + timer_free(d->state.poll_timer); qemu_del_nic(d->state.nic); } @@ -366,6 +366,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) dc->reset = pci_reset; dc->vmsd = &vmstate_pci_pcnet; dc->props = pcnet_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo pcnet_info = { diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index b606d2be3b..7cb47b3f1f 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -861,6 +861,8 @@ static void pcnet_init(PCNetState *s) s->csr[0] |= 0x0101; s->csr[0] &= ~0x0004; /* clear STOP bit */ + + qemu_flush_queued_packets(qemu_get_queue(s->nic)); } static void pcnet_start(PCNetState *s) @@ -878,6 +880,8 @@ static void pcnet_start(PCNetState *s) s->csr[0] &= ~0x0004; /* clear STOP bit */ s->csr[0] |= 0x0002; pcnet_poll_timer(s); + + qemu_flush_queued_packets(qemu_get_queue(s->nic)); } static void pcnet_stop(PCNetState *s) @@ -1327,7 +1331,7 @@ static void pcnet_poll_timer(void *opaque) { PCNetState *s = opaque; - qemu_del_timer(s->poll_timer); + timer_del(s->poll_timer); if (CSR_TDMD(s)) { pcnet_transmit(s); @@ -1336,7 +1340,7 @@ static void pcnet_poll_timer(void *opaque) pcnet_update_irq(s); if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { - uint64_t now = qemu_get_clock_ns(vm_clock) * 33; + uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) * 33; if (!s->timer || !now) s->timer = now; else { @@ -1347,8 +1351,8 @@ static void pcnet_poll_timer(void *opaque) } else CSR_POLL(s) = t; } - qemu_mod_timer(s->poll_timer, - pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock))); + timer_mod(s->poll_timer, + pcnet_get_next_poll_time(s,qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))); } } @@ -1727,7 +1731,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) int i; uint16_t checksum; - s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s); + s->poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pcnet_poll_timer, s); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 65520340fc..c31199f8c8 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -2648,7 +2648,7 @@ static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) s->IntrMask = val; - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); rtl8139_update_irq(s); } @@ -2689,7 +2689,7 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) * and probably emulated is slower is better to assume this resetting was * done before testing on previous rtl8139_update_irq lead to IRQ losing */ - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); rtl8139_update_irq(s); #endif @@ -2697,7 +2697,7 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) { - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); uint32_t ret = s->IntrStatus; @@ -2913,7 +2913,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time) s->TimerExpire = next_time; if ((s->IntrMask & PCSTimeout) != 0 && (s->IntrStatus & PCSTimeout) == 0) { - qemu_mod_timer(s->timer, next_time); + timer_mod(s->timer, next_time); } } @@ -2960,7 +2960,7 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) case Timer: DPRINTF("TCTR Timer reset on write\n"); - s->TCTR_base = qemu_get_clock_ns(vm_clock); + s->TCTR_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); rtl8139_set_next_tctr_time(s, s->TCTR_base); break; @@ -2968,7 +2968,7 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) DPRINTF("FlashReg TimerInt write val=0x%08x\n", val); if (s->TimerInt != val) { s->TimerInt = val; - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } break; @@ -3183,7 +3183,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) break; case Timer: - ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base, + ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base, PCI_FREQUENCY, get_ticks_per_sec()); DPRINTF("TCTR Timer read val=0x%08x\n", ret); break; @@ -3245,7 +3245,7 @@ static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr) static int rtl8139_post_load(void *opaque, int version_id) { RTL8139State* s = opaque; - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); if (version_id < 4) { s->cplus_enabled = s->CpCmd != 0; } @@ -3275,7 +3275,7 @@ static const VMStateDescription vmstate_rtl8139_hotplug_ready ={ static void rtl8139_pre_save(void *opaque) { RTL8139State* s = opaque; - int64_t current_time = qemu_get_clock_ns(vm_clock); + int64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* set IntrStatus correctly */ rtl8139_set_next_tctr_time(s, current_time); @@ -3446,7 +3446,7 @@ static void rtl8139_timer(void *opaque) s->IntrStatus |= PCSTimeout; rtl8139_update_irq(s); - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } static void rtl8139_cleanup(NetClientState *nc) @@ -3466,8 +3466,8 @@ static void pci_rtl8139_uninit(PCIDevice *dev) g_free(s->cplus_txbuffer); s->cplus_txbuffer = NULL; } - qemu_del_timer(s->timer); - qemu_free_timer(s->timer); + timer_del(s->timer); + timer_free(s->timer); qemu_del_nic(s->nic); } @@ -3535,8 +3535,8 @@ static int pci_rtl8139_init(PCIDevice *dev) s->cplus_txbuffer_offset = 0; s->TimerExpire = 0; - s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s); - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rtl8139_timer, s); + rtl8139_set_next_tctr_time(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); add_boot_device_path(s->conf.bootindex, d, "/ethernet-phy@0"); @@ -3563,6 +3563,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) dc->reset = rtl8139_reset; dc->vmsd = &vmstate_rtl8139; dc->props = rtl8139_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo rtl8139_info = { diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index c49e37a8b0..f5963e2cbe 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -16,8 +16,12 @@ /* Number of 2k memory pages available. */ #define NUM_PACKETS 4 +#define TYPE_SMC91C111 "smc91c111" +#define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + NICState *nic; NICConf conf; uint16_t tcr; @@ -254,7 +258,8 @@ static void smc91c111_queue_tx(smc91c111_state *s, int packet) static void smc91c111_reset(DeviceState *dev) { - smc91c111_state *s = FROM_SYSBUS(smc91c111_state, SYS_BUS_DEVICE(dev)); + smc91c111_state *s = SMC91C111(dev); + s->bank = 0; s->tx_fifo_len = 0; s->tx_fifo_done_len = 0; @@ -302,8 +307,9 @@ static void smc91c111_writeb(void *opaque, hwaddr offset, return; case 5: SET_HIGH(rcr, value); - if (s->rcr & RCR_SOFT_RST) - smc91c111_reset(&s->busdev.qdev); + if (s->rcr & RCR_SOFT_RST) { + smc91c111_reset(DEVICE(s)); + } return; case 10: case 11: /* RPCR */ /* Ignored */ @@ -744,16 +750,18 @@ static NetClientInfo net_smc91c111_info = { .cleanup = smc91c111_cleanup, }; -static int smc91c111_init1(SysBusDevice *dev) +static int smc91c111_init1(SysBusDevice *sbd) { - smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev); + DeviceState *dev = DEVICE(sbd); + smc91c111_state *s = SMC91C111(dev); + memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s, "smc91c111-mmio", 16); - sysbus_init_mmio(dev, &s->mmio); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); /* ??? Save/restore. */ return 0; @@ -776,7 +784,7 @@ static void smc91c111_class_init(ObjectClass *klass, void *data) } static const TypeInfo smc91c111_info = { - .name = "smc91c111", + .name = TYPE_SMC91C111, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(smc91c111_state), .class_init = smc91c111_class_init, @@ -795,7 +803,7 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) SysBusDevice *s; qemu_check_nic_model(nd, "smc91c111"); - dev = qdev_create(NULL, "smc91c111"); + dev = qdev_create(NULL, TYPE_SMC91C111); qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 03a09f2047..4ff04113db 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -38,9 +38,9 @@ /*#define DEBUG*/ #ifdef DEBUG -#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0) +#define DPRINTF(fmt...) do { fprintf(stderr, fmt); } while (0) #else -#define dprintf(fmt...) +#define DPRINTF(fmt...) #endif /* @@ -81,9 +81,9 @@ typedef struct VIOsPAPRVLANDevice { VIOsPAPRDevice sdev; NICConf nicconf; NICState *nic; - int isopen; + bool isopen; target_ulong buf_list; - int add_buf_ptr, use_buf_ptr, rx_bufs; + uint32_t add_buf_ptr, use_buf_ptr, rx_bufs; target_ulong rxq_ptr; } VIOsPAPRVLANDevice; @@ -105,7 +105,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, uint64_t handle; uint8_t control; - dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id, + DPRINTF("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id, dev->rx_bufs); if (!dev->isopen) { @@ -123,7 +123,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, } bd = vio_ldq(sdev, dev->buf_list + buf_ptr); - dprintf("use_buf_ptr=%d bd=0x%016llx\n", + DPRINTF("use_buf_ptr=%d bd=0x%016llx\n", buf_ptr, (unsigned long long)bd); } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) && (buf_ptr != dev->use_buf_ptr)); @@ -138,14 +138,14 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, dev->use_buf_ptr = buf_ptr; vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0); - dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs); + DPRINTF("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs); /* Transfer the packet data */ if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) { return -1; } - dprintf("spapr_vlan_receive: DMA write completed\n"); + DPRINTF("spapr_vlan_receive: DMA write completed\n"); /* Update the receive queue */ control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID; @@ -159,7 +159,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8); vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control); - dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n", + DPRINTF("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n", (unsigned long long)dev->rxq_ptr, (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr), @@ -374,7 +374,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); vlan_bd_t bd; - dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx + DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx ", 0x" TARGET_FMT_lx ")\n", reg, buf); if (!sdev) { @@ -405,7 +405,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, dev->rx_bufs++; - dprintf("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d" + DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d" " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs, (unsigned long long)buf); @@ -425,14 +425,14 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, int i, nbufs; int ret; - dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x" + DPRINTF("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x" TARGET_FMT_lx ")\n", reg, continue_token); if (!sdev) { return H_PARAMETER; } - dprintf("rxbufs = %d\n", dev->rx_bufs); + DPRINTF("rxbufs = %d\n", dev->rx_bufs); if (!dev->isopen) { return H_DROPPED; @@ -444,7 +444,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, total_len = 0; for (i = 0; i < 6; i++) { - dprintf(" buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]); + DPRINTF(" buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]); if (!(bufs[i] & VLAN_BD_VALID)) { break; } @@ -452,7 +452,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, } nbufs = i; - dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n", + DPRINTF("h_send_logical_lan() %d buffers, total length 0x%x\n", nbufs, total_len); if (total_len == 0) { @@ -500,6 +500,25 @@ static Property spapr_vlan_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_llan = { + .name = "spapr_llan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice), + /* LLAN state */ + VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice), + VMSTATE_UINTTL(buf_list, VIOsPAPRVLANDevice), + VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice), + VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice), + VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice), + VMSTATE_UINTTL(rxq_ptr, VIOsPAPRVLANDevice), + + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_vlan_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -514,6 +533,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) k->signal_mask = 0x1; dc->props = spapr_vlan_properties; k->rtce_window_size = 0x10000000; + dc->vmsd = &vmstate_spapr_llan; } static const TypeInfo spapr_vlan_info = { diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index aac7c76feb..9dd77f7571 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -42,8 +42,13 @@ do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0) #define SE_TCTL_CRC 0x04 #define SE_TCTL_DUPLEX 0x08 +#define TYPE_STELLARIS_ENET "stellaris_enet" +#define STELLARIS_ENET(obj) \ + OBJECT_CHECK(stellaris_enet_state, (obj), TYPE_STELLARIS_ENET) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + uint32_t ris; uint32_t im; uint32_t rctl; @@ -386,11 +391,7 @@ static void stellaris_enet_cleanup(NetClientState *nc) { stellaris_enet_state *s = qemu_get_nic_opaque(nc); - unregister_savevm(&s->busdev.qdev, "stellaris_enet", s); - - memory_region_destroy(&s->mmio); - - g_free(s); + s->nic = NULL; } static NetClientInfo net_stellaris_enet_info = { @@ -401,26 +402,36 @@ static NetClientInfo net_stellaris_enet_info = { .cleanup = stellaris_enet_cleanup, }; -static int stellaris_enet_init(SysBusDevice *dev) +static int stellaris_enet_init(SysBusDevice *sbd) { - stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev); + DeviceState *dev = DEVICE(sbd); + stellaris_enet_state *s = STELLARIS_ENET(dev); memory_region_init_io(&s->mmio, OBJECT(s), &stellaris_enet_ops, s, "stellaris_enet", 0x1000); - sysbus_init_mmio(dev, &s->mmio); - sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); stellaris_enet_reset(s); - register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1, + register_savevm(dev, "stellaris_enet", -1, 1, stellaris_enet_save, stellaris_enet_load, s); return 0; } +static void stellaris_enet_unrealize(DeviceState *dev, Error **errp) +{ + stellaris_enet_state *s = STELLARIS_ENET(dev); + + unregister_savevm(DEVICE(s), "stellaris_enet", s); + + memory_region_destroy(&s->mmio); +} + static Property stellaris_enet_properties[] = { DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf), DEFINE_PROP_END_OF_LIST(), @@ -432,11 +443,12 @@ static void stellaris_enet_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = stellaris_enet_init; + dc->unrealize = stellaris_enet_unrealize; dc->props = stellaris_enet_properties; } static const TypeInfo stellaris_enet_info = { - .name = "stellaris_enet", + .name = TYPE_STELLARIS_ENET, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_enet_state), .class_init = stellaris_enet_class_init, diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 679f50c33a..dd41008fb0 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -162,14 +162,14 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) if (virtio_net_started(n, queue_status) && !n->vhost_started) { if (q->tx_timer) { - qemu_mod_timer(q->tx_timer, - qemu_get_clock_ns(vm_clock) + n->tx_timeout); + timer_mod(q->tx_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); } else { qemu_bh_schedule(q->tx_bh); } } else { if (q->tx_timer) { - qemu_del_timer(q->tx_timer); + timer_del(q->tx_timer); } else { qemu_bh_cancel(q->tx_bh); } @@ -1131,12 +1131,12 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) if (q->tx_waiting) { virtio_queue_set_notification(vq, 1); - qemu_del_timer(q->tx_timer); + timer_del(q->tx_timer); q->tx_waiting = 0; virtio_net_flush_tx(q); } else { - qemu_mod_timer(q->tx_timer, - qemu_get_clock_ns(vm_clock) + n->tx_timeout); + timer_mod(q->tx_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); q->tx_waiting = 1; virtio_queue_set_notification(vq, 0); } @@ -1233,7 +1233,7 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) if (n->vqs[i].tx_timer) { n->vqs[i].tx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); - n->vqs[i].tx_timer = qemu_new_timer_ns(vm_clock, + n->vqs[i].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_tx_timer, &n->vqs[i]); } else { @@ -1513,7 +1513,7 @@ static int virtio_net_device_init(VirtIODevice *vdev) if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) { n->vqs[0].tx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); - n->vqs[0].tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer, + n->vqs[0].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_tx_timer, &n->vqs[0]); } else { n->vqs[0].tx_vq = virtio_add_queue(vdev, 256, @@ -1598,8 +1598,8 @@ static int virtio_net_device_exit(DeviceState *qdev) qemu_purge_queued_packets(nc); if (q->tx_timer) { - qemu_del_timer(q->tx_timer); - qemu_free_timer(q->tx_timer); + timer_del(q->tx_timer); + timer_free(q->tx_timer); } else { qemu_bh_delete(q->tx_bh); } @@ -1638,6 +1638,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_net_device_exit; dc->props = virtio_net_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); vdc->init = virtio_net_device_init; vdc->get_config = virtio_net_get_config; vdc->set_config = virtio_net_set_config; diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index b39ff08f28..49c2466434 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -528,7 +528,7 @@ vmxnet3_setup_tx_offloads(VMXNET3State *s) break; default: - assert(false); + g_assert_not_reached(); return false; } @@ -575,7 +575,7 @@ vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx, stats->ucastBytesTxOK += tot_len; break; default: - assert(false); + g_assert_not_reached(); } if (s->offload_mode == VMXNET3_OM_TSO) { @@ -599,7 +599,7 @@ vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx, break; default: - assert(false); + g_assert_not_reached(); } } @@ -634,7 +634,7 @@ vmxnet3_on_rx_done_update_stats(VMXNET3State *s, stats->ucastBytesRxOK += tot_len; break; default: - assert(false); + g_assert_not_reached(); } if (tot_len > s->mtu) { @@ -643,7 +643,7 @@ vmxnet3_on_rx_done_update_stats(VMXNET3State *s, } break; default: - assert(false); + g_assert_not_reached(); } } @@ -1106,7 +1106,7 @@ vmxnet3_io_bar0_read(void *opaque, hwaddr addr, unsigned size) { if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR, VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) { - assert(false); + g_assert_not_reached(); } VMW_CBPRN("BAR0 unknown read [%" PRIx64 "], size %d", addr, size); @@ -1651,7 +1651,7 @@ vmxnet3_io_bar1_write(void *opaque, case VMXNET3_REG_ICR: VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d", val, size); - assert(false); + g_assert_not_reached(); break; /* Event Cause Register */ @@ -1801,7 +1801,7 @@ vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const void *data, break; default: - assert(false); + g_assert_not_reached(); } return true; @@ -2453,6 +2453,7 @@ static void vmxnet3_class_init(ObjectClass *class, void *data) dc->reset = vmxnet3_qdev_reset; dc->vmsd = &vmstate_vmxnet3; dc->props = vmxnet3_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo vmxnet3_info = { diff --git a/hw/net/vmxnet_tx_pkt.c b/hw/net/vmxnet_tx_pkt.c index fc01e4da3c..f7344c4cb3 100644 --- a/hw/net/vmxnet_tx_pkt.c +++ b/hw/net/vmxnet_tx_pkt.c @@ -287,7 +287,7 @@ void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable, break; default: - assert(false); + g_assert_not_reached(); } if (csum_enable) { diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 997a5b59ec..9384fa0c5c 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -135,8 +135,12 @@ typedef struct RxTxStats { uint64_t rx_mcast; } RxTxStats; +#define TYPE_XGMAC "xgmac" +#define XGMAC(obj) OBJECT_CHECK(XgmacState, (obj), TYPE_XGMAC) + typedef struct XgmacState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq sbd_irq; qemu_irq pmt_irq; @@ -173,14 +177,14 @@ static const VMStateDescription vmstate_xgmac = { } }; -static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx) +static void xgmac_read_desc(XgmacState *s, struct desc *d, int rx) { uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] : s->regs[DMA_CUR_TX_DESC_ADDR]; cpu_physical_memory_read(addr, d, sizeof(*d)); } -static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx) +static void xgmac_write_desc(XgmacState *s, struct desc *d, int rx) { int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR; uint32_t addr = s->regs[reg]; @@ -195,7 +199,7 @@ static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx) cpu_physical_memory_write(addr, d, sizeof(*d)); } -static void xgmac_enet_send(struct XgmacState *s) +static void xgmac_enet_send(XgmacState *s) { struct desc bd; int frame_size; @@ -246,7 +250,7 @@ static void xgmac_enet_send(struct XgmacState *s) } } -static void enet_update_irq(struct XgmacState *s) +static void enet_update_irq(XgmacState *s) { int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA]; qemu_set_irq(s->sbd_irq, !!stat); @@ -254,7 +258,7 @@ static void enet_update_irq(struct XgmacState *s) static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) { - struct XgmacState *s = opaque; + XgmacState *s = opaque; uint64_t r = 0; addr >>= 2; @@ -274,7 +278,7 @@ static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) static void enet_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct XgmacState *s = opaque; + XgmacState *s = opaque; addr >>= 2; switch (addr) { @@ -310,7 +314,7 @@ static const MemoryRegionOps enet_mem_ops = { static int eth_can_rx(NetClientState *nc) { - struct XgmacState *s = qemu_get_nic_opaque(nc); + XgmacState *s = qemu_get_nic_opaque(nc); /* RX enabled? */ return s->regs[DMA_CONTROL] & DMA_CONTROL_SR; @@ -318,7 +322,7 @@ static int eth_can_rx(NetClientState *nc) static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) { - struct XgmacState *s = qemu_get_nic_opaque(nc); + XgmacState *s = qemu_get_nic_opaque(nc); static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int unicast, broadcast, multicast; @@ -366,7 +370,8 @@ out: static void eth_cleanup(NetClientState *nc) { - struct XgmacState *s = qemu_get_nic_opaque(nc); + XgmacState *s = qemu_get_nic_opaque(nc); + s->nic = NULL; } @@ -378,20 +383,21 @@ static NetClientInfo net_xgmac_enet_info = { .cleanup = eth_cleanup, }; -static int xgmac_enet_init(SysBusDevice *dev) +static int xgmac_enet_init(SysBusDevice *sbd) { - struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev); + DeviceState *dev = DEVICE(sbd); + XgmacState *s = XGMAC(dev); memory_region_init_io(&s->iomem, OBJECT(s), &enet_mem_ops, s, "xgmac", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->sbd_irq); - sysbus_init_irq(dev, &s->pmt_irq); - sysbus_init_irq(dev, &s->mci_irq); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->sbd_irq); + sysbus_init_irq(sbd, &s->pmt_irq); + sysbus_init_irq(sbd, &s->mci_irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) | @@ -405,7 +411,7 @@ static int xgmac_enet_init(SysBusDevice *dev) } static Property xgmac_properties[] = { - DEFINE_NIC_PROPERTIES(struct XgmacState, conf), + DEFINE_NIC_PROPERTIES(XgmacState, conf), DEFINE_PROP_END_OF_LIST(), }; @@ -420,9 +426,9 @@ static void xgmac_enet_class_init(ObjectClass *klass, void *data) } static const TypeInfo xgmac_enet_info = { - .name = "xgmac", + .name = TYPE_XGMAC, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct XgmacState), + .instance_size = sizeof(XgmacState), .class_init = xgmac_enet_class_init, }; diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index 2afc91ad0e..3a2a6c21c9 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -47,9 +47,14 @@ #define CTRL_P 0x2 #define CTRL_S 0x1 +#define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite" +#define XILINX_ETHLITE(obj) \ + OBJECT_CHECK(struct xlx_ethlite, (obj), TYPE_XILINX_ETHLITE) + struct xlx_ethlite { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mmio; qemu_irq irq; NICState *nic; @@ -214,20 +219,21 @@ static NetClientInfo net_xilinx_ethlite_info = { .cleanup = eth_cleanup, }; -static int xilinx_ethlite_init(SysBusDevice *dev) +static int xilinx_ethlite_init(SysBusDevice *sbd) { - struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev); + DeviceState *dev = DEVICE(sbd); + struct xlx_ethlite *s = XILINX_ETHLITE(dev); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); s->rxbuf = 0; memory_region_init_io(&s->mmio, OBJECT(s), ð_ops, s, "xlnx.xps-ethernetlite", R_MAX * 4); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); return 0; } @@ -249,7 +255,7 @@ static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) } static const TypeInfo xilinx_ethlite_info = { - .name = "xlnx.xps-ethernetlite", + .name = TYPE_XILINX_ETHLITE, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_ethlite), .class_init = xilinx_ethlite_class_init, diff --git a/hw/nvram/ds1225y.c b/hw/nvram/ds1225y.c index fa218ce704..f9a700b01c 100644 --- a/hw/nvram/ds1225y.c +++ b/hw/nvram/ds1225y.c @@ -26,7 +26,6 @@ #include "trace.h" typedef struct { - DeviceState qdev; MemoryRegion iomem; uint32_t chip_size; char *filename; @@ -105,14 +104,19 @@ static const VMStateDescription vmstate_nvram = { } }; +#define TYPE_DS1225Y "ds1225y" +#define DS1225Y(obj) OBJECT_CHECK(SysBusNvRamState, (obj), TYPE_DS1225Y) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + NvRamState nvram; } SysBusNvRamState; static int nvram_sysbus_initfn(SysBusDevice *dev) { - NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram; + SysBusNvRamState *sys = DS1225Y(dev); + NvRamState *s = &sys->nvram; FILE *file; s->contents = g_malloc0(s->chip_size); @@ -152,7 +156,7 @@ static void nvram_sysbus_class_init(ObjectClass *klass, void *data) } static const TypeInfo nvram_sysbus_info = { - .name = "ds1225y", + .name = TYPE_DS1225Y, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusNvRamState), .class_init = nvram_sysbus_class_init, diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 0a35015b9e..d0820e507b 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -324,7 +324,7 @@ static const MemoryRegionOps fw_cfg_data_mem_ops = { static const MemoryRegionOps fw_cfg_comb_mem_ops = { .read = fw_cfg_comb_read, .write = fw_cfg_comb_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, .valid.accepts = fw_cfg_comb_valid, }; diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 4144b34be7..988ca20898 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -33,9 +33,9 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu) uint64_t now, next; uint32_t wait; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (!is_counting) { - qemu_del_timer(cpu->env.timer); + timer_del(cpu->env.timer); last_clk = now; return; } @@ -52,7 +52,7 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu) } next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); - qemu_mod_timer(cpu->env.timer, next); + timer_mod(cpu->env.timer, next); } void cpu_openrisc_count_start(OpenRISCCPU *cpu) @@ -72,7 +72,7 @@ static void openrisc_timer_cb(void *opaque) OpenRISCCPU *cpu = opaque; if ((cpu->env.ttmr & TTMR_IE) && - qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) { + timer_expired(cpu->env.timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))) { CPUState *cs = CPU(cpu); cpu->env.ttmr |= TTMR_IP; @@ -97,7 +97,7 @@ static void openrisc_timer_cb(void *opaque) void cpu_openrisc_clock_init(OpenRISCCPU *cpu) { - cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu); + cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &openrisc_timer_cb, cpu); cpu->env.ttmr = 0x00000000; cpu->env.ttcr = 0x00000000; } diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 924438bcc2..28fa41d64e 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -82,13 +82,12 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size, } if (kernel_size < 0) { - qemu_log("QEMU: couldn't load the kernel '%s'\n", + fprintf(stderr, "QEMU: couldn't load the kernel '%s'\n", kernel_filename); exit(1); } + cpu->env.pc = entry; } - - cpu->env.pc = entry; } static void openrisc_sim_init(QEMUMachineInitArgs *args) @@ -96,7 +95,7 @@ static void openrisc_sim_init(QEMUMachineInitArgs *args) ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; - OpenRISCCPU *cpu = NULL; + OpenRISCCPU *cpu = NULL; MemoryRegion *ram; int n; @@ -107,7 +106,7 @@ static void openrisc_sim_init(QEMUMachineInitArgs *args) for (n = 0; n < smp_cpus; n++) { cpu = cpu_openrisc_init(cpu_model); if (cpu == NULL) { - qemu_log("Unable to find CPU definition!\n"); + fprintf(stderr, "Unable to find CPU definition!\n"); exit(1); } qemu_register_reset(main_cpu_reset, cpu); diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c index ca0b7c11bd..2af1d6013a 100644 --- a/hw/openrisc/pic_cpu.c +++ b/hw/openrisc/pic_cpu.c @@ -26,26 +26,25 @@ static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) { OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; CPUState *cs = CPU(cpu); - int i; - uint32_t irq_bit = 1 << irq; + uint32_t irq_bit; if (irq > 31 || irq < 0) { return; } + irq_bit = 1U << irq; + if (level) { cpu->env.picsr |= irq_bit; } else { cpu->env.picsr &= ~irq_bit; } - for (i = 0; i < 32; i++) { - if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - cpu->env.picsr &= ~(1 << i); - } + if (cpu->env.picsr & cpu->env.picmr) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + cpu->env.picsr = 0; } } diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c index efc07c42bd..e5e3be829f 100644 --- a/hw/pci-bridge/dec.c +++ b/hw/pci-bridge/dec.c @@ -74,7 +74,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) static const TypeInfo dec_21154_pci_bridge_info = { .name = "dec-21154-p2p-bridge", - .parent = TYPE_PCI_DEVICE, + .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(PCIBridge), .class_init = dec_21154_pci_bridge_class_init, }; @@ -86,7 +86,7 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) dev = pci_create_multifunction(parent_bus, devfn, false, "dec-21154-p2p-bridge"); - br = DO_UPCAST(PCIBridge, dev, dev); + br = PCI_BRIDGE(dev); pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq); qdev_init_nofail(&dev->qdev); return pci_bridge_get_sec_bus(br); diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index b98bfb0664..14cd7fd405 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -52,7 +52,9 @@ #define I82801ba_SSVID_SSID 0 typedef struct I82801b11Bridge { - PCIBridge br; + /*< private >*/ + PCIBridge parent_obj; + /*< public >*/ } I82801b11Bridge; static int i82801b11_bridge_initfn(PCIDevice *d) @@ -81,17 +83,20 @@ err_bridge: static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->is_bridge = 1; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11; k->revision = ICH9_D2P_A2_REVISION; k->init = i82801b11_bridge_initfn; + k->config_write = pci_bridge_write_config; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo i82801b11_bridge_info = { .name = "i82801b11-bridge", - .parent = TYPE_PCI_DEVICE, + .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(I82801b11Bridge), .class_init = i82801b11_bridge_class_init, }; @@ -107,8 +112,8 @@ PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus) if (!d) { return NULL; } - br = DO_UPCAST(PCIBridge, dev, d); - qdev = &br->dev.qdev; + br = PCI_BRIDGE(d); + qdev = DEVICE(d); snprintf(buf, sizeof(buf), "pci.%d", sec_bus); pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn); diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index bb541ebb12..0f7f2092a7 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -92,9 +92,8 @@ static void ioh3420_reset(DeviceState *qdev) static int ioh3420_initfn(PCIDevice *d) { - PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); - PCIEPort *p = DO_UPCAST(PCIEPort, br, br); - PCIESlot *s = DO_UPCAST(PCIESlot, port, p); + PCIEPort *p = PCIE_PORT(d); + PCIESlot *s = PCIE_SLOT(d); int rc; rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); @@ -148,9 +147,7 @@ err_bridge: static void ioh3420_exitfn(PCIDevice *d) { - PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); - PCIEPort *p = DO_UPCAST(PCIEPort, br, br); - PCIESlot *s = DO_UPCAST(PCIESlot, port, p); + PCIESlot *s = PCIE_SLOT(d); pcie_aer_exit(d); pcie_chassis_del_slot(s); @@ -171,16 +168,16 @@ PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, if (!d) { return NULL; } - br = DO_UPCAST(PCIBridge, dev, d); + br = PCI_BRIDGE(d); - qdev = &br->dev.qdev; + qdev = DEVICE(d); pci_bridge_map_irq(br, bus_name, map_irq); qdev_prop_set_uint8(qdev, "port", port); qdev_prop_set_uint8(qdev, "chassis", chassis); qdev_prop_set_uint16(qdev, "slot", slot); qdev_init_nofail(qdev); - return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br)); + return PCIE_SLOT(d); } static const VMStateDescription vmstate_ioh3420 = { @@ -190,23 +187,13 @@ static const VMStateDescription vmstate_ioh3420 = { .minimum_version_id_old = 1, .post_load = pcie_cap_slot_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot), - VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0, - vmstate_pcie_aer_log, PCIEAERLog), + VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), + VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, + PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() } }; -static Property ioh3420_properties[] = { - DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), - DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), - DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), - DEFINE_PROP_UINT16("aer_log_max", PCIESlot, - port.br.dev.exp.aer_log.log_max, - PCIE_AER_LOG_MAX_DEFAULT), - DEFINE_PROP_END_OF_LIST(), -}; - static void ioh3420_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -220,16 +207,15 @@ static void ioh3420_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_IOH_EPORT; k->revision = PCI_DEVICE_ID_IOH_REV; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Intel IOH device id 3420 PCIE Root Port"; dc->reset = ioh3420_reset; dc->vmsd = &vmstate_ioh3420; - dc->props = ioh3420_properties; } static const TypeInfo ioh3420_info = { .name = "ioh3420", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIESlot), + .parent = TYPE_PCIE_SLOT, .class_init = ioh3420_class_init, }; diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 5f11323fe6..a9392c7bdc 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -27,8 +27,15 @@ #include "exec/memory.h" #include "hw/pci/pci_bus.h" +#define TYPE_PCI_BRIDGE_DEV "pci-bridge" +#define PCI_BRIDGE_DEV(obj) \ + OBJECT_CHECK(PCIBridgeDev, (obj), TYPE_PCI_BRIDGE_DEV) + struct PCIBridgeDev { - PCIBridge bridge; + /*< private >*/ + PCIBridge parent_obj; + /*< public >*/ + MemoryRegion bar; uint8_t chassis_nr; #define PCI_BRIDGE_DEV_F_MSI_REQ 0 @@ -38,8 +45,8 @@ typedef struct PCIBridgeDev PCIBridgeDev; static int pci_bridge_dev_initfn(PCIDevice *dev) { - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); - PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); + PCIBridge *br = PCI_BRIDGE(dev); + PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); int err; err = pci_bridge_initfn(dev, TYPE_PCI_BUS); @@ -81,8 +88,7 @@ bridge_error: static void pci_bridge_dev_exitfn(PCIDevice *dev) { - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); - PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); + PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); if (msi_present(dev)) { msi_uninit(dev); } @@ -104,7 +110,7 @@ static void pci_bridge_dev_write_config(PCIDevice *d, static void qdev_pci_bridge_dev_reset(DeviceState *qdev) { - PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *dev = PCI_DEVICE(qdev); pci_bridge_reset(qdev); shpc_reset(dev); @@ -120,8 +126,8 @@ static Property pci_bridge_dev_properties[] = { static const VMStateDescription pci_bridge_dev_vmstate = { .name = "pci_bridge", .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(bridge.dev, PCIBridgeDev), - SHPC_VMSTATE(bridge.dev.shpc, PCIBridgeDev), + VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), + SHPC_VMSTATE(shpc, PCIDevice), VMSTATE_END_OF_LIST() } }; @@ -141,11 +147,12 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) dc->reset = qdev_pci_bridge_dev_reset; dc->props = pci_bridge_dev_properties; dc->vmsd = &pci_bridge_dev_vmstate; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo pci_bridge_dev_info = { - .name = "pci-bridge", - .parent = TYPE_PCI_DEVICE, + .name = TYPE_PCI_BRIDGE_DEV, + .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(PCIBridgeDev), .class_init = pci_bridge_dev_class_init, }; diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 1810dd23f2..94f97819cf 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -56,9 +56,8 @@ static void xio3130_downstream_reset(DeviceState *qdev) static int xio3130_downstream_initfn(PCIDevice *d) { - PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); - PCIEPort *p = DO_UPCAST(PCIEPort, br, br); - PCIESlot *s = DO_UPCAST(PCIESlot, port, p); + PCIEPort *p = PCIE_PORT(d); + PCIESlot *s = PCIE_SLOT(d); int rc; rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); @@ -113,9 +112,7 @@ err_bridge: static void xio3130_downstream_exitfn(PCIDevice *d) { - PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); - PCIEPort *p = DO_UPCAST(PCIEPort, br, br); - PCIESlot *s = DO_UPCAST(PCIESlot, port, p); + PCIESlot *s = PCIE_SLOT(d); pcie_aer_exit(d); pcie_chassis_del_slot(s); @@ -138,16 +135,16 @@ PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, if (!d) { return NULL; } - br = DO_UPCAST(PCIBridge, dev, d); + br = PCI_BRIDGE(d); - qdev = &br->dev.qdev; + qdev = DEVICE(d); pci_bridge_map_irq(br, bus_name, map_irq); qdev_prop_set_uint8(qdev, "port", port); qdev_prop_set_uint8(qdev, "chassis", chassis); qdev_prop_set_uint16(qdev, "slot", slot); qdev_init_nofail(qdev); - return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br)); + return PCIE_SLOT(d); } static const VMStateDescription vmstate_xio3130_downstream = { @@ -157,23 +154,13 @@ static const VMStateDescription vmstate_xio3130_downstream = { .minimum_version_id_old = 1, .post_load = pcie_cap_slot_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot), - VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0, - vmstate_pcie_aer_log, PCIEAERLog), + VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), + VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, + PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() } }; -static Property xio3130_downstream_properties[] = { - DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), - DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), - DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), - DEFINE_PROP_UINT16("aer_log_max", PCIESlot, - port.br.dev.exp.aer_log.log_max, - PCIE_AER_LOG_MAX_DEFAULT), - DEFINE_PROP_END_OF_LIST(), -}; - static void xio3130_downstream_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -187,16 +174,15 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_TI; k->device_id = PCI_DEVICE_ID_TI_XIO3130D; k->revision = XIO3130_REVISION; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "TI X3130 Downstream Port of PCI Express Switch"; dc->reset = xio3130_downstream_reset; dc->vmsd = &vmstate_xio3130_downstream; - dc->props = xio3130_downstream_properties; } static const TypeInfo xio3130_downstream_info = { .name = "xio3130-downstream", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIESlot), + .parent = TYPE_PCIE_SLOT, .class_init = xio3130_downstream_class_init, }; diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 8e0d97a644..59f97f6ff1 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -53,8 +53,7 @@ static void xio3130_upstream_reset(DeviceState *qdev) static int xio3130_upstream_initfn(PCIDevice *d) { - PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); - PCIEPort *p = DO_UPCAST(PCIEPort, br, br); + PCIEPort *p = PCIE_PORT(d); int rc; rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); @@ -118,14 +117,14 @@ PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, if (!d) { return NULL; } - br = DO_UPCAST(PCIBridge, dev, d); + br = PCI_BRIDGE(d); - qdev = &br->dev.qdev; + qdev = DEVICE(d); pci_bridge_map_irq(br, bus_name, map_irq); qdev_prop_set_uint8(qdev, "port", port); qdev_init_nofail(qdev); - return DO_UPCAST(PCIEPort, br, br); + return PCIE_PORT(d); } static const VMStateDescription vmstate_xio3130_upstream = { @@ -134,20 +133,13 @@ static const VMStateDescription vmstate_xio3130_upstream = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(br.dev, PCIEPort), - VMSTATE_STRUCT(br.dev.exp.aer_log, PCIEPort, 0, vmstate_pcie_aer_log, - PCIEAERLog), + VMSTATE_PCIE_DEVICE(parent_obj.parent_obj, PCIEPort), + VMSTATE_STRUCT(parent_obj.parent_obj.exp.aer_log, PCIEPort, 0, + vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() } }; -static Property xio3130_upstream_properties[] = { - DEFINE_PROP_UINT8("port", PCIEPort, port, 0), - DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max, - PCIE_AER_LOG_MAX_DEFAULT), - DEFINE_PROP_END_OF_LIST(), -}; - static void xio3130_upstream_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -161,16 +153,15 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_TI; k->device_id = PCI_DEVICE_ID_TI_XIO3130U; k->revision = XIO3130_REVISION; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "TI X3130 Upstream Port of PCI Express Switch"; dc->reset = xio3130_upstream_reset; dc->vmsd = &vmstate_xio3130_upstream; - dc->props = xio3130_upstream_properties; } static const TypeInfo xio3130_upstream_info = { .name = "x3130-upstream", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIEPort), + .parent = TYPE_PCIE_PORT, .class_init = xio3130_upstream_class_init, }; diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 06ace085b5..92f289f8f9 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -70,9 +70,14 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0) #define MAX_IVEC 0x40 #define NO_IRQ_REQUEST (MAX_IVEC + 1) +#define TYPE_APB "pbm" + +#define APB_DEVICE(obj) \ + OBJECT_CHECK(APBState, (obj), TYPE_APB) + typedef struct APBState { - SysBusDevice busdev; - PCIBus *bus; + PCIHostState parent_obj; + MemoryRegion apb_config; MemoryRegion pci_config; MemoryRegion pci_mmio; @@ -284,10 +289,11 @@ static void apb_pci_config_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { APBState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); val = qemu_bswap_len(val, size); APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val); - pci_data_write(s->bus, addr, val, size); + pci_data_write(phb->bus, addr, val, size); } static uint64_t apb_pci_config_read(void *opaque, hwaddr addr, @@ -295,63 +301,14 @@ static uint64_t apb_pci_config_read(void *opaque, hwaddr addr, { uint32_t ret; APBState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); - ret = pci_data_read(s->bus, addr, size); + ret = pci_data_read(phb->bus, addr, size); ret = qemu_bswap_len(ret, size); APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret); return ret; } -static void pci_apb_iowriteb (void *opaque, hwaddr addr, - uint32_t val) -{ - cpu_outb(addr & IOPORTS_MASK, val); -} - -static void pci_apb_iowritew (void *opaque, hwaddr addr, - uint32_t val) -{ - cpu_outw(addr & IOPORTS_MASK, bswap16(val)); -} - -static void pci_apb_iowritel (void *opaque, hwaddr addr, - uint32_t val) -{ - cpu_outl(addr & IOPORTS_MASK, bswap32(val)); -} - -static uint32_t pci_apb_ioreadb (void *opaque, hwaddr addr) -{ - uint32_t val; - - val = cpu_inb(addr & IOPORTS_MASK); - return val; -} - -static uint32_t pci_apb_ioreadw (void *opaque, hwaddr addr) -{ - uint32_t val; - - val = bswap16(cpu_inw(addr & IOPORTS_MASK)); - return val; -} - -static uint32_t pci_apb_ioreadl (void *opaque, hwaddr addr) -{ - uint32_t val; - - val = bswap32(cpu_inl(addr & IOPORTS_MASK)); - return val; -} - -static const MemoryRegionOps pci_ioport_ops = { - .old_mmio = { - .read = { pci_apb_ioreadb, pci_apb_ioreadw, pci_apb_ioreadl }, - .write = { pci_apb_iowriteb, pci_apb_iowritew, pci_apb_iowritel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - /* The APB host has an IRQ line for each IRQ line of each slot. */ static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num) { @@ -431,12 +388,13 @@ PCIBus *pci_apb_init(hwaddr special_base, { DeviceState *dev; SysBusDevice *s; + PCIHostState *phb; APBState *d; PCIDevice *pci_dev; PCIBridge *br; /* Ultrasparc PBM main bus */ - dev = qdev_create(NULL, "pbm"); + dev = qdev_create(NULL, TYPE_APB); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); /* apb_config */ @@ -445,46 +403,47 @@ PCIBus *pci_apb_init(hwaddr special_base, sysbus_mmio_map(s, 1, special_base + 0x1000000ULL); /* pci_ioport */ sysbus_mmio_map(s, 2, special_base + 0x2000000ULL); - d = FROM_SYSBUS(APBState, s); + d = APB_DEVICE(dev); memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL); memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio); - d->bus = pci_register_bus(&d->busdev.qdev, "pci", - pci_apb_set_irq, pci_pbm_map_irq, d, - &d->pci_mmio, - get_system_io(), - 0, 32, TYPE_PCI_BUS); + phb = PCI_HOST_BRIDGE(dev); + phb->bus = pci_register_bus(DEVICE(phb), "pci", + pci_apb_set_irq, pci_pbm_map_irq, d, + &d->pci_mmio, + get_system_io(), + 0, 32, TYPE_PCI_BUS); *pbm_irqs = d->pbm_irqs; d->ivec_irqs = ivec_irqs; - pci_create_simple(d->bus, 0, "pbm-pci"); + pci_create_simple(phb->bus, 0, "pbm-pci"); /* APB secondary busses */ - pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true, + pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, "pbm-bridge"); - br = DO_UPCAST(PCIBridge, dev, pci_dev); + br = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1", pci_apb_map_irq); qdev_init_nofail(&pci_dev->qdev); *bus2 = pci_bridge_get_sec_bus(br); - pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true, + pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, "pbm-bridge"); - br = DO_UPCAST(PCIBridge, dev, pci_dev); + br = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2", pci_apb_map_irq); qdev_init_nofail(&pci_dev->qdev); *bus3 = pci_bridge_get_sec_bus(br); - return d->bus; + return phb->bus; } static void pci_pbm_reset(DeviceState *d) { unsigned int i; - APBState *s = container_of(d, APBState, busdev.qdev); + APBState *s = APB_DEVICE(d); for (i = 0; i < 8; i++) { s->pci_irq_map[i] &= PBM_PCI_IMR_MASK; @@ -513,7 +472,7 @@ static int pci_pbm_init_device(SysBusDevice *dev) APBState *s; unsigned int i; - s = FROM_SYSBUS(APBState, dev); + s = APB_DEVICE(dev); for (i = 0; i < 8; i++) { s->pci_irq_map[i] = (0x1f << 6) | (i << 2); } @@ -536,8 +495,8 @@ static int pci_pbm_init_device(SysBusDevice *dev) sysbus_init_mmio(dev, &s->pci_config); /* pci_ioport */ - memory_region_init_io(&s->pci_ioport, OBJECT(s), &pci_ioport_ops, s, - "apb-pci-ioport", 0x10000); + memory_region_init_alias(&s->pci_ioport, OBJECT(s), "apb-pci-ioport", + get_system_io(), 0, 0x10000); /* at region 2 */ sysbus_init_mmio(dev, &s->pci_ioport); @@ -577,12 +536,13 @@ static void pbm_host_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pci_pbm_init_device; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_pbm_reset; } static const TypeInfo pbm_host_info = { - .name = "pbm", - .parent = TYPE_SYS_BUS_DEVICE, + .name = TYPE_APB, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(APBState), .class_init = pbm_host_class_init, }; @@ -599,14 +559,14 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) k->revision = 0x11; k->config_write = pci_bridge_write_config; k->is_bridge = 1; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_bridge_reset; dc->vmsd = &vmstate_pci_device; } static const TypeInfo pbm_pci_bridge_info = { .name = "pbm-bridge", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIBridge), + .parent = TYPE_PCI_BRIDGE, .class_init = pbm_pci_bridge_class_init, }; diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 592d6666bc..5086d42c13 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -210,14 +210,8 @@ typedef struct PCIBonitoState MemoryRegion iomem; MemoryRegion iomem_ldma; MemoryRegion iomem_cop; - - hwaddr bonito_pciio_start; - hwaddr bonito_pciio_length; - int bonito_pciio_handle; - - hwaddr bonito_localio_start; - hwaddr bonito_localio_length; - int bonito_localio_handle; + MemoryRegion bonito_pciio; + MemoryRegion bonito_localio; } PCIBonitoState; @@ -750,15 +744,16 @@ static int bonito_initfn(PCIDevice *dev) sysbus_mmio_map(sysbus, 4, 0xbfe00300); /* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */ - s->bonito_pciio_start = BONITO_PCIIO_BASE; - s->bonito_pciio_length = BONITO_PCIIO_SIZE; - isa_mem_base = s->bonito_pciio_start; - isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length); + memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio", + get_system_io(), 0, BONITO_PCIIO_SIZE); + sysbus_init_mmio(sysbus, &s->bonito_pciio); + sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE); /* add pci local io mapping */ - s->bonito_localio_start = BONITO_DEV_BASE; - s->bonito_localio_length = BONITO_DEV_SIZE; - isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length); + memory_region_init_alias(&s->bonito_localio, OBJECT(s), "isa_mmio", + get_system_io(), 0, BONITO_DEV_SIZE); + sysbus_init_mmio(sysbus, &s->bonito_localio); + sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE); /* set the default value of north bridge pci config */ pci_set_word(dev->config + PCI_COMMAND, 0x0000); diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 39088603bb..dc1718fe30 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -32,14 +32,22 @@ #include "hw/xen/xen.h" #include "hw/pci-host/pam.h" #include "sysemu/sysemu.h" +#include "hw/i386/ioapic.h" +#include "qapi/visitor.h" /* * I440FX chipset data sheet. * http://download.intel.com/design/chipsets/datashts/29054901.pdf */ +#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost" +#define I440FX_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX_PCI_HOST_BRIDGE) + typedef struct I440FXState { PCIHostState parent_obj; + PcPciInfo pci_info; + uint64_t pci_hole64_size; } I440FXState; #define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ @@ -203,14 +211,71 @@ static const VMStateDescription vmstate_i440fx = { } }; +static void i440fx_pcihost_get_pci_hole_start(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); + uint32_t value = s->pci_info.w32.begin; + + visit_type_uint32(v, &value, name, errp); +} + +static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); + uint32_t value = s->pci_info.w32.end; + + visit_type_uint32(v, &value, name, errp); +} + +static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); + + visit_type_uint64(v, &s->pci_info.w64.begin, name, errp); +} + +static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); + + visit_type_uint64(v, &s->pci_info.w64.end, name, errp); +} + static void i440fx_pcihost_initfn(Object *obj) { PCIHostState *s = PCI_HOST_BRIDGE(obj); + I440FXState *d = I440FX_PCI_HOST_BRIDGE(obj); memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s, "pci-conf-idx", 4); memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s, "pci-conf-data", 4); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int", + i440fx_pcihost_get_pci_hole_start, + NULL, NULL, NULL, NULL); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int", + i440fx_pcihost_get_pci_hole_end, + NULL, NULL, NULL, NULL); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int", + i440fx_pcihost_get_pci_hole64_start, + NULL, NULL, NULL, NULL); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int", + i440fx_pcihost_get_pci_hole64_end, + NULL, NULL, NULL, NULL); + + d->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS; } static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) @@ -235,19 +300,17 @@ static int i440fx_initfn(PCIDevice *dev) return 0; } -static PCIBus *i440fx_common_init(const char *device_name, - PCII440FXState **pi440fx_state, - int *piix3_devfn, - ISABus **isa_bus, qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - hwaddr pci_hole_start, - hwaddr pci_hole_size, - hwaddr pci_hole64_start, - hwaddr pci_hole64_size, - MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) +PCIBus *i440fx_init(PCII440FXState **pi440fx_state, + int *piix3_devfn, + ISABus **isa_bus, qemu_irq *pic, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + ram_addr_t ram_size, + hwaddr pci_hole_start, + hwaddr pci_hole_size, + ram_addr_t above_4g_mem_size, + MemoryRegion *pci_address_space, + MemoryRegion *ram_memory) { DeviceState *dev; PCIBus *b; @@ -256,8 +319,9 @@ static PCIBus *i440fx_common_init(const char *device_name, PIIX3State *piix3; PCII440FXState *f; unsigned i; + I440FXState *i440fx; - dev = qdev_create(NULL, "i440FX-pcihost"); + dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE); s = PCI_HOST_BRIDGE(dev); b = pci_bus_new(dev, NULL, pci_address_space, address_space_io, 0, TYPE_PCI_BUS); @@ -265,20 +329,37 @@ static PCIBus *i440fx_common_init(const char *device_name, object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); qdev_init_nofail(dev); - d = pci_create_simple(b, 0, device_name); + d = pci_create_simple(b, 0, TYPE_I440FX_PCI_DEVICE); *pi440fx_state = I440FX_PCI_DEVICE(d); f = *pi440fx_state; f->system_memory = address_space_mem; f->pci_address_space = pci_address_space; f->ram_memory = ram_memory; + + i440fx = I440FX_PCI_HOST_BRIDGE(dev); + /* Set PCI window size the way seabios has always done it. */ + /* Power of 2 so bios can cover it with a single MTRR */ + if (ram_size <= 0x80000000) { + i440fx->pci_info.w32.begin = 0x80000000; + } else if (ram_size <= 0xc0000000) { + i440fx->pci_info.w32.begin = 0xc0000000; + } else { + i440fx->pci_info.w32.begin = 0xe0000000; + } + memory_region_init_alias(&f->pci_hole, OBJECT(d), "pci-hole", f->pci_address_space, pci_hole_start, pci_hole_size); memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole); + + pc_init_pci64_hole(&i440fx->pci_info, 0x100000000ULL + above_4g_mem_size, + i440fx->pci_hole64_size); memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64", f->pci_address_space, - pci_hole64_start, pci_hole64_size); - if (pci_hole64_size) { - memory_region_add_subregion(f->system_memory, pci_hole64_start, + i440fx->pci_info.w64.begin, + i440fx->pci_hole64_size); + if (i440fx->pci_hole64_size) { + memory_region_add_subregion(f->system_memory, + i440fx->pci_info.w64.begin, &f->pci_hole_64bit); } memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region", @@ -326,29 +407,6 @@ static PCIBus *i440fx_common_init(const char *device_name, return b; } -PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, - ISABus **isa_bus, qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - hwaddr pci_hole_start, - hwaddr pci_hole_size, - hwaddr pci_hole64_start, - hwaddr pci_hole64_size, - MemoryRegion *pci_memory, MemoryRegion *ram_memory) - -{ - PCIBus *b; - - b = i440fx_common_init(TYPE_I440FX_PCI_DEVICE, pi440fx_state, - piix3_devfn, isa_bus, pic, - address_space_mem, address_space_io, ram_size, - pci_hole_start, pci_hole_size, - pci_hole64_start, pci_hole64_size, - pci_memory, ram_memory); - return b; -} - /* PIIX3 PCI to ISA bridge */ static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) { @@ -649,6 +707,12 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge, return "0000"; } +static Property i440fx_props[] = { + DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState, + pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE), + DEFINE_PROP_END_OF_LIST(), +}; + static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -658,10 +722,11 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) dc->realize = i440fx_pcihost_realize; dc->fw_name = "pci"; dc->no_user = 1; + dc->props = i440fx_props; } static const TypeInfo i440fx_pcihost_info = { - .name = "i440FX-pcihost", + .name = TYPE_I440FX_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(I440FXState), .instance_init = i440fx_pcihost_initfn, diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 646204e1e5..f00793d819 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -407,6 +407,7 @@ static void e500_pcihost_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = e500_pcihost_initfn; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = pcihost_properties; dc->vmsd = &vmstate_ppce500_pci; } diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index b41d5646cd..e120058511 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -119,6 +119,8 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) MemoryRegion *address_space_mem = get_system_memory(); int i; + isa_mem_base = 0xc0000000; + for (i = 0; i < 4; i++) { sysbus_init_irq(dev, &s->irq[i]); } @@ -210,6 +212,7 @@ static void raven_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->realize = raven_pcihost_realizefn; dc->fw_name = "pci"; dc->no_user = 1; diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 6b1b3b7ab1..12314d8dfe 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -29,6 +29,7 @@ */ #include "hw/hw.h" #include "hw/pci-host/q35.h" +#include "qapi/visitor.h" /**************************************************************************** * Q35 host @@ -64,9 +65,49 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge, return "0000"; } +static void q35_host_get_pci_hole_start(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + Q35PCIHost *s = Q35_HOST_DEVICE(obj); + uint32_t value = s->mch.pci_info.w32.begin; + + visit_type_uint32(v, &value, name, errp); +} + +static void q35_host_get_pci_hole_end(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + Q35PCIHost *s = Q35_HOST_DEVICE(obj); + uint32_t value = s->mch.pci_info.w32.end; + + visit_type_uint32(v, &value, name, errp); +} + +static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + Q35PCIHost *s = Q35_HOST_DEVICE(obj); + + visit_type_uint64(v, &s->mch.pci_info.w64.begin, name, errp); +} + +static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + Q35PCIHost *s = Q35_HOST_DEVICE(obj); + + visit_type_uint64(v, &s->mch.pci_info.w64.end, name, errp); +} + static Property mch_props[] = { DEFINE_PROP_UINT64("MCFG", Q35PCIHost, parent_obj.base_addr, MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT), + DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost, + mch.pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE), DEFINE_PROP_END_OF_LIST(), }; @@ -78,6 +119,7 @@ static void q35_host_class_init(ObjectClass *klass, void *data) hc->root_bus_path = q35_host_root_bus_path; dc->realize = q35_host_realize; dc->props = mch_props; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "pci"; } @@ -95,6 +137,31 @@ static void q35_host_initfn(Object *obj) object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL); qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int", + q35_host_get_pci_hole_start, + NULL, NULL, NULL, NULL); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int", + q35_host_get_pci_hole_end, + NULL, NULL, NULL, NULL); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int", + q35_host_get_pci_hole64_start, + NULL, NULL, NULL, NULL); + + object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int", + q35_host_get_pci_hole64_end, + NULL, NULL, NULL, NULL); + + /* Leave enough space for the biggest MCFG BAR */ + /* TODO: this matches current bios behaviour, but + * it's not a power of two, which means an MTRR + * can't cover it exactly. + */ + s->mch.pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT + + MCH_HOST_BRIDGE_PCIEXBAR_MAX; + s->mch.pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS; } static const TypeInfo q35_host_info = { @@ -252,17 +319,8 @@ static void mch_reset(DeviceState *qdev) static int mch_init(PCIDevice *d) { int i; - hwaddr pci_hole64_size; MCHPCIState *mch = MCH_PCI_DEVICE(d); - /* Leave enough space for the biggest MCFG BAR */ - /* TODO: this matches current bios behaviour, but - * it's not a power of two, which means an MTRR - * can't cover it exactly. - */ - mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT + - MCH_HOST_BRIDGE_PCIEXBAR_MAX; - /* setup pci memory regions */ memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole", mch->pci_address_space, @@ -270,15 +328,16 @@ static int mch_init(PCIDevice *d) 0x100000000ULL - mch->below_4g_mem_size); memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size, &mch->pci_hole); - pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 : - ((uint64_t)1 << 62)); + + pc_init_pci64_hole(&mch->pci_info, 0x100000000ULL + mch->above_4g_mem_size, + mch->pci_hole64_size); memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch), "pci-hole64", mch->pci_address_space, - 0x100000000ULL + mch->above_4g_mem_size, - pci_hole64_size); - if (pci_hole64_size) { + mch->pci_info.w64.begin, + mch->pci_hole64_size); + if (mch->pci_hole64_size) { memory_region_add_subregion(mch->system_memory, - 0x100000000ULL + mch->above_4g_mem_size, + mch->pci_info.w64.begin, &mch->pci_hole_64bit); } /* smram */ @@ -306,6 +365,7 @@ static void mch_class_init(ObjectClass *klass, void *data) k->init = mch_init; k->config_write = mch_write_config; dc->reset = mch_reset; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Host bridge"; dc->vmsd = &vmstate_mch; k->vendor_id = PCI_VENDOR_ID_INTEL; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 81cf5a958c..4c004f5daa 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -397,7 +397,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) pci_update_mappings(s); if (pc->is_bridge) { - PCIBridge *b = container_of(s, PCIBridge, dev); + PCIBridge *b = PCI_BRIDGE(s); pci_bridge_update_mappings(b); } diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 02a396b01c..a90671d2f2 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -141,8 +141,9 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, MemoryRegion *parent_space, bool enabled) { - pcibus_t base = pci_bridge_get_base(&bridge->dev, type); - pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type); + PCIDevice *bridge_dev = PCI_DEVICE(bridge); + pcibus_t base = pci_bridge_get_base(bridge_dev, type); + pcibus_t limit = pci_bridge_get_limit(bridge_dev, type); /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly. * Apparently no way to do this with existing memory APIs. */ pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0; @@ -154,7 +155,8 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent, MemoryRegion *alias_vga) { - uint16_t brctl = pci_get_word(br->dev.config + PCI_BRIDGE_CONTROL); + PCIDevice *pd = PCI_DEVICE(br); + uint16_t brctl = pci_get_word(pd->config + PCI_BRIDGE_CONTROL); memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_LO], OBJECT(br), "pci_bridge_vga_io_lo", &br->address_space_io, @@ -167,7 +169,7 @@ static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent, QEMU_PCI_VGA_MEM_BASE, QEMU_PCI_VGA_MEM_SIZE); if (brctl & PCI_BRIDGE_CTL_VGA) { - pci_register_vga(&br->dev, &alias_vga[QEMU_PCI_VGA_MEM], + pci_register_vga(pd, &alias_vga[QEMU_PCI_VGA_MEM], &alias_vga[QEMU_PCI_VGA_IO_LO], &alias_vga[QEMU_PCI_VGA_IO_HI]); } @@ -175,9 +177,10 @@ static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent, static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) { - PCIBus *parent = br->dev.bus; + PCIDevice *pd = PCI_DEVICE(br); + PCIBus *parent = pd->bus; PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); - uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); + uint16_t cmd = pci_get_word(pd->config + PCI_COMMAND); pci_bridge_init_alias(br, &w->alias_pref_mem, PCI_BASE_ADDRESS_MEM_PREFETCH, @@ -205,12 +208,13 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) { - PCIBus *parent = br->dev.bus; + PCIDevice *pd = PCI_DEVICE(br); + PCIBus *parent = pd->bus; memory_region_del_subregion(parent->address_space_io, &w->alias_io); memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); - pci_unregister_vga(&br->dev); + pci_unregister_vga(pd); } static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) @@ -241,7 +245,7 @@ void pci_bridge_update_mappings(PCIBridge *br) void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { - PCIBridge *s = container_of(d, PCIBridge, dev); + PCIBridge *s = PCI_BRIDGE(d); uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); uint16_t newctl; @@ -331,7 +335,7 @@ void pci_bridge_reset(DeviceState *qdev) int pci_bridge_initfn(PCIDevice *dev, const char *typename) { PCIBus *parent = dev->bus; - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); + PCIBridge *br = PCI_BRIDGE(dev); PCIBus *sec_bus = &br->sec_bus; pci_word_test_and_set_mask(dev->config + PCI_STATUS, @@ -379,7 +383,7 @@ int pci_bridge_initfn(PCIDevice *dev, const char *typename) /* default qdev clean up function for PCI-to-PCI bridge */ void pci_bridge_exitfn(PCIDevice *pci_dev) { - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); + PCIBridge *s = PCI_BRIDGE(pci_dev); assert(QLIST_EMPTY(&s->sec_bus.child)); QLIST_REMOVE(&s->sec_bus, sibling); pci_bridge_region_del(s, s->windows); @@ -400,3 +404,17 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, br->map_irq = map_irq; br->bus_name = bus_name; } + +static const TypeInfo pci_bridge_type_info = { + .name = TYPE_PCI_BRIDGE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIBridge), + .abstract = true, +}; + +static void pci_bridge_register_types(void) +{ + type_register_static(&pci_bridge_type_info); +} + +type_init(pci_bridge_register_types) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 62bd0b8b3e..50af3c1dfe 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -305,7 +305,7 @@ void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) dev->exp.hpev_notified = false; - pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), + pci_bus_hotplug(pci_bridge_get_sec_bus(PCI_BRIDGE(dev)), pcie_cap_slot_hotplug, &dev->qdev); } diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 91b53a0fc2..2adb0300f4 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -116,3 +116,55 @@ void pcie_chassis_del_slot(PCIESlot *s) { QLIST_REMOVE(s, next); } + +static Property pcie_port_props[] = { + DEFINE_PROP_UINT8("port", PCIEPort, port, 0), + DEFINE_PROP_UINT16("aer_log_max", PCIEPort, + parent_obj.parent_obj.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), + DEFINE_PROP_END_OF_LIST() +}; + +static void pcie_port_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->props = pcie_port_props; +} + +static const TypeInfo pcie_port_type_info = { + .name = TYPE_PCIE_PORT, + .parent = TYPE_PCI_BRIDGE, + .instance_size = sizeof(PCIEPort), + .abstract = true, + .class_init = pcie_port_class_init, +}; + +static Property pcie_slot_props[] = { + DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), + DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void pcie_slot_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->props = pcie_slot_props; +} + +static const TypeInfo pcie_slot_type_info = { + .name = TYPE_PCIE_SLOT, + .parent = TYPE_PCIE_PORT, + .instance_size = sizeof(PCIESlot), + .abstract = true, + .class_init = pcie_slot_class_init, +}; + +static void pcie_port_register_types(void) +{ + type_register_static(&pcie_port_type_info); + type_register_static(&pcie_slot_type_info); +} + +type_init(pcie_port_register_types) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index f00a62a1ca..e79612b0e9 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -124,13 +124,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset, } static int ppce500_load_device_tree(CPUPPCState *env, + QEMUMachineInitArgs *args, PPCE500Params *params, hwaddr addr, hwaddr initrd_base, hwaddr initrd_size) { int ret = -1; - uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) }; + uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) }; int fdt_size; void *fdt; uint8_t hypercall[16]; @@ -205,7 +206,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, } ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - params->kernel_cmdline); + args->kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); @@ -559,7 +560,7 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, return mpic; } -void ppce500_init(PPCE500Params *params) +void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -584,8 +585,8 @@ void ppce500_init(PPCE500Params *params) PPCE500CCSRState *ccsr; /* Setup CPUs */ - if (params->cpu_model == NULL) { - params->cpu_model = "e500v2_v30"; + if (args->cpu_model == NULL) { + args->cpu_model = "e500v2_v30"; } irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); @@ -595,7 +596,7 @@ void ppce500_init(PPCE500Params *params) CPUState *cs; qemu_irq *input; - cpu = cpu_ppc_init(params->cpu_model); + cpu = cpu_ppc_init(args->cpu_model); if (cpu == NULL) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); @@ -634,7 +635,7 @@ void ppce500_init(PPCE500Params *params) /* Fixup Memory size on a alignment boundary */ ram_size &= ~(RAM_SIZES_ALIGN - 1); - params->ram_size = ram_size; + args->ram_size = ram_size; /* Register Memory */ memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size); @@ -701,11 +702,11 @@ void ppce500_init(PPCE500Params *params) sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); /* Load kernel. */ - if (params->kernel_filename) { - kernel_size = load_uimage(params->kernel_filename, &entry, + if (args->kernel_filename) { + kernel_size = load_uimage(args->kernel_filename, &entry, &loadaddr, NULL); if (kernel_size < 0) { - kernel_size = load_elf(params->kernel_filename, NULL, NULL, + kernel_size = load_elf(args->kernel_filename, NULL, NULL, &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); entry = elf_entry; @@ -714,7 +715,7 @@ void ppce500_init(PPCE500Params *params) /* XXX try again as binary */ if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - params->kernel_filename); + args->kernel_filename); exit(1); } @@ -726,14 +727,14 @@ void ppce500_init(PPCE500Params *params) } /* Load initrd. */ - if (params->initrd_filename) { + if (args->initrd_filename) { initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; - initrd_size = load_image_targphys(params->initrd_filename, initrd_base, + initrd_size = load_image_targphys(args->initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - params->initrd_filename); + args->initrd_filename); exit(1); } @@ -741,12 +742,12 @@ void ppce500_init(PPCE500Params *params) } /* If we're loading a kernel directly, we must load the device tree too. */ - if (params->kernel_filename) { + if (args->kernel_filename) { struct boot_info *boot_info; int dt_size; - dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, - initrd_size); + dt_size = ppce500_load_device_tree(env, args, params, dt_base, + initrd_base, initrd_size); if (dt_size < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 226c93d248..52726a2ec0 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -1,25 +1,18 @@ #ifndef PPCE500_H #define PPCE500_H +#include "hw/boards.h" + typedef struct PPCE500Params { - /* Standard QEMU machine init params */ - ram_addr_t ram_size; - const char *boot_device; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; - const char *cpu_model; int pci_first_slot; int pci_nr_slots; - /* e500-specific params */ - /* required -- must at least add toplevel board compatible */ void (*fixup_devtree)(struct PPCE500Params *params, void *fdt); int mpic_version; } PPCE500Params; -void ppce500_init(PPCE500Params *params); +void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params); #endif diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index c85299588c..bf65b69366 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -30,19 +30,7 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) static void e500plat_init(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *boot_device = args->boot_device; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; PPCE500Params params = { - .ram_size = ram_size, - .boot_device = boot_device, - .kernel_filename = kernel_filename, - .kernel_cmdline = kernel_cmdline, - .initrd_filename = initrd_filename, - .cpu_model = cpu_model, .pci_first_slot = 0x1, .pci_nr_slots = PCI_SLOT_MAX - 1, .fixup_devtree = e500plat_fixup_devtree, @@ -55,7 +43,7 @@ static void e500plat_init(QEMUMachineInitArgs *args) params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20; } - ppce500_init(¶ms); + ppce500_init(args, ¶ms); } static QEMUMachine e500plat_machine = { diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index fe803480a7..7ef806ef7f 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -152,6 +152,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) CPUPPCState *env = NULL; char *filename; qemu_irq *pic, **openpic_irqs; + MemoryRegion *isa = g_new(MemoryRegion, 1); MemoryRegion *unin_memory = g_new(MemoryRegion, 1); MemoryRegion *unin2_memory = g_new(MemoryRegion, 1); int linux_boot, i, j, k; @@ -288,7 +289,9 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) } /* Register 8 MB of ISA IO space */ - isa_mmio_init(0xf2000000, 0x00800000); + memory_region_init_alias(isa, NULL, "isa_mmio", + get_system_io(), 0, 0x00800000); + memory_region_add_subregion(get_system_memory(), 0xf2000000, isa); /* UniN init: XXX should be a real device */ memory_region_init_io(unin_memory, NULL, &unin_ops, token, "unin", 0x1000); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 8b8c6b93a5..42bb9d55c8 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -87,6 +87,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) int linux_boot, i; MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); + MemoryRegion *isa = g_new(MemoryRegion, 1); uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; @@ -225,7 +226,9 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) } /* Register 2 MB of ISA IO space */ - isa_mmio_init(0xfe000000, 0x00200000); + memory_region_init_alias(isa, NULL, "isa_mmio", + get_system_io(), 0, 0x00200000); + memory_region_add_subregion(sysmem, 0xfe000000, isa); /* XXX: we register only 1 output pin for heathrow PIC */ heathrow_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 444da0246d..1888e75545 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -28,26 +28,14 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) static void mpc8544ds_init(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *boot_device = args->boot_device; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; PPCE500Params params = { - .ram_size = ram_size, - .boot_device = boot_device, - .kernel_filename = kernel_filename, - .kernel_cmdline = kernel_cmdline, - .initrd_filename = initrd_filename, - .cpu_model = cpu_model, .pci_first_slot = 0x11, .pci_nr_slots = 2, .fixup_devtree = mpc8544ds_fixup_devtree, .mpic_version = OPENPIC_MODEL_FSL_MPIC_20, }; - ppce500_init(¶ms); + ppce500_init(args, ¶ms); } diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index e1c095c7e2..59b41cbc6f 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -471,7 +471,7 @@ uint64_t cpu_ppc_load_tbl (CPUPPCState *env) return env->spr[SPR_TBL]; } - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); return tb; @@ -482,7 +482,7 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); return tb >> 32; @@ -510,9 +510,9 @@ void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); tb &= 0xFFFFFFFF00000000ULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), &tb_env->tb_offset, tb | (uint64_t)value); } @@ -521,9 +521,9 @@ static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); tb &= 0x00000000FFFFFFFFULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), &tb_env->tb_offset, ((uint64_t)value << 32) | tb); } @@ -537,7 +537,7 @@ uint64_t cpu_ppc_load_atbl (CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); return tb; @@ -548,7 +548,7 @@ uint32_t cpu_ppc_load_atbu (CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); return tb >> 32; @@ -559,9 +559,9 @@ void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); tb &= 0xFFFFFFFF00000000ULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), &tb_env->atb_offset, tb | (uint64_t)value); } @@ -570,9 +570,9 @@ void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); tb &= 0x00000000FFFFFFFFULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), &tb_env->atb_offset, ((uint64_t)value << 32) | tb); } @@ -583,7 +583,7 @@ static void cpu_ppc_tb_stop (CPUPPCState *env) /* If the time base is already frozen, do nothing */ if (tb_env->tb_freq != 0) { - vmclk = qemu_get_clock_ns(vm_clock); + vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Get the time base */ tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); /* Get the alternate time base */ @@ -605,7 +605,7 @@ static void cpu_ppc_tb_start (CPUPPCState *env) /* If the time base is not frozen, do nothing */ if (tb_env->tb_freq == 0) { - vmclk = qemu_get_clock_ns(vm_clock); + vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Get the time base from tb_offset */ tb = tb_env->tb_offset; /* Get the alternate time base from atb_offset */ @@ -625,7 +625,7 @@ static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) uint32_t decr; int64_t diff; - diff = next - qemu_get_clock_ns(vm_clock); + diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (diff >= 0) { decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec()); } else if (tb_env->flags & PPC_TIMER_BOOKE) { @@ -661,7 +661,7 @@ uint64_t cpu_ppc_load_purr (CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t diff; - diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start; + diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start; return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec()); } @@ -701,7 +701,7 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, return; } - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq); if (is_excp) { next += *nextp - now; @@ -711,7 +711,7 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, } *nextp = next; /* Adjust timer */ - qemu_mod_timer(timer, next); + timer_mod(timer, next); /* If we set a negative value and the decrementer was positive, raise an * exception. @@ -776,7 +776,7 @@ static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) ppc_tb_t *tb_env = cpu->env.tb_env; tb_env->purr_load = value; - tb_env->purr_start = qemu_get_clock_ns(vm_clock); + tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) @@ -806,11 +806,11 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) env->tb_env = tb_env; tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; /* Create new timer */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu); + tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); if (0) { /* XXX: find a suitable condition to enable the hypervisor decrementer */ - tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, + tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, cpu); } else { tb_env->hdecr_timer = NULL; @@ -877,7 +877,7 @@ static void cpu_4xx_fit_cb (void *opaque) cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { case 0: next = 1 << 9; @@ -898,7 +898,7 @@ static void cpu_4xx_fit_cb (void *opaque) next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq); if (next == now) next++; - qemu_mod_timer(ppc40x_timer->fit_timer, next); + timer_mod(ppc40x_timer->fit_timer, next); env->spr[SPR_40x_TSR] |= 1 << 26; if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); @@ -920,18 +920,18 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { /* Stop PIT */ LOG_TB("%s: stop PIT\n", __func__); - qemu_del_timer(tb_env->decr_timer); + timer_del(tb_env->decr_timer); } else { LOG_TB("%s: start PIT %016" PRIx64 "\n", __func__, ppc40x_timer->pit_reload); - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); next = now + muldiv64(ppc40x_timer->pit_reload, get_ticks_per_sec(), tb_env->decr_freq); if (is_excp) next += tb_env->decr_next - now; if (next == now) next++; - qemu_mod_timer(tb_env->decr_timer, next); + timer_mod(tb_env->decr_timer, next); tb_env->decr_next = next; } } @@ -973,7 +973,7 @@ static void cpu_4xx_wdt_cb (void *opaque) cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { case 0: next = 1 << 17; @@ -999,12 +999,12 @@ static void cpu_4xx_wdt_cb (void *opaque) switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { case 0x0: case 0x1: - qemu_mod_timer(ppc40x_timer->wdt_timer, next); + timer_mod(ppc40x_timer->wdt_timer, next); ppc40x_timer->wdt_next = next; env->spr[SPR_40x_TSR] |= 1 << 31; break; case 0x2: - qemu_mod_timer(ppc40x_timer->wdt_timer, next); + timer_mod(ppc40x_timer->wdt_timer, next); ppc40x_timer->wdt_next = next; env->spr[SPR_40x_TSR] |= 1 << 30; if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { @@ -1076,11 +1076,11 @@ clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, LOG_TB("%s freq %" PRIu32 "\n", __func__, freq); if (ppc40x_timer != NULL) { /* We use decr timer for PIT */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env); + tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env); ppc40x_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env); + timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env); ppc40x_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env); + timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env); ppc40x_timer->decr_excp = decr_excp; } diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 290f71ab69..0ef5254cd7 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -1348,7 +1348,7 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr) switch (addr) { case 0x00: /* Time base counter */ - ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset, + ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + gpt->tb_offset, gpt->tb_freq, get_ticks_per_sec()); break; case 0x10: @@ -1405,7 +1405,7 @@ static void ppc4xx_gpt_writel (void *opaque, case 0x00: /* Time base counter */ gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq) - - qemu_get_clock_ns(vm_clock); + - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ppc4xx_gpt_compute_timer(gpt); break; case 0x10: @@ -1476,7 +1476,7 @@ static void ppc4xx_gpt_reset (void *opaque) int i; gpt = opaque; - qemu_del_timer(gpt->timer); + timer_del(gpt->timer); gpt->oe = 0x00000000; gpt->ol = 0x00000000; gpt->im = 0x00000000; @@ -1497,7 +1497,7 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) for (i = 0; i < 5; i++) { gpt->irqs[i] = irqs[i]; } - gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt); + gpt->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ppc4xx_gpt_cb, gpt); #ifdef DEBUG_GPT printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); #endif diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 5b039abb38..369ab9e26e 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -164,6 +164,7 @@ static void bamboo_init(QEMUMachineInitArgs *args) const char *initrd_filename = args->initrd_filename; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *isa = g_new(MemoryRegion, 1); MemoryRegion *ram_memories = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS]; @@ -225,7 +226,9 @@ static void bamboo_init(QEMUMachineInitArgs *args) exit(1); } - isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); + memory_region_init_alias(isa, NULL, "isa_mmio", + get_system_io(), 0, PPC440EP_PCI_IOLEN); + memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa); if (serial_hds[0] != NULL) { serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index 000c27f2e8..8bbfc728de 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -136,7 +136,7 @@ static void booke_update_fixed_timer(CPUPPCState *env, uint64_t period; uint64_t now; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset); period = 1ULL << target_bit; delta_tick = period - (tb & (period - 1)); @@ -167,7 +167,7 @@ static void booke_update_fixed_timer(CPUPPCState *env, (*next)++; } - qemu_mod_timer(timer, *next); + timer_mod(timer, *next); } static void booke_decr_cb(void *opaque) @@ -303,12 +303,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) tb_env->tb_freq = freq; tb_env->decr_freq = freq; tb_env->opaque = booke_timer; - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu); + tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_decr_cb, cpu); booke_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); + timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_fit_cb, cpu); booke_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); + timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_wdt_cb, cpu); ret = kvmppc_booke_watchdog_enable(cpu); diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index 11b7de2f30..78b23fa597 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -42,8 +42,12 @@ typedef struct spin_info { uint64_t reserved; } QEMU_PACKED SpinInfo; -typedef struct spin_state { - SysBusDevice busdev; +#define TYPE_E500_SPIN "e500-spin" +#define E500_SPIN(obj) OBJECT_CHECK(SpinState, (obj), TYPE_E500_SPIN) + +typedef struct SpinState { + SysBusDevice parent_obj; + MemoryRegion iomem; SpinInfo spin[MAX_CPUS]; } SpinState; @@ -187,9 +191,7 @@ static const MemoryRegionOps spin_rw_ops = { static int ppce500_spin_initfn(SysBusDevice *dev) { - SpinState *s; - - s = FROM_SYSBUS(SpinState, SYS_BUS_DEVICE(dev)); + SpinState *s = E500_SPIN(dev); memory_region_init_io(&s->iomem, OBJECT(s), &spin_rw_ops, s, "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS); @@ -208,7 +210,7 @@ static void ppce500_spin_class_init(ObjectClass *klass, void *data) } static const TypeInfo ppce500_spin_info = { - .name = "e500-spin", + .name = TYPE_E500_SPIN, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpinState), .class_init = ppce500_spin_class_init, diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 19f2442482..7e04b1ac84 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -410,7 +410,7 @@ static const MemoryRegionOps PPC_prep_io_ops = { .read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl }, .write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel }, }, - .endianness = DEVICE_LITTLE_ENDIAN, + .endianness = DEVICE_NATIVE_ENDIAN, }; #define NVRAM_SIZE 0x2000 diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 48ae09283d..4b566aa410 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -32,6 +32,7 @@ #include "sysemu/cpus.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" +#include "mmu-hash64.h" #include "hw/boards.h" #include "hw/ppc/ppc.h" @@ -128,6 +129,34 @@ int spapr_allocate_irq_block(int num, bool lsi) return first; } +static XICSState *try_create_xics(const char *type, int nr_servers, + int nr_irqs) +{ + DeviceState *dev; + + dev = qdev_create(NULL, type); + qdev_prop_set_uint32(dev, "nr_servers", nr_servers); + qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs); + if (qdev_init(dev) < 0) { + return NULL; + } + + return XICS(dev); +} + +static XICSState *xics_system_init(int nr_servers, int nr_irqs) +{ + XICSState *icp = NULL; + + icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs); + if (!icp) { + perror("Failed to create XICS\n"); + abort(); + } + + return icp; +} + static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; @@ -666,7 +695,7 @@ static void spapr_cpu_reset(void *opaque) env->spr[SPR_HIOR] = 0; - env->external_htab = spapr->htab; + env->external_htab = (uint8_t *)spapr->htab; env->htab_base = -1; env->htab_mask = HTAB_SIZE(spapr) - 1; env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | @@ -710,6 +739,330 @@ static int spapr_vga_init(PCIBus *pci_bus) } } +static const VMStateDescription vmstate_spapr = { + .name = "spapr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(next_irq, sPAPREnvironment), + + /* RTC offset */ + VMSTATE_UINT64(rtc_offset, sPAPREnvironment), + + VMSTATE_END_OF_LIST() + }, +}; + +#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) +#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID) +#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY) +#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY)) + +static int htab_save_setup(QEMUFile *f, void *opaque) +{ + sPAPREnvironment *spapr = opaque; + + /* "Iteration" header */ + qemu_put_be32(f, spapr->htab_shift); + + if (spapr->htab) { + spapr->htab_save_index = 0; + spapr->htab_first_pass = true; + } else { + assert(kvm_enabled()); + + spapr->htab_fd = kvmppc_get_htab_fd(false); + if (spapr->htab_fd < 0) { + fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", + strerror(errno)); + return -1; + } + } + + + return 0; +} + +static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, + int64_t max_ns) +{ + int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; + int index = spapr->htab_save_index; + int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + assert(spapr->htab_first_pass); + + do { + int chunkstart; + + /* Consume invalid HPTEs */ + while ((index < htabslots) + && !HPTE_VALID(HPTE(spapr->htab, index))) { + index++; + CLEAN_HPTE(HPTE(spapr->htab, index)); + } + + /* Consume valid HPTEs */ + chunkstart = index; + while ((index < htabslots) + && HPTE_VALID(HPTE(spapr->htab, index))) { + index++; + CLEAN_HPTE(HPTE(spapr->htab, index)); + } + + if (index > chunkstart) { + int n_valid = index - chunkstart; + + qemu_put_be32(f, chunkstart); + qemu_put_be16(f, n_valid); + qemu_put_be16(f, 0); + qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), + HASH_PTE_SIZE_64 * n_valid); + + if ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { + break; + } + } + } while ((index < htabslots) && !qemu_file_rate_limit(f)); + + if (index >= htabslots) { + assert(index == htabslots); + index = 0; + spapr->htab_first_pass = false; + } + spapr->htab_save_index = index; +} + +static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, + int64_t max_ns) +{ + bool final = max_ns < 0; + int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; + int examined = 0, sent = 0; + int index = spapr->htab_save_index; + int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + assert(!spapr->htab_first_pass); + + do { + int chunkstart, invalidstart; + + /* Consume non-dirty HPTEs */ + while ((index < htabslots) + && !HPTE_DIRTY(HPTE(spapr->htab, index))) { + index++; + examined++; + } + + chunkstart = index; + /* Consume valid dirty HPTEs */ + while ((index < htabslots) + && HPTE_DIRTY(HPTE(spapr->htab, index)) + && HPTE_VALID(HPTE(spapr->htab, index))) { + CLEAN_HPTE(HPTE(spapr->htab, index)); + index++; + examined++; + } + + invalidstart = index; + /* Consume invalid dirty HPTEs */ + while ((index < htabslots) + && HPTE_DIRTY(HPTE(spapr->htab, index)) + && !HPTE_VALID(HPTE(spapr->htab, index))) { + CLEAN_HPTE(HPTE(spapr->htab, index)); + index++; + examined++; + } + + if (index > chunkstart) { + int n_valid = invalidstart - chunkstart; + int n_invalid = index - invalidstart; + + qemu_put_be32(f, chunkstart); + qemu_put_be16(f, n_valid); + qemu_put_be16(f, n_invalid); + qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), + HASH_PTE_SIZE_64 * n_valid); + sent += index - chunkstart; + + if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { + break; + } + } + + if (examined >= htabslots) { + break; + } + + if (index >= htabslots) { + assert(index == htabslots); + index = 0; + } + } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final)); + + if (index >= htabslots) { + assert(index == htabslots); + index = 0; + } + + spapr->htab_save_index = index; + + return (examined >= htabslots) && (sent == 0) ? 1 : 0; +} + +#define MAX_ITERATION_NS 5000000 /* 5 ms */ +#define MAX_KVM_BUF_SIZE 2048 + +static int htab_save_iterate(QEMUFile *f, void *opaque) +{ + sPAPREnvironment *spapr = opaque; + int rc = 0; + + /* Iteration header */ + qemu_put_be32(f, 0); + + if (!spapr->htab) { + assert(kvm_enabled()); + + rc = kvmppc_save_htab(f, spapr->htab_fd, + MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); + if (rc < 0) { + return rc; + } + } else if (spapr->htab_first_pass) { + htab_save_first_pass(f, spapr, MAX_ITERATION_NS); + } else { + rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS); + } + + /* End marker */ + qemu_put_be32(f, 0); + qemu_put_be16(f, 0); + qemu_put_be16(f, 0); + + return rc; +} + +static int htab_save_complete(QEMUFile *f, void *opaque) +{ + sPAPREnvironment *spapr = opaque; + + /* Iteration header */ + qemu_put_be32(f, 0); + + if (!spapr->htab) { + int rc; + + assert(kvm_enabled()); + + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); + if (rc < 0) { + return rc; + } + close(spapr->htab_fd); + spapr->htab_fd = -1; + } else { + htab_save_later_pass(f, spapr, -1); + } + + /* End marker */ + qemu_put_be32(f, 0); + qemu_put_be16(f, 0); + qemu_put_be16(f, 0); + + return 0; +} + +static int htab_load(QEMUFile *f, void *opaque, int version_id) +{ + sPAPREnvironment *spapr = opaque; + uint32_t section_hdr; + int fd = -1; + + if (version_id < 1 || version_id > 1) { + fprintf(stderr, "htab_load() bad version\n"); + return -EINVAL; + } + + section_hdr = qemu_get_be32(f); + + if (section_hdr) { + /* First section, just the hash shift */ + if (spapr->htab_shift != section_hdr) { + return -EINVAL; + } + return 0; + } + + if (!spapr->htab) { + assert(kvm_enabled()); + + fd = kvmppc_get_htab_fd(true); + if (fd < 0) { + fprintf(stderr, "Unable to open fd to restore KVM hash table: %s\n", + strerror(errno)); + } + } + + while (true) { + uint32_t index; + uint16_t n_valid, n_invalid; + + index = qemu_get_be32(f); + n_valid = qemu_get_be16(f); + n_invalid = qemu_get_be16(f); + + if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) { + /* End of Stream */ + break; + } + + if ((index + n_valid + n_invalid) > + (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) { + /* Bad index in stream */ + fprintf(stderr, "htab_load() bad index %d (%hd+%hd entries) " + "in htab stream (htab_shift=%d)\n", index, n_valid, n_invalid, + spapr->htab_shift); + return -EINVAL; + } + + if (spapr->htab) { + if (n_valid) { + qemu_get_buffer(f, HPTE(spapr->htab, index), + HASH_PTE_SIZE_64 * n_valid); + } + if (n_invalid) { + memset(HPTE(spapr->htab, index + n_valid), 0, + HASH_PTE_SIZE_64 * n_invalid); + } + } else { + int rc; + + assert(fd >= 0); + + rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid); + if (rc < 0) { + return rc; + } + } + } + + if (!spapr->htab) { + assert(fd >= 0); + close(fd); + } + + return 0; +} + +static SaveVMHandlers savevm_htab_handlers = { + .save_live_setup = htab_save_setup, + .save_live_iterate = htab_save_iterate, + .save_live_complete = htab_save_complete, + .load_state = htab_load, +}; + /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(QEMUMachineInitArgs *args) { @@ -848,9 +1201,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Set up EPOW events infrastructure */ spapr_events_init(spapr); - /* Set up IOMMU */ - spapr_iommu_init(); - /* Set up VIO bus */ spapr->vio_bus = spapr_vio_bus_init(); @@ -953,6 +1303,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr->entry_point = 0x100; + vmstate_register(NULL, 0, &vmstate_spapr, spapr); + register_savevm_live(NULL, "spapr/htab", -1, 1, + &savevm_htab_handlers, spapr); + /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index ed32decebf..67d6cd91d1 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -115,7 +115,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, } ppc_hash64_store_hpte1(env, hpte, ptel); /* eieio(); FIXME: need some sort of barrier for smp? */ - ppc_hash64_store_hpte0(env, hpte, pteh); + ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY); args[0] = pte_index + i; return H_SUCCESS; @@ -152,7 +152,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex, } *vp = v; *rp = r; - ppc_hash64_store_hpte0(env, hpte, 0); + ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY); rb = compute_tlbie_rb(v, r, ptex); ppc_tlb_invalidate_one(env, rb); return REMOVE_SUCCESS; @@ -282,11 +282,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, r |= (flags << 48) & HPTE64_R_KEY_HI; r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); rb = compute_tlbie_rb(v, r, pte_index); - ppc_hash64_store_hpte0(env, hpte, v & ~HPTE64_V_VALID); + ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY); ppc_tlb_invalidate_one(env, rb); ppc_hash64_store_hpte1(env, hpte, r); /* Don't need a memory barrier, due to qemu's global lock */ - ppc_hash64_store_hpte0(env, hpte, v); + ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY); return H_SUCCESS; } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 89b33a5478..3d4a1fcfe1 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -36,17 +36,6 @@ enum sPAPRTCEAccess { SPAPR_TCE_RW = 3, }; -struct sPAPRTCETable { - uint32_t liobn; - uint32_t window_size; - sPAPRTCE *table; - bool bypass; - int fd; - MemoryRegion iommu; - QLIST_ENTRY(sPAPRTCETable) list; -}; - - QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) @@ -96,7 +85,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr) return (IOMMUTLBEntry) { .perm = IOMMU_NONE }; } - tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce; + tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT]; #ifdef DEBUG_TCE fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n", @@ -112,55 +101,97 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr) }; } +static int spapr_tce_table_pre_load(void *opaque) +{ + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque); + + tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT; + + return 0; +} + +static const VMStateDescription vmstate_spapr_tce_table = { + .name = "spapr_iommu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_load = spapr_tce_table_pre_load, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable), + VMSTATE_UINT32_EQUAL(window_size, sPAPRTCETable), + + /* IOMMU state */ + VMSTATE_BOOL(bypass, sPAPRTCETable), + VMSTATE_VARRAY_UINT32(table, sPAPRTCETable, nb_table, 0, vmstate_info_uint64, uint64_t), + + VMSTATE_END_OF_LIST() + }, +}; + static MemoryRegionIOMMUOps spapr_iommu_ops = { .translate = spapr_tce_translate_iommu, }; -sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size) +static int spapr_tce_table_realize(DeviceState *dev) { - sPAPRTCETable *tcet; - - if (spapr_tce_find_by_liobn(liobn)) { - fprintf(stderr, "Attempted to create TCE table with duplicate" - " LIOBN 0x%x\n", liobn); - return NULL; - } - - if (!window_size) { - return NULL; - } - - tcet = g_malloc0(sizeof(*tcet)); - tcet->liobn = liobn; - tcet->window_size = window_size; + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); if (kvm_enabled()) { - tcet->table = kvmppc_create_spapr_tce(liobn, - window_size, + tcet->table = kvmppc_create_spapr_tce(tcet->liobn, + tcet->window_size, &tcet->fd); } if (!tcet->table) { - size_t table_size = (window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(uint64_t); tcet->table = g_malloc0(table_size); } + tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT; #ifdef DEBUG_TCE fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, " "table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd); #endif - memory_region_init_iommu(&tcet->iommu, OBJECT(owner), &spapr_iommu_ops, + memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops, "iommu-spapr", UINT64_MAX); QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); + return 0; +} + +sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size) +{ + sPAPRTCETable *tcet; + + if (spapr_tce_find_by_liobn(liobn)) { + fprintf(stderr, "Attempted to create TCE table with duplicate" + " LIOBN 0x%x\n", liobn); + return NULL; + } + + if (!window_size) { + return NULL; + } + + tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE)); + tcet->liobn = liobn; + tcet->window_size = window_size; + + object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL); + + qdev_init_nofail(DEVICE(tcet)); + return tcet; } -void spapr_tce_free(sPAPRTCETable *tcet) +static void spapr_tce_table_finalize(Object *obj) { + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj); + QLIST_REMOVE(tcet, list); if (!kvm_enabled() || @@ -168,8 +199,6 @@ void spapr_tce_free(sPAPRTCETable *tcet) tcet->window_size) != 0)) { g_free(tcet->table); } - - g_free(tcet); } MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet) @@ -182,10 +211,11 @@ void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass) tcet->bypass = bypass; } -void spapr_tce_reset(sPAPRTCETable *tcet) +static void spapr_tce_reset(DeviceState *dev) { + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); + * sizeof(uint64_t); tcet->bypass = false; memset(tcet->table, 0, table_size); @@ -194,7 +224,6 @@ void spapr_tce_reset(sPAPRTCETable *tcet) static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, target_ulong tce) { - sPAPRTCE *tcep; IOMMUTLBEntry entry; if (ioba >= tcet->window_size) { @@ -203,8 +232,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, return H_PARAMETER; } - tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT); - tcep->tce = tce; + tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT] = tce; entry.target_as = &address_space_memory, entry.iova = ioba & ~SPAPR_TCE_PAGE_MASK; @@ -238,14 +266,6 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_PARAMETER; } -void spapr_iommu_init(void) -{ - QLIST_INIT(&spapr_tce_tables); - - /* hcall-tce */ - spapr_register_hypercall(H_PUT_TCE, h_put_tce); -} - int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size) { @@ -286,3 +306,31 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, return spapr_dma_dt(fdt, node_off, propname, tcet->liobn, 0, tcet->window_size); } + +static void spapr_tce_table_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->vmsd = &vmstate_spapr_tce_table; + dc->init = spapr_tce_table_realize; + dc->reset = spapr_tce_reset; + + QLIST_INIT(&spapr_tce_tables); + + /* hcall-tce */ + spapr_register_hypercall(H_PUT_TCE, h_put_tce); +} + +static TypeInfo spapr_tce_table_info = { + .name = TYPE_SPAPR_TCE_TABLE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(sPAPRTCETable), + .class_init = spapr_tce_table_class_init, + .instance_finalize = spapr_tce_table_finalize, +}; + +static void register_types(void) +{ + type_register_static(&spapr_tce_table_info); +} + +type_init(register_types); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 318bc9d6ef..1ca35a0a72 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -440,43 +440,6 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); } -static uint64_t spapr_io_read(void *opaque, hwaddr addr, - unsigned size) -{ - switch (size) { - case 1: - return cpu_inb(addr); - case 2: - return cpu_inw(addr); - case 4: - return cpu_inl(addr); - } - g_assert_not_reached(); -} - -static void spapr_io_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - switch (size) { - case 1: - cpu_outb(addr, data); - return; - case 2: - cpu_outw(addr, data); - return; - case 4: - cpu_outl(addr, data); - return; - } - g_assert_not_reached(); -} - -static const MemoryRegionOps spapr_io_ops = { - .endianness = DEVICE_LITTLE_ENDIAN, - .read = spapr_io_read, - .write = spapr_io_write -}; - /* * MSI/MSIX memory region implementation. * The handler handles both MSI and MSIX. @@ -516,6 +479,7 @@ static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) static int spapr_phb_init(SysBusDevice *s) { + DeviceState *dev = DEVICE(s); sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); PCIHostState *phb = PCI_HOST_BRIDGE(s); const char *busname; @@ -605,8 +569,8 @@ static int spapr_phb_init(SysBusDevice *s) memory_region_add_subregion(get_system_io(), 0, &sphb->iospace); sprintf(namebuf, "%s.io-alias", sphb->dtbusname); - memory_region_init_io(&sphb->iowindow, OBJECT(sphb), &spapr_io_ops, sphb, - namebuf, SPAPR_PCI_IO_WIN_SIZE); + memory_region_init_alias(&sphb->iowindow, OBJECT(sphb), namebuf, + get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE); memory_region_add_subregion(get_system_memory(), sphb->io_win_addr, &sphb->iowindow); @@ -633,14 +597,14 @@ static int spapr_phb_init(SysBusDevice *s) * since it's unique by construction, and makes the guest visible * BUID clear. */ - if (s->qdev.id) { + if (dev->id) { busname = NULL; } else if (sphb->index == 0) { busname = "pci"; } else { busname = sphb->dtbusname; } - bus = pci_register_bus(DEVICE(s), busname, + bus = pci_register_bus(dev, busname, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS); @@ -648,7 +612,7 @@ static int spapr_phb_init(SysBusDevice *s) sphb->dma_window_start = 0; sphb->dma_window_size = 0x40000000; - sphb->tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn, + sphb->tcet = spapr_tce_new_table(dev, sphb->dma_liobn, sphb->dma_window_size); if (!sphb->tcet) { fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname); @@ -682,7 +646,7 @@ static void spapr_phb_reset(DeviceState *qdev) sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); /* Reset the IOMMU state */ - spapr_tce_reset(sphb->tcet); + device_reset(DEVICE(sphb->tcet)); } static Property spapr_phb_properties[] = { @@ -699,6 +663,54 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_pci_lsi = { + .name = "spapr_pci/lsi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi), + + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_pci_msi = { + .name = "spapr_pci/lsi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(config_addr, struct spapr_pci_msi), + VMSTATE_UINT32(irq, struct spapr_pci_msi), + VMSTATE_UINT32(nvec, struct spapr_pci_msi), + + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_pci = { + .name = "spapr_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState), + VMSTATE_UINT32_EQUAL(dma_liobn, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(mem_win_addr, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(msi_win_addr, sPAPRPHBState), + VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0, + vmstate_spapr_pci_lsi, struct spapr_pci_lsi), + VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0, + vmstate_spapr_pci_msi, struct spapr_pci_msi), + + VMSTATE_END_OF_LIST() + }, +}; + static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { @@ -717,6 +729,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) sdc->init = spapr_phb_init; dc->props = spapr_phb_properties; dc->reset = spapr_phb_reset; + dc->vmsd = &vmstate_spapr_pci; } static const TypeInfo spapr_phb_info = { diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 7c6f6e4275..a6a0a5113c 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -39,10 +39,10 @@ /* #define DEBUG_SPAPR */ #ifdef DEBUG_SPAPR -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { } while (0) #endif @@ -201,7 +201,7 @@ static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, dev->crq.qsize = queue_len; dev->crq.qnext = 0; - dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" + DPRINTF("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", reg, queue_addr, queue_len); return H_SUCCESS; @@ -213,7 +213,7 @@ static target_ulong free_crq(VIOsPAPRDevice *dev) dev->crq.qsize = 0; dev->crq.qnext = 0; - dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); + DPRINTF("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); return H_SUCCESS; } @@ -316,7 +316,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) { if (dev->tcet) { - spapr_tce_reset(dev->tcet); + device_reset(DEVICE(dev->tcet)); } free_crq(dev); } @@ -542,6 +542,26 @@ static const TypeInfo spapr_vio_bridge_info = { .class_init = spapr_vio_bridge_class_init, }; +const VMStateDescription vmstate_spapr_vio = { + .name = "spapr_vio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32_EQUAL(reg, VIOsPAPRDevice), + VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice), + + /* General VIO device state */ + VMSTATE_UINTTL(signal_state, VIOsPAPRDevice), + VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice), + VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice), + VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice), + + VMSTATE_END_OF_LIST() + }, +}; + static void vio_spapr_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 0aeb003c9d..d69adb2f5b 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -154,17 +154,19 @@ static void s390_ipl_reset(DeviceState *dev) env->psw.mask = IPL_PSW_MASK; if (!ipl->kernel) { - /* booting firmware, tell what device to boot from */ + /* Tell firmware, if there is a preferred boot device */ + env->regs[7] = -1; DeviceState *dev_st = get_boot_device(0); - VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( - OBJECT(&(dev_st->parent_obj)), "virtio-blk-ccw"); - - if (ccw_dev) { - env->regs[7] = ccw_dev->sch->cssid << 24 | - ccw_dev->sch->ssid << 16 | - ccw_dev->sch->devno; - } else { - env->regs[7] = -1; + if (dev_st) { + VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( + OBJECT(qdev_get_parent_bus(dev_st)->parent), + TYPE_VIRTIO_CCW_DEVICE); + + if (ccw_dev) { + env->regs[7] = ccw_dev->sch->cssid << 24 | + ccw_dev->sch->ssid << 16 | + ccw_dev->sch->devno; + } } } diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 207eb82e91..f0aa9414f2 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -38,10 +38,10 @@ /* #define DEBUG_S390 */ #ifdef DEBUG_S390 -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { } while (0) #endif diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index edbde00d4d..439d7323ec 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -41,10 +41,10 @@ //#define DEBUG_S390 #ifdef DEBUG_S390 -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { } while (0) #endif diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 2ac21d4487..d7ec1736c0 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -392,6 +392,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_AMD_SCSI; k->revision = 0x10; k->class_id = PCI_CLASS_STORAGE_SCSI; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter"; dc->reset = esp_pci_hard_reset; dc->vmsd = &vmstate_esp_pci_scsi; @@ -512,6 +513,7 @@ static void dc390_class_init(ObjectClass *klass, void *data) k->init = dc390_scsi_init; k->config_read = dc390_read_config; k->config_write = dc390_write_config; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "Tekram DC-390 SCSI adapter"; } diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 94639b8391..101e957d4d 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -720,6 +720,7 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data) dc->realize = sysbus_esp_realize; dc->reset = sysbus_esp_hard_reset; dc->vmsd = &vmstate_sysbus_esp_scsi; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sysbus_esp_info = { diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 776e31abbe..611f2aa1b2 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2141,6 +2141,7 @@ static void lsi_class_init(ObjectClass *klass, void *data) k->subsystem_id = 0x1000; dc->reset = lsi_scsi_reset; dc->vmsd = &vmstate_lsi_scsi; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo lsi_info = { diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index eb52164f6d..a6d5285911 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2213,6 +2213,7 @@ static void megasas_class_init(ObjectClass *oc, void *data) dc->props = megasas_properties; dc->reset = megasas_scsi_reset; dc->vmsd = &vmstate_megasas; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "LSI MegaRAID SAS 1078"; } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index b5a863aa5c..fbf9173fb4 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1881,6 +1881,7 @@ const VMStateDescription vmstate_scsi_device = { static void scsi_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_SCSI_BUS; k->init = scsi_qdev_init; k->unplug = scsi_qdev_unplug; diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 55b44b9910..e9090e5c72 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -45,10 +45,10 @@ /*#define DEBUG_VSCSI*/ #ifdef DEBUG_VSCSI -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { } while (0) #endif @@ -75,20 +75,19 @@ typedef struct vscsi_req { /* SCSI request tracking */ SCSIRequest *sreq; uint32_t qtag; /* qemu tag != srp tag */ - int lun; - int active; - long data_len; - int writing; - int senselen; + bool active; + uint32_t data_len; + bool writing; + uint32_t senselen; uint8_t sense[SCSI_SENSE_BUF_SIZE]; /* RDMA related bits */ uint8_t dma_fmt; - struct srp_direct_buf ext_desc; - struct srp_direct_buf *cur_desc; - struct srp_indirect_buf *ind_desc; - int local_desc; - int total_desc; + uint16_t local_desc; + uint16_t total_desc; + uint16_t cdb_offset; + uint16_t cur_desc_num; + uint16_t cur_desc_offset; } vscsi_req; #define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi" @@ -217,8 +216,9 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, union viosrp_iu *iu = &req->iu; uint64_t tag = iu->srp.rsp.tag; int total_len = sizeof(iu->srp.rsp); + uint8_t sol_not = iu->srp.cmd.sol_not; - dprintf("VSCSI: Sending resp status: 0x%x, " + DPRINTF("VSCSI: Sending resp status: 0x%x, " "res_in: %d, res_out: %d\n", status, res_in, res_out); memset(iu, 0, sizeof(struct srp_rsp)); @@ -249,7 +249,7 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, /* Handle success vs. failure */ iu->srp.rsp.status = status; if (status) { - iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2; + iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2; if (req->senselen) { req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen); @@ -257,114 +257,167 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, total_len += req->senselen; } } else { - iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1; + iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1; } vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT); return 0; } -static inline void vscsi_swap_desc(struct srp_direct_buf *desc) +static inline struct srp_direct_buf vscsi_swap_desc(struct srp_direct_buf desc) { - desc->va = be64_to_cpu(desc->va); - desc->len = be32_to_cpu(desc->len); + desc.va = be64_to_cpu(desc.va); + desc.len = be32_to_cpu(desc.len); + return desc; +} + +static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, + unsigned n, unsigned buf_offset, + struct srp_direct_buf *ret) +{ + struct srp_cmd *cmd = &req->iu.srp.cmd; + + switch (req->dma_fmt) { + case SRP_NO_DATA_DESC: { + DPRINTF("VSCSI: no data descriptor\n"); + return 0; + } + case SRP_DATA_DESC_DIRECT: { + memcpy(ret, cmd->add_data + req->cdb_offset, sizeof(*ret)); + assert(req->cur_desc_num == 0); + DPRINTF("VSCSI: direct segment\n"); + break; + } + case SRP_DATA_DESC_INDIRECT: { + struct srp_indirect_buf *tmp = (struct srp_indirect_buf *) + (cmd->add_data + req->cdb_offset); + if (n < req->local_desc) { + *ret = tmp->desc_list[n]; + DPRINTF("VSCSI: indirect segment local tag=0x%x desc#%d/%d\n", + req->qtag, n, req->local_desc); + + } else if (n < req->total_desc) { + int rc; + struct srp_direct_buf tbl_desc = vscsi_swap_desc(tmp->table_desc); + unsigned desc_offset = n * sizeof(struct srp_direct_buf); + + if (desc_offset >= tbl_desc.len) { + DPRINTF("VSCSI: #%d is ouf of range (%d bytes)\n", + n, desc_offset); + return -1; + } + rc = spapr_vio_dma_read(&s->vdev, tbl_desc.va + desc_offset, + ret, sizeof(struct srp_direct_buf)); + if (rc) { + DPRINTF("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n", + rc); + return -1; + } + DPRINTF("VSCSI: indirect segment ext. tag=0x%x desc#%d/%d { va=%"PRIx64" len=%x }\n", + req->qtag, n, req->total_desc, tbl_desc.va, tbl_desc.len); + } else { + DPRINTF("VSCSI: Out of descriptors !\n"); + return 0; + } + break; + } + default: + fprintf(stderr, "VSCSI: Unknown format %x\n", req->dma_fmt); + return -1; + } + + *ret = vscsi_swap_desc(*ret); + if (buf_offset > ret->len) { + DPRINTF(" offset=%x is out of a descriptor #%d boundary=%x\n", + buf_offset, req->cur_desc_num, ret->len); + return -1; + } + ret->va += buf_offset; + ret->len -= buf_offset; + + DPRINTF(" cur=%d offs=%x ret { va=%"PRIx64" len=%x }\n", + req->cur_desc_num, req->cur_desc_offset, ret->va, ret->len); + + return ret->len ? 1 : 0; } static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req, uint8_t *buf, uint32_t len) { - struct srp_direct_buf *md = req->cur_desc; + struct srp_direct_buf md; uint32_t llen; int rc = 0; - dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n", - len, (unsigned long long)md->va, md->len); + rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md); + if (rc < 0) { + return -1; + } else if (rc == 0) { + return 0; + } - llen = MIN(len, md->len); + llen = MIN(len, md.len); if (llen) { if (req->writing) { /* writing = to device = reading from memory */ - rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen); } else { - rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen); } } - md->len -= llen; - md->va += llen; if (rc) { return -1; } + req->cur_desc_offset += llen; + return llen; } static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, uint8_t *buf, uint32_t len) { - struct srp_direct_buf *td = &req->ind_desc->table_desc; - struct srp_direct_buf *md = req->cur_desc; + struct srp_direct_buf md; int rc = 0; uint32_t llen, total = 0; - dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n", - len, (unsigned long long)td->va, td->len); + DPRINTF("VSCSI: indirect segment 0x%x bytes\n", len); /* While we have data ... */ while (len) { - /* If we have a descriptor but it's empty, go fetch a new one */ - if (md && md->len == 0) { - /* More local available, use one */ - if (req->local_desc) { - md = ++req->cur_desc; - --req->local_desc; - --req->total_desc; - td->va += sizeof(struct srp_direct_buf); - } else { - md = req->cur_desc = NULL; - } - } - /* No descriptor at hand, fetch one */ - if (!md) { - if (!req->total_desc) { - dprintf("VSCSI: Out of descriptors !\n"); - break; - } - md = req->cur_desc = &req->ext_desc; - dprintf("VSCSI: Reading desc from 0x%llx\n", - (unsigned long long)td->va); - rc = spapr_vio_dma_read(&s->vdev, td->va, md, - sizeof(struct srp_direct_buf)); - if (rc) { - dprintf("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n", - rc); - break; - } - vscsi_swap_desc(md); - td->va += sizeof(struct srp_direct_buf); - --req->total_desc; + rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md); + if (rc < 0) { + return -1; + } else if (rc == 0) { + break; } - dprintf("VSCSI: [desc va=0x%llx,len=0x%x] remaining=0x%x\n", - (unsigned long long)md->va, md->len, len); /* Perform transfer */ - llen = MIN(len, md->len); + llen = MIN(len, md.len); if (req->writing) { /* writing = to device = reading from memory */ - rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen); } else { - rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen); } if (rc) { - dprintf("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc); + DPRINTF("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc); break; } - dprintf("VSCSI: data: %02x %02x %02x %02x...\n", + DPRINTF("VSCSI: data: %02x %02x %02x %02x...\n", buf[0], buf[1], buf[2], buf[3]); len -= llen; buf += llen; + total += llen; - md->va += llen; - md->len -= llen; + + /* Update current position in the current descriptor */ + req->cur_desc_offset += llen; + if (md.len == llen) { + /* Go to the next descriptor if the current one finished */ + ++req->cur_desc_num; + req->cur_desc_offset = 0; + } } + return rc ? -1 : total; } @@ -375,7 +428,7 @@ static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req, switch (req->dma_fmt) { case SRP_NO_DATA_DESC: - dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len); + DPRINTF("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len); break; case SRP_DATA_DESC_DIRECT: err = vscsi_srp_direct_data(s, req, buf, len); @@ -412,14 +465,13 @@ static int data_out_desc_size(struct srp_cmd *cmd) static int vscsi_preprocess_desc(vscsi_req *req) { struct srp_cmd *cmd = &req->iu.srp.cmd; - int offset, i; - offset = cmd->add_cdb_len & ~3; + req->cdb_offset = cmd->add_cdb_len & ~3; if (req->writing) { req->dma_fmt = cmd->buf_fmt >> 4; } else { - offset += data_out_desc_size(cmd); + req->cdb_offset += data_out_desc_size(cmd); req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1); } @@ -427,31 +479,18 @@ static int vscsi_preprocess_desc(vscsi_req *req) case SRP_NO_DATA_DESC: break; case SRP_DATA_DESC_DIRECT: - req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset); req->total_desc = req->local_desc = 1; - vscsi_swap_desc(req->cur_desc); - dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n", - req->writing ? "write" : "read", - req->cur_desc->len, (unsigned long long)req->cur_desc->va); break; - case SRP_DATA_DESC_INDIRECT: - req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset); - vscsi_swap_desc(&req->ind_desc->table_desc); - req->total_desc = req->ind_desc->table_desc.len / - sizeof(struct srp_direct_buf); + case SRP_DATA_DESC_INDIRECT: { + struct srp_indirect_buf *ind_tmp = (struct srp_indirect_buf *) + (cmd->add_data + req->cdb_offset); + + req->total_desc = be32_to_cpu(ind_tmp->table_desc.len) / + sizeof(struct srp_direct_buf); req->local_desc = req->writing ? cmd->data_out_desc_cnt : - cmd->data_in_desc_cnt; - for (i = 0; i < req->local_desc; i++) { - vscsi_swap_desc(&req->ind_desc->desc_list[i]); - } - req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL; - dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs " - "(%d local) VA: 0x%llx\n", - req->writing ? "read" : "write", - be32_to_cpu(req->ind_desc->len), - req->total_desc, req->local_desc, - (unsigned long long)req->ind_desc->table_desc.va); + cmd->data_in_desc_cnt; break; + } default: fprintf(stderr, "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt); @@ -469,7 +508,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) uint8_t *buf; int rc = 0; - dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", + DPRINTF("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", sreq->tag, len, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); @@ -499,8 +538,8 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re vscsi_req *req = sreq->hba_private; int32_t res_in = 0, res_out = 0; - dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n", - reason, sreq->tag, status, req); + DPRINTF("VSCSI: SCSI cmd complete, tag=0x%x status=0x%x, req=%p\n", + sreq->tag, status, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -509,16 +548,16 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re if (status == CHECK_CONDITION) { req->senselen = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense)); - dprintf("VSCSI: Sense data, %d bytes:\n", len); - dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + DPRINTF("VSCSI: Sense data, %d bytes:\n", req->senselen); + DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n", req->sense[0], req->sense[1], req->sense[2], req->sense[3], req->sense[4], req->sense[5], req->sense[6], req->sense[7]); - dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n", req->sense[8], req->sense[9], req->sense[10], req->sense[11], req->sense[12], req->sense[13], req->sense[14], req->sense[15]); } - dprintf("VSCSI: Command complete err=%d\n", status); + DPRINTF("VSCSI: Command complete err=%d\n", status); if (status == 0) { /* We handle overflows, not underflows for normal commands, * but hopefully nobody cares @@ -540,13 +579,76 @@ static void vscsi_request_cancelled(SCSIRequest *sreq) vscsi_put_req(req); } +static const VMStateDescription vmstate_spapr_vscsi_req = { + .name = "spapr_vscsi_req", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_BUFFER(crq.raw, vscsi_req), + VMSTATE_BUFFER(iu.srp.reserved, vscsi_req), + VMSTATE_UINT32(qtag, vscsi_req), + VMSTATE_BOOL(active, vscsi_req), + VMSTATE_UINT32(data_len, vscsi_req), + VMSTATE_BOOL(writing, vscsi_req), + VMSTATE_UINT32(senselen, vscsi_req), + VMSTATE_BUFFER(sense, vscsi_req), + VMSTATE_UINT8(dma_fmt, vscsi_req), + VMSTATE_UINT16(local_desc, vscsi_req), + VMSTATE_UINT16(total_desc, vscsi_req), + VMSTATE_UINT16(cdb_offset, vscsi_req), + /*Restart SCSI request from the beginning for now */ + /*VMSTATE_UINT16(cur_desc_num, vscsi_req), + VMSTATE_UINT16(cur_desc_offset, vscsi_req),*/ + VMSTATE_END_OF_LIST() + }, +}; + +static void vscsi_save_request(QEMUFile *f, SCSIRequest *sreq) +{ + vscsi_req *req = sreq->hba_private; + assert(req->active); + + vmstate_save_state(f, &vmstate_spapr_vscsi_req, req); + + DPRINTF("VSCSI: saving tag=%u, current desc#%d, offset=%x\n", + req->qtag, req->cur_desc_num, req->cur_desc_offset); +} + +static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq) +{ + SCSIBus *bus = sreq->bus; + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(bus->qbus.parent); + vscsi_req *req; + int rc; + + assert(sreq->tag < VSCSI_REQ_LIMIT); + req = &s->reqs[sreq->tag]; + assert(!req->active); + + memset(req, 0, sizeof(*req)); + rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1); + if (rc) { + fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag); + return NULL; + } + assert(req->active); + + req->sreq = scsi_req_ref(sreq); + + DPRINTF("VSCSI: restoring tag=%u, current desc#%d, offset=%x\n", + req->qtag, req->cur_desc_num, req->cur_desc_offset); + + return req; +} + static void vscsi_process_login(VSCSIState *s, vscsi_req *req) { union viosrp_iu *iu = &req->iu; struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; - dprintf("VSCSI: Got login, sendin response !\n"); + DPRINTF("VSCSI: Got login, sendin response !\n"); /* TODO handle case that requested size is wrong and * buffer format is wrong @@ -612,7 +714,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun); if (!sdev) { - dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun)); + DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n", + be64_to_cpu(srp->cmd.lun)); if (srp->cmd.cdb[0] == INQUIRY) { vscsi_inquiry_no_target(s, req); } else { @@ -621,12 +724,11 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) } return 1; } - req->lun = lun; req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req); n = scsi_req_enqueue(req->sreq); - dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", - req->qtag, srp->cmd.cdb[0], id, lun, n); + DPRINTF("VSCSI: Queued command tag 0x%x CMD 0x%x LUN %d ret: %d\n", + req->qtag, srp->cmd.cdb[0], lun, n); if (n) { /* Transfer direction must be set before preprocessing the @@ -838,7 +940,7 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) crq.s.IU_length = be16_to_cpu(crq.s.IU_length); crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr); - dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]); + DPRINTF("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]); switch (crq.s.valid) { case 0xc0: /* Init command/response */ @@ -895,7 +997,9 @@ static const struct SCSIBusInfo vscsi_scsi_info = { .transfer_data = vscsi_transfer_data, .complete = vscsi_command_complete, - .cancel = vscsi_request_cancelled + .cancel = vscsi_request_cancelled, + .save_request = vscsi_save_request, + .load_request = vscsi_load_request, }; static void spapr_vscsi_reset(VIOsPAPRDevice *dev) @@ -959,6 +1063,20 @@ static Property spapr_vscsi_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_vscsi = { + .name = "spapr_vscsi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SPAPR_VIO(vdev, VSCSIState), + /* VSCSI state */ + /* ???? */ + + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_vscsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -973,6 +1091,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) k->signal_mask = 0x00000001; dc->props = spapr_vscsi_properties; k->rtce_window_size = 0x10000000; + dc->vmsd = &vmstate_spapr_vscsi; } static const TypeInfo spapr_vscsi_info = { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 785e93f545..9e770fba98 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -267,6 +267,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = vhost_scsi_exit; dc->props = vhost_scsi_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = vhost_scsi_init; vdc->get_features = vhost_scsi_get_features; vdc->set_config = vhost_scsi_set_config; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 42cb73bb4e..05da56bd24 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -669,8 +669,10 @@ static Property virtio_scsi_properties[] = { static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) { VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); vdc->get_config = virtio_scsi_get_config; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static void virtio_scsi_class_init(ObjectClass *klass, void *data) @@ -679,6 +681,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_scsi_device_exit; dc->props = virtio_scsi_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = virtio_scsi_device_init; vdc->set_config = virtio_scsi_set_config; vdc->get_features = virtio_scsi_get_features; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index e1074e1d8d..d42b35941b 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1197,6 +1197,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data) dc->reset = pvscsi_reset; dc->vmsd = &vmstate_pvscsi; dc->props = pvscsi_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); k->config_write = pvscsi_write_config; } diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index f69775c41a..42613b3aff 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -58,8 +58,13 @@ enum { R_MAX }; +#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard" +#define MILKYMIST_MEMCARD(obj) \ + OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD) + struct MilkymistMemcardState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; SDState *card; @@ -231,8 +236,7 @@ static const MemoryRegionOps memcard_mmio_ops = { static void milkymist_memcard_reset(DeviceState *d) { - MilkymistMemcardState *s = - container_of(d, MilkymistMemcardState, busdev.qdev); + MilkymistMemcardState *s = MILKYMIST_MEMCARD(d); int i; s->command_write_ptr = 0; @@ -246,7 +250,7 @@ static void milkymist_memcard_reset(DeviceState *d) static int milkymist_memcard_init(SysBusDevice *dev) { - MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev); DriveInfo *dinfo; dinfo = drive_get_next(IF_SD); @@ -289,7 +293,7 @@ static void milkymist_memcard_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_memcard_info = { - .name = "milkymist-memcard", + .name = TYPE_MILKYMIST_MEMCARD, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistMemcardState), .class_init = milkymist_memcard_class_init, diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index f5eb1e4012..03875bf6ca 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -22,8 +22,12 @@ do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0) #define PL181_FIFO_LEN 16 -typedef struct { - SysBusDevice busdev; +#define TYPE_PL181 "pl181" +#define PL181(obj) OBJECT_CHECK(PL181State, (obj), TYPE_PL181) + +typedef struct PL181State { + SysBusDevice parent_obj; + MemoryRegion iomem; SDState *card; uint32_t clock; @@ -50,29 +54,29 @@ typedef struct { qemu_irq irq[2]; /* GPIO outputs for 'card is readonly' and 'card inserted' */ qemu_irq cardstatus[2]; -} pl181_state; +} PL181State; static const VMStateDescription vmstate_pl181 = { .name = "pl181", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(clock, pl181_state), - VMSTATE_UINT32(power, pl181_state), - VMSTATE_UINT32(cmdarg, pl181_state), - VMSTATE_UINT32(cmd, pl181_state), - VMSTATE_UINT32(datatimer, pl181_state), - VMSTATE_UINT32(datalength, pl181_state), - VMSTATE_UINT32(respcmd, pl181_state), - VMSTATE_UINT32_ARRAY(response, pl181_state, 4), - VMSTATE_UINT32(datactrl, pl181_state), - VMSTATE_UINT32(datacnt, pl181_state), - VMSTATE_UINT32(status, pl181_state), - VMSTATE_UINT32_ARRAY(mask, pl181_state, 2), - VMSTATE_INT32(fifo_pos, pl181_state), - VMSTATE_INT32(fifo_len, pl181_state), - VMSTATE_INT32(linux_hack, pl181_state), - VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN), + VMSTATE_UINT32(clock, PL181State), + VMSTATE_UINT32(power, PL181State), + VMSTATE_UINT32(cmdarg, PL181State), + VMSTATE_UINT32(cmd, PL181State), + VMSTATE_UINT32(datatimer, PL181State), + VMSTATE_UINT32(datalength, PL181State), + VMSTATE_UINT32(respcmd, PL181State), + VMSTATE_UINT32_ARRAY(response, PL181State, 4), + VMSTATE_UINT32(datactrl, PL181State), + VMSTATE_UINT32(datacnt, PL181State), + VMSTATE_UINT32(status, PL181State), + VMSTATE_UINT32_ARRAY(mask, PL181State, 2), + VMSTATE_INT32(fifo_pos, PL181State), + VMSTATE_INT32(fifo_len, PL181State), + VMSTATE_INT32(linux_hack, PL181State), + VMSTATE_UINT32_ARRAY(fifo, PL181State, PL181_FIFO_LEN), VMSTATE_END_OF_LIST() } }; @@ -125,7 +129,7 @@ static const VMStateDescription vmstate_pl181 = { static const unsigned char pl181_id[] = { 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; -static void pl181_update(pl181_state *s) +static void pl181_update(PL181State *s) { int i; for (i = 0; i < 2; i++) { @@ -133,7 +137,7 @@ static void pl181_update(pl181_state *s) } } -static void pl181_fifo_push(pl181_state *s, uint32_t value) +static void pl181_fifo_push(PL181State *s, uint32_t value) { int n; @@ -147,7 +151,7 @@ static void pl181_fifo_push(pl181_state *s, uint32_t value) DPRINTF("FIFO push %08x\n", (int)value); } -static uint32_t pl181_fifo_pop(pl181_state *s) +static uint32_t pl181_fifo_pop(PL181State *s) { uint32_t value; @@ -162,7 +166,7 @@ static uint32_t pl181_fifo_pop(pl181_state *s) return value; } -static void pl181_send_command(pl181_state *s) +static void pl181_send_command(PL181State *s) { SDRequest request; uint8_t response[16]; @@ -207,7 +211,7 @@ error: the FIFO holding 32-bit words and the card taking data in single byte chunks. FIFO bytes are transferred in little-endian order. */ -static void pl181_fifo_run(pl181_state *s) +static void pl181_fifo_run(PL181State *s) { uint32_t bits; uint32_t value = 0; @@ -288,7 +292,7 @@ static void pl181_fifo_run(pl181_state *s) static uint64_t pl181_read(void *opaque, hwaddr offset, unsigned size) { - pl181_state *s = (pl181_state *)opaque; + PL181State *s = (PL181State *)opaque; uint32_t tmp; if (offset >= 0xfe0 && offset < 0x1000) { @@ -372,7 +376,7 @@ static uint64_t pl181_read(void *opaque, hwaddr offset, static void pl181_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl181_state *s = (pl181_state *)opaque; + PL181State *s = (PL181State *)opaque; switch (offset) { case 0x00: /* Power */ @@ -449,7 +453,7 @@ static const MemoryRegionOps pl181_ops = { static void pl181_reset(DeviceState *d) { - pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d); + PL181State *s = PL181(d); s->power = 0; s->cmdarg = 0; @@ -474,16 +478,17 @@ static void pl181_reset(DeviceState *d) sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); } -static int pl181_init(SysBusDevice *dev) +static int pl181_init(SysBusDevice *sbd) { - pl181_state *s = FROM_SYSBUS(pl181_state, dev); + DeviceState *dev = DEVICE(sbd); + PL181State *s = PL181(dev); DriveInfo *dinfo; memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq[0]); - sysbus_init_irq(dev, &s->irq[1]); - qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq[0]); + sysbus_init_irq(sbd, &s->irq[1]); + qdev_init_gpio_out(dev, s->cardstatus, 2); dinfo = drive_get_next(IF_SD); s->card = sd_init(dinfo ? dinfo->bdrv : NULL, false); return 0; @@ -501,9 +506,9 @@ static void pl181_class_init(ObjectClass *klass, void *data) } static const TypeInfo pl181_info = { - .name = "pl181", + .name = TYPE_PL181, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl181_state), + .instance_size = sizeof(PL181State), .class_init = pl181_class_init, }; diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index d2dbddc11e..1483e196cd 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -134,8 +134,8 @@ static void sdhci_raise_insertion_irq(void *opaque) SDHCIState *s = (SDHCIState *)opaque; if (s->norintsts & SDHC_NIS_REMOVE) { - qemu_mod_timer(s->insert_timer, - qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY); + timer_mod(s->insert_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); } else { s->prnsts = 0x1ff0000; if (s->norintstsen & SDHC_NISEN_INSERT) { @@ -152,8 +152,8 @@ static void sdhci_insert_eject_cb(void *opaque, int irq, int level) if ((s->norintsts & SDHC_NIS_REMOVE) && level) { /* Give target some time to notice card ejection */ - qemu_mod_timer(s->insert_timer, - qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY); + timer_mod(s->insert_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); } else { if (level) { s->prnsts = 0x1ff0000; @@ -186,8 +186,8 @@ static void sdhci_card_readonly_cb(void *opaque, int irq, int level) static void sdhci_reset(SDHCIState *s) { - qemu_del_timer(s->insert_timer); - qemu_del_timer(s->transfer_timer); + timer_del(s->insert_timer); + timer_del(s->transfer_timer); /* Set all registers to 0. Capabilities registers are not cleared * and assumed to always preserve their value, given to them during * initialization */ @@ -764,8 +764,8 @@ static void sdhci_do_adma(SDHCIState *s) } /* we have unfinished business - reschedule to continue ADMA */ - qemu_mod_timer(s->transfer_timer, - qemu_get_clock_ns(vm_clock) + SDHC_TRANSFER_DELAY); + timer_mod(s->transfer_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_TRANSFER_DELAY); } /* Perform data transfer according to controller configuration */ @@ -1170,18 +1170,18 @@ static void sdhci_initfn(Object *obj) s->ro_cb = qemu_allocate_irqs(sdhci_card_readonly_cb, s, 1)[0]; sd_set_cb(s->card, s->ro_cb, s->eject_cb); - s->insert_timer = qemu_new_timer_ns(vm_clock, sdhci_raise_insertion_irq, s); - s->transfer_timer = qemu_new_timer_ns(vm_clock, sdhci_do_data_transfer, s); + s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); + s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_do_data_transfer, s); } static void sdhci_uninitfn(Object *obj) { SDHCIState *s = SDHCI(obj); - qemu_del_timer(s->insert_timer); - qemu_free_timer(s->insert_timer); - qemu_del_timer(s->transfer_timer); - qemu_free_timer(s->transfer_timer); + timer_del(s->insert_timer); + timer_free(s->insert_timer); + timer_del(s->transfer_timer); + timer_free(s->transfer_timer); qemu_free_irqs(&s->eject_cb); qemu_free_irqs(&s->ro_cb); diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c index c33a72f80f..e81176a11e 100644 --- a/hw/sh4/sh_pci.c +++ b/hw/sh4/sh_pci.c @@ -28,9 +28,14 @@ #include "qemu/bswap.h" #include "exec/address-spaces.h" +#define TYPE_SH_PCI_HOST_BRIDGE "sh_pci" + +#define SH_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(SHPCIState, (obj), TYPE_SH_PCI_HOST_BRIDGE) + typedef struct SHPCIState { - SysBusDevice busdev; - PCIBus *bus; + PCIHostState parent_obj; + PCIDevice *dev; qemu_irq irq[4]; MemoryRegion memconfig_p4; @@ -45,6 +50,8 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, unsigned size) { SHPCIState *pcic = p; + PCIHostState *phb = PCI_HOST_BRIDGE(pcic); + switch(addr) { case 0 ... 0xfc: cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val); @@ -64,7 +71,7 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, } break; case 0x220: - pci_data_write(pcic->bus, pcic->par, val, 4); + pci_data_write(phb->bus, pcic->par, val, 4); break; } } @@ -73,6 +80,8 @@ static uint64_t sh_pci_reg_read (void *p, hwaddr addr, unsigned size) { SHPCIState *pcic = p; + PCIHostState *phb = PCI_HOST_BRIDGE(pcic); + switch(addr) { case 0 ... 0xfc: return le32_to_cpup((uint32_t*)(pcic->dev->config + addr)); @@ -83,7 +92,7 @@ static uint64_t sh_pci_reg_read (void *p, hwaddr addr, case 0x1c8: return pcic->iobr; case 0x220: - return pci_data_read(pcic->bus, pcic->par, 4); + return pci_data_read(phb->bus, pcic->par, 4); } return 0; } @@ -112,30 +121,33 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level) static int sh_pci_device_init(SysBusDevice *dev) { + PCIHostState *phb; SHPCIState *s; int i; - s = FROM_SYSBUS(SHPCIState, dev); + s = SH_PCI_HOST_BRIDGE(dev); + phb = PCI_HOST_BRIDGE(s); for (i = 0; i < 4; i++) { sysbus_init_irq(dev, &s->irq[i]); } - s->bus = pci_register_bus(&s->busdev.qdev, "pci", - sh_pci_set_irq, sh_pci_map_irq, - s->irq, - get_system_memory(), - get_system_io(), - PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); + phb->bus = pci_register_bus(DEVICE(dev), "pci", + sh_pci_set_irq, sh_pci_map_irq, + s->irq, + get_system_memory(), + get_system_io(), + PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s, "sh_pci", 0x224); memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2", &s->memconfig_p4, 0, 0x224); - isa_mmio_setup(&s->isa, 0x40000); + memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa", + get_system_io(), 0, 0x40000); sysbus_init_mmio(dev, &s->memconfig_p4); sysbus_init_mmio(dev, &s->memconfig_a7); s->iobr = 0xfe240000; memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa); - s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host"); + s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host"); return 0; } @@ -171,8 +183,8 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data) } static const TypeInfo sh_pci_device_info = { - .name = "sh_pci", - .parent = TYPE_SYS_BUS_DEVICE, + .name = TYPE_SH_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(SHPCIState), .class_init = sh_pci_device_class_init, }; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 7a0c1ab776..36ef36f5fe 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -66,6 +66,8 @@ #define PROM_FILENAME "openbios-sparc32" #define CFG_ADDR 0xd00000510ULL #define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00) +#define FW_CFG_SUN4M_WIDTH (FW_CFG_ARCH_LOCAL + 0x01) +#define FW_CFG_SUN4M_HEIGHT (FW_CFG_ARCH_LOCAL + 0x02) #define MAX_CPUS 16 #define MAX_PILS 16 @@ -557,6 +559,9 @@ static void tcx_init(hwaddr addr, int vram_size, int width, } /* NCR89C100/MACIO Internal ID register */ + +#define TYPE_MACIO_ID_REGISTER "macio_idreg" + static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 }; static void idreg_init(hwaddr addr) @@ -564,7 +569,7 @@ static void idreg_init(hwaddr addr) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "macio_idreg"); + dev = qdev_create(NULL, TYPE_MACIO_ID_REGISTER); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); @@ -572,14 +577,18 @@ static void idreg_init(hwaddr addr) cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data)); } +#define MACIO_ID_REGISTER(obj) \ + OBJECT_CHECK(IDRegState, (obj), TYPE_MACIO_ID_REGISTER) + typedef struct IDRegState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mem; } IDRegState; static int idreg_init1(SysBusDevice *dev) { - IDRegState *s = FROM_SYSBUS(IDRegState, dev); + IDRegState *s = MACIO_ID_REGISTER(dev); memory_region_init_ram(&s->mem, OBJECT(s), "sun4m.idreg", sizeof(idreg_data)); @@ -597,14 +606,18 @@ static void idreg_class_init(ObjectClass *klass, void *data) } static const TypeInfo idreg_info = { - .name = "macio_idreg", + .name = TYPE_MACIO_ID_REGISTER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IDRegState), .class_init = idreg_class_init, }; +#define TYPE_TCX_AFX "tcx_afx" +#define TCX_AFX(obj) OBJECT_CHECK(AFXState, (obj), TYPE_TCX_AFX) + typedef struct AFXState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mem; } AFXState; @@ -614,7 +627,7 @@ static void afx_init(hwaddr addr) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "tcx_afx"); + dev = qdev_create(NULL, TYPE_TCX_AFX); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); @@ -623,7 +636,7 @@ static void afx_init(hwaddr addr) static int afx_init1(SysBusDevice *dev) { - AFXState *s = FROM_SYSBUS(AFXState, dev); + AFXState *s = TCX_AFX(dev); memory_region_init_ram(&s->mem, OBJECT(s), "sun4m.afx", 4); vmstate_register_ram_global(&s->mem); @@ -639,14 +652,18 @@ static void afx_class_init(ObjectClass *klass, void *data) } static const TypeInfo afx_info = { - .name = "tcx_afx", + .name = TYPE_TCX_AFX, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AFXState), .class_init = afx_class_init, }; +#define TYPE_OPENPROM "openprom" +#define OPENPROM(obj) OBJECT_CHECK(PROMState, (obj), TYPE_OPENPROM) + typedef struct PROMState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion prom; } PROMState; @@ -664,7 +681,7 @@ static void prom_init(hwaddr addr, const char *bios_name) char *filename; int ret; - dev = qdev_create(NULL, "openprom"); + dev = qdev_create(NULL, TYPE_OPENPROM); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); @@ -693,7 +710,7 @@ static void prom_init(hwaddr addr, const char *bios_name) static int prom_init1(SysBusDevice *dev) { - PROMState *s = FROM_SYSBUS(PROMState, dev); + PROMState *s = OPENPROM(dev); memory_region_init_ram(&s->prom, OBJECT(s), "sun4m.prom", PROM_SIZE_MAX); vmstate_register_ram_global(&s->prom); @@ -716,15 +733,18 @@ static void prom_class_init(ObjectClass *klass, void *data) } static const TypeInfo prom_info = { - .name = "openprom", + .name = TYPE_OPENPROM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PROMState), .class_init = prom_class_init, }; -typedef struct RamDevice -{ - SysBusDevice busdev; +#define TYPE_SUN4M_MEMORY "memory" +#define SUN4M_RAM(obj) OBJECT_CHECK(RamDevice, (obj), TYPE_SUN4M_MEMORY) + +typedef struct RamDevice { + SysBusDevice parent_obj; + MemoryRegion ram; uint64_t size; } RamDevice; @@ -732,7 +752,7 @@ typedef struct RamDevice /* System RAM */ static int ram_init1(SysBusDevice *dev) { - RamDevice *d = FROM_SYSBUS(RamDevice, dev); + RamDevice *d = SUN4M_RAM(dev); memory_region_init_ram(&d->ram, OBJECT(d), "sun4m.ram", d->size); vmstate_register_ram_global(&d->ram); @@ -758,7 +778,7 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size, dev = qdev_create(NULL, "memory"); s = SYS_BUS_DEVICE(dev); - d = FROM_SYSBUS(RamDevice, s); + d = SUN4M_RAM(dev); d->size = RAM_size; qdev_init_nofail(dev); @@ -780,7 +800,7 @@ static void ram_class_init(ObjectClass *klass, void *data) } static const TypeInfo ram_info = { - .name = "memory", + .name = TYPE_SUN4M_MEMORY, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RamDevice), .class_init = ram_class_init, @@ -816,12 +836,10 @@ static void dummy_fdc_tc(void *opaque, int irq, int level) { } -static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, + QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; unsigned int i; void *iommu, *espdma, *ledma, *nvram; qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS], @@ -847,10 +865,10 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, /* set up devices */ - ram_init(0, RAM_size, hwdef->max_mem); + ram_init(0, args->ram_size, hwdef->max_mem); /* models without ECC don't trap when missing ram is accessed */ if (!hwdef->ecc_base) { - empty_slot_init(RAM_size, hwdef->max_mem - RAM_size); + empty_slot_init(args->ram_size, hwdef->max_mem - args->ram_size); } prom_init(hwdef->slavio_base, bios_name); @@ -973,11 +991,12 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, empty_slot_init(hwdef->bpp_base, 0x20); } - kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, - RAM_size); + kernel_size = sun4m_load_kernel(args->kernel_filename, + args->initrd_filename, + args->ram_size); - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, - boot_device, RAM_size, kernel_size, graphic_width, + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, args->kernel_cmdline, + args->boot_device, args->ram_size, kernel_size, graphic_width, graphic_height, graphic_depth, hwdef->nvram_machine_id, "Sun4m"); @@ -991,21 +1010,24 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_WIDTH, graphic_width); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_HEIGHT, graphic_height); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { + if (args->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, + args->kernel_cmdline); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, args->kernel_cmdline); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(kernel_cmdline) + 1); + strlen(args->kernel_cmdline) + 1); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, args->boot_device[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } @@ -1269,118 +1291,55 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { /* SPARCstation 5 hardware initialisation */ static void ss5_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[0], args); } /* SPARCstation 10 hardware initialisation */ static void ss10_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[1], args); } /* SPARCserver 600MP hardware initialisation */ static void ss600mp_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[2], args); } /* SPARCstation 20 hardware initialisation */ static void ss20_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[3], args); } /* SPARCstation Voyager hardware initialisation */ static void vger_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[4], args); } /* SPARCstation LX hardware initialisation */ static void ss_lx_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[5], args); } /* SPARCstation 4 hardware initialisation */ static void ss4_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[6], args); } /* SPARCClassic hardware initialisation */ static void scls_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[7], args); } /* SPARCbook hardware initialisation */ static void sbook_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + sun4m_hw_init(&sun4m_hwdefs[8], args); } static QEMUMachine ss5_machine = { diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 564c1959ee..9da083310c 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -363,7 +363,7 @@ void cpu_put_timer(QEMUFile *f, CPUTimer *s) qemu_put_be64s(f, &s->disabled_mask); qemu_put_sbe64s(f, &s->clock_offset); - qemu_put_timer(f, s->qtimer); + timer_put(f, s->qtimer); } void cpu_get_timer(QEMUFile *f, CPUTimer *s) @@ -373,7 +373,7 @@ void cpu_get_timer(QEMUFile *f, CPUTimer *s) qemu_get_be64s(f, &s->disabled_mask); qemu_get_sbe64s(f, &s->clock_offset); - qemu_get_timer(f, s->qtimer); + timer_get(f, s->qtimer); } static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, @@ -387,9 +387,9 @@ static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, timer->disabled_mask = disabled_mask; timer->disabled = 1; - timer->clock_offset = qemu_get_clock_ns(vm_clock); + timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu); + timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu); return timer; } @@ -397,9 +397,9 @@ static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, static void cpu_timer_reset(CPUTimer *timer) { timer->disabled = 1; - timer->clock_offset = qemu_get_clock_ns(vm_clock); + timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - qemu_del_timer(timer->qtimer); + timer_del(timer->qtimer); } static void main_cpu_reset(void *opaque) @@ -495,7 +495,7 @@ void cpu_tick_set_count(CPUTimer *timer, uint64_t count) uint64_t real_count = count & ~timer->disabled_mask; uint64_t disabled_bit = count & timer->disabled_mask; - int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) - + int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - cpu_to_timer_ticks(real_count, timer->frequency); TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", @@ -509,7 +509,7 @@ void cpu_tick_set_count(CPUTimer *timer, uint64_t count) uint64_t cpu_tick_get_count(CPUTimer *timer) { uint64_t real_count = timer_to_cpu_ticks( - qemu_get_clock_ns(vm_clock) - timer->clock_offset, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset, timer->frequency); TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", @@ -524,7 +524,7 @@ uint64_t cpu_tick_get_count(CPUTimer *timer) void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) { - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); uint64_t real_limit = limit & ~timer->disabled_mask; timer->disabled = (limit & timer->disabled_mask) ? 1 : 0; @@ -548,11 +548,11 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) if (!real_limit) { TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n", timer->name); - qemu_del_timer(timer->qtimer); + timer_del(timer->qtimer); } else if (timer->disabled) { - qemu_del_timer(timer->qtimer); + timer_del(timer->qtimer); } else { - qemu_mod_timer(timer->qtimer, expires); + timer_mod(timer->qtimer, expires); } } @@ -605,9 +605,11 @@ pci_ebus_init1(PCIDevice *pci_dev) pci_dev->config[0x09] = 0x00; // programming i/f pci_dev->config[0x0D] = 0x0a; // latency_timer - isa_mmio_setup(&s->bar0, 0x1000000); + memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", get_system_io(), + 0, 0x1000000); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); - isa_mmio_setup(&s->bar1, 0x800000); + memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(), + 0, 0x800000); pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1); return 0; } @@ -630,8 +632,12 @@ static const TypeInfo ebus_info = { .class_init = ebus_class_init, }; +#define TYPE_OPENPROM "openprom" +#define OPENPROM(obj) OBJECT_CHECK(PROMState, (obj), TYPE_OPENPROM) + typedef struct PROMState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion prom; } PROMState; @@ -649,7 +655,7 @@ static void prom_init(hwaddr addr, const char *bios_name) char *filename; int ret; - dev = qdev_create(NULL, "openprom"); + dev = qdev_create(NULL, TYPE_OPENPROM); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); @@ -678,7 +684,7 @@ static void prom_init(hwaddr addr, const char *bios_name) static int prom_init1(SysBusDevice *dev) { - PROMState *s = FROM_SYSBUS(PROMState, dev); + PROMState *s = OPENPROM(dev); memory_region_init_ram(&s->prom, OBJECT(s), "sun4u.prom", PROM_SIZE_MAX); vmstate_register_ram_global(&s->prom); @@ -701,16 +707,19 @@ static void prom_class_init(ObjectClass *klass, void *data) } static const TypeInfo prom_info = { - .name = "openprom", + .name = TYPE_OPENPROM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PROMState), .class_init = prom_class_init, }; -typedef struct RamDevice -{ - SysBusDevice busdev; +#define TYPE_SUN4U_MEMORY "memory" +#define SUN4U_RAM(obj) OBJECT_CHECK(RamDevice, (obj), TYPE_SUN4U_MEMORY) + +typedef struct RamDevice { + SysBusDevice parent_obj; + MemoryRegion ram; uint64_t size; } RamDevice; @@ -718,7 +727,7 @@ typedef struct RamDevice /* System RAM */ static int ram_init1(SysBusDevice *dev) { - RamDevice *d = FROM_SYSBUS(RamDevice, dev); + RamDevice *d = SUN4U_RAM(dev); memory_region_init_ram(&d->ram, OBJECT(d), "sun4u.ram", d->size); vmstate_register_ram_global(&d->ram); @@ -733,10 +742,10 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size) RamDevice *d; /* allocate RAM */ - dev = qdev_create(NULL, "memory"); + dev = qdev_create(NULL, TYPE_SUN4U_MEMORY); s = SYS_BUS_DEVICE(dev); - d = FROM_SYSBUS(RamDevice, s); + d = SUN4U_RAM(dev); d->size = RAM_size; qdev_init_nofail(dev); @@ -758,7 +767,7 @@ static void ram_class_init(ObjectClass *klass, void *data) } static const TypeInfo ram_info = { - .name = "memory", + .name = TYPE_SUN4U_MEMORY, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RamDevice), .class_init = ram_class_init, @@ -802,10 +811,7 @@ static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) } static void sun4uv_init(MemoryRegion *address_space_mem, - ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model, + QEMUMachineInitArgs *args, const struct hwdef *hwdef) { SPARCCPU *cpu; @@ -820,10 +826,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, FWCfgState *fw_cfg; /* init CPUs */ - cpu = cpu_devinit(cpu_model, hwdef); + cpu = cpu_devinit(args->cpu_model, hwdef); /* set up devices */ - ram_init(0, RAM_size); + ram_init(0, args->ram_size); prom_init(hwdef->prom_addr, bios_name); @@ -869,13 +875,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, initrd_size = 0; initrd_addr = 0; - kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, + kernel_size = sun4u_load_kernel(args->kernel_filename, + args->initrd_filename, ram_size, &initrd_size, &initrd_addr, &kernel_addr, &kernel_entry); - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", args->ram_size, + args->boot_device, kernel_addr, kernel_size, - kernel_cmdline, + args->kernel_cmdline, initrd_addr, initrd_size, /* XXX: need an option to load a NVRAM image */ 0, @@ -889,16 +897,16 @@ static void sun4uv_init(MemoryRegion *address_space_mem, fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { + if (args->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + strlen(args->kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, args->kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, args->boot_device[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height); @@ -940,40 +948,19 @@ static const struct hwdef hwdefs[] = { /* Sun4u hardware initialisation */ static void sun4u_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_devices = args->boot_device; - sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]); + sun4uv_init(get_system_memory(), args, &hwdefs[0]); } /* Sun4v hardware initialisation */ static void sun4v_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_devices = args->boot_device; - sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]); + sun4uv_init(get_system_memory(), args, &hwdefs[1]); } /* Niagara hardware initialisation */ static void niagara_init(QEMUMachineInitArgs *args) { - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_devices = args->boot_device; - sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]); + sun4uv_init(get_system_memory(), args, &hwdefs[2]); } static QEMUMachine sun4u_machine = { diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index 711a0c17ab..fd479effb9 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -39,8 +39,12 @@ do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0) #define PL022_INT_RX 0x04 #define PL022_INT_TX 0x08 -typedef struct { - SysBusDevice busdev; +#define TYPE_PL022 "pl022" +#define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022) + +typedef struct PL022State { + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t cr0; uint32_t cr1; @@ -58,12 +62,12 @@ typedef struct { uint16_t rx_fifo[8]; qemu_irq irq; SSIBus *ssi; -} pl022_state; +} PL022State; static const unsigned char pl022_id[8] = { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; -static void pl022_update(pl022_state *s) +static void pl022_update(PL022State *s) { s->sr = 0; if (s->tx_fifo_len == 0) @@ -85,7 +89,7 @@ static void pl022_update(pl022_state *s) qemu_set_irq(s->irq, (s->is & s->im) != 0); } -static void pl022_xfer(pl022_state *s) +static void pl022_xfer(PL022State *s) { int i; int o; @@ -133,7 +137,7 @@ static void pl022_xfer(pl022_state *s) static uint64_t pl022_read(void *opaque, hwaddr offset, unsigned size) { - pl022_state *s = (pl022_state *)opaque; + PL022State *s = (PL022State *)opaque; int val; if (offset >= 0xfe0 && offset < 0x1000) { @@ -177,7 +181,7 @@ static uint64_t pl022_read(void *opaque, hwaddr offset, static void pl022_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - pl022_state *s = (pl022_state *)opaque; + PL022State *s = (PL022State *)opaque; switch (offset) { case 0x00: /* CR0 */ @@ -221,7 +225,7 @@ static void pl022_write(void *opaque, hwaddr offset, } } -static void pl022_reset(pl022_state *s) +static void pl022_reset(PL022State *s) { s->rx_fifo_len = 0; s->tx_fifo_len = 0; @@ -242,47 +246,48 @@ static const VMStateDescription vmstate_pl022 = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(cr0, pl022_state), - VMSTATE_UINT32(cr1, pl022_state), - VMSTATE_UINT32(bitmask, pl022_state), - VMSTATE_UINT32(sr, pl022_state), - VMSTATE_UINT32(cpsr, pl022_state), - VMSTATE_UINT32(is, pl022_state), - VMSTATE_UINT32(im, pl022_state), - VMSTATE_INT32(tx_fifo_head, pl022_state), - VMSTATE_INT32(rx_fifo_head, pl022_state), - VMSTATE_INT32(tx_fifo_len, pl022_state), - VMSTATE_INT32(rx_fifo_len, pl022_state), - VMSTATE_UINT16(tx_fifo[0], pl022_state), - VMSTATE_UINT16(rx_fifo[0], pl022_state), - VMSTATE_UINT16(tx_fifo[1], pl022_state), - VMSTATE_UINT16(rx_fifo[1], pl022_state), - VMSTATE_UINT16(tx_fifo[2], pl022_state), - VMSTATE_UINT16(rx_fifo[2], pl022_state), - VMSTATE_UINT16(tx_fifo[3], pl022_state), - VMSTATE_UINT16(rx_fifo[3], pl022_state), - VMSTATE_UINT16(tx_fifo[4], pl022_state), - VMSTATE_UINT16(rx_fifo[4], pl022_state), - VMSTATE_UINT16(tx_fifo[5], pl022_state), - VMSTATE_UINT16(rx_fifo[5], pl022_state), - VMSTATE_UINT16(tx_fifo[6], pl022_state), - VMSTATE_UINT16(rx_fifo[6], pl022_state), - VMSTATE_UINT16(tx_fifo[7], pl022_state), - VMSTATE_UINT16(rx_fifo[7], pl022_state), + VMSTATE_UINT32(cr0, PL022State), + VMSTATE_UINT32(cr1, PL022State), + VMSTATE_UINT32(bitmask, PL022State), + VMSTATE_UINT32(sr, PL022State), + VMSTATE_UINT32(cpsr, PL022State), + VMSTATE_UINT32(is, PL022State), + VMSTATE_UINT32(im, PL022State), + VMSTATE_INT32(tx_fifo_head, PL022State), + VMSTATE_INT32(rx_fifo_head, PL022State), + VMSTATE_INT32(tx_fifo_len, PL022State), + VMSTATE_INT32(rx_fifo_len, PL022State), + VMSTATE_UINT16(tx_fifo[0], PL022State), + VMSTATE_UINT16(rx_fifo[0], PL022State), + VMSTATE_UINT16(tx_fifo[1], PL022State), + VMSTATE_UINT16(rx_fifo[1], PL022State), + VMSTATE_UINT16(tx_fifo[2], PL022State), + VMSTATE_UINT16(rx_fifo[2], PL022State), + VMSTATE_UINT16(tx_fifo[3], PL022State), + VMSTATE_UINT16(rx_fifo[3], PL022State), + VMSTATE_UINT16(tx_fifo[4], PL022State), + VMSTATE_UINT16(rx_fifo[4], PL022State), + VMSTATE_UINT16(tx_fifo[5], PL022State), + VMSTATE_UINT16(rx_fifo[5], PL022State), + VMSTATE_UINT16(tx_fifo[6], PL022State), + VMSTATE_UINT16(rx_fifo[6], PL022State), + VMSTATE_UINT16(tx_fifo[7], PL022State), + VMSTATE_UINT16(rx_fifo[7], PL022State), VMSTATE_END_OF_LIST() } }; -static int pl022_init(SysBusDevice *dev) +static int pl022_init(SysBusDevice *sbd) { - pl022_state *s = FROM_SYSBUS(pl022_state, dev); + DeviceState *dev = DEVICE(sbd); + PL022State *s = PL022(dev); memory_region_init_io(&s->iomem, OBJECT(s), &pl022_ops, s, "pl022", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - s->ssi = ssi_create_bus(&dev->qdev, "ssi"); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + s->ssi = ssi_create_bus(dev, "ssi"); pl022_reset(s); - vmstate_register(&dev->qdev, -1, &vmstate_pl022, s); + vmstate_register(dev, -1, &vmstate_pl022, s); return 0; } @@ -294,9 +299,9 @@ static void pl022_class_init(ObjectClass *klass, void *data) } static const TypeInfo pl022_info = { - .name = "pl022", + .name = TYPE_PL022, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl022_state), + .instance_size = sizeof(PL022State), .class_init = pl022_class_init, }; diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index 7a9fd81583..d44caae8ad 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -73,8 +73,12 @@ #define FIFO_CAPACITY 256 +#define TYPE_XILINX_SPI "xlnx.xps-spi" +#define XILINX_SPI(obj) OBJECT_CHECK(XilinxSPI, (obj), TYPE_XILINX_SPI) + typedef struct XilinxSPI { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mmio; qemu_irq irq; @@ -109,7 +113,7 @@ static void rxfifo_reset(XilinxSPI *s) static void xlx_spi_update_cs(XilinxSPI *s) { - int i; + int i; for (i = 0; i < s->num_cs; ++i) { qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i)); @@ -154,7 +158,7 @@ static void xlx_spi_do_reset(XilinxSPI *s) static void xlx_spi_reset(DeviceState *d) { - xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d)); + xlx_spi_do_reset(XILINX_SPI(d)); } static inline int spi_master_enabled(XilinxSPI *s) @@ -314,25 +318,26 @@ static const MemoryRegionOps spi_ops = { } }; -static int xilinx_spi_init(SysBusDevice *dev) +static int xilinx_spi_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); + XilinxSPI *s = XILINX_SPI(dev); int i; - XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev); DB_PRINT("\n"); - s->spi = ssi_create_bus(&dev->qdev, "spi"); + s->spi = ssi_create_bus(dev, "spi"); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); s->cs_lines = g_new(qemu_irq, s->num_cs); - ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi); + ssi_auto_connect_slaves(dev, s->cs_lines, s->spi); for (i = 0; i < s->num_cs; ++i) { - sysbus_init_irq(dev, &s->cs_lines[i]); + sysbus_init_irq(sbd, &s->cs_lines[i]); } memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s, "xilinx-spi", R_MAX * 4); - sysbus_init_mmio(dev, &s->mmio); + sysbus_init_mmio(sbd, &s->mmio); s->irqline = -1; @@ -372,7 +377,7 @@ static void xilinx_spi_class_init(ObjectClass *klass, void *data) } static const TypeInfo xilinx_spi_info = { - .name = "xlnx.xps-spi", + .name = TYPE_XILINX_SPI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(XilinxSPI), .class_init = xilinx_spi_class_init, diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 0ceb240490..8020c9f4b5 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -41,8 +41,15 @@ typedef struct { MemoryRegion iomem; } TimerBlock; +#define TYPE_ARM_MPTIMER "arm_mptimer" +#define ARM_MPTIMER(obj) \ + OBJECT_CHECK(ARMMPTimerState, (obj), TYPE_ARM_MPTIMER) + typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t num_cpu; TimerBlock timerblock[MAX_CPUS]; MemoryRegion iomem; @@ -74,10 +81,10 @@ static void timerblock_reload(TimerBlock *tb, int restart) return; } if (restart) { - tb->tick = qemu_get_clock_ns(vm_clock); + tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } tb->tick += (int64_t)tb->count * timerblock_scale(tb); - qemu_mod_timer(tb->timer, tb->tick); + timer_mod(tb->timer, tb->tick); } static void timerblock_tick(void *opaque) @@ -106,7 +113,7 @@ static uint64_t timerblock_read(void *opaque, hwaddr addr, return 0; } /* Slow and ugly, but hopefully won't happen too often. */ - val = tb->tick - qemu_get_clock_ns(vm_clock); + val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); val /= timerblock_scale(tb); if (val < 0) { val = 0; @@ -133,7 +140,7 @@ static void timerblock_write(void *opaque, hwaddr addr, case 4: /* Counter. */ if ((tb->control & 1) && tb->count) { /* Cancel the previous timer. */ - qemu_del_timer(tb->timer); + timer_del(tb->timer); } tb->count = value; if (tb->control & 1) { @@ -204,15 +211,15 @@ static void timerblock_reset(TimerBlock *tb) tb->status = 0; tb->tick = 0; if (tb->timer) { - qemu_del_timer(tb->timer); + timer_del(tb->timer); } } static void arm_mptimer_reset(DeviceState *dev) { - ARMMPTimerState *s = - FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev)); + ARMMPTimerState *s = ARM_MPTIMER(dev); int i; + for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) { timerblock_reset(&s->timerblock[i]); } @@ -220,8 +227,9 @@ static void arm_mptimer_reset(DeviceState *dev) static int arm_mptimer_init(SysBusDevice *dev) { - ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, dev); + ARMMPTimerState *s = ARM_MPTIMER(dev); int i; + if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) { hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS); } @@ -240,7 +248,7 @@ static int arm_mptimer_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->iomem); for (i = 0; i < s->num_cpu; i++) { TimerBlock *tb = &s->timerblock[i]; - tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb); + tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb); sysbus_init_irq(dev, &tb->irq); memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, "arm_mptimer_timerblock", 0x20); @@ -294,7 +302,7 @@ static void arm_mptimer_class_init(ObjectClass *klass, void *data) } static const TypeInfo arm_mptimer_info = { - .name = "arm_mptimer", + .name = TYPE_ARM_MPTIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ARMMPTimerState), .class_init = arm_mptimer_class_init, diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 798a8dabc7..a47afde23a 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -12,6 +12,7 @@ #include "qemu-common.h" #include "hw/qdev.h" #include "hw/ptimer.h" +#include "qemu/main-loop.h" /* Common timer implementation. */ @@ -179,14 +180,18 @@ static arm_timer_state *arm_timer_init(uint32_t freq) * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html */ -typedef struct { - SysBusDevice busdev; +#define TYPE_SP804 "sp804" +#define SP804(obj) OBJECT_CHECK(SP804State, (obj), TYPE_SP804) + +typedef struct SP804State { + SysBusDevice parent_obj; + MemoryRegion iomem; arm_timer_state *timer[2]; uint32_t freq0, freq1; int level[2]; qemu_irq irq; -} sp804_state; +} SP804State; static const uint8_t sp804_ids[] = { /* Timer ID */ @@ -198,7 +203,7 @@ static const uint8_t sp804_ids[] = { /* Merge the IRQs from the two component devices. */ static void sp804_set_irq(void *opaque, int irq, int level) { - sp804_state *s = (sp804_state *)opaque; + SP804State *s = (SP804State *)opaque; s->level[irq] = level; qemu_set_irq(s->irq, s->level[0] || s->level[1]); @@ -207,7 +212,7 @@ static void sp804_set_irq(void *opaque, int irq, int level) static uint64_t sp804_read(void *opaque, hwaddr offset, unsigned size) { - sp804_state *s = (sp804_state *)opaque; + SP804State *s = (SP804State *)opaque; if (offset < 0x20) { return arm_timer_read(s->timer[0], offset); @@ -239,7 +244,7 @@ static uint64_t sp804_read(void *opaque, hwaddr offset, static void sp804_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - sp804_state *s = (sp804_state *)opaque; + SP804State *s = (SP804State *)opaque; if (offset < 0x20) { arm_timer_write(s->timer[0], offset, value); @@ -268,33 +273,39 @@ static const VMStateDescription vmstate_sp804 = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_INT32_ARRAY(level, sp804_state, 2), + VMSTATE_INT32_ARRAY(level, SP804State, 2), VMSTATE_END_OF_LIST() } }; -static int sp804_init(SysBusDevice *dev) +static int sp804_init(SysBusDevice *sbd) { - sp804_state *s = FROM_SYSBUS(sp804_state, dev); + DeviceState *dev = DEVICE(sbd); + SP804State *s = SP804(dev); qemu_irq *qi; qi = qemu_allocate_irqs(sp804_set_irq, s, 2); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); s->timer[0] = arm_timer_init(s->freq0); s->timer[1] = arm_timer_init(s->freq1); s->timer[0]->irq = qi[0]; s->timer[1]->irq = qi[1]; memory_region_init_io(&s->iomem, OBJECT(s), &sp804_ops, s, "sp804", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - vmstate_register(&dev->qdev, -1, &vmstate_sp804, s); + sysbus_init_mmio(sbd, &s->iomem); + vmstate_register(dev, -1, &vmstate_sp804, s); return 0; } /* Integrator/CP timer module. */ +#define TYPE_INTEGRATOR_PIT "integrator_pit" +#define INTEGRATOR_PIT(obj) \ + OBJECT_CHECK(icp_pit_state, (obj), TYPE_INTEGRATOR_PIT) + typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; arm_timer_state *timer[3]; } icp_pit_state; @@ -336,7 +347,7 @@ static const MemoryRegionOps icp_pit_ops = { static int icp_pit_init(SysBusDevice *dev) { - icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev); + icp_pit_state *s = INTEGRATOR_PIT(dev); /* Timer 0 runs at the system clock speed (40MHz). */ s->timer[0] = arm_timer_init(40000000); @@ -364,15 +375,15 @@ static void icp_pit_class_init(ObjectClass *klass, void *data) } static const TypeInfo icp_pit_info = { - .name = "integrator_pit", + .name = TYPE_INTEGRATOR_PIT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pit_state), .class_init = icp_pit_class_init, }; static Property sp804_properties[] = { - DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000), - DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000), + DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000), + DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000), DEFINE_PROP_END_OF_LIST(), }; @@ -386,9 +397,9 @@ static void sp804_class_init(ObjectClass *klass, void *data) } static const TypeInfo sp804_info = { - .name = "sp804", + .name = TYPE_SP804, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(sp804_state), + .instance_size = sizeof(SP804State), .class_init = sp804_class_init, }; diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index a861049e54..a279bced78 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -64,8 +64,13 @@ typedef struct { qemu_irq irq; } CadenceTimerState; -typedef struct { - SysBusDevice busdev; +#define TYPE_CADENCE_TTC "cadence_ttc" +#define CADENCE_TTC(obj) \ + OBJECT_CHECK(CadenceTTCState, (obj), TYPE_CADENCE_TTC) + +typedef struct CadenceTTCState { + SysBusDevice parent_obj; + MemoryRegion iomem; CadenceTimerState timer[3]; } CadenceTTCState; @@ -167,7 +172,7 @@ static void cadence_timer_run(CadenceTimerState *s) event_interval = next_value - (int64_t)s->reg_value; event_interval = (event_interval < 0) ? -event_interval : event_interval; - qemu_mod_timer(s->timer, s->cpu_time + + timer_mod(s->timer, s->cpu_time + cadence_timer_get_ns(s, event_interval)); } @@ -179,7 +184,7 @@ static void cadence_timer_sync(CadenceTimerState *s) (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16; uint64_t old_time = s->cpu_time; - s->cpu_time = qemu_get_clock_ns(vm_clock); + s->cpu_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); DB_PRINT("cpu time: %lld ns\n", (long long)old_time); if (!s->cpu_time_valid || old_time == s->cpu_time) { @@ -396,12 +401,12 @@ static void cadence_timer_init(uint32_t freq, CadenceTimerState *s) cadence_timer_reset(s); - s->timer = qemu_new_timer_ns(vm_clock, cadence_timer_tick, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cadence_timer_tick, s); } static int cadence_ttc_init(SysBusDevice *dev) { - CadenceTTCState *s = FROM_SYSBUS(CadenceTTCState, dev); + CadenceTTCState *s = CADENCE_TTC(dev); int i; for (i = 0; i < 3; ++i) { @@ -476,7 +481,7 @@ static void cadence_ttc_class_init(ObjectClass *klass, void *data) } static const TypeInfo cadence_ttc_info = { - .name = "cadence_ttc", + .name = TYPE_CADENCE_TTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CadenceTTCState), .class_init = cadence_ttc_class_init, diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 6dd1072092..aee4990eb1 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -42,8 +42,13 @@ #define R_INTR 0x50 #define R_MASKED_INTR 0x54 -struct etrax_timer { - SysBusDevice busdev; +#define TYPE_ETRAX_FS_TIMER "etraxfs,timer" +#define ETRAX_TIMER(obj) \ + OBJECT_CHECK(ETRAXTimerState, (obj), TYPE_ETRAX_FS_TIMER) + +typedef struct ETRAXTimerState { + SysBusDevice parent_obj; + MemoryRegion mmio; qemu_irq irq; qemu_irq nmi; @@ -72,12 +77,12 @@ struct etrax_timer { uint32_t rw_ack_intr; uint32_t r_intr; uint32_t r_masked_intr; -}; +} ETRAXTimerState; static uint64_t timer_read(void *opaque, hwaddr addr, unsigned int size) { - struct etrax_timer *t = opaque; + ETRAXTimerState *t = opaque; uint32_t r = 0; switch (addr) { @@ -88,7 +93,7 @@ timer_read(void *opaque, hwaddr addr, unsigned int size) r = ptimer_get_count(t->ptimer_t1); break; case R_TIME: - r = qemu_get_clock_ns(vm_clock) / 10; + r = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 10; break; case RW_INTR_MASK: r = t->rw_intr_mask; @@ -103,7 +108,7 @@ timer_read(void *opaque, hwaddr addr, unsigned int size) return r; } -static void update_ctrl(struct etrax_timer *t, int tnum) +static void update_ctrl(ETRAXTimerState *t, int tnum) { unsigned int op; unsigned int freq; @@ -167,7 +172,7 @@ static void update_ctrl(struct etrax_timer *t, int tnum) } } -static void timer_update_irq(struct etrax_timer *t) +static void timer_update_irq(ETRAXTimerState *t) { t->r_intr &= ~(t->rw_ack_intr); t->r_masked_intr = t->r_intr & t->rw_intr_mask; @@ -178,21 +183,21 @@ static void timer_update_irq(struct etrax_timer *t) static void timer0_hit(void *opaque) { - struct etrax_timer *t = opaque; + ETRAXTimerState *t = opaque; t->r_intr |= 1; timer_update_irq(t); } static void timer1_hit(void *opaque) { - struct etrax_timer *t = opaque; + ETRAXTimerState *t = opaque; t->r_intr |= 2; timer_update_irq(t); } static void watchdog_hit(void *opaque) { - struct etrax_timer *t = opaque; + ETRAXTimerState *t = opaque; if (t->wd_hits == 0) { /* real hw gives a single tick before reseting but we are a bit friendlier to compensate for our slower execution. */ @@ -206,7 +211,7 @@ static void watchdog_hit(void *opaque) t->wd_hits++; } -static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value) +static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value) { unsigned int wd_en = t->rw_wd_ctrl & (1 << 8); unsigned int wd_key = t->rw_wd_ctrl >> 9; @@ -245,7 +250,7 @@ static void timer_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct etrax_timer *t = opaque; + ETRAXTimerState *t = opaque; uint32_t value = val64; switch (addr) @@ -298,7 +303,7 @@ static const MemoryRegionOps timer_ops = { static void etraxfs_timer_reset(void *opaque) { - struct etrax_timer *t = opaque; + ETRAXTimerState *t = opaque; ptimer_stop(t->ptimer_t0); ptimer_stop(t->ptimer_t1); @@ -311,7 +316,7 @@ static void etraxfs_timer_reset(void *opaque) static int etraxfs_timer_init(SysBusDevice *dev) { - struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev); + ETRAXTimerState *t = ETRAX_TIMER(dev); t->bh_t0 = qemu_bh_new(timer0_hit, t); t->bh_t1 = qemu_bh_new(timer1_hit, t); @@ -338,9 +343,9 @@ static void etraxfs_timer_class_init(ObjectClass *klass, void *data) } static const TypeInfo etraxfs_timer_info = { - .name = "etraxfs,timer", + .name = TYPE_ETRAX_FS_TIMER, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof (struct etrax_timer), + .instance_size = sizeof(ETRAXTimerState), .class_init = etraxfs_timer_class_init, }; diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 28ebe5dc7b..86f4fcd3e8 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -54,6 +54,7 @@ #include "hw/sysbus.h" #include "qemu/timer.h" +#include "qemu/main-loop.h" #include "qemu-common.h" #include "hw/ptimer.h" @@ -240,8 +241,13 @@ typedef struct { } Exynos4210MCTLT; +#define TYPE_EXYNOS4210_MCT "exynos4210.mct" +#define EXYNOS4210_MCT(obj) \ + OBJECT_CHECK(Exynos4210MCTState, (obj), TYPE_EXYNOS4210_MCT) + typedef struct Exynos4210MCTState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; /* Registers */ @@ -900,7 +906,7 @@ static void exynos4210_ltick_event(void *opaque) /* raise interrupt if enabled */ if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) { #ifdef DEBUG_MCT - time2[s->id] = qemu_get_clock_ns(vm_clock); + time2[s->id] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); DPRINTF("local timer[%d] IRQ: %llx\n", s->id, time2[s->id] - time1[s->id]); time1[s->id] = time2[s->id]; @@ -955,7 +961,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) /* set defaul_timer values for all fields */ static void exynos4210_mct_reset(DeviceState *d) { - Exynos4210MCTState *s = (Exynos4210MCTState *)d; + Exynos4210MCTState *s = EXYNOS4210_MCT(d); uint32_t i; s->reg_mct_cfg = 0; @@ -1424,7 +1430,7 @@ static const MemoryRegionOps exynos4210_mct_ops = { static int exynos4210_mct_init(SysBusDevice *dev) { int i; - Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev); + Exynos4210MCTState *s = EXYNOS4210_MCT(dev); QEMUBH *bh[2]; /* Global timer */ @@ -1467,7 +1473,7 @@ static void exynos4210_mct_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_mct_info = { - .name = "exynos4210.mct", + .name = TYPE_EXYNOS4210_MCT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210MCTState), .class_init = exynos4210_mct_class_init, diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 8fa0bb2b8f..1aa8f4d07a 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -23,6 +23,7 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" +#include "qemu/main-loop.h" #include "hw/ptimer.h" #include "hw/arm/exynos4210.h" @@ -97,9 +98,13 @@ typedef struct { } Exynos4210PWM; +#define TYPE_EXYNOS4210_PWM "exynos4210.pwm" +#define EXYNOS4210_PWM(obj) \ + OBJECT_CHECK(Exynos4210PWMState, (obj), TYPE_EXYNOS4210_PWM) typedef struct Exynos4210PWMState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t reg_tcfg[2]; @@ -352,7 +357,7 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset, */ static void exynos4210_pwm_reset(DeviceState *d) { - Exynos4210PWMState *s = (Exynos4210PWMState *)d; + Exynos4210PWMState *s = EXYNOS4210_PWM(d); int i; s->reg_tcfg[0] = 0x0101; s->reg_tcfg[1] = 0x0; @@ -378,7 +383,7 @@ static const MemoryRegionOps exynos4210_pwm_ops = { */ static int exynos4210_pwm_init(SysBusDevice *dev) { - Exynos4210PWMState *s = FROM_SYSBUS(Exynos4210PWMState, dev); + Exynos4210PWMState *s = EXYNOS4210_PWM(dev); int i; QEMUBH *bh; @@ -408,7 +413,7 @@ static void exynos4210_pwm_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_pwm_info = { - .name = "exynos4210.pwm", + .name = TYPE_EXYNOS4210_PWM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PWMState), .class_init = exynos4210_pwm_class_init, diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index 7fca071f1d..3f2c8c5578 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -79,8 +79,13 @@ #define RTC_BASE_FREQ 32768 +#define TYPE_EXYNOS4210_RTC "exynos4210.rtc" +#define EXYNOS4210_RTC(obj) \ + OBJECT_CHECK(Exynos4210RTCState, (obj), TYPE_EXYNOS4210_RTC) + typedef struct Exynos4210RTCState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; /* registers */ @@ -507,7 +512,7 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset, */ static void exynos4210_rtc_reset(DeviceState *d) { - Exynos4210RTCState *s = (Exynos4210RTCState *)d; + Exynos4210RTCState *s = EXYNOS4210_RTC(d); qemu_get_timedate(&s->current_tm, 0); @@ -544,7 +549,7 @@ static const MemoryRegionOps exynos4210_rtc_ops = { */ static int exynos4210_rtc_init(SysBusDevice *dev) { - Exynos4210RTCState *s = FROM_SYSBUS(Exynos4210RTCState, dev); + Exynos4210RTCState *s = EXYNOS4210_RTC(dev); QEMUBH *bh; bh = qemu_bh_new(exynos4210_rtc_tick, s); @@ -577,7 +582,7 @@ static void exynos4210_rtc_class_init(ObjectClass *klass, void *data) } static const TypeInfo exynos4210_rtc_info = { - .name = "exynos4210.rtc", + .name = TYPE_EXYNOS4210_RTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210RTCState), .class_init = exynos4210_rtc_class_init, diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index 37ba47d075..74c16d6c90 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -25,6 +25,8 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/ptimer.h" +#include "qemu/timer.h" +#include "qemu/main-loop.h" #include "trace.h" @@ -50,6 +52,10 @@ #define COUNTER_RELOAD_OFFSET 0x04 #define TIMER_BASE 0x10 +#define TYPE_GRLIB_GPTIMER "grlib,gptimer" +#define GRLIB_GPTIMER(obj) \ + OBJECT_CHECK(GPTimerUnit, (obj), TYPE_GRLIB_GPTIMER) + typedef struct GPTimer GPTimer; typedef struct GPTimerUnit GPTimerUnit; @@ -68,7 +74,8 @@ struct GPTimer { }; struct GPTimerUnit { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t nr_timers; /* Number of timers available */ @@ -314,7 +321,7 @@ static const MemoryRegionOps grlib_gptimer_ops = { static void grlib_gptimer_reset(DeviceState *d) { - GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev); + GPTimerUnit *unit = GRLIB_GPTIMER(d); int i = 0; assert(unit != NULL); @@ -343,7 +350,7 @@ static void grlib_gptimer_reset(DeviceState *d) static int grlib_gptimer_init(SysBusDevice *dev) { - GPTimerUnit *unit = FROM_SYSBUS(typeof(*unit), dev); + GPTimerUnit *unit = GRLIB_GPTIMER(dev); unsigned int i; assert(unit->nr_timers > 0); @@ -391,7 +398,7 @@ static void grlib_gptimer_class_init(ObjectClass *klass, void *data) } static const TypeInfo grlib_gptimer_info = { - .name = "grlib,gptimer", + .name = TYPE_GRLIB_GPTIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPTimerUnit), .class_init = grlib_gptimer_class_init, diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 648b38362d..fcd22aea59 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -152,7 +152,7 @@ static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask) static uint64_t hpet_get_ticks(HPETState *s) { - return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset); + return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset); } /* @@ -233,7 +233,7 @@ static int hpet_post_load(void *opaque, int version_id) HPETState *s = opaque; /* Recalculate the offset between the main counter and guest time */ - s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock); + s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Push number of timers into capability returned via HPET_ID */ s->capability &= ~HPET_ID_NUM_TIM_MASK; @@ -332,12 +332,12 @@ static void hpet_timer(void *opaque) } } diff = hpet_calculate_diff(t, cur_tick); - qemu_mod_timer(t->qemu_timer, - qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff)); + timer_mod(t->qemu_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { if (t->wrap_flag) { diff = hpet_calculate_diff(t, cur_tick); - qemu_mod_timer(t->qemu_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(t->qemu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); t->wrap_flag = 0; } @@ -365,13 +365,13 @@ static void hpet_set_timer(HPETTimer *t) t->wrap_flag = 1; } } - qemu_mod_timer(t->qemu_timer, - qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff)); + timer_mod(t->qemu_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); } static void hpet_del_timer(HPETTimer *t) { - qemu_del_timer(t->qemu_timer); + timer_del(t->qemu_timer); update_irq(t, 0); } @@ -567,7 +567,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { /* Enable main counter and interrupt generation. */ s->hpet_offset = - ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock); + ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); for (i = 0; i < s->num_timers; i++) { if ((&s->timer[i])->cmp != ~0ULL) { hpet_set_timer(&s->timer[i]); @@ -726,7 +726,7 @@ static void hpet_realize(DeviceState *dev, Error **errp) } for (i = 0; i < HPET_MAX_TIMERS; i++) { timer = &s->timer[i]; - timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer); + timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer); timer->tn = i; timer->state = s; } diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index cd5214064f..cdbf481951 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -51,7 +51,7 @@ static int pit_get_count(PITChannelState *s) uint64_t d; int counter; - d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ, + d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->count_load_time, PIT_FREQ, get_ticks_per_sec()); switch(s->mode) { case 0: @@ -85,7 +85,7 @@ static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc, case 5: if (sc->gate < val) { /* restart counting on rising edge */ - sc->count_load_time = qemu_get_clock_ns(vm_clock); + sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); pit_irq_timer_update(sc, sc->count_load_time); } break; @@ -93,7 +93,7 @@ static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc, case 3: if (sc->gate < val) { /* restart counting on rising edge */ - sc->count_load_time = qemu_get_clock_ns(vm_clock); + sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); pit_irq_timer_update(sc, sc->count_load_time); } /* XXX: disable/enable counting */ @@ -106,7 +106,7 @@ static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) val = 0x10000; - s->count_load_time = qemu_get_clock_ns(vm_clock); + s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->count = val; pit_irq_timer_update(s, s->count_load_time); } @@ -143,7 +143,7 @@ static void pit_ioport_write(void *opaque, hwaddr addr, /* XXX: add BCD and null count */ s->status = (pit_get_out(s, - qemu_get_clock_ns(vm_clock)) << 7) | + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) << 7) | (s->rw_mode << 4) | (s->mode << 1) | s->bcd; @@ -260,9 +260,9 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) #endif s->next_transition_time = expire_time; if (expire_time != -1) - qemu_mod_timer(s->irq_timer, expire_time); + timer_mod(s->irq_timer, expire_time); else - qemu_del_timer(s->irq_timer); + timer_del(s->irq_timer); } static void pit_irq_timer(void *opaque) @@ -281,7 +281,7 @@ static void pit_reset(DeviceState *dev) s = &pit->channels[0]; if (!s->irq_disabled) { - qemu_mod_timer(s->irq_timer, s->next_transition_time); + timer_mod(s->irq_timer, s->next_transition_time); } } @@ -294,10 +294,10 @@ static void pit_irq_control(void *opaque, int n, int enable) if (enable) { s->irq_disabled = 0; - pit_irq_timer_update(s, qemu_get_clock_ns(vm_clock)); + pit_irq_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } else { s->irq_disabled = 1; - qemu_del_timer(s->irq_timer); + timer_del(s->irq_timer); } } @@ -316,9 +316,9 @@ static void pit_post_load(PITCommonState *s) PITChannelState *sc = &s->channels[0]; if (sc->next_transition_time != -1) { - qemu_mod_timer(sc->irq_timer, sc->next_transition_time); + timer_mod(sc->irq_timer, sc->next_transition_time); } else { - qemu_del_timer(sc->irq_timer); + timer_del(sc->irq_timer); } } @@ -330,7 +330,7 @@ static void pit_realizefn(DeviceState *dev, Error **err) s = &pit->channels[0]; /* the timer 0 is connected to an IRQ */ - s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s); + s->irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pit_irq_timer, s); qdev_init_gpio_out(dev, &s->irq, 1); memory_region_init_io(&pit->ioports, OBJECT(pit), &pit_ioport_ops, diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c index 4e5bf0b63c..e8fb971488 100644 --- a/hw/timer/i8254_common.c +++ b/hw/timer/i8254_common.c @@ -136,7 +136,7 @@ void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc, info->gate = sc->gate; info->mode = sc->mode; info->initial_count = sc->count; - info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock)); + info->out = pit_get_out(sc, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info) @@ -157,7 +157,7 @@ void pit_reset_common(PITCommonState *pit) s = &pit->channels[i]; s->mode = 3; s->gate = (i != 2); - s->count_load_time = qemu_get_clock_ns(vm_clock); + s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->count = 0x10000; if (i == 0 && !s->irq_disabled) { s->next_transition_time = diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index 117dc7bcbb..0dbe15c99b 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -18,6 +18,7 @@ #include "hw/ptimer.h" #include "hw/sysbus.h" #include "hw/arm/imx.h" +#include "qemu/main-loop.h" #define TYPE_IMX_EPIT "imx.epit" @@ -43,7 +44,7 @@ static char const *imx_epit_reg_name(uint32_t reg) } # define DPRINTF(fmt, args...) \ - do { printf("%s: " fmt , __func__, ##args); } while (0) + do { fprintf(stderr, "%s: " fmt , __func__, ##args); } while (0) #else # define DPRINTF(fmt, args...) do {} while (0) #endif @@ -152,7 +153,7 @@ static void imx_epit_reset(DeviceState *dev) /* * Soft reset doesn't touch some bits; hard reset clears them */ - s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); + s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); s->sr = 0; s->lr = TIMER_MAX; s->cmp = 0; @@ -167,7 +168,7 @@ static void imx_epit_reset(DeviceState *dev) ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); if (s->freq && (s->cr & CR_EN)) { /* if the timer is still enabled, restart it */ - ptimer_run(s->timer_reload, 1); + ptimer_run(s->timer_reload, 0); } } @@ -218,17 +219,17 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) static void imx_epit_reload_compare_timer(IMXEPITState *s) { - if ((s->cr & CR_OCIEN) && s->cmp) { - /* if the compare feature is on */ + if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { + /* if the compare feature is on and timers are running */ uint32_t tmp = imx_epit_update_count(s); + uint64_t next; if (tmp > s->cmp) { - /* reinit the cmp timer if required */ - ptimer_set_count(s->timer_cmp, tmp - s->cmp); - if ((s->cr & CR_EN)) { - /* Restart the cmp timer if required */ - ptimer_run(s->timer_cmp, 0); - } + /* It'll fire in this round of the timer */ + next = tmp - s->cmp; + } else { /* catch it next time around */ + next = tmp - s->cmp + ((s->cr & CR_RLD) ? TIMER_MAX : s->lr); } + ptimer_set_count(s->timer_cmp, next); } } @@ -237,11 +238,14 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, { IMXEPITState *s = IMX_EPIT(opaque); uint32_t reg = offset >> 2; + uint64_t oldcr; DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value); switch (reg) { case 0: /* CR */ + + oldcr = s->cr; s->cr = value & 0x03ffffff; if (s->cr & CR_SWR) { /* handle the reset */ @@ -250,22 +254,35 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, imx_epit_set_freq(s); } - if (s->freq && (s->cr & CR_EN)) { + if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) { if (s->cr & CR_ENMOD) { if (s->cr & CR_RLD) { ptimer_set_limit(s->timer_reload, s->lr, 1); + ptimer_set_limit(s->timer_cmp, s->lr, 1); } else { ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1); } } imx_epit_reload_compare_timer(s); - - ptimer_run(s->timer_reload, 1); - } else { + ptimer_run(s->timer_reload, 0); + if (s->cr & CR_OCIEN) { + ptimer_run(s->timer_cmp, 0); + } else { + ptimer_stop(s->timer_cmp); + } + } else if (!(s->cr & CR_EN)) { /* stop both timers */ ptimer_stop(s->timer_reload); ptimer_stop(s->timer_cmp); + } else if (s->cr & CR_OCIEN) { + if (!(oldcr & CR_OCIEN)) { + imx_epit_reload_compare_timer(s); + ptimer_run(s->timer_cmp, 0); + } + } else { + ptimer_stop(s->timer_cmp); } break; @@ -284,13 +301,13 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, /* Also set the limit if the LRD bit is set */ /* If IOVW bit is set then set the timer value */ ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); + ptimer_set_limit(s->timer_cmp, s->lr, 0); } else if (s->cr & CR_IOVW) { /* If IOVW bit is set then set the timer value */ ptimer_set_count(s->timer_reload, s->lr); } imx_epit_reload_compare_timer(s); - break; case 3: /* CMP */ @@ -306,51 +323,14 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, break; } } - -static void imx_epit_timeout(void *opaque) -{ - IMXEPITState *s = IMX_EPIT(opaque); - - DPRINTF("\n"); - - if (!(s->cr & CR_EN)) { - return; - } - - if (s->cr & CR_RLD) { - ptimer_set_limit(s->timer_reload, s->lr, 1); - } else { - ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); - } - - if (s->cr & CR_OCIEN) { - /* if compare register is 0 then we handle the interrupt here */ - if (s->cmp == 0) { - s->sr = 1; - imx_epit_update_int(s); - } else if (s->cmp <= s->lr) { - /* We should launch the compare register */ - ptimer_set_count(s->timer_cmp, s->lr - s->cmp); - ptimer_run(s->timer_cmp, 0); - } else { - IPRINTF("s->lr < s->cmp\n"); - } - } -} - static void imx_epit_cmp(void *opaque) { IMXEPITState *s = IMX_EPIT(opaque); - DPRINTF("\n"); - - ptimer_stop(s->timer_cmp); + DPRINTF("sr was %d\n", s->sr); - /* compare register is not 0 */ - if (s->cmp) { - s->sr = 1; - imx_epit_update_int(s); - } + s->sr = 1; + imx_epit_update_int(s); } void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) @@ -400,8 +380,7 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - bh = qemu_bh_new(imx_epit_timeout, s); - s->timer_reload = ptimer_init(bh); + s->timer_reload = ptimer_init(NULL); bh = qemu_bh_new(imx_epit_cmp, s); s->timer_cmp = ptimer_init(bh); diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 87db0e195c..f2d1975e70 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -18,6 +18,7 @@ #include "hw/ptimer.h" #include "hw/sysbus.h" #include "hw/arm/imx.h" +#include "qemu/main-loop.h" #define TYPE_IMX_GPT "imx.gpt" diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index 016dade3e9..8ed138cc0e 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -27,6 +27,7 @@ #include "qemu/timer.h" #include "hw/ptimer.h" #include "qemu/error-report.h" +#include "qemu/main-loop.h" #define DEFAULT_FREQUENCY (50*1000000) @@ -50,8 +51,12 @@ enum { CR_STOP = (1 << 3), }; +#define TYPE_LM32_TIMER "lm32-timer" +#define LM32_TIMER(obj) OBJECT_CHECK(LM32TimerState, (obj), TYPE_LM32_TIMER) + struct LM32TimerState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; QEMUBH *bh; @@ -161,7 +166,7 @@ static void timer_hit(void *opaque) static void timer_reset(DeviceState *d) { - LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev); + LM32TimerState *s = LM32_TIMER(d); int i; for (i = 0; i < R_MAX; i++) { @@ -172,7 +177,7 @@ static void timer_reset(DeviceState *d) static int lm32_timer_init(SysBusDevice *dev) { - LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev); + LM32TimerState *s = LM32_TIMER(dev); sysbus_init_irq(dev, &s->irq); @@ -217,7 +222,7 @@ static void lm32_timer_class_init(ObjectClass *klass, void *data) } static const TypeInfo lm32_timer_info = { - .name = "lm32-timer", + .name = TYPE_LM32_TIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32TimerState), .class_init = lm32_timer_class_init, diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c index be3490bca3..d3d78ec5a8 100644 --- a/hw/timer/m48t59.c +++ b/hw/timer/m48t59.c @@ -83,8 +83,12 @@ typedef struct M48t59ISAState { MemoryRegion io; } M48t59ISAState; +#define SYSBUS_M48T59(obj) \ + OBJECT_CHECK(M48t59SysBusState, (obj), TYPE_SYSBUS_M48T59) + typedef struct M48t59SysBusState { - SysBusDevice busdev; + SysBusDevice parent_obj; + M48t59State state; MemoryRegion io; } M48t59SysBusState; @@ -133,7 +137,7 @@ static void alarm_cb (void *opaque) /* Repeat once a second */ next_time = 1; } - qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) + + timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) + next_time * 1000); qemu_set_irq(NVRAM->IRQ, 0); } @@ -142,10 +146,10 @@ static void set_alarm(M48t59State *NVRAM) { int diff; if (NVRAM->alrm_timer != NULL) { - qemu_del_timer(NVRAM->alrm_timer); + timer_del(NVRAM->alrm_timer); diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset; if (diff > 0) - qemu_mod_timer(NVRAM->alrm_timer, diff * 1000); + timer_mod(NVRAM->alrm_timer, diff * 1000); } } @@ -184,10 +188,10 @@ static void set_up_watchdog(M48t59State *NVRAM, uint8_t value) NVRAM->buffer[0x1FF0] &= ~0x80; if (NVRAM->wd_timer != NULL) { - qemu_del_timer(NVRAM->wd_timer); + timer_del(NVRAM->wd_timer); if (value != 0) { interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); - qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + + timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + ((interval * 1000) >> 4)); } } @@ -605,10 +609,10 @@ static void m48t59_reset_common(M48t59State *NVRAM) NVRAM->addr = 0; NVRAM->lock = 0; if (NVRAM->alrm_timer != NULL) - qemu_del_timer(NVRAM->alrm_timer); + timer_del(NVRAM->alrm_timer); if (NVRAM->wd_timer != NULL) - qemu_del_timer(NVRAM->wd_timer); + timer_del(NVRAM->wd_timer); } static void m48t59_reset_isa(DeviceState *d) @@ -621,7 +625,7 @@ static void m48t59_reset_isa(DeviceState *d) static void m48t59_reset_sysbus(DeviceState *d) { - M48t59SysBusState *sys = container_of(d, M48t59SysBusState, busdev.qdev); + M48t59SysBusState *sys = SYSBUS_M48T59(d); M48t59State *NVRAM = &sys->state; m48t59_reset_common(NVRAM); @@ -646,13 +650,13 @@ M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base, M48t59SysBusState *d; M48t59State *state; - dev = qdev_create(NULL, "m48t59"); + dev = qdev_create(NULL, TYPE_SYSBUS_M48T59); qdev_prop_set_uint32(dev, "model", model); qdev_prop_set_uint32(dev, "size", size); qdev_prop_set_uint32(dev, "io_base", io_base); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); - d = FROM_SYSBUS(M48t59SysBusState, s); + d = SYSBUS_M48T59(dev); state = &d->state; sysbus_connect_irq(s, 0, IRQ); memory_region_init_io(&d->io, OBJECT(d), &m48t59_io_ops, state, @@ -696,8 +700,8 @@ static void m48t59_realize_common(M48t59State *s, Error **errp) { s->buffer = g_malloc0(s->size); if (s->model == 59) { - s->alrm_timer = qemu_new_timer_ns(rtc_clock, &alarm_cb, s); - s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s); + s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s); + s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s); } qemu_get_timedate(&s->alarm, 0); @@ -716,7 +720,7 @@ static void m48t59_isa_realize(DeviceState *dev, Error **errp) static int m48t59_init1(SysBusDevice *dev) { - M48t59SysBusState *d = FROM_SYSBUS(M48t59SysBusState, dev); + M48t59SysBusState *d = SYSBUS_M48T59(dev); M48t59State *s = &d->state; Error *err = NULL; @@ -776,7 +780,7 @@ static void m48t59_class_init(ObjectClass *klass, void *data) } static const TypeInfo m48t59_info = { - .name = "m48t59", + .name = TYPE_SYSBUS_M48T59, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(M48t59SysBusState), .class_init = m48t59_class_init, diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 3c3baaccfa..7230a6e4fa 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -102,7 +102,7 @@ static inline bool rtc_running(RTCState *s) static uint64_t get_guest_rtc_ns(RTCState *s) { uint64_t guest_rtc; - uint64_t guest_clock = qemu_get_clock_ns(rtc_clock); + uint64_t guest_clock = qemu_clock_get_ns(rtc_clock); guest_rtc = s->base_rtc * NSEC_PER_SEC + guest_clock - s->last_update + s->offset; @@ -113,13 +113,13 @@ static uint64_t get_guest_rtc_ns(RTCState *s) static void rtc_coalesced_timer_update(RTCState *s) { if (s->irq_coalesced == 0) { - qemu_del_timer(s->coalesced_timer); + timer_del(s->coalesced_timer); } else { /* 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) + + int64_t next_clock = qemu_clock_get_ns(rtc_clock) + muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE); - qemu_mod_timer(s->coalesced_timer, next_clock); + timer_mod(s->coalesced_timer, next_clock); } } @@ -169,12 +169,12 @@ static void periodic_timer_update(RTCState *s, int64_t current_time) next_irq_clock = (cur_clock & ~(period - 1)) + period; s->next_periodic_time = muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1; - qemu_mod_timer(s->periodic_timer, s->next_periodic_time); + timer_mod(s->periodic_timer, s->next_periodic_time); } else { #ifdef TARGET_I386 s->irq_coalesced = 0; #endif - qemu_del_timer(s->periodic_timer); + timer_del(s->periodic_timer); } } @@ -222,23 +222,23 @@ static void check_update_timer(RTCState *s) * 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); + timer_del(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); + timer_del(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); + timer_del(s->update_timer); return; } guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC; /* if UF is clear, reprogram to next second */ - next_update_time = qemu_get_clock_ns(rtc_clock) + next_update_time = qemu_clock_get_ns(rtc_clock) + NSEC_PER_SEC - guest_nsec; /* Compute time of next alarm. One second is already accounted @@ -252,8 +252,8 @@ static void check_update_timer(RTCState *s) * 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); + if (next_update_time != timer_expire_time_ns(s->update_timer)) { + timer_mod(s->update_timer, next_update_time); } } @@ -371,7 +371,7 @@ static void rtc_update_timer(void *opaque) rtc_update_time(s); s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - if (qemu_get_clock_ns(rtc_clock) >= s->next_alarm_time) { + if (qemu_clock_get_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); @@ -445,7 +445,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, /* UIP bit is read only */ 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)); + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); check_update_timer(s); break; case RTC_REG_B: @@ -475,7 +475,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, qemu_irq_lower(s->irq); } s->cmos_data[RTC_REG_B] = data; - periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); check_update_timer(s); break; case RTC_REG_C: @@ -535,7 +535,7 @@ static void rtc_set_time(RTCState *s) rtc_get_time(s, &tm); s->base_rtc = mktimegm(&tm); - s->last_update = qemu_get_clock_ns(rtc_clock); + s->last_update = qemu_clock_get_ns(rtc_clock); rtc_change_mon_event(&tm); } @@ -587,10 +587,11 @@ static int update_in_progress(RTCState *s) if (!rtc_running(s)) { return 0; } - if (qemu_timer_pending(s->update_timer)) { - int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer); + if (timer_pending(s->update_timer)) { + int64_t next_update_time = 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)) { + if (qemu_clock_get_ns(rtc_clock) >= + (next_update_time - UIP_HOLD_LENGTH)) { s->cmos_data[RTC_REG_A] |= REG_A_UIP; return 1; } @@ -695,7 +696,7 @@ static void rtc_set_date_from_host(ISADevice *dev) qemu_get_timedate(&tm, 0); s->base_rtc = mktimegm(&tm); - s->last_update = qemu_get_clock_ns(rtc_clock); + s->last_update = qemu_clock_get_ns(rtc_clock); s->offset = 0; /* set the CMOS date */ @@ -843,7 +844,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) switch (s->lost_tick_policy) { case LOST_TICK_SLEW: s->coalesced_timer = - qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s); + timer_new_ns(rtc_clock, rtc_coalesced_timer, s); break; case LOST_TICK_DISCARD: break; @@ -853,12 +854,13 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) } #endif - s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s); - s->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s); + s->periodic_timer = timer_new_ns(rtc_clock, rtc_periodic_timer, s); + s->update_timer = timer_new_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); + qemu_clock_register_reset_notifier(QEMU_CLOCK_REALTIME, + &s->clock_reset_notifier); s->suspend_notifier.notify = rtc_notify_suspend; qemu_register_suspend_notifier(&s->suspend_notifier); diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 5009394930..94246e56f6 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -57,8 +57,13 @@ enum { R_MAX }; +#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl" +#define MILKYMIST_SYSCTL(obj) \ + OBJECT_CHECK(MilkymistSysctlState, (obj), TYPE_MILKYMIST_SYSCTL) + struct MilkymistSysctlState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion regs_region; QEMUBH *bh0; @@ -246,8 +251,7 @@ static void timer1_hit(void *opaque) static void milkymist_sysctl_reset(DeviceState *d) { - MilkymistSysctlState *s = - container_of(d, MilkymistSysctlState, busdev.qdev); + MilkymistSysctlState *s = MILKYMIST_SYSCTL(d); int i; for (i = 0; i < R_MAX; i++) { @@ -267,7 +271,7 @@ static void milkymist_sysctl_reset(DeviceState *d) static int milkymist_sysctl_init(SysBusDevice *dev) { - MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); sysbus_init_irq(dev, &s->gpio_irq); sysbus_init_irq(dev, &s->timer0_irq); @@ -324,7 +328,7 @@ static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) } static const TypeInfo milkymist_sysctl_info = { - .name = "milkymist-sysctl", + .name = TYPE_MILKYMIST_SYSCTL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSysctlState), .class_init = milkymist_sysctl_class_init, diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c index ac389d87ee..016207f626 100644 --- a/hw/timer/omap_gptimer.c +++ b/hw/timer/omap_gptimer.c @@ -103,7 +103,7 @@ static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) uint64_t distance; if (timer->st && timer->rate) { - distance = qemu_get_clock_ns(vm_clock) - timer->time; + distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time; distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); if (distance >= 0xffffffff - timer->val) @@ -118,7 +118,7 @@ static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) { if (timer->st) { timer->val = omap_gp_timer_read(timer); - timer->time = qemu_get_clock_ns(vm_clock); + timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } } @@ -129,17 +129,17 @@ static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) if (timer->st && timer->rate) { expires = muldiv64(0x100000000ll - timer->val, timer->ticks_per_sec, timer->rate); - qemu_mod_timer(timer->timer, timer->time + expires); + timer_mod(timer->timer, timer->time + expires); if (timer->ce && timer->match_val >= timer->val) { matches = muldiv64(timer->match_val - timer->val, timer->ticks_per_sec, timer->rate); - qemu_mod_timer(timer->match, timer->time + matches); + timer_mod(timer->match, timer->time + matches); } else - qemu_del_timer(timer->match); + timer_del(timer->match); } else { - qemu_del_timer(timer->timer); - qemu_del_timer(timer->match); + timer_del(timer->timer); + timer_del(timer->match); omap_gp_timer_out(timer, timer->scpwm); } } @@ -164,7 +164,7 @@ static void omap_gp_timer_tick(void *opaque) timer->val = 0; } else { timer->val = timer->load_val; - timer->time = qemu_get_clock_ns(vm_clock); + timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } if (timer->trigger == gpt_trigger_overflow || @@ -406,7 +406,7 @@ static void omap_gp_timer_write(void *opaque, hwaddr addr, break; case 0x28: /* TCRR */ - s->time = qemu_get_clock_ns(vm_clock); + s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->val = value; omap_gp_timer_update(s); break; @@ -416,7 +416,7 @@ static void omap_gp_timer_write(void *opaque, hwaddr addr, break; case 0x30: /* TTGR */ - s->time = qemu_get_clock_ns(vm_clock); + s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->val = s->load_val; omap_gp_timer_update(s); break; @@ -474,8 +474,8 @@ struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, s->ta = ta; s->irq = irq; s->clk = fclk; - s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s); - s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s); + s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s); s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0]; omap_gp_timer_reset(s); omap_gp_timer_clk_setup(s); diff --git a/hw/timer/omap_synctimer.c b/hw/timer/omap_synctimer.c index a12aca20df..8e50488d17 100644 --- a/hw/timer/omap_synctimer.c +++ b/hw/timer/omap_synctimer.c @@ -28,7 +28,7 @@ struct omap_synctimer_s { /* 32-kHz Sync Timer of the OMAP2 */ static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) { - return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec()); + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000, get_ticks_per_sec()); } void omap_synctimer_reset(struct omap_synctimer_s *s) diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c index 3ce6ed8ae1..65928a4819 100644 --- a/hw/timer/pl031.c +++ b/hw/timer/pl031.c @@ -33,8 +33,12 @@ do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0) #define RTC_MIS 0x18 /* Masked interrupt status register */ #define RTC_ICR 0x1c /* Interrupt clear register */ -typedef struct { - SysBusDevice busdev; +#define TYPE_PL031 "pl031" +#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031) + +typedef struct PL031State { + SysBusDevice parent_obj; + MemoryRegion iomem; QEMUTimer *timer; qemu_irq irq; @@ -51,34 +55,34 @@ typedef struct { uint32_t cr; uint32_t im; uint32_t is; -} pl031_state; +} PL031State; static const unsigned char pl031_id[] = { 0x31, 0x10, 0x14, 0x00, /* Device ID */ 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */ }; -static void pl031_update(pl031_state *s) +static void pl031_update(PL031State *s) { qemu_set_irq(s->irq, s->is & s->im); } static void pl031_interrupt(void * opaque) { - pl031_state *s = (pl031_state *)opaque; + PL031State *s = (PL031State *)opaque; s->is = 1; DPRINTF("Alarm raised\n"); pl031_update(s); } -static uint32_t pl031_get_count(pl031_state *s) +static uint32_t pl031_get_count(PL031State *s) { - int64_t now = qemu_get_clock_ns(rtc_clock); + int64_t now = qemu_clock_get_ns(rtc_clock); return s->tick_offset + now / get_ticks_per_sec(); } -static void pl031_set_alarm(pl031_state *s) +static void pl031_set_alarm(PL031State *s) { uint32_t ticks; @@ -87,18 +91,18 @@ static void pl031_set_alarm(pl031_state *s) ticks = s->mr - pl031_get_count(s); DPRINTF("Alarm set in %ud ticks\n", ticks); if (ticks == 0) { - qemu_del_timer(s->timer); + timer_del(s->timer); pl031_interrupt(s); } else { - int64_t now = qemu_get_clock_ns(rtc_clock); - qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec()); + int64_t now = qemu_clock_get_ns(rtc_clock); + timer_mod(s->timer, now + (int64_t)ticks * get_ticks_per_sec()); } } static uint64_t pl031_read(void *opaque, hwaddr offset, unsigned size) { - pl031_state *s = (pl031_state *)opaque; + PL031State *s = (PL031State *)opaque; if (offset >= 0xfe0 && offset < 0x1000) return pl031_id[(offset - 0xfe0) >> 2]; @@ -136,7 +140,7 @@ static uint64_t pl031_read(void *opaque, hwaddr offset, static void pl031_write(void * opaque, hwaddr offset, uint64_t value, unsigned size) { - pl031_state *s = (pl031_state *)opaque; + PL031State *s = (PL031State *)opaque; switch (offset) { @@ -189,7 +193,7 @@ static const MemoryRegionOps pl031_ops = { static int pl031_init(SysBusDevice *dev) { - pl031_state *s = FROM_SYSBUS(pl031_state, dev); + PL031State *s = PL031(dev); struct tm tm; memory_region_init_io(&s->iomem, OBJECT(s), &pl031_ops, s, "pl031", 0x1000); @@ -197,27 +201,28 @@ static int pl031_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); qemu_get_timedate(&tm, 0); - s->tick_offset = mktimegm(&tm) - qemu_get_clock_ns(rtc_clock) / get_ticks_per_sec(); + s->tick_offset = mktimegm(&tm) - + qemu_clock_get_ns(rtc_clock) / get_ticks_per_sec(); - s->timer = qemu_new_timer_ns(rtc_clock, pl031_interrupt, s); + s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s); return 0; } static void pl031_pre_save(void *opaque) { - pl031_state *s = opaque; + PL031State *s = opaque; /* tick_offset is base_time - rtc_clock base time. Instead, we want to - * store the base time relative to the vm_clock for backwards-compatibility. */ - int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock); + * store the base time relative to the QEMU_CLOCK_VIRTUAL for backwards-compatibility. */ + int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tick_offset_vmstate = s->tick_offset + delta / get_ticks_per_sec(); } static int pl031_post_load(void *opaque, int version_id) { - pl031_state *s = opaque; + PL031State *s = opaque; - int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock); + int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tick_offset = s->tick_offset_vmstate - delta / get_ticks_per_sec(); pl031_set_alarm(s); return 0; @@ -230,12 +235,12 @@ static const VMStateDescription vmstate_pl031 = { .pre_save = pl031_pre_save, .post_load = pl031_post_load, .fields = (VMStateField[]) { - VMSTATE_UINT32(tick_offset_vmstate, pl031_state), - VMSTATE_UINT32(mr, pl031_state), - VMSTATE_UINT32(lr, pl031_state), - VMSTATE_UINT32(cr, pl031_state), - VMSTATE_UINT32(im, pl031_state), - VMSTATE_UINT32(is, pl031_state), + VMSTATE_UINT32(tick_offset_vmstate, PL031State), + VMSTATE_UINT32(mr, PL031State), + VMSTATE_UINT32(lr, PL031State), + VMSTATE_UINT32(cr, PL031State), + VMSTATE_UINT32(im, PL031State), + VMSTATE_UINT32(is, PL031State), VMSTATE_END_OF_LIST() } }; @@ -251,9 +256,9 @@ static void pl031_class_init(ObjectClass *klass, void *data) } static const TypeInfo pl031_info = { - .name = "pl031", + .name = TYPE_PL031, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(pl031_state), + .instance_size = sizeof(PL031State), .class_init = pl031_class_init, }; diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c index 63f2c9f028..fa9eefd925 100644 --- a/hw/timer/puv3_ost.c +++ b/hw/timer/puv3_ost.c @@ -10,13 +10,18 @@ */ #include "hw/sysbus.h" #include "hw/ptimer.h" +#include "qemu/main-loop.h" #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" +#define TYPE_PUV3_OST "puv3_ost" +#define PUV3_OST(obj) OBJECT_CHECK(PUV3OSTState, (obj), TYPE_PUV3_OST) + /* puv3 ostimer implementation. */ -typedef struct { - SysBusDevice busdev; +typedef struct PUV3OSTState { + SysBusDevice parent_obj; + MemoryRegion iomem; QEMUBH *bh; qemu_irq irq; @@ -109,7 +114,7 @@ static void puv3_ost_tick(void *opaque) static int puv3_ost_init(SysBusDevice *dev) { - PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev); + PUV3OSTState *s = PUV3_OST(dev); s->reg_OIER = 0; s->reg_OSSR = 0; @@ -137,7 +142,7 @@ static void puv3_ost_class_init(ObjectClass *klass, void *data) } static const TypeInfo puv3_ost_info = { - .name = "puv3_ost", + .name = TYPE_PUV3_OST, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PUV3OSTState), .class_init = puv3_ost_class_init, diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 4d28719bb1..0f546c4121 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -60,6 +60,10 @@ static int pxa2xx_timer4_freq[8] = { [5 ... 7] = 0, }; +#define TYPE_PXA2XX_TIMER "pxa2xx-timer" +#define PXA2XX_TIMER(obj) \ + OBJECT_CHECK(PXA2xxTimerInfo, (obj), TYPE_PXA2XX_TIMER) + typedef struct PXA2xxTimerInfo PXA2xxTimerInfo; typedef struct { @@ -80,7 +84,8 @@ typedef struct { } PXA2xxTimer4; struct PXA2xxTimerInfo { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; uint32_t flags; @@ -118,7 +123,7 @@ static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) for (i = 0; i < 4; i ++) { new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), get_ticks_per_sec(), s->freq); - qemu_mod_timer(s->timer[i].qtimer, new_qemu); + timer_mod(s->timer[i].qtimer, new_qemu); } } @@ -136,7 +141,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) counter = counters[n]; if (!s->tm4[counter].freq) { - qemu_del_timer(s->tm4[n].tm.qtimer); + timer_del(s->tm4[n].tm.qtimer); return; } @@ -146,7 +151,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), get_ticks_per_sec(), s->tm4[counter].freq); - qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu); + timer_mod(s->tm4[n].tm.qtimer, new_qemu); } static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, @@ -183,7 +188,7 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, goto badreg; return s->tm4[tm].tm.value; case OSCR: - return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) - + return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->lastload, s->freq, get_ticks_per_sec()); case OSCR11: tm ++; /* fall through */ @@ -206,7 +211,7 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { if (s->tm4[tm - 1].freq) s->snapshot = s->tm4[tm - 1].clock + muldiv64( - qemu_get_clock_ns(vm_clock) - + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->tm4[tm - 1].lastload, s->tm4[tm - 1].freq, get_ticks_per_sec()); else @@ -215,7 +220,7 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, if (!s->tm4[tm].freq) return s->tm4[tm].clock; - return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) - + return s->tm4[tm].clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec()); case OIER: return s->irq_enabled; @@ -266,7 +271,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, /* fall through */ case OSMR0: s->timer[tm].value = value; - pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock)); + pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; case OSMR11: tm ++; /* fall through */ @@ -286,11 +291,11 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, if (!pxa2xx_timer_has_tm4(s)) goto badreg; s->tm4[tm].tm.value = value; - pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm); + pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); break; case OSCR: s->oldclock = s->clock; - s->lastload = qemu_get_clock_ns(vm_clock); + s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->clock = value; pxa2xx_timer_update(s, s->lastload); break; @@ -312,7 +317,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, if (!pxa2xx_timer_has_tm4(s)) goto badreg; s->tm4[tm].oldclock = s->tm4[tm].clock; - s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock); + s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tm4[tm].clock = value; pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); break; @@ -346,7 +351,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; else { s->tm4[tm].freq = 0; - pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm); + pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); } break; case OMCR11: tm ++; @@ -365,7 +370,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; else { s->tm4[tm].freq = 0; - pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm); + pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); } break; default: @@ -406,7 +411,7 @@ static void pxa2xx_timer_tick4(void *opaque) if (t->control & (1 << 3)) t->clock = 0; if (t->control & (1 << 6)) - pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4); + pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); if (i->events & 0xff0) qemu_irq_raise(i->irq4); } @@ -417,7 +422,7 @@ static int pxa25x_timer_post_load(void *opaque, int version_id) int64_t now; int i; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); pxa2xx_timer_update(s, now); if (pxa2xx_timer_has_tm4(s)) @@ -429,14 +434,13 @@ static int pxa25x_timer_post_load(void *opaque, int version_id) static int pxa2xx_timer_init(SysBusDevice *dev) { + PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); int i; - PXA2xxTimerInfo *s; - s = FROM_SYSBUS(PXA2xxTimerInfo, dev); s->irq_enabled = 0; s->oldclock = 0; s->clock = 0; - s->lastload = qemu_get_clock_ns(vm_clock); + s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->reset3 = 0; for (i = 0; i < 4; i ++) { @@ -444,7 +448,7 @@ static int pxa2xx_timer_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->timer[i].irq); s->timer[i].info = s; s->timer[i].num = i; - s->timer[i].qtimer = qemu_new_timer_ns(vm_clock, + s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pxa2xx_timer_tick, &s->timer[i]); } if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { @@ -456,7 +460,7 @@ static int pxa2xx_timer_init(SysBusDevice *dev) s->tm4[i].tm.num = i + 4; s->tm4[i].freq = 0; s->tm4[i].control = 0x0; - s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock, + s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pxa2xx_timer_tick4, &s->tm4[i]); } } @@ -527,24 +531,21 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = { static Property pxa25x_timer_dev_properties[] = { DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, - PXA2XX_TIMER_HAVE_TM4, false), + PXA2XX_TIMER_HAVE_TM4, false), DEFINE_PROP_END_OF_LIST(), }; static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = pxa2xx_timer_init; dc->desc = "PXA25x timer"; - dc->vmsd = &vmstate_pxa2xx_timer_regs; dc->props = pxa25x_timer_dev_properties; } static const TypeInfo pxa25x_timer_dev_info = { .name = "pxa25x-timer", - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_PXA2XX_TIMER, .instance_size = sizeof(PXA2xxTimerInfo), .class_init = pxa25x_timer_dev_class_init, }; @@ -552,30 +553,45 @@ static const TypeInfo pxa25x_timer_dev_info = { static Property pxa27x_timer_dev_properties[] = { DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, - PXA2XX_TIMER_HAVE_TM4, true), + PXA2XX_TIMER_HAVE_TM4, true), DEFINE_PROP_END_OF_LIST(), }; static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = pxa2xx_timer_init; dc->desc = "PXA27x timer"; - dc->vmsd = &vmstate_pxa2xx_timer_regs; dc->props = pxa27x_timer_dev_properties; } static const TypeInfo pxa27x_timer_dev_info = { .name = "pxa27x-timer", - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_PXA2XX_TIMER, .instance_size = sizeof(PXA2xxTimerInfo), .class_init = pxa27x_timer_dev_class_init, }; +static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc); + + sdc->init = pxa2xx_timer_init; + dc->vmsd = &vmstate_pxa2xx_timer_regs; +} + +static const TypeInfo pxa2xx_timer_type_info = { + .name = TYPE_PXA2XX_TIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxTimerInfo), + .abstract = true, + .class_init = pxa2xx_timer_class_init, +}; + static void pxa2xx_timer_register_types(void) { + type_register_static(&pxa2xx_timer_type_info); type_register_static(&pxa25x_timer_dev_info); type_register_static(&pxa27x_timer_dev_info); } diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 251a10dbfa..07f0670b5d 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -11,6 +11,7 @@ #include "hw/hw.h" #include "hw/sh4/sh.h" #include "qemu/timer.h" +#include "qemu/main-loop.h" #include "exec/address-spaces.h" #include "hw/ptimer.h" diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index 7f844d7020..f75b914951 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -27,6 +27,7 @@ #include "hw/ptimer.h" #include "hw/sysbus.h" #include "trace.h" +#include "qemu/main-loop.h" /* * Registers of hardware timer in sun4m. @@ -54,8 +55,13 @@ typedef struct CPUTimerState { uint64_t limit; } CPUTimerState; +#define TYPE_SLAVIO_TIMER "slavio_timer" +#define SLAVIO_TIMER(obj) \ + OBJECT_CHECK(SLAVIO_TIMERState, (obj), TYPE_SLAVIO_TIMER) + typedef struct SLAVIO_TIMERState { - SysBusDevice busdev; + SysBusDevice parent_obj; + uint32_t num_cpus; uint32_t cputimer_mode; CPUTimerState cputimer[MAX_CPUS + 1]; @@ -354,7 +360,7 @@ static const VMStateDescription vmstate_slavio_timer = { static void slavio_timer_reset(DeviceState *d) { - SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev); + SLAVIO_TIMERState *s = SLAVIO_TIMER(d); unsigned int i; CPUTimerState *curr_timer; @@ -375,7 +381,7 @@ static void slavio_timer_reset(DeviceState *d) static int slavio_timer_init1(SysBusDevice *dev) { - SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev); + SLAVIO_TIMERState *s = SLAVIO_TIMER(dev); QEMUBH *bh; unsigned int i; TimerContext *tc; @@ -421,7 +427,7 @@ static void slavio_timer_class_init(ObjectClass *klass, void *data) } static const TypeInfo slavio_timer_info = { - .name = "slavio_timer", + .name = TYPE_SLAVIO_TIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_TIMERState), .class_init = slavio_timer_class_init, diff --git a/hw/timer/tusb6010.c b/hw/timer/tusb6010.c index 47b6809225..bd2a89e020 100644 --- a/hw/timer/tusb6010.c +++ b/hw/timer/tusb6010.c @@ -26,8 +26,12 @@ #include "hw/devices.h" #include "hw/sysbus.h" +#define TYPE_TUSB6010 "tusb6010" +#define TUSB(obj) OBJECT_CHECK(TUSBState, (obj), TYPE_TUSB6010) + typedef struct TUSBState { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem[2]; qemu_irq irq; MUSBState *musb; @@ -512,11 +516,11 @@ static void tusb_async_writew(void *opaque, hwaddr addr, case TUSB_DEV_OTG_TIMER: s->otg_timer_val = value; if (value & TUSB_DEV_OTG_TIMER_ENABLE) - qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(TUSB_DEV_OTG_TIMER_VAL(value), get_ticks_per_sec(), TUSB_DEVCLOCK)); else - qemu_del_timer(s->otg_timer); + timer_del(s->otg_timer); break; case TUSB_PRCM_CONF: @@ -724,8 +728,8 @@ static void tusb6010_power(TUSBState *s, int on) /* Pull the interrupt down after TUSB6010 comes up. */ s->intr_ok = 0; tusb_intr_update(s); - qemu_mod_timer(s->pwr_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2); + timer_mod(s->pwr_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() / 2); } } @@ -740,7 +744,7 @@ static void tusb6010_irq(void *opaque, int source, int level) static void tusb6010_reset(DeviceState *dev) { - TUSBState *s = FROM_SYSBUS(TUSBState, SYS_BUS_DEVICE(dev)); + TUSBState *s = TUSB(dev); int i; s->test_reset = TUSB_PROD_TEST_RESET_VAL; @@ -774,18 +778,20 @@ static void tusb6010_reset(DeviceState *dev) musb_reset(s->musb); } -static int tusb6010_init(SysBusDevice *dev) +static int tusb6010_init(SysBusDevice *sbd) { - TUSBState *s = FROM_SYSBUS(TUSBState, dev); - s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s); - s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s); + DeviceState *dev = DEVICE(sbd); + TUSBState *s = TUSB(dev); + + s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s); + s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s); memory_region_init_io(&s->iomem[1], OBJECT(s), &tusb_async_ops, s, "tusb-async", UINT32_MAX); - sysbus_init_mmio(dev, &s->iomem[0]); - sysbus_init_mmio(dev, &s->iomem[1]); - sysbus_init_irq(dev, &s->irq); - qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1); - s->musb = musb_init(&dev->qdev, 1); + sysbus_init_mmio(sbd, &s->iomem[0]); + sysbus_init_mmio(sbd, &s->iomem[1]); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1); + s->musb = musb_init(dev, 1); return 0; } @@ -799,7 +805,7 @@ static void tusb6010_class_init(ObjectClass *klass, void *data) } static const TypeInfo tusb6010_info = { - .name = "tusb6010", + .name = TYPE_TUSB6010, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TUSBState), .class_init = tusb6010_class_init, diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c index b730d853f7..f3ea36503c 100644 --- a/hw/timer/twl92230.c +++ b/hw/timer/twl92230.c @@ -72,14 +72,14 @@ static inline void menelaus_update(MenelausState *s) static inline void menelaus_rtc_start(MenelausState *s) { - s->rtc.next += qemu_get_clock_ms(rtc_clock); - qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); + s->rtc.next += qemu_clock_get_ms(rtc_clock); + timer_mod(s->rtc.hz_tm, s->rtc.next); } static inline void menelaus_rtc_stop(MenelausState *s) { - qemu_del_timer(s->rtc.hz_tm); - s->rtc.next -= qemu_get_clock_ms(rtc_clock); + timer_del(s->rtc.hz_tm); + s->rtc.next -= qemu_clock_get_ms(rtc_clock); if (s->rtc.next < 1) s->rtc.next = 1; } @@ -102,7 +102,7 @@ static void menelaus_rtc_hz(void *opaque) s->rtc.next_comp --; s->rtc.alm_sec --; s->rtc.next += 1000; - qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); + timer_mod(s->rtc.hz_tm, s->rtc.next); if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */ menelaus_rtc_update(s); if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec) @@ -782,7 +782,7 @@ static void menelaus_pre_save(void *opaque) { MenelausState *s = opaque; /* Should be <= 1000 */ - s->rtc_next_vmstate = s->rtc.next - qemu_get_clock_ms(rtc_clock); + s->rtc_next_vmstate = s->rtc.next - qemu_clock_get_ms(rtc_clock); } static int menelaus_post_load(void *opaque, int version_id) @@ -843,7 +843,7 @@ static int twl92230_init(I2CSlave *i2c) { MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c); - s->rtc.hz_tm = qemu_new_timer_ms(rtc_clock, menelaus_rtc_hz, s); + s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s); /* Three output pins plus one interrupt pin. */ qdev_init_gpio_out(&i2c->qdev, s->out, 4); diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index ee5383498e..6113b975bf 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #include "hw/ptimer.h" #include "qemu/log.h" +#include "qemu/main-loop.h" #define D(x) @@ -57,9 +58,14 @@ struct xlx_timer uint32_t regs[R_MAX]; }; +#define TYPE_XILINX_TIMER "xlnx.xps-timer" +#define XILINX_TIMER(obj) \ + OBJECT_CHECK(struct timerblock, (obj), TYPE_XILINX_TIMER) + struct timerblock { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion mmio; qemu_irq irq; uint8_t one_timer_only; @@ -200,7 +206,7 @@ static void timer_hit(void *opaque) static int xilinx_timer_init(SysBusDevice *dev) { - struct timerblock *t = FROM_SYSBUS(typeof (*t), dev); + struct timerblock *t = XILINX_TIMER(dev); unsigned int i; /* All timers share a single irq line. */ @@ -241,7 +247,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) } static const TypeInfo xilinx_timer_info = { - .name = "xlnx.xps-timer", + .name = TYPE_XILINX_TIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct timerblock), .class_init = xilinx_timer_class_init, diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index abe384ba9a..6f0a4d2814 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -28,6 +28,7 @@ #include "hw/pci/pci_ids.h" #include "tpm_tis.h" #include "qemu-common.h" +#include "qemu/main-loop.h" /*#define DEBUG_TIS */ diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index deb6d4703b..aa913df853 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -592,6 +592,7 @@ static void emulated_class_initfn(ObjectClass *klass, void *data) cc->exitfn = emulated_exitfn; cc->get_atr = emulated_get_atr; cc->apdu_from_guest = emulated_apdu_from_guest; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "emulated smartcard"; dc->props = emulated_card_properties; } diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index 5f01ff1e16..10f1d309a6 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -392,6 +392,7 @@ static void passthru_class_initfn(ObjectClass *klass, void *data) cc->exitfn = passthru_exitfn; cc->get_atr = passthru_get_atr; cc->apdu_from_guest = passthru_apdu_from_guest; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "passthrough smartcard"; dc->vmsd = &passthru_vmstate; dc->props = passthru_card_properties; diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 04933a985a..c5420eb057 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -673,6 +673,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_audio; dc->props = usb_audio_properties; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); k->product_desc = "QEMU USB Audio Interface"; k->usb_desc = &desc_audio; k->init = usb_audio_initfn; diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index 68cc1d4fab..f2fc2a8034 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -553,6 +553,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_bt_handle_data; uc->handle_destroy = usb_bt_handle_destroy; dc->vmsd = &vmstate_usb_bt; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo bt_info = { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 31f3cdef42..66c63317d6 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -658,6 +658,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Tablet"; dc->vmsd = &vmstate_usb_ptr; dc->props = usb_tablet_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo usb_tablet_info = { @@ -677,6 +678,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Mouse"; uc->usb_desc = &desc_mouse; dc->vmsd = &vmstate_usb_ptr; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo usb_mouse_info = { @@ -696,6 +698,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Keyboard"; uc->usb_desc = &desc_keyboard; dc->vmsd = &vmstate_usb_kbd; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo usb_keyboard_info = { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 0b71abd028..e865a98751 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -574,6 +574,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_hub_handle_control; uc->handle_data = usb_hub_handle_data; uc->handle_destroy = usb_hub_handle_destroy; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "hub"; dc->vmsd = &vmstate_usb_hub; } diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 5473ac2cd5..660d7743fe 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1429,6 +1429,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_net_handle_control; uc->handle_data = usb_net_handle_data; uc->handle_destroy = usb_net_handle_destroy; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "network"; dc->vmsd = &vmstate_usb_net; dc->props = net_properties; diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 2fc8a3b136..0b150d43fb 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -590,6 +590,7 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_serial_handle_data; dc->vmsd = &vmstate_usb_serial; dc->props = serial_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_info = { @@ -617,6 +618,7 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_serial_handle_data; dc->vmsd = &vmstate_usb_serial; dc->props = braille_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo braille_info = { diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index b33eb25b39..2233c548fa 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1449,6 +1449,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) dc->desc = "CCID Rev 1.1 smartcard reader"; dc->vmsd = &ccid_vmstate; dc->props = ccid_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo ccid_info = { diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 1954811ec4..a8dc2fa960 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -746,6 +746,7 @@ static void usb_msd_class_initfn_common(ObjectClass *klass) uc->handle_reset = usb_msd_handle_reset; uc->handle_control = usb_msd_handle_control; uc->handle_data = usb_msd_handle_data; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_msd; } diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 6efab62544..63ad12ea6b 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -916,6 +916,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_uas_handle_control; uc->handle_data = usb_uas_handle_data; uc->handle_destroy = usb_uas_handle_destroy; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_uas; } diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 3be5cdefda..1b092358f9 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -362,6 +362,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) uc->handle_control = usb_wacom_handle_control; uc->handle_data = usb_wacom_handle_data; uc->handle_destroy = usb_wacom_handle_destroy; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "QEMU PenPartner Tablet"; dc->vmsd = &vmstate_usb_wacom; } diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 5d229bc792..4d21a0b7bb 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -140,11 +140,13 @@ static const TypeInfo ehci_pci_type_info = { static void ehci_data_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); EHCIPCIInfo *i = data; k->vendor_id = i->vendor_id; k->device_id = i->device_id; k->revision = i->revision; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static struct EHCIPCIInfo ehci_pci_info[] = { diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 54147b5fee..fe6eea5908 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -70,6 +70,7 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data) dc->realize = usb_ehci_sysbus_realize; dc->vmsd = &vmstate_ehci_sysbus; dc->props = ehci_sysbus_properties; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_type_info = { @@ -85,7 +86,9 @@ static const TypeInfo ehci_type_info = { static void ehci_xlnx_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + set_bit(DEVICE_CATEGORY_USB, dc->categories); sec->capsbase = 0x100; sec->opregbase = 0x140; } @@ -99,9 +102,11 @@ static const TypeInfo ehci_xlnx_type_info = { static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x0; sec->opregbase = 0x10; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_exynos4210_type_info = { @@ -113,9 +118,11 @@ static const TypeInfo ehci_exynos4210_type_info = { static void ehci_tegra2_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x100; sec->opregbase = 0x140; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_tegra2_type_info = { @@ -183,11 +190,13 @@ static void fusbh200_ehci_init(Object *obj) static void fusbh200_ehci_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x0; sec->opregbase = 0x10; sec->portscbase = 0x20; sec->portnr = 1; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_fusbh200_type_info = { diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 67e4b24273..e5523d54e0 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -150,7 +150,7 @@ typedef enum { #define NLPTR_TYPE_FSTN 3 // frame span traversal node #define SET_LAST_RUN_CLOCK(s) \ - (s)->last_run_ns = qemu_get_clock_ns(vm_clock); + (s)->last_run_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* nifty macros from Arnon's EHCI version */ #define get_field(data, field) \ @@ -958,7 +958,7 @@ static void ehci_reset(void *opaque) } ehci_queues_rip_all(s, 0); ehci_queues_rip_all(s, 1); - qemu_del_timer(s->frame_timer); + timer_del(s->frame_timer); qemu_bh_cancel(s->async_bh); } @@ -1357,7 +1357,7 @@ static void ehci_execute_complete(EHCIQueue *q) default: /* should not be triggerable */ fprintf(stderr, "USB invalid response %d\n", p->packet.status); - assert(0); + g_assert_not_reached(); break; } @@ -2142,7 +2142,7 @@ static void ehci_advance_state(EHCIState *ehci, int async) default: fprintf(stderr, "Bad state!\n"); again = -1; - assert(0); + g_assert_not_reached(); break; } @@ -2206,7 +2206,7 @@ static void ehci_advance_async_state(EHCIState *ehci) /* this should only be due to a developer mistake */ fprintf(stderr, "ehci: Bad asynchronous state %d. " "Resetting to active\n", ehci->astate); - assert(0); + g_assert_not_reached(); } } @@ -2256,7 +2256,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) /* this should only be due to a developer mistake */ fprintf(stderr, "ehci: Bad periodic state %d. " "Resetting to active\n", ehci->pstate); - assert(0); + g_assert_not_reached(); } } @@ -2296,7 +2296,7 @@ static void ehci_frame_timer(void *opaque) int uframes, skipped_uframes; int i; - t_now = qemu_get_clock_ns(vm_clock); + t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ns_elapsed = t_now - ehci->last_run_ns; uframes = ns_elapsed / UFRAME_TIMER_NS; @@ -2374,7 +2374,7 @@ static void ehci_frame_timer(void *opaque) expire_time = t_now + (get_ticks_per_sec() * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ); } - qemu_mod_timer(ehci->frame_timer, expire_time); + timer_mod(ehci->frame_timer, expire_time); } } @@ -2527,7 +2527,7 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp) s->ports[i].dev = 0; } - s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); + s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ehci_frame_timer, s); s->async_bh = qemu_bh_new(ehci_frame_timer, s); qemu_register_reset(ehci_reset, s); diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index 7968e17c34..f91aa5580b 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -558,9 +558,9 @@ static void musb_schedule_cb(USBPort *port, USBPacket *packey) return musb_cb_tick(ep); if (!ep->intv_timer[dir]) - ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep); + ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep); - qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) + + timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(timeout, get_ticks_per_sec(), 8000)); } @@ -962,7 +962,7 @@ static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value) static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir) { if (ep->intv_timer[dir]) - qemu_del_timer(ep->intv_timer[dir]); + timer_del(ep->intv_timer[dir]); } /* Bus control */ diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 2bab8ffb75..39a25a72e1 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -22,7 +22,6 @@ * o Allocate bandwidth in frames properly * o Disable timers when nothing needs to be done, or remove timer usage * all together. - * o Handle unrecoverable errors properly * o BIOS work to boot from USB storage */ @@ -308,6 +307,8 @@ struct ohci_iso_td { #define OHCI_HRESET_FSBIR (1 << 0) +static void ohci_die(OHCIState *ohci); + /* Update IRQ levels */ static inline void ohci_intr_update(OHCIState *ohci) { @@ -508,11 +509,13 @@ static inline int get_dwords(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - dma_memory_read(ohci->as, addr, buf, sizeof(*buf)); + if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { + return -1; + } *buf = le32_to_cpu(*buf); } - return 1; + return 0; } /* Put an array of dwords in to main memory */ @@ -525,10 +528,12 @@ static inline int put_dwords(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint32_t tmp = cpu_to_le32(*buf); - dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp)); + if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { + return -1; + } } - return 1; + return 0; } /* Get an array of words from main memory */ @@ -540,11 +545,13 @@ static inline int get_words(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - dma_memory_read(ohci->as, addr, buf, sizeof(*buf)); + if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { + return -1; + } *buf = le16_to_cpu(*buf); } - return 1; + return 0; } /* Put an array of words in to main memory */ @@ -557,10 +564,12 @@ static inline int put_words(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint16_t tmp = cpu_to_le16(*buf); - dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp)); + if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { + return -1; + } } - return 1; + return 0; } static inline int ohci_read_ed(OHCIState *ohci, @@ -578,15 +587,15 @@ static inline int ohci_read_td(OHCIState *ohci, static inline int ohci_read_iso_td(OHCIState *ohci, dma_addr_t addr, struct ohci_iso_td *td) { - return (get_dwords(ohci, addr, (uint32_t *)td, 4) && - get_words(ohci, addr + 16, td->offset, 8)); + return get_dwords(ohci, addr, (uint32_t *)td, 4) || + get_words(ohci, addr + 16, td->offset, 8); } static inline int ohci_read_hcca(OHCIState *ohci, dma_addr_t addr, struct ohci_hcca *hcca) { - dma_memory_read(ohci->as, addr + ohci->localmem_base, hcca, sizeof(*hcca)); - return 1; + return dma_memory_read(ohci->as, addr + ohci->localmem_base, + hcca, sizeof(*hcca)); } static inline int ohci_put_ed(OHCIState *ohci, @@ -610,23 +619,22 @@ static inline int ohci_put_td(OHCIState *ohci, static inline int ohci_put_iso_td(OHCIState *ohci, dma_addr_t addr, struct ohci_iso_td *td) { - return (put_dwords(ohci, addr, (uint32_t *)td, 4) && - put_words(ohci, addr + 16, td->offset, 8)); + return put_dwords(ohci, addr, (uint32_t *)td, 4 || + put_words(ohci, addr + 16, td->offset, 8)); } static inline int ohci_put_hcca(OHCIState *ohci, dma_addr_t addr, struct ohci_hcca *hcca) { - dma_memory_write(ohci->as, - addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, - (char *)hcca + HCCA_WRITEBACK_OFFSET, - HCCA_WRITEBACK_SIZE); - return 1; + return dma_memory_write(ohci->as, + addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, + (char *)hcca + HCCA_WRITEBACK_OFFSET, + HCCA_WRITEBACK_SIZE); } /* Read/Write the contents of a TD from/to main memory. */ -static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td, - uint8_t *buf, int len, DMADirection dir) +static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, + uint8_t *buf, int len, DMADirection dir) { dma_addr_t ptr, n; @@ -634,18 +642,26 @@ static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td, n = 0x1000 - (ptr & 0xfff); if (n > len) n = len; - dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir); - if (n == len) - return; + + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { + return -1; + } + if (n == len) { + return 0; + } ptr = td->be & ~0xfffu; buf += n; - dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, len - n, dir); + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, + len - n, dir)) { + return -1; + } + return 0; } /* Read/Write the contents of an ISO TD from/to main memory. */ -static void ohci_copy_iso_td(OHCIState *ohci, - uint32_t start_addr, uint32_t end_addr, - uint8_t *buf, int len, DMADirection dir) +static int ohci_copy_iso_td(OHCIState *ohci, + uint32_t start_addr, uint32_t end_addr, + uint8_t *buf, int len, DMADirection dir) { dma_addr_t ptr, n; @@ -653,12 +669,20 @@ static void ohci_copy_iso_td(OHCIState *ohci, n = 0x1000 - (ptr & 0xfff); if (n > len) n = len; - dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir); - if (n == len) - return; + + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { + return -1; + } + if (n == len) { + return 0; + } ptr = end_addr & ~0xfffu; buf += n; - dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, len - n, dir); + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, + len - n, dir)) { + return -1; + } + return 0; } static void ohci_process_lists(OHCIState *ohci, int completion); @@ -698,8 +722,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, addr = ed->head & OHCI_DPTR_MASK; - if (!ohci_read_iso_td(ohci, addr, &iso_td)) { + if (ohci_read_iso_td(ohci, addr, &iso_td)) { printf("usb-ohci: ISO_TD read error at %x\n", addr); + ohci_die(ohci); return 0; } @@ -740,7 +765,10 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, i = OHCI_BM(iso_td.flags, TD_DI); if (i < ohci->done_count) ohci->done_count = i; - ohci_put_iso_td(ohci, addr, &iso_td); + if (ohci_put_iso_td(ohci, addr, &iso_td)) { + ohci_die(ohci); + return 1; + } return 0; } @@ -821,8 +849,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, } if (len && dir != OHCI_TD_DIR_IN) { - ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, - DMA_DIRECTION_TO_DEVICE); + if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, + DMA_DIRECTION_TO_DEVICE)) { + ohci_die(ohci); + return 1; + } } if (!completion) { @@ -852,8 +883,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, /* Writeback */ if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { /* IN transfer succeeded */ - ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, - DMA_DIRECTION_FROM_DEVICE); + if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, + DMA_DIRECTION_FROM_DEVICE)) { + ohci_die(ohci); + return 1; + } OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_NOERROR); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); @@ -910,7 +944,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, if (i < ohci->done_count) ohci->done_count = i; } - ohci_put_iso_td(ohci, addr, &iso_td); + if (ohci_put_iso_td(ohci, addr, &iso_td)) { + ohci_die(ohci); + } return 1; } @@ -943,8 +979,9 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) #endif return 1; } - if (!ohci_read_td(ohci, addr, &td)) { + if (ohci_read_td(ohci, addr, &td)) { fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); + ohci_die(ohci); return 0; } @@ -997,8 +1034,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) pktlen = len; } if (!completion) { - ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, - DMA_DIRECTION_TO_DEVICE); + if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, + DMA_DIRECTION_TO_DEVICE)) { + ohci_die(ohci); + } } } } @@ -1055,8 +1094,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) if (ret >= 0) { if (dir == OHCI_TD_DIR_IN) { - ohci_copy_td(ohci, &td, ohci->usb_buf, ret, - DMA_DIRECTION_FROM_DEVICE); + if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret, + DMA_DIRECTION_FROM_DEVICE)) { + ohci_die(ohci); + } #ifdef DEBUG_PACKET DPRINTF(" data:"); for (i = 0; i < ret; i++) @@ -1133,7 +1174,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) if (i < ohci->done_count) ohci->done_count = i; exit_no_retire: - ohci_put_td(ohci, addr, &td); + if (ohci_put_td(ohci, addr, &td)) { + ohci_die(ohci); + return 1; + } return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; } @@ -1151,8 +1195,9 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) return 0; for (cur = head; cur; cur = next_ed) { - if (!ohci_read_ed(ohci, cur, &ed)) { + if (ohci_read_ed(ohci, cur, &ed)) { fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); + ohci_die(ohci); return 0; } @@ -1194,7 +1239,10 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) } } - ohci_put_ed(ohci, cur, &ed); + if (ohci_put_ed(ohci, cur, &ed)) { + ohci_die(ohci); + return 0; + } } return active; @@ -1203,8 +1251,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) /* Generate a SOF event, and set a timer for EOF */ static void ohci_sof(OHCIState *ohci) { - ohci->sof_time = qemu_get_clock_ns(vm_clock); - qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time); + ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time); ohci_set_interrupt(ohci, OHCI_INTR_SF); } @@ -1236,7 +1284,11 @@ static void ohci_frame_boundary(void *opaque) OHCIState *ohci = opaque; struct ohci_hcca hcca; - ohci_read_hcca(ohci, ohci->hcca, &hcca); + if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { + fprintf(stderr, "usb-ohci: HCCA read error at %x\n", ohci->hcca); + ohci_die(ohci); + return; + } /* Process all the lists at the end of the frame */ if (ohci->ctl & OHCI_CTL_PLE) { @@ -1257,6 +1309,11 @@ static void ohci_frame_boundary(void *opaque) ohci->old_ctl = ohci->ctl; ohci_process_lists(ohci, 0); + /* Stop if UnrecoverableError happened or ohci_sof will crash */ + if (ohci->intr_status & OHCI_INTR_UE) { + return; + } + /* Frame boundary, so do EOF stuf here */ ohci->frt = ohci->fit; @@ -1282,7 +1339,9 @@ static void ohci_frame_boundary(void *opaque) ohci_sof(ohci); /* Writeback HCCA */ - ohci_put_hcca(ohci, ohci->hcca, &hcca); + if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) { + ohci_die(ohci); + } } /* Start sending SOF tokens across the USB bus, lists are processed in @@ -1290,13 +1349,13 @@ static void ohci_frame_boundary(void *opaque) */ static int ohci_bus_start(OHCIState *ohci) { - ohci->eof_timer = qemu_new_timer_ns(vm_clock, + ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ohci_frame_boundary, ohci); if (ohci->eof_timer == NULL) { - fprintf(stderr, "usb-ohci: %s: qemu_new_timer_ns failed\n", ohci->name); - /* TODO: Signal unrecoverable error */ + fprintf(stderr, "usb-ohci: %s: timer_new_ns failed\n", ohci->name); + ohci_die(ohci); return 0; } @@ -1311,7 +1370,7 @@ static int ohci_bus_start(OHCIState *ohci) static void ohci_bus_stop(OHCIState *ohci) { if (ohci->eof_timer) - qemu_del_timer(ohci->eof_timer); + timer_del(ohci->eof_timer); ohci->eof_timer = NULL; } @@ -1415,7 +1474,7 @@ static uint32_t ohci_get_frame_remaining(OHCIState *ohci) /* Being in USB operational state guarnatees sof_time was * set already. */ - tks = qemu_get_clock_ns(vm_clock) - ohci->sof_time; + tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time; /* avoid muldiv if possible */ if (tks >= usb_frame_time) @@ -1857,6 +1916,22 @@ typedef struct { uint32_t firstport; } OHCIPCIState; +/** A typical O/EHCI will stop operating, set itself into error state + * (which can be queried by MMIO) and will set PERR in its config + * space to signal that it got an error + */ +static void ohci_die(OHCIState *ohci) +{ + OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); + + fprintf(stderr, "%s: DMA error\n", __func__); + + ohci_set_interrupt(ohci, OHCI_INTR_UE); + ohci_bus_stop(ohci); + pci_set_word(dev->parent_obj.config + PCI_STATUS, + PCI_STATUS_DETECTED_PARITY); +} + static int usb_ohci_initfn_pci(PCIDevice *dev) { OHCIPCIState *ohci = PCI_OHCI(dev); @@ -1917,6 +1992,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; k->class_id = PCI_CLASS_SERIAL_USB; k->no_hotplug = 1; + set_bit(DEVICE_CATEGORY_USB, dc->categories); dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; } @@ -1939,6 +2015,7 @@ static void ohci_sysbus_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = ohci_realize_pxa; + set_bit(DEVICE_CATEGORY_USB, dc->categories); dc->desc = "OHCI USB Controller"; dc->props = ohci_sysbus_properties; } diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 066072eb3f..578b949c92 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -32,6 +32,7 @@ #include "qemu/iov.h" #include "sysemu/dma.h" #include "trace.h" +#include "qemu/main-loop.h" //#define DEBUG //#define DEBUG_DUMP_DATA @@ -189,6 +190,7 @@ typedef struct UHCI_QH { static void uhci_async_cancel(UHCIAsync *async); static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); +static void uhci_resume(void *opaque); static inline int32_t uhci_queue_token(UHCI_TD *td) { @@ -431,7 +433,7 @@ static int uhci_post_load(void *opaque, int version_id) UHCIState *s = opaque; if (version_id < 2) { - s->expire_time = qemu_get_clock_ns(vm_clock) + + s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / FRAME_TIMER_FREQ); } return 0; @@ -474,9 +476,9 @@ static void uhci_port_write(void *opaque, hwaddr addr, if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { /* start frame processing */ trace_usb_uhci_schedule_start(); - s->expire_time = qemu_get_clock_ns(vm_clock) + + s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, s->expire_time); + timer_mod(s->frame_timer, s->expire_time); s->status &= ~UHCI_STS_HCHALTED; } else if (!(val & UHCI_CMD_RS)) { s->status |= UHCI_STS_HCHALTED; @@ -498,6 +500,12 @@ static void uhci_port_write(void *opaque, hwaddr addr, return; } s->cmd = val; + if (val & UHCI_CMD_EGSM) { + if ((s->ports[0].ctrl & UHCI_PORT_RD) || + (s->ports[1].ctrl & UHCI_PORT_RD)) { + uhci_resume(s); + } + } break; case 0x02: s->status &= ~val; @@ -1153,7 +1161,7 @@ static void uhci_frame_timer(void *opaque) if (!(s->cmd & UHCI_CMD_RS)) { /* Full stop */ trace_usb_uhci_schedule_stop(); - qemu_del_timer(s->frame_timer); + timer_del(s->frame_timer); uhci_async_cancel_all(s); /* set hchalted bit in status - UHCI11D 2.1.2 */ s->status |= UHCI_STS_HCHALTED; @@ -1162,7 +1170,7 @@ static void uhci_frame_timer(void *opaque) /* We still store expire_time in our state, for migration */ t_last_run = s->expire_time - frame_t; - t_now = qemu_get_clock_ns(vm_clock); + t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Process up to MAX_FRAMES_PER_TICK frames */ frames = (t_now - t_last_run) / frame_t; @@ -1196,7 +1204,7 @@ static void uhci_frame_timer(void *opaque) } s->pending_int_mask = 0; - qemu_mod_timer(s->frame_timer, t_now + frame_t); + timer_mod(s->frame_timer, t_now + frame_t); } static const MemoryRegionOps uhci_ioport_ops = { @@ -1253,7 +1261,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) } } s->bh = qemu_bh_new(uhci_bh, s); - s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); + s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; QTAILQ_INIT(&s->queues); @@ -1315,6 +1323,7 @@ static void uhci_class_init(ObjectClass *klass, void *data) k->no_hotplug = 1; dc->vmsd = &vmstate_uhci; dc->props = uhci_properties; + set_bit(DEVICE_CATEGORY_USB, dc->categories); u->info = *info; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 9ba3e3e86d..be6b86e2ba 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -608,7 +608,7 @@ static const char *event_name(XHCIEvent *event) static uint64_t xhci_mfindex_get(XHCIState *xhci) { - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); return (now - xhci->mfindex_start) / 125000; } @@ -619,12 +619,12 @@ static void xhci_mfwrap_update(XHCIState *xhci) int64_t now; if ((xhci->usbcmd & bits) == bits) { - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff; left = 0x4000 - mfindex; - qemu_mod_timer(xhci->mfwrap_timer, now + left * 125000); + timer_mod(xhci->mfwrap_timer, now + left * 125000); } else { - qemu_del_timer(xhci->mfwrap_timer); + timer_del(xhci->mfwrap_timer); } } @@ -1086,7 +1086,7 @@ static void xhci_run(XHCIState *xhci) { trace_usb_xhci_run(); xhci->usbsts &= ~USBSTS_HCH; - xhci->mfindex_start = qemu_get_clock_ns(vm_clock); + xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } static void xhci_stop(XHCIState *xhci) @@ -1229,7 +1229,7 @@ static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci, for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { usb_packet_init(&epctx->transfers[i].packet); } - epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); + epctx->kick_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_ep_kick_timer, epctx); return epctx; } @@ -1304,7 +1304,7 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t) XHCIEPContext *epctx = t->xhci->slots[t->slotid-1].eps[t->epid-1]; if (epctx) { epctx->retry = NULL; - qemu_del_timer(epctx->kick_timer); + timer_del(epctx->kick_timer); } t->running_retry = 0; } @@ -1380,7 +1380,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED); - qemu_free_timer(epctx->kick_timer); + timer_free(epctx->kick_timer); g_free(epctx); slot->eps[epid-1] = NULL; @@ -1429,7 +1429,6 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, { XHCISlot *slot; XHCIEPContext *epctx; - USBDevice *dev; trace_usb_xhci_ep_reset(slotid, epid); assert(slotid >= 1 && slotid <= xhci->numslots); @@ -1465,8 +1464,8 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, ep |= 0x80; } - dev = xhci->slots[slotid-1].uport->dev; - if (!dev) { + if (!xhci->slots[slotid-1].uport || + !xhci->slots[slotid-1].uport->dev) { return CC_USB_TRANSACTION_ERROR; } @@ -1741,6 +1740,7 @@ static int xhci_complete_packet(XHCITransfer *xfer) trace_usb_xhci_xfer_error(xfer, xfer->packet.status); switch (xfer->packet.status) { case USB_RET_NODEV: + case USB_RET_IOERROR: xfer->status = CC_USB_TRANSACTION_ERROR; xhci_xfer_report(xfer); xhci_stall_ep(xfer); @@ -1844,12 +1844,12 @@ static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx, uint64_t mfindex) { if (xfer->mfindex_kick > mfindex) { - qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(epctx->kick_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (xfer->mfindex_kick - mfindex) * 125000); xfer->running_retry = 1; } else { epctx->mfindex_last = xfer->mfindex_kick; - qemu_del_timer(epctx->kick_timer); + timer_del(epctx->kick_timer); xfer->running_retry = 0; } } @@ -2672,7 +2672,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach) xhci_port_notify(port, PORTSC_CSC); } -static void xhci_port_reset(XHCIPort *port) +static void xhci_port_reset(XHCIPort *port, bool warm_reset) { trace_usb_xhci_port_reset(port->portnr); @@ -2683,6 +2683,11 @@ static void xhci_port_reset(XHCIPort *port) usb_device_reset(port->uport->dev); switch (port->uport->dev->speed) { + case USB_SPEED_SUPER: + if (warm_reset) { + port->portsc |= PORTSC_WRC; + } + /* fall through */ case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: @@ -2740,7 +2745,7 @@ static void xhci_reset(DeviceState *dev) xhci->intr[i].ev_buffer_get = 0; } - xhci->mfindex_start = qemu_get_clock_ns(vm_clock); + xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); xhci_mfwrap_update(xhci); } @@ -2845,8 +2850,12 @@ static void xhci_port_write(void *ptr, hwaddr reg, switch (reg) { case 0x00: /* PORTSC */ /* write-1-to-start bits */ + if (val & PORTSC_WPR) { + xhci_port_reset(port, true); + break; + } if (val & PORTSC_PR) { - xhci_port_reset(port); + xhci_port_reset(port, false); break; } @@ -3357,7 +3366,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev) xhci->numslots = 1; } - xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci); + xhci->mfwrap_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_mfwrap_timer, xhci); xhci->irq = dev->irq[0]; @@ -3442,7 +3451,7 @@ static int usb_xhci_post_load(void *opaque, int version_id) epctx->state = state; if (state == EP_RUNNING) { /* kick endpoint after vmload is finished */ - qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock)); + timer_mod(epctx->kick_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } } } @@ -3591,6 +3600,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xhci; dc->props = xhci_properties; dc->reset = xhci_reset; + set_bit(DEVICE_CATEGORY_USB, dc->categories); k->init = usb_xhci_initfn; k->vendor_id = PCI_VENDOR_ID_NEC; k->device_id = PCI_DEVICE_ID_NEC_UPD720200; diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index e2f3cc8ade..128955dd92 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1351,6 +1351,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->flush_ep_queue = usb_host_flush_ep_queue; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static TypeInfo usb_host_dev_info = { @@ -1461,7 +1462,7 @@ static void usb_host_auto_check(void *unused) if (unconnected == 0) { /* nothing to watch */ if (usb_auto_timer) { - qemu_del_timer(usb_auto_timer); + timer_del(usb_auto_timer); trace_usb_host_auto_scan_disabled(); } return; @@ -1473,13 +1474,13 @@ static void usb_host_auto_check(void *unused) usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); } if (!usb_auto_timer) { - usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL); + usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL); if (!usb_auto_timer) { return; } trace_usb_host_auto_scan_enabled(); } - qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000); + timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000); } void usb_host_info(Monitor *mon, const QDict *qdict) diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index ca09a891ee..65cd3b444c 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1530,6 +1530,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->handle_destroy = usb_host_handle_destroy; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo usb_host_dev_info = { @@ -1753,7 +1754,7 @@ static void usb_host_auto_check(void *unused) if (unconnected == 0) { /* nothing to watch */ if (usb_auto_timer) { - qemu_del_timer(usb_auto_timer); + timer_del(usb_auto_timer); trace_usb_host_auto_scan_disabled(); } return; @@ -1764,13 +1765,13 @@ static void usb_host_auto_check(void *unused) usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); } if (!usb_auto_timer) { - usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL); + usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL); if (!usb_auto_timer) { return; } trace_usb_host_auto_scan_enabled(); } - qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000); + timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000); } #ifndef CONFIG_USB_LIBUSB diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index a594e954e4..287a505b48 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1297,7 +1297,7 @@ static int usbredir_initfn(USBDevice *udev) } dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev); packet_id_queue_init(&dev->cancelled, dev, "cancelled"); packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); @@ -1334,11 +1334,12 @@ static void usbredir_handle_destroy(USBDevice *udev) USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); qemu_chr_delete(dev->cs); + dev->cs = NULL; /* Note must be done after qemu_chr_close, as that causes a close event */ qemu_bh_delete(dev->chardev_close_bh); - qemu_del_timer(dev->attach_timer); - qemu_free_timer(dev->attach_timer); + timer_del(dev->attach_timer); + timer_free(dev->attach_timer); usbredir_cleanup_device_queues(dev); @@ -1492,7 +1493,7 @@ static void usbredir_device_connect(void *priv, USBRedirDevice *dev = priv; const char *speed; - if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + if (timer_pending(dev->attach_timer) || dev->dev.attached) { ERROR("Received device connect while already connected\n"); return; } @@ -1547,7 +1548,7 @@ static void usbredir_device_connect(void *priv, } usbredir_check_bulk_receiving(dev); - qemu_mod_timer(dev->attach_timer, dev->next_attach_time); + timer_mod(dev->attach_timer, dev->next_attach_time); } static void usbredir_device_disconnect(void *priv) @@ -1555,7 +1556,7 @@ static void usbredir_device_disconnect(void *priv) USBRedirDevice *dev = priv; /* Stop any pending attaches */ - qemu_del_timer(dev->attach_timer); + timer_del(dev->attach_timer); if (dev->dev.attached) { DPRINTF("detaching device\n"); @@ -1564,7 +1565,7 @@ static void usbredir_device_disconnect(void *priv) * Delay next usb device attach to give the guest a chance to see * see the detach / attach in case of quick close / open succession */ - dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200; + dev->next_attach_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 200; } /* Reset state so that the next dev connected starts with a clean slate */ @@ -1587,7 +1588,7 @@ static void usbredir_interface_info(void *priv, * If we receive interface info after the device has already been * connected (ie on a set_config), re-check interface dependent things. */ - if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + if (timer_pending(dev->attach_timer) || dev->dev.attached) { usbredir_check_bulk_receiving(dev); if (usbredir_check_filter(dev)) { ERROR("Device no longer matches filter after interface info " @@ -2362,6 +2363,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->ep_stopped = usbredir_ep_stopped; dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo usbredir_dev_info = { diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 82cc151b17..351a343806 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -52,6 +52,7 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) void vring_teardown(Vring *vring, VirtIODevice *vdev, int n) { virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx); + virtio_queue_invalidate_signalled_used(vdev, n); hostmem_finalize(&vring->hostmem); } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 8f6ab130ee..9e336ad81e 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -762,6 +762,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, fflush(stderr); } virtio_queue_set_last_avail_idx(vdev, idx, state.num); + virtio_queue_invalidate_signalled_used(vdev, idx); assert (r >= 0); cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx), 0, virtio_queue_get_ring_size(vdev, idx)); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 3fa72a97b9..9504877120 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -53,8 +53,8 @@ static const char *balloon_stat_names[] = { /* * reset_stats - Mark all items in the stats array as unset * - * This function needs to be called at device intialization and before - * before updating to a set of newly-generated stats. This will ensure that no + * This function needs to be called at device initialization and before + * updating to a set of newly-generated stats. This will ensure that no * stale values stick around in case the guest reports a subset of the supported * statistics. */ @@ -78,8 +78,8 @@ static bool balloon_stats_enabled(const VirtIOBalloon *s) static void balloon_stats_destroy_timer(VirtIOBalloon *s) { if (balloon_stats_enabled(s)) { - qemu_del_timer(s->stats_timer); - qemu_free_timer(s->stats_timer); + timer_del(s->stats_timer); + timer_free(s->stats_timer); s->stats_timer = NULL; s->stats_poll_interval = 0; } @@ -87,7 +87,7 @@ static void balloon_stats_destroy_timer(VirtIOBalloon *s) static void balloon_stats_change_timer(VirtIOBalloon *s, int secs) { - qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000); + timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000); } static void balloon_stats_poll_cb(void *opaque) @@ -173,7 +173,7 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, /* create a new timer */ g_assert(s->stats_timer == NULL); - s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s); + s->stats_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, balloon_stats_poll_cb, s); s->stats_poll_interval = value; balloon_stats_change_timer(s, 0); } @@ -392,6 +392,7 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_balloon_device_exit; dc->props = virtio_balloon_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->init = virtio_balloon_device_init; vdc->get_config = virtio_balloon_get_config; vdc->set_config = virtio_balloon_set_config; diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 54d6679516..4bd29533f3 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -151,6 +151,9 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) } return proxy->host_features; case VIRTIO_MMIO_QUEUENUMMAX: + if (!virtio_queue_get_num(vdev, vdev->queue_sel)) { + return 0; + } return VIRTQUEUE_MAX_SIZE; case VIRTIO_MMIO_QUEUEPFN: return virtio_queue_get_addr(vdev, vdev->queue_sel) @@ -370,6 +373,7 @@ static void virtio_mmio_class_init(ObjectClass *klass, void *data) dc->realize = virtio_mmio_realizefn; dc->reset = virtio_mmio_reset; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo virtio_mmio_info = { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index c4db4070ce..f2c489b66c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -911,6 +911,7 @@ static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = 0x2; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = virtio_9p_pci_properties; } @@ -1065,6 +1066,7 @@ static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = virtio_blk_pci_properties; k->init = virtio_blk_pci_init; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; @@ -1135,6 +1137,7 @@ static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_scsi_pci_init_pci; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = virtio_scsi_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; @@ -1191,6 +1194,7 @@ static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = vhost_scsi_pci_init_pci; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = vhost_scsi_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; @@ -1271,6 +1275,7 @@ static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_balloon_pci_init; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->props = virtio_balloon_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; @@ -1356,6 +1361,7 @@ static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_serial_pci_init; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->props = virtio_serial_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; @@ -1417,6 +1423,7 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIRTIO_NET; k->revision = VIRTIO_PCI_ABI_VERSION; k->class_id = PCI_CLASS_NETWORK_ETHERNET; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->props = virtio_net_properties; vpciklass->init = virtio_net_pci_init; } @@ -1468,6 +1475,7 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_rng_pci_init; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->props = virtio_rng_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index cb787c792d..314e393520 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -129,8 +129,8 @@ static void check_rate_limit(void *opaque) vrng->quota_remaining = vrng->conf.max_bytes; virtio_rng_process(vrng); - qemu_mod_timer(vrng->rate_limit_timer, - qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms); + timer_mod(vrng->rate_limit_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vrng->conf.period_ms); } static int virtio_rng_device_init(VirtIODevice *vdev) @@ -172,11 +172,11 @@ static int virtio_rng_device_init(VirtIODevice *vdev) assert(vrng->conf.max_bytes <= INT64_MAX); vrng->quota_remaining = vrng->conf.max_bytes; - vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock, + vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, check_rate_limit, vrng); - qemu_mod_timer(vrng->rate_limit_timer, - qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms); + timer_mod(vrng->rate_limit_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vrng->conf.period_ms); register_savevm(qdev, "virtio-rng", -1, 1, virtio_rng_save, virtio_rng_load, vrng); @@ -189,8 +189,8 @@ static int virtio_rng_device_exit(DeviceState *qdev) VirtIORNG *vrng = VIRTIO_RNG(qdev); VirtIODevice *vdev = VIRTIO_DEVICE(qdev); - qemu_del_timer(vrng->rate_limit_timer); - qemu_free_timer(vrng->rate_limit_timer); + timer_del(vrng->rate_limit_timer); + timer_free(vrng->rate_limit_timer); unregister_savevm(qdev, "virtio-rng", vrng); virtio_cleanup(vdev); return 0; @@ -207,6 +207,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_rng_device_exit; dc->props = virtio_rng_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->init = virtio_rng_device_init; vdc->get_features = get_features; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 09f62c6c70..2f1e73bc75 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -377,8 +377,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, /* loop over the indirect descriptor table */ indirect = 1; max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc); - num_bufs = i = 0; desc_pa = vring_desc_addr(desc_pa, i); + num_bufs = i = 0; } do { @@ -673,10 +673,16 @@ hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n) void virtio_queue_set_num(VirtIODevice *vdev, int n, int num) { - if (num <= VIRTQUEUE_MAX_SIZE) { - vdev->vq[n].vring.num = num; - virtqueue_init(&vdev->vq[n]); + /* Don't allow guest to flip queue between existent and + * nonexistent states, or to set it to an invalid size. + */ + if (!!num != !!vdev->vq[n].vring.num || + num > VIRTQUEUE_MAX_SIZE || + num < 0) { + return; } + vdev->vq[n].vring.num = num; + virtqueue_init(&vdev->vq[n]); } int virtio_queue_get_num(VirtIODevice *vdev, int n) @@ -1059,6 +1065,11 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx) vdev->vq[n].last_avail_idx = idx; } +void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n) +{ + vdev->vq[n].signalled_used_valid = false; +} + VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n) { return vdev->vq + n; diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index cb4e1f9e47..387962ec4a 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -128,7 +128,6 @@ void watchdog_perform_action(void) case WDT_POWEROFF: /* same as 'quit' command in monitor */ watchdog_mon_event("poweroff"); exit(0); - break; case WDT_PAUSE: /* same as 'stop' command in monitor */ watchdog_mon_event("pause"); diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index 85aebc28a3..36d38878ee 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -130,7 +130,7 @@ static void i6300esb_restart_timer(I6300State *d, int stage) i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout); - qemu_mod_timer(d->timer, qemu_get_clock_ns(vm_clock) + timeout); + timer_mod(d->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout); } /* This is called when the guest disables the watchdog. */ @@ -138,7 +138,7 @@ static void i6300esb_disable_timer(I6300State *d) { i6300esb_debug("timer disabled\n"); - qemu_del_timer(d->timer); + timer_del(d->timer); } static void i6300esb_reset(DeviceState *dev) @@ -414,7 +414,7 @@ static int i6300esb_init(PCIDevice *dev) i6300esb_debug("I6300State = %p\n", d); - d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d); + d->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, i6300esb_timer_expired, d); d->previous_reboot_flag = 0; memory_region_init_io(&d->io_mem, OBJECT(d), &i6300esb_ops, d, @@ -451,6 +451,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_SYSTEM_OTHER; dc->reset = i6300esb_reset; dc->vmsd = &vmstate_i6300esb; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo i6300esb_info = { diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index c78855444c..bc994a4c32 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -62,7 +62,7 @@ static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data) ib700_debug("addr = %x, data = %x\n", addr, data); timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec(); - qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout); + timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout); } /* A write (of any value) to this register disables the timer. */ @@ -72,7 +72,7 @@ static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data) ib700_debug("addr = %x, data = %x\n", addr, data); - qemu_del_timer(s->timer); + timer_del(s->timer); } /* This is called when the watchdog expires. */ @@ -83,7 +83,7 @@ static void ib700_timer_expired(void *vp) ib700_debug("watchdog expired\n"); watchdog_perform_action(); - qemu_del_timer(s->timer); + timer_del(s->timer); } static const VMStateDescription vmstate_ib700 = { @@ -110,7 +110,7 @@ static void wdt_ib700_realize(DeviceState *dev, Error **errp) ib700_debug("watchdog init\n"); - s->timer = qemu_new_timer_ns(vm_clock, ib700_timer_expired, s); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ib700_timer_expired, s); portio_list_init(port_list, OBJECT(s), wdt_portio_list, s, "ib700"); portio_list_add(port_list, isa_address_space_io(&s->parent_obj), 0); @@ -122,7 +122,7 @@ static void wdt_ib700_reset(DeviceState *dev) ib700_debug("watchdog reset\n"); - qemu_del_timer(s->timer); + timer_del(s->timer); } static WatchdogTimerModel model = { @@ -137,6 +137,7 @@ static void wdt_ib700_class_init(ObjectClass *klass, void *data) dc->realize = wdt_ib700_realize; dc->reset = wdt_ib700_reset; dc->vmsd = &vmstate_ib700; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo wdt_ib700_info = { diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 20175602b6..ce640c61a5 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,6 +1,6 @@ # xen backend driver support common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o -obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o +obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o diff --git a/hw/xen/xen_platform.c b/hw/xen/xen_platform.c index 6a8ba7e9aa..79bf0b33d3 100644 --- a/hw/xen/xen_platform.c +++ b/hw/xen/xen_platform.c @@ -428,6 +428,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data) k->subsystem_vendor_id = PCI_VENDOR_ID_XEN; k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM; k->revision = 1; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "XEN platform pci device"; dc->reset = platform_reset; dc->vmsd = &vmstate_xen_platform; diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index d7ee7745c8..ca2d460785 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -756,7 +756,8 @@ static int xen_pt_initfn(PCIDevice *d) out: memory_listener_register(&s->memory_listener, &address_space_memory); memory_listener_register(&s->io_listener, &address_space_io); - XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n", + XEN_PT_LOG(d, + "Real physical device %02x:%02x.%d registered successfully!\n", s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function); return 0; @@ -829,6 +830,7 @@ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data) k->exit = xen_pt_unregister_device; k->config_read = xen_pt_pci_read_config; k->config_write = xen_pt_pci_write_config; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "Assign an host PCI device with Xen"; dc->props = xen_pci_passthrough_properties; }; diff --git a/hw/xen/xen_pvdevice.c b/hw/xen/xen_pvdevice.c new file mode 100644 index 0000000000..1132c8934f --- /dev/null +++ b/hw/xen/xen_pvdevice.c @@ -0,0 +1,131 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "trace.h" + +#define TYPE_XEN_PV_DEVICE "xen-pvdevice" + +#define XEN_PV_DEVICE(obj) \ + OBJECT_CHECK(XenPVDevice, (obj), TYPE_XEN_PV_DEVICE) + +typedef struct XenPVDevice { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision; + uint32_t size; + MemoryRegion mmio; +} XenPVDevice; + +static uint64_t xen_pv_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + trace_xen_pv_mmio_read(addr); + + return ~(uint64_t)0; +} + +static void xen_pv_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + trace_xen_pv_mmio_write(addr); +} + +static const MemoryRegionOps xen_pv_mmio_ops = { + .read = &xen_pv_mmio_read, + .write = &xen_pv_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int xen_pv_init(PCIDevice *pci_dev) +{ + XenPVDevice *d = XEN_PV_DEVICE(pci_dev); + uint8_t *pci_conf; + + pci_conf = pci_dev->config; + + pci_set_word(pci_conf + PCI_VENDOR_ID, d->vendor_id); + pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, d->vendor_id); + pci_set_word(pci_conf + PCI_DEVICE_ID, d->device_id); + pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, d->device_id); + pci_set_byte(pci_conf + PCI_REVISION_ID, d->revision); + + pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_MEMORY); + + pci_config_set_prog_interface(pci_conf, 0); + + pci_conf[PCI_INTERRUPT_PIN] = 1; + + memory_region_init_io(&d->mmio, NULL, &xen_pv_mmio_ops, d, + "mmio", d->size); + + pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, + &d->mmio); + + return 0; +} + +static Property xen_pv_props[] = { + DEFINE_PROP_UINT16("vendor-id", XenPVDevice, vendor_id, PCI_VENDOR_ID_XEN), + DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, PCI_DEVICE_ID_XEN_PVDEVICE), + DEFINE_PROP_UINT8("revision", XenPVDevice, revision, 0x01), + DEFINE_PROP_UINT32("size", XenPVDevice, size, 0x400000), + DEFINE_PROP_END_OF_LIST() +}; + +static void xen_pv_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = xen_pv_init; + k->class_id = PCI_CLASS_SYSTEM_OTHER; + dc->desc = "Xen PV Device"; + dc->props = xen_pv_props; +} + +static const TypeInfo xen_pv_type_info = { + .name = TYPE_XEN_PV_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(XenPVDevice), + .class_init = xen_pv_class_init, +}; + +static void xen_pv_register_types(void) +{ + type_register_static(&xen_pv_type_info); +} + +type_init(xen_pv_register_types) diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 7f015ff5ab..e2005bd981 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -52,11 +52,11 @@ void check_interrupts(CPUXtensaState *env) uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; int level; - /* If the CPU is halted advance CCOUNT according to the vm_clock time + /* If the CPU is halted advance CCOUNT according to the QEMU_CLOCK_VIRTUAL time * elapsed since the moment when it was advanced last time. */ if (cs->halted) { - int64_t now = qemu_get_clock_ns(vm_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); xtensa_advance_ccount(env, muldiv64(now - env->halt_clock, @@ -119,7 +119,7 @@ void xtensa_rearm_ccompare_timer(CPUXtensaState *env) } } env->wake_ccount = wake_ccount; - qemu_mod_timer(env->ccompare_timer, env->halt_clock + + timer_mod(env->ccompare_timer, env->halt_clock + muldiv64(wake_ccount - env->sregs[CCOUNT], 1000000, env->config->clock_freq_khz)); } @@ -131,7 +131,7 @@ static void xtensa_ccompare_cb(void *opaque) CPUState *cs = CPU(cpu); if (cs->halted) { - env->halt_clock = qemu_get_clock_ns(vm_clock); + env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); if (!cpu_has_work(cs)) { env->sregs[CCOUNT] = env->wake_ccount + 1; @@ -149,7 +149,7 @@ void xtensa_irq_init(CPUXtensaState *env) if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && env->config->nccompare > 0) { env->ccompare_timer = - qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu); + timer_new_ns(QEMU_CLOCK_VIRTUAL, &xtensa_ccompare_cb, cpu); } } diff --git a/include/block/aio.h b/include/block/aio.h index cc77771c46..2efdf416cf 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -14,10 +14,12 @@ #ifndef QEMU_AIO_H #define QEMU_AIO_H +#include "qemu/typedefs.h" #include "qemu-common.h" #include "qemu/queue.h" #include "qemu/event_notifier.h" #include "qemu/thread.h" +#include "qemu/timer.h" typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); @@ -42,7 +44,7 @@ typedef struct AioHandler AioHandler; typedef void QEMUBHFunc(void *opaque); typedef void IOHandler(void *opaque); -typedef struct AioContext { +struct AioContext { GSource source; /* The list of registered AIO handlers */ @@ -72,10 +74,10 @@ typedef struct AioContext { /* Thread pool for performing work and receiving completion callbacks */ struct ThreadPool *thread_pool; -} AioContext; -/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ -typedef int (AioFlushEventNotifierHandler)(EventNotifier *e); + /* TimerLists for calling timers - one per clock type */ + QEMUTimerListGroup tlg; +}; /** * aio_context_new: Allocate a new AioContext. @@ -198,9 +200,6 @@ bool aio_pending(AioContext *ctx); bool aio_poll(AioContext *ctx, bool blocking); #ifdef CONFIG_POSIX -/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ -typedef int (AioFlushHandler)(void *opaque); - /* Register a file descriptor and associated callbacks. Behaves very similarly * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will * be invoked when using qemu_aio_wait(). @@ -212,7 +211,6 @@ void aio_set_fd_handler(AioContext *ctx, int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque); #endif @@ -225,8 +223,7 @@ void aio_set_fd_handler(AioContext *ctx, */ void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush); + EventNotifierHandler *io_read); /* Return a GSource that lets the main loop poll the file descriptors attached * to this AioContext. @@ -240,15 +237,56 @@ struct ThreadPool *aio_get_thread_pool(AioContext *ctx); bool qemu_aio_wait(void); void qemu_aio_set_event_notifier(EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush); + EventNotifierHandler *io_read); #ifdef CONFIG_POSIX void qemu_aio_set_fd_handler(int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque); #endif +/** + * aio_timer_new: + * @ctx: the aio context + * @type: the clock type + * @scale: the scale + * @cb: the callback to call on timer expiry + * @opaque: the opaque pointer to pass to the callback + * + * Allocate a new timer attached to the context @ctx. + * The function is responsible for memory allocation. + * + * The preferred interface is aio_timer_init. Use that + * unless you really need dynamic memory allocation. + * + * Returns: a pointer to the new timer + */ +static inline QEMUTimer *aio_timer_new(AioContext *ctx, QEMUClockType type, + int scale, + QEMUTimerCB *cb, void *opaque) +{ + return timer_new_tl(ctx->tlg.tl[type], scale, cb, opaque); +} + +/** + * aio_timer_init: + * @ctx: the aio context + * @ts: the timer + * @type: the clock type + * @scale: the scale + * @cb: the callback to call on timer expiry + * @opaque: the opaque pointer to pass to the callback + * + * Initialise a new timer attached to the context @ctx. + * The caller is responsible for memory allocation. + */ +static inline void aio_timer_init(AioContext *ctx, + QEMUTimer *ts, QEMUClockType type, + int scale, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, ctx->tlg.tl[type], scale, cb, opaque); +} + #endif diff --git a/include/block/block_int.h b/include/block/block_int.h index c6ac871e21..8012e253c9 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -34,6 +34,7 @@ #include "monitor/monitor.h" #include "qemu/hbitmap.h" #include "block/snapshot.h" +#include "qemu/main-loop.h" #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 @@ -281,6 +282,9 @@ struct BlockDriverState { /* Whether the disk can expand beyond total_sectors */ int growable; + /* Whether produces zeros when read beyond eof */ + bool zero_beyond_eof; + /* the memory alignment required for the buffers handled by this driver */ int buffer_alignment; @@ -404,6 +408,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, * @bs: Block device to operate on. * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @sync_mode: What parts of the disk image should be copied to the destination. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. * @cb: Completion function for the job. @@ -413,7 +418,8 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, * until the job is cancelled or manually completed. */ void backup_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, BlockdevOnError on_source_error, + int64_t speed, MirrorSyncMode sync_mode, + BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); diff --git a/include/block/blockjob.h b/include/block/blockjob.h index c290d07bba..d530409ff5 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -141,7 +141,7 @@ void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, * Put the job to sleep (assuming that it wasn't canceled) for @ns * nanoseconds. Canceling the job will interrupt the wait immediately. */ -void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); +void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns); /** * block_job_completed: diff --git a/include/block/coroutine.h b/include/block/coroutine.h index 377805a3b0..4232569c53 100644 --- a/include/block/coroutine.h +++ b/include/block/coroutine.h @@ -16,6 +16,7 @@ #define QEMU_COROUTINE_H #include <stdbool.h> +#include "qemu/typedefs.h" #include "qemu/queue.h" #include "qemu/timer.h" @@ -130,12 +131,17 @@ void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue); * * Returns true if a coroutine was restarted, false if the queue is empty. */ -bool qemu_co_queue_next(CoQueue *queue); +bool coroutine_fn qemu_co_queue_next(CoQueue *queue); /** * Restarts all coroutines in the CoQueue and leaves the queue empty. */ -void qemu_co_queue_restart_all(CoQueue *queue); +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue); + +/** + * Enter the next coroutine in the queue + */ +bool qemu_co_enter_next(CoQueue *queue); /** * Checks if the CoQueue is empty. @@ -207,7 +213,7 @@ void qemu_co_rwlock_unlock(CoRwlock *lock); * Note this function uses timers and hence only works when a main loop is in * use. See main-loop.h and do not use from qemu-tool programs. */ -void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns); +void coroutine_fn co_sleep_ns(QEMUClockType type, int64_t ns); /** * Yield until a file descriptor becomes readable diff --git a/include/elf.h b/include/elf.h index cf0d3e2bd6..58bfbf8817 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1348,11 +1348,17 @@ typedef struct elf64_shdr { /* Notes used in ET_CORE */ #define NT_PRSTATUS 1 +#define NT_FPREGSET 2 #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 #define NT_AUXV 6 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ /* Note header in a PT_NOTE section */ diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f2800ec682..a407b50f4a 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -210,11 +210,15 @@ extern unsigned long reserved_va; }) #endif -#define h2g(x) ({ \ +#define h2g_nocheck(x) ({ \ unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \ + (abi_ulong)__ret; \ +}) + +#define h2g(x) ({ \ /* Check if given address fits target address space */ \ assert(h2g_valid(x)); \ - (abi_ulong)__ret; \ + h2g_nocheck(x); \ }) #define saddr(x) g2h(x) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index b5b93db842..a5c028c536 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -154,8 +154,6 @@ typedef struct CPUWatchpoint { memory was accessed */ \ CPU_COMMON_TLB \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ - /* buffer for temporaries in the code generator */ \ - long temp_buf[CPU_TEMP_BUF_NLONGS]; \ \ int64_t icount_extra; /* Instructions until next timer event. */ \ /* Number of cycles left, with interrupt flag in high bit. \ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index b2162a4ec4..ffb69a4c70 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -326,18 +326,7 @@ extern uintptr_t tci_tb_ptr; (6) jump to corresponding code of the next of fast path */ # if defined(__i386__) || defined(__x86_64__) -/* To avoid broken disassembling, long jmp is used for embedding fast path pc, - so that the destination is the next code of fast path, though this jmp is - never executed. - - call MMU helper - jmp POST_PROC (2byte) <- GETRA() - jmp NEXT_CODE (5byte) - POST_PROCESS ... <- GETRA() + 7 - */ -# define GETRA() ((uintptr_t)__builtin_return_address(0)) -# define GETPC_LDST() ((uintptr_t)(GETRA() + 7 + \ - *(int32_t *)((void *)GETRA() + 3) - 1)) +# define GETPC_EXT() GETPC() # elif defined (_ARCH_PPC) && !defined (_ARCH_PPC64) # define GETRA() ((uintptr_t)__builtin_return_address(0)) # define GETPC_LDST() ((uintptr_t) ((*(int32_t *)(GETRA() - 4)) - 1)) @@ -358,11 +347,27 @@ static inline uintptr_t tcg_getpc_ldst(uintptr_t ra) not the start of the next opcode */ return ra; } +# elif defined(__aarch64__) +# define GETRA() ((uintptr_t)__builtin_return_address(0)) +# define GETPC_LDST() tcg_getpc_ldst(GETRA()) +static inline uintptr_t tcg_getpc_ldst(uintptr_t ra) +{ + int32_t b; + ra += 4; /* skip one instruction */ + b = *(int32_t *)ra; /* load the branch insn */ + b = (b << 6) >> (6 - 2); /* extract the displacement */ + ra += b; /* apply the displacement */ + ra -= 4; /* return a pointer into the current opcode, + not the start of the next opcode */ + return ra; +} # else # error "CONFIG_QEMU_LDST_OPTIMIZATION needs GETPC_LDST() implementation!" # endif bool is_tcg_gen_code(uintptr_t pc_ptr); -# define GETPC_EXT() (is_tcg_gen_code(GETRA()) ? GETPC_LDST() : GETPC()) +# ifndef GETPC_EXT +# define GETPC_EXT() (is_tcg_gen_code(GETRA()) ? GETPC_LDST() : GETPC()) +# endif #else # define GETPC_EXT() GETPC() #endif diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 1bd00aea23..a608a26c30 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -32,13 +32,50 @@ void gdb_register_coprocessor(CPUState *cpu, static inline int cpu_index(CPUState *cpu) { -#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) +#if defined(CONFIG_USER_ONLY) return cpu->host_tid; #else return cpu->cpu_index + 1; #endif } +/* The GDB remote protocol transfers values in target byte order. This means + * we can use the raw memory access routines to access the value buffer. + * Conveniently, these also handle the case where the buffer is mis-aligned. + */ + +static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val) +{ + stb_p(mem_buf, val); + return 1; +} + +static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val) +{ + stw_p(mem_buf, val); + return 2; +} + +static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val) +{ + stl_p(mem_buf, val); + return 4; +} + +static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val) +{ + stq_p(mem_buf, val); + return 8; +} + +#if TARGET_LONG_BITS == 64 +#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val) +#define ldtul_p(addr) ldq_p(addr) +#else +#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val) +#define ldtul_p(addr) ldl_p(addr) +#endif + #endif #ifdef CONFIG_USER_ONLY @@ -47,6 +84,14 @@ int gdbserver_start(int); int gdbserver_start(const char *port); #endif +/** + * gdb_has_xml: + * This is an ugly hack to cope with both new and old gdb. + * If gdb sends qXfer:features:read then assume we're talking to a newish + * gdb that understands target descriptions. + */ +extern bool gdb_has_xml; + /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ extern const char *const xml_builtin[][2]; diff --git a/include/exec/poison.h b/include/exec/poison.h index 2341a75041..a4b1eca24f 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -36,7 +36,6 @@ #pragma GCC poison TARGET_PAGE_ALIGN #pragma GCC poison CPUArchState -#pragma GCC poison env #pragma GCC poison lduw_phys #pragma GCC poison ldl_phys diff --git a/include/exec/softmmu_defs.h b/include/exec/softmmu_defs.h index 1f25e33ce4..e55e7178c6 100644 --- a/include/exec/softmmu_defs.h +++ b/include/exec/softmmu_defs.h @@ -9,29 +9,41 @@ #ifndef SOFTMMU_DEFS_H #define SOFTMMU_DEFS_H +uint8_t helper_ret_ldb_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); +uint16_t helper_ret_ldw_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); +uint32_t helper_ret_ldl_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); +uint64_t helper_ret_ldq_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); + +void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, + int mmu_idx, uintptr_t retaddr); +void helper_ret_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, + int mmu_idx, uintptr_t retaddr); +void helper_ret_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx, uintptr_t retaddr); +void helper_ret_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx, uintptr_t retaddr); + uint8_t helper_ldb_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, - int mmu_idx); uint16_t helper_ldw_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, - int mmu_idx); uint32_t helper_ldl_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, - int mmu_idx); uint64_t helper_ldq_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, - int mmu_idx); + +void helper_stb_mmu(CPUArchState *env, target_ulong addr, + uint8_t val, int mmu_idx); +void helper_stw_mmu(CPUArchState *env, target_ulong addr, + uint16_t val, int mmu_idx); +void helper_stl_mmu(CPUArchState *env, target_ulong addr, + uint32_t val, int mmu_idx); +void helper_stq_mmu(CPUArchState *env, target_ulong addr, + uint64_t val, int mmu_idx); uint8_t helper_ldb_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stb_cmmu(CPUArchState *env, target_ulong addr, uint8_t val, -int mmu_idx); uint16_t helper_ldw_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stw_cmmu(CPUArchState *env, target_ulong addr, uint16_t val, - int mmu_idx); uint32_t helper_ldl_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stl_cmmu(CPUArchState *env, target_ulong addr, uint32_t val, - int mmu_idx); uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stq_cmmu(CPUArchState *env, target_ulong addr, uint64_t val, - int mmu_idx); -#endif + +#endif /* SOFTMMU_DEFS_H */ diff --git a/include/exec/softmmu_template.h b/include/exec/softmmu_template.h index 8584902cbe..eaca9e1035 100644 --- a/include/exec/softmmu_template.h +++ b/include/exec/softmmu_template.h @@ -54,10 +54,6 @@ #define ADDR_READ addr_read #endif -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - int mmu_idx, - uintptr_t retaddr); static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, hwaddr physaddr, target_ulong addr, @@ -78,123 +74,86 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, } /* handle all cases except unaligned access which span two pages */ +#ifdef SOFTMMU_CODE_ACCESS +static +#endif DATA_TYPE -glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, - int mmu_idx) +glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, int mmu_idx, + uintptr_t retaddr) { - DATA_TYPE res; - int index; - target_ulong tlb_addr; - hwaddr ioaddr; - uintptr_t retaddr; + int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; + uintptr_t haddr; - /* test if there is match for unaligned or IO access */ - /* XXX: could done more in memory macro in a non portable way */ - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - retaddr = GETPC_EXT(); - ioaddr = env->iotlb[mmu_idx][index]; - res = glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - /* slow unaligned access (it spans two pages or IO) */ - do_unaligned_access: - retaddr = GETPC_EXT(); + /* If the TLB entry is for a different page, reload and try again. */ + if ((addr & TARGET_PAGE_MASK) + != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); -#endif - res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr, - mmu_idx, retaddr); - } else { - /* unaligned/aligned access in the same page */ - uintptr_t addend; -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) { - retaddr = GETPC_EXT(); - do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); - } -#endif - addend = env->tlb_table[mmu_idx][index].addend; - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend)); } - } else { - /* the page is not in the TLB : fill it */ - retaddr = GETPC_EXT(); -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); #endif tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); - goto redo; + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; } - return res; -} -/* handle all unaligned cases */ -static DATA_TYPE -glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - int mmu_idx, - uintptr_t retaddr) -{ - DATA_TYPE res, res1, res2; - int index, shift; - hwaddr ioaddr; - target_ulong tlb_addr, addr1, addr2; + /* Handle an IO access. */ + if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { + hwaddr ioaddr; + if ((addr & (DATA_SIZE - 1)) != 0) { + goto do_unaligned_access; + } + ioaddr = env->iotlb[mmu_idx][index]; + return glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); + } - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - ioaddr = env->iotlb[mmu_idx][index]; - res = glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - do_unaligned_access: - /* slow unaligned access (it spans two pages) */ - addr1 = addr & ~(DATA_SIZE - 1); - addr2 = addr1 + DATA_SIZE; - res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr1, - mmu_idx, retaddr); - res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr2, - mmu_idx, retaddr); - shift = (addr & (DATA_SIZE - 1)) * 8; + /* Handle slow unaligned access (it spans two pages or IO). */ + if (DATA_SIZE > 1 + && unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1 + >= TARGET_PAGE_SIZE)) { + target_ulong addr1, addr2; + DATA_TYPE res1, res2, res; + unsigned shift; + do_unaligned_access: +#ifdef ALIGNED_ONLY + do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); +#endif + addr1 = addr & ~(DATA_SIZE - 1); + addr2 = addr1 + DATA_SIZE; + res1 = glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(env, addr1, + mmu_idx, retaddr); + res2 = glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(env, addr2, + mmu_idx, retaddr); + shift = (addr & (DATA_SIZE - 1)) * 8; #ifdef TARGET_WORDS_BIGENDIAN - res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); + res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); #else - res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); + res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); #endif - res = (DATA_TYPE)res; - } else { - /* unaligned/aligned access in the same page */ - uintptr_t addend = env->tlb_table[mmu_idx][index].addend; - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend)); - } - } else { - /* the page is not in the TLB : fill it */ - tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); - goto redo; + return res; + } + + /* Handle aligned access or unaligned access in the same page. */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } - return res; +#endif + + haddr = addr + env->tlb_table[mmu_idx][index].addend; + return glue(glue(ld, USUFFIX), _raw)((uint8_t *)haddr); } -#ifndef SOFTMMU_CODE_ACCESS +DATA_TYPE +glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, + int mmu_idx) +{ + return glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(env, addr, mmu_idx, + GETPC_EXT()); +} -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - DATA_TYPE val, - int mmu_idx, - uintptr_t retaddr); +#ifndef SOFTMMU_CODE_ACCESS static inline void glue(io_write, SUFFIX)(CPUArchState *env, hwaddr physaddr, @@ -214,107 +173,79 @@ static inline void glue(io_write, SUFFIX)(CPUArchState *env, io_mem_write(mr, physaddr, val, 1 << SHIFT); } -void glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, DATA_TYPE val, - int mmu_idx) +void +glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, DATA_TYPE val, + int mmu_idx, uintptr_t retaddr) { - hwaddr ioaddr; - target_ulong tlb_addr; - uintptr_t retaddr; - int index; + int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + uintptr_t haddr; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - retaddr = GETPC_EXT(); - ioaddr = env->iotlb[mmu_idx][index]; - glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - do_unaligned_access: - retaddr = GETPC_EXT(); + /* If the TLB entry is for a different page, reload and try again. */ + if ((addr & TARGET_PAGE_MASK) + != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { do_unaligned_access(env, addr, 1, mmu_idx, retaddr); -#endif - glue(glue(slow_st, SUFFIX), MMUSUFFIX)(env, addr, val, - mmu_idx, retaddr); - } else { - /* aligned/unaligned access in the same page */ - uintptr_t addend; -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) { - retaddr = GETPC_EXT(); - do_unaligned_access(env, addr, 1, mmu_idx, retaddr); - } -#endif - addend = env->tlb_table[mmu_idx][index].addend; - glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend), val); } - } else { - /* the page is not in the TLB : fill it */ - retaddr = GETPC_EXT(); -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(env, addr, 1, mmu_idx, retaddr); #endif tlb_fill(env, addr, 1, mmu_idx, retaddr); - goto redo; + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; } -} -/* handles all unaligned cases */ -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - DATA_TYPE val, - int mmu_idx, - uintptr_t retaddr) -{ - hwaddr ioaddr; - target_ulong tlb_addr; - int index, i; + /* Handle an IO access. */ + if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { + hwaddr ioaddr; + if ((addr & (DATA_SIZE - 1)) != 0) { + goto do_unaligned_access; + } + ioaddr = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); + return; + } - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - ioaddr = env->iotlb[mmu_idx][index]; - glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - do_unaligned_access: - /* XXX: not efficient, but simple */ - /* Note: relies on the fact that tlb_fill() does not remove the - * previous page from the TLB cache. */ - for(i = DATA_SIZE - 1; i >= 0; i--) { + /* Handle slow unaligned access (it spans two pages or IO). */ + if (DATA_SIZE > 1 + && unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1 + >= TARGET_PAGE_SIZE)) { + int i; + do_unaligned_access: +#ifdef ALIGNED_ONLY + do_unaligned_access(env, addr, 1, mmu_idx, retaddr); +#endif + /* XXX: not efficient, but simple */ + /* Note: relies on the fact that tlb_fill() does not remove the + * previous page from the TLB cache. */ + for (i = DATA_SIZE - 1; i >= 0; i--) { #ifdef TARGET_WORDS_BIGENDIAN - glue(slow_stb, MMUSUFFIX)(env, addr + i, - val >> (((DATA_SIZE - 1) * 8) - (i * 8)), - mmu_idx, retaddr); + uint8_t val8 = val >> (((DATA_SIZE - 1) * 8) - (i * 8)); #else - glue(slow_stb, MMUSUFFIX)(env, addr + i, - val >> (i * 8), - mmu_idx, retaddr); + uint8_t val8 = val >> (i * 8); #endif - } - } else { - /* aligned/unaligned access in the same page */ - uintptr_t addend = env->tlb_table[mmu_idx][index].addend; - glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend), val); + glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8, + mmu_idx, retaddr); } - } else { - /* the page is not in the TLB : fill it */ - tlb_fill(env, addr, 1, mmu_idx, retaddr); - goto redo; + return; + } + + /* Handle aligned access or unaligned access in the same page. */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + do_unaligned_access(env, addr, 1, mmu_idx, retaddr); } +#endif + + haddr = addr + env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)haddr, val); +} + +void +glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, + DATA_TYPE val, int mmu_idx) +{ + glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)(env, addr, val, mmu_idx, + GETPC_EXT()); } #endif /* !defined(SOFTMMU_CODE_ACCESS) */ diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index 635be7be10..51733d3390 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -136,7 +136,7 @@ void acpi_pm_tmr_reset(ACPIREGS *ar); #include "qemu/timer.h" static inline int64_t acpi_pm_tmr_get_clock(void) { - return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, get_ticks_per_sec()); } diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h index bae87c6273..ecbbba871e 100644 --- a/include/hw/arm/arm.h +++ b/include/hw/arm/arm.h @@ -14,11 +14,6 @@ #include "exec/memory.h" #include "hw/irq.h" -/* The CPU is also modelled as an interrupt controller. */ -#define ARM_PIC_CPU_IRQ 0 -#define ARM_PIC_CPU_FIQ 1 -qemu_irq *arm_pic_init_cpu(ARMCPU *cpu); - /* armv7m.c */ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, int flash_size, int sram_size, diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h index bda3213317..2742d70ea0 100644 --- a/include/hw/char/escc.h +++ b/include/hw/char/escc.h @@ -2,6 +2,7 @@ #define HW_ESCC_H 1 /* escc.c */ +#define TYPE_ESCC "escc" #define ESCC_SIZE 4 MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, CharDriverState *chrA, CharDriverState *chrB, diff --git a/include/hw/lm32/lm32_juart.h b/include/hw/char/lm32_juart.h index 67fc5866ea..70dc416e9f 100644 --- a/include/hw/lm32/lm32_juart.h +++ b/include/hw/char/lm32_juart.h @@ -1,7 +1,9 @@ -#ifndef QEMU_HW_LM32_JUART_H -#define QEMU_HW_LM32_JUART_H +#ifndef QEMU_HW_CHAR_LM32_JUART_H +#define QEMU_HW_CHAR_LM32_JUART_H -#include "qemu-common.h" +#include "hw/qdev.h" + +#define TYPE_LM32_JUART "lm32-juart" uint32_t lm32_juart_get_jtx(DeviceState *d); uint32_t lm32_juart_get_jrx(DeviceState *d); diff --git a/include/hw/i386/ioapic.h b/include/hw/i386/ioapic.h index 86e63dac74..6245388c5d 100644 --- a/include/hw/i386/ioapic.h +++ b/include/hw/i386/ioapic.h @@ -21,6 +21,7 @@ #define HW_IOAPIC_H #define IOAPIC_NUM_PINS 24 +#define IO_APIC_DEFAULT_ADDRESS 0xfec00000 void ioapic_eoi_broadcast(int vector); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 7fb97b08a2..f79d4782c1 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -18,8 +18,8 @@ typedef struct PcPciInfo { } PcPciInfo; struct PcGuestInfo { - PcPciInfo pci_info; bool has_pci_info; + bool isapc_ram_fw; FWCfgState *fw_cfg; }; @@ -101,6 +101,16 @@ void pc_acpi_init(const char *default_dsdt); PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size); +#define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" +#define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end" +#define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start" +#define PCI_HOST_PROP_PCI_HOLE64_END "pci-hole64-end" +#define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size" +#define DEFAULT_PCI_HOLE64_SIZE (1ULL << 31) + +void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start, + uint64_t pci_hole64_size); + FWCfgState *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline, @@ -150,8 +160,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, ram_addr_t ram_size, hwaddr pci_hole_start, hwaddr pci_hole_size, - hwaddr pci_hole64_start, - hwaddr pci_hole64_size, + ram_addr_t above_4g_mem_size, MemoryRegion *pci_memory, MemoryRegion *ram_memory); @@ -192,7 +201,8 @@ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) } /* pc_sysfw.c */ -void pc_system_firmware_init(MemoryRegion *rom_memory); +void pc_system_firmware_init(MemoryRegion *rom_memory, + bool isapc_ram_fw); /* pvpanic.c */ void pvpanic_init(ISABus *bus); @@ -235,6 +245,10 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); .driver = "virtio-net-pci",\ .property = "any_layout",\ .value = "off",\ + },{\ + .driver = TYPE_X86_CPU,\ + .property = "pmu",\ + .value = "on",\ } #define PC_COMPAT_1_4 \ diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index e1bf96ca69..495bcf3a08 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -92,9 +92,6 @@ static inline ISABus *isa_bus_from_device(ISADevice *d) extern hwaddr isa_mem_base; -void isa_mmio_setup(MemoryRegion *mr, hwaddr size); -void isa_mmio_init(hwaddr base, hwaddr size); - /* dma.c */ int DMA_get_channel_mode (int nchan); int DMA_read_memory (int nchan, void *buf, int pos, int size); diff --git a/include/hw/loader.h b/include/hw/loader.h index eb9c9a3612..61457360f6 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -36,6 +36,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source); +extern bool rom_file_in_ram; int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex); diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h index 291e85f6b9..2a7a9c9f42 100644 --- a/include/hw/mips/mips.h +++ b/include/hw/mips/mips.h @@ -2,6 +2,9 @@ #define HW_MIPS_H /* Definitions for mips board emulation. */ +/* Kernels can be configured with 64KB pages */ +#define INITRD_PAGE_MASK (~((1 << 16) - 1)) + #include "exec/memory.h" /* gt64xxx.c */ diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 3cb631eeae..6eb7ab676f 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -55,9 +55,11 @@ typedef struct MCHPCIState { MemoryRegion smram_region; MemoryRegion pci_hole; MemoryRegion pci_hole_64bit; + PcPciInfo pci_info; uint8_t smm_enabled; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; + uint64_t pci_hole64_size; PcGuestInfo *guest_info; } MCHPCIState; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1e23dbfb4a..93f9511325 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -52,14 +52,14 @@ typedef struct sPAPRPHBState { sPAPRTCETable *tcet; AddressSpace iommu_as; - struct { + struct spapr_pci_lsi { uint32_t irq; } lsi_table[PCI_NUM_PINS]; - struct { + struct spapr_pci_msi { uint32_t config_addr; uint32_t irq; - int nvec; + uint32_t nvec; } msi_table[SPAPR_MSIX_MAX_DEVS]; QLIST_ENTRY(sPAPRPHBState) list; diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 66762f6d5e..9df17885ec 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -53,8 +53,13 @@ struct PCIBridgeWindows { MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS]; }; +#define TYPE_PCI_BRIDGE "base-pci-bridge" +#define PCI_BRIDGE(obj) OBJECT_CHECK(PCIBridge, (obj), TYPE_PCI_BRIDGE) + struct PCIBridge { - PCIDevice dev; + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ /* private member */ PCIBus sec_bus; diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index d7933bfd16..3ddaf6aad5 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -143,8 +143,9 @@ #define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 -#define PCI_VENDOR_ID_XEN 0x5853 -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 +#define PCI_VENDOR_ID_XEN 0x5853 +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 +#define PCI_DEVICE_ID_XEN_PVDEVICE 0x0002 #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_UPD720200 0x0194 diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index d89aa615c5..e167bf7520 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -24,8 +24,13 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" +#define TYPE_PCIE_PORT "pcie-port" +#define PCIE_PORT(obj) OBJECT_CHECK(PCIEPort, (obj), TYPE_PCIE_PORT) + struct PCIEPort { - PCIBridge br; + /*< private >*/ + PCIBridge parent_obj; + /*< public >*/ /* pci express switch port */ uint8_t port; @@ -33,8 +38,13 @@ struct PCIEPort { void pcie_port_init_reg(PCIDevice *d); +#define TYPE_PCIE_SLOT "pcie-slot" +#define PCIE_SLOT(obj) OBJECT_CHECK(PCIESlot, (obj), TYPE_PCIE_SLOT) + struct PCIESlot { - PCIEPort port; + /*< private >*/ + PCIEPort parent_obj; + /*< public >*/ /* pci express switch port with slot */ uint8_t chassis; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index de95480734..9fc197286c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -7,30 +7,36 @@ struct VIOsPAPRBus; struct sPAPRPHBState; struct sPAPRNVRAM; -struct icp_state; + +#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; QLIST_HEAD(, sPAPRPHBState) phbs; struct sPAPRNVRAM *nvram; - struct icp_state *icp; + XICSState *icp; hwaddr ram_limit; void *htab; - long htab_shift; + uint32_t htab_shift; hwaddr rma_size; int vrma_adjust; hwaddr fdt_addr, rtas_addr; long rtas_size; void *fdt_skel; target_ulong entry_point; - int next_irq; - int rtc_offset; + uint32_t next_irq; + uint64_t rtc_offset; char *cpu_model; bool has_graphics; uint32_t epow_irq; Notifier epow_notifier; + + /* Migration state */ + int htab_save_index; + bool htab_first_pass; + int htab_fd; } sPAPREnvironment; #define H_SUCCESS 0 @@ -334,10 +340,6 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, #define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT) #define SPAPR_TCE_PAGE_MASK (SPAPR_TCE_PAGE_SIZE - 1) -typedef struct sPAPRTCE { - uint64_t tce; -} sPAPRTCE; - #define SPAPR_VIO_BASE_LIOBN 0x00000000 #define SPAPR_PCI_BASE_LIOBN 0x80000000 @@ -345,14 +347,27 @@ typedef struct sPAPRTCE { typedef struct sPAPRTCETable sPAPRTCETable; -void spapr_iommu_init(void); +#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" +#define SPAPR_TCE_TABLE(obj) \ + OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE) + +struct sPAPRTCETable { + DeviceState parent; + uint32_t liobn; + uint32_t window_size; + uint32_t nb_table; + uint64_t *table; + bool bypass; + int fd; + MemoryRegion iommu; + QLIST_ENTRY(sPAPRTCETable) list; +}; + void spapr_events_init(sPAPREnvironment *spapr); void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size); MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet); -void spapr_tce_free(sPAPRTCETable *tcet); -void spapr_tce_reset(sPAPRTCETable *tcet); void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass); int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size); diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 36093270e6..46edc2a20c 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -134,4 +134,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); void spapr_vio_quiesce(void); +extern const VMStateDescription vmstate_spapr_vio; + +#define VMSTATE_SPAPR_VIO(_f, _s) \ + VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice) + #endif /* _HW_SPAPR_VIO_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 6bce0424df..66364c5faf 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -27,15 +27,77 @@ #if !defined(__XICS_H__) #define __XICS_H__ +#include "hw/sysbus.h" + +#define TYPE_XICS "xics" +#define XICS(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) + #define XICS_IPI 0x2 -#define XICS_IRQ_BASE 0x10 +#define XICS_BUID 0x1 +#define XICS_IRQ_BASE (XICS_BUID << 12) + +/* + * We currently only support one BUID which is our interrupt base + * (the kernel implementation supports more but we don't exploit + * that yet) + */ +typedef struct XICSState XICSState; +typedef struct ICPState ICPState; +typedef struct ICSState ICSState; +typedef struct ICSIRQState ICSIRQState; + +struct XICSState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t nr_servers; + uint32_t nr_irqs; + ICPState *ss; + ICSState *ics; +}; + +#define TYPE_ICP "icp" +#define ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_ICP) + +struct ICPState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; +}; + +#define TYPE_ICS "ics" +#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) + +struct ICSState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t nr_irqs; + uint32_t offset; + qemu_irq *qirqs; + bool *islsi; + ICSIRQState *irqs; + XICSState *icp; +}; -struct icp_state; +struct ICSIRQState { + uint32_t server; + uint8_t priority; + uint8_t saved_priority; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; +}; -qemu_irq xics_get_qirq(struct icp_state *icp, int irq); -void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); +qemu_irq xics_get_qirq(XICSState *icp, int irq); +void xics_set_irq_type(XICSState *icp, int irq, bool lsi); -struct icp_state *xics_system_init(int nr_servers, int nr_irqs); -void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu); +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu); #endif /* __XICS_H__ */ diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 7fbffcbaad..46972f4961 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -4,6 +4,7 @@ #include "qemu/queue.h" #include "qemu/option.h" #include "qemu/typedefs.h" +#include "qemu/bitmap.h" #include "qom/object.h" #include "hw/irq.h" #include "qapi/error.h" @@ -17,6 +18,34 @@ enum { #define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) #define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) +typedef enum DeviceCategory { + DEVICE_CATEGORY_BRIDGE, + DEVICE_CATEGORY_USB, + DEVICE_CATEGORY_STORAGE, + DEVICE_CATEGORY_NETWORK, + DEVICE_CATEGORY_INPUT, + DEVICE_CATEGORY_DISPLAY, + DEVICE_CATEGORY_SOUND, + DEVICE_CATEGORY_MISC, + DEVICE_CATEGORY_MAX +} DeviceCategory; + +static inline const char *qdev_category_get_name(DeviceCategory category) +{ + static const char *category_names[DEVICE_CATEGORY_MAX] = { + [DEVICE_CATEGORY_BRIDGE] = "Controller/Bridge/Hub", + [DEVICE_CATEGORY_USB] = "USB", + [DEVICE_CATEGORY_STORAGE] = "Storage", + [DEVICE_CATEGORY_NETWORK] = "Network", + [DEVICE_CATEGORY_INPUT] = "Input", + [DEVICE_CATEGORY_DISPLAY] = "Display", + [DEVICE_CATEGORY_SOUND] = "Sound", + [DEVICE_CATEGORY_MISC] = "Misc", + }; + + return category_names[category]; +}; + typedef int (*qdev_initfn)(DeviceState *dev); typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); @@ -80,6 +109,7 @@ typedef struct DeviceClass { ObjectClass parent_class; /*< public >*/ + DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX); const char *fw_name; const char *desc; Property *props; diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 39448b716c..692f82e935 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -15,6 +15,7 @@ extern PropertyInfo qdev_prop_uint64; extern PropertyInfo qdev_prop_hex8; extern PropertyInfo qdev_prop_hex32; extern PropertyInfo qdev_prop_hex64; +extern PropertyInfo qdev_prop_size; extern PropertyInfo qdev_prop_string; extern PropertyInfo qdev_prop_chr; extern PropertyInfo qdev_prop_ptr; @@ -116,6 +117,8 @@ extern PropertyInfo qdev_prop_arraylen; DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) #define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) +#define DEFINE_PROP_SIZE(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_size, uint64_t) #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 8c17165cf2..bb50a877cc 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -42,7 +42,10 @@ typedef struct SysBusDeviceClass { } SysBusDeviceClass; struct SysBusDevice { - DeviceState qdev; + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + int num_irq; qemu_irq irqs[QDEV_MAX_IRQ]; qemu_irq *irqp[QDEV_MAX_IRQ]; @@ -55,10 +58,6 @@ struct SysBusDevice { pio_addr_t pio[QDEV_MAX_PIO]; }; -/* Macros to compensate for lack of type inheritance in C. */ -#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev) - -void *sysbus_new(void); void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory); MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n); void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p); diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h index 59337faaad..8217522291 100644 --- a/include/hw/timer/m48t59.h +++ b/include/hw/timer/m48t59.h @@ -21,6 +21,9 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, uint32_t initrd_image, uint32_t initrd_size, uint32_t NVRAM_image, int width, int height, int depth); + +#define TYPE_SYSBUS_M48T59 "m48t59" + typedef struct M48t59State M48t59State; void m48t59_write (void *private, uint32_t addr, uint32_t val); diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index fc71853eb4..b87cf490b1 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -125,6 +125,7 @@ typedef struct VirtIOBlock { unsigned short sector_mask; VMChangeStateEntry *change; #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + Notifier migration_state_notifier; struct VirtIOBlockDataPlane *dataplane; #endif } VirtIOBlock; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index d7e9e0fc8a..a90522d6d6 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -237,6 +237,7 @@ hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n); uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); +void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n); VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); uint16_t virtio_get_queue_index(VirtQueue *vq); int virtio_queue_get_id(VirtQueue *vq); diff --git a/include/migration/migration.h b/include/migration/migration.h index 08c772d4dc..140e6b471c 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -90,7 +90,7 @@ int migrate_fd_close(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); -bool migration_is_active(MigrationState *); +bool migration_in_setup(MigrationState *); bool migration_has_finished(MigrationState *); bool migration_has_failed(MigrationState *); MigrationState *migrate_get_current(void); diff --git a/include/qapi/opts-visitor.h b/include/qapi/opts-visitor.h index 5939eeebc7..fd48c14ec8 100644 --- a/include/qapi/opts-visitor.h +++ b/include/qapi/opts-visitor.h @@ -16,6 +16,12 @@ #include "qapi/visitor.h" #include "qemu/option.h" +/* Inclusive upper bound on the size of any flattened range. This is a safety + * (= anti-annoyance) measure; wrong ranges should not cause long startup + * delays nor exhaust virtual memory. + */ +#define OPTS_VISITOR_RANGE_MAX 65536 + typedef struct OptsVisitor OptsVisitor; /* Contrarily to qemu-option.c::parse_option_number(), OptsVisitor's "int" diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 685b2e3fcb..d6855d112e 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -65,5 +65,6 @@ int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value); const char *qdict_get_try_str(const QDict *qdict, const char *key); QDict *qdict_clone_shallow(const QDict *src); +void qdict_flatten(QDict *qdict); #endif /* QDICT_H */ diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 9124649ed2..d0bbc7c4a6 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -44,6 +44,7 @@ typedef enum { QTYPE_QFLOAT, QTYPE_QBOOL, QTYPE_QERROR, + QTYPE_MAX, } qtype_code; struct QObject; diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 5159964863..f3fa420245 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -22,12 +22,18 @@ struct Visitor const char *name, size_t size, Error **errp); void (*end_struct)(Visitor *v, Error **errp); + void (*start_implicit_struct)(Visitor *v, void **obj, size_t size, + Error **errp); + void (*end_implicit_struct)(Visitor *v, Error **errp); + void (*start_list)(Visitor *v, const char *name, Error **errp); GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp); void (*end_list)(Visitor *v, Error **errp); void (*type_enum)(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp); + void (*get_next_type)(Visitor *v, int *kind, const int *qobjects, + const char *name, Error **errp); void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp); void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp); diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 28c21d8338..48a2a2edfd 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -13,6 +13,7 @@ #ifndef QAPI_VISITOR_CORE_H #define QAPI_VISITOR_CORE_H +#include "qapi/qmp/qobject.h" #include "qapi/error.h" #include <stdlib.h> @@ -33,12 +34,17 @@ void visit_end_handle(Visitor *v, Error **errp); void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp); void visit_end_struct(Visitor *v, Error **errp); +void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, + Error **errp); +void visit_end_implicit_struct(Visitor *v, Error **errp); void visit_start_list(Visitor *v, const char *name, Error **errp); GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp); void visit_end_list(Visitor *v, Error **errp); void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp); void visit_end_optional(Visitor *v, Error **errp); +void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, + const char *name, Error **errp); void visit_type_enum(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp); void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp); diff --git a/include/qemu/option.h b/include/qemu/option.h index a83c700323..7a58e477d9 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -73,6 +73,8 @@ QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest, QEMUOptionParameter *list); QEMUOptionParameter *parse_option_parameters(const char *param, QEMUOptionParameter *list, QEMUOptionParameter *dest); +void parse_option_size(const char *name, const char *value, + uint64_t *ret, Error **errp); void free_option_parameters(QEMUOptionParameter *list); void print_option_parameters(QEMUOptionParameter *list); void print_option_help(QEMUOptionParameter *list); @@ -120,6 +122,7 @@ bool qemu_opt_has_help_opt(QemuOpts *opts); bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval); uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval); uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval); +int qemu_opt_unset(QemuOpts *opts, const char *name); int qemu_opt_set(QemuOpts *opts, const char *name, const char *value); void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, Error **errp); diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h index d1610f135b..d413a4a696 100644 --- a/include/qemu/ratelimit.h +++ b/include/qemu/ratelimit.h @@ -23,7 +23,7 @@ typedef struct { static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n) { - int64_t now = qemu_get_clock_ns(rt_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); if (limit->next_slice_time < now) { limit->next_slice_time = now + limit->slice_ns; diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h index 0f30dccb53..361566abc4 100644 --- a/include/qemu/thread-posix.h +++ b/include/qemu/thread-posix.h @@ -15,7 +15,7 @@ struct QemuSemaphore { #if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_t lock; pthread_cond_t cond; - int count; + unsigned int count; #else sem_t sem; #endif diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 9dd206ce7f..e4934dd61b 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -1,8 +1,8 @@ #ifndef QEMU_TIMER_H #define QEMU_TIMER_H +#include "qemu/typedefs.h" #include "qemu-common.h" -#include "qemu/main-loop.h" #include "qemu/notify.h" /* timers */ @@ -11,80 +11,643 @@ #define SCALE_US 1000 #define SCALE_NS 1 -typedef struct QEMUClock QEMUClock; +/** + * QEMUClockType: + * + * The following clock types are available: + * + * @QEMU_CLOCK_REALTIME: Real time clock + * + * The real time clock should be used only for stuff which does not + * change the virtual machine state, as it is run even if the virtual + * machine is stopped. The real time clock has a frequency of 1000 + * Hz. + * + * @QEMU_CLOCK_VIRTUAL: virtual clock + * + * The virtual clock is only run during the emulation. It is stopped + * when the virtual machine is stopped. Virtual timers use a high + * precision clock, usually cpu cycles (use ticks_per_sec). + * + * @QEMU_CLOCK_HOST: host clock + * + * The host clock should be use for device models that emulate accurate + * real time sources. It will continue to run when the virtual machine + * is suspended, and it will reflect system time changes the host may + * undergo (e.g. due to NTP). The host clock has the same precision as + * the virtual clock. + */ + +typedef enum { + QEMU_CLOCK_REALTIME = 0, + QEMU_CLOCK_VIRTUAL = 1, + QEMU_CLOCK_HOST = 2, + QEMU_CLOCK_MAX +} QEMUClockType; + +typedef struct QEMUTimerList QEMUTimerList; + +struct QEMUTimerListGroup { + QEMUTimerList *tl[QEMU_CLOCK_MAX]; +}; + typedef void QEMUTimerCB(void *opaque); +typedef void QEMUTimerListNotifyCB(void *opaque); + +struct QEMUTimer { + int64_t expire_time; /* in nanoseconds */ + QEMUTimerList *timer_list; + QEMUTimerCB *cb; + void *opaque; + QEMUTimer *next; + int scale; +}; + +extern QEMUTimerListGroup main_loop_tlg; + +/* + * QEMUClockType + */ + +/* + * qemu_clock_get_ns; + * @type: the clock type + * + * Get the nanosecond value of a clock with + * type @type + * + * Returns: the clock value in nanoseconds + */ +int64_t qemu_clock_get_ns(QEMUClockType type); + +/** + * qemu_clock_get_ms; + * @type: the clock type + * + * Get the millisecond value of a clock with + * type @type + * + * Returns: the clock value in milliseconds + */ +static inline int64_t qemu_clock_get_ms(QEMUClockType type) +{ + return qemu_clock_get_ns(type) / SCALE_MS; +} + +/** + * qemu_clock_get_us; + * @type: the clock type + * + * Get the microsecond value of a clock with + * type @type + * + * Returns: the clock value in microseconds + */ +static inline int64_t qemu_clock_get_us(QEMUClockType type) +{ + return qemu_clock_get_ns(type) / SCALE_US; +} + +/** + * qemu_clock_has_timers: + * @type: the clock type + * + * Determines whether a clock's default timer list + * has timers attached + * + * Returns: true if the clock's default timer list + * has timers attached + */ +bool qemu_clock_has_timers(QEMUClockType type); + +/** + * qemu_clock_expired: + * @type: the clock type + * + * Determines whether a clock's default timer list + * has an expired clock. + * + * Returns: true if the clock's default timer list has + * an expired timer + */ +bool qemu_clock_expired(QEMUClockType type); + +/** + * qemu_clock_use_for_deadline: + * @type: the clock type + * + * Determine whether a clock should be used for deadline + * calculations. Some clocks, for instance vm_clock with + * use_icount set, do not count in nanoseconds. Such clocks + * are not used for deadline calculations, and are presumed + * to interrupt any poll using qemu_notify/aio_notify + * etc. + * + * Returns: true if the clock runs in nanoseconds and + * should be used for a deadline. + */ +bool qemu_clock_use_for_deadline(QEMUClockType type); + +/** + * qemu_clock_deadline_ns_all: + * @type: the clock type + * + * Calculate the deadline across all timer lists associated + * with a clock (as opposed to just the default one) + * in nanoseconds, or -1 if no timer is set to expire. + * + * Returns: time until expiry in nanoseconds or -1 + */ +int64_t qemu_clock_deadline_ns_all(QEMUClockType type); + +/** + * qemu_clock_get_main_loop_timerlist: + * @type: the clock type + * + * Return the default timer list assocatiated with a clock. + * + * Returns: the default timer list + */ +QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type); -/* The real time clock should be used only for stuff which does not - change the virtual machine state, as it is run even if the virtual - machine is stopped. The real time clock has a frequency of 1000 - Hz. */ -extern QEMUClock *rt_clock; - -/* The virtual clock is only run during the emulation. It is stopped - when the virtual machine is stopped. Virtual timers use a high - precision clock, usually cpu cycles (use ticks_per_sec). */ -extern QEMUClock *vm_clock; - -/* The host clock should be use for device models that emulate accurate - real time sources. It will continue to run when the virtual machine - is suspended, and it will reflect system time changes the host may - undergo (e.g. due to NTP). The host clock has the same precision as - the virtual clock. */ -extern QEMUClock *host_clock; - -int64_t qemu_get_clock_ns(QEMUClock *clock); -int64_t qemu_clock_has_timers(QEMUClock *clock); -int64_t qemu_clock_expired(QEMUClock *clock); -int64_t qemu_clock_deadline(QEMUClock *clock); -void qemu_clock_enable(QEMUClock *clock, bool enabled); -void qemu_clock_warp(QEMUClock *clock); - -void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier); -void qemu_unregister_clock_reset_notifier(QEMUClock *clock, +/** + * qemu_clock_nofify: + * @type: the clock type + * + * Call the notifier callback connected with the default timer + * list linked to the clock, or qemu_notify() if none. + */ +void qemu_clock_notify(QEMUClockType type); + +/** + * qemu_clock_enable: + * @type: the clock type + * @enabled: true to enable, false to disable + * + * Enable or disable a clock + */ +void qemu_clock_enable(QEMUClockType type, bool enabled); + +/** + * qemu_clock_warp: + * @type: the clock type + * + * Warp a clock to a new value + */ +void qemu_clock_warp(QEMUClockType type); + +/** + * qemu_clock_register_reset_notifier: + * @type: the clock type + * @notifier: the notifier function + * + * Register a notifier function to call when the clock + * concerned is reset. + */ +void qemu_clock_register_reset_notifier(QEMUClockType type, + Notifier *notifier); + +/** + * qemu_clock_unregister_reset_notifier: + * @type: the clock type + * @notifier: the notifier function + * + * Unregister a notifier function to call when the clock + * concerned is reset. + */ +void qemu_clock_unregister_reset_notifier(QEMUClockType type, Notifier *notifier); -QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, - QEMUTimerCB *cb, void *opaque); -void qemu_free_timer(QEMUTimer *ts); -void qemu_del_timer(QEMUTimer *ts); -void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time); -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); -bool qemu_timer_pending(QEMUTimer *ts); -bool qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); -uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts); - -void qemu_run_timers(QEMUClock *clock); -void qemu_run_all_timers(void); -void configure_alarms(char const *opt); -void init_clocks(void); -int init_timer_alarm(void); +/** + * qemu_clock_run_timers: + * @type: clock on which to operate + * + * Run all the timers associated with the default timer list + * of a clock. + * + * Returns: true if any timer ran. + */ +bool qemu_clock_run_timers(QEMUClockType type); -int64_t cpu_get_ticks(void); -void cpu_enable_ticks(void); -void cpu_disable_ticks(void); +/** + * qemu_clock_run_all_timers: + * + * Run all the timers associated with the default timer list + * of every clock. + * + * Returns: true if any timer ran. + */ +bool qemu_clock_run_all_timers(void); + +/* + * QEMUTimerList + */ + +/** + * timerlist_new: + * @type: the clock type to associate with the timerlist + * @cb: the callback to call on notification + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timerlist associated with the clock of + * type @type. + * + * Returns: a pointer to the QEMUTimerList created + */ +QEMUTimerList *timerlist_new(QEMUClockType type, + QEMUTimerListNotifyCB *cb, void *opaque); + +/** + * timerlist_free: + * @timer_list: the timer list to free + * + * Frees a timer_list. It must have no active timers. + */ +void timerlist_free(QEMUTimerList *timer_list); + +/** + * timerlist_has_timers: + * @timer_list: the timer list to operate on + * + * Determine whether a timer list has active timers + * + * Returns: true if the timer list has timers. + */ +bool timerlist_has_timers(QEMUTimerList *timer_list); + +/** + * timerlist_expired: + * @timer_list: the timer list to operate on + * + * Determine whether a timer list has any timers which + * are expired. + * + * Returns: true if the timer list has timers which + * have expired. + */ +bool timerlist_expired(QEMUTimerList *timer_list); + +/** + * timerlist_deadline_ns: + * @timer_list: the timer list to operate on + * + * Determine the deadline for a timer_list, i.e. + * the number of nanoseconds until the first timer + * expires. Return -1 if there are no timers. + * + * Returns: the number of nanoseconds until the earliest + * timer expires -1 if none + */ +int64_t timerlist_deadline_ns(QEMUTimerList *timer_list); + +/** + * timerlist_get_clock: + * @timer_list: the timer list to operate on + * + * Determine the clock type associated with a timer list. + * + * Returns: the clock type associated with the + * timer list. + */ +QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list); + +/** + * timerlist_run_timers: + * @timer_list: the timer list to use + * + * Call all expired timers associated with the timer list. + * + * Returns: true if any timer expired + */ +bool timerlist_run_timers(QEMUTimerList *timer_list); + +/** + * timerlist_notify: + * @timer_list: the timer list to use + * + * call the notifier callback associated with the timer list. + */ +void timerlist_notify(QEMUTimerList *timer_list); + +/* + * QEMUTimerListGroup + */ + +/** + * timerlistgroup_init: + * @tlg: the timer list group + * @cb: the callback to call when a notify is required + * @opaque: the opaque pointer to be passed to the callback. + * + * Initialise a timer list group. This must already be + * allocated in memory and zeroed. The notifier callback is + * called whenever a clock in the timer list group is + * reenabled or whenever a timer associated with any timer + * list is modified. If @cb is specified as null, qemu_notify() + * is used instead. + */ +void timerlistgroup_init(QEMUTimerListGroup *tlg, + QEMUTimerListNotifyCB *cb, void *opaque); + +/** + * timerlistgroup_deinit: + * @tlg: the timer list group + * + * Deinitialise a timer list group. This must already be + * initialised. Note the memory is not freed. + */ +void timerlistgroup_deinit(QEMUTimerListGroup *tlg); + +/** + * timerlistgroup_run_timers: + * @tlg: the timer list group + * + * Run the timers associated with a timer list group. + * This will run timers on multiple clocks. + * + * Returns: true if any timer callback ran + */ +bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg); + +/** + * timerlistgroup_deadline_ns: + * @tlg: the timer list group + * + * Determine the deadline of the soonest timer to + * expire associated with any timer list linked to + * the timer list group. Only clocks suitable for + * deadline calculation are included. + * + * Returns: the deadline in nanoseconds or -1 if no + * timers are to expire. + */ +int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg); + +/* + * QEMUTimer + */ + +/** + * timer_init: + * @ts: the timer to be initialised + * @timer_list: the timer list to attach the timer to + * @scale: the scale value for the tiemr + * @cb: the callback to be called when the timer expires + * @opaque: the opaque pointer to be passed to the callback + * + * Initialise a new timer and associate it with @timer_list. + * The caller is responsible for allocating the memory. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +void timer_init(QEMUTimer *ts, + QEMUTimerList *timer_list, int scale, + QEMUTimerCB *cb, void *opaque); + +/** + * timer_new_tl: + * @timer_list: the timer list to attach the timer to + * @scale: the scale value for the tiemr + * @cb: the callback to be called when the timer expires + * @opaque: the opaque pointer to be passed to the callback + * + * Creeate a new timer and associate it with @timer_list. + * The memory is allocated by the function. + * + * This is not the preferred interface unless you know you + * are going to call timer_free. Use timer_init instead. + * + * Returns: a pointer to the timer + */ +static inline QEMUTimer *timer_new_tl(QEMUTimerList *timer_list, + int scale, + QEMUTimerCB *cb, + void *opaque) +{ + QEMUTimer *ts = g_malloc0(sizeof(QEMUTimer)); + timer_init(ts, timer_list, scale, cb, opaque); + return ts; +} -static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb, - void *opaque) +/** + * timer_new: + * @type: the clock type to use + * @scale: the scale value for the tiemr + * @cb: the callback to be called when the timer expires + * @opaque: the opaque pointer to be passed to the callback + * + * Creeate a new timer and associate it with the default + * timer list for the clock type @type. + * + * Returns: a pointer to the timer + */ +static inline QEMUTimer *timer_new(QEMUClockType type, int scale, + QEMUTimerCB *cb, void *opaque) { - return qemu_new_timer(clock, SCALE_NS, cb, opaque); + return timer_new_tl(main_loop_tlg.tl[type], scale, cb, opaque); } -static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, QEMUTimerCB *cb, - void *opaque) +/** + * timer_new_ns: + * @clock: the clock to associate with the timer + * @callback: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timer with nanosecond scale on the default timer list + * associated with the clock. + * + * Returns: a pointer to the newly created timer + */ +static inline QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb, + void *opaque) { - return qemu_new_timer(clock, SCALE_MS, cb, opaque); + return timer_new(type, SCALE_NS, cb, opaque); } -static inline int64_t qemu_get_clock_ms(QEMUClock *clock) +/** + * timer_new_us: + * @clock: the clock to associate with the timer + * @callback: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timer with microsecond scale on the default timer list + * associated with the clock. + * + * Returns: a pointer to the newly created timer + */ +static inline QEMUTimer *timer_new_us(QEMUClockType type, QEMUTimerCB *cb, + void *opaque) { - return qemu_get_clock_ns(clock) / SCALE_MS; + return timer_new(type, SCALE_US, cb, opaque); } +/** + * timer_new_ms: + * @clock: the clock to associate with the timer + * @callback: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timer with millisecond scale on the default timer list + * associated with the clock. + * + * Returns: a pointer to the newly created timer + */ +static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb, + void *opaque) +{ + return timer_new(type, SCALE_MS, cb, opaque); +} + +/** + * timer_free: + * @ts: the timer + * + * Free a timer (it must not be on the active list) + */ +void timer_free(QEMUTimer *ts); + +/** + * timer_del: + * @ts: the timer + * + * Delete a timer from the active list. + */ +void timer_del(QEMUTimer *ts); + +/** + * timer_mod_ns: + * @ts: the timer + * @expire_time: the expiry time in nanoseconds + * + * Modify a timer to expire at @expire_time + */ +void timer_mod_ns(QEMUTimer *ts, int64_t expire_time); + +/** + * timer_mod: + * @ts: the timer + * @expire_time: the expire time in the units associated with the timer + * + * Modify a timer to expiry at @expire_time, taking into + * account the scale associated with the timer. + */ +void timer_mod(QEMUTimer *ts, int64_t expire_timer); + +/** + * timer_pending: + * @ts: the timer + * + * Determines whether a timer is pending (i.e. is on the + * active list of timers, whether or not it has not yet expired). + * + * Returns: true if the timer is pending + */ +bool timer_pending(QEMUTimer *ts); + +/** + * timer_expired: + * @ts: the timer + * + * Determines whether a timer has expired. + * + * Returns: true if the timer has expired + */ +bool timer_expired(QEMUTimer *timer_head, int64_t current_time); + +/** + * timer_expire_time_ns: + * @ts: the timer + * + * Determine the expiry time of a timer + * + * Returns: the expiry time in nanoseconds + */ +uint64_t timer_expire_time_ns(QEMUTimer *ts); + +/** + * timer_get: + * @f: the file + * @ts: the timer + * + * Read a timer @ts from a file @f + */ +void timer_get(QEMUFile *f, QEMUTimer *ts); + +/** + * timer_put: + * @f: the file + * @ts: the timer + */ +void timer_put(QEMUFile *f, QEMUTimer *ts); + +/* + * General utility functions + */ + +/** + * qemu_timeout_ns_to_ms: + * @ns: nanosecond timeout value + * + * Convert a nanosecond timeout value (or -1) to + * a millisecond value (or -1), always rounding up. + * + * Returns: millisecond timeout value + */ +int qemu_timeout_ns_to_ms(int64_t ns); + +/** + * qemu_poll_ns: + * @fds: Array of file descriptors + * @nfds: number of file descriptors + * @timeout: timeout in nanoseconds + * + * Perform a poll like g_poll but with a timeout in nanoseconds. + * See g_poll documentation for further details. + * + * Returns: number of fds ready + */ +int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout); + +/** + * qemu_soonest_timeout: + * @timeout1: first timeout in nanoseconds (or -1 for infinite) + * @timeout2: second timeout in nanoseconds (or -1 for infinite) + * + * Calculates the soonest of two timeout values. -1 means infinite, which + * is later than any other value. + * + * Returns: soonest timeout value in nanoseconds (or -1 for infinite) + */ +static inline int64_t qemu_soonest_timeout(int64_t timeout1, int64_t timeout2) +{ + /* we can abuse the fact that -1 (which means infinite) is a maximal + * value when cast to unsigned. As this is disgusting, it's kept in + * one inline function. + */ + return ((uint64_t) timeout1 < (uint64_t) timeout2) ? timeout1 : timeout2; +} + +/** + * initclocks: + * + * Initialise the clock & timer infrastructure + */ +void init_clocks(void); + +int64_t cpu_get_ticks(void); +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + static inline int64_t get_ticks_per_sec(void) { return 1000000000LL; } +/* + * Low level clock functions + */ + /* real time host monotonic timer */ static inline int64_t get_clock_realtime(void) { @@ -128,9 +691,6 @@ static inline int64_t get_clock(void) } #endif -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); - /* icount */ int64_t cpu_get_icount(void); int64_t cpu_get_clock(void); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index ac9f8d41a3..3205540059 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -4,9 +4,12 @@ /* A load of opaque types so that device init declarations don't have to pull in all the real definitions. */ typedef struct QEMUTimer QEMUTimer; +typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QEMUFile QEMUFile; typedef struct QEMUBH QEMUBH; +typedef struct AioContext AioContext; + struct Monitor; typedef struct Monitor Monitor; typedef struct MigrationParams MigrationParams; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index daf1835c1a..3e4993661a 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -80,7 +80,11 @@ struct TranslationBlock; * @synchronize_from_tb: Callback for synchronizing state from a TCG * #TranslationBlock. * @get_phys_page_debug: Callback for obtaining a physical address. + * @gdb_read_register: Callback for letting GDB read a register. + * @gdb_write_register: Callback for letting GDB write a register. * @vmsd: State description for migration. + * @gdb_num_core_regs: Number of core registers accessible to GDB. + * @gdb_core_xml_file: File name for core registers GDB XML description. * * Represents a CPU family or model. */ @@ -108,8 +112,9 @@ typedef struct CPUClass { void (*set_pc)(CPUState *cpu, vaddr value); void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb); hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr); + int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg); + int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg); - const struct VMStateDescription *vmsd; int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, int cpuid, void *opaque); int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, @@ -118,6 +123,10 @@ typedef struct CPUClass { int cpuid, void *opaque); int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, void *opaque); + + const struct VMStateDescription *vmsd; + int gdb_num_core_regs; + const char *gdb_core_xml_file; } CPUClass; struct KVMState; @@ -142,6 +151,8 @@ struct kvm_run; * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @gdb_regs: Additional GDB registers. + * @gdb_num_regs: Number of total registers accessible to GDB. + * @gdb_num_g_regs: Number of registers in GDB 'g' packets. * @next_cpu: Next CPU sharing TB cache. * @kvm_fd: vCPU file descriptor for KVM. * @@ -177,6 +188,8 @@ struct CPUState { void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; struct GDBRegisterState *gdb_regs; + int gdb_num_regs; + int gdb_num_g_regs; CPUState *next_cpu; int kvm_fd; diff --git a/include/qom/object.h b/include/qom/object.h index 23fc048088..9b69065b7a 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -398,6 +398,8 @@ struct Object * @instance_init: This function is called to initialize an object. The parent * class will have already been initialized so the type is only responsible * for initializing its own members. + * @instance_post_init: This function is called to finish initialization of + * an object, after all @instance_init functions were called. * @instance_finalize: This function is called during object destruction. This * is called before the parent @instance_finalize function has been called. * An object should only free the members that are unique to its type in this @@ -433,6 +435,7 @@ struct TypeInfo size_t instance_size; void (*instance_init)(Object *obj); + void (*instance_post_init)(Object *obj); void (*instance_finalize)(Object *obj); bool abstract; diff --git a/include/sysemu/char.h b/include/sysemu/char.h index e65e4a4844..8053130a97 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -77,6 +77,7 @@ struct CharDriverState { int explicit_fe_open; int explicit_be_open; int avail_connections; + int is_mux; QemuOpts *opts; QTAILQ_ENTRY(CharDriverState) next; }; diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index b8c770f8d9..19fafb2cf9 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -20,7 +20,9 @@ typedef struct ArchDumpInfo { int d_class; /* ELFCLASS32 or ELFCLASS64 */ } ArchDumpInfo; -int cpu_get_dump_info(ArchDumpInfo *info); +struct GuestPhysBlockList; /* memory_mapping.h */ +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks); ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); #endif diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index ce3efaf210..8e7668524b 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -174,7 +174,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, target_ulong len, int type); void kvm_remove_all_breakpoints(CPUState *cpu); -int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap); +int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap); #ifndef _WIN32 int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset); #endif diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 6dfb68ddcd..a75d59a55d 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -17,6 +17,25 @@ #include "qemu/queue.h" #include "qemu/typedefs.h" +typedef struct GuestPhysBlock { + /* visible to guest, reflects PCI hole, etc */ + hwaddr target_start; + + /* implies size */ + hwaddr target_end; + + /* points into host memory */ + uint8_t *host_addr; + + QTAILQ_ENTRY(GuestPhysBlock) next; +} GuestPhysBlock; + +/* point-in-time snapshot of guest-visible physical mappings */ +typedef struct GuestPhysBlockList { + unsigned num; + QTAILQ_HEAD(GuestPhysBlockHead, GuestPhysBlock) head; +} GuestPhysBlockList; + /* The physical and virtual address in the memory mapping are contiguous. */ typedef struct MemoryMapping { hwaddr phys_addr; @@ -45,10 +64,17 @@ void memory_mapping_list_free(MemoryMappingList *list); void memory_mapping_list_init(MemoryMappingList *list); -void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp); +void guest_phys_blocks_free(GuestPhysBlockList *list); +void guest_phys_blocks_init(GuestPhysBlockList *list); +void guest_phys_blocks_append(GuestPhysBlockList *list); + +void qemu_get_guest_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks, + Error **errp); /* get guest's memory mapping without do paging(virtual address is 0). */ -void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list); +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks); void memory_mapping_filter(MemoryMappingList *list, int64_t begin, int64_t length); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 3caeb66eb2..b1aa059102 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -103,7 +103,6 @@ typedef enum { extern int vga_interface_type; #define xenfb_enabled (vga_interface_type == VGA_XENFB) -#define qxl_enabled (vga_interface_type == VGA_QXL) extern int graphic_width; extern int graphic_height; @@ -125,7 +124,7 @@ extern int boot_menu; extern uint8_t *boot_splash_filedata; extern size_t boot_splash_filedata_size; extern uint8_t qemu_extra_params_fw[2]; -extern QEMUClock *rtc_clock; +extern QEMUClockType rtc_clock; #define MAX_NODES 64 #define MAX_CPUMASK_BITS 255 diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index eba6d77d1d..c6c756b23d 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -27,6 +27,7 @@ #include "monitor/monitor.h" extern int using_spice; +extern int spice_displays; void qemu_spice_init(void); void qemu_spice_input_init(void); @@ -57,6 +58,7 @@ static inline CharDriverState *qemu_chr_open_spice_port(const char *name) #include "monitor/monitor.h" #define using_spice 0 +#define spice_displays 0 static inline int qemu_spice_set_passwd(const char *passwd, bool fail_if_connected, bool disconnect_if_connected) @@ -183,6 +183,7 @@ static void portio_write(void *opaque, hwaddr addr, uint64_t data, static const MemoryRegionOps portio_ops = { .read = portio_read, .write = portio_write, + .endianness = DEVICE_LITTLE_ENDIAN, .valid.unaligned = true, .impl.unaligned = true, }; @@ -1875,9 +1875,8 @@ static void kvm_invoke_set_guest_debug(void *data) &dbg_data->dbg); } -int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) +int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) { - CPUState *cpu = ENV_GET_CPU(env); struct kvm_set_guest_debug_data data; data.dbg.control = reinject_trap; @@ -1927,9 +1926,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, } for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - CPUArchState *env = cpu->env_ptr; - - err = kvm_update_guest_debug(env, 0); + err = kvm_update_guest_debug(cpu, 0); if (err) { return err; } @@ -1969,9 +1966,7 @@ int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, } for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - CPUArchState *env = cpu->env_ptr; - - err = kvm_update_guest_debug(env, 0); + err = kvm_update_guest_debug(cpu, 0); if (err) { return err; } @@ -1999,15 +1994,13 @@ void kvm_remove_all_breakpoints(CPUState *cpu) kvm_arch_remove_all_hw_breakpoints(); for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - CPUArchState *env = cpu->env_ptr; - - kvm_update_guest_debug(env, 0); + kvm_update_guest_debug(cpu, 0); } } #else /* !KVM_CAP_SET_GUEST_DEBUG */ -int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) +int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) { return -EINVAL; } diff --git a/kvm-stub.c b/kvm-stub.c index 806b044124..548f471c17 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -78,7 +78,7 @@ void kvm_setup_guest_memory(void *start, size_t size) { } -int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) +int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) { return -ENOSYS; } diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 003d424701..73f29314f6 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -40,3 +40,5 @@ struct target_pt_regs { #else #define UNAME_MACHINE "armv5tel" #endif + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index 50e50b4f3f..832ee64bd8 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -38,4 +38,6 @@ struct target_pt_regs { unsigned long eda; }; +#define TARGET_CLONE_BACKWARDS2 + #endif diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 266e2c4c83..12b8c3b672 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -144,3 +144,5 @@ struct target_vm86plus_struct { }; #define UNAME_MACHINE "i686" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/i386/target_cpu.h b/linux-user/i386/target_cpu.h index abcac79d25..58f86454d6 100644 --- a/linux-user/i386/target_cpu.h +++ b/linux-user/i386/target_cpu.h @@ -28,6 +28,21 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp) env->regs[R_EAX] = 0; } -/* TODO: need to implement cpu_set_tls() */ +#if defined(TARGET_ABI32) +abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr); -#endif +static inline void cpu_set_tls(CPUX86State *env, target_ulong newtls) +{ + do_set_thread_area(env, newtls); + cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector); +} +#else +abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr); + +static inline void cpu_set_tls(CPUX86State *env, target_ulong newtls) +{ + do_arch_prctl(env, TARGET_ARCH_SET_FS, newtls); +} +#endif /* defined(TARGET_ABI32) */ + +#endif /* !defined(TARGET_CPU_H) */ diff --git a/linux-user/m68k/target_cpu.h b/linux-user/m68k/target_cpu.h index 8a2a305a0b..cad9c90dd0 100644 --- a/linux-user/m68k/target_cpu.h +++ b/linux-user/m68k/target_cpu.h @@ -29,6 +29,10 @@ static inline void cpu_clone_regs(CPUM68KState *env, target_ulong newsp) env->dregs[0] = 0; } -/* TODO: need to implement cpu_set_tls() */ +static inline void cpu_set_tls(CPUM68KState *env, target_ulong newtls) +{ + TaskState *ts = env->opaque; + ts->tp_value = newtls; +} #endif diff --git a/linux-user/main.c b/linux-user/main.c index f6a3aad9e5..03859bcc23 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -92,7 +92,6 @@ int cpu_get_pic_interrupt(CPUX86State *env) } #endif -#if defined(CONFIG_USE_NPTL) /***********************************************************/ /* Helper routines for implementing atomic operations. */ @@ -207,43 +206,6 @@ void cpu_list_unlock(void) { pthread_mutex_unlock(&cpu_list_mutex); } -#else /* if !CONFIG_USE_NPTL */ -/* These are no-ops because we are not threadsafe. */ -static inline void cpu_exec_start(CPUState *cpu) -{ -} - -static inline void cpu_exec_end(CPUState *cpu) -{ -} - -static inline void start_exclusive(void) -{ -} - -static inline void end_exclusive(void) -{ -} - -void fork_start(void) -{ -} - -void fork_end(int child) -{ - if (child) { - gdbserver_fork((CPUArchState *)thread_cpu->env_ptr); - } -} - -void cpu_list_lock(void) -{ -} - -void cpu_list_unlock(void) -{ -} -#endif #ifdef TARGET_I386 @@ -1958,7 +1920,7 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_sched_get_priority_min, 1) MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */ MIPS_SYS(sys_nanosleep, 2) - MIPS_SYS(sys_mremap , 4) + MIPS_SYS(sys_mremap , 5) MIPS_SYS(sys_accept , 3) MIPS_SYS(sys_bind , 3) MIPS_SYS(sys_connect , 3) /* 4170 */ @@ -2095,7 +2057,7 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_pselect6, 6) MIPS_SYS(sys_ppoll, 5) MIPS_SYS(sys_unshare, 1) - MIPS_SYS(sys_splice, 4) + MIPS_SYS(sys_splice, 6) MIPS_SYS(sys_sync_file_range, 7) /* 4305 */ MIPS_SYS(sys_tee, 4) MIPS_SYS(sys_vmsplice, 4) @@ -2349,7 +2311,31 @@ done_syscall: abi_ulong trap_instr; unsigned int code; - ret = get_user_ual(trap_instr, env->active_tc.PC); + if (env->hflags & MIPS_HFLAG_M16) { + if (env->insn_flags & ASE_MICROMIPS) { + /* microMIPS mode */ + abi_ulong instr[2]; + + ret = get_user_u16(instr[0], env->active_tc.PC) || + get_user_u16(instr[1], env->active_tc.PC + 2); + + trap_instr = (instr[0] << 16) | instr[1]; + } else { + /* MIPS16e mode */ + ret = get_user_u16(trap_instr, env->active_tc.PC); + if (ret != 0) { + goto error; + } + code = (trap_instr >> 6) & 0x3f; + if (do_break(env, &info, code) != 0) { + goto error; + } + break; + } + } else { + ret = get_user_ual(trap_instr, env->active_tc.PC); + } + if (ret != 0) { goto error; } @@ -2373,14 +2359,30 @@ done_syscall: abi_ulong trap_instr; unsigned int code = 0; - ret = get_user_ual(trap_instr, env->active_tc.PC); + if (env->hflags & MIPS_HFLAG_M16) { + /* microMIPS mode */ + abi_ulong instr[2]; + + ret = get_user_u16(instr[0], env->active_tc.PC) || + get_user_u16(instr[1], env->active_tc.PC + 2); + + trap_instr = (instr[0] << 16) | instr[1]; + } else { + ret = get_user_ual(trap_instr, env->active_tc.PC); + } + if (ret != 0) { goto error; } /* The immediate versions don't provide a code. */ if (!(trap_instr & 0xFC000000)) { - code = ((trap_instr >> 6) & ((1 << 10) - 1)); + if (env->hflags & MIPS_HFLAG_M16) { + /* microMIPS mode */ + code = ((trap_instr >> 12) & ((1 << 4) - 1)); + } else { + code = ((trap_instr >> 6) & ((1 << 10) - 1)); + } } if (do_break(env, &info, code) != 0) { @@ -3157,12 +3159,7 @@ THREAD CPUState *thread_cpu; void task_settid(TaskState *ts) { if (ts->ts_tid == 0) { -#ifdef CONFIG_USE_NPTL ts->ts_tid = (pid_t)syscall(SYS_gettid); -#else - /* when no threads are used, tid becomes pid */ - ts->ts_tid = getpid(); -#endif } } @@ -3640,9 +3637,7 @@ int main(int argc, char **argv, char **envp) exit(1); } cpu = ENV_GET_CPU(env); -#if defined(TARGET_SPARC) || defined(TARGET_PPC) cpu_reset(cpu); -#endif thread_cpu = cpu; diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index c3e5c55b3d..d550989d5e 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -48,4 +48,6 @@ struct target_pt_regs { uint32_t kernel_mode; }; +#define TARGET_CLONE_BACKWARDS + #endif diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 3deb862cc4..9d437d918b 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -225,3 +225,5 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index cd707df32f..1710f766e2 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -222,3 +222,5 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips64" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/mmap.c b/linux-user/mmap.c index de2219768d..a249f0ceb6 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -33,7 +33,6 @@ //#define DEBUG_MMAP -#if defined(CONFIG_USE_NPTL) static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static __thread int mmap_lock_count; @@ -66,16 +65,6 @@ void mmap_fork_end(int child) else pthread_mutex_unlock(&mmap_mutex); } -#else -/* We aren't threadsafe to start with, so no need to worry about locking. */ -void mmap_lock(void) -{ -} - -void mmap_unlock(void) -{ -} -#endif /* NOTE: all the constants are the HOST ones, but addresses are target. */ int target_mprotect(abi_ulong start, abi_ulong len, int prot) diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h index 501fb81162..32a46ac840 100644 --- a/linux-user/openrisc/target_cpu.h +++ b/linux-user/openrisc/target_cpu.h @@ -25,9 +25,14 @@ static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp) if (newsp) { env->gpr[1] = newsp; } - env->gpr[2] = 0; + env->gpr[11] = 0; } -/* TODO: need to implement cpu_set_tls() */ +static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls) +{ + /* Linux kernel 3.10 does not pay any attention to CLONE_SETTLS + * in copy_thread(), so QEMU need not do so either. + */ +} #endif diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index 481047b2dd..ba36acbc33 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -62,3 +62,5 @@ struct target_revectored_struct { #else #define UNAME_MACHINE "ppc" #endif + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 6569608b64..4a16e8fe1d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -16,16 +16,10 @@ #include "exec/user/thunk.h" #include "syscall_defs.h" #include "syscall.h" -#include "target_cpu.h" -#include "target_signal.h" #include "exec/gdbstub.h" #include "qemu/queue.h" -#if defined(CONFIG_USE_NPTL) #define THREAD __thread -#else -#define THREAD -#endif /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain @@ -118,11 +112,10 @@ typedef struct TaskState { uint32_t v86flags; uint32_t v86mask; #endif -#ifdef CONFIG_USE_NPTL abi_ulong child_tidptr; -#endif #ifdef TARGET_M68K int sim_syscalls; + abi_ulong tp_value; #endif #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) /* Extra fields for semihosted binaries. */ @@ -269,10 +262,8 @@ void mmap_unlock(void); abi_ulong mmap_find_vma(abi_ulong, abi_ulong); void cpu_list_lock(void); void cpu_list_unlock(void); -#if defined(CONFIG_USE_NPTL) void mmap_fork_start(void); void mmap_fork_end(int child); -#endif /* main.c */ extern unsigned long guest_stack_size; @@ -450,8 +441,13 @@ static inline void *lock_user_string(abi_ulong guest_addr) #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) -#if defined(CONFIG_USE_NPTL) #include <pthread.h> -#endif + +/* Include target-specific struct and function definitions; + * they may need access to the target-independent structures + * above, so include them last. + */ +#include "target_cpu.h" +#include "target_signal.h" #endif /* QEMU_H */ diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index e4603b79c3..ea8c304840 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -21,3 +21,5 @@ struct target_pt_regs { }; #define UNAME_MACHINE "s390x" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/signal.c b/linux-user/signal.c index a5e8906c4d..23d65dab77 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1552,7 +1552,7 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc) static long do_sigreturn_v1(CPUARMState *env) { abi_ulong frame_addr; - struct sigframe_v1 *frame; + struct sigframe_v1 *frame = NULL; target_sigset_t set; sigset_t host_set; int i; @@ -1562,10 +1562,11 @@ static long do_sigreturn_v1(CPUARMState *env) * then 'sp' should be word aligned here. If it's * not, then the user is trying to mess with us. */ - if (env->regs[13] & 7) - goto badframe; - frame_addr = env->regs[13]; + if (frame_addr & 7) { + goto badframe; + } + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; @@ -1693,17 +1694,18 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, static long do_sigreturn_v2(CPUARMState *env) { abi_ulong frame_addr; - struct sigframe_v2 *frame; + struct sigframe_v2 *frame = NULL; /* * Since we stacked the signal on a 64-bit boundary, * then 'sp' should be word aligned here. If it's * not, then the user is trying to mess with us. */ - if (env->regs[13] & 7) - goto badframe; - frame_addr = env->regs[13]; + if (frame_addr & 7) { + goto badframe; + } + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; @@ -1731,7 +1733,7 @@ long do_sigreturn(CPUARMState *env) static long do_rt_sigreturn_v1(CPUARMState *env) { abi_ulong frame_addr; - struct rt_sigframe_v1 *frame; + struct rt_sigframe_v1 *frame = NULL; sigset_t host_set; /* @@ -1739,10 +1741,11 @@ static long do_rt_sigreturn_v1(CPUARMState *env) * then 'sp' should be word aligned here. If it's * not, then the user is trying to mess with us. */ - if (env->regs[13] & 7) - goto badframe; - frame_addr = env->regs[13]; + if (frame_addr & 7) { + goto badframe; + } + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; @@ -1772,17 +1775,18 @@ badframe: static long do_rt_sigreturn_v2(CPUARMState *env) { abi_ulong frame_addr; - struct rt_sigframe_v2 *frame; + struct rt_sigframe_v2 *frame = NULL; /* * Since we stacked the signal on a 64-bit boundary, * then 'sp' should be word aligned here. If it's * not, then the user is trying to mess with us. */ - if (env->regs[13] & 7) - goto badframe; - frame_addr = env->regs[13]; + if (frame_addr & 7) { + goto badframe; + } + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; @@ -4603,7 +4607,7 @@ long do_sigreturn(CPUPPCState *env) { struct target_sigcontext *sc = NULL; struct target_mcontext *sr = NULL; - target_ulong sr_addr, sc_addr; + target_ulong sr_addr = 0, sc_addr; sigset_t blocked; target_sigset_t set; diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 5a9bb7e546..4cd64bf41d 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -7,3 +7,10 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4" + +/* SPARC kernels don't define this in their Kconfig, but they have the + * same ABI as if they did, implemented by sparc-specific code which fishes + * directly in the u_regs() struct for half the parameters in sparc_do_fork() + * and copy_thread(). + */ +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h index 5a620a2bb7..4944d465a2 100644 --- a/linux-user/sparc/target_cpu.h +++ b/linux-user/sparc/target_cpu.h @@ -25,12 +25,20 @@ static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp) if (newsp) { env->regwptr[22] = newsp; } + /* syscall return for clone child: 0, and clear CF since + * this counts as a success return value. + */ env->regwptr[0] = 0; - /* FIXME: Do we also need to clear CF? */ - /* XXXXX */ - printf("HELPME: %s:%d\n", __FILE__, __LINE__); +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + env->xcc &= ~PSR_CARRY; +#else + env->psr &= ~PSR_CARRY; +#endif } -/* TODO: need to implement cpu_set_tls() */ +static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) +{ + env->gregs[7] = newtls; +} #endif diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index 81a816de94..e60bf311c0 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -8,3 +8,10 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4u" + +/* SPARC kernels don't define this in their Kconfig, but they have the + * same ABI as if they did, implemented by sparc-specific code which fishes + * directly in the u_regs() struct for half the parameters in sparc_do_fork() + * and copy_thread(). + */ +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 00a0390ea9..f986548c2d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -111,13 +111,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include "qemu.h" -#if defined(CONFIG_USE_NPTL) #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) -#else -/* XXX: Hardcode the above values. */ -#define CLONE_NPTL_FLAGS2 0 -#endif //#define DEBUG @@ -234,12 +229,10 @@ _syscall1(int,exit_group,int,error_code) #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) _syscall1(int,set_tid_address,int *,tidptr) #endif -#if defined(CONFIG_USE_NPTL) #if defined(TARGET_NR_futex) && defined(__NR_futex) _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, const struct timespec *,timeout,int *,uaddr2,int,val3) #endif -#endif #define __NR_sys_sched_getaffinity __NR_sched_getaffinity _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len, unsigned long *, user_mask_ptr); @@ -1039,6 +1032,9 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, #elif defined(TARGET_SH4) ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; return host_pipe[0]; +#elif defined(TARGET_SPARC) + ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1]; + return host_pipe[0]; #endif } @@ -4055,7 +4051,7 @@ static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, } #if defined(TARGET_I386) && defined(TARGET_ABI32) -static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) +abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) { uint64_t *gdt_table = g2h(env->gdt.base); struct target_modify_ldt_ldt_s ldt_info; @@ -4189,7 +4185,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) #endif /* TARGET_I386 && TARGET_ABI32 */ #ifndef TARGET_ABI32 -static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) +abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) { abi_long ret = 0; abi_ulong val; @@ -4227,7 +4223,6 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) #define NEW_STACK_SIZE 0x40000 -#if defined(CONFIG_USE_NPTL) static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER; typedef struct { @@ -4272,16 +4267,6 @@ static void *clone_func(void *arg) /* never exits */ return NULL; } -#else - -static int clone_func(void *arg) -{ - CPUArchState *env = arg; - cpu_loop(env); - /* never exits */ - return 0; -} -#endif /* do_fork() Must return host values and target errnos (unlike most do_*() functions). */ @@ -4292,12 +4277,8 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, int ret; TaskState *ts; CPUArchState *new_env; -#if defined(CONFIG_USE_NPTL) unsigned int nptl_flags; sigset_t sigmask; -#else - uint8_t *new_stack; -#endif /* Emulate vfork() with fork() */ if (flags & CLONE_VFORK) @@ -4305,23 +4286,18 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, if (flags & CLONE_VM) { TaskState *parent_ts = (TaskState *)env->opaque; -#if defined(CONFIG_USE_NPTL) new_thread_info info; pthread_attr_t attr; -#endif + ts = g_malloc0(sizeof(TaskState)); init_task_state(ts); /* we create a new CPU instance. */ new_env = cpu_copy(env); -#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) - cpu_reset(ENV_GET_CPU(new_env)); -#endif /* Init regs that differ from the parent. */ cpu_clone_regs(new_env, newsp); new_env->opaque = ts; ts->bprm = parent_ts->bprm; ts->info = parent_ts->info; -#if defined(CONFIG_USE_NPTL) nptl_flags = flags; flags &= ~CLONE_NPTL_FLAGS2; @@ -4371,17 +4347,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_cond_destroy(&info.cond); pthread_mutex_destroy(&info.mutex); pthread_mutex_unlock(&clone_lock); -#else - if (flags & CLONE_NPTL_FLAGS2) - return -EINVAL; - /* This is probably going to die very quickly, but do it anyway. */ - new_stack = g_malloc0 (NEW_STACK_SIZE); -#ifdef __ia64__ - ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env); -#else - ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); -#endif -#endif } else { /* if no CLONE_VM, we consider it is a fork */ if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) @@ -4392,7 +4357,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, /* Child Process. */ cpu_clone_regs(env, newsp); fork_end(1); -#if defined(CONFIG_USE_NPTL) /* There is a race condition here. The parent process could theoretically read the TID in the child process before the child tid is set. This would require using either ptrace @@ -4408,7 +4372,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, cpu_set_tls (env, newtls); if (flags & CLONE_CHILD_CLEARTID) ts->child_tidptr = child_tidptr; -#endif } else { fork_end(0); } @@ -4834,7 +4797,6 @@ static inline abi_long host_to_target_stat64(void *cpu_env, } #endif -#if defined(CONFIG_USE_NPTL) /* ??? Using host futex calls even when target atomic operations are not really atomic probably breaks things. However implementing futexes locally would make futexes shared between multiple processes @@ -4886,7 +4848,6 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, return -TARGET_ENOSYS; } } -#endif /* Map host to target signal numbers for the wait family of syscalls. Assume all other status bits are the same. */ @@ -5132,9 +5093,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) { -#ifdef CONFIG_USE_NPTL CPUState *cpu = ENV_GET_CPU(cpu_env); -#endif abi_long ret; struct stat st; struct statfs stfs; @@ -5148,7 +5107,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, switch(num) { case TARGET_NR_exit: -#ifdef CONFIG_USE_NPTL /* In old applications this may be used to implement _exit(2). However in threaded applictions it is used for thread termination, and _exit_group is used for application termination. @@ -5186,7 +5144,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, g_free(ts); pthread_exit(NULL); } -#endif #ifdef TARGET_GPROF _mcleanup(); #endif @@ -6956,16 +6913,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(fsync(arg1)); break; case TARGET_NR_clone: -#if defined(TARGET_SH4) || defined(TARGET_ALPHA) - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); -#elif defined(TARGET_CRIS) - ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5)); -#elif defined(TARGET_MICROBLAZE) + /* Linux manages to have three different orderings for its + * arguments to clone(); the BACKWARDS and BACKWARDS2 defines + * match the kernel's CONFIG_CLONE_* settings. + * Microblaze is further special in that it uses a sixth + * implicit argument to clone for the TLS pointer. + */ +#if defined(TARGET_MICROBLAZE) ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5)); -#elif defined(TARGET_S390X) +#elif defined(TARGET_CLONE_BACKWARDS) + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); +#elif defined(TARGET_CLONE_BACKWARDS2) ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4)); #else - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); #endif break; #ifdef __NR_exit_group @@ -8558,6 +8519,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #elif defined(TARGET_I386) && defined(TARGET_ABI32) ret = do_set_thread_area(cpu_env, arg1); break; +#elif defined(TARGET_M68K) + { + TaskState *ts = ((CPUArchState *)cpu_env)->opaque; + ts->tp_value = arg1; + ret = 0; + break; + } #else goto unimplemented_nowarn; #endif @@ -8566,6 +8534,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_get_thread_area: #if defined(TARGET_I386) && defined(TARGET_ABI32) ret = do_get_thread_area(cpu_env, arg1); + break; +#elif defined(TARGET_M68K) + { + TaskState *ts = ((CPUArchState *)cpu_env)->opaque; + ret = ts->tp_value; + break; + } #else goto unimplemented_nowarn; #endif @@ -8670,11 +8645,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif -#if defined(CONFIG_USE_NPTL) case TARGET_NR_futex: ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6); break; -#endif #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init) case TARGET_NR_inotify_init: ret = get_errno(sys_inotify_init()); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 92c01a9603..086fbfffe7 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1138,8 +1138,7 @@ struct target_winsize { #endif #if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \ - || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) \ - || defined(TARGET_OPENRISC) + || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) struct target_stat { unsigned short st_dev; unsigned short __pad1; @@ -1837,29 +1836,55 @@ struct target_stat { abi_ulong __unused[3]; }; #elif defined(TARGET_OPENRISC) + +/* These are the asm-generic versions of the stat and stat64 structures */ + struct target_stat { abi_ulong st_dev; abi_ulong st_ino; - abi_ulong st_nlink; - unsigned int st_mode; + unsigned int st_nlink; unsigned int st_uid; unsigned int st_gid; - unsigned int __pad0; abi_ulong st_rdev; + abi_ulong __pad1; abi_long st_size; - abi_long st_blksize; - abi_long st_blocks; /* Number 512-byte blocks allocated. */ - - abi_ulong target_st_atime; + int st_blksize; + int __pad2; + abi_long st_blocks; + abi_long target_st_atime; abi_ulong target_st_atime_nsec; - abi_ulong target_st_mtime; + abi_long target_st_mtime; abi_ulong target_st_mtime_nsec; - abi_ulong target_st_ctime; + abi_long target_st_ctime; abi_ulong target_st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; +}; - abi_long __unused[3]; +struct target_stat64 { + uint64_t st_dev; + uint64_t st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + uint64_t st_rdev; + uint64_t __pad1; + int64_t st_size; + int st_blksize; + int __pad2; + int64_t st_blocks; + int target_st_atime; + unsigned int target_st_atime_nsec; + int target_st_mtime; + unsigned int target_st_mtime_nsec; + int target_st_ctime; + unsigned int target_st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; }; + #else #error unsupported CPU #endif @@ -2434,8 +2459,11 @@ typedef union target_epoll_data { struct target_epoll_event { uint32_t events; +#ifdef TARGET_ARM + uint32_t __pad; +#endif target_epoll_data_t data; -}; +} QEMU_PACKED; #endif struct target_rlimit64 { uint64_t rlim_cur; diff --git a/main-loop.c b/main-loop.c index a44fff6e9a..1c38ea2b93 100644 --- a/main-loop.c +++ b/main-loop.c @@ -131,10 +131,6 @@ int qemu_init_main_loop(void) GSource *src; init_clocks(); - if (init_timer_alarm() < 0) { - fprintf(stderr, "could not initialize alarm timer\n"); - exit(1); - } ret = qemu_signal_init(); if (ret) { @@ -155,10 +151,11 @@ static int max_priority; static int glib_pollfds_idx; static int glib_n_poll_fds; -static void glib_pollfds_fill(uint32_t *cur_timeout) +static void glib_pollfds_fill(int64_t *cur_timeout) { GMainContext *context = g_main_context_default(); int timeout = 0; + int64_t timeout_ns; int n; g_main_context_prepare(context, &max_priority); @@ -174,9 +171,13 @@ static void glib_pollfds_fill(uint32_t *cur_timeout) glib_n_poll_fds); } while (n != glib_n_poll_fds); - if (timeout >= 0 && timeout < *cur_timeout) { - *cur_timeout = timeout; + if (timeout < 0) { + timeout_ns = -1; + } else { + timeout_ns = (int64_t)timeout * (int64_t)SCALE_MS; } + + *cur_timeout = qemu_soonest_timeout(timeout_ns, *cur_timeout); } static void glib_pollfds_poll(void) @@ -191,7 +192,7 @@ static void glib_pollfds_poll(void) #define MAX_MAIN_LOOP_SPIN (1000) -static int os_host_main_loop_wait(uint32_t timeout) +static int os_host_main_loop_wait(int64_t timeout) { int ret; static int spin_counter; @@ -204,7 +205,7 @@ static int os_host_main_loop_wait(uint32_t timeout) * print a message to the screen. If we run into this condition, create * a fake timeout in order to give the VCPU threads a chance to run. */ - if (spin_counter > MAX_MAIN_LOOP_SPIN) { + if (!timeout && (spin_counter > MAX_MAIN_LOOP_SPIN)) { static bool notified; if (!notified) { @@ -214,19 +215,19 @@ static int os_host_main_loop_wait(uint32_t timeout) notified = true; } - timeout = 1; + timeout = SCALE_MS; } - if (timeout > 0) { + if (timeout) { spin_counter = 0; qemu_mutex_unlock_iothread(); } else { spin_counter++; } - ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout); + ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout); - if (timeout > 0) { + if (timeout) { qemu_mutex_lock_iothread(); } @@ -373,7 +374,7 @@ static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds, } } -static int os_host_main_loop_wait(uint32_t timeout) +static int os_host_main_loop_wait(int64_t timeout) { GMainContext *context = g_main_context_default(); GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ @@ -382,6 +383,7 @@ static int os_host_main_loop_wait(uint32_t timeout) PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; + int64_t poll_timeout_ns; static struct timeval tv0; fd_set rfds, wfds, xfds; int nfds; @@ -419,12 +421,17 @@ static int os_host_main_loop_wait(uint32_t timeout) poll_fds[n_poll_fds + i].events = G_IO_IN; } - if (poll_timeout < 0 || timeout < poll_timeout) { - poll_timeout = timeout; + if (poll_timeout < 0) { + poll_timeout_ns = -1; + } else { + poll_timeout_ns = (int64_t)poll_timeout * (int64_t)SCALE_MS; } + poll_timeout_ns = qemu_soonest_timeout(poll_timeout_ns, timeout); + qemu_mutex_unlock_iothread(); - g_poll_ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); + g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns); + qemu_mutex_lock_iothread(); if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { @@ -449,6 +456,7 @@ int main_loop_wait(int nonblocking) { int ret; uint32_t timeout = UINT32_MAX; + int64_t timeout_ns; if (nonblocking) { timeout = 0; @@ -462,13 +470,24 @@ int main_loop_wait(int nonblocking) slirp_pollfds_fill(gpollfds); #endif qemu_iohandler_fill(gpollfds); - ret = os_host_main_loop_wait(timeout); + + if (timeout == UINT32_MAX) { + timeout_ns = -1; + } else { + timeout_ns = (uint64_t)timeout * (int64_t)(SCALE_MS); + } + + timeout_ns = qemu_soonest_timeout(timeout_ns, + timerlistgroup_deadline_ns( + &main_loop_tlg)); + + ret = os_host_main_loop_wait(timeout_ns); qemu_iohandler_poll(gpollfds, ret); #ifdef CONFIG_SLIRP slirp_pollfds_poll(gpollfds, (ret < 0)); #endif - qemu_run_all_timers(); + qemu_clock_run_all_timers(); return ret; } @@ -489,17 +508,14 @@ bool qemu_aio_wait(void) void qemu_aio_set_fd_handler(int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque) { - aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush, - opaque); + aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, opaque); } #endif void qemu_aio_set_event_notifier(EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush) + EventNotifierHandler *io_read) { - aio_set_event_notifier(qemu_aio_context, notifier, io_read, io_flush); + aio_set_event_notifier(qemu_aio_context, notifier, io_read); } @@ -18,7 +18,7 @@ #include "exec/ioport.h" #include "qemu/bitops.h" #include "qom/object.h" -#include "sysemu/kvm.h" +#include "trace.h" #include <assert.h> #include "exec/memory-internal.h" @@ -339,65 +339,104 @@ static void flatview_simplify(FlatView *view) } } -static void memory_region_oldmmio_read_accessor(void *opaque, +static bool memory_region_big_endian(MemoryRegion *mr) +{ +#ifdef TARGET_WORDS_BIGENDIAN + return mr->ops->endianness != DEVICE_LITTLE_ENDIAN; +#else + return mr->ops->endianness == DEVICE_BIG_ENDIAN; +#endif +} + +static bool memory_region_wrong_endianness(MemoryRegion *mr) +{ +#ifdef TARGET_WORDS_BIGENDIAN + return mr->ops->endianness == DEVICE_LITTLE_ENDIAN; +#else + return mr->ops->endianness == DEVICE_BIG_ENDIAN; +#endif +} + +static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size) +{ + if (memory_region_wrong_endianness(mr)) { + switch (size) { + case 1: + break; + case 2: + *data = bswap16(*data); + break; + case 4: + *data = bswap32(*data); + break; + case 8: + *data = bswap64(*data); + break; + default: + abort(); + } + } +} + +static void memory_region_oldmmio_read_accessor(MemoryRegion *mr, hwaddr addr, uint64_t *value, unsigned size, unsigned shift, uint64_t mask) { - MemoryRegion *mr = opaque; uint64_t tmp; tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr); + trace_memory_region_ops_read(mr, addr, tmp, size); *value |= (tmp & mask) << shift; } -static void memory_region_read_accessor(void *opaque, +static void memory_region_read_accessor(MemoryRegion *mr, hwaddr addr, uint64_t *value, unsigned size, unsigned shift, uint64_t mask) { - MemoryRegion *mr = opaque; uint64_t tmp; if (mr->flush_coalesced_mmio) { qemu_flush_coalesced_mmio_buffer(); } tmp = mr->ops->read(mr->opaque, addr, size); + trace_memory_region_ops_read(mr, addr, tmp, size); *value |= (tmp & mask) << shift; } -static void memory_region_oldmmio_write_accessor(void *opaque, +static void memory_region_oldmmio_write_accessor(MemoryRegion *mr, hwaddr addr, uint64_t *value, unsigned size, unsigned shift, uint64_t mask) { - MemoryRegion *mr = opaque; uint64_t tmp; tmp = (*value >> shift) & mask; + trace_memory_region_ops_write(mr, addr, tmp, size); mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp); } -static void memory_region_write_accessor(void *opaque, +static void memory_region_write_accessor(MemoryRegion *mr, hwaddr addr, uint64_t *value, unsigned size, unsigned shift, uint64_t mask) { - MemoryRegion *mr = opaque; uint64_t tmp; if (mr->flush_coalesced_mmio) { qemu_flush_coalesced_mmio_buffer(); } tmp = (*value >> shift) & mask; + trace_memory_region_ops_write(mr, addr, tmp, size); mr->ops->write(mr->opaque, addr, tmp, size); } @@ -406,13 +445,13 @@ static void access_with_adjusted_size(hwaddr addr, unsigned size, unsigned access_size_min, unsigned access_size_max, - void (*access)(void *opaque, + void (*access)(MemoryRegion *mr, hwaddr addr, uint64_t *value, unsigned size, unsigned shift, uint64_t mask), - void *opaque) + MemoryRegion *mr) { uint64_t access_mask; unsigned access_size; @@ -428,13 +467,15 @@ static void access_with_adjusted_size(hwaddr addr, /* FIXME: support unaligned access? */ access_size = MAX(MIN(size, access_size_max), access_size_min); access_mask = -1ULL >> (64 - access_size * 8); - for (i = 0; i < size; i += access_size) { -#ifdef TARGET_WORDS_BIGENDIAN - access(opaque, addr + i, value, access_size, - (size - access_size - i) * 8, access_mask); -#else - access(opaque, addr + i, value, access_size, i * 8, access_mask); -#endif + if (memory_region_big_endian(mr)) { + for (i = 0; i < size; i += access_size) { + access(mr, addr + i, value, access_size, + (size - access_size - i) * 8, access_mask); + } + } else { + for (i = 0; i < size; i += access_size) { + access(mr, addr + i, value, access_size, i * 8, access_mask); + } } } @@ -786,15 +827,6 @@ static void memory_region_destructor_rom_device(MemoryRegion *mr) qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK); } -static bool memory_region_wrong_endianness(MemoryRegion *mr) -{ -#ifdef TARGET_WORDS_BIGENDIAN - return mr->ops->endianness == DEVICE_LITTLE_ENDIAN; -#else - return mr->ops->endianness == DEVICE_BIG_ENDIAN; -#endif -} - void memory_region_init(MemoryRegion *mr, Object *owner, const char *name, @@ -921,27 +953,6 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr, return data; } -static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size) -{ - if (memory_region_wrong_endianness(mr)) { - switch (size) { - case 1: - break; - case 2: - *data = bswap16(*data); - break; - case 4: - *data = bswap32(*data); - break; - case 8: - *data = bswap64(*data); - break; - default: - abort(); - } - } -} - static bool memory_region_dispatch_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, diff --git a/memory_mapping.c b/memory_mapping.c index 515a984e0d..eeeeb44026 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -11,9 +11,15 @@ * */ +#include <glib.h> + #include "cpu.h" #include "exec/cpu-all.h" #include "sysemu/memory_mapping.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" + +//#define DEBUG_GUEST_PHYS_REGION_ADD static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list, MemoryMapping *mapping) @@ -165,6 +171,101 @@ void memory_mapping_list_init(MemoryMappingList *list) QTAILQ_INIT(&list->head); } +void guest_phys_blocks_free(GuestPhysBlockList *list) +{ + GuestPhysBlock *p, *q; + + QTAILQ_FOREACH_SAFE(p, &list->head, next, q) { + QTAILQ_REMOVE(&list->head, p, next); + g_free(p); + } + list->num = 0; +} + +void guest_phys_blocks_init(GuestPhysBlockList *list) +{ + list->num = 0; + QTAILQ_INIT(&list->head); +} + +typedef struct GuestPhysListener { + GuestPhysBlockList *list; + MemoryListener listener; +} GuestPhysListener; + +static void guest_phys_blocks_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + GuestPhysListener *g; + uint64_t section_size; + hwaddr target_start, target_end; + uint8_t *host_addr; + GuestPhysBlock *predecessor; + + /* we only care about RAM */ + if (!memory_region_is_ram(section->mr)) { + return; + } + + g = container_of(listener, GuestPhysListener, listener); + section_size = int128_get64(section->size); + target_start = section->offset_within_address_space; + target_end = target_start + section_size; + host_addr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region; + predecessor = NULL; + + /* find continuity in guest physical address space */ + if (!QTAILQ_EMPTY(&g->list->head)) { + hwaddr predecessor_size; + + predecessor = QTAILQ_LAST(&g->list->head, GuestPhysBlockHead); + predecessor_size = predecessor->target_end - predecessor->target_start; + + /* the memory API guarantees monotonically increasing traversal */ + g_assert(predecessor->target_end <= target_start); + + /* we want continuity in both guest-physical and host-virtual memory */ + if (predecessor->target_end < target_start || + predecessor->host_addr + predecessor_size != host_addr) { + predecessor = NULL; + } + } + + if (predecessor == NULL) { + /* isolated mapping, allocate it and add it to the list */ + GuestPhysBlock *block = g_malloc0(sizeof *block); + + block->target_start = target_start; + block->target_end = target_end; + block->host_addr = host_addr; + + QTAILQ_INSERT_TAIL(&g->list->head, block, next); + ++g->list->num; + } else { + /* expand predecessor until @target_end; predecessor's start doesn't + * change + */ + predecessor->target_end = target_end; + } + +#ifdef DEBUG_GUEST_PHYS_REGION_ADD + fprintf(stderr, "%s: target_start=" TARGET_FMT_plx " target_end=" + TARGET_FMT_plx ": %s (count: %u)\n", __FUNCTION__, target_start, + target_end, predecessor ? "joined" : "added", g->list->num); +#endif +} + +void guest_phys_blocks_append(GuestPhysBlockList *list) +{ + GuestPhysListener g = { 0 }; + + g.list = list; + g.listener.region_add = &guest_phys_blocks_region_add; + memory_listener_register(&g.listener, &address_space_memory); + memory_listener_unregister(&g.listener); +} + static CPUState *find_paging_enabled_cpu(CPUState *start_cpu) { CPUState *cpu; @@ -178,10 +279,12 @@ static CPUState *find_paging_enabled_cpu(CPUState *start_cpu) return NULL; } -void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp) +void qemu_get_guest_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks, + Error **errp) { CPUState *cpu, *first_paging_enabled_cpu; - RAMBlock *block; + GuestPhysBlock *block; ram_addr_t offset, length; first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu); @@ -201,19 +304,21 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp) * If the guest doesn't use paging, the virtual address is equal to physical * address. */ - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - offset = block->offset; - length = block->length; + QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { + offset = block->target_start; + length = block->target_end - block->target_start; create_new_memory_mapping(list, offset, offset, length); } } -void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list) +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks) { - RAMBlock *block; + GuestPhysBlock *block; - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - create_new_memory_mapping(list, block->offset, 0, block->length); + QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { + create_new_memory_mapping(list, block->target_start, 0, + block->target_end - block->target_start); } } diff --git a/migration-exec.c b/migration-exec.c index deab4e378e..479024752f 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -17,6 +17,7 @@ #include "qemu-common.h" #include "qemu/sockets.h" +#include "qemu/main-loop.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "block/block.h" diff --git a/migration-fd.c b/migration-fd.c index 3d4613cbaf..d2e523af74 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -14,6 +14,7 @@ */ #include "qemu-common.h" +#include "qemu/main-loop.h" #include "qemu/sockets.h" #include "migration/migration.h" #include "monitor/monitor.h" diff --git a/migration-rdma.c b/migration-rdma.c index d044830ed8..3d1266f40a 100644 --- a/migration-rdma.c +++ b/migration-rdma.c @@ -27,7 +27,7 @@ #include <string.h> #include <rdma/rdma_cma.h> -#define DEBUG_RDMA +//#define DEBUG_RDMA //#define DEBUG_RDMA_VERBOSE //#define DEBUG_RDMA_REALLY_VERBOSE @@ -60,7 +60,7 @@ */ #define ERROR(errp, fmt, ...) \ do { \ - fprintf(stderr, "RDMA ERROR: " fmt, ## __VA_ARGS__); \ + fprintf(stderr, "RDMA ERROR: " fmt "\n", ## __VA_ARGS__); \ if (errp && (*(errp) == NULL)) { \ error_setg(errp, "RDMA ERROR: " fmt, ## __VA_ARGS__); \ } \ @@ -322,7 +322,7 @@ typedef struct RDMAContext { char *host; int port; - RDMAWorkRequestData wr_data[RDMA_WRID_MAX + 1]; + RDMAWorkRequestData wr_data[RDMA_WRID_MAX]; /* * This is used by *_exchange_send() to figure out whether or not @@ -707,15 +707,27 @@ static int __qemu_rdma_delete_block(RDMAContext *rdma, ram_addr_t block_offset) */ static void qemu_rdma_dump_id(const char *who, struct ibv_context *verbs) { + struct ibv_port_attr port; + + if (ibv_query_port(verbs, 1, &port)) { + fprintf(stderr, "FAILED TO QUERY PORT INFORMATION!\n"); + return; + } + printf("%s RDMA Device opened: kernel name %s " "uverbs device name %s, " - "infiniband_verbs class device path %s," - " infiniband class device path %s\n", + "infiniband_verbs class device path %s, " + "infiniband class device path %s, " + "transport: (%d) %s\n", who, verbs->device->name, verbs->device->dev_name, verbs->device->dev_path, - verbs->device->ibdev_path); + verbs->device->ibdev_path, + port.link_layer, + (port.link_layer == IBV_LINK_LAYER_INFINIBAND) ? "Infiniband" : + ((port.link_layer == IBV_LINK_LAYER_ETHERNET) + ? "Ethernet" : "Unknown")); } /* @@ -733,6 +745,132 @@ static void qemu_rdma_dump_gid(const char *who, struct rdma_cm_id *id) } /* + * As of now, IPv6 over RoCE / iWARP is not supported by linux. + * We will try the next addrinfo struct, and fail if there are + * no other valid addresses to bind against. + * + * If user is listening on '[::]', then we will not have a opened a device + * yet and have no way of verifying if the device is RoCE or not. + * + * In this case, the source VM will throw an error for ALL types of + * connections (both IPv4 and IPv6) if the destination machine does not have + * a regular infiniband network available for use. + * + * The only way to gaurantee that an error is thrown for broken kernels is + * for the management software to choose a *specific* interface at bind time + * and validate what time of hardware it is. + * + * Unfortunately, this puts the user in a fix: + * + * If the source VM connects with an IPv4 address without knowing that the + * destination has bound to '[::]' the migration will unconditionally fail + * unless the management software is explicitly listening on the the IPv4 + * address while using a RoCE-based device. + * + * If the source VM connects with an IPv6 address, then we're OK because we can + * throw an error on the source (and similarly on the destination). + * + * But in mixed environments, this will be broken for a while until it is fixed + * inside linux. + * + * We do provide a *tiny* bit of help in this function: We can list all of the + * devices in the system and check to see if all the devices are RoCE or + * Infiniband. + * + * If we detect that we have a *pure* RoCE environment, then we can safely + * thrown an error even if the management sofware has specified '[::]' as the + * bind address. + * + * However, if there is are multiple hetergeneous devices, then we cannot make + * this assumption and the user just has to be sure they know what they are + * doing. + * + * Patches are being reviewed on linux-rdma. + */ +static int qemu_rdma_broken_ipv6_kernel(Error **errp, struct ibv_context *verbs) +{ + struct ibv_port_attr port_attr; + + /* This bug only exists in linux, to our knowledge. */ +#ifdef CONFIG_LINUX + + /* + * Verbs are only NULL if management has bound to '[::]'. + * + * Let's iterate through all the devices and see if there any pure IB + * devices (non-ethernet). + * + * If not, then we can safely proceed with the migration. + * Otherwise, there are no gaurantees until the bug is fixed in linux. + */ + if (!verbs) { + int num_devices, x; + struct ibv_device ** dev_list = ibv_get_device_list(&num_devices); + bool roce_found = false; + bool ib_found = false; + + for (x = 0; x < num_devices; x++) { + verbs = ibv_open_device(dev_list[x]); + + if (ibv_query_port(verbs, 1, &port_attr)) { + ibv_close_device(verbs); + ERROR(errp, "Could not query initial IB port"); + return -EINVAL; + } + + if (port_attr.link_layer == IBV_LINK_LAYER_INFINIBAND) { + ib_found = true; + } else if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { + roce_found = true; + } + + ibv_close_device(verbs); + + } + + if (roce_found) { + if (ib_found) { + fprintf(stderr, "WARN: migrations may fail:" + " IPv6 over RoCE / iWARP in linux" + " is broken. But since you appear to have a" + " mixed RoCE / IB environment, be sure to only" + " migrate over the IB fabric until the kernel " + " fixes the bug.\n"); + } else { + ERROR(errp, "You only have RoCE / iWARP devices in your systems" + " and your management software has specified '[::]'" + ", but IPv6 over RoCE / iWARP is not supported in Linux."); + return -ENONET; + } + } + + return 0; + } + + /* + * If we have a verbs context, that means that some other than '[::]' was + * used by the management software for binding. In which case we can actually + * warn the user about a potential broken kernel; + */ + + /* IB ports start with 1, not 0 */ + if (ibv_query_port(verbs, 1, &port_attr)) { + ERROR(errp, "Could not query initial IB port"); + return -EINVAL; + } + + if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { + ERROR(errp, "Linux kernel's RoCE / iWARP does not support IPv6 " + "(but patches on linux-rdma in progress)"); + return -ENONET; + } + +#endif + + return 0; +} + +/* * Figure out which RDMA device corresponds to the requested IP hostname * Also create the initial connection manager identifiers for opening * the connection. @@ -740,63 +878,73 @@ static void qemu_rdma_dump_gid(const char *who, struct rdma_cm_id *id) static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) { int ret; - struct addrinfo *res; + struct rdma_addrinfo *res; char port_str[16]; struct rdma_cm_event *cm_event; char ip[40] = "unknown"; + struct rdma_addrinfo *e; if (rdma->host == NULL || !strcmp(rdma->host, "")) { - ERROR(errp, "RDMA hostname has not been set\n"); - return -1; + ERROR(errp, "RDMA hostname has not been set"); + return -EINVAL; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { - ERROR(errp, "could not create CM channel\n"); - return -1; + ERROR(errp, "could not create CM channel"); + return -EINVAL; } /* create CM id */ ret = rdma_create_id(rdma->channel, &rdma->cm_id, NULL, RDMA_PS_TCP); if (ret) { - ERROR(errp, "could not create channel id\n"); + ERROR(errp, "could not create channel id"); goto err_resolve_create_id; } snprintf(port_str, 16, "%d", rdma->port); port_str[15] = '\0'; - ret = getaddrinfo(rdma->host, port_str, NULL, &res); + ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); if (ret < 0) { - ERROR(errp, "could not getaddrinfo address %s\n", rdma->host); + ERROR(errp, "could not rdma_getaddrinfo address %s", rdma->host); goto err_resolve_get_addr; } - inet_ntop(AF_INET, &((struct sockaddr_in *) res->ai_addr)->sin_addr, - ip, sizeof ip); - DPRINTF("%s => %s\n", rdma->host, ip); + for (e = res; e != NULL; e = e->ai_next) { + inet_ntop(e->ai_family, + &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); + DPRINTF("Trying %s => %s\n", rdma->host, ip); - /* resolve the first address */ - ret = rdma_resolve_addr(rdma->cm_id, NULL, res->ai_addr, - RDMA_RESOLVE_TIMEOUT_MS); - if (ret) { - ERROR(errp, "could not resolve address %s\n", rdma->host); - goto err_resolve_get_addr; + ret = rdma_resolve_addr(rdma->cm_id, NULL, e->ai_dst_addr, + RDMA_RESOLVE_TIMEOUT_MS); + if (!ret) { + ret = qemu_rdma_broken_ipv6_kernel(errp, rdma->cm_id->verbs); + if (ret) { + continue; + } + goto route; + } } + ERROR(errp, "could not resolve address %s", rdma->host); + goto err_resolve_get_addr; + +route: qemu_rdma_dump_gid("source_resolve_addr", rdma->cm_id); ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret) { - ERROR(errp, "could not perform event_addr_resolved\n"); + ERROR(errp, "could not perform event_addr_resolved"); goto err_resolve_get_addr; } if (cm_event->event != RDMA_CM_EVENT_ADDR_RESOLVED) { - ERROR(errp, "result not equal to event_addr_resolved %s\n", + ERROR(errp, "result not equal to event_addr_resolved %s", rdma_event_str(cm_event->event)); perror("rdma_resolve_addr"); + ret = -EINVAL; goto err_resolve_get_addr; } rdma_ack_cm_event(cm_event); @@ -804,19 +952,20 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) /* resolve route */ ret = rdma_resolve_route(rdma->cm_id, RDMA_RESOLVE_TIMEOUT_MS); if (ret) { - ERROR(errp, "could not resolve rdma route\n"); + ERROR(errp, "could not resolve rdma route"); goto err_resolve_get_addr; } ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret) { - ERROR(errp, "could not perform event_route_resolved\n"); + ERROR(errp, "could not perform event_route_resolved"); goto err_resolve_get_addr; } if (cm_event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) { - ERROR(errp, "result not equal to event_route_resolved: %s\n", + ERROR(errp, "result not equal to event_route_resolved: %s", rdma_event_str(cm_event->event)); rdma_ack_cm_event(cm_event); + ret = -EINVAL; goto err_resolve_get_addr; } rdma_ack_cm_event(cm_event); @@ -831,8 +980,7 @@ err_resolve_get_addr: err_resolve_create_id: rdma_destroy_event_channel(rdma->channel); rdma->channel = NULL; - - return -1; + return ret; } /* @@ -1212,7 +1360,8 @@ static void qemu_rdma_signal_unregister(RDMAContext *rdma, uint64_t index, * (of any kind) has completed. * Return the work request ID that completed. */ -static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out) +static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out, + uint32_t *byte_len) { int ret; struct ibv_wc wc; @@ -1283,6 +1432,9 @@ static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out) } *wr_id_out = wc.wr_id; + if (byte_len) { + *byte_len = wc.byte_len; + } return 0; } @@ -1300,7 +1452,8 @@ static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out) * completions only need to be recorded, but do not actually * need further processing. */ -static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested) +static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, + uint32_t *byte_len) { int num_cq_events = 0, ret = 0; struct ibv_cq *cq; @@ -1312,7 +1465,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested) } /* poll cq first */ while (wr_id != wrid_requested) { - ret = qemu_rdma_poll(rdma, &wr_id_in); + ret = qemu_rdma_poll(rdma, &wr_id_in, byte_len); if (ret < 0) { return ret; } @@ -1354,7 +1507,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested) } while (wr_id != wrid_requested) { - ret = qemu_rdma_poll(rdma, &wr_id_in); + ret = qemu_rdma_poll(rdma, &wr_id_in, byte_len); if (ret < 0) { goto err_block_for_wrid; } @@ -1397,7 +1550,7 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, RDMAControlHeader *head) { int ret = 0; - RDMAWorkRequestData *wr = &rdma->wr_data[RDMA_WRID_MAX]; + RDMAWorkRequestData *wr = &rdma->wr_data[RDMA_WRID_CONTROL]; struct ibv_send_wr *bad_wr; struct ibv_sge sge = { .addr = (uint64_t)(wr->control), @@ -1422,6 +1575,7 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, * The copy makes the RDMAControlHeader simpler to manipulate * for the time being. */ + assert(head->len <= RDMA_CONTROL_MAX_BUFFER - sizeof(*head)); memcpy(wr->control, head, sizeof(RDMAControlHeader)); control_to_network((void *) wr->control); @@ -1439,7 +1593,7 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, return ret; } - ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL); + ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL, NULL); if (ret < 0) { fprintf(stderr, "rdma migration: send polling control error!\n"); } @@ -1480,7 +1634,9 @@ static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx) static int qemu_rdma_exchange_get_response(RDMAContext *rdma, RDMAControlHeader *head, int expecting, int idx) { - int ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RECV_CONTROL + idx); + uint32_t byte_len; + int ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RECV_CONTROL + idx, + &byte_len); if (ret < 0) { fprintf(stderr, "rdma migration: recv polling control error!\n"); @@ -1502,6 +1658,15 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, control_desc[head->type], head->type, head->len); return -EIO; } + if (head->len > RDMA_CONTROL_MAX_BUFFER - sizeof(*head)) { + fprintf(stderr, "too long length: %d\n", head->len); + return -EINVAL; + } + if (sizeof(*head) + head->len != byte_len) { + fprintf(stderr, "Malformed length: %d byte_len %d\n", + head->len, byte_len); + return -EINVAL; + } return 0; } @@ -1731,7 +1896,7 @@ retry: count++, current_index, chunk, sge.addr, length, rdma->nb_sent, block->nb_chunks); - ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE); + ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { fprintf(stderr, "Failed to Wait for previous write to complete " @@ -1875,7 +2040,7 @@ retry: if (ret == ENOMEM) { DDPRINTF("send queue is full. wait a little....\n"); - ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE); + ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { fprintf(stderr, "rdma migration: failed to make " "room in full send queue! %d\n", ret); @@ -1931,10 +2096,21 @@ static int qemu_rdma_write_flush(QEMUFile *f, RDMAContext *rdma) static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, uint64_t offset, uint64_t len) { - RDMALocalBlock *block = - &(rdma->local_ram_blocks.block[rdma->current_index]); - uint8_t *host_addr = block->local_host_addr + (offset - block->offset); - uint8_t *chunk_end = ram_chunk_end(block, rdma->current_chunk); + RDMALocalBlock *block; + uint8_t *host_addr; + uint8_t *chunk_end; + + if (rdma->current_index < 0) { + return 0; + } + + if (rdma->current_chunk < 0) { + return 0; + } + + block = &(rdma->local_ram_blocks.block[rdma->current_index]); + host_addr = block->local_host_addr + (offset - block->offset); + chunk_end = ram_chunk_end(block, rdma->current_chunk); if (rdma->current_length == 0) { return 0; @@ -1947,10 +2123,6 @@ static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, return 0; } - if (rdma->current_index < 0) { - return 0; - } - if (offset < block->offset) { return 0; } @@ -1959,10 +2131,6 @@ static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, return 0; } - if (rdma->current_chunk < 0) { - return 0; - } - if ((host_addr + len) > chunk_end) { return 0; } @@ -2049,7 +2217,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) g_free(rdma->block); rdma->block = NULL; - for (idx = 0; idx <= RDMA_WRID_MAX; idx++) { + for (idx = 0; idx < RDMA_WRID_MAX; idx++) { if (rdma->wr_data[idx].control_mr) { rdma->total_registrations--; ibv_dereg_mr(rdma->wr_data[idx].control_mr); @@ -2092,6 +2260,8 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) rdma_destroy_event_channel(rdma->channel); rdma->channel = NULL; } + g_free(rdma->host); + rdma->host = NULL; } @@ -2115,26 +2285,26 @@ static int qemu_rdma_source_init(RDMAContext *rdma, Error **errp, bool pin_all) if (ret) { ERROR(temp, "rdma migration: error allocating pd and cq! Your mlock()" " limits may be too low. Please check $ ulimit -a # and " - "search for 'ulimit -l' in the output\n"); + "search for 'ulimit -l' in the output"); goto err_rdma_source_init; } ret = qemu_rdma_alloc_qp(rdma); if (ret) { - ERROR(temp, "rdma migration: error allocating qp!\n"); + ERROR(temp, "rdma migration: error allocating qp!"); goto err_rdma_source_init; } ret = qemu_rdma_init_ram_blocks(rdma); if (ret) { - ERROR(temp, "rdma migration: error initializing ram blocks!\n"); + ERROR(temp, "rdma migration: error initializing ram blocks!"); goto err_rdma_source_init; } - for (idx = 0; idx <= RDMA_WRID_MAX; idx++) { + for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); if (ret) { - ERROR(temp, "rdma migration: error registering %d control!\n", + ERROR(temp, "rdma migration: error registering %d control!", idx); goto err_rdma_source_init; } @@ -2176,7 +2346,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp) ret = rdma_connect(rdma->cm_id, &conn_param); if (ret) { perror("rdma_connect"); - ERROR(errp, "connecting to destination!\n"); + ERROR(errp, "connecting to destination!"); rdma_destroy_id(rdma->cm_id); rdma->cm_id = NULL; goto err_rdma_source_connect; @@ -2185,7 +2355,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp) ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret) { perror("rdma_get_cm_event after rdma_connect"); - ERROR(errp, "connecting to destination!\n"); + ERROR(errp, "connecting to destination!"); rdma_ack_cm_event(cm_event); rdma_destroy_id(rdma->cm_id); rdma->cm_id = NULL; @@ -2194,7 +2364,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp) if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) { perror("rdma_get_cm_event != EVENT_ESTABLISHED after rdma_connect"); - ERROR(errp, "connecting to destination!\n"); + ERROR(errp, "connecting to destination!"); rdma_ack_cm_event(cm_event); rdma_destroy_id(rdma->cm_id); rdma->cm_id = NULL; @@ -2210,7 +2380,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp) */ if (rdma->pin_all && !(cap.flags & RDMA_CAPABILITY_PIN_ALL)) { ERROR(errp, "Server cannot support pinning all memory. " - "Will register memory dynamically.\n"); + "Will register memory dynamically."); rdma->pin_all = false; } @@ -2218,9 +2388,9 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp) rdma_ack_cm_event(cm_event); - ret = qemu_rdma_post_recv_control(rdma, 0); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret) { - ERROR(errp, "posting second control recv!\n"); + ERROR(errp, "posting second control recv!"); goto err_rdma_source_connect; } @@ -2236,24 +2406,25 @@ err_rdma_source_connect: static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) { int ret = -EINVAL, idx; - struct sockaddr_in sin; struct rdma_cm_id *listen_id; char ip[40] = "unknown"; + struct rdma_addrinfo *res; + char port_str[16]; - for (idx = 0; idx <= RDMA_WRID_MAX; idx++) { + for (idx = 0; idx < RDMA_WRID_MAX; idx++) { rdma->wr_data[idx].control_len = 0; rdma->wr_data[idx].control_curr = NULL; } if (rdma->host == NULL) { - ERROR(errp, "RDMA host is not set!\n"); + ERROR(errp, "RDMA host is not set!"); rdma->error_state = -EINVAL; return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { - ERROR(errp, "could not create rdma event channel\n"); + ERROR(errp, "could not create rdma event channel"); rdma->error_state = -EINVAL; return -1; } @@ -2261,36 +2432,47 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) /* create CM id */ ret = rdma_create_id(rdma->channel, &listen_id, NULL, RDMA_PS_TCP); if (ret) { - ERROR(errp, "could not create cm_id!\n"); + ERROR(errp, "could not create cm_id!"); goto err_dest_init_create_listen_id; } - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(rdma->port); + snprintf(port_str, 16, "%d", rdma->port); + port_str[15] = '\0'; if (rdma->host && strcmp("", rdma->host)) { - struct hostent *dest_addr; - dest_addr = gethostbyname(rdma->host); - if (!dest_addr) { - ERROR(errp, "migration could not gethostbyname!\n"); - ret = -EINVAL; + struct rdma_addrinfo *e; + + ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); + if (ret < 0) { + ERROR(errp, "could not rdma_getaddrinfo address %s", rdma->host); goto err_dest_init_bind_addr; } - memcpy(&sin.sin_addr.s_addr, dest_addr->h_addr, - dest_addr->h_length); - inet_ntop(AF_INET, dest_addr->h_addr, ip, sizeof ip); - } else { - sin.sin_addr.s_addr = INADDR_ANY; - } - DPRINTF("%s => %s\n", rdma->host, ip); + for (e = res; e != NULL; e = e->ai_next) { + inet_ntop(e->ai_family, + &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); + DPRINTF("Trying %s => %s\n", rdma->host, ip); + ret = rdma_bind_addr(listen_id, e->ai_dst_addr); + if (!ret) { + if (e->ai_family == AF_INET6) { + ret = qemu_rdma_broken_ipv6_kernel(errp, listen_id->verbs); + if (ret) { + continue; + } + } + + goto listen; + } + } - ret = rdma_bind_addr(listen_id, (struct sockaddr *)&sin); - if (ret) { - ERROR(errp, "Error: could not rdma_bind_addr!\n"); + ERROR(errp, "Error: could not rdma_bind_addr!"); + goto err_dest_init_bind_addr; + } else { + ERROR(errp, "migration host and port not specified!"); + ret = -EINVAL; goto err_dest_init_bind_addr; } +listen: rdma->listen_id = listen_id; qemu_rdma_dump_gid("dest_init", listen_id); @@ -2452,7 +2634,7 @@ static int qemu_rdma_drain_cq(QEMUFile *f, RDMAContext *rdma) } while (rdma->nb_sent) { - ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE); + ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { fprintf(stderr, "rdma migration: complete polling error!\n"); return -EIO; @@ -2494,7 +2676,7 @@ static int qemu_rdma_close(void *opaque) * @size == 0 : * A 'hint' or 'advice' that means that we wish to speculatively * and asynchronously unregister this memory. In this case, there is no - * gaurantee that the unregister will actually happen, for example, + * guarantee that the unregister will actually happen, for example, * if the memory is being actively transmitted. Additionally, the memory * may be re-registered at any future time if a write within the same * chunk was requested again, even if you attempted to unregister it @@ -2570,7 +2752,7 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, qemu_rdma_signal_unregister(rdma, index, chunk, 0); /* - * TODO: Synchronous, gauranteed unregistration (should not occur during + * TODO: Synchronous, guaranteed unregistration (should not occur during * fast-path). Otherwise, unregisters will process on the next call to * qemu_rdma_drain_cq() if (size < 0) { @@ -2588,7 +2770,7 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, */ while (1) { uint64_t wr_id, wr_id_in; - int ret = qemu_rdma_poll(rdma, &wr_id_in); + int ret = qemu_rdma_poll(rdma, &wr_id_in, NULL); if (ret < 0) { fprintf(stderr, "rdma migration: polling error! %d\n", ret); goto err; @@ -2693,7 +2875,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) goto err_rdma_dest_wait; } - for (idx = 0; idx <= RDMA_WRID_MAX; idx++) { + for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); if (ret) { fprintf(stderr, "rdma: error registering %d control!\n", idx); @@ -2723,7 +2905,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) rdma_ack_cm_event(cm_event); - ret = qemu_rdma_post_recv_control(rdma, 0); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret) { fprintf(stderr, "rdma migration: error posting second control recv!\n"); goto err_rdma_dest_wait; @@ -3027,14 +3209,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, ®_result_idx, rdma->pin_all ? qemu_rdma_reg_whole_ram_blocks : NULL); if (ret < 0) { - ERROR(errp, "receiving remote info!\n"); + ERROR(errp, "receiving remote info!"); return ret; } - qemu_rdma_move_header(rdma, reg_result_idx, &resp); - memcpy(rdma->block, - rdma->wr_data[reg_result_idx].control_curr, resp.len); - nb_remote_blocks = resp.len / sizeof(RDMARemoteBlock); /* @@ -3052,10 +3230,13 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, if (local->nb_blocks != nb_remote_blocks) { ERROR(errp, "ram blocks mismatch #1! " "Your QEMU command line parameters are probably " - "not identical on both the source and destination.\n"); + "not identical on both the source and destination."); return -EINVAL; } + qemu_rdma_move_header(rdma, reg_result_idx, &resp); + memcpy(rdma->block, + rdma->wr_data[reg_result_idx].control_curr, resp.len); for (i = 0; i < nb_remote_blocks; i++) { network_to_remote_block(&rdma->block[i]); @@ -3068,7 +3249,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, if (rdma->block[i].length != local->block[j].length) { ERROR(errp, "ram blocks mismatch #2! " "Your QEMU command line parameters are probably " - "not identical on both the source and destination.\n"); + "not identical on both the source and destination."); return -EINVAL; } local->block[j].remote_host_addr = @@ -3080,7 +3261,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, if (j >= local->nb_blocks) { ERROR(errp, "ram blocks mismatch #3! " "Your QEMU command line parameters are probably " - "not identical on both the source and destination.\n"); + "not identical on both the source and destination."); return -EINVAL; } } @@ -3154,7 +3335,7 @@ static void rdma_accept_incoming_migration(void *opaque) ret = qemu_rdma_accept(rdma); if (ret) { - ERROR(errp, "RDMA Migration initialization failed!\n"); + ERROR(errp, "RDMA Migration initialization failed!"); return; } @@ -3162,7 +3343,7 @@ static void rdma_accept_incoming_migration(void *opaque) f = qemu_fopen_rdma(rdma, "rb"); if (f == NULL) { - ERROR(errp, "could not qemu_fopen_rdma!\n"); + ERROR(errp, "could not qemu_fopen_rdma!"); qemu_rdma_cleanup(rdma); return; } @@ -3195,7 +3376,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) ret = rdma_listen(rdma->listen_id, 5); if (ret) { - ERROR(errp, "listening on socket!\n"); + ERROR(errp, "listening on socket!"); goto err; } @@ -3219,7 +3400,7 @@ void rdma_start_outgoing_migration(void *opaque, int ret = 0; if (rdma == NULL) { - ERROR(temp, "Failed to initialize RDMA data structures! %d\n", ret); + ERROR(temp, "Failed to initialize RDMA data structures! %d", ret); goto err; } diff --git a/migration-tcp.c b/migration-tcp.c index b20ee58f55..782572de82 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -18,6 +18,7 @@ #include "migration/migration.h" #include "migration/qemu-file.h" #include "block/block.h" +#include "qemu/main-loop.h" //#define DEBUG_MIGRATION_TCP diff --git a/migration-unix.c b/migration-unix.c index 94b7022fc8..651fc5b707 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -15,6 +15,7 @@ #include "qemu-common.h" #include "qemu/sockets.h" +#include "qemu/main-loop.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "block/block.h" diff --git a/migration.c b/migration.c index e12e7840e6..200d404547 100644 --- a/migration.c +++ b/migration.c @@ -14,6 +14,7 @@ */ #include "qemu-common.h" +#include "qemu/main-loop.h" #include "migration/migration.h" #include "monitor/monitor.h" #include "migration/qemu-file.h" @@ -197,7 +198,7 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->has_status = true; info->status = g_strdup("active"); info->has_total_time = true; - info->total_time = qemu_get_clock_ms(rt_clock) + info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - s->total_time; info->has_expected_downtime = true; info->expected_downtime = s->expected_downtime; @@ -231,6 +232,7 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->has_status = true; info->status = g_strdup("completed"); + info->has_total_time = true; info->total_time = s->total_time; info->has_downtime = true; info->downtime = s->downtime; @@ -338,9 +340,9 @@ void remove_migration_state_change_notifier(Notifier *notify) notifier_remove(notify); } -bool migration_is_active(MigrationState *s) +bool migration_in_setup(MigrationState *s) { - return s->state == MIG_STATE_ACTIVE; + return s->state == MIG_STATE_SETUP; } bool migration_has_finished(MigrationState *s) @@ -374,7 +376,7 @@ static MigrationState *migrate_init(const MigrationParams *params) s->state = MIG_STATE_SETUP; trace_migrate_set_state(MIG_STATE_SETUP); - s->total_time = qemu_get_clock_ms(rt_clock); + s->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); return s; } @@ -399,8 +401,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, MigrationParams params; const char *p; - params.blk = blk; - params.shared = inc; + params.blk = has_blk && blk; + params.shared = has_inc && inc; if (s->state == MIG_STATE_ACTIVE || s->state == MIG_STATE_SETUP) { error_set(errp, QERR_MIGRATION_ACTIVE); @@ -543,8 +545,8 @@ int64_t migrate_xbzrle_cache_size(void) static void *migration_thread(void *opaque) { MigrationState *s = opaque; - int64_t initial_time = qemu_get_clock_ms(rt_clock); - int64_t setup_start = qemu_get_clock_ms(host_clock); + int64_t initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + int64_t setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST); int64_t initial_bytes = 0; int64_t max_size = 0; int64_t start_time = initial_time; @@ -553,7 +555,7 @@ static void *migration_thread(void *opaque) DPRINTF("beginning savevm\n"); qemu_savevm_state_begin(s->file, &s->params); - s->setup_time = qemu_get_clock_ms(host_clock) - setup_start; + s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start; migrate_set_state(s, MIG_STATE_SETUP, MIG_STATE_ACTIVE); DPRINTF("setup complete\n"); @@ -573,7 +575,7 @@ static void *migration_thread(void *opaque) DPRINTF("done iterating\n"); qemu_mutex_lock_iothread(); - start_time = qemu_get_clock_ms(rt_clock); + start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); old_vm_running = runstate_is_running(); @@ -600,7 +602,7 @@ static void *migration_thread(void *opaque) migrate_set_state(s, MIG_STATE_ACTIVE, MIG_STATE_ERROR); break; } - current_time = qemu_get_clock_ms(rt_clock); + current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = qemu_ftell(s->file) - initial_bytes; uint64_t time_spent = current_time - initial_time; @@ -631,7 +633,7 @@ static void *migration_thread(void *opaque) qemu_mutex_lock_iothread(); if (s->state == MIG_STATE_COMPLETED) { - int64_t end_time = qemu_get_clock_ms(rt_clock); + int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); s->total_time = end_time - s->total_time; s->downtime = end_time - start_time; runstate_set(RUN_STATE_POSTMIGRATE); @@ -658,7 +660,9 @@ void migrate_fd_connect(MigrationState *s) qemu_file_set_rate_limit(s->file, s->bandwidth_limit / XFER_LIMIT_RATIO); + /* Notify before starting migration thread */ + notifier_list_notify(&migration_state_notifiers, s); + qemu_thread_create(&s->thread, migration_thread, s, QEMU_THREAD_JOINABLE); - notifier_list_notify(&migration_state_notifiers, s); } @@ -537,7 +537,7 @@ monitor_protocol_event_queue(MonitorEvent event, QObject *data) { MonitorEventState *evstate; - int64_t now = qemu_get_clock_ns(rt_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); assert(event < QEVENT_MAX); qemu_mutex_lock(&monitor_event_state_lock); @@ -564,7 +564,7 @@ monitor_protocol_event_queue(MonitorEvent event, qobject_decref(evstate->data); } else { int64_t then = evstate->last + evstate->rate; - qemu_mod_timer_ns(evstate->timer, then); + timer_mod_ns(evstate->timer, then); } evstate->data = data; qobject_incref(evstate->data); @@ -584,7 +584,7 @@ monitor_protocol_event_queue(MonitorEvent event, static void monitor_protocol_event_handler(void *opaque) { MonitorEventState *evstate = opaque; - int64_t now = qemu_get_clock_ns(rt_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); qemu_mutex_lock(&monitor_event_state_lock); @@ -622,7 +622,7 @@ monitor_protocol_event_throttle(MonitorEvent event, trace_monitor_protocol_event_throttle(event, rate); evstate->event = event; evstate->rate = rate * SCALE_MS; - evstate->timer = qemu_new_timer(rt_clock, + evstate->timer = timer_new(QEMU_CLOCK_REALTIME, SCALE_MS, monitor_protocol_event_handler, evstate); @@ -3171,9 +3171,13 @@ static const MonitorDef monitor_defs[] = { { NULL }, }; -static void expr_error(Monitor *mon, const char *msg) +static void expr_error(Monitor *mon, const char *fmt, ...) { - monitor_printf(mon, "%s\n", msg); + va_list ap; + va_start(ap, fmt); + monitor_vprintf(mon, fmt, ap); + monitor_printf(mon, "\n"); + va_end(ap); siglongjmp(expr_env, 1); } @@ -3291,7 +3295,7 @@ static int64_t expr_unary(Monitor *mon) expr_error(mon, "number too large"); } if (pch == p) { - expr_error(mon, "invalid char in expression"); + expr_error(mon, "invalid char '%c' in expression", *p); } pch = p; while (qemu_isspace(*pch)) @@ -38,6 +38,7 @@ #include "qemu/sockets.h" #include "qemu/queue.h" +#include "qemu/main-loop.h" //#define DEBUG_NBD diff --git a/net/dump.c b/net/dump.c index 4119721720..9d3a09e334 100644 --- a/net/dump.c +++ b/net/dump.c @@ -69,7 +69,7 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } - ts = muldiv64(qemu_get_clock_ns(vm_clock), 1000000, get_ticks_per_sec()); + ts = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 1000000, get_ticks_per_sec()); caplen = size > s->pcap_caplen ? s->pcap_caplen : size; hdr.ts.tv_sec = ts / 1000000 + s->start_ts; @@ -73,7 +73,7 @@ eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto) } /* Unsupported offload */ - assert(false); + g_assert_not_reached(); return VIRTIO_NET_HDR_GSO_NONE | ecn_state; } @@ -36,6 +36,7 @@ #include "qmp-commands.h" #include "hw/qdev.h" #include "qemu/iov.h" +#include "qemu/main-loop.h" #include "qapi-visit.h" #include "qapi/opts-visitor.h" #include "qapi/dealloc-visitor.h" diff --git a/net/socket.c b/net/socket.c index 87af1d3d39..e61309d8d5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -31,6 +31,7 @@ #include "qemu/option.h" #include "qemu/sockets.h" #include "qemu/iov.h" +#include "qemu/main-loop.h" typedef struct NetSocketState { NetClientState nc; diff --git a/pc-bios/README b/pc-bios/README index 53b52894f7..e404a228a4 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -11,8 +11,8 @@ firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for PowerPC (for 32 and 64 bit PPC CPUs), - Sparc32 and Sparc64 are built from OpenBIOS 1.1 release (SVN - revision 1136). + Sparc32 and Sparc64 are built from OpenBIOS SVN revision + 1198. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at diff --git a/pc-bios/acpi-dsdt.aml b/pc-bios/acpi-dsdt.aml Binary files differindex 75dfd1e310..48dbe3242c 100644 --- a/pc-bios/acpi-dsdt.aml +++ b/pc-bios/acpi-dsdt.aml diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex c2a19b8930..cccc487814 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex 77eb55dce8..c6b3319fab 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex c5ba6ae6d1..2aa400cfd9 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex c4aaa05173..f6ee286034 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 diff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml Binary files differindex cf7b085762..91ab67cada 100644 --- a/pc-bios/q35-acpi-dsdt.aml +++ b/pc-bios/q35-acpi-dsdt.aml diff --git a/pc-bios/qemu-nsis.bmp b/pc-bios/qemu-nsis.bmp Binary files differnew file mode 100644 index 0000000000..ae82cd2697 --- /dev/null +++ b/pc-bios/qemu-nsis.bmp diff --git a/pc-bios/qemu-nsis.ico b/pc-bios/qemu-nsis.ico Binary files differnew file mode 100644 index 0000000000..1d0128cd4c --- /dev/null +++ b/pc-bios/qemu-nsis.ico diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img Binary files differindex 1b2a11e728..05fc7c2fae 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h index cb5815accd..f5b4549ea3 100644 --- a/pc-bios/s390-ccw/cio.h +++ b/pc-bios/s390-ccw/cio.h @@ -93,6 +93,26 @@ struct subchannel_id { __u32 sch_no : 16; } __attribute__ ((packed, aligned(4))); +struct chsc_header { + __u16 length; + __u16 code; +} __attribute__((packed)); + +struct chsc_area_sda { + struct chsc_header request; + __u8 reserved1:4; + __u8 format:4; + __u8 reserved2; + __u16 operation_code; + __u32 reserved3; + __u32 reserved4; + __u32 operation_data_area[252]; + struct chsc_header response; + __u32 reserved5:4; + __u32 format2:4; + __u32 reserved6:24; +} __attribute__((packed)); + /* * TPI info structure */ diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 1665c57225..c5d533231b 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -35,6 +35,13 @@ static void virtio_setup(uint64_t dev_info) check_devno = true; dev_no = dev_info & 0xffff; debug_print_int("device no. ", dev_no); + blk_schid.ssid = (dev_info >> 16) & 0x3; + if (blk_schid.ssid != 0) { + debug_print_int("ssid ", blk_schid.ssid); + if (enable_mss_facility() != 0) { + virtio_panic("Failed to enable mss facility\n"); + } + } } for (i = 0; i < 0x10000; i++) { diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 8241b0af05..5e871ac84c 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -61,6 +61,7 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, bool virtio_is_blk(struct subchannel_id schid); void virtio_setup_block(struct subchannel_id schid); int virtio_read(ulong sector, void *load_addr); +int enable_mss_facility(void); /* bootmap.c */ int zipl_load(void); diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index f438af15aa..49f2d291fc 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -13,6 +13,8 @@ struct vring block; +static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); + static long kvm_hypercall(unsigned long nr, unsigned long param1, unsigned long param2) { @@ -301,3 +303,19 @@ bool virtio_is_blk(struct subchannel_id schid) return true; } +int enable_mss_facility(void) +{ + int ret; + struct chsc_area_sda *sda_area = (struct chsc_area_sda *) chsc_page; + + memset(sda_area, 0, PAGE_SIZE); + sda_area->request.length = 0x0400; + sda_area->request.code = 0x0031; + sda_area->operation_code = 0x2; + + ret = chsc(sda_area); + if ((ret == 0) && (sda_area->response.code == 0x0001)) { + return 0; + } + return -EIO; +} diff --git a/po/Makefile b/po/Makefile index 60ccd7d3bb..705166e2d3 100644 --- a/po/Makefile +++ b/po/Makefile @@ -1,20 +1,23 @@ # This makefile is very special as it's meant to build as part of the build # process and also within the source tree to update the translation files. -VERSION=$(shell cat ../VERSION) -SRCS=$(filter-out messages.po,$(wildcard *.po)) -OBJS=$(patsubst %.po,%.mo,$(SRCS)) - +# Set SRC_PATH for in-tree builds without configuration. SRC_PATH=.. -include ../config-host.mak +include $(SRC_PATH)/rules.mak + +PO_PATH=$(SRC_PATH)/po + +VERSION=$(shell cat $(SRC_PATH)/VERSION) +SRCS=$(filter-out $(PO_PATH)/messages.po,$(wildcard $(PO_PATH)/*.po)) +OBJS=$(patsubst $(PO_PATH)/%.po,%.mo,$(SRCS)) -vpath %.po $(SRC_PATH)/po +vpath %.po $(PO_PATH) all: - @echo Use 'make update' to update translation files - @echo or us 'make build' or 'make install' to build and install - @echo the translation files + @echo "Use 'make update' to update translation files or use 'make build'" + @echo "or 'make install' to build and install the translation files." update: $(SRCS) @@ -31,12 +34,16 @@ install: $(OBJS) done %.mo: %.po - @msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po + $(call quiet-command, msgfmt -o $@ $<, " GEN $@") -messages.po: $(SRC_PATH)/ui/gtk.c - @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=$(VERSION) --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $< +$(PO_PATH)/messages.po: $(SRC_PATH)/ui/gtk.c + $(call quiet-command, cd $(SRC_PATH) && \ + (xgettext -o - --from-code=UTF-8 --foreign-user \ + --package-name=QEMU --package-version=$(VERSION) \ + --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C ui/gtk.c | \ + sed -e s/CHARSET/UTF-8/) >$@, " GEN $@") -%.po: messages.po - @msgmerge $@ $< > $@.bak && mv $@.bak $@ +$(PO_PATH)/%.po: $(PO_PATH)/messages.po + $(call quiet-command, msgmerge -q $@ $< > $@.bak && mv $@.bak $@, " GEN $@") .PHONY: clean all diff --git a/po/de_DE.po b/po/de_DE.po index e35aaf4871..fcbde954c2 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-03-31 20:42+0200\n" +"POT-Creation-Date: 2013-07-05 22:36+0200\n" "PO-Revision-Date: 2012-02-28 16:00+0100\n" "Last-Translator: Kevin Wolf <kwolf@redhat.com>\n" "Language-Team: Deutsch <de@li.org>\n" @@ -16,49 +16,49 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" -#: ../ui/gtk.c:213 +#: ui/gtk.c:214 msgid " - Press Ctrl+Alt+G to release grab" msgstr " - Strg+Alt+G drücken, um Eingabegeräte freizugeben" -#: ../ui/gtk.c:217 +#: ui/gtk.c:218 msgid " [Paused]" msgstr " [Angehalten]" -#: ../ui/gtk.c:1250 -msgid "_Machine" -msgstr "_Maschine" - -#: ../ui/gtk.c:1252 +#: ui/gtk.c:1318 msgid "_Pause" msgstr "_Angehalten" -#: ../ui/gtk.c:1258 +#: ui/gtk.c:1324 msgid "_Reset" msgstr "_Reset" -#: ../ui/gtk.c:1261 +#: ui/gtk.c:1327 msgid "Power _Down" msgstr "_Herunterfahren" -#: ../ui/gtk.c:1276 -msgid "_View" -msgstr "_Ansicht" - -#: ../ui/gtk.c:1306 +#: ui/gtk.c:1381 msgid "Zoom To _Fit" msgstr "Auf _Fenstergröße skalieren" -#: ../ui/gtk.c:1312 +#: ui/gtk.c:1387 msgid "Grab On _Hover" msgstr "Tastatur _automatisch einfangen" -#: ../ui/gtk.c:1315 +#: ui/gtk.c:1390 msgid "_Grab Input" msgstr "_Eingabegeräte einfangen" -#: ../ui/gtk.c:1341 +#: ui/gtk.c:1416 msgid "Show _Tabs" msgstr "_Tableiste anzeigen" +#: ui/gtk.c:1430 +msgid "_Machine" +msgstr "_Maschine" + +#: ui/gtk.c:1435 +msgid "_View" +msgstr "_Ansicht" + #~ msgid "_File" #~ msgstr "_Datei" diff --git a/po/fr_FR.po b/po/fr_FR.po index 27d86367c9..45b2c0153d 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-03-31 20:42+0200\n" +"POT-Creation-Date: 2013-07-05 22:36+0200\n" "PO-Revision-Date: 2013-03-31 19:39+0200\n" "Last-Translator: Aurelien Jarno <aurelien@aurel32.net>\n" "Language-Team: French <FR@li.org>\n" @@ -17,46 +17,46 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Lokalize 1.4\n" -#: ../ui/gtk.c:213 +#: ui/gtk.c:214 msgid " - Press Ctrl+Alt+G to release grab" msgstr "- Appuyer sur Ctrl+Alt+G pour arrêter la capture" -#: ../ui/gtk.c:217 +#: ui/gtk.c:218 msgid " [Paused]" msgstr " [En pause]" -#: ../ui/gtk.c:1250 -msgid "_Machine" -msgstr "_Machine" - -#: ../ui/gtk.c:1252 +#: ui/gtk.c:1318 msgid "_Pause" msgstr "_Pause" -#: ../ui/gtk.c:1258 +#: ui/gtk.c:1324 msgid "_Reset" msgstr "_Réinitialiser" -#: ../ui/gtk.c:1261 +#: ui/gtk.c:1327 msgid "Power _Down" msgstr "_Éteindre" -#: ../ui/gtk.c:1276 -msgid "_View" -msgstr "_Vue" - -#: ../ui/gtk.c:1306 +#: ui/gtk.c:1381 msgid "Zoom To _Fit" msgstr "Zoomer pour _ajuster" -#: ../ui/gtk.c:1312 +#: ui/gtk.c:1387 msgid "Grab On _Hover" msgstr "Capturer en _survolant" -#: ../ui/gtk.c:1315 +#: ui/gtk.c:1390 msgid "_Grab Input" msgstr "_Capturer les entrées" -#: ../ui/gtk.c:1341 +#: ui/gtk.c:1416 msgid "Show _Tabs" msgstr "Montrer les _onglets" + +#: ui/gtk.c:1430 +msgid "_Machine" +msgstr "_Machine" + +#: ui/gtk.c:1435 +msgid "_View" +msgstr "_Vue" @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-05-06 20:42+0200\n" +"POT-Creation-Date: 2013-07-05 22:36+0200\n" "PO-Revision-Date: 2013-05-06 20:42+0200\n" "Last-Translator: Ákos Kovács <akoskovacs@gmx.com>\n" "Language-Team: Hungarian <hu@li.org>\n" @@ -15,49 +15,49 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../ui/gtk.c:213 +#: ui/gtk.c:214 msgid " - Press Ctrl+Alt+G to release grab" msgstr " - Nyomj Ctrl+Alt+G-t a bemeneti eszközök elengedéséhez" -#: ../ui/gtk.c:217 +#: ui/gtk.c:218 msgid " [Paused]" msgstr " [Megállítva]" -#: ../ui/gtk.c:1250 -msgid "_Machine" -msgstr "_Gép" - -#: ../ui/gtk.c:1252 +#: ui/gtk.c:1318 msgid "_Pause" msgstr "_Megállítás" -#: ../ui/gtk.c:1258 +#: ui/gtk.c:1324 msgid "_Reset" msgstr "Új_raindítás" -#: ../ui/gtk.c:1261 +#: ui/gtk.c:1327 msgid "Power _Down" msgstr "_Leállítás" -#: ../ui/gtk.c:1276 -msgid "_View" -msgstr "_Nézet" - -#: ../ui/gtk.c:1306 +#: ui/gtk.c:1381 msgid "Zoom To _Fit" msgstr "Ablakmérethez _igazítás" -#: ../ui/gtk.c:1312 +#: ui/gtk.c:1387 msgid "Grab On _Hover" msgstr "Automatikus _elfogás" -#: ../ui/gtk.c:1315 +#: ui/gtk.c:1390 msgid "_Grab Input" msgstr "_Bemeneti eszközök megragadása" -#: ../ui/gtk.c:1341 +#: ui/gtk.c:1416 msgid "Show _Tabs" msgstr "_Fülek megjelenítése" +#: ui/gtk.c:1430 +msgid "_Machine" +msgstr "_Gép" + +#: ui/gtk.c:1435 +msgid "_View" +msgstr "_Nézet" + #~ msgid "_File" #~ msgstr "_File" @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-03-31 20:42+0200\n" +"POT-Creation-Date: 2013-07-05 22:36+0200\n" "PO-Revision-Date: 2012-02-27 08:23+0100\n" "Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n" "Language-Team: Italian <it@li.org>\n" @@ -16,49 +16,49 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../ui/gtk.c:213 +#: ui/gtk.c:214 msgid " - Press Ctrl+Alt+G to release grab" msgstr "" -#: ../ui/gtk.c:217 +#: ui/gtk.c:218 msgid " [Paused]" msgstr "" -#: ../ui/gtk.c:1250 -msgid "_Machine" -msgstr "" - -#: ../ui/gtk.c:1252 +#: ui/gtk.c:1318 msgid "_Pause" msgstr "" -#: ../ui/gtk.c:1258 +#: ui/gtk.c:1324 msgid "_Reset" msgstr "" -#: ../ui/gtk.c:1261 +#: ui/gtk.c:1327 msgid "Power _Down" msgstr "" -#: ../ui/gtk.c:1276 -msgid "_View" -msgstr "_Visualizza" - -#: ../ui/gtk.c:1306 +#: ui/gtk.c:1381 msgid "Zoom To _Fit" msgstr "Adatta alla _finestra" -#: ../ui/gtk.c:1312 +#: ui/gtk.c:1387 msgid "Grab On _Hover" msgstr "Cattura _automatica input" -#: ../ui/gtk.c:1315 +#: ui/gtk.c:1390 msgid "_Grab Input" msgstr "_Cattura input" -#: ../ui/gtk.c:1341 +#: ui/gtk.c:1416 msgid "Show _Tabs" msgstr "Mostra _tab" +#: ui/gtk.c:1430 +msgid "_Machine" +msgstr "" + +#: ui/gtk.c:1435 +msgid "_View" +msgstr "_Visualizza" + #~ msgid "_File" #~ msgstr "_File" diff --git a/po/messages.po b/po/messages.po index 42a3eacbea..26c76bce8b 100644 --- a/po/messages.po +++ b/po/messages.po @@ -5,57 +5,57 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: QEMU 1.4.50\n" +"Project-Id-Version: QEMU 1.5.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-03-31 20:42+0200\n" +"POT-Creation-Date: 2013-07-05 22:36+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../ui/gtk.c:213 +#: ui/gtk.c:214 msgid " - Press Ctrl+Alt+G to release grab" msgstr "" -#: ../ui/gtk.c:217 +#: ui/gtk.c:218 msgid " [Paused]" msgstr "" -#: ../ui/gtk.c:1250 -msgid "_Machine" -msgstr "" - -#: ../ui/gtk.c:1252 +#: ui/gtk.c:1318 msgid "_Pause" msgstr "" -#: ../ui/gtk.c:1258 +#: ui/gtk.c:1324 msgid "_Reset" msgstr "" -#: ../ui/gtk.c:1261 +#: ui/gtk.c:1327 msgid "Power _Down" msgstr "" -#: ../ui/gtk.c:1276 -msgid "_View" -msgstr "" - -#: ../ui/gtk.c:1306 +#: ui/gtk.c:1381 msgid "Zoom To _Fit" msgstr "" -#: ../ui/gtk.c:1312 +#: ui/gtk.c:1387 msgid "Grab On _Hover" msgstr "" -#: ../ui/gtk.c:1315 +#: ui/gtk.c:1390 msgid "_Grab Input" msgstr "" -#: ../ui/gtk.c:1341 +#: ui/gtk.c:1416 msgid "Show _Tabs" msgstr "" + +#: ui/gtk.c:1430 +msgid "_Machine" +msgstr "" + +#: ui/gtk.c:1435 +msgid "_View" +msgstr "" @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-04-22 18:33+0300\n" +"POT-Creation-Date: 2013-07-05 22:36+0200\n" "PO-Revision-Date: 2013-04-22 18:35+0300\n" "Last-Translator: Ozan Çağlayan <ozancag@gmail.com>\n" "Language-Team: Türkçe <>\n" @@ -17,46 +17,46 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 2.91.6\n" -#: ../ui/gtk.c:214 +#: ui/gtk.c:214 msgid " - Press Ctrl+Alt+G to release grab" msgstr " - Yakalamayı durdurmak için Ctrl+Alt+G tuşlarına basın" -#: ../ui/gtk.c:218 +#: ui/gtk.c:218 msgid " [Paused]" msgstr " [Duraklatıldı]" -#: ../ui/gtk.c:1282 -msgid "_Machine" -msgstr "_Makine" - -#: ../ui/gtk.c:1284 +#: ui/gtk.c:1318 msgid "_Pause" msgstr "_Duraklat" -#: ../ui/gtk.c:1290 +#: ui/gtk.c:1324 msgid "_Reset" msgstr "_Sıfırla" -#: ../ui/gtk.c:1293 +#: ui/gtk.c:1327 msgid "Power _Down" msgstr "_Kapat" -#: ../ui/gtk.c:1308 -msgid "_View" -msgstr "_Görüntüle" - -#: ../ui/gtk.c:1338 +#: ui/gtk.c:1381 msgid "Zoom To _Fit" msgstr "Yakınlaş ve Sığ_dır" -#: ../ui/gtk.c:1344 +#: ui/gtk.c:1387 msgid "Grab On _Hover" msgstr "Ü_zerindeyken Yakala" -#: ../ui/gtk.c:1347 +#: ui/gtk.c:1390 msgid "_Grab Input" msgstr "Girdiyi _Yakala" -#: ../ui/gtk.c:1373 +#: ui/gtk.c:1416 msgid "Show _Tabs" msgstr "Se_kmeleri Göster" + +#: ui/gtk.c:1430 +msgid "_Machine" +msgstr "_Makine" + +#: ui/gtk.c:1435 +msgid "_View" +msgstr "_Görüntüle" diff --git a/qapi-schema.json b/qapi-schema.json index f82d829fdc..a51f7d2d6e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3362,15 +3362,15 @@ '*rows' : 'int' } } ## -# @ChardevMemory: +# @ChardevRingbuf: # -# Configuration info for memory chardevs +# Configuration info for ring buffer chardevs. # -# @size: #optional Ringbuffer size, must be power of two, default is 65536 +# @size: #optional ring buffer size, must be power of two, default is 65536 # # Since: 1.5 ## -{ 'type': 'ChardevMemory', 'data': { '*size' : 'int' } } +{ 'type': 'ChardevRingbuf', 'data': { '*size' : 'int' } } ## # @ChardevBackend: @@ -3397,7 +3397,9 @@ 'spicevmc' : 'ChardevSpiceChannel', 'spiceport' : 'ChardevSpicePort', 'vc' : 'ChardevVC', - 'memory' : 'ChardevMemory' } } + 'ringbuf': 'ChardevRingbuf', + # next one is just for compatibility + 'memory' : 'ChardevRingbuf' } } ## # @ChardevReturn: diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 174bd8bdb0..96ed85899d 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -1,7 +1,7 @@ /* * Options Visitor * - * Copyright Red Hat, Inc. 2012 + * Copyright Red Hat, Inc. 2012, 2013 * * Author: Laszlo Ersek <lersek@redhat.com> * @@ -18,6 +18,40 @@ #include "qapi/visitor-impl.h" +enum ListMode +{ + LM_NONE, /* not traversing a list of repeated options */ + LM_STARTED, /* opts_start_list() succeeded */ + + LM_IN_PROGRESS, /* opts_next_list() has been called. + * + * Generating the next list link will consume the most + * recently parsed QemuOpt instance of the repeated + * option. + * + * Parsing a value into the list link will examine the + * next QemuOpt instance of the repeated option, and + * possibly enter LM_SIGNED_INTERVAL or + * LM_UNSIGNED_INTERVAL. + */ + + LM_SIGNED_INTERVAL, /* opts_next_list() has been called. + * + * Generating the next list link will consume the most + * recently stored element from the signed interval, + * parsed from the most recent QemuOpt instance of the + * repeated option. This may consume QemuOpt itself + * and return to LM_IN_PROGRESS. + * + * Parsing a value into the list link will store the + * next element of the signed interval. + */ + + LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */ +}; + +typedef enum ListMode ListMode; + struct OptsVisitor { Visitor visitor; @@ -35,8 +69,17 @@ struct OptsVisitor /* The list currently being traversed with opts_start_list() / * opts_next_list(). The list must have a struct element type in the * schema, with a single mandatory scalar member. */ + ListMode list_mode; GQueue *repeated_opts; - bool repeated_opts_first; + + /* When parsing a list of repeating options as integers, values of the form + * "a-b", representing a closed interval, are allowed. Elements in the + * range are generated individually. + */ + union { + int64_t s; + uint64_t u; + } range_next, range_limit; /* If "opts_root->id" is set, reinstantiate it as a fake QemuOpt for * uniformity. Only its "name" and "str" fields are set. "fake_id_opt" does @@ -156,9 +199,11 @@ opts_start_list(Visitor *v, const char *name, Error **errp) OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); /* we can't traverse a list in a list */ - assert(ov->repeated_opts == NULL); + assert(ov->list_mode == LM_NONE); ov->repeated_opts = lookup_distinct(ov, name, errp); - ov->repeated_opts_first = (ov->repeated_opts != NULL); + if (ov->repeated_opts != NULL) { + ov->list_mode = LM_STARTED; + } } @@ -168,10 +213,29 @@ opts_next_list(Visitor *v, GenericList **list, Error **errp) OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); GenericList **link; - if (ov->repeated_opts_first) { - ov->repeated_opts_first = false; + switch (ov->list_mode) { + case LM_STARTED: + ov->list_mode = LM_IN_PROGRESS; link = list; - } else { + break; + + case LM_SIGNED_INTERVAL: + case LM_UNSIGNED_INTERVAL: + link = &(*list)->next; + + if (ov->list_mode == LM_SIGNED_INTERVAL) { + if (ov->range_next.s < ov->range_limit.s) { + ++ov->range_next.s; + break; + } + } else if (ov->range_next.u < ov->range_limit.u) { + ++ov->range_next.u; + break; + } + ov->list_mode = LM_IN_PROGRESS; + /* range has been completed, fall through in order to pop option */ + + case LM_IN_PROGRESS: { const QemuOpt *opt; opt = g_queue_pop_head(ov->repeated_opts); @@ -180,6 +244,11 @@ opts_next_list(Visitor *v, GenericList **list, Error **errp) return NULL; } link = &(*list)->next; + break; + } + + default: + abort(); } *link = g_malloc0(sizeof **link); @@ -192,14 +261,19 @@ opts_end_list(Visitor *v, Error **errp) { OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + assert(ov->list_mode == LM_STARTED || + ov->list_mode == LM_IN_PROGRESS || + ov->list_mode == LM_SIGNED_INTERVAL || + ov->list_mode == LM_UNSIGNED_INTERVAL); ov->repeated_opts = NULL; + ov->list_mode = LM_NONE; } static const QemuOpt * lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) { - if (ov->repeated_opts == NULL) { + if (ov->list_mode == LM_NONE) { GQueue *list; /* the last occurrence of any QemuOpt takes effect when queried by name @@ -207,6 +281,7 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) list = lookup_distinct(ov, name, errp); return list ? g_queue_peek_tail(list) : NULL; } + assert(ov->list_mode == LM_IN_PROGRESS); return g_queue_peek_head(ov->repeated_opts); } @@ -214,9 +289,12 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) static void processed(OptsVisitor *ov, const char *name) { - if (ov->repeated_opts == NULL) { + if (ov->list_mode == LM_NONE) { g_hash_table_remove(ov->unprocessed_opts, name); + return; } + assert(ov->list_mode == LM_IN_PROGRESS); + /* do nothing */ } @@ -278,21 +356,50 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) long long val; char *endptr; + if (ov->list_mode == LM_SIGNED_INTERVAL) { + *obj = ov->range_next.s; + return; + } + opt = lookup_scalar(ov, name, errp); if (!opt) { return; } str = opt->str ? opt->str : ""; + /* we've gotten past lookup_scalar() */ + assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS); + errno = 0; val = strtoll(str, &endptr, 0); - if (*str != '\0' && *endptr == '\0' && errno == 0 && INT64_MIN <= val && - val <= INT64_MAX) { - *obj = val; - processed(ov, name); - return; + if (errno == 0 && endptr > str && INT64_MIN <= val && val <= INT64_MAX) { + if (*endptr == '\0') { + *obj = val; + processed(ov, name); + return; + } + if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { + long long val2; + + str = endptr + 1; + val2 = strtoll(str, &endptr, 0); + if (errno == 0 && endptr > str && *endptr == '\0' && + INT64_MIN <= val2 && val2 <= INT64_MAX && val <= val2 && + (val > INT64_MAX - OPTS_VISITOR_RANGE_MAX || + val2 < val + OPTS_VISITOR_RANGE_MAX)) { + ov->range_next.s = val; + ov->range_limit.s = val2; + ov->list_mode = LM_SIGNED_INTERVAL; + + /* as if entering on the top */ + *obj = ov->range_next.s; + return; + } + } } - error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "an int64 value"); + error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, + (ov->list_mode == LM_NONE) ? "an int64 value" : + "an int64 value or range"); } @@ -302,34 +409,49 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); const QemuOpt *opt; const char *str; + unsigned long long val; + char *endptr; + + if (ov->list_mode == LM_UNSIGNED_INTERVAL) { + *obj = ov->range_next.u; + return; + } opt = lookup_scalar(ov, name, errp); if (!opt) { return; } - str = opt->str; - if (str != NULL) { - while (isspace((unsigned char)*str)) { - ++str; - } - if (*str != '-' && *str != '\0') { - unsigned long long val; - char *endptr; + /* we've gotten past lookup_scalar() */ + assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS); - /* non-empty, non-negative subject sequence */ - errno = 0; - val = strtoull(str, &endptr, 0); - if (*endptr == '\0' && errno == 0 && val <= UINT64_MAX) { - *obj = val; - processed(ov, name); + if (parse_uint(str, &val, &endptr, 0) == 0 && val <= UINT64_MAX) { + if (*endptr == '\0') { + *obj = val; + processed(ov, name); + return; + } + if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { + unsigned long long val2; + + str = endptr + 1; + if (parse_uint_full(str, &val2, 0) == 0 && + val2 <= UINT64_MAX && val <= val2 && + val2 - val < OPTS_VISITOR_RANGE_MAX) { + ov->range_next.u = val; + ov->range_limit.u = val2; + ov->list_mode = LM_UNSIGNED_INTERVAL; + + /* as if entering on the top */ + *obj = ov->range_next.u; return; } } } error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, - "an uint64 value"); + (ov->list_mode == LM_NONE) ? "a uint64 value" : + "a uint64 value or range"); } @@ -365,7 +487,7 @@ opts_start_optional(Visitor *v, bool *present, const char *name, OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); /* we only support a single mandatory scalar field in a list node */ - assert(ov->repeated_opts == NULL); + assert(ov->list_mode == LM_NONE); *present = (lookup_distinct(ov, name, NULL) != NULL); } diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 401ee6e597..6451a21a28 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -12,6 +12,7 @@ */ #include "qemu-common.h" +#include "qapi/qmp/qobject.h" #include "qapi/qmp/qerror.h" #include "qapi/visitor.h" #include "qapi/visitor-impl.h" @@ -45,6 +46,22 @@ void visit_end_struct(Visitor *v, Error **errp) v->end_struct(v, errp); } +void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, + Error **errp) +{ + if (!error_is_set(errp) && v->start_implicit_struct) { + v->start_implicit_struct(v, obj, size, errp); + } +} + +void visit_end_implicit_struct(Visitor *v, Error **errp) +{ + assert(!error_is_set(errp)); + if (v->end_implicit_struct) { + v->end_implicit_struct(v, errp); + } +} + void visit_start_list(Visitor *v, const char *name, Error **errp) { if (!error_is_set(errp)) { @@ -82,6 +99,14 @@ void visit_end_optional(Visitor *v, Error **errp) } } +void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, + const char *name, Error **errp) +{ + if (!error_is_set(errp) && v->get_next_type) { + v->get_next_type(v, obj, qtypes, name, errp); + } +} + void visit_type_enum(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp) { @@ -238,8 +263,17 @@ void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) { + int64_t value; if (!error_is_set(errp)) { - (v->type_size ? v->type_size : v->type_uint64)(v, obj, name, errp); + if (v->type_size) { + v->type_size(v, obj, name, errp); + } else if (v->type_uint64) { + v->type_uint64(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + *obj = value; + } } } diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index 67fb127050..bf42c04ea6 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -41,13 +41,14 @@ static QmpInputVisitor *to_qiv(Visitor *v) } static QObject *qmp_input_get_object(QmpInputVisitor *qiv, - const char *name) + const char *name, + bool consume) { QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj; if (qobj) { if (name && qobject_type(qobj) == QTYPE_QDICT) { - if (qiv->stack[qiv->nb_stack - 1].h) { + if (qiv->stack[qiv->nb_stack - 1].h && consume) { g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name); } return qdict_get(qobject_to_qdict(qobj), name); @@ -117,7 +118,7 @@ static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); Error *err = NULL; if (!qobj || qobject_type(qobj) != QTYPE_QDICT) { @@ -144,10 +145,22 @@ static void qmp_input_end_struct(Visitor *v, Error **errp) qmp_input_pop(qiv, errp); } +static void qmp_input_start_implicit_struct(Visitor *v, void **obj, + size_t size, Error **errp) +{ + if (obj) { + *obj = g_malloc0(size); + } +} + +static void qmp_input_end_implicit_struct(Visitor *v, Error **errp) +{ +} + static void qmp_input_start_list(Visitor *v, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj || qobject_type(qobj) != QTYPE_QLIST) { error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", @@ -195,11 +208,24 @@ static void qmp_input_end_list(Visitor *v, Error **errp) qmp_input_pop(qiv, errp); } +static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects, + const char *name, Error **errp) +{ + QmpInputVisitor *qiv = to_qiv(v); + QObject *qobj = qmp_input_get_object(qiv, name, false); + + if (!qobj) { + error_set(errp, QERR_MISSING_PARAMETER, name ? name : "null"); + return; + } + *kind = qobjects[qobject_type(qobj)]; +} + static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj || qobject_type(qobj) != QTYPE_QINT) { error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", @@ -214,7 +240,7 @@ static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) { error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", @@ -229,7 +255,7 @@ static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) { error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", @@ -244,7 +270,7 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT && qobject_type(qobj) != QTYPE_QINT)) { @@ -264,7 +290,7 @@ static void qmp_input_start_optional(Visitor *v, bool *present, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name); + QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj) { *present = false; @@ -293,6 +319,8 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.start_struct = qmp_input_start_struct; v->visitor.end_struct = qmp_input_end_struct; + v->visitor.start_implicit_struct = qmp_input_start_implicit_struct; + v->visitor.end_implicit_struct = qmp_input_end_implicit_struct; v->visitor.start_list = qmp_input_start_list; v->visitor.next_list = qmp_input_next_list; v->visitor.end_list = qmp_input_end_list; @@ -302,6 +330,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.type_str = qmp_input_type_str; v->visitor.type_number = qmp_input_type_number; v->visitor.start_optional = qmp_input_start_optional; + v->visitor.get_next_type = qmp_input_get_next_type; qmp_input_push(v, obj, NULL); qobject_incref(obj); diff --git a/qdev-monitor.c b/qdev-monitor.c index e54dbc2c5d..410cdcbe97 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -75,24 +75,27 @@ static bool qdev_class_has_alias(DeviceClass *dc) return (qdev_class_get_alias(dc) != NULL); } -static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +static void qdev_print_class_devinfo(DeviceClass *dc) { - DeviceClass *dc; - bool *show_no_user = opaque; - - dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + DeviceCategory category; - if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { + if (!dc) { return; } - error_printf("name \"%s\"", object_class_get_name(klass)); + error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc))); if (dc->bus_type) { error_printf(", bus %s", dc->bus_type); } if (qdev_class_has_alias(dc)) { error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); } + error_printf(", categories"); + for (category = 0; category < DEVICE_CATEGORY_MAX; ++category) { + if (test_bit(category, dc->categories)) { + error_printf(" \"%s\"", qdev_category_get_name(category)); + } + } if (dc->desc) { error_printf(", desc \"%s\"", dc->desc); } @@ -102,6 +105,15 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque) error_printf("\n"); } +static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +{ + DeviceClass *dc; + + dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + + qdev_print_class_devinfo(dc); +} + static int set_property(const char *name, const char *value, void *opaque) { DeviceState *dev = opaque; @@ -139,6 +151,21 @@ static const char *find_typename_by_alias(const char *alias) return NULL; } +static void qdev_print_category_devices(DeviceCategory category) +{ + DeviceClass *dc; + GSList *list, *curr; + + list = object_class_get_list(TYPE_DEVICE, false); + for (curr = list; curr; curr = g_slist_next(curr)) { + dc = (DeviceClass *)object_class_dynamic_cast(curr->data, TYPE_DEVICE); + if (!dc->no_user && test_bit(category, dc->categories)) { + qdev_print_class_devinfo(dc); + } + } + g_slist_free(list); +} + int qdev_device_help(QemuOpts *opts) { const char *driver; @@ -147,8 +174,11 @@ int qdev_device_help(QemuOpts *opts) driver = qemu_opt_get(opts, "driver"); if (driver && is_help_option(driver)) { - bool show_no_user = false; - object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); + DeviceCategory category; + for (category = 0; category < DEVICE_CATEGORY_MAX; ++category) { + qdev_print_category_devices(category); + } + return 1; } @@ -360,7 +390,7 @@ static BusState *qbus_find(const char *path) /* find device */ if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); + g_assert_not_reached(); elem[0] = len = 0; } pos += len; @@ -397,7 +427,7 @@ static BusState *qbus_find(const char *path) /* find bus */ if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); + g_assert_not_reached(); elem[0] = len = 0; } pos += len; diff --git a/qemu-char.c b/qemu-char.c index c86ce4ba2e..62594965bd 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -281,7 +281,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) int64_t ti; int secs; - ti = qemu_get_clock_ms(rt_clock); + ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); if (d->timestamps_start == -1) d->timestamps_start = ti; ti -= d->timestamps_start; @@ -476,6 +476,46 @@ static void mux_chr_update_read_handler(CharDriverState *chr) mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); } +static bool muxes_realized; + +/** + * Called after processing of default and command-line-specified + * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached + * to a mux chardev. This is done here to ensure that + * output/prompts/banners are only displayed for the FE that has + * focus when initial command-line processing/machine init is + * completed. + * + * After this point, any new FE attached to any new or existing + * mux will receive CHR_EVENT_OPENED notifications for the BE + * immediately. + */ +static void muxes_realize_done(Notifier *notifier, void *unused) +{ + CharDriverState *chr; + + QTAILQ_FOREACH(chr, &chardevs, next) { + if (chr->is_mux) { + MuxDriver *d = chr->opaque; + int i; + + /* send OPENED to all already-attached FEs */ + for (i = 0; i < d->mux_cnt; i++) { + mux_chr_send_event(d, i, CHR_EVENT_OPENED); + } + /* mark mux as OPENED so any new FEs will immediately receive + * OPENED event + */ + qemu_chr_be_generic_open(chr); + } + } + muxes_realized = true; +} + +static Notifier muxes_realize_notify = { + .notify = muxes_realize_done, +}; + static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) { CharDriverState *chr; @@ -492,6 +532,11 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->chr_accept_input = mux_chr_accept_input; /* Frontend guest-open / -close notification is not support with muxes */ chr->chr_set_fe_open = NULL; + /* only default to opened state if we've realized the initial + * set of muxes + */ + chr->explicit_be_open = muxes_realized ? 0 : 1; + chr->is_mux = 1; return chr; } @@ -1097,8 +1142,8 @@ static void pty_chr_state(CharDriverState *chr, int connected) s->timer_tag = 0; } if (!s->connected) { - qemu_chr_be_generic_open(chr); s->connected = 1; + qemu_chr_be_generic_open(chr); s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr); } } @@ -2783,8 +2828,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, - Error **errp) +static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, + Error **errp) { CharDriverState *chr; RingBufCharDriver *d; @@ -2796,7 +2841,7 @@ static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, /* The size must be power of 2 */ if (d->size & (d->size - 1)) { - error_setg(errp, "size of memory chardev must be power of two"); + error_setg(errp, "size of ringbuf chardev must be power of two"); goto fail; } @@ -3105,17 +3150,17 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, backend->pipe->device = g_strdup(device); } -static void qemu_chr_parse_memory(QemuOpts *opts, ChardevBackend *backend, - Error **errp) +static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, + Error **errp) { int val; - backend->memory = g_new0(ChardevMemory, 1); + backend->ringbuf = g_new0(ChardevRingbuf, 1); val = qemu_opt_get_size(opts, "size", 0); if (val != 0) { - backend->memory->has_size = true; - backend->memory->size = val; + backend->ringbuf->has_size = true; + backend->ringbuf->size = val; } } @@ -3299,7 +3344,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in chr = qemu_chr_new_from_opts(opts, init, &err); if (error_is_set(&err)) { - fprintf(stderr, "%s\n", error_get_pretty(err)); + error_report("%s", error_get_pretty(err)); error_free(err); } if (chr && qemu_opt_get_bool(opts, "mux", 0)) { @@ -3723,8 +3768,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_VC: chr = vc_init(backend->vc); break; + case CHARDEV_BACKEND_KIND_RINGBUF: case CHARDEV_BACKEND_KIND_MEMORY: - chr = qemu_chr_open_memory(backend->memory, errp); + chr = qemu_chr_open_ringbuf(backend->ringbuf, errp); break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); @@ -3774,8 +3820,8 @@ static void register_types(void) register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); - register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, - qemu_chr_parse_memory); + register_char_driver_qapi("ringbuf", CHARDEV_BACKEND_KIND_RINGBUF, + qemu_chr_parse_ringbuf); register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, qemu_chr_parse_file_out); register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO, @@ -3794,6 +3840,14 @@ static void register_types(void) qemu_chr_parse_pipe); register_char_driver_qapi("mux", CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux); + /* Bug-compatibility: */ + register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, + qemu_chr_parse_ringbuf); + /* this must be done after machine init, since we register FEs with muxes + * as part of realize functions like serial_isa_realizefn when -nographic + * is specified + */ + qemu_add_machine_init_done_notifier(&muxes_realize_notify); } type_init(register_types); diff --git a/qemu-coroutine-io.c b/qemu-coroutine-io.c index c4df35a640..054ca70627 100644 --- a/qemu-coroutine-io.c +++ b/qemu-coroutine-io.c @@ -26,6 +26,7 @@ #include "qemu/sockets.h" #include "block/coroutine.h" #include "qemu/iov.h" +#include "qemu/main-loop.h" ssize_t coroutine_fn qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt, diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c index d9fea4989d..aeb33b9118 100644 --- a/qemu-coroutine-lock.c +++ b/qemu-coroutine-lock.c @@ -88,16 +88,32 @@ static bool qemu_co_queue_do_restart(CoQueue *queue, bool single) return true; } -bool qemu_co_queue_next(CoQueue *queue) +bool coroutine_fn qemu_co_queue_next(CoQueue *queue) { + assert(qemu_in_coroutine()); return qemu_co_queue_do_restart(queue, true); } -void qemu_co_queue_restart_all(CoQueue *queue) +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue) { + assert(qemu_in_coroutine()); qemu_co_queue_do_restart(queue, false); } +bool qemu_co_enter_next(CoQueue *queue) +{ + Coroutine *next; + + next = QTAILQ_FIRST(&queue->entries); + if (!next) { + return false; + } + + QTAILQ_REMOVE(&queue->entries, next, co_queue_next); + qemu_coroutine_enter(next, NULL); + return true; +} + bool qemu_co_queue_empty(CoQueue *queue) { return (QTAILQ_FIRST(&queue->entries) == NULL); diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c index 169ce5ccc9..f6db978c1d 100644 --- a/qemu-coroutine-sleep.c +++ b/qemu-coroutine-sleep.c @@ -26,14 +26,14 @@ static void co_sleep_cb(void *opaque) qemu_coroutine_enter(sleep_cb->co, NULL); } -void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns) +void coroutine_fn co_sleep_ns(QEMUClockType type, int64_t ns) { CoSleepCB sleep_cb = { .co = qemu_coroutine_self(), }; - sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb); - qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns); + sleep_cb.ts = timer_new(type, SCALE_NS, co_sleep_cb, &sleep_cb); + timer_mod(sleep_cb.ts, qemu_clock_get_ns(type) + ns); qemu_coroutine_yield(); - qemu_del_timer(sleep_cb.ts); - qemu_free_timer(sleep_cb.ts); + timer_del(sleep_cb.ts); + timer_free(sleep_cb.ts); } diff --git a/qemu-img.c b/qemu-img.c index c55ca5c557..b9a848db74 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -396,6 +396,9 @@ static int img_create(int argc, char **argv) } img_size = (uint64_t)sval; } + if (optind != argc) { + help(); + } if (options && is_help_option(options)) { return print_block_option_help(filename, fmt); @@ -573,7 +576,7 @@ static int img_check(int argc, char **argv) break; } } - if (optind >= argc) { + if (optind != argc - 1) { help(); } filename = argv[optind++]; @@ -684,7 +687,7 @@ static int img_commit(int argc, char **argv) break; } } - if (optind >= argc) { + if (optind != argc - 1) { help(); } filename = argv[optind++]; @@ -930,7 +933,7 @@ static int img_compare(int argc, char **argv) } - if (optind > argc - 2) { + if (optind != argc - 2) { help(); } filename1 = argv[optind++]; @@ -1741,7 +1744,7 @@ static int img_info(int argc, char **argv) break; } } - if (optind >= argc) { + if (optind != argc - 1) { help(); } filename = argv[optind++]; @@ -1842,7 +1845,7 @@ static int img_snapshot(int argc, char **argv) } } - if (optind >= argc) { + if (optind != argc - 1) { help(); } filename = argv[optind++]; @@ -1953,7 +1956,7 @@ static int img_rebase(int argc, char **argv) progress = 0; } - if ((optind >= argc) || (!unsafe && !out_baseimg)) { + if ((optind != argc - 1) || (!unsafe && !out_baseimg)) { help(); } filename = argv[optind++]; @@ -2232,7 +2235,7 @@ static int img_resize(int argc, char **argv) break; } } - if (optind >= argc) { + if (optind != argc - 1) { help(); } filename = argv[optind++]; @@ -2319,6 +2322,10 @@ int main(int argc, char **argv) const img_cmd_t *cmd; const char *cmdname; +#ifdef CONFIG_POSIX + signal(SIGPIPE, SIG_IGN); +#endif + error_set_progname(argv[0]); qemu_init_main_loop(); diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index ffbcf31cfc..f91b6c4f02 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -10,6 +10,7 @@ #include "qemu-io.h" #include "block/block_int.h" +#include "qemu/main-loop.h" #define CMD_NOFILE_OK 0x01 @@ -335,6 +335,10 @@ int main(int argc, char **argv) int opt_index = 0; int flags = BDRV_O_UNMAP; +#ifdef CONFIG_POSIX + signal(SIGPIPE, SIG_IGN); +#endif + progname = basename(argv[0]); while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { diff --git a/qemu-nbd.c b/qemu-nbd.c index 9c31d45706..f044546c28 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -19,6 +19,7 @@ #include "qemu-common.h" #include "block/block.h" #include "block/nbd.h" +#include "qemu/main-loop.h" #include <stdarg.h> #include <stdio.h> diff --git a/qemu-options.hx b/qemu-options.hx index 2dbfd42a8c..d15338e879 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -844,7 +844,8 @@ you can totally disable graphical output so that QEMU is a simple command line application. The emulated serial port is redirected on the console and muxed with the monitor (unless redirected elsewhere explicitly). Therefore, you can still use QEMU to debug a Linux kernel -with a serial console. +with a serial console. Use @key{C-a h} for help on switching between +the console and monitor. ETEXI DEF("curses", 0, QEMU_OPTION_curses, @@ -1782,7 +1783,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev msmouse,id=id[,mux=on|off]\n" "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n" " [,mux=on|off]\n" - "-chardev memory,id=id[,size=size]\n" + "-chardev ringbuf,id=id[,size=size]\n" "-chardev file,id=id,path=path[,mux=on|off]\n" "-chardev pipe,id=id,path=path[,mux=on|off]\n" #ifdef _WIN32 @@ -1820,7 +1821,7 @@ Backend is one of: @option{udp}, @option{msmouse}, @option{vc}, -@option{memory}, +@option{ringbuf}, @option{file}, @option{pipe}, @option{console}, @@ -1929,7 +1930,7 @@ the console, in pixels. @option{cols} and @option{rows} specify that the console be sized to fit a text console with the given dimensions. -@item -chardev memory ,id=@var{id} [,size=@var{size}] +@item -chardev ringbuf ,id=@var{id} [,size=@var{size}] Create a ring buffer with fixed size @option{size}. @var{size} must be a power of two, and defaults to @code{64K}). diff --git a/qemu-seccomp.c b/qemu-seccomp.c index ca123bfeba..37d38f881c 100644 --- a/qemu-seccomp.c +++ b/qemu-seccomp.c @@ -26,13 +26,11 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(timer_gettime), 254 }, { SCMP_SYS(futex), 253 }, { SCMP_SYS(select), 252 }, -#if defined(__x86_64__) { SCMP_SYS(recvfrom), 251 }, { SCMP_SYS(sendto), 250 }, -#elif defined(__i386__) { SCMP_SYS(socketcall), 250 }, -#endif { SCMP_SYS(read), 249 }, + { SCMP_SYS(io_submit), 249 }, { SCMP_SYS(brk), 248 }, { SCMP_SYS(clone), 247 }, { SCMP_SYS(mmap), 247 }, @@ -40,7 +38,6 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(execve), 245 }, { SCMP_SYS(open), 245 }, { SCMP_SYS(ioctl), 245 }, -#if defined(__x86_64__) { SCMP_SYS(socket), 245 }, { SCMP_SYS(setsockopt), 245 }, { SCMP_SYS(recvmsg), 245 }, @@ -51,9 +48,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(bind), 245 }, { SCMP_SYS(listen), 245 }, { SCMP_SYS(semget), 245 }, -#elif defined(__i386__) { SCMP_SYS(ipc), 245 }, -#endif { SCMP_SYS(gettimeofday), 245 }, { SCMP_SYS(readlink), 245 }, { SCMP_SYS(access), 245 }, @@ -64,7 +59,6 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(statfs), 245 }, { SCMP_SYS(unlink), 245 }, { SCMP_SYS(wait4), 245 }, -#if defined(__i386__) { SCMP_SYS(fcntl64), 245 }, { SCMP_SYS(fstat64), 245 }, { SCMP_SYS(stat64), 245 }, @@ -77,7 +71,6 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(_llseek), 245 }, { SCMP_SYS(mmap2), 245 }, { SCMP_SYS(sigprocmask), 245 }, -#endif { SCMP_SYS(sched_getparam), 245 }, { SCMP_SYS(sched_getscheduler), 245 }, { SCMP_SYS(fstat), 245 }, @@ -116,7 +109,6 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(lseek), 245 }, { SCMP_SYS(pselect6), 245 }, { SCMP_SYS(fork), 245 }, - { SCMP_SYS(eventfd), 245 }, { SCMP_SYS(rt_sigprocmask), 245 }, { SCMP_SYS(write), 244 }, { SCMP_SYS(fcntl), 243 }, @@ -145,21 +137,17 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(epoll_create), 242 }, { SCMP_SYS(epoll_ctl), 242 }, { SCMP_SYS(epoll_wait), 242 }, -#if defined(__i386__) { SCMP_SYS(waitpid), 242 }, -#elif defined(__x86_64__) { SCMP_SYS(getsockname), 242 }, { SCMP_SYS(getpeername), 242 }, { SCMP_SYS(accept4), 242 }, { SCMP_SYS(newfstatat), 241 }, { SCMP_SYS(shutdown), 241 }, { SCMP_SYS(getsockopt), 241 }, - { SCMP_SYS(semctl), 241 }, { SCMP_SYS(semop), 241 }, { SCMP_SYS(semtimedop), 241 }, { SCMP_SYS(epoll_ctl_old), 241 }, { SCMP_SYS(epoll_wait_old), 241 }, -#endif { SCMP_SYS(epoll_pwait), 241 }, { SCMP_SYS(epoll_create1), 241 }, { SCMP_SYS(ppoll), 241 }, @@ -174,7 +162,6 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(getresuid), 241 }, { SCMP_SYS(getresgid), 241 }, { SCMP_SYS(getgroups), 241 }, -#if defined(__i386__) { SCMP_SYS(getresuid32), 241 }, { SCMP_SYS(getresgid32), 241 }, { SCMP_SYS(getgroups32), 241 }, @@ -193,7 +180,6 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(lstat64), 241 }, { SCMP_SYS(sendfile64), 241 }, { SCMP_SYS(ugetrlimit), 241 }, -#endif { SCMP_SYS(alarm), 241 }, { SCMP_SYS(rt_sigsuspend), 241 }, { SCMP_SYS(rt_sigqueueinfo), 241 }, @@ -205,12 +191,10 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(lchown), 241 }, { SCMP_SYS(fchownat), 241 }, { SCMP_SYS(fstatfs), 241 }, - { SCMP_SYS(sendfile), 241 }, { SCMP_SYS(getitimer), 241 }, { SCMP_SYS(syncfs), 241 }, { SCMP_SYS(fsync), 241 }, { SCMP_SYS(fchdir), 241 }, - { SCMP_SYS(flock), 241 }, { SCMP_SYS(msync), 241 }, { SCMP_SYS(sched_setparam), 241 }, { SCMP_SYS(sched_setscheduler), 241 }, @@ -231,8 +215,10 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(recvmmsg), 241 }, { SCMP_SYS(prlimit64), 241 }, { SCMP_SYS(waitid), 241 }, + { SCMP_SYS(io_cancel), 241 }, { SCMP_SYS(io_setup), 241 }, - { SCMP_SYS(io_destroy), 241 } + { SCMP_SYS(io_destroy), 241 }, + { SCMP_SYS(arch_prctl), 240 } }; int seccomp_start(void) diff --git a/qemu-timer.c b/qemu-timer.c index b2d95e2fec..95ff47fef3 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -33,276 +33,277 @@ #include <pthread.h> #endif -#ifdef _WIN32 -#include <mmsystem.h> +#ifdef CONFIG_PPOLL +#include <poll.h> +#endif + +#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK +#include <sys/prctl.h> #endif /***********************************************************/ /* timers */ -#define QEMU_CLOCK_REALTIME 0 -#define QEMU_CLOCK_VIRTUAL 1 -#define QEMU_CLOCK_HOST 2 - -struct QEMUClock { - QEMUTimer *active_timers; +typedef struct QEMUClock { + QLIST_HEAD(, QEMUTimerList) timerlists; NotifierList reset_notifiers; int64_t last; - int type; + QEMUClockType type; bool enabled; -}; +} QEMUClock; -struct QEMUTimer { - int64_t expire_time; /* in nanoseconds */ - QEMUClock *clock; - QEMUTimerCB *cb; - void *opaque; - QEMUTimer *next; - int scale; -}; +QEMUTimerListGroup main_loop_tlg; +QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; -struct qemu_alarm_timer { - char const *name; - int (*start)(struct qemu_alarm_timer *t); - void (*stop)(struct qemu_alarm_timer *t); - void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns); -#if defined(__linux__) - timer_t timer; - int fd; -#elif defined(_WIN32) - HANDLE timer; -#endif - bool expired; - bool pending; +/* A QEMUTimerList is a list of timers attached to a clock. More + * than one QEMUTimerList can be attached to each clock, for instance + * used by different AioContexts / threads. Each clock also has + * a list of the QEMUTimerLists associated with it, in order that + * reenabling the clock can call all the notifiers. + */ + +struct QEMUTimerList { + QEMUClock *clock; + QEMUTimer *active_timers; + QLIST_ENTRY(QEMUTimerList) list; + QEMUTimerListNotifyCB *notify_cb; + void *notify_opaque; }; -static struct qemu_alarm_timer *alarm_timer; +/** + * qemu_clock_ptr: + * @type: type of clock + * + * Translate a clock type into a pointer to QEMUClock object. + * + * Returns: a pointer to the QEMUClock object + */ +static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) +{ + return &qemu_clocks[type]; +} -static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) +static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) { return timer_head && (timer_head->expire_time <= current_time); } -static int64_t qemu_next_alarm_deadline(void) +QEMUTimerList *timerlist_new(QEMUClockType type, + QEMUTimerListNotifyCB *cb, + void *opaque) { - int64_t delta = INT64_MAX; - int64_t rtdelta; - - if (!use_icount && vm_clock->enabled && vm_clock->active_timers) { - delta = vm_clock->active_timers->expire_time - - qemu_get_clock_ns(vm_clock); - } - if (host_clock->enabled && host_clock->active_timers) { - int64_t hdelta = host_clock->active_timers->expire_time - - qemu_get_clock_ns(host_clock); - if (hdelta < delta) { - delta = hdelta; - } - } - if (rt_clock->enabled && rt_clock->active_timers) { - rtdelta = (rt_clock->active_timers->expire_time - - qemu_get_clock_ns(rt_clock)); - if (rtdelta < delta) { - delta = rtdelta; - } - } + QEMUTimerList *timer_list; + QEMUClock *clock = qemu_clock_ptr(type); - return delta; + timer_list = g_malloc0(sizeof(QEMUTimerList)); + timer_list->clock = clock; + timer_list->notify_cb = cb; + timer_list->notify_opaque = opaque; + QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list); + return timer_list; } -static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) +void timerlist_free(QEMUTimerList *timer_list) { - int64_t nearest_delta_ns = qemu_next_alarm_deadline(); - if (nearest_delta_ns < INT64_MAX) { - t->rearm(t, nearest_delta_ns); + assert(!timerlist_has_timers(timer_list)); + if (timer_list->clock) { + QLIST_REMOVE(timer_list, list); } + g_free(timer_list); } -/* TODO: MIN_TIMER_REARM_NS should be optimized */ -#define MIN_TIMER_REARM_NS 250000 - -#ifdef _WIN32 - -static int mm_start_timer(struct qemu_alarm_timer *t); -static void mm_stop_timer(struct qemu_alarm_timer *t); -static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); - -static int win32_start_timer(struct qemu_alarm_timer *t); -static void win32_stop_timer(struct qemu_alarm_timer *t); -static void win32_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); - -#else - -static int unix_start_timer(struct qemu_alarm_timer *t); -static void unix_stop_timer(struct qemu_alarm_timer *t); -static void unix_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); - -#ifdef __linux__ - -static int dynticks_start_timer(struct qemu_alarm_timer *t); -static void dynticks_stop_timer(struct qemu_alarm_timer *t); -static void dynticks_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); - -#endif /* __linux__ */ - -#endif /* _WIN32 */ +static void qemu_clock_init(QEMUClockType type) +{ + QEMUClock *clock = qemu_clock_ptr(type); -static struct qemu_alarm_timer alarm_timers[] = { -#ifndef _WIN32 -#ifdef __linux__ - {"dynticks", dynticks_start_timer, - dynticks_stop_timer, dynticks_rearm_timer}, -#endif - {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer}, -#else - {"mmtimer", mm_start_timer, mm_stop_timer, mm_rearm_timer}, - {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer}, -#endif - {NULL, } -}; + clock->type = type; + clock->enabled = true; + clock->last = INT64_MIN; + QLIST_INIT(&clock->timerlists); + notifier_list_init(&clock->reset_notifiers); + main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL); +} -static void show_available_alarms(void) +bool qemu_clock_use_for_deadline(QEMUClockType type) { - int i; - - printf("Available alarm timers, in order of precedence:\n"); - for (i = 0; alarm_timers[i].name; i++) - printf("%s\n", alarm_timers[i].name); + return !(use_icount && (type == QEMU_CLOCK_VIRTUAL)); } -void configure_alarms(char const *opt) +void qemu_clock_notify(QEMUClockType type) { - int i; - int cur = 0; - int count = ARRAY_SIZE(alarm_timers) - 1; - char *arg; - char *name; - struct qemu_alarm_timer tmp; + QEMUTimerList *timer_list; + QEMUClock *clock = qemu_clock_ptr(type); + QLIST_FOREACH(timer_list, &clock->timerlists, list) { + timerlist_notify(timer_list); + } +} - if (is_help_option(opt)) { - show_available_alarms(); - exit(0); +void qemu_clock_enable(QEMUClockType type, bool enabled) +{ + QEMUClock *clock = qemu_clock_ptr(type); + bool old = clock->enabled; + clock->enabled = enabled; + if (enabled && !old) { + qemu_clock_notify(type); } +} - arg = g_strdup(opt); +bool timerlist_has_timers(QEMUTimerList *timer_list) +{ + return !!timer_list->active_timers; +} - /* Reorder the array */ - name = strtok(arg, ","); - while (name) { - for (i = 0; i < count && alarm_timers[i].name; i++) { - if (!strcmp(alarm_timers[i].name, name)) - break; - } +bool qemu_clock_has_timers(QEMUClockType type) +{ + return timerlist_has_timers( + main_loop_tlg.tl[type]); +} - if (i == count) { - fprintf(stderr, "Unknown clock %s\n", name); - goto next; - } +bool timerlist_expired(QEMUTimerList *timer_list) +{ + return (timer_list->active_timers && + timer_list->active_timers->expire_time < + qemu_clock_get_ns(timer_list->clock->type)); +} - if (i < cur) - /* Ignore */ - goto next; +bool qemu_clock_expired(QEMUClockType type) +{ + return timerlist_expired( + main_loop_tlg.tl[type]); +} - /* Swap */ - tmp = alarm_timers[i]; - alarm_timers[i] = alarm_timers[cur]; - alarm_timers[cur] = tmp; +/* + * As above, but return -1 for no deadline, and do not cap to 2^32 + * as we know the result is always positive. + */ + +int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) +{ + int64_t delta; - cur++; -next: - name = strtok(NULL, ","); + if (!timer_list->clock->enabled || !timer_list->active_timers) { + return -1; } - g_free(arg); + delta = timer_list->active_timers->expire_time - + qemu_clock_get_ns(timer_list->clock->type); - if (cur) { - /* Disable remaining timers */ - for (i = cur; i < count; i++) - alarm_timers[i].name = NULL; - } else { - show_available_alarms(); - exit(1); + if (delta <= 0) { + return 0; } -} -QEMUClock *rt_clock; -QEMUClock *vm_clock; -QEMUClock *host_clock; + return delta; +} -static QEMUClock *qemu_new_clock(int type) +/* Calculate the soonest deadline across all timerlists attached + * to the clock. This is used for the icount timeout so we + * ignore whether or not the clock should be used in deadline + * calculations. + */ +int64_t qemu_clock_deadline_ns_all(QEMUClockType type) { - QEMUClock *clock; - - clock = g_malloc0(sizeof(QEMUClock)); - clock->type = type; - clock->enabled = true; - clock->last = INT64_MIN; - notifier_list_init(&clock->reset_notifiers); - return clock; + int64_t deadline = -1; + QEMUTimerList *timer_list; + QEMUClock *clock = qemu_clock_ptr(type); + QLIST_FOREACH(timer_list, &clock->timerlists, list) { + deadline = qemu_soonest_timeout(deadline, + timerlist_deadline_ns(timer_list)); + } + return deadline; } -void qemu_clock_enable(QEMUClock *clock, bool enabled) +QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) { - bool old = clock->enabled; - clock->enabled = enabled; - if (enabled && !old) { - qemu_rearm_alarm_timer(alarm_timer); - } + return timer_list->clock->type; } -int64_t qemu_clock_has_timers(QEMUClock *clock) +QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) { - return !!clock->active_timers; + return main_loop_tlg.tl[type]; } -int64_t qemu_clock_expired(QEMUClock *clock) +void timerlist_notify(QEMUTimerList *timer_list) { - return (clock->active_timers && - clock->active_timers->expire_time < qemu_get_clock_ns(clock)); + if (timer_list->notify_cb) { + timer_list->notify_cb(timer_list->notify_opaque); + } else { + qemu_notify_event(); + } } -int64_t qemu_clock_deadline(QEMUClock *clock) +/* Transition function to convert a nanosecond timeout to ms + * This is used where a system does not support ppoll + */ +int qemu_timeout_ns_to_ms(int64_t ns) { - /* To avoid problems with overflow limit this to 2^32. */ - int64_t delta = INT32_MAX; + int64_t ms; + if (ns < 0) { + return -1; + } - if (clock->active_timers) { - delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock); + if (!ns) { + return 0; } - if (delta < 0) { - delta = 0; + + /* Always round up, because it's better to wait too long than to wait too + * little and effectively busy-wait + */ + ms = (ns + SCALE_MS - 1) / SCALE_MS; + + /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */ + if (ms > (int64_t) INT32_MAX) { + ms = INT32_MAX; } - return delta; + + return (int) ms; } -QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, - QEMUTimerCB *cb, void *opaque) + +/* qemu implementation of g_poll which uses a nanosecond timeout but is + * otherwise identical to g_poll + */ +int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) { - QEMUTimer *ts; +#ifdef CONFIG_PPOLL + if (timeout < 0) { + return ppoll((struct pollfd *)fds, nfds, NULL, NULL); + } else { + struct timespec ts; + ts.tv_sec = timeout / 1000000000LL; + ts.tv_nsec = timeout % 1000000000LL; + return ppoll((struct pollfd *)fds, nfds, &ts, NULL); + } +#else + return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout)); +#endif +} - ts = g_malloc0(sizeof(QEMUTimer)); - ts->clock = clock; + +void timer_init(QEMUTimer *ts, + QEMUTimerList *timer_list, int scale, + QEMUTimerCB *cb, void *opaque) +{ + ts->timer_list = timer_list; ts->cb = cb; ts->opaque = opaque; ts->scale = scale; - return ts; } -void qemu_free_timer(QEMUTimer *ts) +void timer_free(QEMUTimer *ts) { g_free(ts); } /* stop a timer, but do not dealloc it */ -void qemu_del_timer(QEMUTimer *ts) +void timer_del(QEMUTimer *ts) { QEMUTimer **pt, *t; /* NOTE: this code must be signal safe because - qemu_timer_expired() can be called from a signal. */ - pt = &ts->clock->active_timers; + timer_expired() can be called from a signal. */ + pt = &ts->timer_list->active_timers; for(;;) { t = *pt; if (!t) @@ -317,19 +318,19 @@ void qemu_del_timer(QEMUTimer *ts) /* modify the current timer so that it will be fired when current_time >= expire_time. The corresponding callback will be called. */ -void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) +void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) { QEMUTimer **pt, *t; - qemu_del_timer(ts); + timer_del(ts); /* add the timer in the sorted list */ /* NOTE: this code must be signal safe because - qemu_timer_expired() can be called from a signal. */ - pt = &ts->clock->active_timers; + timer_expired() can be called from a signal. */ + pt = &ts->timer_list->active_timers; for(;;) { t = *pt; - if (!qemu_timer_expired_ns(t, expire_time)) { + if (!timer_expired_ns(t, expire_time)) { break; } pt = &t->next; @@ -339,27 +340,22 @@ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) *pt = ts; /* Rearm if necessary */ - if (pt == &ts->clock->active_timers) { - if (!alarm_timer->pending) { - qemu_rearm_alarm_timer(alarm_timer); - } + if (pt == &ts->timer_list->active_timers) { /* Interrupt execution to force deadline recalculation. */ - qemu_clock_warp(ts->clock); - if (use_icount) { - qemu_notify_event(); - } + qemu_clock_warp(ts->timer_list->clock->type); + timerlist_notify(ts->timer_list); } } -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) +void timer_mod(QEMUTimer *ts, int64_t expire_time) { - qemu_mod_timer_ns(ts, expire_time * ts->scale); + timer_mod_ns(ts, expire_time * ts->scale); } -bool qemu_timer_pending(QEMUTimer *ts) +bool timer_pending(QEMUTimer *ts) { QEMUTimer *t; - for (t = ts->clock->active_timers; t != NULL; t = t->next) { + for (t = ts->timer_list->active_timers; t != NULL; t = t->next) { if (t == ts) { return true; } @@ -367,39 +363,90 @@ bool qemu_timer_pending(QEMUTimer *ts) return false; } -bool qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) +bool timer_expired(QEMUTimer *timer_head, int64_t current_time) { - return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale); + return timer_expired_ns(timer_head, current_time * timer_head->scale); } -void qemu_run_timers(QEMUClock *clock) +bool timerlist_run_timers(QEMUTimerList *timer_list) { QEMUTimer *ts; int64_t current_time; + bool progress = false; - if (!clock->enabled) - return; + if (!timer_list->clock->enabled) { + return progress; + } - current_time = qemu_get_clock_ns(clock); + current_time = qemu_clock_get_ns(timer_list->clock->type); for(;;) { - ts = clock->active_timers; - if (!qemu_timer_expired_ns(ts, current_time)) { + ts = timer_list->active_timers; + if (!timer_expired_ns(ts, current_time)) { break; } /* remove timer from the list before calling the callback */ - clock->active_timers = ts->next; + timer_list->active_timers = ts->next; ts->next = NULL; /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); + progress = true; + } + return progress; +} + +bool qemu_clock_run_timers(QEMUClockType type) +{ + return timerlist_run_timers(main_loop_tlg.tl[type]); +} + +void timerlistgroup_init(QEMUTimerListGroup *tlg, + QEMUTimerListNotifyCB *cb, void *opaque) +{ + QEMUClockType type; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { + tlg->tl[type] = timerlist_new(type, cb, opaque); } } -int64_t qemu_get_clock_ns(QEMUClock *clock) +void timerlistgroup_deinit(QEMUTimerListGroup *tlg) +{ + QEMUClockType type; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { + timerlist_free(tlg->tl[type]); + } +} + +bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) +{ + QEMUClockType type; + bool progress = false; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { + progress |= timerlist_run_timers(tlg->tl[type]); + } + return progress; +} + +int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) +{ + int64_t deadline = -1; + QEMUClockType type; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { + if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) { + deadline = qemu_soonest_timeout(deadline, + timerlist_deadline_ns( + tlg->tl[type])); + } + } + return deadline; +} + +int64_t qemu_clock_get_ns(QEMUClockType type) { int64_t now, last; + QEMUClock *clock = qemu_clock_ptr(type); - switch(clock->type) { + switch (type) { case QEMU_CLOCK_REALTIME: return get_clock(); default: @@ -420,361 +467,44 @@ int64_t qemu_get_clock_ns(QEMUClock *clock) } } -void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier) +void qemu_clock_register_reset_notifier(QEMUClockType type, + Notifier *notifier) { + QEMUClock *clock = qemu_clock_ptr(type); notifier_list_add(&clock->reset_notifiers, notifier); } -void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier) +void qemu_clock_unregister_reset_notifier(QEMUClockType type, + Notifier *notifier) { notifier_remove(notifier); } void init_clocks(void) { - if (!rt_clock) { - rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); - vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); - host_clock = qemu_new_clock(QEMU_CLOCK_HOST); - } -} - -uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts) -{ - return qemu_timer_pending(ts) ? ts->expire_time : -1; -} - -void qemu_run_all_timers(void) -{ - alarm_timer->pending = false; - - /* vm time timers */ - qemu_run_timers(vm_clock); - qemu_run_timers(rt_clock); - qemu_run_timers(host_clock); - - /* rearm timer, if not periodic */ - if (alarm_timer->expired) { - alarm_timer->expired = false; - qemu_rearm_alarm_timer(alarm_timer); + QEMUClockType type; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { + qemu_clock_init(type); } -} -#ifdef _WIN32 -static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused) -#else -static void host_alarm_handler(int host_signum) +#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK + prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); #endif -{ - struct qemu_alarm_timer *t = alarm_timer; - if (!t) - return; - - t->expired = true; - t->pending = true; - qemu_notify_event(); -} - -#if defined(__linux__) - -#include "qemu/compatfd.h" - -static int dynticks_start_timer(struct qemu_alarm_timer *t) -{ - struct sigevent ev; - timer_t host_timer; - struct sigaction act; - - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - - /* - * Initialize ev struct to 0 to avoid valgrind complaining - * about uninitialized data in timer_create call - */ - memset(&ev, 0, sizeof(ev)); - ev.sigev_value.sival_int = 0; - ev.sigev_notify = SIGEV_SIGNAL; -#ifdef CONFIG_SIGEV_THREAD_ID - if (qemu_signalfd_available()) { - ev.sigev_notify = SIGEV_THREAD_ID; - ev._sigev_un._tid = qemu_get_thread_id(); - } -#endif /* CONFIG_SIGEV_THREAD_ID */ - ev.sigev_signo = SIGALRM; - - if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { - perror("timer_create"); - return -1; - } - - t->timer = host_timer; - - return 0; -} - -static void dynticks_stop_timer(struct qemu_alarm_timer *t) -{ - timer_t host_timer = t->timer; - - timer_delete(host_timer); -} - -static void dynticks_rearm_timer(struct qemu_alarm_timer *t, - int64_t nearest_delta_ns) -{ - timer_t host_timer = t->timer; - struct itimerspec timeout; - int64_t current_ns; - - if (nearest_delta_ns < MIN_TIMER_REARM_NS) - nearest_delta_ns = MIN_TIMER_REARM_NS; - - /* check whether a timer is already running */ - if (timer_gettime(host_timer, &timeout)) { - perror("gettime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } - current_ns = timeout.it_value.tv_sec * 1000000000LL + timeout.it_value.tv_nsec; - if (current_ns && current_ns <= nearest_delta_ns) - return; - - timeout.it_interval.tv_sec = 0; - timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ - timeout.it_value.tv_sec = nearest_delta_ns / 1000000000; - timeout.it_value.tv_nsec = nearest_delta_ns % 1000000000; - if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { - perror("settime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } -} - -#endif /* defined(__linux__) */ - -#if !defined(_WIN32) - -static int unix_start_timer(struct qemu_alarm_timer *t) -{ - struct sigaction act; - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - return 0; -} - -static void unix_rearm_timer(struct qemu_alarm_timer *t, - int64_t nearest_delta_ns) -{ - struct itimerval itv; - int err; - - if (nearest_delta_ns < MIN_TIMER_REARM_NS) - nearest_delta_ns = MIN_TIMER_REARM_NS; - - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 0; /* 0 for one-shot timer */ - itv.it_value.tv_sec = nearest_delta_ns / 1000000000; - itv.it_value.tv_usec = (nearest_delta_ns % 1000000000) / 1000; - err = setitimer(ITIMER_REAL, &itv, NULL); - if (err) { - perror("setitimer"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } -} - -static void unix_stop_timer(struct qemu_alarm_timer *t) -{ - struct itimerval itv; - - memset(&itv, 0, sizeof(itv)); - setitimer(ITIMER_REAL, &itv, NULL); -} - -#endif /* !defined(_WIN32) */ - - -#ifdef _WIN32 - -static MMRESULT mm_timer; -static TIMECAPS mm_tc; - -static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg, - DWORD_PTR dwUser, DWORD_PTR dw1, - DWORD_PTR dw2) -{ - struct qemu_alarm_timer *t = alarm_timer; - if (!t) { - return; - } - t->expired = true; - t->pending = true; - qemu_notify_event(); } -static int mm_start_timer(struct qemu_alarm_timer *t) +uint64_t timer_expire_time_ns(QEMUTimer *ts) { - timeGetDevCaps(&mm_tc, sizeof(mm_tc)); - return 0; + return timer_pending(ts) ? ts->expire_time : -1; } -static void mm_stop_timer(struct qemu_alarm_timer *t) +bool qemu_clock_run_all_timers(void) { - if (mm_timer) { - timeKillEvent(mm_timer); - } -} + bool progress = false; + QEMUClockType type; -static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta) -{ - int64_t nearest_delta_ms = delta / 1000000; - if (nearest_delta_ms < mm_tc.wPeriodMin) { - nearest_delta_ms = mm_tc.wPeriodMin; - } else if (nearest_delta_ms > mm_tc.wPeriodMax) { - nearest_delta_ms = mm_tc.wPeriodMax; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { + progress |= qemu_clock_run_timers(type); } - if (mm_timer) { - timeKillEvent(mm_timer); - } - mm_timer = timeSetEvent((UINT)nearest_delta_ms, - mm_tc.wPeriodMin, - mm_alarm_handler, - (DWORD_PTR)t, - TIME_ONESHOT | TIME_CALLBACK_FUNCTION); - - if (!mm_timer) { - fprintf(stderr, "Failed to re-arm win32 alarm timer\n"); - timeEndPeriod(mm_tc.wPeriodMin); - exit(1); - } + return progress; } - -static int win32_start_timer(struct qemu_alarm_timer *t) -{ - HANDLE hTimer; - BOOLEAN success; - - /* If you call ChangeTimerQueueTimer on a one-shot timer (its period - is zero) that has already expired, the timer is not updated. Since - creating a new timer is relatively expensive, set a bogus one-hour - interval in the dynticks case. */ - success = CreateTimerQueueTimer(&hTimer, - NULL, - host_alarm_handler, - t, - 1, - 3600000, - WT_EXECUTEINTIMERTHREAD); - - if (!success) { - fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", - GetLastError()); - return -1; - } - - t->timer = hTimer; - return 0; -} - -static void win32_stop_timer(struct qemu_alarm_timer *t) -{ - HANDLE hTimer = t->timer; - - if (hTimer) { - DeleteTimerQueueTimer(NULL, hTimer, NULL); - } -} - -static void win32_rearm_timer(struct qemu_alarm_timer *t, - int64_t nearest_delta_ns) -{ - HANDLE hTimer = t->timer; - int64_t nearest_delta_ms; - BOOLEAN success; - - nearest_delta_ms = nearest_delta_ns / 1000000; - if (nearest_delta_ms < 1) { - nearest_delta_ms = 1; - } - /* ULONG_MAX can be 32 bit */ - if (nearest_delta_ms > ULONG_MAX) { - nearest_delta_ms = ULONG_MAX; - } - success = ChangeTimerQueueTimer(NULL, - hTimer, - (unsigned long) nearest_delta_ms, - 3600000); - - if (!success) { - fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n", - GetLastError()); - exit(-1); - } - -} - -#endif /* _WIN32 */ - -static void quit_timers(void) -{ - struct qemu_alarm_timer *t = alarm_timer; - alarm_timer = NULL; - t->stop(t); -} - -#ifdef CONFIG_POSIX -static void reinit_timers(void) -{ - struct qemu_alarm_timer *t = alarm_timer; - t->stop(t); - if (t->start(t)) { - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } - qemu_rearm_alarm_timer(t); -} -#endif /* CONFIG_POSIX */ - -int init_timer_alarm(void) -{ - struct qemu_alarm_timer *t = NULL; - int i, err = -1; - - if (alarm_timer) { - return 0; - } - - for (i = 0; alarm_timers[i].name; i++) { - t = &alarm_timers[i]; - - err = t->start(t); - if (!err) - break; - } - - if (err) { - err = -ENOENT; - goto fail; - } - - atexit(quit_timers); -#ifdef CONFIG_POSIX - pthread_atfork(NULL, NULL, reinit_timers); -#endif - alarm_timer = t; - return 0; - -fail: - return err; -} - diff --git a/qemu.nsi b/qemu.nsi new file mode 100644 index 0000000000..1d57455956 --- /dev/null +++ b/qemu.nsi @@ -0,0 +1,250 @@ +;!/usr/bin/makensis + +; This NSIS script creates an installer for QEMU on Windows. + +; Copyright (C) 2006-2012 Stefan Weil +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 2 of the License, or +; (at your option) version 3 or any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see <http://www.gnu.org/licenses/>. + +; NSIS_WIN32_MAKENSIS + +!define PRODUCT "QEMU" +!define URL "http://www.qemu.org/" + +!define UNINST_EXE "$INSTDIR\qemu-uninstall.exe" +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT}" + +!ifndef BINDIR +!define BINDIR nsis.tmp +!endif +!ifndef SRCDIR +!define SRCDIR . +!endif +!ifndef OUTFILE +!define OUTFILE "qemu-setup.exe" +!endif + +; Optionally install documentation. +!ifndef CONFIG_DOCUMENTATION +!define CONFIG_DOCUMENTATION +!endif + +; Use maximum compression. +SetCompressor /SOLID lzma + +!include "MUI2.nsh" + +; The name of the installer. +Name "QEMU" + +; The file to write +OutFile "${OUTFILE}" + +; The default installation directory. +!ifdef W64 +InstallDir $PROGRAMFILES64\qemu +!else +InstallDir $PROGRAMFILES\qemu +!endif + +; Registry key to check for directory (so if you install again, it will +; overwrite the old one automatically) +InstallDirRegKey HKLM "Software\qemu" "Install_Dir" + +; Request administrator privileges for Windows Vista. +RequestExecutionLevel admin + +;-------------------------------- +; Interface Settings. +;!define MUI_HEADERIMAGE "qemu-nsis.bmp" +; !define MUI_SPECIALBITMAP "qemu.bmp" +!define MUI_ICON "${SRCDIR}\pc-bios\qemu-nsis.ico" +!define MUI_UNICON "${SRCDIR}\pc-bios\qemu-nsis.ico" +!define MUI_WELCOMEFINISHPAGE_BITMAP "${SRCDIR}\pc-bios\qemu-nsis.bmp" +; !define MUI_HEADERIMAGE_BITMAP "qemu-install.bmp" +; !define MUI_HEADERIMAGE_UNBITMAP "qemu-uninstall.bmp" +; !define MUI_COMPONENTSPAGE_SMALLDESC +; !define MUI_WELCOMEPAGE_TEXT "Insert text here.$\r$\n$\r$\n$\r$\n$_CLICK" + +;-------------------------------- +; Pages. + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "${SRCDIR}\COPYING" +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!define MUI_FINISHPAGE_LINK "Visit the QEMU Wiki online!" +!define MUI_FINISHPAGE_LINK_LOCATION "${URL}" +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +; Languages. + +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "German" + +;-------------------------------- + +; The stuff to install. +Section "${PRODUCT} (required)" + + SectionIn RO + + ; Set output path to the installation directory. + SetOutPath "$INSTDIR" + + File "${SRCDIR}\Changelog" + File "${SRCDIR}\COPYING" + File "${SRCDIR}\COPYING.LIB" + File "${SRCDIR}\README" + File "${SRCDIR}\VERSION" + + File "${BINDIR}\*.bmp" + File "${BINDIR}\*.bin" + File "${BINDIR}\*.dtb" + File "${BINDIR}\*.rom" + File "${BINDIR}\openbios-*" + + File /r "${BINDIR}\keymaps" +!ifdef CONFIG_GTK + File /r "${BINDIR}\share" +!endif + +!ifdef W64 + SetRegView 64 +!endif + + ; Write the installation path into the registry + WriteRegStr HKLM SOFTWARE\${PRODUCT} "Install_Dir" "$INSTDIR" + + ; Write the uninstall keys for Windows + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "QEMU" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" '"${UNINST_EXE}"' + WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" 1 + WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" 1 + WriteUninstaller "qemu-uninstall.exe" +SectionEnd + +Section "Tools" SectionTools + SetOutPath "$INSTDIR" + File "${BINDIR}\qemu-img.exe" + File "${BINDIR}\qemu-io.exe" +SectionEnd + +SectionGroup "System Emulations" SectionSystem + +!include "${BINDIR}\system-emulations.nsh" + +SectionGroupEnd + +!ifdef DLLDIR +Section "Libraries (DLL)" SectionDll + SetOutPath "$INSTDIR" + File "${DLLDIR}\*.dll" +SectionEnd +!endif + +!ifdef CONFIG_DOCUMENTATION +Section "Documentation" SectionDoc + SetOutPath "$INSTDIR" + File "${BINDIR}\qemu-doc.html" + File "${BINDIR}\qemu-tech.html" + CreateDirectory "$SMPROGRAMS\${PRODUCT}" + CreateShortCut "$SMPROGRAMS\${PRODUCT}\User Documentation.lnk" "$INSTDIR\qemu-doc.html" "" "$INSTDIR\qemu-doc.html" 0 + CreateShortCut "$SMPROGRAMS\${PRODUCT}\Technical Documentation.lnk" "$INSTDIR\qemu-tech.html" "" "$INSTDIR\qemu-tech.html" 0 +SectionEnd +!endif + +; Optional section (can be disabled by the user) +Section "Start Menu Shortcuts" SectionMenu + CreateDirectory "$SMPROGRAMS\${PRODUCT}" + CreateShortCut "$SMPROGRAMS\${PRODUCT}\Uninstall.lnk" "${UNINST_EXE}" "" "${UNINST_EXE}" 0 +SectionEnd + +;-------------------------------- + +; Uninstaller + +Section "Uninstall" + ; Remove registry keys +!ifdef W64 + SetRegView 64 +!endif + DeleteRegKey HKLM "${UNINST_KEY}" + DeleteRegKey HKLM SOFTWARE\${PRODUCT} + + ; Remove shortcuts, if any + Delete "$SMPROGRAMS\${PRODUCT}\User Documentation.lnk" + Delete "$SMPROGRAMS\${PRODUCT}\Technical Documentation.lnk" + Delete "$SMPROGRAMS\${PRODUCT}\Uninstall.lnk" + RMDir "$SMPROGRAMS\${PRODUCT}" + + ; Remove files and directories used + Delete "$INSTDIR\Changelog" + Delete "$INSTDIR\COPYING" + Delete "$INSTDIR\COPYING.LIB" + Delete "$INSTDIR\README" + Delete "$INSTDIR\VERSION" + Delete "$INSTDIR\*.bmp" + Delete "$INSTDIR\*.bin" + Delete "$INSTDIR\*.dll" + Delete "$INSTDIR\*.dtb" + Delete "$INSTDIR\*.rom" + Delete "$INSTDIR\openbios-*" + Delete "$INSTDIR\qemu-img.exe" + Delete "$INSTDIR\qemu-io.exe" + Delete "$INSTDIR\qemu.exe" + Delete "$INSTDIR\qemu-system-*.exe" + Delete "$INSTDIR\qemu-doc.html" + Delete "$INSTDIR\qemu-tech.html" + RMDir /r "$INSTDIR\keymaps" + RMDir /r "$INSTDIR\share" + ; Remove generated files + Delete "$INSTDIR\stderr.txt" + Delete "$INSTDIR\stdout.txt" + ; Remove uninstaller + Delete "${UNINST_EXE}" + RMDir "$INSTDIR" +SectionEnd + +;-------------------------------- + +; Descriptions (mouse-over). +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SectionSystem} "System emulation." + !insertmacro MUI_DESCRIPTION_TEXT ${Section_alpha} "Alpha system emulation." + !insertmacro MUI_DESCRIPTION_TEXT ${Section_alphaw} "Alpha system emulation (GUI)." + !insertmacro MUI_DESCRIPTION_TEXT ${Section_i386} "PC i386 system emulation." + !insertmacro MUI_DESCRIPTION_TEXT ${Section_i386w} "PC i386 system emulation (GUI)." + !insertmacro MUI_DESCRIPTION_TEXT ${SectionTools} "Tools." +!ifdef DLLDIR + !insertmacro MUI_DESCRIPTION_TEXT ${SectionDll} "Runtime Libraries (DLL)." +!endif +!ifdef CONFIG_DOCUMENTATION + !insertmacro MUI_DESCRIPTION_TEXT ${SectionDoc} "Documentation." +!endif + !insertmacro MUI_DESCRIPTION_TEXT ${SectionMenu} "Menu entries." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- +; Functions. + +Function .onInit + !insertmacro MUI_LANGDLL_DISPLAY +FunctionEnd diff --git a/qga/service-win32.c b/qga/service-win32.c index 02926abb28..aef41f04f1 100644 --- a/qga/service-win32.c +++ b/qga/service-win32.c @@ -29,36 +29,106 @@ static int printf_win_error(const char *text) MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *)&message, 0, NULL); - n = printf("%s. (Error: %d) %s", text, (int)err, message); + n = fprintf(stderr, "%s. (Error: %d) %s", text, (int)err, message); LocalFree(message); return n; } +/* Windows command line escaping. Based on + * <http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx> and + * <http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft%28v=vs.85%29.aspx>. + * + * The caller is responsible for initializing @buffer; prior contents are lost. + */ +static const char *win_escape_arg(const char *to_escape, GString *buffer) +{ + size_t backslash_count; + const char *c; + + /* open with a double quote */ + g_string_assign(buffer, "\""); + + backslash_count = 0; + for (c = to_escape; *c != '\0'; ++c) { + switch (*c) { + case '\\': + /* The meaning depends on the first non-backslash character coming + * up. + */ + ++backslash_count; + break; + + case '"': + /* We must escape each pending backslash, then escape the double + * quote. This creates a case of "odd number of backslashes [...] + * followed by a double quotation mark". + */ + while (backslash_count) { + --backslash_count; + g_string_append(buffer, "\\\\"); + } + g_string_append(buffer, "\\\""); + break; + + default: + /* Any pending backslashes are without special meaning, flush them. + * "Backslashes are interpreted literally, unless they immediately + * precede a double quotation mark." + */ + while (backslash_count) { + --backslash_count; + g_string_append_c(buffer, '\\'); + } + g_string_append_c(buffer, *c); + } + } + + /* We're about to close with a double quote in string delimiter role. + * Double all pending backslashes, creating a case of "even number of + * backslashes [...] followed by a double quotation mark". + */ + while (backslash_count) { + --backslash_count; + g_string_append(buffer, "\\\\"); + } + g_string_append_c(buffer, '"'); + + return buffer->str; +} + int ga_install_service(const char *path, const char *logfile, const char *state_dir) { + int ret = EXIT_FAILURE; SC_HANDLE manager; SC_HANDLE service; TCHAR module_fname[MAX_PATH]; + GString *esc; GString *cmdline; + SERVICE_DESCRIPTION desc = { (char *)QGA_SERVICE_DESCRIPTION }; if (GetModuleFileName(NULL, module_fname, MAX_PATH) == 0) { printf_win_error("No full path to service's executable"); return EXIT_FAILURE; } - cmdline = g_string_new(module_fname); - g_string_append(cmdline, " -d"); + esc = g_string_new(""); + cmdline = g_string_new(""); + + g_string_append_printf(cmdline, "%s -d", + win_escape_arg(module_fname, esc)); if (path) { - g_string_append_printf(cmdline, " -p %s", path); + g_string_append_printf(cmdline, " -p %s", win_escape_arg(path, esc)); } if (logfile) { - g_string_append_printf(cmdline, " -l %s -v", logfile); + g_string_append_printf(cmdline, " -l %s -v", + win_escape_arg(logfile, esc)); } if (state_dir) { - g_string_append_printf(cmdline, " -t %s", state_dir); + g_string_append_printf(cmdline, " -t %s", + win_escape_arg(state_dir, esc)); } g_debug("service's cmdline: %s", cmdline->str); @@ -66,28 +136,29 @@ int ga_install_service(const char *path, const char *logfile, manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (manager == NULL) { printf_win_error("No handle to service control manager"); - g_string_free(cmdline, TRUE); - return EXIT_FAILURE; + goto out_strings; } service = CreateService(manager, QGA_SERVICE_NAME, QGA_SERVICE_DISPLAY_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, cmdline->str, NULL, NULL, NULL, NULL, NULL); - - if (service) { - SERVICE_DESCRIPTION desc = { (char *)QGA_SERVICE_DESCRIPTION }; - ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &desc); - - printf("Service was installed successfully.\n"); - } else { + if (service == NULL) { printf_win_error("Failed to install service"); + goto out_manager; } + ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &desc); + fprintf(stderr, "Service was installed successfully.\n"); + ret = EXIT_SUCCESS; CloseServiceHandle(service); + +out_manager: CloseServiceHandle(manager); +out_strings: g_string_free(cmdline, TRUE); - return (service == NULL); + g_string_free(esc, TRUE); + return ret; } int ga_uninstall_service(void) @@ -111,7 +182,7 @@ int ga_uninstall_service(void) if (DeleteService(service) == FALSE) { printf_win_error("Failed to delete service"); } else { - printf("Service was deleted successfully.\n"); + fprintf(stderr, "Service was deleted successfully.\n"); } CloseServiceHandle(service); diff --git a/qmp-commands.hx b/qmp-commands.hx index 65a9e26423..cf47e3fe72 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -960,6 +960,7 @@ Arguments: Example: -> { "execute": "drive-backup", "arguments": { "device": "drive0", + "sync": "full", "target": "backup.img" } } <- { "return": {} } EQMP @@ -2620,6 +2621,12 @@ The main json-object contains the following: - "total-time": total amount of ms since migration started. If migration has ended, it returns the total migration time (json-int) +- "setup-time" amount of setup time in milliseconds _before_ the + iterations begin but _after_ the QMP command is issued. + This is designed to provide an accounting of any activities + (such as RDMA pinning) which may be expensive, but do not + actually occur during the iterative migration rounds + themselves. (json-int) - "downtime": only present when migration has finished correctly total amount in ms for downtime that happened (json-int) - "expected-downtime": only present while migration is active @@ -2673,6 +2680,7 @@ Examples: "remaining":123, "total":246, "total-time":12345, + "setup-time":12345, "downtime":12345, "duplicate":123, "normal":123, @@ -2697,6 +2705,7 @@ Examples: "remaining":123, "total":246, "total-time":12345, + "setup-time":12345, "expected-downtime":12345, "duplicate":123, "normal":123, @@ -2716,6 +2725,7 @@ Examples: "remaining":1053304, "transferred":3720, "total-time":12345, + "setup-time":12345, "expected-downtime":12345, "duplicate":123, "normal":123, @@ -2741,6 +2751,7 @@ Examples: "remaining":1053304, "transferred":3720, "total-time":12345, + "setup-time":12345, "expected-downtime":12345, "duplicate":10, "normal":3333, diff --git a/qobject/qdict.c b/qobject/qdict.c index ed381f9a50..472f106e27 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -476,3 +476,54 @@ static void qdict_destroy_obj(QObject *obj) g_free(qdict); } + +static void qdict_do_flatten(QDict *qdict, QDict *target, const char *prefix) +{ + QObject *value; + const QDictEntry *entry, *next; + const char *new_key; + bool delete; + + entry = qdict_first(qdict); + + while (entry != NULL) { + + next = qdict_next(qdict, entry); + value = qdict_entry_value(entry); + new_key = NULL; + delete = false; + + if (prefix) { + qobject_incref(value); + new_key = g_strdup_printf("%s.%s", prefix, entry->key); + qdict_put_obj(target, new_key, value); + delete = true; + } + + if (qobject_type(value) == QTYPE_QDICT) { + qdict_do_flatten(qobject_to_qdict(value), target, + new_key ? new_key : entry->key); + delete = true; + } + + if (delete) { + qdict_del(qdict, entry->key); + + /* Restart loop after modifying the iterated QDict */ + entry = qdict_first(qdict); + continue; + } + + entry = next; + } +} + +/** + * qdict_flatten(): For each nested QDict with key x, all fields with key y + * are moved to this QDict and their key is renamed to "x.y". This operation + * is applied recursively for nested QDicts. + */ +void qdict_flatten(QDict *qdict) +{ + qdict_do_flatten(qdict, qdict, NULL); +} diff --git a/qobject/qjson.c b/qobject/qjson.c index 19085a1bb7..6cf2511580 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -260,6 +260,8 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) /* XXX: should QError be emitted? */ case QTYPE_NONE: break; + case QTYPE_MAX: + abort(); } } @@ -157,6 +157,17 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, } +static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg) +{ + return 0; +} + +static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) +{ + return 0; +} + + void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags) { @@ -217,8 +228,6 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) { CPUState *cpu = CPU(dev); - qemu_init_vcpu(cpu); - if (dev->hotplugged) { cpu_synchronize_post_init(cpu); notifier_list_notify(&cpu_added_notifiers, dev); @@ -226,6 +235,14 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) } } +static void cpu_common_initfn(Object *obj) +{ + CPUState *cpu = CPU(obj); + CPUClass *cc = CPU_GET_CLASS(obj); + + cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; +} + static int64_t cpu_common_get_arch_id(CPUState *cpu) { return cpu->cpu_index; @@ -245,6 +262,8 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->write_elf32_note = cpu_common_write_elf32_note; k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; k->write_elf64_note = cpu_common_write_elf64_note; + k->gdb_read_register = cpu_common_gdb_read_register; + k->gdb_write_register = cpu_common_gdb_write_register; dc->realize = cpu_common_realizefn; dc->no_user = 1; } @@ -253,6 +272,7 @@ static const TypeInfo cpu_type_info = { .name = TYPE_CPU, .parent = TYPE_DEVICE, .instance_size = sizeof(CPUState), + .instance_init = cpu_common_initfn, .abstract = true, .class_size = sizeof(CPUClass), .class_init = cpu_class_init, diff --git a/qom/object.c b/qom/object.c index b2479d1c06..74fd241a02 100644 --- a/qom/object.c +++ b/qom/object.c @@ -51,6 +51,7 @@ struct TypeImpl void *class_data; void (*instance_init)(Object *obj); + void (*instance_post_init)(Object *obj); void (*instance_finalize)(Object *obj); bool abstract; @@ -111,6 +112,7 @@ static TypeImpl *type_register_internal(const TypeInfo *info) ti->class_data = info->class_data; ti->instance_init = info->instance_init; + ti->instance_post_init = info->instance_post_init; ti->instance_finalize = info->instance_finalize; ti->abstract = info->abstract; @@ -298,6 +300,17 @@ static void object_init_with_type(Object *obj, TypeImpl *ti) } } +static void object_post_init_with_type(Object *obj, TypeImpl *ti) +{ + if (ti->instance_post_init) { + ti->instance_post_init(obj); + } + + if (type_has_parent(ti)) { + object_post_init_with_type(obj, type_get_parent(ti)); + } +} + void object_initialize_with_type(void *data, TypeImpl *type) { Object *obj = data; @@ -313,6 +326,7 @@ void object_initialize_with_type(void *data, TypeImpl *type) object_ref(obj); QTAILQ_INIT(&obj->properties); object_init_with_type(obj, type); + object_post_init_with_type(obj, type); } void object_initialize(void *data, const char *typename) @@ -47,7 +47,7 @@ static bool qtest_opened; * * Clock management: * - * The qtest client is completely in charge of the vm_clock. qtest commands + * The qtest client is completely in charge of the QEMU_CLOCK_VIRTUAL. qtest commands * let you adjust the value of the clock (monotonically). All the commands * return the current value of the clock in nanoseconds. * @@ -412,11 +412,11 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) if (words[1]) { ns = strtoll(words[1], NULL, 0); } else { - ns = qemu_clock_deadline(vm_clock); + ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); } - qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns); + qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns); qtest_send_prefix(chr); - qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock)); + qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } else if (strcmp(words[0], "clock_set") == 0) { int64_t ns; @@ -424,7 +424,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) ns = strtoll(words[1], NULL, 0); qtest_clock_warp(ns); qtest_send_prefix(chr); - qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock)); + qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } else { qtest_send_prefix(chr); qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]); diff --git a/roms/openbios b/roms/openbios -Subproject 569e40c517e9623e672be38a21da7bcec046e3b +Subproject 0f3d51ef22ec9166beb3ed434d253029ed7cfe8 @@ -97,18 +97,18 @@ static void qemu_announce_self_once(void *opaque) if (--count) { /* delay 50ms, 150ms, 250ms, ... */ - qemu_mod_timer(timer, qemu_get_clock_ms(rt_clock) + + timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100); } else { - qemu_del_timer(timer); - qemu_free_timer(timer); + timer_del(timer); + timer_free(timer); } } void qemu_announce_self(void) { static QEMUTimer *timer; - timer = qemu_new_timer_ms(rt_clock, qemu_announce_self_once, &timer); + timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_announce_self_once, &timer); qemu_announce_self_once(&timer); } @@ -979,23 +979,23 @@ uint64_t qemu_get_be64(QEMUFile *f) /* timer */ -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +void timer_put(QEMUFile *f, QEMUTimer *ts) { uint64_t expire_time; - expire_time = qemu_timer_expire_time_ns(ts); + expire_time = timer_expire_time_ns(ts); qemu_put_be64(f, expire_time); } -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) +void timer_get(QEMUFile *f, QEMUTimer *ts) { uint64_t expire_time; expire_time = qemu_get_be64(f); if (expire_time != -1) { - qemu_mod_timer_ns(ts, expire_time); + timer_mod_ns(ts, expire_time); } else { - qemu_del_timer(ts); + timer_del(ts); } } @@ -1339,14 +1339,14 @@ const VMStateInfo vmstate_info_float64 = { static int get_timer(QEMUFile *f, void *pv, size_t size) { QEMUTimer *v = pv; - qemu_get_timer(f, v); + timer_get(f, v); return 0; } static void put_timer(QEMUFile *f, void *pv, size_t size) { QEMUTimer *v = pv; - qemu_put_timer(f, v); + timer_put(f, v); } const VMStateInfo vmstate_info_timer = { @@ -2387,7 +2387,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) qemu_gettimeofday(&tv); sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; - sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); + sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (name) { ret = bdrv_snapshot_find(bs, old_sn, name); diff --git a/scripts/disas-objdump.pl b/scripts/disas-objdump.pl new file mode 100755 index 0000000000..8f7e8182a1 --- /dev/null +++ b/scripts/disas-objdump.pl @@ -0,0 +1,99 @@ +#!/usr/bin/perl -w + +use File::Temp qw/ tempfile /; +use Getopt::Long; + +# Default to the system objdump if a cross-compiler edition not given. +my $aobjdump = "objdump"; +my $hobjdump = ""; +my $tobjdump = ""; +my $hmachine = ""; +my $tmachine = ""; + +GetOptions ('O|objdump=s' => \$aobjdump, + 'host-objdump=s' => \$hobjdump, + 'target-objdump=s' => \$tobjdump, + 'h|host-machine=s' => \$hmachine, + 't|target-machine=s' => \$tmachine); + +# But we can't default the machines. Sanity check that we've at least one. +die "No host or target machine type" if !$hmachine && !$tmachine; + +# Reuse one temp file for all of the hunks. +my ($outh, $outname) = tempfile(); +binmode($outh); +END { unlink $outname; } + +# Pre-construct the command-lines for executing the dump. +sub mkobjcommand ($$) { + my ($cmd, $mach) = @_; + return 0 if !$mach; + $cmd = $aobjdump if !$cmd; + return "$cmd -m $mach --disassemble-all -b binary"; +} + +$objdump[1] = mkobjcommand($hobjdump, $hmachine); +$objdump[2] = mkobjcommand($tobjdump, $tmachine); + +# Zero-initialize current dumping state. +my $mem = ""; +my $inobjd = 0; +my $vma = 0; + +sub objcommand { + my $ret = $objdump[$inobjd]; + if (!$ret) { + die "Host machine type not specified" if $inobjd == 1; + die "Target machine type not specified" if $inobjd == 2; + die "Internal error"; + } + return $ret; +} + +while (<>) { + # Collect the data from the relevant OBJD-* lines ... + if (/^OBJD-H: /) { + die "Internal error" if $inobjd == 2; + $mem = $mem . pack("H*", substr($_, 8, -1)); + $inobjd = 1; + } elsif (/^OBJD-T: /) { + die "Internal error" if $inobjd == 1; + $mem = $mem . pack("H*", substr($_, 8, -1)); + $inobjd = 2; + } + # ... which will always be followed by a blank line, + # at which point we should produce our dump. + elsif ($inobjd) { + # Rewrite the temp file in one go; it will usually be small. + sysseek $outh, 0, 0; + truncate $outh, 0; + syswrite $outh, $mem; + + my $cmd = objcommand(); + $cmd = $cmd . " --adjust-vma=" . $vma if $vma; + $cmd = $cmd . " " . $outname; + + # Pipe from objdump... + open IN, "-|", $cmd; + + # ... copying all but the first 7 lines of boilerplate to our stdout. + my $i = 0; + while (<IN>) { + print if (++$i > 7); + } + close IN; + print "\n"; + + $mem = ""; + $inobjd = 0; + $vma = 0; + } + # The line before "OBJD-*" will be of the form "0x<hex>+: +\n". + # Extract the value for passing to --adjust-vma. + elsif (/^(0x[0-9a-fA-F]+):\s*$/) { + $vma = $1; + print; + } else { + print; + } +} diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index ddcfed9f4b..5ee46ea1b3 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -150,7 +150,48 @@ typedef enum %(name)s return lookup_decl + enum_decl -def generate_union(name, typeinfo): +def generate_anon_union_qtypes(expr): + + name = expr['union'] + members = expr['data'] + + ret = mcgen(''' +const int %(name)s_qtypes[QTYPE_MAX] = { +''', + name=name) + + for key in members: + qapi_type = members[key] + if builtin_type_qtypes.has_key(qapi_type): + qtype = builtin_type_qtypes[qapi_type] + elif find_struct(qapi_type): + qtype = "QTYPE_QDICT" + elif find_union(qapi_type): + qtype = "QTYPE_QDICT" + else: + assert False, "Invalid anonymous union member" + + ret += mcgen(''' + [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, +''', + qtype = qtype, + abbrev = de_camel_case(name).upper(), + enum = c_fun(de_camel_case(key),False).upper()) + + ret += mcgen(''' +}; +''') + return ret + + +def generate_union(expr): + + name = expr['union'] + typeinfo = expr['data'] + + base = expr.get('base') + discriminator = expr.get('discriminator') + ret = mcgen(''' struct %(name)s { @@ -169,8 +210,26 @@ struct %(name)s ret += mcgen(''' }; +''') + + if base: + base_fields = find_struct(base)['data'] + if discriminator: + base_fields = base_fields.copy() + del base_fields[discriminator] + ret += generate_struct_fields(base_fields) + else: + assert not discriminator + + ret += mcgen(''' }; ''') + if discriminator == {}: + ret += mcgen(''' +extern const int %(name)s_qtypes[]; +''', + name=name) + return ret @@ -323,6 +382,8 @@ for expr in exprs: ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys())) + if expr.get('discriminator') == {}: + fdef.write(generate_anon_union_qtypes(expr)) else: continue fdecl.write(ret) @@ -352,7 +413,7 @@ for expr in exprs: ret += generate_type_cleanup_decl(expr['type']) fdef.write(generate_type_cleanup(expr['type']) + "\n") elif expr.has_key('union'): - ret += generate_union(expr['union'], expr['data']) + ret += generate_union(expr) ret += generate_type_cleanup_decl(expr['union'] + "List") fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n") ret += generate_type_cleanup_decl(expr['union']) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 6cac05acd5..597cca4b66 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -17,34 +17,31 @@ import os import getopt import errno -def generate_visit_struct_body(field_prefix, name, members): - ret = mcgen(''' -if (!error_is_set(errp)) { -''') - push_indent() +def generate_visit_struct_fields(name, field_prefix, fn_prefix, members): + substructs = [] + ret = '' + full_name = name if not fn_prefix else "%s_%s" % (name, fn_prefix) - if len(field_prefix): - field_prefix = field_prefix + "." - ret += mcgen(''' -Error **errp = &err; /* from outer scope */ -Error *err = NULL; -visit_start_struct(m, NULL, "", "%(name)s", 0, &err); -''', - name=name) - else: - ret += mcgen(''' -Error *err = NULL; -visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); -''', - name=name) + for argname, argentry, optional, structured in parse_args(members): + if structured: + if not fn_prefix: + nested_fn_prefix = argname + else: + nested_fn_prefix = "%s_%s" % (fn_prefix, argname) + + nested_field_prefix = "%s%s." % (field_prefix, argname) + ret += generate_visit_struct_fields(name, nested_field_prefix, + nested_fn_prefix, argentry) ret += mcgen(''' -if (!err) { - if (!obj || *obj) { -''') +static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error **errp) +{ + Error *err = NULL; +''', + name=name, full_name=full_name) push_indent() - push_indent() + for argname, argentry, optional, structured in parse_args(members): if optional: ret += mcgen(''' @@ -56,7 +53,7 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) { push_indent() if structured: - ret += generate_visit_struct_body(field_prefix + argname, argname, argentry) + ret += generate_visit_struct_body(full_name, argname, argentry) else: ret += mcgen(''' visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err); @@ -76,11 +73,43 @@ visit_end_optional(m, &err); ret += mcgen(''' error_propagate(errp, err); - err = NULL; } ''') + return ret + + +def generate_visit_struct_body(field_prefix, name, members): + ret = mcgen(''' +if (!error_is_set(errp)) { +''') + push_indent() + + full_name = name if not field_prefix else "%s_%s" % (field_prefix, name) + + if len(field_prefix): + ret += mcgen(''' +Error **errp = &err; /* from outer scope */ +Error *err = NULL; +visit_start_struct(m, NULL, "", "%(name)s", 0, &err); +''', + name=name) + else: + ret += mcgen(''' +Error *err = NULL; +visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); +''', + name=name) + + ret += mcgen(''' +if (!err) { + if (!obj || *obj) { + visit_type_%(name)s_fields(m, obj, &err); + error_propagate(errp, err); + err = NULL; + } +''', + name=full_name) - pop_indent() pop_indent() ret += mcgen(''' /* Always call end_struct if start_struct succeeded. */ @@ -92,7 +121,9 @@ visit_end_optional(m, &err); return ret def generate_visit_struct(name, members): - ret = mcgen(''' + ret = generate_visit_struct_fields(name, "", "", members) + + ret += mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) { @@ -145,9 +176,70 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e ''', name=name) -def generate_visit_union(name, members): +def generate_visit_anon_union(name, members): + ret = mcgen(''' + +void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) +{ + Error *err = NULL; + + if (!error_is_set(errp)) { + visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); + visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); + switch ((*obj)->kind) { +''', + name=name) + + for key in members: + assert (members[key] in builtin_types + or find_struct(members[key]) + or find_union(members[key])), "Invalid anonymous union member" + + ret += mcgen(''' + case %(abbrev)s_KIND_%(enum)s: + visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); + break; +''', + abbrev = de_camel_case(name).upper(), + enum = c_fun(de_camel_case(key),False).upper(), + c_type = type_name(members[key]), + c_name = c_fun(key)) + + ret += mcgen(''' + default: + abort(); + } + error_propagate(errp, err); + err = NULL; + visit_end_implicit_struct(m, &err); + } +} +''') + + return ret + + +def generate_visit_union(expr): + + name = expr['union'] + members = expr['data'] + + base = expr.get('base') + discriminator = expr.get('discriminator') + + if discriminator == {}: + assert not base + return generate_visit_anon_union(name, members) + ret = generate_visit_enum('%sKind' % name, members.keys()) + if base: + base_fields = find_struct(base)['data'] + if discriminator: + base_fields = base_fields.copy() + del base_fields[discriminator] + ret += generate_visit_struct_fields(name, "", "", base_fields) + ret += mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) @@ -158,18 +250,43 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); if (!err) { if (obj && *obj) { - visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err); - if (!err) { - switch ((*obj)->kind) { ''', name=name) + push_indent() push_indent() + push_indent() + + if base: + ret += mcgen(''' + visit_type_%(name)s_fields(m, obj, &err); +''', + name=name) + + pop_indent() + ret += mcgen(''' + visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err); + if (!err) { + switch ((*obj)->kind) { +''', + name=name, type="type" if not discriminator else discriminator) + for key in members: + if not discriminator: + fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' + else: + fmt = '''visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(c_type)s), &err); + if (!err) { + visit_type_%(c_type)s_fields(m, &(*obj)->%(c_name)s, &err); + error_propagate(errp, err); + err = NULL; + visit_end_implicit_struct(m, &err); + }''' + ret += mcgen(''' case %(abbrev)s_KIND_%(enum)s: - visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err); + ''' + fmt + ''' break; ''', abbrev = de_camel_case(name).upper(), @@ -362,7 +479,7 @@ for expr in exprs: ret = generate_declaration(expr['type'], expr['data']) fdecl.write(ret) elif expr.has_key('union'): - ret = generate_visit_union(expr['union'], expr['data']) + ret = generate_visit_union(expr) ret += generate_visit_list(expr['union'], expr['data']) fdef.write(ret) diff --git a/scripts/qapi.py b/scripts/qapi.py index baf13213a9..1069310f8d 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -2,14 +2,17 @@ # QAPI helper library # # Copyright IBM, Corp. 2011 +# Copyright (c) 2013 Red Hat Inc. # # Authors: # Anthony Liguori <aliguori@us.ibm.com> +# Markus Armbruster <armbru@redhat.com> # # This work is licensed under the terms of the GNU GPLv2. # See the COPYING.LIB file in the top-level directory. from ordereddict import OrderedDict +import sys builtin_types = [ 'str', 'int', 'number', 'bool', @@ -17,98 +20,162 @@ builtin_types = [ 'uint8', 'uint16', 'uint32', 'uint64' ] -def tokenize(data): - while len(data): - ch = data[0] - data = data[1:] - if ch in ['{', '}', ':', ',', '[', ']']: - yield ch - elif ch in ' \n': - None - elif ch == "'": - string = '' - esc = False - while True: - if (data == ''): - raise Exception("Mismatched quotes") - ch = data[0] - data = data[1:] - if esc: - string += ch - esc = False - elif ch == "\\": - esc = True - elif ch == "'": - break - else: - string += ch - yield string - -def parse(tokens): - if tokens[0] == '{': - ret = OrderedDict() - tokens = tokens[1:] - while tokens[0] != '}': - key = tokens[0] - tokens = tokens[1:] - - tokens = tokens[1:] # : - - value, tokens = parse(tokens) - - if tokens[0] == ',': - tokens = tokens[1:] - - ret[key] = value - tokens = tokens[1:] - return ret, tokens - elif tokens[0] == '[': - ret = [] - tokens = tokens[1:] - while tokens[0] != ']': - value, tokens = parse(tokens) - if tokens[0] == ',': - tokens = tokens[1:] - ret.append(value) - tokens = tokens[1:] - return ret, tokens - else: - return tokens[0], tokens[1:] - -def evaluate(string): - return parse(map(lambda x: x, tokenize(string)))[0] - -def get_expr(fp): - expr = '' - - for line in fp: - if line.startswith('#') or line == '\n': - continue - - if line.startswith(' '): - expr += line - elif expr: - yield expr - expr = line +builtin_type_qtypes = { + 'str': 'QTYPE_QSTRING', + 'int': 'QTYPE_QINT', + 'number': 'QTYPE_QFLOAT', + 'bool': 'QTYPE_QBOOL', + 'int8': 'QTYPE_QINT', + 'int16': 'QTYPE_QINT', + 'int32': 'QTYPE_QINT', + 'int64': 'QTYPE_QINT', + 'uint8': 'QTYPE_QINT', + 'uint16': 'QTYPE_QINT', + 'uint32': 'QTYPE_QINT', + 'uint64': 'QTYPE_QINT', +} + +class QAPISchemaError(Exception): + def __init__(self, schema, msg): + self.fp = schema.fp + self.msg = msg + self.line = self.col = 1 + for ch in schema.src[0:schema.pos]: + if ch == '\n': + self.line += 1 + self.col = 1 + elif ch == '\t': + self.col = (self.col + 7) % 8 + 1 + else: + self.col += 1 + + def __str__(self): + return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg) + +class QAPISchema: + + def __init__(self, fp): + self.fp = fp + self.src = fp.read() + if self.src == '' or self.src[-1] != '\n': + self.src += '\n' + self.cursor = 0 + self.exprs = [] + self.accept() + + while self.tok != None: + self.exprs.append(self.get_expr(False)) + + def accept(self): + while True: + self.tok = self.src[self.cursor] + self.pos = self.cursor + self.cursor += 1 + self.val = None + + if self.tok == '#': + self.cursor = self.src.find('\n', self.cursor) + elif self.tok in ['{', '}', ':', ',', '[', ']']: + return + elif self.tok == "'": + string = '' + esc = False + while True: + ch = self.src[self.cursor] + self.cursor += 1 + if ch == '\n': + raise QAPISchemaError(self, + 'Missing terminating "\'"') + if esc: + string += ch + esc = False + elif ch == "\\": + esc = True + elif ch == "'": + self.val = string + return + else: + string += ch + elif self.tok == '\n': + if self.cursor == len(self.src): + self.tok = None + return + elif not self.tok.isspace(): + raise QAPISchemaError(self, 'Stray "%s"' % self.tok) + + def get_members(self): + expr = OrderedDict() + if self.tok == '}': + self.accept() + return expr + if self.tok != "'": + raise QAPISchemaError(self, 'Expected string or "}"') + while True: + key = self.val + self.accept() + if self.tok != ':': + raise QAPISchemaError(self, 'Expected ":"') + self.accept() + expr[key] = self.get_expr(True) + if self.tok == '}': + self.accept() + return expr + if self.tok != ',': + raise QAPISchemaError(self, 'Expected "," or "}"') + self.accept() + if self.tok != "'": + raise QAPISchemaError(self, 'Expected string') + + def get_values(self): + expr = [] + if self.tok == ']': + self.accept() + return expr + if not self.tok in [ '{', '[', "'" ]: + raise QAPISchemaError(self, 'Expected "{", "[", "]" or string') + while True: + expr.append(self.get_expr(True)) + if self.tok == ']': + self.accept() + return expr + if self.tok != ',': + raise QAPISchemaError(self, 'Expected "," or "]"') + self.accept() + + def get_expr(self, nested): + if self.tok != '{' and not nested: + raise QAPISchemaError(self, 'Expected "{"') + if self.tok == '{': + self.accept() + expr = self.get_members() + elif self.tok == '[': + self.accept() + expr = self.get_values() + elif self.tok == "'": + expr = self.val + self.accept() else: - expr += line - - if expr: - yield expr + raise QAPISchemaError(self, 'Expected "{", "[" or string') + return expr def parse_schema(fp): - exprs = [] + try: + schema = QAPISchema(fp) + except QAPISchemaError, e: + print >>sys.stderr, e + exit(1) - for expr in get_expr(fp): - expr_eval = evaluate(expr) + exprs = [] - if expr_eval.has_key('enum'): - add_enum(expr_eval['enum']) - elif expr_eval.has_key('union'): - add_enum('%sKind' % expr_eval['union']) - elif expr_eval.has_key('type'): - add_struct(expr_eval) - exprs.append(expr_eval) + for expr in schema.exprs: + if expr.has_key('enum'): + add_enum(expr['enum']) + elif expr.has_key('union'): + add_union(expr) + add_enum('%sKind' % expr['union']) + elif expr.has_key('type'): + add_struct(expr) + exprs.append(expr) return exprs @@ -188,6 +255,7 @@ def type_name(name): enum_types = [] struct_types = [] +union_types = [] def add_struct(definition): global struct_types @@ -200,6 +268,17 @@ def find_struct(name): return struct return None +def add_union(definition): + global union_types + union_types.append(definition) + +def find_union(name): + global union_types + for union in union_types: + if union['union'] == name: + return union + return None + def add_enum(name): global enum_types enum_types.append(name) diff --git a/scripts/switch-timer-api b/scripts/switch-timer-api new file mode 100755 index 0000000000..a369a083d1 --- /dev/null +++ b/scripts/switch-timer-api @@ -0,0 +1,178 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Getopt::Long; +use FindBin; + +my @legacy = qw(qemu_clock_ptr qemu_get_clock_ns qemu_get_clock_ms qemu_register_clock_reset_notifier qemu_unregister_clock_reset_notifier qemu_new_timer qemu_free_timer qemu_del_timer qemu_mod_timer_ns qemu_mod_timer qemu_run_timers qemu_new_timer_ns qemu_new_timer_us qemu_new_timer_ms); +my $legacyre = '\b('.join('|', @legacy).')\b'; +my $option_git; +my $option_dryrun; +my $option_quiet; +my $option_rtc; +my $suffix=".tmp.$$"; +my @files; +my $getfiles = 'git grep -l -E \'\b((host|rt|vm|rtc)_clock\b|qemu_\w*timer)\' | egrep \'\.[ch]$\' | egrep -v \'qemu-timer\.c$|include/qemu/timer\.h$\''; + +sub Syntax +{ + print STDERR <<STOP; +Usage: $FindBin::Script [options] FILE ... + +Translate each FILE to the new Qemu timer API. If no files +are passed, a reasonable guess is taken. + +Options: + -q, --quiet Do not show warnings etc + -d, --dry-run Do a dry run + -g, --git Generate a git commit for each change + -r, --rtc Only fix up rtc usage + -h, --help Print this message + +STOP +return; +} + +sub ParseOptions +{ + if (!GetOptions ( + "dry-run|d" => \$option_dryrun, + "git|g" => \$option_git, + "quiet|q" => \$option_quiet, + "rtc|r" => \$option_rtc, + "help|h" => sub { Syntax(); exit(0); } + )) + { + Syntax(); + die "Bad options"; + } + + if ($#ARGV >=0) + { + @files = @ARGV; + } + else + { + @files = split(/\s+/, `$getfiles`); + } + + foreach my $file (@files) + { + die "Cannot find $file" unless (-f $file && -r $file); + } +} + +sub DoWarn +{ + my $text = shift @_; + my $line = shift @_; + return if ($option_quiet); + chomp ($line); + print STDERR "$text\n"; + print STDERR "$line\n\n"; +} + +sub Process +{ + my $ifn = shift @_; + my $ofn = $ifn.$suffix; + + my $intext; + my $outtext; + my $linenum = 0; + + open my $input, "<", $ifn || die "Cannot open $ifn for read: $!"; + + while (<$input>) + { + my $line = $_; + $intext .= $line; + $linenum++; + + # fix the specific uses + unless ($option_rtc) + { + $line =~ s/\bqemu_new_timer(_[num]s)\s*\((vm_|rt_|host_)clock\b/timer_new$1(XXX_$2clock/g; + $line =~ s/\bqemu_new_timer\s*\((vm_|rt_|host_)clock\b/timer_new(XXX_$1clock/g; + $line =~ s/\bqemu_get_clock(_[num]s)\s*\((vm_|rt_|host_)clock\b/qemu_clock_get$1(XXX_$2clock/g; + } + + # rtc is different + $line =~ s/\bqemu_new_timer(_[num]s)\s*\(rtc_clock\b/timer_new$1(rtc_clock/g; + $line =~ s/\bqemu_new_timer\s*\(rtc_clock\b/timer_new(rtc_clock/g; + $line =~ s/\bqemu_get_clock(_[num]s)\s*\(rtc_clock\b/qemu_clock_get$1(rtc_clock/g; + $line =~ s/\bqemu_register_clock_reset_notifier\s*\(rtc_clock\b/qemu_register_clock_reset_notifier(qemu_clock_ptr(rtc_clock)/g; + + unless ($option_rtc) + { + # fix up comments + $line =~ s/\b(vm_|rt_|host_)clock\b/XXX_$1clock/g if ($line =~ m,^[/ ]+\*,); + + # spurious fprintf error reporting + $line =~ s/: qemu_new_timer_ns failed/: timer_new_ns failed/g; + + # these have just changed name + $line =~ s/\bqemu_mod_timer\b/timer_mod/g; + $line =~ s/\bqemu_mod_timer_(ns|us|ms)\b/timer_mod_$1/g; + $line =~ s/\bqemu_free_timer\b/timer_free/g; + $line =~ s/\bqemu_del_timer\b/timer_del/g; + } + + # fix up rtc_clock + $line =~ s/QEMUClock \*rtc_clock;/QEMUClockType rtc_clock;/g; + $line =~ s/\brtc_clock = (vm_|rt_|host_)clock\b/rtc_clock = XXX_$1clock/g; + + unless ($option_rtc) + { + # replace any more general uses + $line =~ s/\b(vm_|rt_|host_)clock\b/qemu_clock_ptr(XXX_$1clock)/g; + } + + # fix up the place holders + $line =~ s/\bXXX_vm_clock\b/QEMU_CLOCK_VIRTUAL/g; + $line =~ s/\bXXX_rt_clock\b/QEMU_CLOCK_REALTIME/g; + $line =~ s/\bXXX_host_clock\b/QEMU_CLOCK_HOST/g; + + unless ($option_rtc) + { + DoWarn("$ifn:$linenum WARNING: timer $1 not fixed up", $line) if ($line =~ /\b((vm_|rt_|host_)clock)\b/); + DoWarn("$ifn:$linenum WARNING: function $1 not fixed up", $line) if ($line =~ /\b(qemu_new_timer\w+)\b/); + DoWarn("$ifn:$linenum WARNING: legacy function $1 remains", $line) if ($line =~ /$legacyre/o); + } + + $outtext .= $line; + } + + close $input; + + if ($intext ne $outtext) + { + print STDERR "Patching $ifn\n" unless ($option_quiet); + unless ($option_dryrun) + { + open my $output, ">", $ofn || die "Cannot open $ofn for write: $!"; + print $output $outtext; + close $output; + rename ($ofn, $ifn) || die "Cannot rename temp file to $ifn: $!"; + return 1; + } + } + return 0; +} + +sub DoCommit +{ + my $file = shift @_; + open (my $git, "| git commit -F - $file") || die "Cannot run git commit on $file: $!"; + print $git "timers api: use new timer api in $file\n\nConvert $file to use new timer API.\nThis is an automated commit made by scripts/switch-timer-api\n"; + close ($git); +} + +ParseOptions; + +foreach my $file (@files) +{ + my $changed = Process ($file); + DoCommit($file) if ($changed && $option_git); +} diff --git a/slirp/if.c b/slirp/if.c index dcd5fafe5d..87ca8a53a9 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -154,7 +154,7 @@ diddit: */ void if_start(Slirp *slirp) { - uint64_t now = qemu_get_clock_ns(rt_clock); + uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); bool from_batchq, next_from_batchq; struct mbuf *ifm, *ifm_next, *ifqt; diff --git a/slirp/misc.c b/slirp/misc.c index 0bcc481939..c0d489950a 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -9,6 +9,7 @@ #include <libslirp.h> #include "monitor/monitor.h" +#include "qemu/main-loop.h" #ifdef DEBUG int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR; diff --git a/slirp/slirp.c b/slirp/slirp.c index 80b28ea89e..5c3dabba93 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -448,7 +448,7 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error) return; } - curtime = qemu_get_clock_ms(rt_clock); + curtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); QTAILQ_FOREACH(slirp, &slirp_instances, entry) { /* @@ -787,7 +787,7 @@ int if_encap(Slirp *slirp, struct mbuf *ifm) ifm->arp_requested = true; /* Expire request and drop outgoing packet after 1 second */ - ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL; + ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL; } return 0; } else { diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 9b701b4714..f306cbada3 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -7,6 +7,7 @@ stub-obj-y += fdset-add-fd.o stub-obj-y += fdset-find-fd.o stub-obj-y += fdset-get-fd.o stub-obj-y += fdset-remove-fd.o +stub-obj-y += gdbstub.o stub-obj-y += get-fd.o stub-obj-y += get-vm-name.o stub-obj-y += iothread-lock.o diff --git a/stubs/clock-warp.c b/stubs/clock-warp.c index b64c462e73..5565118d11 100644 --- a/stubs/clock-warp.c +++ b/stubs/clock-warp.c @@ -1,7 +1,7 @@ #include "qemu-common.h" #include "qemu/timer.h" -void qemu_clock_warp(QEMUClock *clock) +void qemu_clock_warp(QEMUClockType type) { } diff --git a/stubs/dump.c b/stubs/dump.c index 43c9a3fa02..370cd96eb2 100644 --- a/stubs/dump.c +++ b/stubs/dump.c @@ -16,7 +16,8 @@ #include "qapi/qmp/qerror.h" #include "qmp-commands.h" -int cpu_get_dump_info(ArchDumpInfo *info) +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks) { return -1; } diff --git a/stubs/gdbstub.c b/stubs/gdbstub.c new file mode 100644 index 0000000000..c1dbfe7fb7 --- /dev/null +++ b/stubs/gdbstub.c @@ -0,0 +1,5 @@ +#include "qemu-common.h" + +const char *const xml_builtin[][2] = { + { NULL, NULL } +}; diff --git a/target-alpha/Makefile.objs b/target-alpha/Makefile.objs index 590304cc61..b96c5da98d 100644 --- a/target-alpha/Makefile.objs +++ b/target-alpha/Makefile.objs @@ -1,3 +1,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o obj-y += translate.o helper.o cpu.o obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o +obj-y += gdbstub.o diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h index b2eeba36f3..2ebc9bcacb 100644 --- a/target-alpha/cpu-qom.h +++ b/target-alpha/cpu-qom.h @@ -82,5 +82,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu); void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index c8c8c2c861..cfad2ea121 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -33,8 +33,11 @@ static void alpha_cpu_set_pc(CPUState *cs, vaddr value) static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev); + qemu_init_vcpu(cs); + acc->parent_realize(dev, errp); } @@ -271,11 +274,14 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = alpha_cpu_do_interrupt; cc->dump_state = alpha_cpu_dump_state; cc->set_pc = alpha_cpu_set_pc; + cc->gdb_read_register = alpha_cpu_gdb_read_register; + cc->gdb_write_register = alpha_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->do_unassigned_access = alpha_cpu_unassigned_access; cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug; dc->vmsd = &vmstate_alpha_cpu; #endif + cc->gdb_num_core_regs = 67; } static const TypeInfo alpha_cpu_type_info = { diff --git a/target-alpha/gdbstub.c b/target-alpha/gdbstub.c new file mode 100644 index 0000000000..980f140e72 --- /dev/null +++ b/target-alpha/gdbstub.c @@ -0,0 +1,93 @@ +/* + * Alpha gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AlphaCPU *cpu = ALPHA_CPU(cs); + CPUAlphaState *env = &cpu->env; + uint64_t val; + CPU_DoubleU d; + + switch (n) { + case 0 ... 30: + val = env->ir[n]; + break; + case 32 ... 62: + d.d = env->fir[n - 32]; + val = d.ll; + break; + case 63: + val = cpu_alpha_load_fpcr(env); + break; + case 64: + val = env->pc; + break; + case 66: + val = env->unique; + break; + case 31: + case 65: + /* 31 really is the zero register; 65 is unassigned in the + gdb protocol, but is still required to occupy 8 bytes. */ + val = 0; + break; + default: + return 0; + } + return gdb_get_regl(mem_buf, val); +} + +int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AlphaCPU *cpu = ALPHA_CPU(cs); + CPUAlphaState *env = &cpu->env; + target_ulong tmp = ldtul_p(mem_buf); + CPU_DoubleU d; + + switch (n) { + case 0 ... 30: + env->ir[n] = tmp; + break; + case 32 ... 62: + d.ll = tmp; + env->fir[n - 32] = d.d; + break; + case 63: + cpu_alpha_store_fpcr(env, tmp); + break; + case 64: + env->pc = tmp; + break; + case 66: + env->unique = tmp; + break; + case 31: + case 65: + /* 31 really is the zero register; 65 is unassigned in the + gdb protocol, but is still required to occupy 8 bytes. */ + break; + default: + return 0; + } + return 8; +} diff --git a/target-alpha/helper.h b/target-alpha/helper.h index 0e425cfc08..732b701d53 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -99,6 +99,7 @@ DEF_HELPER_FLAGS_2(ieee_input_cmp, TCG_CALL_NO_WG, void, env, i64) #if !defined (CONFIG_USER_ONLY) DEF_HELPER_2(hw_ret, void, env, i64) +DEF_HELPER_3(call_pal, void, env, i64, i64) DEF_HELPER_1(ldl_phys, i64, i64) DEF_HELPER_1(ldq_phys, i64, i64) @@ -111,6 +112,7 @@ DEF_HELPER_3(stq_c_phys, i64, env, i64, i64) DEF_HELPER_FLAGS_1(tbia, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_2(tbis, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(tb_flush, TCG_CALL_NO_RWG, void, env) DEF_HELPER_1(halt, void, i64); diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c index bd94597d36..035810c27c 100644 --- a/target-alpha/sys_helper.c +++ b/target-alpha/sys_helper.c @@ -30,9 +30,9 @@ uint64_t helper_load_pcc(CPUAlphaState *env) In order to make OS-level time accounting work with the RPCC, present it with a well-timed clock fixed at 250MHz. */ return (((uint64_t)env->pcc_ofs << 32) - | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2)); + | (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 2)); #else - /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu + /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist. Just pass through the host cpu clock ticks. Also, don't bother taking PCC_OFS into account. */ return (uint32_t)cpu_get_real_ticks(); #endif @@ -51,6 +51,17 @@ void helper_hw_ret(CPUAlphaState *env, uint64_t a) } } +void helper_call_pal(CPUAlphaState *env, uint64_t pc, uint64_t entry_ofs) +{ + int pal_mode = env->pal_mode; + env->exc_addr = pc | pal_mode; + env->pc = env->palbr + entry_ofs; + if (!pal_mode) { + env->pal_mode = 1; + swap_shadow_regs(env); + } +} + void helper_tbia(CPUAlphaState *env) { tlb_flush(env, 1); @@ -61,6 +72,11 @@ void helper_tbis(CPUAlphaState *env, uint64_t p) tlb_flush_page(env, p); } +void helper_tb_flush(CPUAlphaState *env) +{ + tb_flush(env); +} + void helper_halt(uint64_t restart) { if (restart) { @@ -72,12 +88,12 @@ void helper_halt(uint64_t restart) uint64_t helper_get_vmtime(void) { - return qemu_get_clock_ns(vm_clock); + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } uint64_t helper_get_walltime(void) { - return qemu_get_clock_ns(rtc_clock); + return qemu_clock_get_ns(rtc_clock); } void helper_set_alarm(CPUAlphaState *env, uint64_t expire) @@ -86,9 +102,10 @@ void helper_set_alarm(CPUAlphaState *env, uint64_t expire) if (expire) { env->alarm_expire = expire; - qemu_mod_timer(cpu->alarm_timer, expire); + timer_mod(cpu->alarm_timer, expire); } else { - qemu_del_timer(cpu->alarm_timer); + timer_del(cpu->alarm_timer); } } + #endif /* CONFIG_USER_ONLY */ diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 0efd5595e6..309dea6ff0 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -379,13 +379,26 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb, #endif } -static int use_goto_tb(DisasContext *ctx, uint64_t dest) +static bool in_superpage(DisasContext *ctx, int64_t addr) { - /* Check for the dest on the same page as the start of the TB. We - also want to suppress goto_tb in the case of single-steping and IO. */ - return (((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0 - && !ctx->singlestep_enabled - && !(ctx->tb->cflags & CF_LAST_IO)); + return ((ctx->tb->flags & TB_FLAGS_USER_MODE) == 0 + && addr < 0 + && ((addr >> 41) & 3) == 2 + && addr >> TARGET_VIRT_ADDR_SPACE_BITS == addr >> 63); +} + +static bool use_goto_tb(DisasContext *ctx, uint64_t dest) +{ + /* Suppress goto_tb in the case of single-steping and IO. */ + if (ctx->singlestep_enabled || (ctx->tb->cflags & CF_LAST_IO)) { + return false; + } + /* If the destination is in the superpage, the page perms can't change. */ + if (in_superpage(ctx, dest)) { + return true; + } + /* Check for the dest on the same page as the start of the TB. */ + return ((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0; } static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp) @@ -1521,7 +1534,8 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]); break; default: - return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf); + palcode &= 0xbf; + goto do_call_pal; } return NO_EXIT; } @@ -1586,13 +1600,42 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) break; default: - return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f); + palcode &= 0x3f; + goto do_call_pal; } return NO_EXIT; } #endif - return gen_invalid(ctx); + + do_call_pal: +#ifdef CONFIG_USER_ONLY + return gen_excp(ctx, EXCP_CALL_PAL, palcode); +#else + { + TCGv pc = tcg_const_i64(ctx->pc); + TCGv entry = tcg_const_i64(palcode & 0x80 + ? 0x2000 + (palcode - 0x80) * 64 + : 0x1000 + palcode * 64); + + gen_helper_call_pal(cpu_env, pc, entry); + + tcg_temp_free(entry); + tcg_temp_free(pc); + + /* Since the destination is running in PALmode, we don't really + need the page permissions check. We'll see the existance of + the page when we create the TB, and we'll flush all TBs if + we change the PAL base register. */ + if (!ctx->singlestep_enabled && !(ctx->tb->cflags & CF_LAST_IO)) { + tcg_gen_goto_tb(0); + tcg_gen_exit_tb((tcg_target_long)ctx->tb); + return EXIT_GOTO_TB; + } + + return EXIT_PC_UPDATED; + } +#endif } #ifndef CONFIG_USER_ONLY @@ -1708,6 +1751,15 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno) gen_helper_set_alarm(cpu_env, tmp); break; + case 7: + /* PALBR */ + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUAlphaState, palbr)); + /* Changing the PAL base register implies un-chaining all of the TBs + that ended with a CALL_PAL. Since the base register usually only + changes during boot, flushing everything works well. */ + gen_helper_tb_flush(cpu_env); + return EXIT_PC_STALE; + default: /* The basic registers are data only, and unknown registers are read-zero, write-ignore. */ @@ -3392,6 +3444,7 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, CPUAlphaState *env = &cpu->env; DisasContext ctx, *ctxp = &ctx; target_ulong pc_start; + target_ulong pc_mask; uint32_t insn; uint16_t *gen_opc_end; CPUBreakpoint *bp; @@ -3421,8 +3474,15 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) + if (max_insns == 0) { max_insns = CF_COUNT_MASK; + } + + if (in_superpage(&ctx, pc_start)) { + pc_mask = (1ULL << 41) - 1; + } else { + pc_mask = ~TARGET_PAGE_MASK; + } gen_tb_start(); do { @@ -3460,7 +3520,7 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, /* If we reach a page boundary, are single stepping, or exhaust instruction count, stop generation. */ if (ret == NO_EXIT - && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0 + && ((ctx.pc & pc_mask) == 0 || tcg_ctx.gen_opc_ptr >= gen_opc_end || num_insns >= max_insns || singlestep diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs index 4a6e52e528..2d9f77fa9b 100644 --- a/target-arm/Makefile.objs +++ b/target-arm/Makefile.objs @@ -4,3 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-y += translate.o op_helper.o helper.o cpu.o obj-y += neon_helper.o iwmmxt_helper.o +obj-y += gdbstub.o diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 02162c9aba..9f47baebf8 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -86,6 +86,11 @@ typedef struct ARMCPU { uint64_t *cpreg_vmstate_values; int32_t cpreg_vmstate_array_len; + /* Timers used by the generic (architected) timer */ + QEMUTimer *gt_timer[NUM_GTIMERS]; + /* GPIO outputs for generic timer */ + qemu_irq gt_timer_outputs[NUM_GTIMERS]; + /* The instance init functions for implementation-specific subclasses * set these fields to specify the implementation-dependent values of * various constant registers and reset values of non-constant @@ -149,4 +154,11 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + +/* Callback functions for the generic timer's timers. */ +void arm_gt_ptimer_cb(void *opaque); +void arm_gt_vtimer_cb(void *opaque); + #endif diff --git a/target-arm/cpu.c b/target-arm/cpu.c index d3906a4829..b2556c66b4 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -23,7 +23,9 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/loader.h" #endif +#include "hw/arm/arm.h" #include "sysemu/sysemu.h" +#include "sysemu/kvm.h" static void arm_cpu_set_pc(CPUState *cs, vaddr value) { @@ -129,6 +131,55 @@ static void arm_cpu_reset(CPUState *s) tb_flush(env); } +#ifndef CONFIG_USER_ONLY +static void arm_cpu_set_irq(void *opaque, int irq, int level) +{ + ARMCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + + switch (irq) { + case ARM_CPU_IRQ: + if (level) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + break; + case ARM_CPU_FIQ: + if (level) { + cpu_interrupt(cs, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ); + } + break; + default: + hw_error("arm_cpu_set_irq: Bad interrupt line %d\n", irq); + } +} + +static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level) +{ +#ifdef CONFIG_KVM + ARMCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT; + + switch (irq) { + case ARM_CPU_IRQ: + kvm_irq |= KVM_ARM_IRQ_CPU_IRQ; + break; + case ARM_CPU_FIQ: + kvm_irq |= KVM_ARM_IRQ_CPU_FIQ; + break; + default: + hw_error("arm_cpu_kvm_set_irq: Bad interrupt line %d\n", irq); + } + kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT; + kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0); +#endif +} +#endif + static inline void set_feature(CPUARMState *env, int feature) { env->features |= 1ULL << feature; @@ -145,6 +196,22 @@ static void arm_cpu_initfn(Object *obj) cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); +#ifndef CONFIG_USER_ONLY + /* Our inbound IRQ and FIQ lines */ + if (kvm_enabled()) { + qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 2); + } else { + qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 2); + } + + cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, + arm_gt_ptimer_cb, cpu); + cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, + arm_gt_vtimer_cb, cpu); + qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs, + ARRAY_SIZE(cpu->gt_timer_outputs)); +#endif + if (tcg_enabled() && !inited) { inited = true; arm_translate_init(); @@ -159,6 +226,7 @@ static void arm_cpu_finalizefn(Object *obj) static void arm_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); ARMCPU *cpu = ARM_CPU(dev); ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev); CPUARMState *env = &cpu->env; @@ -214,7 +282,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) init_cpreg_list(cpu); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + qemu_init_vcpu(cs); acc->parent_realize(dev, errp); } @@ -824,10 +893,14 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = arm_cpu_do_interrupt; cc->dump_state = arm_cpu_dump_state; cc->set_pc = arm_cpu_set_pc; + cc->gdb_read_register = arm_cpu_gdb_read_register; + cc->gdb_write_register = arm_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = arm_cpu_get_phys_page_debug; cc->vmsd = &vmstate_arm_cpu; #endif + cc->gdb_num_core_regs = 26; + cc->gdb_core_xml_file = "arm-core.xml"; } static void cpu_register(const ARMCPUInfo *info) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index b2dc49413c..f2abdf37ce 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -58,6 +58,9 @@ /* ARM-specific interrupt pending bits. */ #define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1 +/* Meanings of the ARMCPU object's two inbound GPIO lines */ +#define ARM_CPU_IRQ 0 +#define ARM_CPU_FIQ 1 typedef void ARMWriteCPFunc(void *opaque, int cp_info, int srcreg, int operand, uint32_t value); @@ -76,6 +79,21 @@ struct arm_boot_info; s<2n+1> maps to the most significant half of d<n> */ +/* CPU state for each instance of a generic timer (in cp15 c14) */ +typedef struct ARMGenericTimer { + uint64_t cval; /* Timer CompareValue register */ + uint32_t ctl; /* Timer Control register */ +} ARMGenericTimer; + +#define GTIMER_PHYS 0 +#define GTIMER_VIRT 1 +#define NUM_GTIMERS 2 + +/* Scale factor for generic timers, ie number of ns per tick. + * This gives a 62.5MHz timer. + */ +#define GTIMER_SCALE 16 + typedef struct CPUARMState { /* Regs for current mode. */ uint32_t regs[16]; @@ -143,6 +161,9 @@ typedef struct CPUARMState { uint32_t c13_tls1; /* User RW Thread register. */ uint32_t c13_tls2; /* User RO Thread register. */ uint32_t c13_tls3; /* Privileged Thread register. */ + uint32_t c14_cntfrq; /* Counter Frequency register */ + uint32_t c14_cntkctl; /* Timer Control register */ + ARMGenericTimer c14_timer[NUM_GTIMERS]; uint32_t c15_cpar; /* XScale Coprocessor Access Register */ uint32_t c15_ticonfig; /* TI925T configuration byte. */ uint32_t c15_i_max; /* Maximum D-cache dirty line index. */ @@ -469,6 +490,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) * old must have the OVERRIDE bit set. * NO_MIGRATE indicates that this register should be ignored for migration; * (eg because any state is accessed via some other coprocessor register). + * IO indicates that this register does I/O and therefore its accesses + * need to be surrounded by gen_io_start()/gen_io_end(). In particular, + * registers which implement clocks or timers require this. */ #define ARM_CP_SPECIAL 1 #define ARM_CP_CONST 2 @@ -476,13 +500,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) #define ARM_CP_SUPPRESS_TB_END 8 #define ARM_CP_OVERRIDE 16 #define ARM_CP_NO_MIGRATE 32 +#define ARM_CP_IO 64 #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8)) #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8)) #define ARM_LAST_SPECIAL ARM_CP_WFI /* Used only as a terminator for ARMCPRegInfo lists */ #define ARM_CP_SENTINEL 0xffff /* Mask of only the flag bits in a type field */ -#define ARM_CP_FLAG_MASK 0x3f +#define ARM_CP_FLAG_MASK 0x7f /* Return true if cptype is a valid type field. This is used to try to * catch errors where the sentinel has been accidentally left off the end diff --git a/target-arm/gdbstub.c b/target-arm/gdbstub.c new file mode 100644 index 0000000000..1c3439654f --- /dev/null +++ b/target-arm/gdbstub.c @@ -0,0 +1,102 @@ +/* + * ARM gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect + whatever the target description contains. Due to a historical mishap + the FPA registers appear in between core integer regs and the CPSR. + We hack round this by giving the FPA regs zero size when talking to a + newer gdb. */ + +int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + if (n < 16) { + /* Core integer register. */ + return gdb_get_reg32(mem_buf, env->regs[n]); + } + if (n < 24) { + /* FPA registers. */ + if (gdb_has_xml) { + return 0; + } + memset(mem_buf, 0, 12); + return 12; + } + switch (n) { + case 24: + /* FPA status register. */ + if (gdb_has_xml) { + return 0; + } + return gdb_get_reg32(mem_buf, 0); + case 25: + /* CPSR */ + return gdb_get_reg32(mem_buf, cpsr_read(env)); + } + /* Unknown register. */ + return 0; +} + +int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + uint32_t tmp; + + tmp = ldl_p(mem_buf); + + /* Mask out low bit of PC to workaround gdb bugs. This will probably + cause problems if we ever implement the Jazelle DBX extensions. */ + if (n == 15) { + tmp &= ~1; + } + + if (n < 16) { + /* Core integer register. */ + env->regs[n] = tmp; + return 4; + } + if (n < 24) { /* 16-23 */ + /* FPA registers (ignored). */ + if (gdb_has_xml) { + return 0; + } + return 12; + } + switch (n) { + case 24: + /* FPA status register (ignored). */ + if (gdb_has_xml) { + return 0; + } + return 4; + case 25: + /* CPSR */ + cpsr_write(env, tmp, 0xffffffff); + return 4; + } + /* Unknown register. */ + return 0; +} diff --git a/target-arm/helper.c b/target-arm/helper.c index b0c3ca1fbe..e51ef20aea 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -67,14 +67,22 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) static int raw_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { - *value = CPREG_FIELD32(env, ri); + if (ri->type & ARM_CP_64BIT) { + *value = CPREG_FIELD64(env, ri); + } else { + *value = CPREG_FIELD32(env, ri); + } return 0; } static int raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - CPREG_FIELD32(env, ri) = value; + if (ri->type & ARM_CP_64BIT) { + CPREG_FIELD64(env, ri) = value; + } else { + CPREG_FIELD32(env, ri) = value; + } return 0; } @@ -687,15 +695,261 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { REGINFO_SENTINEL }; +#ifndef CONFIG_USER_ONLY + +static uint64_t gt_get_countervalue(CPUARMState *env) +{ + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +} + +static void gt_recalc_timer(ARMCPU *cpu, int timeridx) +{ + ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx]; + + if (gt->ctl & 1) { + /* Timer enabled: calculate and set current ISTATUS, irq, and + * reset timer to when ISTATUS next has to change + */ + uint64_t count = gt_get_countervalue(&cpu->env); + /* Note that this must be unsigned 64 bit arithmetic: */ + int istatus = count >= gt->cval; + uint64_t nexttick; + + gt->ctl = deposit32(gt->ctl, 2, 1, istatus); + qemu_set_irq(cpu->gt_timer_outputs[timeridx], + (istatus && !(gt->ctl & 2))); + if (istatus) { + /* Next transition is when count rolls back over to zero */ + nexttick = UINT64_MAX; + } else { + /* Next transition is when we hit cval */ + nexttick = gt->cval; + } + /* Note that the desired next expiry time might be beyond the + * signed-64-bit range of a QEMUTimer -- in this case we just + * set the timer for as far in the future as possible. When the + * timer expires we will reset the timer for any remaining period. + */ + if (nexttick > INT64_MAX / GTIMER_SCALE) { + nexttick = INT64_MAX / GTIMER_SCALE; + } + timer_mod(cpu->gt_timer[timeridx], nexttick); + } else { + /* Timer disabled: ISTATUS and timer output always clear */ + gt->ctl &= ~4; + qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0); + timer_del(cpu->gt_timer[timeridx]); + } +} + +static int gt_cntfrq_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + /* Not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */ + if (arm_current_pl(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) { + return EXCP_UDEF; + } + *value = env->cp15.c14_cntfrq; + return 0; +} + +static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + int timeridx = ri->opc1 & 1; + + timer_del(cpu->gt_timer[timeridx]); +} + +static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int timeridx = ri->opc1 & 1; + + if (arm_current_pl(env) == 0 && + !extract32(env->cp15.c14_cntkctl, timeridx, 1)) { + return EXCP_UDEF; + } + *value = gt_get_countervalue(env); + return 0; +} + +static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int timeridx = ri->opc1 & 1; + + if (arm_current_pl(env) == 0 && + !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { + return EXCP_UDEF; + } + *value = env->cp15.c14_timer[timeridx].cval; + return 0; +} + +static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + int timeridx = ri->opc1 & 1; + + env->cp15.c14_timer[timeridx].cval = value; + gt_recalc_timer(arm_env_get_cpu(env), timeridx); + return 0; +} +static int gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int timeridx = ri->crm & 1; + + if (arm_current_pl(env) == 0 && + !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { + return EXCP_UDEF; + } + *value = (uint32_t)(env->cp15.c14_timer[timeridx].cval - + gt_get_countervalue(env)); + return 0; +} + +static int gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + int timeridx = ri->crm & 1; + + env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) + + + sextract64(value, 0, 32); + gt_recalc_timer(arm_env_get_cpu(env), timeridx); + return 0; +} + +static int gt_ctl_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int timeridx = ri->crm & 1; + + if (arm_current_pl(env) == 0 && + !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { + return EXCP_UDEF; + } + *value = env->cp15.c14_timer[timeridx].ctl; + return 0; +} + +static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + int timeridx = ri->crm & 1; + uint32_t oldval = env->cp15.c14_timer[timeridx].ctl; + + env->cp15.c14_timer[timeridx].ctl = value & 3; + if ((oldval ^ value) & 1) { + /* Enable toggled */ + gt_recalc_timer(cpu, timeridx); + } else if ((oldval & value) & 2) { + /* IMASK toggled: don't need to recalculate, + * just set the interrupt line based on ISTATUS + */ + qemu_set_irq(cpu->gt_timer_outputs[timeridx], + (oldval & 4) && (value & 2)); + } + return 0; +} + +void arm_gt_ptimer_cb(void *opaque) +{ + ARMCPU *cpu = opaque; + + gt_recalc_timer(cpu, GTIMER_PHYS); +} + +void arm_gt_vtimer_cb(void *opaque) +{ + ARMCPU *cpu = opaque; + + gt_recalc_timer(cpu, GTIMER_VIRT); +} + +static const ARMCPRegInfo generic_timer_cp_reginfo[] = { + /* Note that CNTFRQ is purely reads-as-written for the benefit + * of software; writing it doesn't actually change the timer frequency. + * Our reset value matches the fixed frequency we implement the timer at. + */ + { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW | PL0_R, + .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq), + .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE, + .readfn = gt_cntfrq_read, .raw_readfn = raw_read, + }, + /* overall control: mostly access permissions */ + { .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl), + .resetvalue = 0, + }, + /* per-timer control */ + { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, + .type = ARM_CP_IO, .access = PL1_RW | PL0_R, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), + .resetvalue = 0, + .readfn = gt_ctl_read, .writefn = gt_ctl_write, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, + { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1, + .type = ARM_CP_IO, .access = PL1_RW | PL0_R, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), + .resetvalue = 0, + .readfn = gt_ctl_read, .writefn = gt_ctl_write, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, + /* TimerValue views: a 32 bit downcounting view of the underlying state */ + { .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0, + .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, + .readfn = gt_tval_read, .writefn = gt_tval_write, + }, + { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, + .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, + .readfn = gt_tval_read, .writefn = gt_tval_write, + }, + /* The counter itself */ + { .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0, + .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, + .readfn = gt_cnt_read, .resetfn = gt_cnt_reset, + }, + { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1, + .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, + .readfn = gt_cnt_read, .resetfn = gt_cnt_reset, + }, + /* Comparison value, indicating when the timer goes off */ + { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2, + .access = PL1_RW | PL0_R, + .type = ARM_CP_64BIT | ARM_CP_IO, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), + .resetvalue = 0, + .readfn = gt_cval_read, .writefn = gt_cval_write, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, + { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, + .access = PL1_RW | PL0_R, + .type = ARM_CP_64BIT | ARM_CP_IO, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), + .resetvalue = 0, + .readfn = gt_cval_read, .writefn = gt_cval_write, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, + REGINFO_SENTINEL +}; + +#else +/* In user-mode none of the generic timer registers are accessible, + * and their implementation depends on QEMU_CLOCK_VIRTUAL and qdev gpio outputs, + * so instead just don't register any of them. + */ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { - /* Dummy implementation: RAZ/WI the whole crn=14 space */ - { .name = "GENERIC_TIMER", .cp = 15, .crn = 14, - .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_MIGRATE, - .resetvalue = 0 }, REGINFO_SENTINEL }; +#endif + static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { if (arm_feature(env, ARM_FEATURE_LPAE)) { @@ -1653,7 +1907,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, "was %s, now %s\n", r2->cp, 32 + 32 * is64, r2->crn, r2->crm, r2->opc1, r2->opc2, oldreg->name, r2->name); - assert(0); + g_assert_not_reached(); } } g_hash_table_insert(cpu->cp_regs, key, r2); @@ -1974,6 +2228,37 @@ static void do_v7m_exception_exit(CPUARMState *env) pointer. */ } +/* Exception names for debug logging; note that not all of these + * precisely correspond to architectural exceptions. + */ +static const char * const excnames[] = { + [EXCP_UDEF] = "Undefined Instruction", + [EXCP_SWI] = "SVC", + [EXCP_PREFETCH_ABORT] = "Prefetch Abort", + [EXCP_DATA_ABORT] = "Data Abort", + [EXCP_IRQ] = "IRQ", + [EXCP_FIQ] = "FIQ", + [EXCP_BKPT] = "Breakpoint", + [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit", + [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage", + [EXCP_STREX] = "QEMU intercept of STREX", +}; + +static inline void arm_log_exception(int idx) +{ + if (qemu_loglevel_mask(CPU_LOG_INT)) { + const char *exc = NULL; + + if (idx >= 0 && idx < ARRAY_SIZE(excnames)) { + exc = excnames[idx]; + } + if (!exc) { + exc = "unknown"; + } + qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc); + } +} + void arm_v7m_cpu_do_interrupt(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); @@ -1982,6 +2267,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) uint32_t lr; uint32_t addr; + arm_log_exception(env->exception_index); + lr = 0xfffffff1; if (env->v7m.current_sp) lr |= 4; @@ -2011,6 +2298,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) if (nr == 0xab) { env->regs[15] += 2; env->regs[0] = do_arm_semihosting(env); + qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n"); return; } } @@ -2064,6 +2352,8 @@ void arm_cpu_do_interrupt(CPUState *cs) assert(!IS_M(env)); + arm_log_exception(env->exception_index); + /* TODO: Vectored interrupt controller. */ switch (env->exception_index) { case EXCP_UDEF: @@ -2091,6 +2381,7 @@ void arm_cpu_do_interrupt(CPUState *cs) || (mask == 0xab && env->thumb)) && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { env->regs[0] = do_arm_semihosting(env); + qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n"); return; } } @@ -2108,18 +2399,23 @@ void arm_cpu_do_interrupt(CPUState *cs) && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { env->regs[15] += 2; env->regs[0] = do_arm_semihosting(env); + qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n"); return; } } env->cp15.c5_insn = 2; /* Fall through to prefetch abort. */ case EXCP_PREFETCH_ABORT: + qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n", + env->cp15.c5_insn, env->cp15.c6_insn); new_mode = ARM_CPU_MODE_ABT; addr = 0x0c; mask = CPSR_A | CPSR_I; offset = 4; break; case EXCP_DATA_ABORT: + qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n", + env->cp15.c5_data, env->cp15.c6_data); new_mode = ARM_CPU_MODE_ABT; addr = 0x10; mask = CPSR_A | CPSR_I; diff --git a/target-arm/machine.c b/target-arm/machine.c index 6d4c2d4ed0..5b6f3754ca 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id) const VMStateDescription vmstate_arm_cpu = { .name = "cpu", - .version_id = 12, - .minimum_version_id = 12, - .minimum_version_id_old = 12, + .version_id = 13, + .minimum_version_id = 13, + .minimum_version_id_old = 13, .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField[]) { @@ -257,6 +257,8 @@ const VMStateDescription vmstate_arm_cpu = { VMSTATE_UINT32(env.exclusive_val, ARMCPU), VMSTATE_UINT32(env.exclusive_high, ARMCPU), VMSTATE_UINT64(env.features, ARMCPU), + VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU), + VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU), VMSTATE_END_OF_LIST() }, .subsections = (VMStateSubsection[]) { diff --git a/target-arm/translate.c b/target-arm/translate.c index 6db4c50df4..d1e8538142 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6280,6 +6280,10 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) break; } + if (use_icount && (ri->type & ARM_CP_IO)) { + gen_io_start(); + } + if (isread) { /* Read */ if (is64) { @@ -6369,14 +6373,20 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) store_cpu_offset(tmp, ri->fieldoffset); } } + } + + if (use_icount && (ri->type & ARM_CP_IO)) { + /* I/O operations must end the TB here (whether read or write) */ + gen_io_end(); + gen_lookup_tb(s); + } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { /* We default to ending the TB on a coprocessor register write, * but allow this to be suppressed by the register definition * (usually only necessary to work around guest bugs). */ - if (!(ri->type & ARM_CP_SUPPRESS_TB_END)) { - gen_lookup_tb(s); - } + gen_lookup_tb(s); } + return 0; } diff --git a/target-cris/Makefile.objs b/target-cris/Makefile.objs index afb87bcc80..7779227fc4 100644 --- a/target-cris/Makefile.objs +++ b/target-cris/Makefile.objs @@ -1,2 +1,3 @@ obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o obj-$(CONFIG_SOFTMMU) += mmu.o machine.o diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h index d7baf0746a..75593667d6 100644 --- a/target-cris/cpu-qom.h +++ b/target-cris/cpu-qom.h @@ -81,4 +81,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + #endif diff --git a/target-cris/cpu.c b/target-cris/cpu.c index ba095e75a5..44301a4b10 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -137,10 +137,11 @@ void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf) static void cris_cpu_realizefn(DeviceState *dev, Error **errp) { - CRISCPU *cpu = CRIS_CPU(dev); + CPUState *cs = CPU(dev); CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + qemu_init_vcpu(cs); ccc->parent_realize(dev, errp); } @@ -175,6 +176,7 @@ static void crisv8_cpu_class_init(ObjectClass *oc, void *data) ccc->vr = 8; cc->do_interrupt = crisv10_cpu_do_interrupt; + cc->gdb_read_register = crisv10_cpu_gdb_read_register; } static void crisv9_cpu_class_init(ObjectClass *oc, void *data) @@ -184,6 +186,7 @@ static void crisv9_cpu_class_init(ObjectClass *oc, void *data) ccc->vr = 9; cc->do_interrupt = crisv10_cpu_do_interrupt; + cc->gdb_read_register = crisv10_cpu_gdb_read_register; } static void crisv10_cpu_class_init(ObjectClass *oc, void *data) @@ -193,6 +196,7 @@ static void crisv10_cpu_class_init(ObjectClass *oc, void *data) ccc->vr = 10; cc->do_interrupt = crisv10_cpu_do_interrupt; + cc->gdb_read_register = crisv10_cpu_gdb_read_register; } static void crisv11_cpu_class_init(ObjectClass *oc, void *data) @@ -202,6 +206,7 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void *data) ccc->vr = 11; cc->do_interrupt = crisv10_cpu_do_interrupt; + cc->gdb_read_register = crisv10_cpu_gdb_read_register; } static void crisv32_cpu_class_init(ObjectClass *oc, void *data) @@ -255,9 +260,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = cris_cpu_do_interrupt; cc->dump_state = cris_cpu_dump_state; cc->set_pc = cris_cpu_set_pc; + cc->gdb_read_register = cris_cpu_gdb_read_register; + cc->gdb_write_register = cris_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = cris_cpu_get_phys_page_debug; #endif + + cc->gdb_num_core_regs = 49; } static const TypeInfo cris_cpu_type_info = { diff --git a/target-cris/gdbstub.c b/target-cris/gdbstub.c new file mode 100644 index 0000000000..5db3683ab6 --- /dev/null +++ b/target-cris/gdbstub.c @@ -0,0 +1,130 @@ +/* + * CRIS gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + CRISCPU *cpu = CRIS_CPU(cs); + CPUCRISState *env = &cpu->env; + + if (n < 15) { + return gdb_get_reg32(mem_buf, env->regs[n]); + } + + if (n == 15) { + return gdb_get_reg32(mem_buf, env->pc); + } + + if (n < 32) { + switch (n) { + case 16: + return gdb_get_reg8(mem_buf, env->pregs[n - 16]); + case 17: + return gdb_get_reg8(mem_buf, env->pregs[n - 16]); + case 20: + case 21: + return gdb_get_reg16(mem_buf, env->pregs[n - 16]); + default: + if (n >= 23) { + return gdb_get_reg32(mem_buf, env->pregs[n - 16]); + } + break; + } + } + return 0; +} + +int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + CRISCPU *cpu = CRIS_CPU(cs); + CPUCRISState *env = &cpu->env; + uint8_t srs; + + srs = env->pregs[PR_SRS]; + if (n < 16) { + return gdb_get_reg32(mem_buf, env->regs[n]); + } + + if (n >= 21 && n < 32) { + return gdb_get_reg32(mem_buf, env->pregs[n - 16]); + } + if (n >= 33 && n < 49) { + return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]); + } + switch (n) { + case 16: + return gdb_get_reg8(mem_buf, env->pregs[0]); + case 17: + return gdb_get_reg8(mem_buf, env->pregs[1]); + case 18: + return gdb_get_reg32(mem_buf, env->pregs[2]); + case 19: + return gdb_get_reg8(mem_buf, srs); + case 20: + return gdb_get_reg16(mem_buf, env->pregs[4]); + case 32: + return gdb_get_reg32(mem_buf, env->pc); + } + + return 0; +} + +int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + CRISCPU *cpu = CRIS_CPU(cs); + CPUCRISState *env = &cpu->env; + uint32_t tmp; + + if (n > 49) { + return 0; + } + + tmp = ldl_p(mem_buf); + + if (n < 16) { + env->regs[n] = tmp; + } + + if (n >= 21 && n < 32) { + env->pregs[n - 16] = tmp; + } + + /* FIXME: Should support function regs be writable? */ + switch (n) { + case 16: + return 1; + case 17: + return 1; + case 18: + env->pregs[PR_PID] = tmp; + break; + case 19: + return 1; + case 20: + return 2; + case 32: + env->pc = tmp; + break; + } + + return 4; +} diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs index c1d4f059da..da1fc404c7 100644 --- a/target-i386/Makefile.objs +++ b/target-i386/Makefile.objs @@ -1,8 +1,9 @@ obj-y += translate.o helper.o cpu.o obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o +obj-y += gdbstub.o obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o -obj-$(CONFIG_KVM) += kvm.o hyperv.o +obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-$(CONFIG_LINUX_USER) += ioport-user.o obj-$(CONFIG_BSD_USER) += ioport-user.o diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c index 10dc2284bf..0bbed239f8 100644 --- a/target-i386/arch_dump.c +++ b/target-i386/arch_dump.c @@ -15,6 +15,7 @@ #include "exec/cpu-all.h" #include "sysemu/dump.h" #include "elf.h" +#include "sysemu/memory_mapping.h" #ifdef TARGET_X86_64 typedef struct { @@ -389,10 +390,11 @@ int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs, return cpu_write_qemu_note(f, &cpu->env, opaque, 0); } -int cpu_get_dump_info(ArchDumpInfo *info) +int cpu_get_dump_info(ArchDumpInfo *info, + const GuestPhysBlockList *guest_phys_blocks) { bool lma = false; - RAMBlock *block; + GuestPhysBlock *block; #ifdef TARGET_X86_64 X86CPU *first_x86_cpu = X86_CPU(first_cpu); @@ -412,8 +414,8 @@ int cpu_get_dump_info(ArchDumpInfo *info) } else { info->d_class = ELFCLASS32; - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - if (block->offset + block->length > UINT_MAX) { + QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { + if (block->target_end > UINT_MAX) { /* The memory size is greater than 4G */ info->d_class = ELFCLASS64; break; diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index d928562c53..c4447c2b6e 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -66,8 +66,19 @@ typedef struct X86CPU { CPUX86State env; + bool hyperv_vapic; + bool hyperv_relaxed_timing; + int hyperv_spinlock_attempts; + /* Features that were filtered out because of missing host capabilities */ uint32_t filtered_features[FEATURE_WORDS]; + + /* Enable PMU CPUID bits. This can't be enabled by default yet because + * it doesn't have ABI stability guarantees, as it passes all PMU CPUID + * bits returned by GET_SUPPORTED_CPUID (that depend on host CPU and kernel + * capabilities) directly to the guest. + */ + bool enable_pmu; } X86CPU; static inline X86CPU *x86_env_get_cpu(CPUX86State *env) @@ -106,4 +117,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index cd350cb8e4..42c5de034e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -35,8 +35,6 @@ #include "qapi/visitor.h" #include "sysemu/arch_init.h" -#include "hyperv.h" - #include "hw/hw.h" #if defined(CONFIG_KVM) #include <linux/kvm_para.h> @@ -1475,9 +1473,11 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque, error_propagate(errp, err); } -static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) +static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t *x86_cpu_def, + const char *name) { x86_def_t *def; + Error *err = NULL; int i; if (name == NULL) { @@ -1485,6 +1485,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) } if (kvm_enabled() && strcmp(name, "host") == 0) { kvm_cpu_fill_host(x86_cpu_def); + object_property_set_bool(OBJECT(cpu), true, "pmu", &err); + assert_no_error(err); return 0; } @@ -1587,12 +1589,19 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp); } else if (!strcmp(featurestr, "hv-spinlocks")) { char *err; + const int min = 0xFFF; numvalue = strtoul(val, &err, 0); if (!*val || *err) { error_setg(errp, "bad numerical value %s", val); goto out; } - hyperv_set_spinlock_retries(numvalue); + if (numvalue < min) { + fprintf(stderr, "hv-spinlocks value shall always be >= 0x%x" + ", fixup will be removed in future versions\n", + min); + numvalue = min; + } + cpu->hyperv_spinlock_attempts = numvalue; } else { error_setg(errp, "unrecognized feature %s", featurestr); goto out; @@ -1602,9 +1611,9 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) } else if (!strcmp(featurestr, "enforce")) { check_cpuid = enforce_cpuid = 1; } else if (!strcmp(featurestr, "hv_relaxed")) { - hyperv_enable_relaxed_timing(true); + cpu->hyperv_relaxed_timing = true; } else if (!strcmp(featurestr, "hv_vapic")) { - hyperv_enable_vapic_recommended(true); + cpu->hyperv_vapic = true; } else { error_setg(errp, "feature string `%s' not in format (+feature|" "-feature|feature=xyz)", featurestr); @@ -1742,7 +1751,7 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp) memset(def, 0, sizeof(*def)); - if (cpu_x86_find_by_name(def, name) < 0) { + if (cpu_x86_find_by_name(cpu, def, name) < 0) { error_setg(errp, "Unable to find CPU definition: %s", name); return; } @@ -1820,7 +1829,11 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge, } out: - error_propagate(errp, error); + if (error != NULL) { + error_propagate(errp, error); + object_unref(OBJECT(cpu)); + cpu = NULL; + } g_strfreev(model_pieces); return cpu; } @@ -1839,7 +1852,7 @@ X86CPU *cpu_x86_init(const char *cpu_model) out: if (error) { - fprintf(stderr, "%s\n", error_get_pretty(error)); + error_report("%s", error_get_pretty(error)); error_free(error); if (cpu != NULL) { object_unref(OBJECT(cpu)); @@ -2016,7 +2029,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0xA: /* Architectural Performance Monitoring Leaf */ - if (kvm_enabled()) { + if (kvm_enabled() && cpu->enable_pmu) { KVMState *s = cs->kvm_state; *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); @@ -2333,6 +2346,7 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) static void x86_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); X86CPU *cpu = X86_CPU(dev); X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); CPUX86State *env = &cpu->env; @@ -2387,12 +2401,13 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) #endif mce_init(cpu); + qemu_init_vcpu(cs); x86_cpu_apic_realize(cpu, &local_err); if (local_err != NULL) { goto out; } - cpu_reset(CPU(cpu)); + cpu_reset(cs); xcc->parent_realize(dev, &local_err); out: @@ -2479,6 +2494,7 @@ static void x86_cpu_initfn(Object *obj) x86_cpu_get_feature_words, NULL, NULL, (void *)cpu->filtered_features, NULL); + cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); /* init various static tables used in TCG mode */ @@ -2520,6 +2536,11 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) cpu->env.eip = tb->pc - tb->cs_base; } +static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), + DEFINE_PROP_END_OF_LIST() +}; + static void x86_cpu_common_class_init(ObjectClass *oc, void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); @@ -2529,6 +2550,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) xcc->parent_realize = dc->realize; dc->realize = x86_cpu_realizefn; dc->bus_type = TYPE_ICC_BUS; + dc->props = x86_cpu_properties; xcc->parent_reset = cc->reset; cc->reset = x86_cpu_reset; @@ -2538,6 +2560,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->dump_state = x86_cpu_dump_state; cc->set_pc = x86_cpu_set_pc; cc->synchronize_from_tb = x86_cpu_synchronize_from_tb; + cc->gdb_read_register = x86_cpu_gdb_read_register; + cc->gdb_write_register = x86_cpu_gdb_write_register; cc->get_arch_id = x86_cpu_get_arch_id; cc->get_paging_enabled = x86_cpu_get_paging_enabled; #ifndef CONFIG_USER_ONLY @@ -2549,6 +2573,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote; cc->vmsd = &vmstate_x86_cpu; #endif + cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25; } static const TypeInfo x86_cpu_type_info = { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 31de2653d0..5723eff9a8 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -562,24 +562,28 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */ -#define EXCP00_DIVZ 0 -#define EXCP01_DB 1 -#define EXCP02_NMI 2 -#define EXCP03_INT3 3 -#define EXCP04_INTO 4 -#define EXCP05_BOUND 5 -#define EXCP06_ILLOP 6 -#define EXCP07_PREX 7 -#define EXCP08_DBLE 8 -#define EXCP09_XERR 9 -#define EXCP0A_TSS 10 -#define EXCP0B_NOSEG 11 -#define EXCP0C_STACK 12 -#define EXCP0D_GPF 13 -#define EXCP0E_PAGE 14 -#define EXCP10_COPR 16 -#define EXCP11_ALGN 17 -#define EXCP12_MCHK 18 +#ifndef HYPERV_SPINLOCK_NEVER_RETRY +#define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF +#endif + +#define EXCP00_DIVZ 0 +#define EXCP01_DB 1 +#define EXCP02_NMI 2 +#define EXCP03_INT3 3 +#define EXCP04_INTO 4 +#define EXCP05_BOUND 5 +#define EXCP06_ILLOP 6 +#define EXCP07_PREX 7 +#define EXCP08_DBLE 8 +#define EXCP09_XERR 9 +#define EXCP0A_TSS 10 +#define EXCP0B_NOSEG 11 +#define EXCP0C_STACK 12 +#define EXCP0D_GPF 13 +#define EXCP0E_PAGE 14 +#define EXCP10_COPR 16 +#define EXCP11_ALGN 17 +#define EXCP12_MCHK 18 #define EXCP_SYSCALL 0x100 /* only happens in user only emulation for syscall instruction */ diff --git a/target-i386/gdbstub.c b/target-i386/gdbstub.c new file mode 100644 index 0000000000..15bebeff89 --- /dev/null +++ b/target-i386/gdbstub.c @@ -0,0 +1,231 @@ +/* + * x86 gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +#ifdef TARGET_X86_64 +static const int gpr_map[16] = { + R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP, + 8, 9, 10, 11, 12, 13, 14, 15 +}; +#else +#define gpr_map gpr_map32 +#endif +static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +#define IDX_IP_REG CPU_NB_REGS +#define IDX_FLAGS_REG (IDX_IP_REG + 1) +#define IDX_SEG_REGS (IDX_FLAGS_REG + 1) +#define IDX_FP_REGS (IDX_SEG_REGS + 6) +#define IDX_XMM_REGS (IDX_FP_REGS + 16) +#define IDX_MXCSR_REG (IDX_XMM_REGS + CPU_NB_REGS) + +int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (n < CPU_NB_REGS) { + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]); + } else if (n < CPU_NB_REGS32) { + return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]); + } + } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { +#ifdef USE_X86LDOUBLE + /* FIXME: byteswap float values - after fixing fpregs layout. */ + memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10); +#else + memset(mem_buf, 0, 10); +#endif + return 10; + } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { + n -= IDX_XMM_REGS; + if (n < CPU_NB_REGS32 || + (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { + stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0)); + stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1)); + return 16; + } + } else { + switch (n) { + case IDX_IP_REG: + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + return gdb_get_reg64(mem_buf, env->eip); + } else { + return gdb_get_reg32(mem_buf, env->eip); + } + case IDX_FLAGS_REG: + return gdb_get_reg32(mem_buf, env->eflags); + + case IDX_SEG_REGS: + return gdb_get_reg32(mem_buf, env->segs[R_CS].selector); + case IDX_SEG_REGS + 1: + return gdb_get_reg32(mem_buf, env->segs[R_SS].selector); + case IDX_SEG_REGS + 2: + return gdb_get_reg32(mem_buf, env->segs[R_DS].selector); + case IDX_SEG_REGS + 3: + return gdb_get_reg32(mem_buf, env->segs[R_ES].selector); + case IDX_SEG_REGS + 4: + return gdb_get_reg32(mem_buf, env->segs[R_FS].selector); + case IDX_SEG_REGS + 5: + return gdb_get_reg32(mem_buf, env->segs[R_GS].selector); + + case IDX_FP_REGS + 8: + return gdb_get_reg32(mem_buf, env->fpuc); + case IDX_FP_REGS + 9: + return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) | + (env->fpstt & 0x7) << 11); + case IDX_FP_REGS + 10: + return gdb_get_reg32(mem_buf, 0); /* ftag */ + case IDX_FP_REGS + 11: + return gdb_get_reg32(mem_buf, 0); /* fiseg */ + case IDX_FP_REGS + 12: + return gdb_get_reg32(mem_buf, 0); /* fioff */ + case IDX_FP_REGS + 13: + return gdb_get_reg32(mem_buf, 0); /* foseg */ + case IDX_FP_REGS + 14: + return gdb_get_reg32(mem_buf, 0); /* fooff */ + case IDX_FP_REGS + 15: + return gdb_get_reg32(mem_buf, 0); /* fop */ + + case IDX_MXCSR_REG: + return gdb_get_reg32(mem_buf, env->mxcsr); + } + } + return 0; +} + +static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf) +{ + CPUX86State *env = &cpu->env; + uint16_t selector = ldl_p(mem_buf); + + if (selector != env->segs[sreg].selector) { +#if defined(CONFIG_USER_ONLY) + cpu_x86_load_seg(env, sreg, selector); +#else + unsigned int limit, flags; + target_ulong base; + + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + base = selector << 4; + limit = 0xffff; + flags = 0; + } else { + if (!cpu_x86_get_descr_debug(env, selector, &base, &limit, + &flags)) { + return 4; + } + } + cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags); +#endif + } + return 4; +} + +int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint32_t tmp; + + if (n < CPU_NB_REGS) { + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + env->regs[gpr_map[n]] = ldtul_p(mem_buf); + return sizeof(target_ulong); + } else if (n < CPU_NB_REGS32) { + n = gpr_map32[n]; + env->regs[n] &= ~0xffffffffUL; + env->regs[n] |= (uint32_t)ldl_p(mem_buf); + return 4; + } + } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { +#ifdef USE_X86LDOUBLE + /* FIXME: byteswap float values - after fixing fpregs layout. */ + memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10); +#endif + return 10; + } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { + n -= IDX_XMM_REGS; + if (n < CPU_NB_REGS32 || + (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { + env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf); + env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8); + return 16; + } + } else { + switch (n) { + case IDX_IP_REG: + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + env->eip = ldq_p(mem_buf); + return 8; + } else { + env->eip &= ~0xffffffffUL; + env->eip |= (uint32_t)ldl_p(mem_buf); + return 4; + } + case IDX_FLAGS_REG: + env->eflags = ldl_p(mem_buf); + return 4; + + case IDX_SEG_REGS: + return x86_cpu_gdb_load_seg(cpu, R_CS, mem_buf); + case IDX_SEG_REGS + 1: + return x86_cpu_gdb_load_seg(cpu, R_SS, mem_buf); + case IDX_SEG_REGS + 2: + return x86_cpu_gdb_load_seg(cpu, R_DS, mem_buf); + case IDX_SEG_REGS + 3: + return x86_cpu_gdb_load_seg(cpu, R_ES, mem_buf); + case IDX_SEG_REGS + 4: + return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf); + case IDX_SEG_REGS + 5: + return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf); + + case IDX_FP_REGS + 8: + env->fpuc = ldl_p(mem_buf); + return 4; + case IDX_FP_REGS + 9: + tmp = ldl_p(mem_buf); + env->fpstt = (tmp >> 11) & 7; + env->fpus = tmp & ~0x3800; + return 4; + case IDX_FP_REGS + 10: /* ftag */ + return 4; + case IDX_FP_REGS + 11: /* fiseg */ + return 4; + case IDX_FP_REGS + 12: /* fioff */ + return 4; + case IDX_FP_REGS + 13: /* foseg */ + return 4; + case IDX_FP_REGS + 14: /* fooff */ + return 4; + case IDX_FP_REGS + 15: /* fop */ + return 4; + + case IDX_MXCSR_REG: + env->mxcsr = ldl_p(mem_buf); + return 4; + } + } + /* Unrecognised register. */ + return 0; +} diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c deleted file mode 100644 index f284e99772..0000000000 --- a/target-i386/hyperv.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * QEMU Hyper-V support - * - * Copyright Red Hat, Inc. 2011 - * - * Author: Vadim Rozenfeld <vrozenfe@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "hyperv.h" - -static bool hyperv_vapic; -static bool hyperv_relaxed_timing; -static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; - -void hyperv_enable_vapic_recommended(bool val) -{ - hyperv_vapic = val; -} - -void hyperv_enable_relaxed_timing(bool val) -{ - hyperv_relaxed_timing = val; -} - -void hyperv_set_spinlock_retries(int val) -{ - hyperv_spinlock_attempts = val; - if (hyperv_spinlock_attempts < 0xFFF) { - hyperv_spinlock_attempts = 0xFFF; - } -} - -bool hyperv_enabled(void) -{ - return hyperv_hypercall_available() || hyperv_relaxed_timing_enabled(); -} - -bool hyperv_hypercall_available(void) -{ - if (hyperv_vapic || - (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) { - return true; - } - return false; -} - -bool hyperv_vapic_recommended(void) -{ - return hyperv_vapic; -} - -bool hyperv_relaxed_timing_enabled(void) -{ - return hyperv_relaxed_timing; -} - -int hyperv_get_spinlock_retries(void) -{ - return hyperv_spinlock_attempts; -} diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h deleted file mode 100644 index bacb1d4373..0000000000 --- a/target-i386/hyperv.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * QEMU Hyper-V support - * - * Copyright Red Hat, Inc. 2011 - * - * Author: Vadim Rozenfeld <vrozenfe@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef QEMU_HW_HYPERV_H -#define QEMU_HW_HYPERV_H 1 - -#include "qemu-common.h" -#ifdef CONFIG_KVM -#include <asm/hyperv.h> -#endif - -#ifndef HYPERV_SPINLOCK_NEVER_RETRY -#define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF -#endif - -#ifndef KVM_CPUID_SIGNATURE_NEXT -#define KVM_CPUID_SIGNATURE_NEXT 0x40000100 -#endif - -#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_KVM) -void hyperv_enable_vapic_recommended(bool val); -void hyperv_enable_relaxed_timing(bool val); -void hyperv_set_spinlock_retries(int val); -#else -static inline void hyperv_enable_vapic_recommended(bool val) { } -static inline void hyperv_enable_relaxed_timing(bool val) { } -static inline void hyperv_set_spinlock_retries(int val) { } -#endif - -bool hyperv_enabled(void); -bool hyperv_hypercall_available(void); -bool hyperv_vapic_recommended(void); -bool hyperv_relaxed_timing_enabled(void); -int hyperv_get_spinlock_retries(void); - -#endif /* QEMU_HW_HYPERV_H */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 58f7bb7909..749aa09a21 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -31,7 +31,7 @@ #include "hw/i386/pc.h" #include "hw/i386/apic.h" #include "exec/ioport.h" -#include "hyperv.h" +#include <asm/hyperv.h> #include "hw/pci/pci.h" //#define DEBUG_KVM @@ -424,6 +424,22 @@ unsigned long kvm_arch_vcpu_id(CPUState *cs) return cpu->env.cpuid_apic_id; } +#ifndef KVM_CPUID_SIGNATURE_NEXT +#define KVM_CPUID_SIGNATURE_NEXT 0x40000100 +#endif + +static bool hyperv_hypercall_available(X86CPU *cpu) +{ + return cpu->hyperv_vapic || + (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY); +} + +static bool hyperv_enabled(X86CPU *cpu) +{ + return hyperv_hypercall_available(cpu) || + cpu->hyperv_relaxed_timing; +} + #define KVM_MAX_CPUID_ENTRIES 100 int kvm_arch_init_vcpu(CPUState *cs) @@ -446,7 +462,7 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_SIGNATURE; - if (!hyperv_enabled()) { + if (!hyperv_enabled(cpu)) { memcpy(signature, "KVMKVMKVM\0\0\0", 12); c->eax = 0; } else { @@ -462,7 +478,7 @@ int kvm_arch_init_vcpu(CPUState *cs) c->function = KVM_CPUID_FEATURES; c->eax = env->features[FEAT_KVM]; - if (hyperv_enabled()) { + if (hyperv_enabled(cpu)) { memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); c->eax = signature[0]; @@ -475,10 +491,10 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_FEATURES; - if (hyperv_relaxed_timing_enabled()) { + if (cpu->hyperv_relaxed_timing) { c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; } - if (hyperv_vapic_recommended()) { + if (cpu->hyperv_vapic) { c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; } @@ -486,13 +502,13 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; - if (hyperv_relaxed_timing_enabled()) { + if (cpu->hyperv_relaxed_timing) { c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; } - if (hyperv_vapic_recommended()) { + if (cpu->hyperv_vapic) { c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED; } - c->ebx = hyperv_get_spinlock_retries(); + c->ebx = cpu->hyperv_spinlock_attempts; c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); @@ -1186,11 +1202,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_CTRL, env->msr_global_ctrl); } - if (hyperv_hypercall_available()) { + if (hyperv_hypercall_available(cpu)) { kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0); kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0); } - if (hyperv_vapic_recommended()) { + if (cpu->hyperv_vapic) { kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0); } if (has_msr_feature_control) { @@ -1735,7 +1751,7 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu) */ if (reinject_trap || (!kvm_has_robust_singlestep() && cs->singlestep_enabled)) { - ret = kvm_update_guest_debug(env, reinject_trap); + ret = kvm_update_guest_debug(cs, reinject_trap); } return ret; } diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs index ca20f21443..40236876c8 100644 --- a/target-lm32/Makefile.objs +++ b/target-lm32/Makefile.objs @@ -1,2 +1,3 @@ obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h index 9e2732919d..723f6049c3 100644 --- a/target-lm32/cpu-qom.h +++ b/target-lm32/cpu-qom.h @@ -79,5 +79,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu); void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index ce55e4807d..869878c04a 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -46,10 +46,12 @@ static void lm32_cpu_reset(CPUState *s) static void lm32_cpu_realizefn(DeviceState *dev, Error **errp) { - LM32CPU *cpu = LM32_CPU(dev); + CPUState *cs = CPU(dev); LM32CPUClass *lcc = LM32_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + + qemu_init_vcpu(cs); lcc->parent_realize(dev, errp); } @@ -87,10 +89,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = lm32_cpu_do_interrupt; cc->dump_state = lm32_cpu_dump_state; cc->set_pc = lm32_cpu_set_pc; + cc->gdb_read_register = lm32_cpu_gdb_read_register; + cc->gdb_write_register = lm32_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug; cc->vmsd = &vmstate_lm32_cpu; #endif + cc->gdb_num_core_regs = 32 + 7; } static const TypeInfo lm32_cpu_type_info = { diff --git a/target-lm32/gdbstub.c b/target-lm32/gdbstub.c new file mode 100644 index 0000000000..4979a98d74 --- /dev/null +++ b/target-lm32/gdbstub.c @@ -0,0 +1,92 @@ +/* + * LM32 gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" +#include "hw/lm32/lm32_pic.h" + +int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + LM32CPU *cpu = LM32_CPU(cs); + CPULM32State *env = &cpu->env; + + if (n < 32) { + return gdb_get_reg32(mem_buf, env->regs[n]); + } else { + switch (n) { + case 32: + return gdb_get_reg32(mem_buf, env->pc); + /* FIXME: put in right exception ID */ + case 33: + return gdb_get_reg32(mem_buf, 0); + case 34: + return gdb_get_reg32(mem_buf, env->eba); + case 35: + return gdb_get_reg32(mem_buf, env->deba); + case 36: + return gdb_get_reg32(mem_buf, env->ie); + case 37: + return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state)); + case 38: + return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state)); + } + } + return 0; +} + +int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + LM32CPU *cpu = LM32_CPU(cs); + CPUClass *cc = CPU_GET_CLASS(cs); + CPULM32State *env = &cpu->env; + uint32_t tmp; + + if (n > cc->gdb_num_core_regs) { + return 0; + } + + tmp = ldl_p(mem_buf); + + if (n < 32) { + env->regs[n] = tmp; + } else { + switch (n) { + case 32: + env->pc = tmp; + break; + case 34: + env->eba = tmp; + break; + case 35: + env->deba = tmp; + break; + case 36: + env->ie = tmp; + break; + case 37: + lm32_pic_set_im(env->pic_state, tmp); + break; + case 38: + lm32_pic_set_ip(env->pic_state, tmp); + break; + } + } + return 4; +} diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index f106873ad8..2dab9f27b4 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -4,7 +4,7 @@ #include "qemu/host-utils.h" #include "hw/lm32/lm32_pic.h" -#include "hw/lm32/lm32_juart.h" +#include "hw/char/lm32_juart.h" #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu diff --git a/target-m68k/Makefile.objs b/target-m68k/Makefile.objs index 2e2b85044d..02cf616a78 100644 --- a/target-m68k/Makefile.objs +++ b/target-m68k/Makefile.objs @@ -1,2 +1,3 @@ obj-y += m68k-semi.o obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h index 7115707e91..7f388eda68 100644 --- a/target-m68k/cpu-qom.h +++ b/target-m68k/cpu-qom.h @@ -74,5 +74,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu); void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 988f476257..008d8db2da 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -143,12 +143,14 @@ static const M68kCPUInfo m68k_cpus[] = { static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); M68kCPU *cpu = M68K_CPU(dev); M68kCPUClass *mcc = M68K_CPU_GET_CLASS(dev); m68k_cpu_init_gdb(cpu); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + qemu_init_vcpu(cs); mcc->parent_realize(dev, errp); } @@ -190,10 +192,14 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) cc->do_interrupt = m68k_cpu_do_interrupt; cc->dump_state = m68k_cpu_dump_state; cc->set_pc = m68k_cpu_set_pc; + cc->gdb_read_register = m68k_cpu_gdb_read_register; + cc->gdb_write_register = m68k_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug; #endif dc->vmsd = &vmstate_m68k_cpu; + cc->gdb_num_core_regs = 18; + cc->gdb_core_xml_file = "cf-core.xml"; } static void register_cpu_type(const M68kCPUInfo *info) diff --git a/target-m68k/gdbstub.c b/target-m68k/gdbstub.c new file mode 100644 index 0000000000..ae8179c016 --- /dev/null +++ b/target-m68k/gdbstub.c @@ -0,0 +1,75 @@ +/* + * m68k gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + + if (n < 8) { + /* D0-D7 */ + return gdb_get_reg32(mem_buf, env->dregs[n]); + } else if (n < 16) { + /* A0-A7 */ + return gdb_get_reg32(mem_buf, env->aregs[n - 8]); + } else { + switch (n) { + case 16: + return gdb_get_reg32(mem_buf, env->sr); + case 17: + return gdb_get_reg32(mem_buf, env->pc); + } + } + /* FP registers not included here because they vary between + ColdFire and m68k. Use XML bits for these. */ + return 0; +} + +int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + uint32_t tmp; + + tmp = ldl_p(mem_buf); + + if (n < 8) { + /* D0-D7 */ + env->dregs[n] = tmp; + } else if (n < 16) { + /* A0-A7 */ + env->aregs[n - 8] = tmp; + } else { + switch (n) { + case 16: + env->sr = tmp; + break; + case 17: + env->pc = tmp; + break; + default: + return 0; + } + } + return 4; +} diff --git a/target-microblaze/Makefile.objs b/target-microblaze/Makefile.objs index 985330eac5..f3d7b44c89 100644 --- a/target-microblaze/Makefile.objs +++ b/target-microblaze/Makefile.objs @@ -1,2 +1,3 @@ obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o obj-$(CONFIG_SOFTMMU) += mmu.o diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h index 1318a36676..35a12b42a5 100644 --- a/target-microblaze/cpu-qom.h +++ b/target-microblaze/cpu-qom.h @@ -75,5 +75,7 @@ void mb_cpu_do_interrupt(CPUState *cs); void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 9f10c8c778..0ef9aa4b74 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -90,10 +90,11 @@ static void mb_cpu_reset(CPUState *s) static void mb_cpu_realizefn(DeviceState *dev, Error **errp) { - MicroBlazeCPU *cpu = MICROBLAZE_CPU(dev); + CPUState *cs = CPU(dev); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + qemu_init_vcpu(cs); mcc->parent_realize(dev, errp); } @@ -141,12 +142,15 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = mb_cpu_do_interrupt; cc->dump_state = mb_cpu_dump_state; cc->set_pc = mb_cpu_set_pc; + cc->gdb_read_register = mb_cpu_gdb_read_register; + cc->gdb_write_register = mb_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->do_unassigned_access = mb_cpu_unassigned_access; cc->get_phys_page_debug = mb_cpu_get_phys_page_debug; #endif dc->vmsd = &vmstate_mb_cpu; dc->props = mb_properties; + cc->gdb_num_core_regs = 32 + 5; } static const TypeInfo mb_cpu_type_info = { diff --git a/target-microblaze/gdbstub.c b/target-microblaze/gdbstub.c new file mode 100644 index 0000000000..a70e2ee3cb --- /dev/null +++ b/target-microblaze/gdbstub.c @@ -0,0 +1,56 @@ +/* + * MicroBlaze gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + CPUMBState *env = &cpu->env; + + if (n < 32) { + return gdb_get_reg32(mem_buf, env->regs[n]); + } else { + return gdb_get_reg32(mem_buf, env->sregs[n - 32]); + } + return 0; +} + +int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + CPUClass *cc = CPU_GET_CLASS(cs); + CPUMBState *env = &cpu->env; + uint32_t tmp; + + if (n > cc->gdb_num_core_regs) { + return 0; + } + + tmp = ldl_p(mem_buf); + + if (n < 32) { + env->regs[n] = tmp; + } else { + env->sregs[n - 32] = tmp; + } + return 4; +} diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs index 119c816518..0277d56e82 100644 --- a/target-mips/Makefile.objs +++ b/target-mips/Makefile.objs @@ -1,2 +1,3 @@ obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o +obj-y += gdbstub.o obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h index 7c8e616392..8877f813f7 100644 --- a/target-mips/cpu-qom.h +++ b/target-mips/cpu-qom.h @@ -78,5 +78,7 @@ void mips_cpu_do_interrupt(CPUState *cpu); void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 4834c86d02..9dd47e84f7 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -62,10 +62,11 @@ static void mips_cpu_reset(CPUState *s) static void mips_cpu_realizefn(DeviceState *dev, Error **errp) { - MIPSCPU *cpu = MIPS_CPU(dev); + CPUState *cs = CPU(dev); MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + qemu_init_vcpu(cs); mcc->parent_realize(dev, errp); } @@ -100,10 +101,14 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) cc->dump_state = mips_cpu_dump_state; cc->set_pc = mips_cpu_set_pc; cc->synchronize_from_tb = mips_cpu_synchronize_from_tb; + cc->gdb_read_register = mips_cpu_gdb_read_register; + cc->gdb_write_register = mips_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->do_unassigned_access = mips_cpu_unassigned_access; cc->get_phys_page_debug = mips_cpu_get_phys_page_debug; #endif + + cc->gdb_num_core_regs = 73; } static const TypeInfo mips_cpu_type_info = { diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 4116de93c3..b088a25017 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -390,7 +390,7 @@ static inline int32_t mipsdsp_mul_q15_q15_overflowflag21(uint16_t a, uint16_t b, temp = 0x7FFFFFFF; set_DSPControl_overflow_flag(1, 21, env); } else { - temp = ((int32_t)(int16_t)a * (int32_t)(int16_t)b) << 1; + temp = ((int16_t)a * (int16_t)b) << 1; } return temp; @@ -583,7 +583,7 @@ static inline int64_t mipsdsp_mul_q31_q31(int32_t ac, uint32_t a, uint32_t b, temp = (0x01ull << 63) - 1; set_DSPControl_overflow_flag(1, 16 + ac, env); } else { - temp = ((uint64_t)a * (uint64_t)b) << 1; + temp = ((int64_t)(int32_t)a * (int32_t)b) << 1; } return temp; @@ -622,7 +622,7 @@ static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b, temp = 0x7FFF0000; set_DSPControl_overflow_flag(1, 21, env); } else { - temp = (a * b) << 1; + temp = ((int16_t)a * (int16_t)b) << 1; temp = temp + 0x00008000; } @@ -648,16 +648,22 @@ static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b, static inline uint16_t mipsdsp_trunc16_sat16_round(int32_t a, CPUMIPSState *env) { - int64_t temp; + uint16_t temp; - temp = (int32_t)a + 0x00008000; - if (a > (int)0x7fff8000) { - temp = 0x7FFFFFFF; + /* + * The value 0x00008000 will be added to the input Q31 value, and the code + * needs to check if the addition causes an overflow. Since a positive value + * is added, overflow can happen in one direction only. + */ + if (a > 0x7FFF7FFF) { + temp = 0x7FFF; set_DSPControl_overflow_flag(1, 22, env); + } else { + temp = ((a + 0x8000) >> 16) & 0xFFFF; } - return (temp >> 16) & 0xFFFF; + return temp; } static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a, diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c new file mode 100644 index 0000000000..5b72d58a44 --- /dev/null +++ b/target-mips/gdbstub.c @@ -0,0 +1,155 @@ +/* + * MIPS gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + if (n < 32) { + return gdb_get_regl(mem_buf, env->active_tc.gpr[n]); + } + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + if (n >= 38 && n < 70) { + if (env->CP0_Status & (1 << CP0St_FR)) { + return gdb_get_regl(mem_buf, + env->active_fpu.fpr[n - 38].d); + } else { + return gdb_get_regl(mem_buf, + env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]); + } + } + switch (n) { + case 70: + return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31); + case 71: + return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0); + } + } + switch (n) { + case 32: + return gdb_get_regl(mem_buf, (int32_t)env->CP0_Status); + case 33: + return gdb_get_regl(mem_buf, env->active_tc.LO[0]); + case 34: + return gdb_get_regl(mem_buf, env->active_tc.HI[0]); + case 35: + return gdb_get_regl(mem_buf, env->CP0_BadVAddr); + case 36: + return gdb_get_regl(mem_buf, (int32_t)env->CP0_Cause); + case 37: + return gdb_get_regl(mem_buf, env->active_tc.PC | + !!(env->hflags & MIPS_HFLAG_M16)); + case 72: + return gdb_get_regl(mem_buf, 0); /* fp */ + case 89: + return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid); + } + if (n >= 73 && n <= 88) { + /* 16 embedded regs. */ + return gdb_get_regl(mem_buf, 0); + } + + return 0; +} + +/* convert MIPS rounding mode in FCR31 to IEEE library */ +static unsigned int ieee_rm[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; +#define RESTORE_ROUNDING_MODE \ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \ + &env->active_fpu.fp_status) + +int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + target_ulong tmp; + + tmp = ldtul_p(mem_buf); + + if (n < 32) { + env->active_tc.gpr[n] = tmp; + return sizeof(target_ulong); + } + if (env->CP0_Config1 & (1 << CP0C1_FP) + && n >= 38 && n < 73) { + if (n < 70) { + if (env->CP0_Status & (1 << CP0St_FR)) { + env->active_fpu.fpr[n - 38].d = tmp; + } else { + env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; + } + } + switch (n) { + case 70: + env->active_fpu.fcr31 = tmp & 0xFF83FFFF; + /* set rounding mode */ + RESTORE_ROUNDING_MODE; + break; + case 71: + env->active_fpu.fcr0 = tmp; + break; + } + return sizeof(target_ulong); + } + switch (n) { + case 32: + env->CP0_Status = tmp; + break; + case 33: + env->active_tc.LO[0] = tmp; + break; + case 34: + env->active_tc.HI[0] = tmp; + break; + case 35: + env->CP0_BadVAddr = tmp; + break; + case 36: + env->CP0_Cause = tmp; + break; + case 37: + env->active_tc.PC = tmp & ~(target_ulong)1; + if (tmp & 1) { + env->hflags |= MIPS_HFLAG_M16; + } else { + env->hflags &= ~(MIPS_HFLAG_M16); + } + break; + case 72: /* fp, ignored */ + break; + default: + if (n > 89) { + return 0; + } + /* Other registers are readonly. Ignore writes. */ + break; + } + + return sizeof(target_ulong); +} diff --git a/target-mips/helper.c b/target-mips/helper.c index 6feef7bcd6..33e0e88637 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -193,7 +193,7 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical, } } #if 0 - qemu_log(TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n", + qemu_log(TARGET_FMT_lx " %d %d => %" HWADDR_PRIx " %d (%d)\n", address, rw, access_type, *physical, *prot, ret); #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 5cf1c3f04b..b828375714 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1735,7 +1735,6 @@ target_ulong helper_evpe(CPUMIPSState *env) void helper_fork(target_ulong arg1, target_ulong arg2) { // arg1 = rt, arg2 = rs - arg1 = 0; // TODO: store to TC register } diff --git a/target-mips/translate.c b/target-mips/translate.c index 877f8dfe88..e2eb908cf3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -9571,8 +9571,7 @@ static void decode_i64_mips16 (DisasContext *ctx, } #endif -static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, - int *is_branch) +static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) { int extend = cpu_lduw_code(env, ctx->pc + 2); int op, rx, ry, funct, sa; @@ -9763,8 +9762,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, return 4; } -static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, - int *is_branch) +static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) { int rx, ry; int sa; @@ -9807,7 +9805,6 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; gen_compute_branch(ctx, op, 4, rx, ry, offset); n_bytes = 4; - *is_branch = 1; break; case M16_OPC_BEQZ: gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1); @@ -10046,9 +10043,6 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); - if (!nd) { - *is_branch = 1; - } } break; case RR_SDBBP: @@ -10193,7 +10187,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } break; case M16_OPC_EXTEND: - decode_extended_mips16_opc(env, ctx, is_branch); + decode_extended_mips16_opc(env, ctx); n_bytes = 4; break; #if defined(TARGET_MIPS64) @@ -10802,7 +10796,7 @@ static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, } -static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) +static void gen_pool16c_insn(DisasContext *ctx) { int rd = mmreg((ctx->opcode >> 3) & 0x7); int rs = mmreg(ctx->opcode & 0x7); @@ -10864,7 +10858,6 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); } - *is_branch = 1; break; case JRC16 + 0: case JRC16 + 1: @@ -10889,7 +10882,6 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) gen_compute_branch(ctx, opc, 2, reg, 31, 0); } - *is_branch = 1; break; case MFHI16 + 0: case MFHI16 + 1: @@ -11020,8 +11012,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, tcg_temp_free(t1); } -static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, - int *is_branch) +static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) { int extension = (ctx->opcode >> 6) & 0x3f; int minor = (ctx->opcode >> 12) & 0xf; @@ -11070,6 +11061,36 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, } break; #endif + case 0x2a: + switch (minor & 3) { + case MADD_ACC: + gen_muldiv(ctx, OPC_MADD, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MADDU_ACC: + gen_muldiv(ctx, OPC_MADDU, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MSUB_ACC: + gen_muldiv(ctx, OPC_MSUB, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MSUBU_ACC: + gen_muldiv(ctx, OPC_MSUBU, (ctx->opcode >> 14) & 3, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x32: + switch (minor & 3) { + case MULT_ACC: + gen_muldiv(ctx, OPC_MULT, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MULTU_ACC: + gen_muldiv(ctx, OPC_MULTU, (ctx->opcode >> 14) & 3, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; case 0x2c: switch (minor) { case SEB: @@ -11122,7 +11143,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, mips32_op = OPC_MSUBU; do_mul: check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, mips32_op, (ctx->opcode >> 14) & 3, rs, rt); + gen_muldiv(ctx, mips32_op, 0, rs, rt); break; default: goto pool32axf_invalid; @@ -11147,12 +11168,10 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, case JALR: case JALR_HB: gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0); - *is_branch = 1; break; case JALRS: case JALRS_HB: gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0); - *is_branch = 1; break; default: goto pool32axf_invalid; @@ -11258,24 +11277,42 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, goto pool32axf_invalid; } break; - case 0x35: + case 0x01: switch (minor & 3) { - case MFHI32: + case MFHI_ACC: gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); break; - case MFLO32: + case MFLO_ACC: gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); break; - case MTHI32: + case MTHI_ACC: gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); break; - case MTLO32: + case MTLO_ACC: gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); break; default: goto pool32axf_invalid; } break; + case 0x35: + switch (minor) { + case MFHI32: + gen_HILO(ctx, OPC_MFHI, 0, rs); + break; + case MFLO32: + gen_HILO(ctx, OPC_MFLO, 0, rs); + break; + case MTHI32: + gen_HILO(ctx, OPC_MTHI, 0, rs); + break; + case MTLO32: + gen_HILO(ctx, OPC_MTLO, 0, rs); + break; + default: + goto pool32axf_invalid; + } + break; default: pool32axf_invalid: MIPS_INVAL("pool32axf"); @@ -11551,7 +11588,7 @@ static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) } static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, - uint16_t insn_hw1, int *is_branch) + uint16_t insn_hw1) { int32_t offset; uint16_t insn; @@ -11685,7 +11722,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); return; case POOL32AXF: - gen_pool32axf(env, ctx, rt, rs, is_branch); + gen_pool32axf(env, ctx, rt, rs); break; case 0x07: generate_exception(ctx, EXCP_BREAK); @@ -12048,7 +12085,6 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, mips32_op = OPC_BGTZ; do_branch: gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1); - *is_branch = 1; break; /* Traps */ @@ -12109,7 +12145,6 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, do_cp1branch: gen_compute_branch1(ctx, mips32_op, (ctx->opcode >> 18) & 0x7, imm << 1); - *is_branch = 1; break; case BPOSGE64: case BPOSGE32: @@ -12216,30 +12251,24 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case JALX32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset); - *is_branch = 1; break; case JALS32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset); - *is_branch = 1; break; case BEQ32: gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1); - *is_branch = 1; break; case BNE32: gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1); - *is_branch = 1; break; case J32: gen_compute_branch(ctx, OPC_J, 4, rt, rs, (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); - *is_branch = 1; break; case JAL32: gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); - *is_branch = 1; break; /* Floating point (COP1) */ case LWC132: @@ -12309,7 +12338,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, } } -static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) +static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) { uint32_t op; @@ -12442,7 +12471,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b } break; case POOL16C: - gen_pool16c_insn(ctx, is_branch); + gen_pool16c_insn(ctx); break; case LWGP16: { @@ -12582,14 +12611,12 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b case B16: gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, SIMM(ctx->opcode, 0, 10) << 1); - *is_branch = 1; break; case BNEZ16: case BEQZ16: gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, mmreg(uMIPS_RD(ctx->opcode)), 0, SIMM(ctx->opcode, 0, 7) << 1); - *is_branch = 1; break; case LI16: { @@ -12610,7 +12637,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b generate_exception(ctx, EXCP_RI); break; default: - decode_micromips32_opc (env, ctx, op, is_branch); + decode_micromips32_opc (env, ctx, op); return 4; } @@ -14346,7 +14373,7 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, /* End MIPSDSP functions. */ -static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) +static void decode_opc (CPUMIPSState *env, DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; @@ -14460,7 +14487,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_JR ... OPC_JALR: gen_compute_branch(ctx, op1, 4, rs, rd, sa); - *is_branch = 1; break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: @@ -15227,7 +15253,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ case OPC_BLTZAL ... OPC_BGEZALL: gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); - *is_branch = 1; break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: @@ -15243,7 +15268,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) #endif check_dsp(ctx); gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); - *is_branch = 1; break; default: /* Invalid */ MIPS_INVAL("regimm"); @@ -15355,12 +15379,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); - *is_branch = 1; break; case OPC_BEQ ... OPC_BGTZ: /* Branch */ case OPC_BEQL ... OPC_BGTZL: gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); - *is_branch = 1; break; case OPC_LB ... OPC_LWR: /* Load and stores */ case OPC_LL: @@ -15420,7 +15442,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_BC1: gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); - *is_branch = 1; break; case OPC_S_FMT: case OPC_D_FMT: @@ -15527,7 +15548,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); - *is_branch = 1; break; case OPC_MDMX: check_insn(ctx, ASE_MDMX); @@ -15553,7 +15573,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, int num_insns; int max_insns; int insn_bytes; - int is_branch; + int is_delay; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -15611,23 +15631,23 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); - is_branch = 0; + is_delay = ctx.hflags & MIPS_HFLAG_BMASK; if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; - decode_opc(env, &ctx, &is_branch); + decode_opc(env, &ctx); } else if (ctx.insn_flags & ASE_MICROMIPS) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_micromips_opc(env, &ctx, &is_branch); + insn_bytes = decode_micromips_opc(env, &ctx); } else if (ctx.insn_flags & ASE_MIPS16) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_mips16_opc(env, &ctx, &is_branch); + insn_bytes = decode_mips16_opc(env, &ctx); } else { generate_exception(&ctx, EXCP_RI); ctx.bstate = BS_STOP; break; } - if (!is_branch) { + if (is_delay) { handle_delay_slot(&ctx, insn_bytes); } ctx.pc += insn_bytes; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 7cf238f34b..c45b1b21b2 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -274,14 +274,13 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) | (1 << CP0C1_CA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_VInt) | (1 << CP0C3_MT), + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_VInt) | (1 << CP0C3_MT) | + (1 << CP0C3_DSPP), .CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, .CCRes = 2, - /* No DSP implemented. */ - .CP0_Status_rw_bitmask = 0x3678FF1F, - /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x3778FF1F, .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) | (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) | (0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) | diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c index 6550be5b35..d97a091eb4 100644 --- a/target-moxie/cpu.c +++ b/target-moxie/cpu.c @@ -45,10 +45,11 @@ static void moxie_cpu_reset(CPUState *s) static void moxie_cpu_realizefn(DeviceState *dev, Error **errp) { - MoxieCPU *cpu = MOXIE_CPU(dev); + CPUState *cs = CPU(dev); MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + qemu_init_vcpu(cs); + cpu_reset(cs); mcc->parent_realize(dev, errp); } diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs index 44dc5399df..397d01650e 100644 --- a/target-openrisc/Makefile.objs +++ b/target-openrisc/Makefile.objs @@ -2,3 +2,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o obj-y += cpu.o exception.o interrupt.o mmu.o translate.o obj-y += exception_helper.o fpu_helper.o int_helper.o \ interrupt_helper.o mmu_helper.o sys_helper.o +obj-y += gdbstub.o diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 3da5a7a8b1..075f00a897 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -66,10 +66,11 @@ static inline void set_feature(OpenRISCCPU *cpu, int feature) static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) { - OpenRISCCPU *cpu = OPENRISC_CPU(dev); + CPUState *cs = CPU(dev); OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + qemu_init_vcpu(cs); + cpu_reset(cs); occ->parent_realize(dev, errp); } @@ -106,6 +107,7 @@ static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model) typename = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, cpu_model); oc = object_class_by_name(typename); + g_free(typename); if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) || object_class_is_abstract(oc))) { return NULL; @@ -154,10 +156,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = openrisc_cpu_do_interrupt; cc->dump_state = openrisc_cpu_dump_state; cc->set_pc = openrisc_cpu_set_pc; + cc->gdb_read_register = openrisc_cpu_gdb_read_register; + cc->gdb_write_register = openrisc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug; dc->vmsd = &vmstate_openrisc_cpu; #endif + cc->gdb_num_core_regs = 32 + 3; } static void cpu_register(const OpenRISCCPUInfo *info) diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 3ddb7674c7..8fd0bc0bf0 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -350,6 +350,8 @@ void openrisc_cpu_do_interrupt(CPUState *cpu); void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void openrisc_translate_init(void); int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, target_ulong address, diff --git a/target-openrisc/gdbstub.c b/target-openrisc/gdbstub.c new file mode 100644 index 0000000000..18bcc46167 --- /dev/null +++ b/target-openrisc/gdbstub.c @@ -0,0 +1,83 @@ +/* + * OpenRISC gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(cs); + CPUOpenRISCState *env = &cpu->env; + + if (n < 32) { + return gdb_get_reg32(mem_buf, env->gpr[n]); + } else { + switch (n) { + case 32: /* PPC */ + return gdb_get_reg32(mem_buf, env->ppc); + + case 33: /* NPC */ + return gdb_get_reg32(mem_buf, env->npc); + + case 34: /* SR */ + return gdb_get_reg32(mem_buf, env->sr); + + default: + break; + } + } + return 0; +} + +int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(cs); + CPUClass *cc = CPU_GET_CLASS(cs); + CPUOpenRISCState *env = &cpu->env; + uint32_t tmp; + + if (n > cc->gdb_num_core_regs) { + return 0; + } + + tmp = ldl_p(mem_buf); + + if (n < 32) { + env->gpr[n] = tmp; + } else { + switch (n) { + case 32: /* PPC */ + env->ppc = tmp; + break; + + case 33: /* NPC */ + env->npc = tmp; + break; + + case 34: /* SR */ + env->sr = tmp; + break; + + default: + break; + } + } + return 4; +} diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 6e78cb3624..f72e3993f7 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -13,3 +13,4 @@ obj-y += timebase_helper.o obj-y += misc_helper.o obj-y += mem_helper.o obj-$(CONFIG_USER_ONLY) += user_only_helper.o +obj-y += gdbstub.o diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 9578ed8891..8dea560383 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -1120,15 +1120,11 @@ #if defined(TODO) POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5, "POWER5") - POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5, - "POWER5GR") #endif -#if defined(TODO) POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P, "POWER5+") - POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P, - "POWER5GS") -#endif + POWERPC_DEF("POWER5+_v2.1", CPU_POWERPC_POWER5P_v21, POWER5P, + "POWER5+ v2.1") #if defined(TODO) POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6, "POWER6") @@ -1143,6 +1139,8 @@ "POWER7 v2.1") POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, "POWER7 v2.3") + POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, + "POWER7+ v2.1") POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, "POWER8 v1.0") POWERPC_DEF("970", CPU_POWERPC_970, 970, @@ -1389,7 +1387,10 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "Boxer", "POWER3" }, { "Dino", "POWER3" }, { "POWER3+", "631" }, + { "POWER5gr", "POWER5" }, + { "POWER5gs", "POWER5+" }, { "POWER7", "POWER7_v2.3" }, + { "POWER7+", "POWER7+_v2.1" }, { "POWER8", "POWER8_v1.0" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" }, diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index 01e488f71c..d9145d147f 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -547,15 +547,15 @@ enum { CPU_POWERPC_POWER4P = 0x00380000, /* XXX: missing 0x003A0201 */ CPU_POWERPC_POWER5 = 0x003A0203, -#define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 CPU_POWERPC_POWER5P = 0x003B0000, -#define CPU_POWERPC_POWER5GS CPU_POWERPC_POWER5P + CPU_POWERPC_POWER5P_v21 = 0x003B0201, CPU_POWERPC_POWER6 = 0x003E0000, CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ CPU_POWERPC_POWER6A = 0x0F000002, CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, + CPU_POWERPC_POWER7P_v21 = 0x004A0201, CPU_POWERPC_POWER8_v10 = 0x004B0100, CPU_POWERPC_970 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 3341c5151d..f3c710a9e5 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -106,5 +106,11 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_ppc_cpu; +#endif #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6f51e1f526..711db083e0 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -948,7 +948,7 @@ struct CPUPPCState { #if defined(TARGET_PPC64) /* PowerPC 64 SLB area */ ppc_slb_t slb[64]; - int slb_nr; + int32_t slb_nr; #endif /* segment registers */ hwaddr htab_base; @@ -957,11 +957,11 @@ struct CPUPPCState { /* externally stored hash table */ uint8_t *external_htab; /* BATs */ - int nb_BATs; + uint32_t nb_BATs; target_ulong DBAT[2][8]; target_ulong IBAT[2][8]; /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */ - int nb_tlb; /* Total number of TLB */ + int32_t nb_tlb; /* Total number of TLB */ int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ int nb_ways; /* Number of ways in the TLB set */ int last_way; /* Last used way used to allocate TLB in a LRU way */ @@ -1176,8 +1176,6 @@ static inline CPUPPCState *cpu_init(const char *cpu_model) #define cpu_signal_handler cpu_ppc_signal_handler #define cpu_list ppc_cpu_list -#define CPU_SAVE_VERSION 4 - /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _user #define MMU_MODE1_SUFFIX _kernel diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c new file mode 100644 index 0000000000..1c910902ea --- /dev/null +++ b/target-ppc/gdbstub.c @@ -0,0 +1,131 @@ +/* + * PowerPC gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +/* Old gdb always expects FP registers. Newer (xml-aware) gdb only + * expects whatever the target description contains. Due to a + * historical mishap the FP registers appear in between core integer + * regs and PC, MSR, CR, and so forth. We hack round this by giving the + * FP regs zero size when talking to a newer gdb. + */ + +int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { + /* gprs */ + return gdb_get_regl(mem_buf, env->gpr[n]); + } else if (n < 64) { + /* fprs */ + if (gdb_has_xml) { + return 0; + } + stfq_p(mem_buf, env->fpr[n-32]); + return 8; + } else { + switch (n) { + case 64: + return gdb_get_regl(mem_buf, env->nip); + case 65: + return gdb_get_regl(mem_buf, env->msr); + case 66: + { + uint32_t cr = 0; + int i; + for (i = 0; i < 8; i++) { + cr |= env->crf[i] << (32 - ((i + 1) * 4)); + } + return gdb_get_reg32(mem_buf, cr); + } + case 67: + return gdb_get_regl(mem_buf, env->lr); + case 68: + return gdb_get_regl(mem_buf, env->ctr); + case 69: + return gdb_get_regl(mem_buf, env->xer); + case 70: + { + if (gdb_has_xml) { + return 0; + } + return gdb_get_reg32(mem_buf, env->fpscr); + } + } + } + return 0; +} + +int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { + /* gprs */ + env->gpr[n] = ldtul_p(mem_buf); + return sizeof(target_ulong); + } else if (n < 64) { + /* fprs */ + if (gdb_has_xml) { + return 0; + } + env->fpr[n-32] = ldfq_p(mem_buf); + return 8; + } else { + switch (n) { + case 64: + env->nip = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 65: + ppc_store_msr(env, ldtul_p(mem_buf)); + return sizeof(target_ulong); + case 66: + { + uint32_t cr = ldl_p(mem_buf); + int i; + for (i = 0; i < 8; i++) { + env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF; + } + return 4; + } + case 67: + env->lr = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 68: + env->ctr = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 69: + env->xer = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 70: + /* fpscr */ + if (gdb_has_xml) { + return 0; + } + store_fpscr(env, ldtul_p(mem_buf), 0xffffffff); + return sizeof(target_ulong); + } + } + return 0; +} diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index b0099e122f..8a196c6cc1 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -40,10 +40,10 @@ //#define DEBUG_KVM #ifdef DEBUG_KVM -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { } while (0) #endif @@ -65,6 +65,7 @@ static int cap_one_reg; static int cap_epr; static int cap_ppc_watchdog; static int cap_papr; +static int cap_htab_fd; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -101,6 +102,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG); /* Note: we don't set cap_papr here, because this capability is * only activated after this by kvmppc_set_papr() */ + cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -417,7 +419,7 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } - idle_timer = qemu_new_timer_ns(vm_clock, kvm_kick_cpu, cpu); + idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, kvm_kick_cpu, cpu); /* Some targets support access to KVM's guest TLB. */ switch (cenv->mmu_model) { @@ -548,7 +550,7 @@ static int kvm_put_fp(CPUState *cs) reg.addr = (uintptr_t)&fpscr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set FPSCR to KVM: %s\n", strerror(errno)); + DPRINTF("Unable to set FPSCR to KVM: %s\n", strerror(errno)); return ret; } @@ -562,7 +564,7 @@ static int kvm_put_fp(CPUState *cs) ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set %s%d to KVM: %s\n", vsx ? "VSR" : "FPR", + DPRINTF("Unable to set %s%d to KVM: %s\n", vsx ? "VSR" : "FPR", i, strerror(errno)); return ret; } @@ -574,7 +576,7 @@ static int kvm_put_fp(CPUState *cs) reg.addr = (uintptr_t)&env->vscr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set VSCR to KVM: %s\n", strerror(errno)); + DPRINTF("Unable to set VSCR to KVM: %s\n", strerror(errno)); return ret; } @@ -583,7 +585,7 @@ static int kvm_put_fp(CPUState *cs) reg.addr = (uintptr_t)&env->avr[i]; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set VR%d to KVM: %s\n", i, strerror(errno)); + DPRINTF("Unable to set VR%d to KVM: %s\n", i, strerror(errno)); return ret; } } @@ -608,7 +610,7 @@ static int kvm_get_fp(CPUState *cs) reg.addr = (uintptr_t)&fpscr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get FPSCR from KVM: %s\n", strerror(errno)); + DPRINTF("Unable to get FPSCR from KVM: %s\n", strerror(errno)); return ret; } else { env->fpscr = fpscr; @@ -622,7 +624,7 @@ static int kvm_get_fp(CPUState *cs) ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get %s%d from KVM: %s\n", + DPRINTF("Unable to get %s%d from KVM: %s\n", vsx ? "VSR" : "FPR", i, strerror(errno)); return ret; } else { @@ -639,7 +641,7 @@ static int kvm_get_fp(CPUState *cs) reg.addr = (uintptr_t)&env->vscr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get VSCR from KVM: %s\n", strerror(errno)); + DPRINTF("Unable to get VSCR from KVM: %s\n", strerror(errno)); return ret; } @@ -648,7 +650,7 @@ static int kvm_get_fp(CPUState *cs) reg.addr = (uintptr_t)&env->avr[i]; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get VR%d from KVM: %s\n", + DPRINTF("Unable to get VR%d from KVM: %s\n", i, strerror(errno)); return ret; } @@ -670,7 +672,7 @@ static int kvm_get_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->vpa_addr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get VPA address from KVM: %s\n", strerror(errno)); + DPRINTF("Unable to get VPA address from KVM: %s\n", strerror(errno)); return ret; } @@ -680,7 +682,7 @@ static int kvm_get_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->slb_shadow_addr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get SLB shadow state from KVM: %s\n", + DPRINTF("Unable to get SLB shadow state from KVM: %s\n", strerror(errno)); return ret; } @@ -690,7 +692,7 @@ static int kvm_get_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->dtl_addr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to get dispatch trace log state from KVM: %s\n", + DPRINTF("Unable to get dispatch trace log state from KVM: %s\n", strerror(errno)); return ret; } @@ -716,7 +718,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->vpa_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set VPA address to KVM: %s\n", strerror(errno)); + DPRINTF("Unable to set VPA address to KVM: %s\n", strerror(errno)); return ret; } } @@ -727,7 +729,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->slb_shadow_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set SLB shadow state to KVM: %s\n", strerror(errno)); + DPRINTF("Unable to set SLB shadow state to KVM: %s\n", strerror(errno)); return ret; } @@ -736,7 +738,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->dtl_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set dispatch trace log state to KVM: %s\n", + DPRINTF("Unable to set dispatch trace log state to KVM: %s\n", strerror(errno)); return ret; } @@ -746,7 +748,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&env->vpa_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - dprintf("Unable to set VPA address to KVM: %s\n", strerror(errno)); + DPRINTF("Unable to set VPA address to KVM: %s\n", strerror(errno)); return ret; } } @@ -864,7 +866,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) #ifdef TARGET_PPC64 if (cap_papr) { if (kvm_put_vpa(cs) < 0) { - dprintf("Warning: Unable to set VPA information to KVM\n"); + DPRINTF("Warning: Unable to set VPA information to KVM\n"); } } #endif /* TARGET_PPC64 */ @@ -1073,7 +1075,7 @@ int kvm_arch_get_registers(CPUState *cs) #ifdef TARGET_PPC64 if (cap_papr) { if (kvm_get_vpa(cs) < 0) { - dprintf("Warning: Unable to get VPA information from KVM\n"); + DPRINTF("Warning: Unable to get VPA information from KVM\n"); } } #endif @@ -1127,14 +1129,14 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) */ irq = KVM_INTERRUPT_SET; - dprintf("injected interrupt %d\n", irq); + DPRINTF("injected interrupt %d\n", irq); r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); if (r < 0) { printf("cpu %d fail inject %x\n", cs->cpu_index, irq); } /* Always wake up soon in case the interrupt was level based */ - qemu_mod_timer(idle_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(idle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (get_ticks_per_sec() / 50)); } @@ -1191,20 +1193,20 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) switch (run->exit_reason) { case KVM_EXIT_DCR: if (run->dcr.is_write) { - dprintf("handle dcr write\n"); + DPRINTF("handle dcr write\n"); ret = kvmppc_handle_dcr_write(env, run->dcr.dcrn, run->dcr.data); } else { - dprintf("handle dcr read\n"); + DPRINTF("handle dcr read\n"); ret = kvmppc_handle_dcr_read(env, run->dcr.dcrn, &run->dcr.data); } break; case KVM_EXIT_HLT: - dprintf("handle halt\n"); + DPRINTF("handle halt\n"); ret = kvmppc_handle_halt(cpu); break; #if defined(TARGET_PPC64) case KVM_EXIT_PAPR_HCALL: - dprintf("handle PAPR hypercall\n"); + DPRINTF("handle PAPR hypercall\n"); run->papr_hcall.ret = spapr_hypercall(cpu, run->papr_hcall.nr, run->papr_hcall.args); @@ -1212,12 +1214,12 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) break; #endif case KVM_EXIT_EPR: - dprintf("handle epr\n"); + DPRINTF("handle epr\n"); run->epr.epr = ldl_phys(env->mpic_iack); ret = 0; break; case KVM_EXIT_WATCHDOG: - dprintf("handle watchdog expiry\n"); + DPRINTF("handle watchdog expiry\n"); watchdog_perform_action(); ret = 0; break; @@ -1626,7 +1628,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) return NULL; } - len = (window_size / SPAPR_TCE_PAGE_SIZE) * sizeof(sPAPRTCE); + len = (window_size / SPAPR_TCE_PAGE_SIZE) * sizeof(uint64_t); /* FIXME: round this up to page size */ table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); @@ -1649,7 +1651,7 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return -1; } - len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(sPAPRTCE); + len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(uint64_t); if ((munmap(table, len) < 0) || (close(fd) < 0)) { fprintf(stderr, "KVM: Unexpected error removing TCE table: %s", @@ -1788,6 +1790,73 @@ static int kvm_ppc_register_host_cpu_type(void) } +int kvmppc_get_htab_fd(bool write) +{ + struct kvm_get_htab_fd s = { + .flags = write ? KVM_GET_HTAB_WRITE : 0, + .start_index = 0, + }; + + if (!cap_htab_fd) { + fprintf(stderr, "KVM version doesn't support saving the hash table\n"); + return -1; + } + + return kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &s); +} + +int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns) +{ + int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + uint8_t buf[bufsize]; + ssize_t rc; + + do { + rc = read(fd, buf, bufsize); + if (rc < 0) { + fprintf(stderr, "Error reading data from KVM HTAB fd: %s\n", + strerror(errno)); + return rc; + } else if (rc) { + /* Kernel already retuns data in BE format for the file */ + qemu_put_buffer(f, buf, rc); + } + } while ((rc != 0) + && ((max_ns < 0) + || ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) < max_ns))); + + return (rc == 0) ? 1 : 0; +} + +int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, + uint16_t n_valid, uint16_t n_invalid) +{ + struct kvm_get_htab_header *buf; + size_t chunksize = sizeof(*buf) + n_valid*HASH_PTE_SIZE_64; + ssize_t rc; + + buf = alloca(chunksize); + /* This is KVM on ppc, so this is all big-endian */ + buf->index = index; + buf->n_valid = n_valid; + buf->n_invalid = n_invalid; + + qemu_get_buffer(f, (void *)(buf + 1), HASH_PTE_SIZE_64*n_valid); + + rc = write(fd, buf, chunksize); + if (rc < 0) { + fprintf(stderr, "Error writing KVM hash table: %s\n", + strerror(errno)); + return rc; + } + if (rc != chunksize) { + /* We should never get a short write on a single chunk */ + fprintf(stderr, "Short write, restoring KVM hash table\n"); + return -1; + } + return 0; +} + bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { return true; diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c index 1b192a8038..9b8365503b 100644 --- a/target-ppc/kvm_ppc.c +++ b/target-ppc/kvm_ppc.c @@ -24,7 +24,7 @@ static unsigned int kvmppc_timer_rate; static void kvmppc_timer_hack(void *opaque) { qemu_notify_event(); - qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate); + timer_mod(kvmppc_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + kvmppc_timer_rate); } void kvmppc_init(void) @@ -34,7 +34,7 @@ void kvmppc_init(void) * run. So, until QEMU gains IO threads, we create this timer to ensure * that the device model gets a chance to run. */ kvmppc_timer_rate = get_ticks_per_sec() / 10; - kvmppc_timer = qemu_new_timer_ns(vm_clock, &kvmppc_timer_hack, NULL); - qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate); + kvmppc_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &kvmppc_timer_hack, NULL); + timer_mod(kvmppc_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + kvmppc_timer_rate); } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 771cfbe82b..4ae7bf2c32 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -38,6 +38,10 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ int kvmppc_fixup_cpu(PowerPCCPU *cpu); bool kvmppc_has_cap_epr(void); +int kvmppc_get_htab_fd(bool write); +int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns); +int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, + uint16_t n_valid, uint16_t n_invalid); #else @@ -159,6 +163,24 @@ static inline bool kvmppc_has_cap_epr(void) { return false; } + +static inline int kvmppc_get_htab_fd(bool write) +{ + return -1; +} + +static inline int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, + int64_t max_ns) +{ + abort(); +} + +static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, + uint16_t n_valid, uint16_t n_invalid) +{ + abort(); +} + #endif #ifndef CONFIG_KVM diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 2d10adb60d..12e1512996 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -1,96 +1,12 @@ #include "hw/hw.h" #include "hw/boards.h" #include "sysemu/kvm.h" +#include "helper_regs.h" -void cpu_save(QEMUFile *f, void *opaque) +static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) { - CPUPPCState *env = (CPUPPCState *)opaque; - unsigned int i, j; - uint32_t fpscr; - target_ulong xer; - - for (i = 0; i < 32; i++) - qemu_put_betls(f, &env->gpr[i]); -#if !defined(TARGET_PPC64) - for (i = 0; i < 32; i++) - qemu_put_betls(f, &env->gprh[i]); -#endif - qemu_put_betls(f, &env->lr); - qemu_put_betls(f, &env->ctr); - for (i = 0; i < 8; i++) - qemu_put_be32s(f, &env->crf[i]); - xer = cpu_read_xer(env); - qemu_put_betls(f, &xer); - qemu_put_betls(f, &env->reserve_addr); - qemu_put_betls(f, &env->msr); - for (i = 0; i < 4; i++) - qemu_put_betls(f, &env->tgpr[i]); - for (i = 0; i < 32; i++) { - union { - float64 d; - uint64_t l; - } u; - u.d = env->fpr[i]; - qemu_put_be64(f, u.l); - } - fpscr = env->fpscr; - qemu_put_be32s(f, &fpscr); - qemu_put_sbe32s(f, &env->access_type); -#if defined(TARGET_PPC64) - qemu_put_betls(f, &env->spr[SPR_ASR]); - qemu_put_sbe32s(f, &env->slb_nr); -#endif - qemu_put_betls(f, &env->spr[SPR_SDR1]); - for (i = 0; i < 32; i++) - qemu_put_betls(f, &env->sr[i]); - for (i = 0; i < 2; i++) - for (j = 0; j < 8; j++) - qemu_put_betls(f, &env->DBAT[i][j]); - for (i = 0; i < 2; i++) - for (j = 0; j < 8; j++) - qemu_put_betls(f, &env->IBAT[i][j]); - qemu_put_sbe32s(f, &env->nb_tlb); - qemu_put_sbe32s(f, &env->tlb_per_way); - qemu_put_sbe32s(f, &env->nb_ways); - qemu_put_sbe32s(f, &env->last_way); - qemu_put_sbe32s(f, &env->id_tlbs); - qemu_put_sbe32s(f, &env->nb_pids); - if (env->tlb.tlb6) { - // XXX assumes 6xx - for (i = 0; i < env->nb_tlb; i++) { - qemu_put_betls(f, &env->tlb.tlb6[i].pte0); - qemu_put_betls(f, &env->tlb.tlb6[i].pte1); - qemu_put_betls(f, &env->tlb.tlb6[i].EPN); - } - } - for (i = 0; i < 4; i++) - qemu_put_betls(f, &env->pb[i]); - for (i = 0; i < 1024; i++) - qemu_put_betls(f, &env->spr[i]); - qemu_put_be32s(f, &env->vscr); - qemu_put_be64s(f, &env->spe_acc); - qemu_put_be32s(f, &env->spe_fscr); - qemu_put_betls(f, &env->msr_mask); - qemu_put_be32s(f, &env->flags); - qemu_put_sbe32s(f, &env->error_code); - qemu_put_be32s(f, &env->pending_interrupts); - qemu_put_be32s(f, &env->irq_input_state); - for (i = 0; i < POWERPC_EXCP_NB; i++) - qemu_put_betls(f, &env->excp_vectors[i]); - qemu_put_betls(f, &env->excp_prefix); - qemu_put_betls(f, &env->ivor_mask); - qemu_put_betls(f, &env->ivpr_mask); - qemu_put_betls(f, &env->hreset_vector); - qemu_put_betls(f, &env->nip); - qemu_put_betls(f, &env->hflags); - qemu_put_betls(f, &env->hflags_nmsr); - qemu_put_sbe32s(f, &env->mmu_idx); - qemu_put_sbe32(f, 0); -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - CPUPPCState *env = (CPUPPCState *)opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; unsigned int i, j; target_ulong sdr1; uint32_t fpscr; @@ -177,3 +93,442 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) return 0; } + +static int get_avr(QEMUFile *f, void *pv, size_t size) +{ + ppc_avr_t *v = pv; + + v->u64[0] = qemu_get_be64(f); + v->u64[1] = qemu_get_be64(f); + + return 0; +} + +static void put_avr(QEMUFile *f, void *pv, size_t size) +{ + ppc_avr_t *v = pv; + + qemu_put_be64(f, v->u64[0]); + qemu_put_be64(f, v->u64[1]); +} + +const VMStateInfo vmstate_info_avr = { + .name = "avr", + .get = get_avr, + .put = put_avr, +}; + +#define VMSTATE_AVR_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_avr, ppc_avr_t) + +#define VMSTATE_AVR_ARRAY(_f, _s, _n) \ + VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0) + +static void cpu_pre_save(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int i; + + env->spr[SPR_LR] = env->lr; + env->spr[SPR_CTR] = env->ctr; + env->spr[SPR_XER] = env->xer; +#if defined(TARGET_PPC64) + env->spr[SPR_CFAR] = env->cfar; +#endif + env->spr[SPR_BOOKE_SPEFSCR] = env->spe_fscr; + + for (i = 0; (i < 4) && (i < env->nb_BATs); i++) { + env->spr[SPR_DBAT0U + 2*i] = env->DBAT[0][i]; + env->spr[SPR_DBAT0U + 2*i + 1] = env->DBAT[1][i]; + env->spr[SPR_IBAT0U + 2*i] = env->IBAT[0][i]; + env->spr[SPR_IBAT0U + 2*i + 1] = env->IBAT[1][i]; + } + for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) { + env->spr[SPR_DBAT4U + 2*i] = env->DBAT[0][i+4]; + env->spr[SPR_DBAT4U + 2*i + 1] = env->DBAT[1][i+4]; + env->spr[SPR_IBAT4U + 2*i] = env->IBAT[0][i+4]; + env->spr[SPR_IBAT4U + 2*i + 1] = env->IBAT[1][i+4]; + } +} + +static int cpu_post_load(void *opaque, int version_id) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int i; + + env->lr = env->spr[SPR_LR]; + env->ctr = env->spr[SPR_CTR]; + env->xer = env->spr[SPR_XER]; +#if defined(TARGET_PPC64) + env->cfar = env->spr[SPR_CFAR]; +#endif + env->spe_fscr = env->spr[SPR_BOOKE_SPEFSCR]; + + for (i = 0; (i < 4) && (i < env->nb_BATs); i++) { + env->DBAT[0][i] = env->spr[SPR_DBAT0U + 2*i]; + env->DBAT[1][i] = env->spr[SPR_DBAT0U + 2*i + 1]; + env->IBAT[0][i] = env->spr[SPR_IBAT0U + 2*i]; + env->IBAT[1][i] = env->spr[SPR_IBAT0U + 2*i + 1]; + } + for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) { + env->DBAT[0][i+4] = env->spr[SPR_DBAT4U + 2*i]; + env->DBAT[1][i+4] = env->spr[SPR_DBAT4U + 2*i + 1]; + env->IBAT[0][i+4] = env->spr[SPR_IBAT4U + 2*i]; + env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1]; + } + + /* Restore htab_base and htab_mask variables */ + ppc_store_sdr1(env, env->spr[SPR_SDR1]); + + hreg_compute_hflags(env); + hreg_compute_mem_idx(env); + + return 0; +} + +static bool fpu_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return (cpu->env.insns_flags & PPC_FLOAT); +} + +static const VMStateDescription vmstate_fpu = { + .name = "cpu/fpu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_FLOAT64_ARRAY(env.fpr, PowerPCCPU, 32), + VMSTATE_UINTTL(env.fpscr, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, +}; + +static bool altivec_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return (cpu->env.insns_flags & PPC_ALTIVEC); +} + +static const VMStateDescription vmstate_altivec = { + .name = "cpu/altivec", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_AVR_ARRAY(env.avr, PowerPCCPU, 32), + VMSTATE_UINT32(env.vscr, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, +}; + +static bool vsx_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return (cpu->env.insns_flags2 & PPC2_VSX); +} + +static const VMStateDescription vmstate_vsx = { + .name = "cpu/vsx", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64_ARRAY(env.vsr, PowerPCCPU, 32), + VMSTATE_END_OF_LIST() + }, +}; + +static bool sr_needed(void *opaque) +{ +#ifdef TARGET_PPC64 + PowerPCCPU *cpu = opaque; + + return !(cpu->env.mmu_model & POWERPC_MMU_64); +#else + return true; +#endif +} + +static const VMStateDescription vmstate_sr = { + .name = "cpu/sr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL_ARRAY(env.sr, PowerPCCPU, 32), + VMSTATE_END_OF_LIST() + }, +}; + +#ifdef TARGET_PPC64 +static int get_slbe(QEMUFile *f, void *pv, size_t size) +{ + ppc_slb_t *v = pv; + + v->esid = qemu_get_be64(f); + v->vsid = qemu_get_be64(f); + + return 0; +} + +static void put_slbe(QEMUFile *f, void *pv, size_t size) +{ + ppc_slb_t *v = pv; + + qemu_put_be64(f, v->esid); + qemu_put_be64(f, v->vsid); +} + +const VMStateInfo vmstate_info_slbe = { + .name = "slbe", + .get = get_slbe, + .put = put_slbe, +}; + +#define VMSTATE_SLB_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_slbe, ppc_slb_t) + +#define VMSTATE_SLB_ARRAY(_f, _s, _n) \ + VMSTATE_SLB_ARRAY_V(_f, _s, _n, 0) + +static bool slb_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + /* We don't support any of the old segment table based 64-bit CPUs */ + return (cpu->env.mmu_model & POWERPC_MMU_64); +} + +static const VMStateDescription vmstate_slb = { + .name = "cpu/slb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.slb_nr, PowerPCCPU), + VMSTATE_SLB_ARRAY(env.slb, PowerPCCPU, 64), + VMSTATE_END_OF_LIST() + } +}; +#endif /* TARGET_PPC64 */ + +static const VMStateDescription vmstate_tlb6xx_entry = { + .name = "cpu/tlb6xx_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL(pte0, ppc6xx_tlb_t), + VMSTATE_UINTTL(pte1, ppc6xx_tlb_t), + VMSTATE_UINTTL(EPN, ppc6xx_tlb_t), + VMSTATE_END_OF_LIST() + }, +}; + +static bool tlb6xx_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + return env->nb_tlb && (env->tlb_type == TLB_6XX); +} + +static const VMStateDescription vmstate_tlb6xx = { + .name = "cpu/tlb6xx", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU), + VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlb6, PowerPCCPU, + env.nb_tlb, + vmstate_tlb6xx_entry, + ppc6xx_tlb_t), + VMSTATE_UINTTL_ARRAY(env.tgpr, PowerPCCPU, 4), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_tlbemb_entry = { + .name = "cpu/tlbemb_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(RPN, ppcemb_tlb_t), + VMSTATE_UINTTL(EPN, ppcemb_tlb_t), + VMSTATE_UINTTL(PID, ppcemb_tlb_t), + VMSTATE_UINTTL(size, ppcemb_tlb_t), + VMSTATE_UINT32(prot, ppcemb_tlb_t), + VMSTATE_UINT32(attr, ppcemb_tlb_t), + VMSTATE_END_OF_LIST() + }, +}; + +static bool tlbemb_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + return env->nb_tlb && (env->tlb_type == TLB_EMB); +} + +static bool pbr403_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + uint32_t pvr = cpu->env.spr[SPR_PVR]; + + return (pvr & 0xffff0000) == 0x00200000; +} + +static const VMStateDescription vmstate_pbr403 = { + .name = "cpu/pbr403", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL_ARRAY(env.pb, PowerPCCPU, 4), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_tlbemb = { + .name = "cpu/tlb6xx", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU), + VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbe, PowerPCCPU, + env.nb_tlb, + vmstate_tlbemb_entry, + ppcemb_tlb_t), + /* 403 protection registers */ + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_pbr403, + .needed = pbr403_needed, + } , { + /* empty */ + } + } +}; + +static const VMStateDescription vmstate_tlbmas_entry = { + .name = "cpu/tlbmas_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(mas8, ppcmas_tlb_t), + VMSTATE_UINT32(mas1, ppcmas_tlb_t), + VMSTATE_UINT64(mas2, ppcmas_tlb_t), + VMSTATE_UINT64(mas7_3, ppcmas_tlb_t), + VMSTATE_END_OF_LIST() + }, +}; + +static bool tlbmas_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + return env->nb_tlb && (env->tlb_type == TLB_MAS); +} + +static const VMStateDescription vmstate_tlbmas = { + .name = "cpu/tlbmas", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU), + VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbm, PowerPCCPU, + env.nb_tlb, + vmstate_tlbmas_entry, + ppcmas_tlb_t), + VMSTATE_END_OF_LIST() + } +}; + +const VMStateDescription vmstate_ppc_cpu = { + .name = "cpu", + .version_id = 5, + .minimum_version_id = 5, + .minimum_version_id_old = 4, + .load_state_old = cpu_load_old, + .pre_save = cpu_pre_save, + .post_load = cpu_post_load, + .fields = (VMStateField []) { + /* Verify we haven't changed the pvr */ + VMSTATE_UINTTL_EQUAL(env.spr[SPR_PVR], PowerPCCPU), + + /* User mode architected state */ + VMSTATE_UINTTL_ARRAY(env.gpr, PowerPCCPU, 32), +#if !defined(TARGET_PPC64) + VMSTATE_UINTTL_ARRAY(env.gprh, PowerPCCPU, 32), +#endif + VMSTATE_UINT32_ARRAY(env.crf, PowerPCCPU, 8), + VMSTATE_UINTTL(env.nip, PowerPCCPU), + + /* SPRs */ + VMSTATE_UINTTL_ARRAY(env.spr, PowerPCCPU, 1024), + VMSTATE_UINT64(env.spe_acc, PowerPCCPU), + + /* Reservation */ + VMSTATE_UINTTL(env.reserve_addr, PowerPCCPU), + + /* Supervisor mode architected state */ + VMSTATE_UINTTL(env.msr, PowerPCCPU), + + /* Internal state */ + VMSTATE_UINTTL(env.hflags_nmsr, PowerPCCPU), + /* FIXME: access_type? */ + + /* Sanity checking */ + VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU), + VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU), + VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU), + VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_fpu, + .needed = fpu_needed, + } , { + .vmsd = &vmstate_altivec, + .needed = altivec_needed, + } , { + .vmsd = &vmstate_vsx, + .needed = vsx_needed, + } , { + .vmsd = &vmstate_sr, + .needed = sr_needed, + } , { +#ifdef TARGET_PPC64 + .vmsd = &vmstate_slb, + .needed = slb_needed, + } , { +#endif /* TARGET_PPC64 */ + .vmsd = &vmstate_tlb6xx, + .needed = tlb6xx_needed, + } , { + .vmsd = &vmstate_tlbemb, + .needed = tlbemb_needed, + } , { + .vmsd = &vmstate_tlbmas, + .needed = tlbmas_needed, + } , { + /* empty */ + } + } +}; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0b0844f467..609f797083 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -27,6 +27,7 @@ #include "cpu-models.h" #include "mmu-hash32.h" #include "mmu-hash64.h" +#include "qemu/error-report.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -7023,6 +7024,110 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } +static void init_proc_power5plus(CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_clear, + 0x60000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750FX_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_970_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + POWERPC970_HID5_INIT); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, NULL, + 0x00000000); + /* Memory management */ + /* XXX: not correct */ + gen_low_BATs(env); + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCSR0, "MMUCSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ + spr_register(env, SPR_HIOR, "SPR_HIOR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_hior, &spr_write_hior, + 0x00000000); + spr_register(env, SPR_CTRL, "SPR_CTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UCTRL, "SPR_UCTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_VRSAVE, "SPR_VRSAVE", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#if !defined(CONFIG_USER_ONLY) + env->slb_nr = 64; +#endif + init_excp_970(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; + /* Allocate hardware IRQ controller */ + ppc970_irq_init(env); + /* Can't find information on what this should be on reset. This + * value is the one used by 74xx processors. */ + vscr_init(env, 0x00010000); +} + +POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "POWER5+"; + pcc->init_proc = init_proc_power5plus; + pcc->check_pow = check_pow_970FX; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | + PPC_SEGMENT_64B | PPC_SLBI; + pcc->msr_mask = 0x800000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_64B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif + pcc->excp_model = POWERPC_EXCP_970; + pcc->bus_model = PPC_FLAGS_INPUT_970; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; +} + static void init_proc_POWER7 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -7825,7 +7930,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) error_setg(errp, "Unable to virtualize selected CPU with KVM"); return; } - } else { + } else if (tcg_enabled()) { if (ppc_fixup_cpu(cpu) != 0) { error_setg(errp, "Unable to emulate selected CPU with TCG"); return; @@ -7861,6 +7966,8 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) 34, "power-spe.xml", 0); } + qemu_init_vcpu(cs); + pcc->parent_realize(dev, errp); #if defined(PPC_DUMP_CPU) @@ -8175,7 +8282,7 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) object_property_set_bool(OBJECT(cpu), true, "realized", &err); if (err != NULL) { - fprintf(stderr, "%s\n", error_get_pretty(err)); + error_report("%s", error_get_pretty(err)); error_free(err); object_unref(OBJECT(cpu)); return NULL; @@ -8458,8 +8565,18 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->dump_state = ppc_cpu_dump_state; cc->dump_statistics = ppc_cpu_dump_statistics; cc->set_pc = ppc_cpu_set_pc; + cc->gdb_read_register = ppc_cpu_gdb_read_register; + cc->gdb_write_register = ppc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug; + cc->vmsd = &vmstate_ppc_cpu; +#endif + + cc->gdb_num_core_regs = 71; +#if defined(TARGET_PPC64) + cc->gdb_core_xml_file = "power64-core.xml"; +#else + cc->gdb_core_xml_file = "power-core.xml"; #endif } diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 4e634173a4..f8731463ff 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,4 +1,5 @@ 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) += ioinst.o +obj-y += gdbstub.o +obj-$(CONFIG_SOFTMMU) += ioinst.o arch_dump.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target-s390x/arch_dump.c b/target-s390x/arch_dump.c new file mode 100644 index 0000000000..9d36116242 --- /dev/null +++ b/target-s390x/arch_dump.c @@ -0,0 +1,213 @@ +/* + * writing ELF notes for s390x arch + * + * + * Copyright IBM Corp. 2012, 2013 + * + * Ekaterina Tumanova <tumanova@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "elf.h" +#include "exec/cpu-all.h" +#include "sysemu/dump.h" +#include "sysemu/kvm.h" + + +struct S390xUserRegsStruct { + uint64_t psw[2]; + uint64_t gprs[16]; + uint32_t acrs[16]; +} QEMU_PACKED; + +typedef struct S390xUserRegsStruct S390xUserRegs; + +struct S390xElfPrstatusStruct { + uint8_t pad1[32]; + uint32_t pid; + uint8_t pad2[76]; + S390xUserRegs regs; + uint8_t pad3[16]; +} QEMU_PACKED; + +typedef struct S390xElfPrstatusStruct S390xElfPrstatus; + +struct S390xElfFpregsetStruct { + uint32_t fpc; + uint32_t pad; + uint64_t fprs[16]; +} QEMU_PACKED; + +typedef struct S390xElfFpregsetStruct S390xElfFpregset; + +typedef struct noteStruct { + Elf64_Nhdr hdr; + char name[5]; + char pad3[3]; + union { + S390xElfPrstatus prstatus; + S390xElfFpregset fpregset; + uint32_t prefix; + uint64_t timer; + uint64_t todcmp; + uint32_t todpreg; + uint64_t ctrs[16]; + } contents; +} QEMU_PACKED Note; + +static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu) +{ + int i; + S390xUserRegs *regs; + + note->hdr.n_type = cpu_to_be32(NT_PRSTATUS); + + regs = &(note->contents.prstatus.regs); + regs->psw[0] = cpu_to_be64(cpu->env.psw.mask); + regs->psw[1] = cpu_to_be64(cpu->env.psw.addr); + for (i = 0; i <= 15; i++) { + regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]); + regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]); + } +} + +static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu) +{ + int i; + + note->hdr.n_type = cpu_to_be32(NT_FPREGSET); + note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc); + for (i = 0; i <= 15; i++) { + note->contents.fpregset.fprs[i] = cpu_to_be64(cpu->env.fregs[i].ll); + } +} + + +static void s390x_write_elf64_timer(Note *note, S390CPU *cpu) +{ + note->hdr.n_type = cpu_to_be32(NT_S390_TIMER); + note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm)); +} + +static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu) +{ + note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP); + note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc)); +} + +static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu) +{ + note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG); + note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr)); +} + +static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu) +{ + int i; + + note->hdr.n_type = cpu_to_be32(NT_S390_CTRS); + + for (i = 0; i <= 15; i++) { + note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]); + } +} + +static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu) +{ + note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX); + note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); +} + + +struct NoteFuncDescStruct { + int contents_size; + void (*note_contents_func)(Note *note, S390CPU *cpu); +} note_func[] = { + {sizeof(((Note *)0)->contents.prstatus), s390x_write_elf64_prstatus}, + {sizeof(((Note *)0)->contents.prefix), s390x_write_elf64_prefix}, + {sizeof(((Note *)0)->contents.fpregset), s390x_write_elf64_fpregset}, + {sizeof(((Note *)0)->contents.ctrs), s390x_write_elf64_ctrs}, + {sizeof(((Note *)0)->contents.timer), s390x_write_elf64_timer}, + {sizeof(((Note *)0)->contents.todcmp), s390x_write_elf64_todcmp}, + {sizeof(((Note *)0)->contents.todpreg), s390x_write_elf64_todpreg}, + { 0, NULL} +}; + +typedef struct NoteFuncDescStruct NoteFuncDesc; + + +static int s390x_write_all_elf64_notes(const char *note_name, + WriteCoreDumpFunction f, + S390CPU *cpu, int id, + void *opaque) +{ + Note note; + NoteFuncDesc *nf; + int note_size; + int ret = -1; + + for (nf = note_func; nf->note_contents_func; nf++) { + note.hdr.n_namesz = cpu_to_be32(sizeof(note.name)); + note.hdr.n_descsz = cpu_to_be32(nf->contents_size); + strncpy(note.name, note_name, sizeof(note.name)); + (*nf->note_contents_func)(¬e, cpu); + + note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; + ret = f(¬e, note_size, opaque); + + if (ret < 0) { + return -1; + } + + } + + return 0; +} + + +int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) +{ + S390CPU *cpu = S390_CPU(cs); + return s390x_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque); +} + +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks) +{ + info->d_machine = EM_S390; + info->d_endian = ELFDATA2MSB; + info->d_class = ELFCLASS64; + + return 0; +} + +ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) +{ + int name_size = 8; /* "CORE" or "QEMU" rounded */ + size_t elf_note_size = 0; + int note_head_size; + NoteFuncDesc *nf; + + assert(class == ELFCLASS64); + assert(machine == EM_S390); + + note_head_size = sizeof(Elf64_Nhdr); + + for (nf = note_func; nf->note_contents_func; nf++) { + elf_note_size = elf_note_size + note_head_size + name_size + + nf->contents_size; + } + + return (elf_note_size) * nr_cpus; +} + +int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index a4fe8fb5fc..cbe2341b3b 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -74,6 +74,13 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env) void s390_cpu_do_interrupt(CPUState *cpu); void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); +int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque); + +int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque); hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index cb89d1a46b..5cc99387b2 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -101,10 +101,11 @@ static void s390_cpu_machine_reset_cb(void *opaque) static void s390_cpu_realizefn(DeviceState *dev, Error **errp) { - S390CPU *cpu = S390_CPU(dev); + CPUState *cs = CPU(dev); S390CPUClass *scc = S390_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + qemu_init_vcpu(cs); + cpu_reset(cs); scc->parent_realize(dev, errp); } @@ -128,8 +129,8 @@ static void s390_cpu_initfn(Object *obj) env->tod_offset = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL); env->tod_basetime = 0; - env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu); - env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu); + env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); + env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); /* set CPUState::halted state to 1 to avoid decrementing the running * cpu counter in s390_cpu_reset to a negative number at * initial ipl */ @@ -173,10 +174,15 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = s390_cpu_do_interrupt; cc->dump_state = s390_cpu_dump_state; cc->set_pc = s390_cpu_set_pc; + cc->gdb_read_register = s390_cpu_gdb_read_register; + cc->gdb_write_register = s390_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = s390_cpu_get_phys_page_debug; + cc->write_elf64_note = s390_cpu_write_elf64_note; + cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote; #endif dc->vmsd = &vmstate_s390_cpu; + cc->gdb_num_core_regs = S390_NUM_REGS; } static const TypeInfo s390_cpu_type_info = { diff --git a/target-s390x/gdbstub.c b/target-s390x/gdbstub.c new file mode 100644 index 0000000000..a129742e2f --- /dev/null +++ b/target-s390x/gdbstub.c @@ -0,0 +1,88 @@ +/* + * s390x gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" +#include "qemu/bitops.h" + +int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + uint64_t val; + int cc_op; + + switch (n) { + case S390_PSWM_REGNUM: + cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); + val = deposit64(env->psw.mask, 44, 2, cc_op); + return gdb_get_regl(mem_buf, val); + case S390_PSWA_REGNUM: + return gdb_get_regl(mem_buf, env->psw.addr); + case S390_R0_REGNUM ... S390_R15_REGNUM: + return gdb_get_regl(mem_buf, env->regs[n-S390_R0_REGNUM]); + case S390_A0_REGNUM ... S390_A15_REGNUM: + return gdb_get_reg32(mem_buf, env->aregs[n-S390_A0_REGNUM]); + case S390_FPC_REGNUM: + return gdb_get_reg32(mem_buf, env->fpc); + case S390_F0_REGNUM ... S390_F15_REGNUM: + return gdb_get_reg64(mem_buf, env->fregs[n-S390_F0_REGNUM].ll); + } + + return 0; +} + +int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + target_ulong tmpl; + uint32_t tmp32; + int r = 8; + tmpl = ldtul_p(mem_buf); + tmp32 = ldl_p(mem_buf); + + switch (n) { + case S390_PSWM_REGNUM: + env->psw.mask = tmpl; + env->cc_op = extract64(tmpl, 44, 2); + break; + case S390_PSWA_REGNUM: + env->psw.addr = tmpl; + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + env->regs[n-S390_R0_REGNUM] = tmpl; + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + env->aregs[n-S390_A0_REGNUM] = tmp32; + r = 4; + break; + case S390_FPC_REGNUM: + env->fpc = tmp32; + r = 4; + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + env->fregs[n-S390_F0_REGNUM].ll = tmpl; + break; + default: + return 0; + } + return r; +} diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 28c508d541..85fd285736 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -151,23 +151,24 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) int cc; hwaddr len = sizeof(*schib); - if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); + addr = decode_basedisp_s(env, ipb); + if (addr & 3) { + program_interrupt(env, PGM_SPECIFICATION, 2); return -EIO; } - trace_ioinst_sch_id("msch", cssid, ssid, schid); - addr = decode_basedisp_s(env, ipb); schib = s390_cpu_physical_memory_map(env, addr, &len, 0); if (!schib || len != sizeof(*schib)) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); cc = -EIO; goto out; } - if (!ioinst_schib_valid(schib)) { + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || + !ioinst_schib_valid(schib)) { program_interrupt(env, PGM_OPERAND, 2); cc = -EIO; goto out; } + trace_ioinst_sch_id("msch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_msch(sch, schib); @@ -222,24 +223,25 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) int cc; hwaddr len = sizeof(*orig_orb); - if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); + addr = decode_basedisp_s(env, ipb); + if (addr & 3) { + program_interrupt(env, PGM_SPECIFICATION, 2); return -EIO; } - trace_ioinst_sch_id("ssch", cssid, ssid, schid); - addr = decode_basedisp_s(env, ipb); orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0); if (!orig_orb || len != sizeof(*orig_orb)) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); cc = -EIO; goto out; } copy_orb_from_guest(&orb, orig_orb); - if (!ioinst_orb_valid(&orb)) { + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || + !ioinst_orb_valid(&orb)) { program_interrupt(env, PGM_OPERAND, 2); cc = -EIO; goto out; } + trace_ioinst_sch_id("ssch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_ssch(sch, &orb); @@ -272,9 +274,13 @@ int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb) hwaddr len = sizeof(*crw); addr = decode_basedisp_s(env, ipb); + if (addr & 3) { + program_interrupt(env, PGM_SPECIFICATION, 2); + return -EIO; + } crw = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!crw || len != sizeof(*crw)) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); cc = -EIO; goto out; } @@ -294,18 +300,24 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) SCHIB *schib; hwaddr len = sizeof(*schib); - if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); + addr = decode_basedisp_s(env, ipb); + if (addr & 3) { + program_interrupt(env, PGM_SPECIFICATION, 2); return -EIO; } - trace_ioinst_sch_id("stsch", cssid, ssid, schid); - addr = decode_basedisp_s(env, ipb); schib = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!schib || len != sizeof(*schib)) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); + cc = -EIO; + goto out; + } + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); cc = -EIO; goto out; } + trace_ioinst_sch_id("stsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch) { if (css_subch_visible(sch)) { @@ -345,9 +357,13 @@ int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) } trace_ioinst_sch_id("tsch", cssid, ssid, schid); addr = decode_basedisp_s(env, ipb); + if (addr & 3) { + program_interrupt(env, PGM_SPECIFICATION, 2); + return -EIO; + } irb = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!irb || len != sizeof(*irb)) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); cc = -EIO; goto out; } @@ -580,7 +596,7 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb) } req = s390_cpu_physical_memory_map(env, addr, &map_size, 1); if (!req || map_size != TARGET_PAGE_SIZE) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); ret = -EIO; goto out; } @@ -625,12 +641,17 @@ int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb) trace_ioinst("tpi"); addr = decode_basedisp_s(env, ipb); + if (addr & 3) { + program_interrupt(env, PGM_SPECIFICATION, 2); + return -EIO; + } + lowcore = addr ? 0 : 1; len = lowcore ? 8 /* two words */ : 12 /* three words */; orig_len = len; int_code = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!int_code || (len != orig_len)) { - program_interrupt(env, PGM_SPECIFICATION, 2); + program_interrupt(env, PGM_ADDRESSING, 2); ret = -EIO; goto out; } @@ -663,7 +684,7 @@ int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2, update = SCHM_REG1_UPD(reg1); dct = SCHM_REG1_DCT(reg1); - if (update && (reg2 & 0x0000000000000fff)) { + if (update && (reg2 & 0x000000000000001f)) { program_interrupt(env, PGM_OPERAND, 2); return -EIO; } diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 60e94f8ee8..26d18e3bcf 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -40,10 +40,10 @@ /* #define DEBUG_KVM */ #ifdef DEBUG_KVM -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define DPRINTF(fmt, ...) \ do { } while (0) #endif @@ -345,12 +345,10 @@ void *kvm_arch_ram_alloc(ram_addr_t size) int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { - S390CPU *cpu = S390_CPU(cs); - CPUS390XState *env = &cpu->env; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; - if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || - cpu_memory_rw_debug(env, bp->pc, (uint8_t *)diag_501, 4, 1)) { + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) { return -EINVAL; } return 0; @@ -358,16 +356,14 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { - S390CPU *cpu = S390_CPU(cs); - CPUS390XState *env = &cpu->env; uint8_t t[4]; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; - if (cpu_memory_rw_debug(env, bp->pc, t, 4, 0)) { + if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) { return -EINVAL; } else if (memcmp(t, diag_501, 4)) { return -EINVAL; - } else if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) { + } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) { return -EINVAL; } @@ -532,50 +528,19 @@ static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run, no_cc = 1; r = ioinst_handle_sal(env, env->regs[1]); break; - default: - r = -1; + case PRIV_SIGA: + /* Not provided, set CC = 3 for subchannel not operational */ + r = 3; break; + default: + return -1; } - if (r >= 0) { - if (!no_cc) { - setcc(cpu, r); - } - r = 0; - } else if (r < -1) { - r = 0; - } - return r; -} - -static int is_ioinst(uint8_t ipa0, uint8_t ipa1, uint8_t ipb) -{ - int ret = 0; - uint16_t ipa = (ipa0 << 8) | ipa1; - - switch (ipa) { - case IPA0_B2 | PRIV_CSCH: - case IPA0_B2 | PRIV_HSCH: - case IPA0_B2 | PRIV_MSCH: - case IPA0_B2 | PRIV_SSCH: - case IPA0_B2 | PRIV_STSCH: - case IPA0_B2 | PRIV_TPI: - case IPA0_B2 | PRIV_SAL: - case IPA0_B2 | PRIV_RSCH: - case IPA0_B2 | PRIV_STCRW: - case IPA0_B2 | PRIV_STCPS: - case IPA0_B2 | PRIV_RCHP: - case IPA0_B2 | PRIV_SCHM: - case IPA0_B2 | PRIV_CHSC: - case IPA0_B2 | PRIV_SIGA: - case IPA0_B2 | PRIV_XSCH: - case IPA0_B9 | PRIV_EQBS: - case IPA0_EB | PRIV_SQBS: - ret = 1; - break; + if (r >= 0 && !no_cc) { + setcc(cpu, r); } - return ret; + return 0; } static int handle_priv(S390CPU *cpu, struct kvm_run *run, @@ -585,21 +550,15 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16; uint8_t ipb = run->s390_sieic.ipb & 0xff; - dprintf("KVM: PRIV: %d\n", ipa1); + DPRINTF("KVM: PRIV: %d\n", ipa1); switch (ipa1) { case PRIV_SCLP_CALL: r = kvm_sclp_service_call(cpu, run, ipbh0); break; default: - if (is_ioinst(ipa0, ipa1, ipb)) { - r = kvm_handle_css_inst(cpu, run, ipa0, ipa1, ipb); - if (r == -1) { - setcc(cpu, 3); - r = 0; - } - } else { - dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); - r = -1; + r = kvm_handle_css_inst(cpu, run, ipa0, ipa1, ipb); + if (r == -1) { + DPRINTF("KVM: unhandled PRIV: 0x%x\n", ipa1); } break; } @@ -631,7 +590,7 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, int ipb_code) sleep(10); break; default: - dprintf("KVM: unknown DIAG: 0x%x\n", ipb_code); + DPRINTF("KVM: unknown DIAG: 0x%x\n", ipb_code); r = -1; break; } @@ -644,7 +603,7 @@ static int s390_cpu_restart(S390CPU *cpu) kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); s390_add_running_cpu(cpu); qemu_cpu_kick(CPU(cpu)); - dprintf("DONE: SIGP cpu restart: %p\n", &cpu->env); + DPRINTF("DONE: SIGP cpu restart: %p\n", &cpu->env); return 0; } @@ -672,7 +631,7 @@ static int s390_cpu_initial_reset(S390CPU *cpu) env->regs[i] = 0; } - dprintf("DONE: SIGP initial reset: %p\n", env); + DPRINTF("DONE: SIGP initial reset: %p\n", env); return 0; } @@ -734,14 +693,15 @@ out: return 0; } -static int handle_instruction(S390CPU *cpu, struct kvm_run *run) +static void handle_instruction(S390CPU *cpu, struct kvm_run *run) { unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00); uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff; int ipb_code = (run->s390_sieic.ipb & 0x0fff0000) >> 16; int r = -1; - dprintf("handle_instruction 0x%x 0x%x\n", run->s390_sieic.ipa, run->s390_sieic.ipb); + DPRINTF("handle_instruction 0x%x 0x%x\n", + run->s390_sieic.ipa, run->s390_sieic.ipb); switch (ipa0) { case IPA0_B2: case IPA0_B9: @@ -759,7 +719,6 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run) if (r < 0) { enter_pgmcheck(cpu, 0x0001); } - return 0; } static bool is_special_wait_psw(CPUState *cs) @@ -775,11 +734,11 @@ static int handle_intercept(S390CPU *cpu) int icpt_code = run->s390_sieic.icptcode; int r = 0; - dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code, + DPRINTF("intercept: 0x%x (at 0x%lx)\n", icpt_code, (long)cs->kvm_run->psw_addr); switch (icpt_code) { case ICPT_INSTRUCTION: - r = handle_instruction(cpu, run); + handle_instruction(cpu, run); break; case ICPT_WAITPSW: /* disabled wait, since enabled wait is handled in kernel */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 09301d0a6f..454960aa01 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -225,7 +225,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_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); return time; } @@ -248,7 +248,7 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) /* nanoseconds */ time = (time * 125) >> 9; - qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); + timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); } /* Store Clock Comparator */ @@ -268,7 +268,7 @@ void HELPER(spt)(CPUS390XState *env, uint64_t time) /* nanoseconds */ time = (time * 125) >> 9; - qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); + timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); } /* Store CPU Timer */ diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs index cb448a840f..a285358adf 100644 --- a/target-sh4/Makefile.objs +++ b/target-sh4/Makefile.objs @@ -1 +1,2 @@ obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index 7c9160bab8..c04e78631b 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -87,5 +87,7 @@ void superh_cpu_do_interrupt(CPUState *cpu); void superh_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index 51a77576fb..34b2b57ba7 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -240,10 +240,11 @@ static const TypeInfo sh7785_type_info = { static void superh_cpu_realizefn(DeviceState *dev, Error **errp) { - SuperHCPU *cpu = SUPERH_CPU(dev); + CPUState *cs = CPU(dev); SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev); - cpu_reset(CPU(cpu)); + cpu_reset(cs); + qemu_init_vcpu(cs); scc->parent_realize(dev, errp); } @@ -286,10 +287,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) cc->dump_state = superh_cpu_dump_state; cc->set_pc = superh_cpu_set_pc; cc->synchronize_from_tb = superh_cpu_synchronize_from_tb; + cc->gdb_read_register = superh_cpu_gdb_read_register; + cc->gdb_write_register = superh_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = superh_cpu_get_phys_page_debug; #endif dc->vmsd = &vmstate_sh_cpu; + cc->gdb_num_core_regs = 59; } static const TypeInfo superh_cpu_type_info = { diff --git a/target-sh4/gdbstub.c b/target-sh4/gdbstub.c new file mode 100644 index 0000000000..df4fa2af76 --- /dev/null +++ b/target-sh4/gdbstub.c @@ -0,0 +1,146 @@ +/* + * SuperH gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +/* Hint: Use "set architecture sh4" in GDB to see fpu registers */ +/* FIXME: We should use XML for this. */ + +int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + SuperHCPU *cpu = SUPERH_CPU(cs); + CPUSH4State *env = &cpu->env; + + switch (n) { + case 0 ... 7: + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + return gdb_get_regl(mem_buf, env->gregs[n + 16]); + } else { + return gdb_get_regl(mem_buf, env->gregs[n]); + } + case 8 ... 15: + return gdb_get_regl(mem_buf, env->gregs[n]); + case 16: + return gdb_get_regl(mem_buf, env->pc); + case 17: + return gdb_get_regl(mem_buf, env->pr); + case 18: + return gdb_get_regl(mem_buf, env->gbr); + case 19: + return gdb_get_regl(mem_buf, env->vbr); + case 20: + return gdb_get_regl(mem_buf, env->mach); + case 21: + return gdb_get_regl(mem_buf, env->macl); + case 22: + return gdb_get_regl(mem_buf, env->sr); + case 23: + return gdb_get_regl(mem_buf, env->fpul); + case 24: + return gdb_get_regl(mem_buf, env->fpscr); + case 25 ... 40: + if (env->fpscr & FPSCR_FR) { + stfl_p(mem_buf, env->fregs[n - 9]); + } else { + stfl_p(mem_buf, env->fregs[n - 25]); + } + return 4; + case 41: + return gdb_get_regl(mem_buf, env->ssr); + case 42: + return gdb_get_regl(mem_buf, env->spc); + case 43 ... 50: + return gdb_get_regl(mem_buf, env->gregs[n - 43]); + case 51 ... 58: + return gdb_get_regl(mem_buf, env->gregs[n - (51 - 16)]); + } + + return 0; +} + +int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + SuperHCPU *cpu = SUPERH_CPU(cs); + CPUSH4State *env = &cpu->env; + + switch (n) { + case 0 ... 7: + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + env->gregs[n + 16] = ldl_p(mem_buf); + } else { + env->gregs[n] = ldl_p(mem_buf); + } + break; + case 8 ... 15: + env->gregs[n] = ldl_p(mem_buf); + break; + case 16: + env->pc = ldl_p(mem_buf); + break; + case 17: + env->pr = ldl_p(mem_buf); + break; + case 18: + env->gbr = ldl_p(mem_buf); + break; + case 19: + env->vbr = ldl_p(mem_buf); + break; + case 20: + env->mach = ldl_p(mem_buf); + break; + case 21: + env->macl = ldl_p(mem_buf); + break; + case 22: + env->sr = ldl_p(mem_buf); + break; + case 23: + env->fpul = ldl_p(mem_buf); + break; + case 24: + env->fpscr = ldl_p(mem_buf); + break; + case 25 ... 40: + if (env->fpscr & FPSCR_FR) { + env->fregs[n - 9] = ldfl_p(mem_buf); + } else { + env->fregs[n - 25] = ldfl_p(mem_buf); + } + break; + case 41: + env->ssr = ldl_p(mem_buf); + break; + case 42: + env->spc = ldl_p(mem_buf); + break; + case 43 ... 50: + env->gregs[n - 43] = ldl_p(mem_buf); + break; + case 51 ... 58: + env->gregs[n - (51 - 16)] = ldl_p(mem_buf); + break; + default: + return 0; + } + + return 4; +} diff --git a/target-sparc/Makefile.objs b/target-sparc/Makefile.objs index 9fc42ea9b0..1cd81cccc3 100644 --- a/target-sparc/Makefile.objs +++ b/target-sparc/Makefile.objs @@ -4,3 +4,4 @@ obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o obj-$(TARGET_SPARC) += int32_helper.o obj-$(TARGET_SPARC64) += int64_helper.o obj-$(TARGET_SPARC64) += vis_helper.o +obj-y += gdbstub.o diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h index 39d975b5fc..8e3e0de277 100644 --- a/target-sparc/cpu-qom.h +++ b/target-sparc/cpu-qom.h @@ -79,5 +79,7 @@ void sparc_cpu_do_interrupt(CPUState *cpu); void sparc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index d1d03396ef..47ce60de4a 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -743,6 +743,8 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) { SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev); + qemu_init_vcpu(CPU(dev)); + scc->parent_realize(dev, errp); } @@ -787,10 +789,18 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) #endif cc->set_pc = sparc_cpu_set_pc; cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb; + cc->gdb_read_register = sparc_cpu_gdb_read_register; + cc->gdb_write_register = sparc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->do_unassigned_access = sparc_cpu_unassigned_access; cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug; #endif + +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + cc->gdb_num_core_regs = 86; +#else + cc->gdb_num_core_regs = 72; +#endif } static const TypeInfo sparc_cpu_type_info = { diff --git a/target-sparc/gdbstub.c b/target-sparc/gdbstub.c new file mode 100644 index 0000000000..3de3242b29 --- /dev/null +++ b/target-sparc/gdbstub.c @@ -0,0 +1,208 @@ +/* + * SPARC gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +#ifdef TARGET_ABI32 +#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val) +#else +#define gdb_get_rega(buf, val) gdb_get_regl(buf, val) +#endif + +int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; + + if (n < 8) { + /* g0..g7 */ + return gdb_get_rega(mem_buf, env->gregs[n]); + } + if (n < 32) { + /* register window */ + return gdb_get_rega(mem_buf, env->regwptr[n - 8]); + } +#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64) + if (n < 64) { + /* fprs */ + if (n & 1) { + return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower); + } else { + return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper); + } + } + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + switch (n) { + case 64: + return gdb_get_rega(mem_buf, env->y); + case 65: + return gdb_get_rega(mem_buf, cpu_get_psr(env)); + case 66: + return gdb_get_rega(mem_buf, env->wim); + case 67: + return gdb_get_rega(mem_buf, env->tbr); + case 68: + return gdb_get_rega(mem_buf, env->pc); + case 69: + return gdb_get_rega(mem_buf, env->npc); + case 70: + return gdb_get_rega(mem_buf, env->fsr); + case 71: + return gdb_get_rega(mem_buf, 0); /* csr */ + default: + return gdb_get_rega(mem_buf, 0); + } +#else + if (n < 64) { + /* f0-f31 */ + if (n & 1) { + return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower); + } else { + return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper); + } + } + if (n < 80) { + /* f32-f62 (double width, even numbers only) */ + return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll); + } + switch (n) { + case 80: + return gdb_get_regl(mem_buf, env->pc); + case 81: + return gdb_get_regl(mem_buf, env->npc); + case 82: + return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) | + ((env->asi & 0xff) << 24) | + ((env->pstate & 0xfff) << 8) | + cpu_get_cwp64(env)); + case 83: + return gdb_get_regl(mem_buf, env->fsr); + case 84: + return gdb_get_regl(mem_buf, env->fprs); + case 85: + return gdb_get_regl(mem_buf, env->y); + } +#endif + return 0; +} + +int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; +#if defined(TARGET_ABI32) + abi_ulong tmp; + + tmp = ldl_p(mem_buf); +#else + target_ulong tmp; + + tmp = ldtul_p(mem_buf); +#endif + + if (n < 8) { + /* g0..g7 */ + env->gregs[n] = tmp; + } else if (n < 32) { + /* register window */ + env->regwptr[n - 8] = tmp; + } +#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64) + else if (n < 64) { + /* fprs */ + /* f0-f31 */ + if (n & 1) { + env->fpr[(n - 32) / 2].l.lower = tmp; + } else { + env->fpr[(n - 32) / 2].l.upper = tmp; + } + } else { + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + switch (n) { + case 64: + env->y = tmp; + break; + case 65: + cpu_put_psr(env, tmp); + break; + case 66: + env->wim = tmp; + break; + case 67: + env->tbr = tmp; + break; + case 68: + env->pc = tmp; + break; + case 69: + env->npc = tmp; + break; + case 70: + env->fsr = tmp; + break; + default: + return 0; + } + } + return 4; +#else + else if (n < 64) { + /* f0-f31 */ + tmp = ldl_p(mem_buf); + if (n & 1) { + env->fpr[(n - 32) / 2].l.lower = tmp; + } else { + env->fpr[(n - 32) / 2].l.upper = tmp; + } + return 4; + } else if (n < 80) { + /* f32-f62 (double width, even numbers only) */ + env->fpr[(n - 32) / 2].ll = tmp; + } else { + switch (n) { + case 80: + env->pc = tmp; + break; + case 81: + env->npc = tmp; + break; + case 82: + cpu_put_ccr(env, tmp >> 32); + env->asi = (tmp >> 24) & 0xff; + env->pstate = (tmp >> 8) & 0xfff; + cpu_put_cwp64(env, tmp & 0xff); + break; + case 83: + env->fsr = tmp; + break; + case 84: + env->fprs = tmp; + break; + case 85: + env->y = tmp; + break; + default: + return 0; + } + } + return 8; +#endif +} diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 46813e52ae..3f78208360 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -92,6 +92,8 @@ static void uc32_cpu_realizefn(DeviceState *dev, Error **errp) { UniCore32CPUClass *ucc = UNICORE32_CPU_GET_CLASS(dev); + qemu_init_vcpu(CPU(dev)); + ucc->parent_realize(dev, errp); } diff --git a/target-xtensa/Makefile.objs b/target-xtensa/Makefile.objs index 644b7f99bb..5c150a870f 100644 --- a/target-xtensa/Makefile.objs +++ b/target-xtensa/Makefile.objs @@ -3,3 +3,4 @@ obj-y += core-dc232b.o obj-y += core-dc233c.o obj-y += core-fsf.o obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h index b9896f2647..c6cc2d91f4 100644 --- a/target-xtensa/cpu-qom.h +++ b/target-xtensa/cpu-qom.h @@ -45,6 +45,7 @@ * XtensaCPUClass: * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. + * @config: The CPU core configuration. * * An Xtensa CPU model. */ @@ -55,6 +56,8 @@ typedef struct XtensaCPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); + + const XtensaConfig *config; } XtensaCPUClass; /** @@ -84,5 +87,7 @@ void xtensa_cpu_do_interrupt(CPUState *cpu); void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #endif diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index d2bcfc69a2..c19d17ad04 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -64,10 +64,34 @@ static void xtensa_cpu_reset(CPUState *s) reset_mmu(env); } +static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + char *typename; + + if (cpu_model == NULL) { + return NULL; + } + + typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) || + object_class_is_abstract(oc)) { + return NULL; + } + return oc; +} + static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); + cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; + + qemu_init_vcpu(cs); + xcc->parent_realize(dev, errp); } @@ -75,10 +99,12 @@ static void xtensa_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); XtensaCPU *cpu = XTENSA_CPU(obj); + XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj); CPUXtensaState *env = &cpu->env; static bool tcg_inited; cs->env_ptr = env; + env->config = xcc->config; cpu_exec_init(env); if (tcg_enabled() && !tcg_inited) { @@ -105,9 +131,12 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) xcc->parent_reset = cc->reset; cc->reset = xtensa_cpu_reset; + cc->class_by_name = xtensa_cpu_class_by_name; cc->do_interrupt = xtensa_cpu_do_interrupt; cc->dump_state = xtensa_cpu_dump_state; cc->set_pc = xtensa_cpu_set_pc; + cc->gdb_read_register = xtensa_cpu_gdb_read_register; + cc->gdb_write_register = xtensa_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug; #endif @@ -119,7 +148,7 @@ static const TypeInfo xtensa_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(XtensaCPU), .instance_init = xtensa_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(XtensaCPUClass), .class_init = xtensa_cpu_class_init, }; diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index a8f02f6e4b..95103e9e87 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -484,6 +484,7 @@ static inline int cpu_mmu_index(CPUXtensaState *env) #define XTENSA_TBFLAG_ICOUNT 0x20 #define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0 #define XTENSA_TBFLAG_CPENABLE_SHIFT 6 +#define XTENSA_TBFLAG_EXCEPTION 0x4000 static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, target_ulong *cs_base, int *flags) @@ -510,6 +511,9 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) { *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; } + if (ENV_GET_CPU(env)->singlestep_enabled && env->exception_taken) { + *flags |= XTENSA_TBFLAG_EXCEPTION; + } } #include "exec/cpu-all.h" diff --git a/target-xtensa/gdbstub.c b/target-xtensa/gdbstub.c new file mode 100644 index 0000000000..9e13b20c46 --- /dev/null +++ b/target-xtensa/gdbstub.c @@ -0,0 +1,109 @@ +/* + * Xtensa gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + XtensaCPU *cpu = XTENSA_CPU(cs); + CPUXtensaState *env = &cpu->env; + const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; + + if (n < 0 || n >= env->config->gdb_regmap.num_regs) { + return 0; + } + + switch (reg->type) { + case 9: /*pc*/ + return gdb_get_reg32(mem_buf, env->pc); + + case 1: /*ar*/ + xtensa_sync_phys_from_window(env); + return gdb_get_reg32(mem_buf, env->phys_regs[(reg->targno & 0xff) + % env->config->nareg]); + + case 2: /*SR*/ + return gdb_get_reg32(mem_buf, env->sregs[reg->targno & 0xff]); + + case 3: /*UR*/ + return gdb_get_reg32(mem_buf, env->uregs[reg->targno & 0xff]); + + case 4: /*f*/ + return gdb_get_reg32(mem_buf, float32_val(env->fregs[reg->targno + & 0x0f])); + + case 8: /*a*/ + return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]); + + default: + qemu_log("%s from reg %d of unsupported type %d\n", + __func__, n, reg->type); + return 0; + } +} + +int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + XtensaCPU *cpu = XTENSA_CPU(cs); + CPUXtensaState *env = &cpu->env; + uint32_t tmp; + const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; + + if (n < 0 || n >= env->config->gdb_regmap.num_regs) { + return 0; + } + + tmp = ldl_p(mem_buf); + + switch (reg->type) { + case 9: /*pc*/ + env->pc = tmp; + break; + + case 1: /*ar*/ + env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp; + xtensa_sync_window_from_phys(env); + break; + + case 2: /*SR*/ + env->sregs[reg->targno & 0xff] = tmp; + break; + + case 3: /*UR*/ + env->uregs[reg->targno & 0xff] = tmp; + break; + + case 4: /*f*/ + env->fregs[reg->targno & 0x0f] = make_float32(tmp); + break; + + case 8: /*a*/ + env->regs[reg->targno & 0x0f] = tmp; + break; + + default: + qemu_log("%s to reg %d of unsupported type %d\n", + __func__, n, reg->type); + return 0; + } + + return 4; +} diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index de6cc3b7c5..a0f9993b2d 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -35,10 +35,35 @@ static struct XtensaConfigList *xtensa_cores; +static void xtensa_core_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc); + const XtensaConfig *config = data; + + xcc->config = config; + + /* Use num_core_regs to see only non-privileged registers in an unmodified + * gdb. Use num_regs to see all registers. gdb modification is required + * for that: reset bit 0 in the 'flags' field of the registers definitions + * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. + */ + cc->gdb_num_core_regs = config->gdb_regmap.num_regs; +} + void xtensa_register_core(XtensaConfigList *node) { + TypeInfo type = { + .parent = TYPE_XTENSA_CPU, + .class_init = xtensa_core_class_init, + .class_data = (void *)node->config, + }; + node->next = xtensa_cores; xtensa_cores = node; + type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name); + type_register(&type); + g_free((gpointer)type.name); } static uint32_t check_hw_breakpoints(CPUXtensaState *env) @@ -72,24 +97,17 @@ void xtensa_breakpoint_handler(CPUXtensaState *env) XtensaCPU *cpu_xtensa_init(const char *cpu_model) { + ObjectClass *oc; XtensaCPU *cpu; CPUXtensaState *env; - const XtensaConfig *config = NULL; - XtensaConfigList *core = xtensa_cores; - - for (; core; core = core->next) - if (strcmp(core->config->name, cpu_model) == 0) { - config = core->config; - break; - } - if (config == NULL) { + oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model); + if (oc == NULL) { return NULL; } - cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU)); + cpu = XTENSA_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; - env->config = config; xtensa_irq_init(env); diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index 4c41de0668..01123af707 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -96,6 +96,9 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) void HELPER(exception)(CPUXtensaState *env, uint32_t excp) { env->exception_index = excp; + if (excp == EXCP_DEBUG) { + env->exception_taken = 0; + } cpu_loop_exit(env); } @@ -387,7 +390,7 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel) } cpu = CPU(xtensa_env_get_cpu(env)); - env->halt_clock = qemu_get_clock_ns(vm_clock); + env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); cpu->halted = 1; if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { xtensa_rearm_ccompare_timer(env); @@ -448,8 +451,10 @@ void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) switch (access & PAGE_CACHE_MASK) { case PAGE_CACHE_WB: atomctl >>= 2; + /* fall through */ case PAGE_CACHE_WT: atomctl >>= 2; + /* fall through */ case PAGE_CACHE_BYPASS: if ((atomctl & 0x3) == 0) { HELPER(exception_cause_vaddr)(env, pc, diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index e692329157..504cc539e3 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -305,16 +305,21 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) tcg_temp_free(tmp); } -static void gen_advance_ccount(DisasContext *dc) +static void gen_advance_ccount_cond(DisasContext *dc) { if (dc->ccount_delta > 0) { TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta); - dc->ccount_delta = 0; gen_helper_advance_ccount(cpu_env, tmp); tcg_temp_free(tmp); } } +static void gen_advance_ccount(DisasContext *dc) +{ + gen_advance_ccount_cond(dc); + dc->ccount_delta = 0; +} + static void reset_used_window(DisasContext *dc) { dc->used_window = 0; @@ -491,7 +496,7 @@ static void gen_brcondi(DisasContext *dc, TCGCond cond, tcg_temp_free(tmp); } -static void gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) +static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) { if (!xtensa_option_bits_enabled(dc->config, sregnames[sr].opt_bits)) { if (sregnames[sr].name) { @@ -500,6 +505,7 @@ static void gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) qemu_log("SR %d is not implemented\n", sr); } gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return false; } else if (!(sregnames[sr].access & access)) { static const char * const access_text[] = { [SR_R] = "rsr", @@ -510,7 +516,9 @@ static void gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) qemu_log("SR %s is not available for %s\n", sregnames[sr].name, access_text[access]); gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return false; } + return true; } static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) @@ -826,15 +834,27 @@ static void gen_window_check1(DisasContext *dc, unsigned r1) } if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) && r1 / 4 > dc->used_window) { - TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 w = tcg_const_i32(r1 / 4); + int label = gen_new_label(); + TCGv_i32 ws = tcg_temp_new_i32(); dc->used_window = r1 / 4; - gen_advance_ccount(dc); - gen_helper_window_check(cpu_env, pc, w); + tcg_gen_deposit_i32(ws, cpu_SR[WINDOW_START], cpu_SR[WINDOW_START], + dc->config->nareg / 4, dc->config->nareg / 4); + tcg_gen_shr_i32(ws, ws, cpu_SR[WINDOW_BASE]); + tcg_gen_andi_i32(ws, ws, (2 << (r1 / 4)) - 2); + tcg_gen_brcondi_i32(TCG_COND_EQ, ws, 0, label); + { + TCGv_i32 pc = tcg_const_i32(dc->pc); + TCGv_i32 w = tcg_const_i32(r1 / 4); + + gen_advance_ccount_cond(dc); + gen_helper_window_check(cpu_env, pc, w); - tcg_temp_free(w); - tcg_temp_free(pc); + tcg_temp_free(w); + tcg_temp_free(pc); + } + gen_set_label(label); + tcg_temp_free(ws); } } @@ -1482,9 +1502,9 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) break; case 6: /*XSR*/ - { + if (gen_check_sr(dc, RSR_SR, SR_X)) { TCGv_i32 tmp = tcg_temp_new_i32(); - gen_check_sr(dc, RSR_SR, SR_X); + if (RSR_SR >= 64) { gen_check_privilege(dc); } @@ -1707,21 +1727,23 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 3: /*RST3*/ switch (OP2) { case 0: /*RSR*/ - gen_check_sr(dc, RSR_SR, SR_R); - if (RSR_SR >= 64) { - gen_check_privilege(dc); + if (gen_check_sr(dc, RSR_SR, SR_R)) { + if (RSR_SR >= 64) { + gen_check_privilege(dc); + } + gen_window_check1(dc, RRR_T); + gen_rsr(dc, cpu_R[RRR_T], RSR_SR); } - gen_window_check1(dc, RRR_T); - gen_rsr(dc, cpu_R[RRR_T], RSR_SR); break; case 1: /*WSR*/ - gen_check_sr(dc, RSR_SR, SR_W); - if (RSR_SR >= 64) { - gen_check_privilege(dc); + if (gen_check_sr(dc, RSR_SR, SR_W)) { + if (RSR_SR >= 64) { + gen_check_privilege(dc); + } + gen_window_check1(dc, RRR_T); + gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); } - gen_window_check1(dc, RRR_T); - gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); break; case 2: /*SEXTu*/ @@ -2918,8 +2940,7 @@ void gen_intermediate_code_internal(XtensaCPU *cpu, gen_tb_start(); - if (cs->singlestep_enabled && env->exception_taken) { - env->exception_taken = 0; + if (tb->flags & XTENSA_TBFLAG_EXCEPTION) { tcg_gen_movi_i32(cpu_pc, dc.pc); gen_exception(&dc, EXCP_DEBUG); } diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c index 562a549dab..41a17f8a62 100644 --- a/tcg/aarch64/tcg-target.c +++ b/tcg/aarch64/tcg-target.c @@ -315,6 +315,17 @@ static inline void tcg_out_ldst_9(TCGContext *s, tcg_out32(s, op_data << 24 | mod << 20 | off << 12 | rn << 5 | rd); } +/* tcg_out_ldst_12 expects a scaled unsigned immediate offset */ +static inline void tcg_out_ldst_12(TCGContext *s, + enum aarch64_ldst_op_data op_data, + enum aarch64_ldst_op_type op_type, + TCGReg rd, TCGReg rn, + tcg_target_ulong scaled_uimm) +{ + tcg_out32(s, (op_data | 1) << 24 + | op_type << 20 | scaled_uimm << 10 | rn << 5 | rd); +} + static inline void tcg_out_movr(TCGContext *s, int ext, TCGReg rd, TCGReg src) { /* register to register move using MOV (shifted register with no shift) */ @@ -374,10 +385,25 @@ static inline void tcg_out_ldst(TCGContext *s, enum aarch64_ldst_op_data data, { if (offset >= -256 && offset < 256) { tcg_out_ldst_9(s, data, type, rd, rn, offset); - } else { - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset); - tcg_out_ldst_r(s, data, type, rd, rn, TCG_REG_TMP); + return; + } + + if (offset >= 256) { + /* if the offset is naturally aligned and in range, + then we can use the scaled uimm12 encoding */ + unsigned int s_bits = data >> 6; + if (!(offset & ((1 << s_bits) - 1))) { + tcg_target_ulong scaled_uimm = offset >> s_bits; + if (scaled_uimm <= 0xfff) { + tcg_out_ldst_12(s, data, type, rd, rn, scaled_uimm); + return; + } + } } + + /* worst-case scenario, move offset to temp register, use reg offset */ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset); + tcg_out_ldst_r(s, data, type, rd, rn, TCG_REG_TMP); } /* mov alias implemented with add immediate, useful to move to/from SP */ @@ -706,6 +732,51 @@ static inline void tcg_out_uxt(TCGContext *s, int s_bits, tcg_out_ubfm(s, 0, rd, rn, 0, bits); } +static inline void tcg_out_addi(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int aimm) +{ + /* add immediate aimm unsigned 12bit value (with LSL 0 or 12) */ + /* using ADD 0x11000000 | (ext) | (aimm << 10) | (rn << 5) | rd */ + unsigned int base = ext ? 0x91000000 : 0x11000000; + + if (aimm <= 0xfff) { + aimm <<= 10; + } else { + /* we can only shift left by 12, on assert we cannot represent */ + assert(!(aimm & 0xfff)); + assert(aimm <= 0xfff000); + base |= 1 << 22; /* apply LSL 12 */ + aimm >>= 2; + } + + tcg_out32(s, base | aimm | (rn << 5) | rd); +} + +static inline void tcg_out_subi(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int aimm) +{ + /* sub immediate aimm unsigned 12bit value (with LSL 0 or 12) */ + /* using SUB 0x51000000 | (ext) | (aimm << 10) | (rn << 5) | rd */ + unsigned int base = ext ? 0xd1000000 : 0x51000000; + + if (aimm <= 0xfff) { + aimm <<= 10; + } else { + /* we can only shift left by 12, on assert we cannot represent */ + assert(!(aimm & 0xfff)); + assert(aimm <= 0xfff000); + base |= 1 << 22; /* apply LSL 12 */ + aimm >>= 2; + } + + tcg_out32(s, base | aimm | (rn << 5) | rd); +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, 0xd503201f); +} + #ifdef CONFIG_SOFTMMU #include "exec/softmmu_defs.h" @@ -727,7 +798,125 @@ static const void * const qemu_st_helpers[4] = { helper_stq_mmu, }; -#else /* !CONFIG_SOFTMMU */ +static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) +{ + reloc_pc19(lb->label_ptr[0], (tcg_target_long)s->code_ptr); + tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0); + tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, lb->addrlo_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, lb->mem_index); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, + (tcg_target_long)qemu_ld_helpers[lb->opc & 3]); + tcg_out_callr(s, TCG_REG_TMP); + if (lb->opc & 0x04) { + tcg_out_sxt(s, 1, lb->opc & 3, lb->datalo_reg, TCG_REG_X0); + } else { + tcg_out_movr(s, 1, lb->datalo_reg, TCG_REG_X0); + } + + tcg_out_goto(s, (tcg_target_long)lb->raddr); +} + +static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) +{ + reloc_pc19(lb->label_ptr[0], (tcg_target_long)s->code_ptr); + + tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0); + tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, lb->addrlo_reg); + tcg_out_movr(s, 1, TCG_REG_X2, lb->datalo_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, lb->mem_index); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, + (tcg_target_long)qemu_st_helpers[lb->opc & 3]); + tcg_out_callr(s, TCG_REG_TMP); + + tcg_out_nop(s); + tcg_out_goto(s, (tcg_target_long)lb->raddr); +} + +void tcg_out_tb_finalize(TCGContext *s) +{ + int i; + for (i = 0; i < s->nb_qemu_ldst_labels; i++) { + TCGLabelQemuLdst *label = &s->qemu_ldst_labels[i]; + if (label->is_ld) { + tcg_out_qemu_ld_slow_path(s, label); + } else { + tcg_out_qemu_st_slow_path(s, label); + } + } +} + +static void add_qemu_ldst_label(TCGContext *s, int is_ld, int opc, + TCGReg data_reg, TCGReg addr_reg, + int mem_index, + uint8_t *raddr, uint8_t *label_ptr) +{ + int idx; + TCGLabelQemuLdst *label; + + if (s->nb_qemu_ldst_labels >= TCG_MAX_QEMU_LDST) { + tcg_abort(); + } + + idx = s->nb_qemu_ldst_labels++; + label = &s->qemu_ldst_labels[idx]; + label->is_ld = is_ld; + label->opc = opc; + label->datalo_reg = data_reg; + label->addrlo_reg = addr_reg; + label->mem_index = mem_index; + label->raddr = raddr; + label->label_ptr[0] = label_ptr; +} + +/* Load and compare a TLB entry, emitting the conditional jump to the + slow path for the failure case, which will be patched later when finalizing + the slow path. Generated code returns the host addend in X1, + clobbers X0,X2,X3,TMP. */ +static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, + int s_bits, uint8_t **label_ptr, int mem_index, int is_read) +{ + TCGReg base = TCG_AREG0; + int tlb_offset = is_read ? + offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) + : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write); + /* Extract the TLB index from the address into X0. + X0<CPU_TLB_BITS:0> = + addr_reg<TARGET_PAGE_BITS+CPU_TLB_BITS:TARGET_PAGE_BITS> */ + tcg_out_ubfm(s, (TARGET_LONG_BITS == 64), TCG_REG_X0, addr_reg, + TARGET_PAGE_BITS, TARGET_PAGE_BITS + CPU_TLB_BITS); + /* Store the page mask part of the address and the low s_bits into X3. + Later this allows checking for equality and alignment at the same time. + X3 = addr_reg & (PAGE_MASK | ((1 << s_bits) - 1)) */ + tcg_out_andi(s, (TARGET_LONG_BITS == 64), TCG_REG_X3, addr_reg, + (TARGET_LONG_BITS - TARGET_PAGE_BITS) + s_bits, + (TARGET_LONG_BITS - TARGET_PAGE_BITS)); + /* Add any "high bits" from the tlb offset to the env address into X2, + to take advantage of the LSL12 form of the addi instruction. + X2 = env + (tlb_offset & 0xfff000) */ + tcg_out_addi(s, 1, TCG_REG_X2, base, tlb_offset & 0xfff000); + /* Merge the tlb index contribution into X2. + X2 = X2 + (X0 << CPU_TLB_ENTRY_BITS) */ + tcg_out_arith(s, ARITH_ADD, 1, TCG_REG_X2, TCG_REG_X2, + TCG_REG_X0, -CPU_TLB_ENTRY_BITS); + /* Merge "low bits" from tlb offset, load the tlb comparator into X0. + X0 = load [X2 + (tlb_offset & 0x000fff)] */ + tcg_out_ldst(s, TARGET_LONG_BITS == 64 ? LDST_64 : LDST_32, + LDST_LD, TCG_REG_X0, TCG_REG_X2, + (tlb_offset & 0xfff)); + /* Load the tlb addend. Do that early to avoid stalling. + X1 = load [X2 + (tlb_offset & 0xfff) + offsetof(addend)] */ + tcg_out_ldst(s, LDST_64, LDST_LD, TCG_REG_X1, TCG_REG_X2, + (tlb_offset & 0xfff) + (offsetof(CPUTLBEntry, addend)) - + (is_read ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write))); + /* Perform the address comparison. */ + tcg_out_cmp(s, (TARGET_LONG_BITS == 64), TCG_REG_X0, TCG_REG_X3, 0); + *label_ptr = s->code_ptr; + /* If not equal, we jump to the slow path. */ + tcg_out_goto_cond_noaddr(s, TCG_COND_NE); +} + +#endif /* CONFIG_SOFTMMU */ static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data_r, TCGReg addr_r, TCGReg off_r) @@ -815,13 +1004,13 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data_r, tcg_abort(); } } -#endif /* CONFIG_SOFTMMU */ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) { TCGReg addr_reg, data_reg; #ifdef CONFIG_SOFTMMU int mem_index, s_bits; + uint8_t *label_ptr; #endif data_reg = args[0]; addr_reg = args[1]; @@ -829,23 +1018,10 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) #ifdef CONFIG_SOFTMMU mem_index = args[2]; s_bits = opc & 3; - - /* TODO: insert TLB lookup here */ - - /* all arguments passed via registers */ - tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0); - tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, mem_index); - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, - (tcg_target_long)qemu_ld_helpers[s_bits]); - tcg_out_callr(s, TCG_REG_TMP); - - if (opc & 0x04) { /* sign extend */ - tcg_out_sxt(s, 1, s_bits, data_reg, TCG_REG_X0); - } else { - tcg_out_movr(s, 1, data_reg, TCG_REG_X0); - } - + tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 1); + tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, TCG_REG_X1); + add_qemu_ldst_label(s, 1, opc, data_reg, addr_reg, + mem_index, s->code_ptr, label_ptr); #else /* !CONFIG_SOFTMMU */ tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR); @@ -857,6 +1033,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) TCGReg addr_reg, data_reg; #ifdef CONFIG_SOFTMMU int mem_index, s_bits; + uint8_t *label_ptr; #endif data_reg = args[0]; addr_reg = args[1]; @@ -865,17 +1042,10 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) mem_index = args[2]; s_bits = opc & 3; - /* TODO: insert TLB lookup here */ - - /* all arguments passed via registers */ - tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0); - tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg); - tcg_out_movr(s, 1, TCG_REG_X2, data_reg); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, mem_index); - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, - (tcg_target_long)qemu_st_helpers[s_bits]); - tcg_out_callr(s, TCG_REG_TMP); - + tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 0); + tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, TCG_REG_X1); + add_qemu_ldst_label(s, 0, opc, data_reg, addr_reg, + mem_index, s->code_ptr, label_ptr); #else /* !CONFIG_SOFTMMU */ tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR); @@ -1318,26 +1488,6 @@ static void tcg_target_init(TCGContext *s) tcg_add_target_add_op_defs(aarch64_op_defs); } -static inline void tcg_out_addi(TCGContext *s, int ext, - TCGReg rd, TCGReg rn, unsigned int aimm) -{ - /* add immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */ - /* using ADD 0x11000000 | (ext) | (aimm << 10) | (rn << 5) | rd */ - unsigned int base = ext ? 0x91000000 : 0x11000000; - assert(aimm <= 0xfff); - tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd); -} - -static inline void tcg_out_subi(TCGContext *s, int ext, - TCGReg rd, TCGReg rn, unsigned int aimm) -{ - /* sub immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */ - /* using SUB 0x51000000 | (ext) | (aimm << 10) | (rn << 5) | rd */ - unsigned int base = ext ? 0xd1000000 : 0x51000000; - assert(aimm <= 0xfff); - tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd); -} - static void tcg_target_qemu_prologue(TCGContext *s) { /* NB: frame sizes are in 16 byte stack units! */ diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 87eeab3d30..12a7ca3440 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -190,11 +190,11 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) /* qemu_ld/st address constraint */ case 'L': ct->ct |= TCG_CT_REG; -#if TCG_TARGET_REG_BITS == 64 + if (TCG_TARGET_REG_BITS == 64) { tcg_regset_set32(ct->u.regs, 0, 0xffff); -#else + } else { tcg_regset_set32(ct->u.regs, 0, 0xff); -#endif + } tcg_regset_reset_reg(ct->u.regs, TCG_REG_L0); tcg_regset_reset_reg(ct->u.regs, TCG_REG_L1); break; @@ -541,20 +541,34 @@ static inline void tcg_out_mov(TCGContext *s, TCGType type, static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret, tcg_target_long arg) { + tcg_target_long diff; + if (arg == 0) { tgen_arithr(s, ARITH_XOR, ret, ret); return; - } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) { + } + if (arg == (uint32_t)arg || type == TCG_TYPE_I32) { tcg_out_opc(s, OPC_MOVL_Iv + LOWREGMASK(ret), 0, ret, 0); tcg_out32(s, arg); - } else if (arg == (int32_t)arg) { + return; + } + if (arg == (int32_t)arg) { tcg_out_modrm(s, OPC_MOVL_EvIz + P_REXW, 0, ret); tcg_out32(s, arg); - } else { - tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0); - tcg_out32(s, arg); - tcg_out32(s, arg >> 31 >> 1); + return; + } + + /* Try a 7 byte pc-relative lea before the 10 byte movq. */ + diff = arg - ((tcg_target_long)s->code_ptr + 7); + if (diff == (int32_t)diff) { + tcg_out_opc(s, OPC_LEA | P_REXW, ret, 0, 0); + tcg_out8(s, (LOWREGMASK(ret) << 3) | 5); + tcg_out32(s, diff); + return; } + + tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0); + tcg_out64(s, arg); } static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val) @@ -594,6 +608,14 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, tcg_out_modrm_offset(s, opc, arg, arg1, arg2); } +static inline void tcg_out_sti(TCGContext *s, TCGType type, TCGReg base, + tcg_target_long ofs, tcg_target_long val) +{ + int opc = OPC_MOVL_EvIz + (type == TCG_TYPE_I64 ? P_REXW : 0); + tcg_out_modrm_offset(s, opc, 0, base, ofs); + tcg_out32(s, val); +} + static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count) { /* Propagate an opcode prefix, such as P_DATA16. */ @@ -1003,22 +1025,24 @@ static void tcg_out_jmp(TCGContext *s, tcg_target_long dest) #include "exec/softmmu_defs.h" -/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, - int mmu_idx) */ -static const void *qemu_ld_helpers[4] = { - helper_ldb_mmu, - helper_ldw_mmu, - helper_ldl_mmu, - helper_ldq_mmu, +/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, + * int mmu_idx, uintptr_t ra) + */ +static const void * const qemu_ld_helpers[4] = { + helper_ret_ldb_mmu, + helper_ret_ldw_mmu, + helper_ret_ldl_mmu, + helper_ret_ldq_mmu, }; -/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, - uintxx_t val, int mmu_idx) */ -static const void *qemu_st_helpers[4] = { - helper_stb_mmu, - helper_stw_mmu, - helper_stl_mmu, - helper_stq_mmu, +/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, + * uintxx_t val, int mmu_idx, uintptr_t ra) + */ +static const void * const qemu_st_helpers[4] = { + helper_ret_stb_mmu, + helper_ret_stw_mmu, + helper_ret_stl_mmu, + helper_ret_stq_mmu, }; static void add_qemu_ldst_label(TCGContext *s, @@ -1446,25 +1470,21 @@ static void add_qemu_ldst_label(TCGContext *s, } } +/* See the GETPC definition in include/exec/exec-all.h. */ +static inline uintptr_t do_getpc(uint8_t *raddr) +{ + return (uintptr_t)raddr - 1; +} + /* * Generate code for the slow path for a load at the end of block */ -static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *label) +static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { - int s_bits; - int opc = label->opc; - int mem_index = label->mem_index; -#if TCG_TARGET_REG_BITS == 32 - int stack_adjust; - int addrlo_reg = label->addrlo_reg; - int addrhi_reg = label->addrhi_reg; -#endif - int data_reg = label->datalo_reg; - int data_reg2 = label->datahi_reg; - uint8_t *raddr = label->raddr; - uint8_t **label_ptr = &label->label_ptr[0]; - - s_bits = opc & 3; + int opc = l->opc; + int s_bits = opc & 3; + TCGReg data_reg; + uint8_t **label_ptr = &l->label_ptr[0]; /* resolve label address */ *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4); @@ -1472,52 +1492,36 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *label) *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4); } -#if TCG_TARGET_REG_BITS == 32 - tcg_out_pushi(s, mem_index); - stack_adjust = 4; - if (TARGET_LONG_BITS == 64) { - tcg_out_push(s, addrhi_reg); - stack_adjust += 4; - } - tcg_out_push(s, addrlo_reg); - stack_adjust += 4; - tcg_out_push(s, TCG_AREG0); - stack_adjust += 4; -#else - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); - /* The second argument is already loaded with addrlo. */ - tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], mem_index); -#endif + if (TCG_TARGET_REG_BITS == 32) { + int ofs = 0; - /* Code generation of qemu_ld/st's slow path calling MMU helper + tcg_out_st(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, ofs); + ofs += 4; - PRE_PROC ... - call MMU helper - jmp POST_PROC (2b) : short forward jump <- GETRA() - jmp next_code (5b) : dummy long backward jump which is never executed - POST_PROC ... : do post-processing <- GETRA() + 7 - jmp next_code : jump to the code corresponding to next IR of qemu_ld/st - */ + tcg_out_st(s, TCG_TYPE_I32, l->addrlo_reg, TCG_REG_ESP, ofs); + ofs += 4; - tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]); + if (TARGET_LONG_BITS == 64) { + tcg_out_st(s, TCG_TYPE_I32, l->addrhi_reg, TCG_REG_ESP, ofs); + ofs += 4; + } - /* Jump to post-processing code */ - tcg_out8(s, OPC_JMP_short); - tcg_out8(s, 5); - /* Dummy backward jump having information of fast path'pc for MMU helpers */ - tcg_out8(s, OPC_JMP_long); - *(int32_t *)s->code_ptr = (int32_t)(raddr - s->code_ptr - 4); - s->code_ptr += 4; + tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, l->mem_index); + ofs += 4; -#if TCG_TARGET_REG_BITS == 32 - if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) { - /* Pop and discard. This is 2 bytes smaller than the add. */ - tcg_out_pop(s, TCG_REG_ECX); - } else if (stack_adjust != 0) { - tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust); + tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, do_getpc(l->raddr)); + } else { + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0); + /* The second argument is already loaded with addrlo. */ + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + l->mem_index); + tcg_out_movi(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[3], + do_getpc(l->raddr)); } -#endif + tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]); + + data_reg = l->datalo_reg; switch(opc) { case 0 | 4: tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW); @@ -1545,10 +1549,10 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *label) } else if (data_reg == TCG_REG_EDX) { /* xchg %edx, %eax */ tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX, 0, 0, 0); - tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EAX); + tcg_out_mov(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_EAX); } else { tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX); - tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EDX); + tcg_out_mov(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_EDX); } break; default: @@ -1556,28 +1560,17 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *label) } /* Jump to the code corresponding to next IR of qemu_st */ - tcg_out_jmp(s, (tcg_target_long)raddr); + tcg_out_jmp(s, (tcg_target_long)l->raddr); } /* * Generate code for the slow path for a store at the end of block */ -static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *label) +static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { - int s_bits; - int stack_adjust; - int opc = label->opc; - int mem_index = label->mem_index; - int data_reg = label->datalo_reg; -#if TCG_TARGET_REG_BITS == 32 - int data_reg2 = label->datahi_reg; - int addrlo_reg = label->addrlo_reg; - int addrhi_reg = label->addrhi_reg; -#endif - uint8_t *raddr = label->raddr; - uint8_t **label_ptr = &label->label_ptr[0]; - - s_bits = opc & 3; + int opc = l->opc; + int s_bits = opc & 3; + uint8_t **label_ptr = &l->label_ptr[0]; /* resolve label address */ *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4); @@ -1585,61 +1578,56 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *label) *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4); } -#if TCG_TARGET_REG_BITS == 32 - tcg_out_pushi(s, mem_index); - stack_adjust = 4; - if (opc == 3) { - tcg_out_push(s, data_reg2); - stack_adjust += 4; - } - tcg_out_push(s, data_reg); - stack_adjust += 4; - if (TARGET_LONG_BITS == 64) { - tcg_out_push(s, addrhi_reg); - stack_adjust += 4; - } - tcg_out_push(s, addrlo_reg); - stack_adjust += 4; - tcg_out_push(s, TCG_AREG0); - stack_adjust += 4; -#else - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); - /* The second argument is already loaded with addrlo. */ - tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), - tcg_target_call_iarg_regs[2], data_reg); - tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], mem_index); - stack_adjust = 0; -#endif + if (TCG_TARGET_REG_BITS == 32) { + int ofs = 0; - /* Code generation of qemu_ld/st's slow path calling MMU helper + tcg_out_st(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, ofs); + ofs += 4; - PRE_PROC ... - call MMU helper - jmp POST_PROC (2b) : short forward jump <- GETRA() - jmp next_code (5b) : dummy long backward jump which is never executed - POST_PROC ... : do post-processing <- GETRA() + 7 - jmp next_code : jump to the code corresponding to next IR of qemu_ld/st - */ + tcg_out_st(s, TCG_TYPE_I32, l->addrlo_reg, TCG_REG_ESP, ofs); + ofs += 4; - tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]); + if (TARGET_LONG_BITS == 64) { + tcg_out_st(s, TCG_TYPE_I32, l->addrhi_reg, TCG_REG_ESP, ofs); + ofs += 4; + } - /* Jump to post-processing code */ - tcg_out8(s, OPC_JMP_short); - tcg_out8(s, 5); - /* Dummy backward jump having information of fast path'pc for MMU helpers */ - tcg_out8(s, OPC_JMP_long); - *(int32_t *)s->code_ptr = (int32_t)(raddr - s->code_ptr - 4); - s->code_ptr += 4; + tcg_out_st(s, TCG_TYPE_I32, l->datalo_reg, TCG_REG_ESP, ofs); + ofs += 4; + + if (opc == 3) { + tcg_out_st(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_ESP, ofs); + ofs += 4; + } - if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) { - /* Pop and discard. This is 2 bytes smaller than the add. */ - tcg_out_pop(s, TCG_REG_ECX); - } else if (stack_adjust != 0) { - tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust); + tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, l->mem_index); + ofs += 4; + + tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, do_getpc(l->raddr)); + } else { + uintptr_t pc; + + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0); + /* The second argument is already loaded with addrlo. */ + tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), + tcg_target_call_iarg_regs[2], l->datalo_reg); + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + l->mem_index); + + pc = do_getpc(l->raddr); + if (ARRAY_SIZE(tcg_target_call_iarg_regs) > 4) { + tcg_out_movi(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[4], pc); + } else if (pc == (int32_t)pc) { + tcg_out_sti(s, TCG_TYPE_PTR, TCG_REG_ESP, 0, pc); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, pc); + tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RAX, TCG_REG_ESP, 0); + } } - /* Jump to the code corresponding to next IR of qemu_st */ - tcg_out_jmp(s, (tcg_target_long)raddr); + tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]); + + tcg_out_jmp(s, (tcg_target_long)l->raddr); } /* diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 373c3640f0..793532ec95 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1617,19 +1617,29 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_shl_i32, { "r", "rZ", "ri" } }, { INDEX_op_shr_i32, { "r", "rZ", "ri" } }, { INDEX_op_sar_i32, { "r", "rZ", "ri" } }, +#if TCG_TARGET_HAS_rot_i32 { INDEX_op_rotr_i32, { "r", "rZ", "ri" } }, { INDEX_op_rotl_i32, { "r", "rZ", "ri" } }, +#endif +#if TCG_TARGET_HAS_bswap16_i32 { INDEX_op_bswap16_i32, { "r", "r" } }, +#endif +#if TCG_TARGET_HAS_bswap32_i32 { INDEX_op_bswap32_i32, { "r", "r" } }, +#endif { INDEX_op_ext8s_i32, { "r", "rZ" } }, { INDEX_op_ext16s_i32, { "r", "rZ" } }, +#if TCG_TARGET_HAS_deposit_i32 { INDEX_op_deposit_i32, { "r", "0", "rZ" } }, +#endif { INDEX_op_brcond_i32, { "rZ", "rZ" } }, +#if TCG_TARGET_HAS_movcond_i32 { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "0" } }, +#endif { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } }, @@ -121,14 +121,23 @@ static inline void tcg_out8(TCGContext *s, uint8_t v) static inline void tcg_out16(TCGContext *s, uint16_t v) { - *(uint16_t *)s->code_ptr = v; - s->code_ptr += 2; + uint8_t *p = s->code_ptr; + *(uint16_t *)p = v; + s->code_ptr = p + 2; } static inline void tcg_out32(TCGContext *s, uint32_t v) { - *(uint32_t *)s->code_ptr = v; - s->code_ptr += 4; + uint8_t *p = s->code_ptr; + *(uint32_t *)p = v; + s->code_ptr = p + 4; +} + +static inline void tcg_out64(TCGContext *s, uint64_t v) +{ + uint8_t *p = s->code_ptr; + *(uint64_t *)p = v; + s->code_ptr = p + 8; } /* label relocation processing */ diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index d1241b5692..e118bc7179 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -34,9 +34,6 @@ tcg_abort(); \ } while (0) -/* Single bit n. */ -#define BIT(n) (1 << (n)) - /* Bitfield n...m (in 32 bit value). */ #define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m) diff --git a/tests/.gitignore b/tests/.gitignore index fb05c2ae87..d11cc22373 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -11,6 +11,7 @@ test-iov test-mul64 test-qapi-types.[ch] test-qapi-visit.[ch] +test-qdev-global-props test-qmp-commands.h test-qmp-commands test-qmp-input-strict diff --git a/tests/Makefile b/tests/Makefile index 6c34eec1d2..baba9e95ad 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -23,6 +23,8 @@ check-unit-y += tests/test-string-input-visitor$(EXESUF) gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c check-unit-y += tests/test-string-output-visitor$(EXESUF) gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c +check-unit-y += tests/test-opts-visitor$(EXESUF) +gcov-files-test-opts-visitor-y = qapi/opts-visitor.c check-unit-y += tests/test-coroutine$(EXESUF) gcov-files-test-coroutine-y = coroutine-$(CONFIG_COROUTINE_BACKEND).c check-unit-y += tests/test-visitor-serialization$(EXESUF) @@ -48,12 +50,14 @@ check-unit-y += tests/test-int128$(EXESUF) # all code tested by test-int128 is inside int128.h gcov-files-test-int128-y = check-unit-y += tests/test-bitops$(EXESUF) +check-unit-y += tests/test-qdev-global-props$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh # All QTests for now are POSIX-only, but the dependencies are # really in libqtest, not in the testcases themselves. -check-qtest-i386-y = tests/fdc-test$(EXESUF) +check-qtest-i386-y = tests/endianness-test$(EXESUF) +check-qtest-i386-y += tests/fdc-test$(EXESUF) gcov-files-i386-y = hw/fdc.c check-qtest-i386-y += tests/ide-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) @@ -65,8 +69,16 @@ check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) +check-qtest-mips-y = tests/endianness-test$(EXESUF) +check-qtest-mips64-y = tests/endianness-test$(EXESUF) +check-qtest-mips64el-y = tests/endianness-test$(EXESUF) +check-qtest-ppc-y = tests/endianness-test$(EXESUF) +check-qtest-ppc64-y = tests/endianness-test$(EXESUF) +check-qtest-sh4-y = tests/endianness-test$(EXESUF) +check-qtest-sh4eb-y = tests/endianness-test$(EXESUF) +check-qtest-sparc64-y = tests/endianness-test$(EXESUF) #check-qtest-sparc-y = tests/m48t59-test$(EXESUF) -#check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) +#check-qtest-sparc64-y += tests/m48t59-test$(EXESUF) gcov-files-sparc-y += hw/m48t59.c gcov-files-sparc64-y += hw/m48t59.c check-qtest-arm-y = tests/tmp105-test$(EXESUF) @@ -74,6 +86,14 @@ gcov-files-arm-y += hw/tmp105.c check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) +check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ + comments.json empty.json funny-char.json indented-expr.json \ + missing-colon.json missing-comma-list.json \ + missing-comma-object.json non-objects.json \ + qapi-schema-test.json quoted-structural-chars.json \ + trailing-comma-list.json trailing-comma-object.json \ + unclosed-list.json unclosed-object.json unclosed-string.json) + GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ @@ -82,7 +102,8 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o \ - tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o + tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \ + tests/test-opts-visitor.o test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o @@ -106,15 +127,21 @@ tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuutil.a tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o tests/test-int128$(EXESUF): tests/test-int128.o +tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ + hw/core/qdev.o hw/core/qdev-properties.o \ + hw/core/irq.o \ + qom/object.o qom/container.o qom/qom-qobject.o \ + $(test-qapi-obj-y) \ + libqemuutil.a libqemustub.a tests/test-qapi-types.c tests/test-qapi-types.h :\ -$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ -$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ -$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a @@ -124,6 +151,7 @@ tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a @@ -136,6 +164,7 @@ libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o +tests/endianness-test$(EXESUF): tests/endianness-test.o tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o @@ -161,6 +190,7 @@ check-help: @echo " make check-qtest-TARGET Run qtest tests for given target" @echo " make check-qtest Run qtest tests" @echo " make check-unit Run qobject tests" + @echo " make check-qapi-schema Run QAPI schema tests" @echo " make check-block Run block tests" @echo " make check-report.html Generates an HTML test report" @echo @@ -223,13 +253,24 @@ check-report.html: check-report.xml check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $< +.PHONY: check-tests/test-qapi.py +check-tests/test-qapi.py: tests/test-qapi.py + +.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) +$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json + $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py <$^ >$*.out 2>$*.err; echo $$? >$*.exit, " TEST $*.out") + @diff -q $(SRC_PATH)/$*.out $*.out + @diff -q $(SRC_PATH)/$*.err $*.err + @diff -q $(SRC_PATH)/$*.exit $*.exit + # Consolidated targets -.PHONY: check-qtest check-unit check +.PHONY: check-qapi-schema check-qtest check-unit check +check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y)) check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS)) check-unit: $(patsubst %,check-%, $(check-unit-y)) check-block: $(patsubst %,check-%, $(check-block-y)) -check: check-unit check-qtest +check: check-qapi-schema check-unit check-qtest -include $(wildcard tests/*.d) -include $(wildcard tests/libqos/*.d) diff --git a/tests/endianness-test.c b/tests/endianness-test.c new file mode 100644 index 0000000000..feb32a8503 --- /dev/null +++ b/tests/endianness-test.c @@ -0,0 +1,316 @@ +/* + * QTest testcase for ISA endianness + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "libqtest.h" + +#include <glib.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "qemu/bswap.h" + +typedef struct TestCase TestCase; +struct TestCase { + const char *arch; + const char *machine; + uint64_t isa_base; + bool bswap; + const char *superio; +}; + +static const TestCase test_cases[] = { + { "i386", "pc", -1 }, + { "mips", "magnum", 0x90000000, .bswap = true }, + { "mips", "pica61", 0x90000000, .bswap = true }, + { "mips", "mips", 0x14000000, .bswap = true }, + { "mips", "malta", 0x10000000, .bswap = true }, + { "mips64", "magnum", 0x90000000, .bswap = true }, + { "mips64", "pica61", 0x90000000, .bswap = true }, + { "mips64", "mips", 0x14000000, .bswap = true }, + { "mips64", "malta", 0x10000000, .bswap = true }, + { "mips64el", "fulong2e", 0x1fd00000 }, + { "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" }, + { "ppc", "prep", 0x80000000, .bswap = true }, + { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" }, + { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" }, + { "ppc64", "pseries", 0x10080000000, .bswap = true, .superio = "i82378" }, + { "sh4", "r2d", 0xfe240000, .superio = "i82378" }, + { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" }, + { "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true }, + { "x86_64", "pc", -1 }, + {} +}; + +static uint8_t isa_inb(const TestCase *test, uint16_t addr) +{ + uint8_t value; + if (test->isa_base == -1) { + value = inb(addr); + } else { + value = readb(test->isa_base + addr); + } + return value; +} + +static uint16_t isa_inw(const TestCase *test, uint16_t addr) +{ + uint16_t value; + if (test->isa_base == -1) { + value = inw(addr); + } else { + value = readw(test->isa_base + addr); + } + return test->bswap ? bswap16(value) : value; +} + +static uint32_t isa_inl(const TestCase *test, uint16_t addr) +{ + uint32_t value; + if (test->isa_base == -1) { + value = inl(addr); + } else { + value = readl(test->isa_base + addr); + } + return test->bswap ? bswap32(value) : value; +} + +static void isa_outb(const TestCase *test, uint16_t addr, uint8_t value) +{ + if (test->isa_base == -1) { + outb(addr, value); + } else { + writeb(test->isa_base + addr, value); + } +} + +static void isa_outw(const TestCase *test, uint16_t addr, uint16_t value) +{ + value = test->bswap ? bswap16(value) : value; + if (test->isa_base == -1) { + outw(addr, value); + } else { + writew(test->isa_base + addr, value); + } +} + +static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value) +{ + value = test->bswap ? bswap32(value) : value; + if (test->isa_base == -1) { + outl(addr, value); + } else { + writel(test->isa_base + addr, value); + } +} + + +static void test_endianness(gconstpointer data) +{ + const TestCase *test = data; + char *args; + + args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev", + test->machine, + test->superio ? " -device " : "", + test->superio ?: ""); + qtest_start(args); + isa_outl(test, 0xe0, 0x87654321); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21); + + isa_outw(test, 0xe2, 0x8866); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21); + + isa_outw(test, 0xe0, 0x4422); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); + + isa_outb(test, 0xe3, 0x87); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); + + isa_outb(test, 0xe2, 0x65); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); + + isa_outb(test, 0xe1, 0x43); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); + + isa_outb(test, 0xe0, 0x21); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); + g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21); + qtest_quit(global_qtest); + g_free(args); +} + +static void test_endianness_split(gconstpointer data) +{ + const TestCase *test = data; + char *args; + + args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev", + test->machine, + test->superio ? " -device " : "", + test->superio ?: ""); + qtest_start(args); + isa_outl(test, 0xe8, 0x87654321); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); + + isa_outw(test, 0xea, 0x8866); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); + + isa_outw(test, 0xe8, 0x4422); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); + + isa_outb(test, 0xeb, 0x87); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766); + + isa_outb(test, 0xea, 0x65); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); + + isa_outb(test, 0xe9, 0x43); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322); + + isa_outb(test, 0xe8, 0x21); + g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); + qtest_quit(global_qtest); + g_free(args); +} + +static void test_endianness_combine(gconstpointer data) +{ + const TestCase *test = data; + char *args; + + args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev", + test->machine, + test->superio ? " -device " : "", + test->superio ?: ""); + qtest_start(args); + isa_outl(test, 0xe0, 0x87654321); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321); + + isa_outw(test, 0xe2, 0x8866); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664321); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866); + g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321); + + isa_outw(test, 0xe0, 0x4422); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664422); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866); + g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422); + + isa_outb(test, 0xe3, 0x87); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87664422); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8766); + + isa_outb(test, 0xe2, 0x65); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654422); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422); + + isa_outb(test, 0xe1, 0x43); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654322); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4322); + + isa_outb(test, 0xe0, 0x21); + g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321); + g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321); + qtest_quit(global_qtest); + g_free(args); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + int ret; + int i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; test_cases[i].arch; i++) { + gchar *path; + if (strcmp(test_cases[i].arch, arch) != 0) { + continue; + } + path = g_strdup_printf("/%s/endianness/%s", + arch, test_cases[i].machine); + g_test_add_data_func(path, &test_cases[i], test_endianness); + + path = g_strdup_printf("/%s/endianness/split/%s", + arch, test_cases[i].machine); + g_test_add_data_func(path, &test_cases[i], test_endianness_split); + + path = g_strdup_printf("/%s/endianness/combine/%s", + arch, test_cases[i].machine); + g_test_add_data_func(path, &test_cases[i], test_endianness_combine); + } + + ret = g_test_run(); + + return ret; +} diff --git a/tests/libqtest.h b/tests/libqtest.h index 0f6aade092..a6e99bd023 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -258,9 +258,9 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size) * qtest_clock_step_next: * @s: #QTestState instance to operate on. * - * Advance the vm_clock to the next deadline. + * Advance the QEMU_CLOCK_VIRTUAL to the next deadline. * - * Returns: The current value of the vm_clock in nanoseconds. + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. */ int64_t qtest_clock_step_next(QTestState *s); @@ -269,9 +269,9 @@ int64_t qtest_clock_step_next(QTestState *s); * @s: QTestState instance to operate on. * @step: Number of nanoseconds to advance the clock by. * - * Advance the vm_clock by @step nanoseconds. + * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds. * - * Returns: The current value of the vm_clock in nanoseconds. + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. */ int64_t qtest_clock_step(QTestState *s, int64_t step); @@ -280,9 +280,9 @@ int64_t qtest_clock_step(QTestState *s, int64_t step); * @s: QTestState instance to operate on. * @val: Nanoseconds value to advance the clock to. * - * Advance the vm_clock to @val nanoseconds since the VM was launched. + * Advance the QEMU_CLOCK_VIRTUAL to @val nanoseconds since the VM was launched. * - * Returns: The current value of the vm_clock in nanoseconds. + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. */ int64_t qtest_clock_set(QTestState *s, int64_t val); @@ -584,9 +584,9 @@ static inline void memwrite(uint64_t addr, const void *data, size_t size) /** * clock_step_next: * - * Advance the vm_clock to the next deadline. + * Advance the QEMU_CLOCK_VIRTUAL to the next deadline. * - * Returns: The current value of the vm_clock in nanoseconds. + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. */ static inline int64_t clock_step_next(void) { @@ -597,9 +597,9 @@ static inline int64_t clock_step_next(void) * clock_step: * @step: Number of nanoseconds to advance the clock by. * - * Advance the vm_clock by @step nanoseconds. + * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds. * - * Returns: The current value of the vm_clock in nanoseconds. + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. */ static inline int64_t clock_step(int64_t step) { @@ -610,9 +610,9 @@ static inline int64_t clock_step(int64_t step) * clock_set: * @val: Nanoseconds value to advance the clock to. * - * Advance the vm_clock to @val nanoseconds since the VM was launched. + * Advance the QEMU_CLOCK_VIRTUAL to @val nanoseconds since the VM was launched. * - * Returns: The current value of the vm_clock in nanoseconds. + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. */ static inline int64_t clock_set(int64_t val) { diff --git a/tests/qapi-schema/comments.err b/tests/qapi-schema/comments.err new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/comments.err diff --git a/tests/qapi-schema/comments.exit b/tests/qapi-schema/comments.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/comments.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/comments.json b/tests/qapi-schema/comments.json new file mode 100644 index 0000000000..e643f3a74c --- /dev/null +++ b/tests/qapi-schema/comments.json @@ -0,0 +1,4 @@ +# Unindented comment +{ 'enum': 'Status', # Comment to the right of code + # Indented comment + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out new file mode 100644 index 0000000000..e3bd904453 --- /dev/null +++ b/tests/qapi-schema/comments.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +['Status'] +[] diff --git a/tests/qapi-schema/empty.err b/tests/qapi-schema/empty.err new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/empty.err diff --git a/tests/qapi-schema/empty.exit b/tests/qapi-schema/empty.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/empty.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/empty.json b/tests/qapi-schema/empty.json new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/empty.json diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out new file mode 100644 index 0000000000..b7f89a45c6 --- /dev/null +++ b/tests/qapi-schema/empty.out @@ -0,0 +1,3 @@ +[] +[] +[] diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err new file mode 100644 index 0000000000..d3dd293faf --- /dev/null +++ b/tests/qapi-schema/funny-char.err @@ -0,0 +1 @@ +<stdin>:2:36: Stray ";" diff --git a/tests/qapi-schema/funny-char.exit b/tests/qapi-schema/funny-char.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/funny-char.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/funny-char.json b/tests/qapi-schema/funny-char.json new file mode 100644 index 0000000000..d4973a2cdf --- /dev/null +++ b/tests/qapi-schema/funny-char.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ]; } diff --git a/tests/qapi-schema/funny-char.out b/tests/qapi-schema/funny-char.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/funny-char.out diff --git a/tests/qapi-schema/indented-expr.err b/tests/qapi-schema/indented-expr.err new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/indented-expr.err diff --git a/tests/qapi-schema/indented-expr.exit b/tests/qapi-schema/indented-expr.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/indented-expr.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/indented-expr.json b/tests/qapi-schema/indented-expr.json new file mode 100644 index 0000000000..d80af60564 --- /dev/null +++ b/tests/qapi-schema/indented-expr.json @@ -0,0 +1,2 @@ +{ 'id' : 'eins' } + { 'id' : 'zwei' } diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out new file mode 100644 index 0000000000..98af89aa1d --- /dev/null +++ b/tests/qapi-schema/indented-expr.out @@ -0,0 +1,3 @@ +[OrderedDict([('id', 'eins')]), OrderedDict([('id', 'zwei')])] +[] +[] diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err new file mode 100644 index 0000000000..9f2a35515c --- /dev/null +++ b/tests/qapi-schema/missing-colon.err @@ -0,0 +1 @@ +<stdin>:1:10: Expected ":" diff --git a/tests/qapi-schema/missing-colon.exit b/tests/qapi-schema/missing-colon.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/missing-colon.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/missing-colon.json b/tests/qapi-schema/missing-colon.json new file mode 100644 index 0000000000..6fc27ce409 --- /dev/null +++ b/tests/qapi-schema/missing-colon.json @@ -0,0 +1,2 @@ +{ 'enum' 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/missing-colon.out b/tests/qapi-schema/missing-colon.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/missing-colon.out diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err new file mode 100644 index 0000000000..4fe0700195 --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.err @@ -0,0 +1 @@ +<stdin>:2:20: Expected "," or "]" diff --git a/tests/qapi-schema/missing-comma-list.exit b/tests/qapi-schema/missing-comma-list.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/missing-comma-list.json b/tests/qapi-schema/missing-comma-list.json new file mode 100644 index 0000000000..1af39b2930 --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good' 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/missing-comma-list.out b/tests/qapi-schema/missing-comma-list.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.out diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err new file mode 100644 index 0000000000..b0121b5f3a --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.err @@ -0,0 +1 @@ +<stdin>:2:3: Expected "," or "}" diff --git a/tests/qapi-schema/missing-comma-object.exit b/tests/qapi-schema/missing-comma-object.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/missing-comma-object.json b/tests/qapi-schema/missing-comma-object.json new file mode 100644 index 0000000000..50f51786e4 --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status' + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/missing-comma-object.out b/tests/qapi-schema/missing-comma-object.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.out diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err new file mode 100644 index 0000000000..a6c2dc26a6 --- /dev/null +++ b/tests/qapi-schema/non-objects.err @@ -0,0 +1 @@ +<stdin>:1:1: Expected "{" diff --git a/tests/qapi-schema/non-objects.exit b/tests/qapi-schema/non-objects.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/non-objects.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/non-objects.json b/tests/qapi-schema/non-objects.json new file mode 100644 index 0000000000..f3fa851d4b --- /dev/null +++ b/tests/qapi-schema/non-objects.json @@ -0,0 +1,2 @@ +'string' +[ ] diff --git a/tests/qapi-schema/non-objects.out b/tests/qapi-schema/non-objects.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/non-objects.out diff --git a/tests/qapi-schema/qapi-schema-test.err b/tests/qapi-schema/qapi-schema-test.err new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/qapi-schema-test.err diff --git a/tests/qapi-schema/qapi-schema-test.exit b/tests/qapi-schema/qapi-schema-test.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/qapi-schema-test.exit @@ -0,0 +1 @@ +0 diff --git a/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 4434fa3961..fe5af756c5 100644 --- a/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -51,3 +51,18 @@ { 'command': 'user_def_cmd', 'data': {} } { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} } { 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', 'ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' } + +# For testing integer range flattening in opts-visitor. The following schema +# corresponds to the option format: +# +# -userdef i64=3-6,i64=-5--1,u64=2,u16=1,u16=7-12 +# +# For simplicity, this example doesn't use [type=]discriminator nor optargs +# specific to discriminator values. +{ 'type': 'UserDefOptions', + 'data': { + '*i64' : [ 'int' ], + '*u64' : [ 'uint64' ], + '*u16' : [ 'uint16' ], + '*i64x': 'int' , + '*u64x': 'uint64' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out new file mode 100644 index 0000000000..3851880de3 --- /dev/null +++ b/tests/qapi-schema/qapi-schema-test.out @@ -0,0 +1,21 @@ +[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]), + OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefOne'), ('data', OrderedDict([('integer', 'int'), ('string', 'str'), ('*enum1', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), + OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), + OrderedDict([('union', 'UserDefUnion'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), + OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]), + OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), + OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), + OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), + OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] +['EnumOne', 'UserDefUnionKind', 'UserDefNativeListUnionKind'] +[OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefOne'), ('data', OrderedDict([('integer', 'int'), ('string', 'str'), ('*enum1', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), + OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), + OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err new file mode 100644 index 0000000000..a6c2dc26a6 --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.err @@ -0,0 +1 @@ +<stdin>:1:1: Expected "{" diff --git a/tests/qapi-schema/quoted-structural-chars.exit b/tests/qapi-schema/quoted-structural-chars.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/quoted-structural-chars.json b/tests/qapi-schema/quoted-structural-chars.json new file mode 100644 index 0000000000..9fe657ae9c --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.json @@ -0,0 +1 @@ +'{' 'key1' ':' 'value1' ',' 'key2' ':' '[' ']' '}' diff --git a/tests/qapi-schema/quoted-structural-chars.out b/tests/qapi-schema/quoted-structural-chars.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.out diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py new file mode 100644 index 0000000000..b3d1e1dbce --- /dev/null +++ b/tests/qapi-schema/test-qapi.py @@ -0,0 +1,27 @@ +# +# QAPI parser test harness +# +# Copyright (c) 2013 Red Hat Inc. +# +# Authors: +# Markus Armbruster <armbru@redhat.com> +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. +# + +from qapi import * +from pprint import pprint +import sys + +try: + exprs = parse_schema(sys.stdin) +except SystemExit: + raise +except: + print >>sys.stderr, "Crashed:", sys.exc_info()[0] + exit(1) + +pprint(exprs) +pprint(enum_types) +pprint(struct_types) diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err new file mode 100644 index 0000000000..ff839a34e9 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.err @@ -0,0 +1 @@ +<stdin>:2:36: Expected "{", "[" or string diff --git a/tests/qapi-schema/trailing-comma-list.exit b/tests/qapi-schema/trailing-comma-list.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/trailing-comma-list.json b/tests/qapi-schema/trailing-comma-list.json new file mode 100644 index 0000000000..9b0c8bd70b --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly', ] } diff --git a/tests/qapi-schema/trailing-comma-list.out b/tests/qapi-schema/trailing-comma-list.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.out diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err new file mode 100644 index 0000000000..f5409627da --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.err @@ -0,0 +1 @@ +<stdin>:2:38: Expected string diff --git a/tests/qapi-schema/trailing-comma-object.exit b/tests/qapi-schema/trailing-comma-object.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/trailing-comma-object.json b/tests/qapi-schema/trailing-comma-object.json new file mode 100644 index 0000000000..bbaea550c8 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ], } diff --git a/tests/qapi-schema/trailing-comma-object.out b/tests/qapi-schema/trailing-comma-object.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.out diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err new file mode 100644 index 0000000000..0e837a7fad --- /dev/null +++ b/tests/qapi-schema/unclosed-list.err @@ -0,0 +1 @@ +<stdin>:1:20: Expected "," or "]" diff --git a/tests/qapi-schema/unclosed-list.exit b/tests/qapi-schema/unclosed-list.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/unclosed-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/unclosed-list.json b/tests/qapi-schema/unclosed-list.json new file mode 100644 index 0000000000..e3e9566982 --- /dev/null +++ b/tests/qapi-schema/unclosed-list.json @@ -0,0 +1 @@ +{ 'key': [ 'value' } diff --git a/tests/qapi-schema/unclosed-list.out b/tests/qapi-schema/unclosed-list.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/unclosed-list.out diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err new file mode 100644 index 0000000000..e6dc9501dc --- /dev/null +++ b/tests/qapi-schema/unclosed-object.err @@ -0,0 +1 @@ +<stdin>:1:21: Expected "," or "}" diff --git a/tests/qapi-schema/unclosed-object.exit b/tests/qapi-schema/unclosed-object.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/unclosed-object.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/unclosed-object.json b/tests/qapi-schema/unclosed-object.json new file mode 100644 index 0000000000..8ac069dce3 --- /dev/null +++ b/tests/qapi-schema/unclosed-object.json @@ -0,0 +1 @@ +{ 'key': [ 'value' ] diff --git a/tests/qapi-schema/unclosed-object.out b/tests/qapi-schema/unclosed-object.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/unclosed-object.out diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err new file mode 100644 index 0000000000..948d88339d --- /dev/null +++ b/tests/qapi-schema/unclosed-string.err @@ -0,0 +1 @@ +<stdin>:1:11: Missing terminating "'" diff --git a/tests/qapi-schema/unclosed-string.exit b/tests/qapi-schema/unclosed-string.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/unclosed-string.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/unclosed-string.json b/tests/qapi-schema/unclosed-string.json new file mode 100644 index 0000000000..8c16b6b6f6 --- /dev/null +++ b/tests/qapi-schema/unclosed-string.json @@ -0,0 +1,2 @@ +{ 'text': 'lorem ips +} diff --git a/tests/qapi-schema/unclosed-string.out b/tests/qapi-schema/unclosed-string.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/unclosed-string.out diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 1cf8bf79b6..1f39c6ad21 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -72,11 +72,11 @@ echo echo === Enable and disable lazy refcounting on the command line, plus some invalid values === echo -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts=on -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts=off -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts= -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts=42 -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts=foo +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=on +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=off +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts= +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=42 +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=foo echo @@ -85,8 +85,8 @@ echo _make_test_img -ocompat=0.10 $size -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts=on -run_qemu -drive file=$TEST_IMG,format=qcow2,lazy_refcounts=off +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=on +run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=off echo echo === No medium === diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 95ff245f40..5582ed3655 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -22,101 +22,101 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: could not === Enable and disable lazy refcounting on the command line, plus some invalid values === -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on -QEMU 1.5.50 monitor - type 'help' for more information
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on +QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
-Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=off -QEMU 1.5.50 monitor - type 'help' for more information
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off +QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
-Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts= -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=: Parameter 'lazy_refcounts' expects 'on' or 'off' -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=: could not open disk image TEST_DIR/t.qcow2: Invalid argument +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Invalid argument -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=42 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=42: Parameter 'lazy_refcounts' expects 'on' or 'off' -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=42: could not open disk image TEST_DIR/t.qcow2: Invalid argument +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: could not open disk image TEST_DIR/t.qcow2: Invalid argument -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=foo: Parameter 'lazy_refcounts' expects 'on' or 'off' -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=foo: could not open disk image TEST_DIR/t.qcow2: Invalid argument +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: could not open disk image TEST_DIR/t.qcow2: Invalid argument === With version 2 images enabling lazy refcounts must fail === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on: could not open disk image TEST_DIR/t.qcow2: Invalid argument +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Invalid argument -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=off -QEMU 1.5.50 monitor - type 'help' for more information
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off +QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
=== No medium === Testing: -drive if=floppy -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=ide,media=cdrom -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=scsi,media=cdrom -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=ide -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: Device needs media, but drive is empty QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device ide-hd failed Testing: -drive if=virtio -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty QEMU_PROG: -drive if=virtio: Device initialization failed. QEMU_PROG: -drive if=virtio: Device initialization failed. QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized Testing: -drive if=scsi -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty QEMU_PROG: -drive if=scsi: Device initialization failed. QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device lsi53c895a failed Testing: -drive if=none,id=disk -device ide-cd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=none,id=disk -device ide-drive,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized Testing: -drive if=none,id=disk -device ide-hd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device scsi-disk,drive=disk: Device initialization failed. QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device scsi-hd,drive=disk: Device initialization failed. QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized @@ -125,77 +125,77 @@ QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized === Read-only === Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on: readonly not supported by this bus type +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on: read-only not supported by this bus type Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
=== Cache modes === Testing: -drive media=cdrom,cache=none -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=directsync -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=writeback -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=writethrough -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=unsafe -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=invalid_value @@ -205,7 +205,7 @@ QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option === Specifying the protocol layer === Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file -QEMU 1.5.50 monitor - type 'help' for more information
+QEMU X.Y.Z monitor - type 'help' for more information
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2 diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index c66f8dbd7d..44bb025687 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -97,6 +97,12 @@ class TestSingleDrive(iotests.QMPTestCase): target=target_img, sync='full', mode='existing') self.assert_qmp(result, 'error/class', 'GenericError') + def test_invalid_format(self): + result = self.vm.qmp('drive-backup', device='drive0', + target=target_img, sync='full', + format='spaghetti-noodles') + self.assert_qmp(result, 'error/class', 'GenericError') + def test_device_not_found(self): result = self.vm.qmp('drive-backup', device='nonexistent', target=target_img, sync='full') diff --git a/tests/qemu-iotests/055.out b/tests/qemu-iotests/055.out index fa16b5ccef..6323079e08 100644 --- a/tests/qemu-iotests/055.out +++ b/tests/qemu-iotests/055.out @@ -1,5 +1,5 @@ -............. +.............. ---------------------------------------------------------------------- -Ran 13 tests +Ran 14 tests OK diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 new file mode 100755 index 0000000000..63893423cf --- /dev/null +++ b/tests/qemu-iotests/056 @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# +# Tests for drive-backup +# +# Copyright (C) 2013 Red Hat, Inc. +# +# Based on 041. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import time +import os +import iotests +from iotests import qemu_img, qemu_io, create_image + +backing_img = os.path.join(iotests.test_dir, 'backing.img') +test_img = os.path.join(iotests.test_dir, 'test.img') +target_img = os.path.join(iotests.test_dir, 'target.img') + +class TestSyncModesNoneAndTop(iotests.QMPTestCase): + image_len = 64 * 1024 * 1024 # MB + + def setUp(self): + create_image(backing_img, TestSyncModesNoneAndTop.image_len) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_io('-c', 'write -P0x41 0 512', test_img) + qemu_io('-c', 'write -P0xd5 1M 32k', test_img) + qemu_io('-c', 'write -P0xdc 32M 124k', test_img) + qemu_io('-c', 'write -P0xdc 67043328 64k', test_img) + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + os.remove(backing_img) + try: + os.remove(target_img) + except OSError: + pass + + def test_complete_top(self): + self.assert_no_active_block_jobs() + result = self.vm.qmp('drive-backup', device='drive0', sync='top', + format=iotests.imgfmt, target=target_img) + self.assert_qmp(result, 'return', {}) + + # Custom completed check as we are not copying all data. + completed = False + while not completed: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED': + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp_absent(event, 'data/error') + completed = True + + self.assert_no_active_block_jobs() + self.vm.shutdown() + self.assertTrue(iotests.compare_images(test_img, target_img), + 'target image does not match source after backup') + + def test_cancel_sync_none(self): + self.assert_no_active_block_jobs() + + result = self.vm.qmp('drive-backup', device='drive0', + sync='none', target=target_img) + self.assert_qmp(result, 'return', {}) + time.sleep(1) + self.vm.hmp_qemu_io('drive0', 'write -P0x5e 0 512') + self.vm.hmp_qemu_io('drive0', 'aio_flush') + # Verify that the original contents exist in the target image. + + event = self.cancel_and_wait() + self.assert_qmp(event, 'data/type', 'backup') + + self.vm.shutdown() + time.sleep(1) + self.assertEqual(-1, qemu_io('-c', 'read -P0x41 0 512', target_img).find("verification failed")) + + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2', 'qed']) diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out new file mode 100644 index 0000000000..fbc63e62f8 --- /dev/null +++ b/tests/qemu-iotests/056.out @@ -0,0 +1,5 @@ +.. +---------------------------------------------------------------------- +Ran 2 tests + +OK diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 new file mode 100755 index 0000000000..b03429dd01 --- /dev/null +++ b/tests/qemu-iotests/059 @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Test case for vmdk +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=famz@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# This tests vmdk-specific low-level functionality +_supported_fmt vmdk +_supported_proto generic +_supported_os Linux + +capacity_offset=16 +granularity_offset=20 +grain_table_size_offset=44 + +echo "=== Testing invalid granularity ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "$granularity_offset" "\xff\xff\xff\xff\xff\xff\xff\xff" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +echo "=== Testing too big L2 table size ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "$grain_table_size_offset" "\xff\xff\xff\xff" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +echo "=== Testing too big L1 table size ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "$capacity_offset" "\xff\xff\xff\xff" +poke_file "$TEST_IMG" "$grain_table_size_offset" "\x01\x00\x00\x00" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out new file mode 100644 index 0000000000..9e715e5a95 --- /dev/null +++ b/tests/qemu-iotests/059.out @@ -0,0 +1,20 @@ +QA output created by 059 +=== Testing invalid granularity === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +invalid granularity, image may be corrupt +qemu-io: can't open device TEST_DIR/t.vmdk +no file open, try 'help open' +=== Testing too big L2 table size === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +L2 table size too big +qemu-io: can't open device TEST_DIR/t.vmdk +no file open, try 'help open' +=== Testing too big L1 table size === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +L1 size too big +qemu-io: can't open device TEST_DIR/t.vmdk +no file open, try 'help open' +*** done diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 9dbcae8d8c..97a31ff0b1 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -155,7 +155,8 @@ _filter_qemu_io() # replace occurrences of QEMU_PROG with "qemu" _filter_qemu() { - sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" + sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ + -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' } # make sure this script returns success diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index e9ba3586b5..5e077c3573 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -34,6 +34,12 @@ dd() fi } +# poke_file 'test.img' 512 '\xff\xfe' +poke_file() +{ + printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null +} + # we need common.config if [ "$iam" != "check" ] then diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index fdc6ed14ca..43c05d6f5c 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -57,8 +57,10 @@ 048 img auto quick 049 rw auto 050 rw auto backing quick -051 rw auto +#051 rw auto 052 rw auto backing 053 rw auto 054 rw auto 055 rw auto +056 rw auto backing +059 rw auto diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index b028a890e6..33ad0ecb92 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -95,6 +95,11 @@ class VM(object): self._num_drives += 1 return self + def hmp_qemu_io(self, drive, cmd): + '''Write to a given drive using an HMP command''' + return self.qmp('human-monitor-command', + command_line='qemu-io %s "%s"' % (drive, cmd)) + def add_fd(self, fd, fdset, opaque, opts=''): '''Pass a file descriptor to the VM''' options = ['fd=%d' % fd, diff --git a/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c b/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c index ce864844d9..cbf900713f 100644 --- a/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c +++ b/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c @@ -14,7 +14,7 @@ int main() resultdsp = 0x01; __asm ("mthi %0, $ac1\n\t" - "mtlo %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" "dpaq_sa.l.w $ac1, %3, %4\n\t" "mfhi %0, $ac1\n\t" "mflo %1, $ac1\n\t" @@ -27,8 +27,8 @@ int main() assert(ach == resulth); assert(acl == resultl); - ach = 0x12; - acl = 0x48; + ach = 0x00000012; + acl = 0x00000048; rs = 0x80000000; rt = 0x80000000; @@ -37,7 +37,7 @@ int main() resultdsp = 0x01; __asm ("mthi %0, $ac1\n\t" - "mtlo %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" "dpaq_sa.l.w $ac1, %3, %4\n\t" "mfhi %0, $ac1\n\t" "mflo %1, $ac1\n\t" @@ -51,16 +51,64 @@ int main() assert(acl == resultl); ach = 0x741532A0; - acl = 0xfceabb08; + acl = 0xFCEABB08; rs = 0x80000000; rt = 0x80000000; - resulth = 0x7fffffff; - resultl = 0xffffffff; + resulth = 0x7FFFFFFF; + resultl = 0xFFFFFFFF; resultdsp = 0x01; __asm ("mthi %0, $ac1\n\t" - "mtlo %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "dpaq_sa.l.w $ac1, %3, %4\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + "rddsp %2\n\t" + : "+r"(ach), "+r"(acl), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + dsp = (dsp >> 17) & 0x01; + assert(dsp == resultdsp); + assert(ach == resulth); + assert(acl == resultl); + + ach = 0; + acl = 0; + rs = 0xC0000000; + rt = 0x7FFFFFFF; + + resulth = 0xC0000000; + resultl = 0x80000000; + resultdsp = 0; + __asm + ("wrdsp $0\n\t" + "mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "dpaq_sa.l.w $ac1, %3, %4\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + "rddsp %2\n\t" + : "+r"(ach), "+r"(acl), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + dsp = (dsp >> 17) & 0x01; + assert(dsp == resultdsp); + assert(ach == resulth); + assert(acl == resultl); + + ach = 0x20000000; + acl = 0; + rs = 0xE0000000; + rt = 0x7FFFFFFF; + + resulth = 0; + resultl = 0x40000000; + resultdsp = 0; + __asm + ("wrdsp $0\n\t" + "mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" "dpaq_sa.l.w $ac1, %3, %4\n\t" "mfhi %0, $ac1\n\t" "mflo %1, $ac1\n\t" diff --git a/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c b/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c index 22ab4d57ba..74058fe7ec 100644 --- a/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c +++ b/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c @@ -9,8 +9,8 @@ int main() rs = 0xBC0123AD; rt = 0x01643721; - resulth = 0x04; - resultl = 0xEE9794A3; + resulth = 0x00000004; + resultl = 0xF15F94A3; __asm ("mthi %0, $ac1\n\t" "mtlo %1, $ac1\n\t" @@ -23,12 +23,12 @@ int main() assert(ach == resulth); assert(acl == resultl); - ach = 0x1424Ef1f; + ach = 0x1424EF1F; acl = 0x1035219A; rs = 0x800083AD; rt = 0x80003721; - resulth = 0x1424ef1e; - resultl = 0x577ed901; + resulth = 0x1424EF1E; + resultl = 0xC5C0D901; __asm ("mthi %0, $ac1\n\t" "mtlo %1, $ac1\n\t" diff --git a/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c b/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c index b7b73fdb66..eda3b14e2b 100644 --- a/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c +++ b/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c @@ -9,8 +9,8 @@ int main() rs = 0xBC0123AD; rt = 0x01643721; - resulth = 0xfdf4cbe0; - resultl = 0xd138776b; + resulth = 0x00BD3A22; + resultl = 0xD138776B; resultdsp = 0x00; __asm ("mthi %0, $ac1\n\t" diff --git a/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c b/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c index 292d68566d..0f7c070155 100644 --- a/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c +++ b/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c @@ -10,12 +10,12 @@ int main() int resulth, resultl; int resdsp; - achi = 0x05; - acli = 0xB4CB; + achi = 0x00000005; + acli = 0x0000B4CB; rs = 0xFF060000; rt = 0xCB000000; - resulth = 0x04; - resultl = 0x947438CB; + resulth = 0x00000005; + resultl = 0x006838CB; __asm ("mthi %2, $ac1\n\t" @@ -29,12 +29,12 @@ int main() assert(resulth == acho); assert(resultl == aclo); - achi = 0x06; - acli = 0xB4CB; + achi = 0x00000006; + acli = 0x0000B4CB; rs = 0x80000000; rt = 0x80000000; - resulth = 0x6; - resultl = 0x8000b4ca; + resulth = 0x00000006; + resultl = 0x8000B4CA; resdsp = 1; __asm diff --git a/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c b/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c index 7b2ef2ab71..942722a530 100644 --- a/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c +++ b/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c @@ -10,12 +10,12 @@ int main() int resulth, resultl; int resdsp; - achi = 0x05; - acli = 0xB4CB; - rs = 0xFF06; - rt = 0xCB00; - resulth = 0x04; - resultl = 0x947438CB; + achi = 0x00000005; + acli = 0x0000B4CB; + rs = 0x0000FF06; + rt = 0x0000CB00; + resulth = 0x00000005; + resultl = 0x006838CB; __asm ("mthi %2, $ac1\n\t" @@ -29,12 +29,12 @@ int main() assert(resulth == acho); assert(resultl == aclo); - achi = 0x06; - acli = 0xB4CB; - rs = 0x8000; - rt = 0x8000; - resulth = 0x6; - resultl = 0x8000b4ca; + achi = 0x00000006; + acli = 0x0000B4CB; + rs = 0x00008000; + rt = 0x00008000; + resulth = 0x00000006; + resultl = 0x8000B4CA; resdsp = 1; __asm diff --git a/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c b/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c index c7206039ea..370c2a8018 100644 --- a/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c +++ b/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c @@ -12,7 +12,24 @@ int main() resultdsp = 1; __asm - ("mulq_rs.ph %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "mulq_rs.ph %0, %2, %3\n\t" + "rddsp %1\n\t" + : "=r"(rd), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + dsp = (dsp >> 21) & 0x01; + assert(rd == result); + assert(dsp == resultdsp); + + rs = 0x80011234; + rt = 0x80024321; + result = 0x7FFD098C; + resultdsp = 0; + + __asm + ("wrdsp $0\n\t" + "mulq_rs.ph %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) diff --git a/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c b/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c index 3535b37a58..da6845bf24 100644 --- a/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c +++ b/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c @@ -12,18 +12,34 @@ int main() result = 0x12348765; __asm - ("precrq_rs.ph.w %0, %1, %2\n\t" + ("wrdsp $0\n\t" + "precrq_rs.ph.w %0, %1, %2\n\t" : "=r"(rd) : "r"(rs), "r"(rt) ); assert(result == rd); - rs = 0x7fffC678; + rs = 0x7FFFC678; rt = 0x865432A0; - result = 0x7fff8654; + result = 0x7FFF8654; __asm - ("precrq_rs.ph.w %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "precrq_rs.ph.w %0, %2, %3\n\t" + "rddsp %1\n\t" + : "=r"(rd), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + assert(((dsp >> 22) & 0x01) == 1); + assert(result == rd); + + rs = 0xBEEFFEED; + rt = 0x7FFF8000; + result = 0xBEF07FFF; + + __asm + ("wrdsp $0\n\t" + "precrq_rs.ph.w %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) diff --git a/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c index 798c4da5ca..d551d64ae2 100644 --- a/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c @@ -4,14 +4,17 @@ int main() { int rs, rt, dsp; - int ach = 5, acl = 5; + int ach, acl; int resulth, resultl, resultdsp; + ach = 0x00000005; + acl = 0x00000005; rs = 0x00FF00FF; rt = 0x00010002; resulth = 0x00; resultl = 0x7FFFFFFF; resultdsp = 0x01; + dsp = 0; __asm ("wrdsp %2\n\t" "mthi %0, $ac1\n\t" @@ -27,13 +30,14 @@ int main() assert(ach == resulth); assert(acl == resultl); - ach = 9; - acl = 0xb; + ach = 0x00000009; + acl = 0x0000000B; rs = 0x800000FF; rt = 0x00018000; resulth = 0x00; - resultl = 0x7fffffff; + resultl = 0x7FFFFFFF; resultdsp = 0x01; + dsp = 0; __asm ("wrdsp %2\n\t" "mthi %0, $ac1\n\t" diff --git a/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c index 14cdd7c0f5..e40543fd82 100644 --- a/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c @@ -9,8 +9,8 @@ int main() rs = 0xBC0123AD; rt = 0x01643721; - resulth = 0x04; - resultl = 0xAEA3E09B; + resulth = 0x00000005; + resultl = 0x1CE5E09B; resultdsp = 0x00; __asm ("mthi %0, $ac1\n\t" @@ -27,12 +27,12 @@ int main() assert(ach == resulth); assert(acl == resultl); - ach = 0x99f13005; + ach = 0x99F13005; acl = 0x51730062; rs = 0x80008000; rt = 0x80008000; - resulth = 0x99f13004; + resulth = 0x99F13004; resultl = 0x51730064; resultdsp = 0x01; __asm diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 002fd871d9..1b519cae45 100644 --- a/tests/tcg/xtensa/Makefile +++ b/tests/tcg/xtensa/Makefile @@ -1,9 +1,9 @@ --include ../../config-host.mak +-include ../../../config-host.mak CROSS=xtensa-dc232b-elf- ifndef XT -SIM = qemu-system-xtensa +SIM = ../../../xtensa-softmmu/qemu-system-xtensa SIMFLAGS = -M sim -cpu dc232b -nographic -semihosting $(EXTFLAGS) -kernel SIMDEBUG = -s -S else @@ -13,10 +13,12 @@ SIMDEBUG = --gdbserve=0 endif CC = $(CROSS)gcc -AS = $(CROSS)gcc -x assembler +AS = $(CROSS)gcc -x assembler-with-cpp LD = $(CROSS)ld -LDFLAGS = -Tlinker.ld +XTENSA_SRC_PATH = $(SRC_PATH)/tests/tcg/xtensa + +LDFLAGS = -T$(XTENSA_SRC_PATH)/linker.ld CRT = crt.o vectors.o @@ -26,6 +28,7 @@ TESTCASES += test_bi.tst TESTCASES += test_break.tst TESTCASES += test_bz.tst TESTCASES += test_clamps.tst +TESTCASES += test_extui.tst TESTCASES += test_fail.tst TESTCASES += test_interrupt.tst TESTCASES += test_loop.tst @@ -52,13 +55,13 @@ TESTCASES += test_windowed.tst all: build -%.o: $(SRC_PATH)/tests/xtensa/%.c - $(CC) $(CFLAGS) -c $< -o $@ +%.o: $(XTENSA_SRC_PATH)/%.c + $(CC) -I$(XTENSA_SRC_PATH) $(CFLAGS) -c $< -o $@ -%.o: $(SRC_PATH)/tests/xtensa/%.S - $(AS) $(ASFLAGS) -c $< -o $@ +%.o: $(XTENSA_SRC_PATH)/%.S + $(AS) -Wa,-I,$(XTENSA_SRC_PATH) $(ASFLAGS) -c $< -o $@ -%.tst: %.o macros.inc $(CRT) Makefile +%.tst: %.o $(XTENSA_SRC_PATH)/macros.inc $(CRT) Makefile $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@ build: $(TESTCASES) diff --git a/tests/tcg/xtensa/test_extui.S b/tests/tcg/xtensa/test_extui.S new file mode 100644 index 0000000000..5d55451704 --- /dev/null +++ b/tests/tcg/xtensa/test_extui.S @@ -0,0 +1,26 @@ +.include "macros.inc" + +test_suite extui + +.macro test_extui v, shiftimm, maskimm + .if \shiftimm + \maskimm <= 32 + movi a2, \v + extui a3, a2, \shiftimm, \maskimm + movi a4, ((\v) >> (\shiftimm)) & ((1 << (\maskimm)) - 1) + assert eq, a3, a4 + .endif +.endm + +test extui + .set shiftimm, 0 + .rept 32 + .set maskimm, 1 + .rept 16 + test_extui 0xc8df1370, shiftimm, maskimm + .set maskimm, maskimm + 1 + .endr + .set shiftimm, shiftimm + 1 + .endr +test_end + +test_suite_end diff --git a/tests/test-aio.c b/tests/test-aio.c index c1738706cd..07a1f61f87 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -12,9 +12,17 @@ #include <glib.h> #include "block/aio.h" +#include "qemu/timer.h" AioContext *ctx; +typedef struct { + EventNotifier e; + int n; + int active; + bool auto_set; +} EventNotifierTestData; + /* Wait until there are no more BHs or AIO requests */ static void wait_for_aio(void) { @@ -23,6 +31,14 @@ static void wait_for_aio(void) } } +/* Wait until event notifier becomes inactive */ +static void wait_until_inactive(EventNotifierTestData *data) +{ + while (data->active > 0) { + aio_poll(ctx, true); + } +} + /* Simple callbacks for testing. */ typedef struct { @@ -31,6 +47,15 @@ typedef struct { int max; } BHTestData; +typedef struct { + QEMUTimer timer; + QEMUClockType clock_type; + int n; + int max; + int64_t ns; + AioContext *ctx; +} TimerTestData; + static void bh_test_cb(void *opaque) { BHTestData *data = opaque; @@ -39,6 +64,19 @@ static void bh_test_cb(void *opaque) } } +static void timer_test_cb(void *opaque) +{ + TimerTestData *data = opaque; + if (++data->n < data->max) { + timer_mod(&data->timer, + qemu_clock_get_ns(data->clock_type) + data->ns); + } +} + +static void dummy_io_handler_read(void *opaque) +{ +} + static void bh_delete_cb(void *opaque) { BHTestData *data = opaque; @@ -50,19 +88,6 @@ static void bh_delete_cb(void *opaque) } } -typedef struct { - EventNotifier e; - int n; - int active; - bool auto_set; -} EventNotifierTestData; - -static int event_active_cb(EventNotifier *e) -{ - EventNotifierTestData *data = container_of(e, EventNotifierTestData, e); - return data->active > 0; -} - static void event_ready_cb(EventNotifier *e) { EventNotifierTestData *data = container_of(e, EventNotifierTestData, e); @@ -231,11 +256,11 @@ static void test_set_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 0 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, event_active_cb); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); event_notifier_cleanup(&data.e); @@ -245,8 +270,8 @@ static void test_wait_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, event_active_cb); - g_assert(aio_poll(ctx, false)); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); + g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 1); @@ -259,7 +284,7 @@ static void test_wait_event_notifier(void) g_assert_cmpint(data.n, ==, 1); g_assert_cmpint(data.active, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 1); @@ -270,8 +295,8 @@ static void test_flush_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, event_active_cb); - g_assert(aio_poll(ctx, false)); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); + g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 10); @@ -281,12 +306,12 @@ static void test_flush_event_notifier(void) g_assert_cmpint(data.active, ==, 9); g_assert(aio_poll(ctx, false)); - wait_for_aio(); + wait_until_inactive(&data); g_assert_cmpint(data.n, ==, 10); g_assert_cmpint(data.active, ==, 0); g_assert(!aio_poll(ctx, false)); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); event_notifier_cleanup(&data.e); } @@ -297,7 +322,7 @@ static void test_wait_event_notifier_noflush(void) EventNotifierTestData dummy = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, NULL); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); @@ -305,41 +330,99 @@ static void test_wait_event_notifier_noflush(void) /* Until there is an active descriptor, aio_poll may or may not call * event_ready_cb. Still, it must not block. */ event_notifier_set(&data.e); - g_assert(!aio_poll(ctx, true)); + g_assert(aio_poll(ctx, true)); data.n = 0; /* An active event notifier forces aio_poll to look at EventNotifiers. */ event_notifier_init(&dummy.e, false); - aio_set_event_notifier(ctx, &dummy.e, event_ready_cb, event_active_cb); + aio_set_event_notifier(ctx, &dummy.e, event_ready_cb); event_notifier_set(&data.e); g_assert(aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 1); - g_assert(aio_poll(ctx, false)); + g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 1); event_notifier_set(&data.e); g_assert(aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); - g_assert(aio_poll(ctx, false)); + g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); event_notifier_set(&dummy.e); - wait_for_aio(); + wait_until_inactive(&dummy); g_assert_cmpint(data.n, ==, 2); g_assert_cmpint(dummy.n, ==, 1); g_assert_cmpint(dummy.active, ==, 0); - aio_set_event_notifier(ctx, &dummy.e, NULL, NULL); + aio_set_event_notifier(ctx, &dummy.e, NULL); event_notifier_cleanup(&dummy.e); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); event_notifier_cleanup(&data.e); } +static void test_timer_schedule(void) +{ + TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL, + .max = 2, + .clock_type = QEMU_CLOCK_VIRTUAL }; + int pipefd[2]; + + /* aio_poll will not block to wait for timers to complete unless it has + * an fd to wait on. Fixing this breaks other tests. So create a dummy one. + */ + g_assert(!pipe2(pipefd, O_NONBLOCK)); + aio_set_fd_handler(ctx, pipefd[0], + dummy_io_handler_read, NULL, NULL); + aio_poll(ctx, false); + + aio_timer_init(ctx, &data.timer, data.clock_type, + SCALE_NS, timer_test_cb, &data); + timer_mod(&data.timer, + qemu_clock_get_ns(data.clock_type) + + data.ns); + + g_assert_cmpint(data.n, ==, 0); + + /* timer_mod may well cause an event notifer to have gone off, + * so clear that + */ + do {} while (aio_poll(ctx, false)); + + g_assert(!aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 0); + + sleep(1); + g_assert_cmpint(data.n, ==, 0); + + g_assert(aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 1); + + /* timer_mod called by our callback */ + do {} while (aio_poll(ctx, false)); + + g_assert(!aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 1); + + g_assert(aio_poll(ctx, true)); + g_assert_cmpint(data.n, ==, 2); + + /* As max is now 2, an event notifier should not have gone off */ + + g_assert(!aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 2); + + aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL); + close(pipefd[0]); + close(pipefd[1]); + + timer_del(&data.timer); +} + /* Now the same tests, using the context as a GSource. They are * very similar to the ones above, with g_main_context_iteration * replacing aio_poll. However: @@ -513,11 +596,11 @@ static void test_source_set_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 0 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, event_active_cb); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); event_notifier_cleanup(&data.e); @@ -527,7 +610,7 @@ static void test_source_wait_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, event_active_cb); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); g_assert(g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 1); @@ -541,7 +624,7 @@ static void test_source_wait_event_notifier(void) g_assert_cmpint(data.n, ==, 1); g_assert_cmpint(data.active, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 1); @@ -552,7 +635,7 @@ static void test_source_flush_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, event_active_cb); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); g_assert(g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 10); @@ -568,7 +651,7 @@ static void test_source_flush_event_notifier(void) g_assert_cmpint(data.active, ==, 0); g_assert(!g_main_context_iteration(NULL, false)); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); event_notifier_cleanup(&data.e); } @@ -579,7 +662,7 @@ static void test_source_wait_event_notifier_noflush(void) EventNotifierTestData dummy = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb, NULL); + aio_set_event_notifier(ctx, &data.e, event_ready_cb); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); @@ -592,7 +675,7 @@ static void test_source_wait_event_notifier_noflush(void) /* An active event notifier forces aio_poll to look at EventNotifiers. */ event_notifier_init(&dummy.e, false); - aio_set_event_notifier(ctx, &dummy.e, event_ready_cb, event_active_cb); + aio_set_event_notifier(ctx, &dummy.e, event_ready_cb); event_notifier_set(&data.e); g_assert(g_main_context_iteration(NULL, false)); @@ -612,22 +695,71 @@ static void test_source_wait_event_notifier_noflush(void) g_assert_cmpint(dummy.n, ==, 1); g_assert_cmpint(dummy.active, ==, 0); - aio_set_event_notifier(ctx, &dummy.e, NULL, NULL); + aio_set_event_notifier(ctx, &dummy.e, NULL); event_notifier_cleanup(&dummy.e); - aio_set_event_notifier(ctx, &data.e, NULL, NULL); + aio_set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 2); event_notifier_cleanup(&data.e); } +static void test_source_timer_schedule(void) +{ + TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL, + .max = 2, + .clock_type = QEMU_CLOCK_VIRTUAL }; + int pipefd[2]; + int64_t expiry; + + /* aio_poll will not block to wait for timers to complete unless it has + * an fd to wait on. Fixing this breaks other tests. So create a dummy one. + */ + g_assert(!pipe2(pipefd, O_NONBLOCK)); + aio_set_fd_handler(ctx, pipefd[0], + dummy_io_handler_read, NULL, NULL); + do {} while (g_main_context_iteration(NULL, false)); + + aio_timer_init(ctx, &data.timer, data.clock_type, + SCALE_NS, timer_test_cb, &data); + expiry = qemu_clock_get_ns(data.clock_type) + + data.ns; + timer_mod(&data.timer, expiry); + + g_assert_cmpint(data.n, ==, 0); + + sleep(1); + g_assert_cmpint(data.n, ==, 0); + + g_assert(g_main_context_iteration(NULL, false)); + g_assert_cmpint(data.n, ==, 1); + + /* The comment above was not kidding when it said this wakes up itself */ + do { + g_assert(g_main_context_iteration(NULL, true)); + } while (qemu_clock_get_ns(data.clock_type) <= expiry); + sleep(1); + g_main_context_iteration(NULL, false); + + g_assert_cmpint(data.n, ==, 2); + + aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL); + close(pipefd[0]); + close(pipefd[1]); + + timer_del(&data.timer); +} + + /* End of tests. */ int main(int argc, char **argv) { GSource *src; + init_clocks(); + ctx = aio_context_new(); src = aio_get_g_source(ctx); g_source_attach(src, NULL); @@ -648,6 +780,7 @@ int main(int argc, char **argv) g_test_add_func("/aio/event/wait", test_wait_event_notifier); g_test_add_func("/aio/event/wait/no-flush-cb", test_wait_event_notifier_noflush); g_test_add_func("/aio/event/flush", test_flush_event_notifier); + g_test_add_func("/aio/timer/schedule", test_timer_schedule); g_test_add_func("/aio-gsource/notify", test_source_notify); g_test_add_func("/aio-gsource/flush", test_source_flush); @@ -662,5 +795,6 @@ int main(int argc, char **argv) g_test_add_func("/aio-gsource/event/wait", test_source_wait_event_notifier); g_test_add_func("/aio-gsource/event/wait/no-flush-cb", test_source_wait_event_notifier_noflush); g_test_add_func("/aio-gsource/event/flush", test_source_flush_event_notifier); + g_test_add_func("/aio-gsource/timer/schedule", test_source_timer_schedule); return g_test_run(); } diff --git a/tests/test-opts-visitor.c b/tests/test-opts-visitor.c new file mode 100644 index 0000000000..9f902b597e --- /dev/null +++ b/tests/test-opts-visitor.c @@ -0,0 +1,275 @@ +/* + * Options Visitor unit-tests. + * + * Copyright (C) 2013 Red Hat, Inc. + * + * Authors: + * Laszlo Ersek <lersek@redhat.com> (based on test-string-output-visitor) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> + +#include "qemu/config-file.h" /* qemu_add_opts() */ +#include "qemu/option.h" /* qemu_opts_parse() */ +#include "qapi/opts-visitor.h" /* opts_visitor_new() */ +#include "test-qapi-visit.h" /* visit_type_UserDefOptions() */ +#include "qapi/dealloc-visitor.h" /* qapi_dealloc_visitor_new() */ + +static QemuOptsList userdef_opts = { + .name = "userdef", + .head = QTAILQ_HEAD_INITIALIZER(userdef_opts.head), + .desc = { { 0 } } /* validated with OptsVisitor */ +}; + +/* fixture (= glib test case context) and test case manipulation */ + +typedef struct OptsVisitorFixture { + UserDefOptions *userdef; + Error *err; +} OptsVisitorFixture; + + +static void +setup_fixture(OptsVisitorFixture *f, gconstpointer test_data) +{ + const char *opts_string = test_data; + QemuOpts *opts; + OptsVisitor *ov; + + opts = qemu_opts_parse(qemu_find_opts("userdef"), opts_string, 0); + g_assert(opts != NULL); + + ov = opts_visitor_new(opts); + visit_type_UserDefOptions(opts_get_visitor(ov), &f->userdef, NULL, + &f->err); + opts_visitor_cleanup(ov); + qemu_opts_del(opts); +} + + +static void +teardown_fixture(OptsVisitorFixture *f, gconstpointer test_data) +{ + if (f->userdef != NULL) { + QapiDeallocVisitor *dv; + + dv = qapi_dealloc_visitor_new(); + visit_type_UserDefOptions(qapi_dealloc_get_visitor(dv), &f->userdef, + NULL, NULL); + qapi_dealloc_visitor_cleanup(dv); + } + error_free(f->err); +} + + +static void +add_test(const char *testpath, + void (*test_func)(OptsVisitorFixture *f, gconstpointer test_data), + gconstpointer test_data) +{ + g_test_add(testpath, OptsVisitorFixture, test_data, setup_fixture, + test_func, teardown_fixture); +} + +/* test output evaluation */ + +static void +expect_ok(OptsVisitorFixture *f, gconstpointer test_data) +{ + g_assert(f->err == NULL); + g_assert(f->userdef != NULL); +} + + +static void +expect_fail(OptsVisitorFixture *f, gconstpointer test_data) +{ + g_assert(f->err != NULL); + + /* The error message is printed when this test utility is invoked directly + * (ie. without gtester) and the --verbose flag is passed: + * + * tests/test-opts-visitor --verbose + */ + g_test_message("'%s': %s", (const char *)test_data, + error_get_pretty(f->err)); +} + + +static void +test_value(OptsVisitorFixture *f, gconstpointer test_data) +{ + uint64_t magic, bitval; + intList *i64; + uint64List *u64; + uint16List *u16; + + expect_ok(f, test_data); + + magic = 0; + for (i64 = f->userdef->i64; i64 != NULL; i64 = i64->next) { + g_assert(-16 <= i64->value && i64->value < 64-16); + bitval = 1ull << (i64->value + 16); + g_assert((magic & bitval) == 0); + magic |= bitval; + } + g_assert(magic == 0xDEADBEEF); + + magic = 0; + for (u64 = f->userdef->u64; u64 != NULL; u64 = u64->next) { + g_assert(u64->value < 64); + bitval = 1ull << u64->value; + g_assert((magic & bitval) == 0); + magic |= bitval; + } + g_assert(magic == 0xBADC0FFEE0DDF00D); + + magic = 0; + for (u16 = f->userdef->u16; u16 != NULL; u16 = u16->next) { + g_assert(u16->value < 64); + bitval = 1ull << u16->value; + g_assert((magic & bitval) == 0); + magic |= bitval; + } + g_assert(magic == 0xD15EA5E); +} + + +static void +expect_i64_min(OptsVisitorFixture *f, gconstpointer test_data) +{ + expect_ok(f, test_data); + g_assert(f->userdef->has_i64); + g_assert(f->userdef->i64->next == NULL); + g_assert(f->userdef->i64->value == INT64_MIN); +} + + +static void +expect_i64_max(OptsVisitorFixture *f, gconstpointer test_data) +{ + expect_ok(f, test_data); + g_assert(f->userdef->has_i64); + g_assert(f->userdef->i64->next == NULL); + g_assert(f->userdef->i64->value == INT64_MAX); +} + + +static void +expect_zero(OptsVisitorFixture *f, gconstpointer test_data) +{ + expect_ok(f, test_data); + g_assert(f->userdef->has_u64); + g_assert(f->userdef->u64->next == NULL); + g_assert(f->userdef->u64->value == 0); +} + + +static void +expect_u64_max(OptsVisitorFixture *f, gconstpointer test_data) +{ + expect_ok(f, test_data); + g_assert(f->userdef->has_u64); + g_assert(f->userdef->u64->next == NULL); + g_assert(f->userdef->u64->value == UINT64_MAX); +} + +/* test cases */ + +int +main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qemu_add_opts(&userdef_opts); + + /* Three hexadecimal magic numbers, "dead beef", "bad coffee, odd food" and + * "disease", from + * <http://en.wikipedia.org/wiki/Magic_number_%28programming%29>, were + * converted to binary and dissected into bit ranges. Each magic number is + * going to be recomposed using the lists called "i64", "u64" and "u16", + * respectively. + * + * (Note that these types pertain to the individual bit shift counts, not + * the magic numbers themselves; the intent is to exercise opts_type_int() + * and opts_type_uint64().) + * + * The "i64" shift counts have been decreased by 16 (decimal) in order to + * test negative values as well. Finally, the full list of QemuOpt elements + * has been permuted with "shuf". + * + * Both "i64" and "u64" have some (distinct) single-element ranges + * represented as both "a" and "a-a". "u16" is a special case of "i64" (see + * visit_type_uint16()), so it wouldn't add a separate test in this regard. + */ + + add_test("/visitor/opts/flatten/value", &test_value, + "i64=-1-0,u64=12-16,u64=2-3,i64=-11--9,u64=57,u16=9,i64=5-5," + "u16=1-4,u16=20,u64=63-63,i64=-16--13,u64=50-52,i64=14-15,u16=11," + "i64=7,u16=18,i64=2-3,u16=6,u64=54-55,u64=0,u64=18-20,u64=33-43," + "i64=9-12,u16=26-27,u64=59-61,u16=13-16,u64=29-31,u64=22-23," + "u16=24,i64=-7--3"); + + add_test("/visitor/opts/i64/val1/errno", &expect_fail, + "i64=0x8000000000000000"); + add_test("/visitor/opts/i64/val1/empty", &expect_fail, "i64="); + add_test("/visitor/opts/i64/val1/trailing", &expect_fail, "i64=5z"); + add_test("/visitor/opts/i64/nonlist", &expect_fail, "i64x=5-6"); + add_test("/visitor/opts/i64/val2/errno", &expect_fail, + "i64=0x7fffffffffffffff-0x8000000000000000"); + add_test("/visitor/opts/i64/val2/empty", &expect_fail, "i64=5-"); + add_test("/visitor/opts/i64/val2/trailing", &expect_fail, "i64=5-6z"); + add_test("/visitor/opts/i64/range/empty", &expect_fail, "i64=6-5"); + add_test("/visitor/opts/i64/range/minval", &expect_i64_min, + "i64=-0x8000000000000000--0x8000000000000000"); + add_test("/visitor/opts/i64/range/maxval", &expect_i64_max, + "i64=0x7fffffffffffffff-0x7fffffffffffffff"); + + add_test("/visitor/opts/u64/val1/errno", &expect_fail, "u64=-1"); + add_test("/visitor/opts/u64/val1/empty", &expect_fail, "u64="); + add_test("/visitor/opts/u64/val1/trailing", &expect_fail, "u64=5z"); + add_test("/visitor/opts/u64/nonlist", &expect_fail, "u64x=5-6"); + add_test("/visitor/opts/u64/val2/errno", &expect_fail, + "u64=0xffffffffffffffff-0x10000000000000000"); + add_test("/visitor/opts/u64/val2/empty", &expect_fail, "u64=5-"); + add_test("/visitor/opts/u64/val2/trailing", &expect_fail, "u64=5-6z"); + add_test("/visitor/opts/u64/range/empty", &expect_fail, "u64=6-5"); + add_test("/visitor/opts/u64/range/minval", &expect_zero, "u64=0-0"); + add_test("/visitor/opts/u64/range/maxval", &expect_u64_max, + "u64=0xffffffffffffffff-0xffffffffffffffff"); + + /* Test maximum range sizes. The macro value is open-coded here + * *intentionally*; the test case must use concrete values by design. If + * OPTS_VISITOR_RANGE_MAX is changed, the following values need to be + * recalculated as well. The assert and this comment should help with it. + */ + g_assert(OPTS_VISITOR_RANGE_MAX == 65536); + + /* The unsigned case is simple, a u64-u64 difference can always be + * represented as a u64. + */ + add_test("/visitor/opts/u64/range/max", &expect_ok, "u64=0-65535"); + add_test("/visitor/opts/u64/range/2big", &expect_fail, "u64=0-65536"); + + /* The same cannot be said about an i64-i64 difference. */ + add_test("/visitor/opts/i64/range/max/pos/a", &expect_ok, + "i64=0x7fffffffffff0000-0x7fffffffffffffff"); + add_test("/visitor/opts/i64/range/max/pos/b", &expect_ok, + "i64=0x7ffffffffffeffff-0x7ffffffffffffffe"); + add_test("/visitor/opts/i64/range/2big/pos", &expect_fail, + "i64=0x7ffffffffffeffff-0x7fffffffffffffff"); + add_test("/visitor/opts/i64/range/max/neg/a", &expect_ok, + "i64=-0x8000000000000000--0x7fffffffffff0001"); + add_test("/visitor/opts/i64/range/max/neg/b", &expect_ok, + "i64=-0x7fffffffffffffff--0x7fffffffffff0000"); + add_test("/visitor/opts/i64/range/2big/neg", &expect_fail, + "i64=-0x8000000000000000--0x7fffffffffff0000"); + add_test("/visitor/opts/i64/range/2big/full", &expect_fail, + "i64=-0x8000000000000000-0x7fffffffffffffff"); + + g_test_run(); + return 0; +} diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c new file mode 100644 index 0000000000..e4ad173d72 --- /dev/null +++ b/tests/test-qdev-global-props.c @@ -0,0 +1,180 @@ +/* + * Test code for qdev global-properties handling + * + * Copyright (c) 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <glib.h> +#include <stdint.h> + +#include "hw/qdev.h" +#include "qom/object.h" +#include "qapi/visitor.h" + + +#define TYPE_STATIC_PROPS "static_prop_type" +#define STATIC_TYPE(obj) \ + OBJECT_CHECK(MyType, (obj), TYPE_STATIC_PROPS) + +#define PROP_DEFAULT 100 + +typedef struct MyType { + DeviceState parent_obj; + + uint32_t prop1; + uint32_t prop2; +} MyType; + +static Property static_props[] = { + DEFINE_PROP_UINT32("prop1", MyType, prop1, PROP_DEFAULT), + DEFINE_PROP_UINT32("prop2", MyType, prop2, PROP_DEFAULT), + DEFINE_PROP_END_OF_LIST() +}; + +static void static_prop_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = NULL; + dc->props = static_props; +} + +static const TypeInfo static_prop_type = { + .name = TYPE_STATIC_PROPS, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyType), + .class_init = static_prop_class_init, +}; + +/* Test simple static property setting to default value */ +static void test_static_prop(void) +{ + MyType *mt; + + mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS)); + qdev_init_nofail(DEVICE(mt)); + + g_assert_cmpuint(mt->prop1, ==, PROP_DEFAULT); +} + +/* Test setting of static property using global properties */ +static void test_static_globalprop(void) +{ + MyType *mt; + static GlobalProperty props[] = { + { TYPE_STATIC_PROPS, "prop1", "200" }, + {} + }; + + qdev_prop_register_global_list(props); + + mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS)); + qdev_init_nofail(DEVICE(mt)); + + g_assert_cmpuint(mt->prop1, ==, 200); + g_assert_cmpuint(mt->prop2, ==, PROP_DEFAULT); +} + +#define TYPE_DYNAMIC_PROPS "dynamic-prop-type" +#define DYNAMIC_TYPE(obj) \ + OBJECT_CHECK(MyType, (obj), TYPE_DYNAMIC_PROPS) + +static void prop1_accessor(Object *obj, + Visitor *v, + void *opaque, + const char *name, + Error **errp) +{ + MyType *mt = DYNAMIC_TYPE(obj); + + visit_type_uint32(v, &mt->prop1, name, errp); +} + +static void prop2_accessor(Object *obj, + Visitor *v, + void *opaque, + const char *name, + Error **errp) +{ + MyType *mt = DYNAMIC_TYPE(obj); + + visit_type_uint32(v, &mt->prop2, name, errp); +} + +static void dynamic_instance_init(Object *obj) +{ + object_property_add(obj, "prop1", "uint32", prop1_accessor, prop1_accessor, + NULL, NULL, NULL); + object_property_add(obj, "prop2", "uint32", prop2_accessor, prop2_accessor, + NULL, NULL, NULL); +} + +static void dynamic_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = NULL; +} + + +static const TypeInfo dynamic_prop_type = { + .name = TYPE_DYNAMIC_PROPS, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyType), + .instance_init = dynamic_instance_init, + .class_init = dynamic_class_init, +}; + +/* Test setting of static property using global properties */ +static void test_dynamic_globalprop(void) +{ + MyType *mt; + static GlobalProperty props[] = { + { TYPE_DYNAMIC_PROPS, "prop1", "101" }, + { TYPE_DYNAMIC_PROPS, "prop2", "102" }, + {} + }; + + qdev_prop_register_global_list(props); + + mt = DYNAMIC_TYPE(object_new(TYPE_DYNAMIC_PROPS)); + qdev_init_nofail(DEVICE(mt)); + + g_assert_cmpuint(mt->prop1, ==, 101); + g_assert_cmpuint(mt->prop2, ==, 102); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + type_register_static(&static_prop_type); + type_register_static(&dynamic_prop_type); + + g_test_add_func("/qdev/properties/static/default", test_static_prop); + g_test_add_func("/qdev/properties/static/global", test_static_globalprop); + g_test_add_func("/qdev/properties/dynamic/global", test_dynamic_globalprop); + + g_test_run(); + + return 0; +} diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index 2741eef3fa..0beb8fbfd2 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -394,7 +394,7 @@ static void test_native_list_integer_helper(TestInputVisitorData *data, break; } default: - g_assert(false); + g_assert_not_reached(); } g_string_free(gstr_union, true); diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index b2fa9a74f6..e073d833bf 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -559,7 +559,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } default: - g_assert(false); + g_assert_not_reached(); } } @@ -645,7 +645,7 @@ static void check_native_list(QObject *qobj, } break; default: - g_assert(false); + g_assert_not_reached(); } QDECREF(qlist); } diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c index b62338f375..c1f8e13a9f 100644 --- a/tests/test-thread-pool.c +++ b/tests/test-thread-pool.c @@ -3,6 +3,7 @@ #include "block/aio.h" #include "block/thread-pool.h" #include "block/block.h" +#include "qemu/timer.h" static AioContext *ctx; static ThreadPool *pool; @@ -40,19 +41,13 @@ static void done_cb(void *opaque, int ret) active--; } -/* Wait until all aio and bh activity has finished */ -static void qemu_aio_wait_all(void) -{ - while (aio_poll(ctx, true)) { - /* Do nothing */ - } -} - static void test_submit(void) { WorkerTestData data = { .n = 0 }; thread_pool_submit(pool, worker_cb, &data); - qemu_aio_wait_all(); + while (data.n == 0) { + aio_poll(ctx, true); + } g_assert_cmpint(data.n, ==, 1); } @@ -65,7 +60,9 @@ static void test_submit_aio(void) /* The callbacks are not called until after the first wait. */ active = 1; g_assert_cmpint(data.ret, ==, -EINPROGRESS); - qemu_aio_wait_all(); + while (data.ret == -EINPROGRESS) { + aio_poll(ctx, true); + } g_assert_cmpint(active, ==, 0); g_assert_cmpint(data.n, ==, 1); g_assert_cmpint(data.ret, ==, 0); @@ -103,7 +100,9 @@ static void test_submit_co(void) /* qemu_aio_wait_all will execute the rest of the coroutine. */ - qemu_aio_wait_all(); + while (data.ret == -EINPROGRESS) { + aio_poll(ctx, true); + } /* Back here after the coroutine has finished. */ @@ -187,7 +186,9 @@ static void test_cancel(void) } /* Finish execution and execute any remaining callbacks. */ - qemu_aio_wait_all(); + while (active > 0) { + aio_poll(ctx, true); + } g_assert_cmpint(active, ==, 0); for (i = 0; i < 100; i++) { if (data[i].n == 3) { @@ -205,6 +206,8 @@ int main(int argc, char **argv) { int ret; + init_clocks(); + ctx = aio_context_new(); pool = aio_get_thread_pool(ctx); diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index ee7916b806..9aaa5872e5 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -136,7 +136,7 @@ static void visit_primitive_type(Visitor *v, void **native, Error **errp) visit_type_int64(v, &pt->value.s64, NULL, errp); break; case PTYPE_EOL: - g_assert(false); + g_assert_not_reached(); } } @@ -181,7 +181,7 @@ static void visit_primitive_list(Visitor *v, void **native, Error **errp) visit_type_uint64List(v, &pl->value.u64_integers, NULL, errp); break; default: - g_assert(false); + g_assert_not_reached(); } } @@ -500,7 +500,7 @@ static void test_primitive_lists(gconstpointer opaque) break; } default: - g_assert(0); + g_assert_not_reached(); } } @@ -656,7 +656,7 @@ static void test_primitive_lists(gconstpointer opaque) break; } default: - g_assert(0); + g_assert_not_reached(); } i++; } while (cur_head); diff --git a/thread-pool.c b/thread-pool.c index 0ebd4c2964..3735fd34bc 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -23,6 +23,7 @@ #include "block/block_int.h" #include "qemu/event_notifier.h" #include "block/thread-pool.h" +#include "qemu/main-loop.h" static void do_spawn_thread(ThreadPool *pool); @@ -197,12 +198,6 @@ restart: } } -static int thread_pool_active(EventNotifier *notifier) -{ - ThreadPool *pool = container_of(notifier, ThreadPool, notifier); - return !QLIST_EMPTY(&pool->head); -} - static void thread_pool_cancel(BlockDriverAIOCB *acb) { ThreadPoolElement *elem = (ThreadPoolElement *)acb; @@ -309,8 +304,7 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) QLIST_INIT(&pool->head); QTAILQ_INIT(&pool->request_list); - aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready, - thread_pool_active); + aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready); } ThreadPool *thread_pool_new(AioContext *ctx) @@ -344,7 +338,7 @@ void thread_pool_free(ThreadPool *pool) qemu_mutex_unlock(&pool->lock); - aio_set_event_notifier(pool->ctx, &pool->notifier, NULL, NULL); + aio_set_event_notifier(pool->ctx, &pool->notifier, NULL); qemu_sem_destroy(&pool->sem); qemu_cond_destroy(&pool->check_cancel); qemu_cond_destroy(&pool->worker_stopped); @@ -32,7 +32,7 @@ static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { }; static enum TpmModel tpm_models[TPM_MAX_MODELS] = { - -1, + TPM_MODEL_MAX, }; int tpm_register_model(enum TpmModel model) @@ -40,7 +40,7 @@ int tpm_register_model(enum TpmModel model) int i; for (i = 0; i < TPM_MAX_MODELS; i++) { - if (tpm_models[i] == -1) { + if (tpm_models[i] == TPM_MODEL_MAX) { tpm_models[i] = model; return 0; } diff --git a/trace-events b/trace-events index 002df83b9d..3856b5c206 100644 --- a/trace-events +++ b/trace-events @@ -1165,6 +1165,14 @@ kvm_vm_ioctl(int type, void *arg) "type %d, arg %p" kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type %d, arg %p" kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d" +# memory.c +memory_region_ops_read(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" +memory_region_ops_write(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" + # qom/object.c object_dynamic_cast_assert(const char *type, const char *target, const char *file, int line, const char *func) "%s->%s (%s:%d:%s)" object_class_dynamic_cast_assert(const char *type, const char *target, const char *file, int line, const char *func) "%s->%s (%s:%d:%s)" + +# hw/xen/xen_pvdevice.c +xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")" +xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")" diff --git a/translate-all.c b/translate-all.c index e8683d2c66..3b5fc7c901 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1148,7 +1148,8 @@ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len) #if !defined(CONFIG_SOFTMMU) static void tb_invalidate_phys_page(tb_page_addr_t addr, - uintptr_t pc, void *puc) + uintptr_t pc, void *puc, + bool locked) { TranslationBlock *tb; PageDesc *p; @@ -1206,6 +1207,9 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, itself */ cpu->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + if (locked) { + mmap_unlock(); + } cpu_resume_from_signal(env, puc); } #endif @@ -1723,7 +1727,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) if (!(p->flags & PAGE_WRITE) && (flags & PAGE_WRITE) && p->first_tb) { - tb_invalidate_phys_page(addr, 0, NULL); + tb_invalidate_phys_page(addr, 0, NULL, false); } p->flags = flags; } @@ -1818,7 +1822,7 @@ int page_unprotect(target_ulong address, uintptr_t pc, void *puc) /* and since the content will be modified, we must invalidate the corresponding translated code. */ - tb_invalidate_phys_page(addr, pc, puc); + tb_invalidate_phys_page(addr, pc, puc, true); #ifdef DEBUG_TB_CHECK tb_invalidate_check(addr); #endif diff --git a/ui/console.c b/ui/console.c index e3e82979d8..aad4fc9a57 100644 --- a/ui/console.c +++ b/ui/console.c @@ -208,8 +208,8 @@ static void gui_update(void *opaque) } trace_console_refresh(interval); } - ds->last_update = qemu_get_clock_ms(rt_clock); - qemu_mod_timer(ds->gui_timer, ds->last_update + interval); + ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + timer_mod(ds->gui_timer, ds->last_update + interval); } static void gui_setup_refresh(DisplayState *ds) @@ -232,12 +232,12 @@ static void gui_setup_refresh(DisplayState *ds) } if (need_timer && ds->gui_timer == NULL) { - ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds); - qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock)); + ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds); + timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); } if (!need_timer && ds->gui_timer != NULL) { - qemu_del_timer(ds->gui_timer); - qemu_free_timer(ds->gui_timer); + timer_del(ds->gui_timer); + timer_free(ds->gui_timer); ds->gui_timer = NULL; } @@ -1040,7 +1040,7 @@ void console_select(unsigned int index) DisplayState *ds = s->ds; if (active_console && active_console->cursor_timer) { - qemu_del_timer(active_console->cursor_timer); + timer_del(active_console->cursor_timer); } active_console = s; if (ds->have_gfx) { @@ -1059,8 +1059,8 @@ void console_select(unsigned int index) dpy_text_resize(s, s->width, s->height); } if (s->cursor_timer) { - qemu_mod_timer(s->cursor_timer, - qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2); + timer_mod(s->cursor_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2); } } } @@ -1105,7 +1105,7 @@ static void kbd_send_chars(void *opaque) /* characters are pending: we send them a bit later (XXX: horrible, should change char device API) */ if (s->out_fifo.count > 0) { - qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1); + timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1); } } @@ -1366,7 +1366,7 @@ void update_displaychangelistener(DisplayChangeListener *dcl, dcl->update_interval = interval; if (!ds->refreshing && ds->update_interval > interval) { - qemu_mod_timer(ds->gui_timer, ds->last_update + interval); + timer_mod(ds->gui_timer, ds->last_update + interval); } } @@ -1691,8 +1691,8 @@ static void text_console_update_cursor(void *opaque) s->cursor_visible_phase = !s->cursor_visible_phase; graphic_hw_invalidate(s); - qemu_mod_timer(s->cursor_timer, - qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2); + timer_mod(s->cursor_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2); } static const GraphicHwOps text_console_ops = { @@ -1712,7 +1712,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) s->out_fifo.buf = s->out_fifo_buf; s->out_fifo.buf_size = sizeof(s->out_fifo_buf); - s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s); + s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s); s->ds = ds; s->y_displayed = 0; @@ -1729,7 +1729,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) } s->cursor_timer = - qemu_new_timer_ms(rt_clock, text_console_update_cursor, s); + timer_new_ms(QEMU_CLOCK_REALTIME, text_console_update_cursor, s); s->hw_ops = &text_console_ops; s->hw = s; @@ -51,10 +51,6 @@ #include <glib/gi18n.h> #include <locale.h> #include <vte/vte.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/wait.h> #include <math.h> #include "ui/console.h" diff --git a/ui/input.c b/ui/input.c index 92c44ca810..10d8c056f1 100644 --- a/ui/input.c +++ b/ui/input.c @@ -277,11 +277,11 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, KeyValueList *p; if (!key_timer) { - key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); + key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL); } if (keycodes != NULL) { - qemu_del_timer(key_timer); + timer_del(key_timer); release_keys(NULL); } @@ -308,7 +308,7 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, } /* delayed key up events */ - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + + timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(get_ticks_per_sec(), hold_time, 1000)); } diff --git a/ui/spice-core.c b/ui/spice-core.c index f308fd9d5e..3a2cd7e0c6 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -48,6 +48,7 @@ static char *auth_passwd; static time_t auth_expires = TIME_MAX; static int spice_migration_completed; int using_spice = 0; +int spice_displays; static QemuThread me; @@ -62,25 +63,25 @@ static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque) SpiceTimer *timer; timer = g_malloc0(sizeof(*timer)); - timer->timer = qemu_new_timer_ms(rt_clock, func, opaque); + timer->timer = timer_new_ms(QEMU_CLOCK_REALTIME, func, opaque); QTAILQ_INSERT_TAIL(&timers, timer, next); return timer; } static void timer_start(SpiceTimer *timer, uint32_t ms) { - qemu_mod_timer(timer->timer, qemu_get_clock_ms(rt_clock) + ms); + timer_mod(timer->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ms); } static void timer_cancel(SpiceTimer *timer) { - qemu_del_timer(timer->timer); + timer_del(timer->timer); } static void timer_remove(SpiceTimer *timer) { - qemu_del_timer(timer->timer); - qemu_free_timer(timer->timer); + timer_del(timer->timer); + timer_free(timer->timer); QTAILQ_REMOVE(&timers, timer, next); g_free(timer); } @@ -563,7 +564,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) { MigrationState *s = data; - if (migration_is_active(s)) { + if (migration_in_setup(s)) { spice_server_migrate_start(spice_server); } else if (migration_has_finished(s)) { spice_server_migrate_end(spice_server, true); @@ -836,6 +837,10 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); } + if (strcmp(sin->sif->type, SPICE_INTERFACE_QXL) == 0) { + spice_displays++; + } + return spice_server_add_interface(spice_server, sin); } diff --git a/ui/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h index 8091d689cb..3f59da67eb 100644 --- a/ui/vnc-auth-sasl.h +++ b/ui/vnc-auth-sasl.h @@ -33,6 +33,7 @@ typedef struct VncStateSASL VncStateSASL; typedef struct VncDisplaySASL VncDisplaySASL; #include "qemu/acl.h" +#include "qemu/main-loop.h" struct VncStateSASL { sasl_conn_t *conn; diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index c59b188602..bc7032e695 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -25,7 +25,7 @@ */ #include "vnc.h" - +#include "qemu/main-loop.h" static void start_auth_vencrypt_subauth(VncState *vs) { diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index df89315733..e304bafeb0 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -19,6 +19,7 @@ */ #include "vnc.h" +#include "qemu/main-loop.h" #ifdef CONFIG_VNC_TLS #include "qemu/sockets.h" diff --git a/user-exec.c b/user-exec.c index d45ca8e877..82bfa66ce3 100644 --- a/user-exec.c +++ b/user-exec.c @@ -95,6 +95,10 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, return 1; } + /* Convert forcefully to guest address space, invalid addresses + are still valid segv ones */ + address = h2g_nocheck(address); + env = current_cpu->env_ptr; /* see if it is an MMU fault */ ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX); diff --git a/util/aes.c b/util/aes.c index 91e97fa6e7..4b4d88e7e6 100644 --- a/util/aes.c +++ b/util/aes.c @@ -30,12 +30,7 @@ #include "qemu-common.h" #include "qemu/aes.h" -#ifndef NDEBUG -#define NDEBUG -#endif - typedef uint32_t u32; -typedef uint16_t u16; typedef uint8_t u8; /* This controls loop-unrolling in aes_core.c */ diff --git a/util/iov.c b/util/iov.c index cc6e837c83..f705586808 100644 --- a/util/iov.c +++ b/util/iov.c @@ -202,6 +202,12 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, return -1; } + if (ret == 0 && !do_send) { + /* recv returns 0 when the peer has performed an orderly + * shutdown. */ + break; + } + /* Prepare for the next iteration */ offset += ret; total += ret; diff --git a/util/qemu-option.c b/util/qemu-option.c index e0ef426daa..4ebdc4c33c 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -173,8 +173,8 @@ static void parse_option_number(const char *name, const char *value, } } -static void parse_option_size(const char *name, const char *value, - uint64_t *ret, Error **errp) +void parse_option_size(const char *name, const char *value, + uint64_t *ret, Error **errp) { char *postfix; double sizef; @@ -593,6 +593,20 @@ static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, return NULL; } +int qemu_opt_unset(QemuOpts *opts, const char *name) +{ + QemuOpt *opt = qemu_opt_find(opts, name); + + assert(opts_accepts_any(opts)); + + if (opt == NULL) { + return -1; + } else { + qemu_opt_del(opt); + return 0; + } +} + static void opt_set(QemuOpts *opts, const char *name, const char *value, bool prepend, Error **errp) { @@ -914,6 +928,15 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, get_opt_value(value, sizeof(value), p+4); id = value; } + + /* + * This code doesn't work for defaults && !list->merge_lists: when + * params has no id=, and list has an element with !opts->id, it + * appends a new element instead of returning the existing opts. + * However, we got no use for this case. Guard against possible + * (if unlikely) future misuse: + */ + assert(!defaults || list->merge_lists); opts = qemu_opts_create(list, id, !defaults, &local_err); if (opts == NULL) { if (error_is_set(&local_err)) { diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index 4489abf1d8..4de133e7b2 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -170,12 +170,11 @@ void qemu_sem_post(QemuSemaphore *sem) #if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_lock(&sem->lock); - if (sem->count == INT_MAX) { + if (sem->count == UINT_MAX) { rc = EINVAL; - } else if (sem->count++ < 0) { - rc = pthread_cond_signal(&sem->cond); } else { - rc = 0; + sem->count++; + rc = pthread_cond_signal(&sem->cond); } pthread_mutex_unlock(&sem->lock); if (rc != 0) { @@ -207,19 +206,21 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) struct timespec ts; #if defined(__APPLE__) || defined(__NetBSD__) + rc = 0; compute_abs_deadline(&ts, ms); pthread_mutex_lock(&sem->lock); - --sem->count; - while (sem->count < 0) { + while (sem->count == 0) { rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); if (rc == ETIMEDOUT) { - ++sem->count; break; } if (rc != 0) { error_exit(rc, __func__); } } + if (rc != ETIMEDOUT) { + --sem->count; + } pthread_mutex_unlock(&sem->lock); return (rc == ETIMEDOUT ? -1 : 0); #else @@ -249,16 +250,19 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) void qemu_sem_wait(QemuSemaphore *sem) { + int rc; + #if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_lock(&sem->lock); - --sem->count; - while (sem->count < 0) { - pthread_cond_wait(&sem->cond, &sem->lock); + while (sem->count == 0) { + rc = pthread_cond_wait(&sem->cond, &sem->lock); + if (rc != 0) { + error_exit(rc, __func__); + } } + --sem->count; pthread_mutex_unlock(&sem->lock); #else - int rc; - do { rc = sem_wait(&sem->sem); } while (rc == -1 && errno == EINTR); diff --git a/version.rc b/version.rc index 82e10ecf26..a50d62fa0c 100644 --- a/version.rc +++ b/version.rc @@ -26,3 +26,5 @@ FILESUBTYPE VFT2_UNKNOWN VALUE "Translation", 0x0409, 1252 } } + +IDI_ICON1 ICON "pc-bios/qemu-nsis.ico" @@ -196,7 +196,7 @@ NICInfo nd_table[MAX_NICS]; int autostart; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ -QEMUClock *rtc_clock; +QEMUClockType rtc_clock; int vga_interface_type = VGA_NONE; static int full_screen = 0; static int no_frame = 0; @@ -805,11 +805,11 @@ static void configure_rtc(QemuOpts *opts) value = qemu_opt_get(opts, "clock"); if (value) { if (!strcmp(value, "host")) { - rtc_clock = host_clock; + rtc_clock = QEMU_CLOCK_HOST; } else if (!strcmp(value, "rt")) { - rtc_clock = rt_clock; + rtc_clock = QEMU_CLOCK_REALTIME; } else if (!strcmp(value, "vm")) { - rtc_clock = vm_clock; + rtc_clock = QEMU_CLOCK_VIRTUAL; } else { fprintf(stderr, "qemu: invalid option value '%s'\n", value); exit(1); @@ -2393,7 +2393,7 @@ static int chardev_init_func(QemuOpts *opts, void *opaque) qemu_chr_new_from_opts(opts, NULL, &local_err); if (error_is_set(&local_err)) { - fprintf(stderr, "%s\n", error_get_pretty(local_err)); + error_report("%s", error_get_pretty(local_err)); error_free(local_err); return -1; } @@ -2965,7 +2965,7 @@ int main(int argc, char **argv, char **envp) runstate_init(); init_clocks(); - rtc_clock = host_clock; + rtc_clock = QEMU_CLOCK_HOST; qemu_cache_utils_init(envp); @@ -3714,7 +3714,9 @@ int main(int argc, char **argv, char **envp) old_param = 1; break; case QEMU_OPTION_clock: - configure_alarms(optarg); + /* Clock options no longer exist. Keep this option for + * backward compatibility. + */ break; case QEMU_OPTION_startdate: configure_rtc_date_offset(optarg, 1); @@ -4375,8 +4377,8 @@ int main(int argc, char **argv, char **envp) vnc_display_init(ds); vnc_display_open(ds, vnc_display, &local_err); if (local_err != NULL) { - fprintf(stderr, "Failed to start VNC server on `%s': %s\n", - vnc_display, error_get_pretty(local_err)); + error_report("Failed to start VNC server on `%s': %s", + vnc_display, error_get_pretty(local_err)); error_free(local_err); exit(1); } @@ -4387,7 +4389,7 @@ int main(int argc, char **argv, char **envp) } #endif #ifdef CONFIG_SPICE - if (using_spice && !qxl_enabled) { + if (using_spice && !spice_displays) { qemu_spice_display_init(ds); } #endif @@ -4419,7 +4421,8 @@ int main(int argc, char **argv, char **envp) Error *local_err = NULL; qemu_start_incoming_migration(incoming, &local_err); if (local_err) { - fprintf(stderr, "-incoming %s: %s\n", incoming, error_get_pretty(local_err)); + error_report("-incoming %s: %s", incoming, + error_get_pretty(local_err)); error_free(local_err); exit(1); } @@ -606,8 +606,8 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state) port = xc_evtchn_pending(state->xce_handle); if (port == state->bufioreq_local_port) { - qemu_mod_timer(state->buffered_io_timer, - BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock)); + timer_mod(state->buffered_io_timer, + BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); return NULL; } @@ -828,10 +828,10 @@ static void handle_buffered_io(void *opaque) XenIOState *state = opaque; if (handle_buffered_iopage(state)) { - qemu_mod_timer(state->buffered_io_timer, - BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock)); + timer_mod(state->buffered_io_timer, + BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); } else { - qemu_del_timer(state->buffered_io_timer); + timer_del(state->buffered_io_timer); xc_evtchn_unmask(state->xce_handle, state->bufioreq_local_port); } } @@ -962,7 +962,7 @@ static void xen_main_loop_prepare(XenIOState *state) evtchn_fd = xc_evtchn_fd(state->xce_handle); } - state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io, + state->buffered_io_timer = timer_new_ms(QEMU_CLOCK_REALTIME, handle_buffered_io, state); if (evtchn_fd != -1) { |