diff options
239 files changed, 11739 insertions, 1846 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 508ea1ee24..d034ce4b5a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -62,6 +62,7 @@ F: target-alpha/ ARM M: Paul Brook <paul@codesourcery.com> +M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: target-arm/ @@ -115,6 +116,12 @@ M: qemu-devel@nongnu.org S: Odd Fixes F: target-i386/ +Xtensa +M: Max Filippov <jcmvbkbc@gmail.com> +W: http://kkv.spb.su/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa +S: Maintained +F: target-xtensa/ + Guest CPU Cores (KVM): ---------------------- @@ -162,6 +169,7 @@ F: hw/gumstix.c Integrator CP M: Paul Brook <paul@codesourcery.com> +M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: hw/integratorcp.c @@ -187,6 +195,7 @@ F: hw/palm.c Real View M: Paul Brook <paul@codesourcery.com> +M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: hw/realview* @@ -197,11 +206,13 @@ F: hw/spitz.c Stellaris M: Paul Brook <paul@codesourcery.com> +M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: hw/stellaris.c Versatile PB M: Paul Brook <paul@codesourcery.com> +M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: hw/versatilepb.c @@ -335,6 +346,13 @@ M: Anthony Liguori <aliguori@us.ibm.com> S: Supported F: hw/pc.[ch] hw/pc_piix.c +Xtensa Machines +--------------- +DC232B +M: Max Filippov <jcmvbkbc@gmail.com> +S: Maintained +F: hw/xtensa_dc232b.c + Devices ------- IDE @@ -446,6 +464,12 @@ S: Maintained F: slirp/ T: git://git.kiszka.org/qemu.git queues/slirp +Tracing +M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> +S: Maintained +F: trace/ +T: git://repo.or.cz/qemu/stefanha.git tracing + Usermode Emulation ------------------ BSD user @@ -1,5 +1,8 @@ # Makefile for QEMU. +# Always point to the root of the build tree (needs GNU make). +BUILD_DIR=$(CURDIR) + GENERATED_HEADERS = config-host.h trace.h qemu-options.def ifeq ($(TRACE_BACKEND),dtrace) GENERATED_HEADERS += trace-dtrace.h @@ -37,7 +40,7 @@ else DOCS= endif -SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) +SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR) SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS)) SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS)) @@ -116,7 +119,7 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -version.o: $(SRC_PATH)/version.rc config-host.mak +version.o: $(SRC_PATH)/version.rc config-host.h $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") version-obj-$(CONFIG_WIN32) += version.o @@ -365,41 +368,5 @@ tar: cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn rm -rf /tmp/$(FILE) -SYSTEM_TARGETS=$(filter %-softmmu,$(TARGET_DIRS)) -SYSTEM_PROGS=$(patsubst %-softmmu,qemu-system-%, \ - $(SYSTEM_TARGETS)) - -USER_TARGETS=$(filter %-user,$(TARGET_DIRS)) -USER_PROGS=$(patsubst %-bsd-user,qemu-%, \ - $(patsubst %-darwin-user,qemu-%, \ - $(patsubst %-linux-user,qemu-%, \ - $(USER_TARGETS)))) - -# generate a binary distribution -tarbin: - cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \ - $(patsubst %,$(bindir)/%, $(SYSTEM_PROGS)) \ - $(patsubst %,$(bindir)/%, $(USER_PROGS)) \ - $(bindir)/qemu-img \ - $(bindir)/qemu-nbd \ - $(datadir)/bios.bin \ - $(datadir)/vgabios.bin \ - $(datadir)/vgabios-cirrus.bin \ - $(datadir)/ppc_rom.bin \ - $(datadir)/openbios-sparc32 \ - $(datadir)/openbios-sparc64 \ - $(datadir)/openbios-ppc \ - $(datadir)/pxe-e1000.rom \ - $(datadir)/pxe-eepro100.rom \ - $(datadir)/pxe-ne2k_pci.rom \ - $(datadir)/pxe-pcnet.rom \ - $(datadir)/pxe-rtl8139.rom \ - $(datadir)/pxe-virtio.rom \ - $(docdir)/qemu-doc.html \ - $(docdir)/qemu-tech.html \ - $(mandir)/man1/qemu.1 \ - $(mandir)/man1/qemu-img.1 \ - $(mandir)/man8/qemu-nbd.8 - # Include automatically generated dependency files -include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d) diff --git a/Makefile.objs b/Makefile.objs index 26b885bfeb..1c65087ea7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -177,6 +177,7 @@ user-obj-y = user-obj-y += envlist.o path.o user-obj-y += tcg-runtime.o host-utils.o user-obj-y += cutils.o cache-utils.o +user-obj-y += $(trace-obj-y) ###################################################################### # libhw @@ -240,6 +241,7 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o # MIPS devices hw-obj-$(CONFIG_PIIX4) += piix4.o +hw-obj-$(CONFIG_G364FB) += g364fb.o # PCI watchdog devices hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o @@ -339,12 +341,12 @@ trace.h: trace.h-timestamp trace-dtrace.h else trace.h: trace.h-timestamp endif -trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak +trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") @cmp -s $@ trace.h || cp $@ trace.h trace.c: trace.c-timestamp -trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak +trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") @cmp -s $@ trace.c || cp $@ trace.c @@ -357,7 +359,7 @@ trace-dtrace.h: trace-dtrace.dtrace # but that gets picked up by QEMU's Makefile as an external dependency # rule file. So we use '.dtrace' instead trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp -trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak +trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace @@ -390,6 +392,8 @@ trace-nested-y += control.o trace-obj-y += $(addprefix trace/, $(trace-nested-y)) +$(trace-obj-y): $(GENERATED_HEADERS) + ###################################################################### # smartcard diff --git a/Makefile.target b/Makefile.target index 8822442a8a..88d2f1fb7e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -284,7 +284,7 @@ obj-lm32-y += framebuffer.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o obj-mips-y += vga.o i8259.o -obj-mips-y += g364fb.o jazz_led.o +obj-mips-y += jazz_led.o obj-mips-y += gt64xxx.o mc146818rtc.o obj-mips-y += cirrus_vga.o obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o @@ -368,6 +368,11 @@ obj-s390x-y = s390-virtio-bus.o s390-virtio.o obj-alpha-y = i8259.o mc146818rtc.o obj-alpha-y += vga.o cirrus_vga.o +obj-xtensa-y += xtensa_pic.o +obj-xtensa-y += xtensa_sample.o +obj-xtensa-y += xtensa_dc232b.o +obj-xtensa-y += xtensa-semi.o + main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) monitor.o: hmp-commands.h qmp-commands.h @@ -378,6 +383,7 @@ obj-y += $(addprefix ../, $(common-obj-y)) obj-y += $(addprefix ../libdis/, $(libdis-y)) obj-y += $(libobj-y) obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) +obj-y += $(addprefix ../, $(trace-obj-y)) endif # CONFIG_SOFTMMU @@ -389,7 +395,6 @@ obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y)) endif # CONFIG_BSD_USER endif # CONFIG_LINUX_USER -obj-y += $(addprefix ../, $(trace-obj-y)) obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) diff --git a/Makefile.user b/Makefile.user index 024b7736b9..2b1e4d154e 100644 --- a/Makefile.user +++ b/Makefile.user @@ -17,7 +17,9 @@ all: $(user-obj-y) @true clean: - rm -f *.o *.d *.a *~ + for d in . trace; do \ + rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \ + done # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff --git a/arch_init.c b/arch_init.c index 567ab3281c..a6c69c75a9 100644 --- a/arch_init.c +++ b/arch_init.c @@ -78,6 +78,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con #define QEMU_ARCH QEMU_ARCH_SH4 #elif defined(TARGET_SPARC) #define QEMU_ARCH QEMU_ARCH_SPARC +#elif defined(TARGET_XTENSA) +#define QEMU_ARCH QEMU_ARCH_XTENSA #endif const uint32_t arch_type = QEMU_ARCH; @@ -457,11 +459,6 @@ int ram_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void qemu_service_io(void) -{ - qemu_notify_event(); -} - #ifdef HAS_AUDIO struct soundhw { const char *name; diff --git a/arch_init.h b/arch_init.h index 2de9f0852d..a74187a57d 100644 --- a/arch_init.h +++ b/arch_init.h @@ -17,6 +17,7 @@ enum { QEMU_ARCH_S390X = 512, QEMU_ARCH_SH4 = 1024, QEMU_ARCH_SPARC = 2048, + QEMU_ARCH_XTENSA = 4096, }; extern const uint32_t arch_type; diff --git a/audio/audio.c b/audio/audio.c index 5649075b01..50d0d7183f 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1743,7 +1743,7 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv) } static void audio_vm_change_state_handler (void *opaque, int running, - int reason) + RunState state) { AudioState *s = opaque; HWVoiceOut *hwo = NULL; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index aed18176ee..a449b5127e 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -30,7 +30,7 @@ typedef struct WAVVoiceOut { HWVoiceOut hw; - QEMUFile *f; + FILE *f; int64_t old_ticks; void *pcm_buf; int total_samples; @@ -76,7 +76,10 @@ static int wav_run_out (HWVoiceOut *hw, int live) dst = advance (wav->pcm_buf, rpos << hw->info.shift); hw->clip (dst, src, convert_samples); - qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); + if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) { + dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n", + convert_samples << hw->info.shift, strerror (errno)); + } rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; @@ -152,7 +155,7 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as) le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); le_store (hdr + 32, 1 << (bits16 + stereo), 2); - wav->f = qemu_fopen (conf.wav_path, "wb"); + wav->f = fopen (conf.wav_path, "wb"); if (!wav->f) { dolog ("Failed to open wave file `%s'\nReason: %s\n", conf.wav_path, strerror (errno)); @@ -161,7 +164,11 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as) return -1; } - qemu_put_buffer (wav->f, hdr, sizeof (hdr)); + if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) { + dolog ("wav_init_out: failed to write header\nReason: %s\n", + strerror(errno)); + return -1; + } return 0; } @@ -180,13 +187,32 @@ static void wav_fini_out (HWVoiceOut *hw) le_store (rlen, rifflen, 4); le_store (dlen, datalen, 4); - qemu_fseek (wav->f, 4, SEEK_SET); - qemu_put_buffer (wav->f, rlen, 4); - - qemu_fseek (wav->f, 32, SEEK_CUR); - qemu_put_buffer (wav->f, dlen, 4); + if (fseek (wav->f, 4, SEEK_SET)) { + dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n", + strerror(errno)); + goto doclose; + } + if (fwrite (rlen, 4, 1, wav->f) != 1) { + dolog ("wav_fini_out: failed to write rlen\nReason: %s\n", + strerror (errno)); + goto doclose; + } + if (fseek (wav->f, 32, SEEK_CUR)) { + dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n", + strerror (errno)); + goto doclose; + } + if (fwrite (dlen, 4, 1, wav->f) != 1) { + dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n", + strerror (errno)); + goto doclose; + } - qemu_fclose (wav->f); + doclose: + if (fclose (wav->f)) { + dolog ("wav_fini_out: fclose %p failed\nReason: %s\n", + wav->f, strerror (errno)); + } wav->f = NULL; g_free (wav->pcm_buf); diff --git a/audio/wavcapture.c b/audio/wavcapture.c index c64f0ef075..4f785f5f49 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -3,7 +3,7 @@ #include "audio.h" typedef struct { - QEMUFile *f; + FILE *f; int bytes; char *path; int freq; @@ -35,17 +35,37 @@ static void wav_destroy (void *opaque) uint8_t dlen[4]; uint32_t datalen = wav->bytes; uint32_t rifflen = datalen + 36; + Monitor *mon = cur_mon; if (wav->f) { le_store (rlen, rifflen, 4); le_store (dlen, datalen, 4); - qemu_fseek (wav->f, 4, SEEK_SET); - qemu_put_buffer (wav->f, rlen, 4); - - qemu_fseek (wav->f, 32, SEEK_CUR); - qemu_put_buffer (wav->f, dlen, 4); - qemu_fclose (wav->f); + if (fseek (wav->f, 4, SEEK_SET)) { + monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n", + strerror (errno)); + goto doclose; + } + if (fwrite (rlen, 4, 1, wav->f) != 1) { + monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n", + strerror (errno)); + goto doclose; + } + if (fseek (wav->f, 32, SEEK_CUR)) { + monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n", + strerror (errno)); + goto doclose; + } + if (fwrite (dlen, 1, 4, wav->f) != 4) { + monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n", + strerror (errno)); + goto doclose; + } + doclose: + if (fclose (wav->f)) { + fprintf (stderr, "wav_destroy: fclose failed: %s", + strerror (errno)); + } } g_free (wav->path); @@ -55,7 +75,10 @@ static void wav_capture (void *opaque, void *buf, int size) { WAVState *wav = opaque; - qemu_put_buffer (wav->f, buf, size); + if (fwrite (buf, size, 1, wav->f) != 1) { + monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s", + strerror (errno)); + } wav->bytes += size; } @@ -71,9 +94,9 @@ static void wav_capture_info (void *opaque) WAVState *wav = opaque; char *path = wav->path; - monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n", - wav->freq, wav->bits, wav->nchannels, - path ? path : "<not available>", wav->bytes); + monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n", + wav->freq, wav->bits, wav->nchannels, + path ? path : "<not available>", wav->bytes); } static struct capture_ops wav_capture_ops = { @@ -98,13 +121,13 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, CaptureVoiceOut *cap; if (bits != 8 && bits != 16) { - monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits); + monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits); return -1; } if (nchannels != 1 && nchannels != 2) { - monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n", - nchannels); + monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n", + nchannels); return -1; } @@ -130,10 +153,10 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, le_store (hdr + 28, freq << shift, 4); le_store (hdr + 32, 1 << shift, 2); - wav->f = qemu_fopen (path, "wb"); + wav->f = fopen (path, "wb"); if (!wav->f) { - monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n", - path, strerror (errno)); + monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n", + path, strerror (errno)); g_free (wav); return -1; } @@ -143,19 +166,29 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, wav->nchannels = nchannels; wav->freq = freq; - qemu_put_buffer (wav->f, hdr, sizeof (hdr)); + if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) { + monitor_printf (mon, "Failed to write header\nReason: %s\n", + strerror (errno)); + goto error_free; + } cap = AUD_add_capture (&as, &ops, wav); if (!cap) { - monitor_printf(mon, "Failed to add audio capture\n"); - g_free (wav->path); - qemu_fclose (wav->f); - g_free (wav); - return -1; + monitor_printf (mon, "Failed to add audio capture\n"); + goto error_free; } wav->cap = cap; s->opaque = wav; s->ops = wav_capture_ops; return 0; + +error_free: + g_free (wav->path); + if (fclose (wav->f)) { + monitor_printf (mon, "Failed to close wave file\nReason: %s\n", + strerror (errno)); + } + g_free (wav); + return -1; } @@ -52,6 +52,16 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, return 0; } +void qemu_remove_balloon_handler(void *opaque) +{ + if (balloon_opaque != opaque) { + return; + } + balloon_event_fn = NULL; + balloon_stat_fn = NULL; + balloon_opaque = NULL; +} + static int qemu_balloon(ram_addr_t target) { if (!balloon_event_fn) { @@ -22,6 +22,7 @@ typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb, int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, QEMUBalloonStatus *stat_func, void *opaque); +void qemu_remove_balloon_handler(void *opaque); void monitor_print_balloon(Monitor *mon, const QObject *data); int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque); @@ -44,7 +44,7 @@ #include <windows.h> #endif -static void bdrv_dev_change_media_cb(BlockDriverState *bs); +static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load); static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); @@ -480,7 +480,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename, bs->encrypted = 0; bs->valid_key = 0; bs->open_flags = flags; - /* buffer_alignment defaulted to 512, drivers can change this value */ bs->buffer_alignment = 512; pstrcpy(bs->filename, sizeof(bs->filename), filename); @@ -689,7 +688,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, } if (!bdrv_key_required(bs)) { - bdrv_dev_change_media_cb(bs); + bdrv_dev_change_media_cb(bs, true); } return 0; @@ -725,7 +724,7 @@ void bdrv_close(BlockDriverState *bs) bdrv_close(bs->file); } - bdrv_dev_change_media_cb(bs); + bdrv_dev_change_media_cb(bs, false); } } @@ -789,6 +788,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev) bs->dev = NULL; bs->dev_ops = NULL; bs->dev_opaque = NULL; + bs->buffer_alignment = 512; } /* TODO change to return DeviceState * when all users are qdevified */ @@ -802,13 +802,29 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, { bs->dev_ops = ops; bs->dev_opaque = opaque; + if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) { + bs_snapshots = NULL; + } } -static void bdrv_dev_change_media_cb(BlockDriverState *bs) +static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load) { if (bs->dev_ops && bs->dev_ops->change_media_cb) { - bs->dev_ops->change_media_cb(bs->dev_opaque); + bs->dev_ops->change_media_cb(bs->dev_opaque, load); + } +} + +bool bdrv_dev_has_removable_media(BlockDriverState *bs) +{ + return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb); +} + +bool bdrv_dev_is_tray_open(BlockDriverState *bs) +{ + if (bs->dev_ops && bs->dev_ops->is_tray_open) { + return bs->dev_ops->is_tray_open(bs->dev_opaque); } + return false; } static void bdrv_dev_resize_cb(BlockDriverState *bs) @@ -818,6 +834,14 @@ static void bdrv_dev_resize_cb(BlockDriverState *bs) } } +bool bdrv_dev_is_medium_locked(BlockDriverState *bs) +{ + if (bs->dev_ops && bs->dev_ops->is_medium_locked) { + return bs->dev_ops->is_medium_locked(bs->dev_opaque); + } + return false; +} + /* * Run consistency checks on an image * @@ -1321,7 +1345,7 @@ int64_t bdrv_getlength(BlockDriverState *bs) if (!drv) return -ENOMEDIUM; - if (bs->growable || bs->removable) { + if (bs->growable || bdrv_dev_has_removable_media(bs)) { if (drv->bdrv_getlength) { return drv->bdrv_getlength(bs); } @@ -1598,19 +1622,6 @@ BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read) return is_read ? bs->on_read_error : bs->on_write_error; } -void bdrv_set_removable(BlockDriverState *bs, int removable) -{ - bs->removable = removable; - if (removable && bs == bs_snapshots) { - bs_snapshots = NULL; - } -} - -int bdrv_is_removable(BlockDriverState *bs) -{ - return bs->removable; -} - int bdrv_is_read_only(BlockDriverState *bs) { return bs->read_only; @@ -1663,7 +1674,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key) } else if (!bs->valid_key) { bs->valid_key = 1; /* call the change callback now, we skipped it on open */ - bdrv_dev_change_media_cb(bs); + bdrv_dev_change_media_cb(bs, true); } return ret; } @@ -1850,8 +1861,9 @@ static void bdrv_print_dict(QObject *obj, void *opaque) if (qdict_get_bool(bs_dict, "removable")) { monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked")); + monitor_printf(mon, " tray-open=%d", + qdict_get_bool(bs_dict, "tray-open")); } - if (qdict_haskey(bs_dict, "inserted")) { QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted")); @@ -1886,15 +1898,21 @@ void bdrv_info(Monitor *mon, QObject **ret_data) QTAILQ_FOREACH(bs, &bdrv_states, list) { QObject *bs_obj; + QDict *bs_dict; bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', " "'removable': %i, 'locked': %i }", - bs->device_name, bs->removable, - bs->locked); - + bs->device_name, + bdrv_dev_has_removable_media(bs), + bdrv_dev_is_medium_locked(bs)); + bs_dict = qobject_to_qdict(bs_obj); + + if (bdrv_dev_has_removable_media(bs)) { + qdict_put(bs_dict, "tray-open", + qbool_from_int(bdrv_dev_is_tray_open(bs))); + } if (bs->drv) { QObject *obj; - QDict *bs_dict = qobject_to_qdict(bs_obj); obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, " "'encrypted': %i }", @@ -3026,13 +3044,12 @@ static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs) int bdrv_is_inserted(BlockDriverState *bs) { BlockDriver *drv = bs->drv; - int ret; + if (!drv) return 0; if (!drv->bdrv_is_inserted) - return !bs->tray_open; - ret = drv->bdrv_is_inserted(bs); - return ret; + return 1; + return drv->bdrv_is_inserted(bs); } /** @@ -3052,39 +3069,27 @@ int bdrv_media_changed(BlockDriverState *bs) /** * If eject_flag is TRUE, eject the media. Otherwise, close the tray */ -int bdrv_eject(BlockDriverState *bs, int eject_flag) +void bdrv_eject(BlockDriverState *bs, int eject_flag) { BlockDriver *drv = bs->drv; - if (eject_flag && bs->locked) { - return -EBUSY; - } - if (drv && drv->bdrv_eject) { drv->bdrv_eject(bs, eject_flag); } - bs->tray_open = eject_flag; - return 0; -} - -int bdrv_is_locked(BlockDriverState *bs) -{ - return bs->locked; } /** * Lock or unlock the media (if it is locked, the user won't be able * to eject it manually). */ -void bdrv_set_locked(BlockDriverState *bs, int locked) +void bdrv_lock_medium(BlockDriverState *bs, bool locked) { BlockDriver *drv = bs->drv; - trace_bdrv_set_locked(bs, locked); + trace_bdrv_lock_medium(bs, locked); - bs->locked = locked; - if (drv && drv->bdrv_set_locked) { - drv->bdrv_set_locked(bs, locked); + if (drv && drv->bdrv_lock_medium) { + drv->bdrv_lock_medium(bs, locked); } } @@ -3110,7 +3115,10 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, return NULL; } - +void bdrv_set_buffer_alignment(BlockDriverState *bs, int align) +{ + bs->buffer_alignment = align; +} void *qemu_blockalign(BlockDriverState *bs, size_t size) { @@ -32,10 +32,22 @@ typedef struct QEMUSnapshotInfo { typedef struct BlockDevOps { /* * Runs when virtual media changed (monitor commands eject, change) + * Argument load is true on load and false on eject. * Beware: doesn't run when a host device's physical media * changes. Sure would be useful if it did. + * Device models with removable media must implement this callback. */ - void (*change_media_cb)(void *opaque); + void (*change_media_cb)(void *opaque, bool load); + /* + * Is the virtual tray open? + * Device models implement this only when the device has a tray. + */ + bool (*is_tray_open)(void *opaque); + /* + * Is the virtual medium locked into the device? + * Device models implement this only when device has such a lock. + */ + bool (*is_medium_locked)(void *opaque); /* * Runs when the size changed (e.g. monitor command block_resize) */ @@ -94,6 +106,9 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev); void *bdrv_get_attached_dev(BlockDriverState *bs); void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, void *opaque); +bool bdrv_dev_has_removable_media(BlockDriverState *bs); +bool bdrv_dev_is_tray_open(BlockDriverState *bs); +bool bdrv_dev_is_medium_locked(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int bdrv_write(BlockDriverState *bs, int64_t sector_num, @@ -199,16 +214,13 @@ int bdrv_get_translation_hint(BlockDriverState *bs); void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error, BlockErrorAction on_write_error); BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read); -void bdrv_set_removable(BlockDriverState *bs, int removable); -int bdrv_is_removable(BlockDriverState *bs); int bdrv_is_read_only(BlockDriverState *bs); int bdrv_is_sg(BlockDriverState *bs); int bdrv_enable_write_cache(BlockDriverState *bs); int bdrv_is_inserted(BlockDriverState *bs); int bdrv_media_changed(BlockDriverState *bs); -int bdrv_is_locked(BlockDriverState *bs); -void bdrv_set_locked(BlockDriverState *bs, int locked); -int bdrv_eject(BlockDriverState *bs, int eject_flag); +void bdrv_lock_medium(BlockDriverState *bs, bool locked); +void bdrv_eject(BlockDriverState *bs, int eject_flag); void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); BlockDriverState *bdrv_find(const char *name); BlockDriverState *bdrv_next(BlockDriverState *bs); @@ -258,6 +270,7 @@ int bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, char *options, uint64_t img_size, int flags); +void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 @@ -339,5 +352,43 @@ typedef enum { #define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt) void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event); + +/* Convenience for block device models */ + +typedef struct BlockConf { + BlockDriverState *bs; + uint16_t physical_block_size; + uint16_t logical_block_size; + uint16_t min_io_size; + uint32_t opt_io_size; + int32_t bootindex; + uint32_t discard_granularity; +} BlockConf; + +static inline unsigned int get_physical_block_exp(BlockConf *conf) +{ + unsigned int exp = 0, size; + + for (size = conf->physical_block_size; + size > conf->logical_block_size; + size >>= 1) { + exp++; + } + + return exp; +} + +#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \ + DEFINE_PROP_DRIVE("drive", _state, _conf.bs), \ + DEFINE_PROP_UINT16("logical_block_size", _state, \ + _conf.logical_block_size, 512), \ + DEFINE_PROP_UINT16("physical_block_size", _state, \ + _conf.physical_block_size, 512), \ + DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \ + DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \ + DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \ + DEFINE_PROP_UINT32("discard_granularity", _state, \ + _conf.discard_granularity, 0) + #endif diff --git a/block/curl.c b/block/curl.c index f3f61cc8a1..4209ac88ce 100644 --- a/block/curl.c +++ b/block/curl.c @@ -47,7 +47,12 @@ struct BDRVCURLState; typedef struct CURLAIOCB { BlockDriverAIOCB common; + QEMUBH *bh; QEMUIOVector *qiov; + + int64_t sector_num; + int nb_sectors; + size_t start; size_t end; } CURLAIOCB; @@ -76,6 +81,7 @@ 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) @@ -83,14 +89,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, NULL, NULL, s); + qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, + NULL, s); break; case CURL_POLL_OUT: - qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, NULL, s); + qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, + NULL, s); break; case CURL_POLL_INOUT: - qemu_aio_set_fd_handler(fd, curl_multi_do, - curl_multi_do, NULL, NULL, s); + qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, + curl_aio_flush, NULL, s); break; case CURL_POLL_REMOVE: qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL); @@ -412,6 +420,21 @@ 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... @@ -422,43 +445,42 @@ static AIOPool curl_aio_pool = { .cancel = curl_aio_cancel, }; -static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) + +static void curl_readv_bh_cb(void *p) { - BDRVCURLState *s = bs->opaque; - CURLAIOCB *acb; - size_t start = sector_num * SECTOR_SIZE; - size_t end; CURLState *state; - acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque); - if (!acb) - return NULL; + CURLAIOCB *acb = p; + BDRVCURLState *s = acb->common.bs->opaque; - acb->qiov = qiov; + qemu_bh_delete(acb->bh); + acb->bh = NULL; + + size_t start = acb->sector_num * SECTOR_SIZE; + size_t end; // In case we have the requested data already (e.g. read-ahead), // we can just call the callback and be done. - - switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) { + switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) { case FIND_RET_OK: qemu_aio_release(acb); // fall through case FIND_RET_WAIT: - return &acb->common; + return; default: break; } // No cache found, so let's start a new request - state = curl_init_state(s); - if (!state) - return NULL; + if (!state) { + acb->common.cb(acb->common.opaque, -EIO); + qemu_aio_release(acb); + return; + } acb->start = 0; - acb->end = (nb_sectors * SECTOR_SIZE); + acb->end = (acb->nb_sectors * SECTOR_SIZE); state->buf_off = 0; if (state->orig_buf) @@ -471,12 +493,38 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, snprintf(state->range, 127, "%zd-%zd", start, end); DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n", - (nb_sectors * SECTOR_SIZE), start, state->range); + (acb->nb_sectors * SECTOR_SIZE), start, state->range); curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range); curl_multi_add_handle(s->multi, state->curl); curl_multi_do(s); +} + +static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + CURLAIOCB *acb; + + acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque); + + if (!acb) { + return NULL; + } + + acb->qiov = qiov; + acb->sector_num = sector_num; + acb->nb_sectors = nb_sectors; + + acb->bh = qemu_bh_new(curl_readv_bh_cb, acb); + + if (!acb->bh) { + DPRINTF("CURL: qemu_bh_new failed\n"); + return NULL; + } + + qemu_bh_schedule(acb->bh); return &acb->common; } diff --git a/block/nbd.c b/block/nbd.c index 55cb2fd8ba..76f04d863c 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -28,6 +28,7 @@ #include "qemu-common.h" #include "nbd.h" +#include "block_int.h" #include "module.h" #include "qemu_socket.h" @@ -47,6 +48,7 @@ typedef struct BDRVNBDState { int sock; + uint32_t nbdflags; off_t size; size_t blocksize; char *export_name; /* An NBD server may export several devices */ @@ -110,7 +112,6 @@ static int nbd_establish_connection(BlockDriverState *bs) int ret; off_t size; size_t blocksize; - uint32_t nbdflags; if (s->host_spec[0] == '/') { sock = unix_socket_outgoing(s->host_spec); @@ -125,7 +126,7 @@ static int nbd_establish_connection(BlockDriverState *bs) } /* NBD handshake */ - ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size, + ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size, &blocksize); if (ret == -1) { logout("Failed to negotiate with the NBD server\n"); diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index e06be64876..2f76311354 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -694,7 +694,7 @@ err: * If the offset is not found, allocate a new cluster. * * If the cluster was already allocated, m->nb_clusters is set to 0, - * m->depends_on is set to NULL and the other fields in m are meaningless. + * other fields in m are meaningless. * * If the cluster is newly allocated, m->nb_clusters is set to the number of * contiguous clusters that have been allocated. In this case, the other @@ -736,7 +736,6 @@ again: cluster_offset &= ~QCOW_OFLAG_COPIED; m->nb_clusters = 0; - m->depends_on = NULL; goto out; } @@ -777,17 +776,17 @@ again: */ QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) { - uint64_t end_offset = offset + nb_clusters * s->cluster_size; - uint64_t old_offset = old_alloc->offset; - uint64_t old_end_offset = old_alloc->offset + - old_alloc->nb_clusters * s->cluster_size; + uint64_t start = offset >> s->cluster_bits; + uint64_t end = start + nb_clusters; + uint64_t old_start = old_alloc->offset >> s->cluster_bits; + uint64_t old_end = old_start + old_alloc->nb_clusters; - if (end_offset < old_offset || offset > old_end_offset) { + if (end < old_start || start > old_end) { /* No intersection */ } else { - if (offset < old_offset) { + if (start < old_start) { /* Stop at the start of a running allocation */ - nb_clusters = (old_offset - offset) >> s->cluster_bits; + nb_clusters = old_start - start; } else { nb_clusters = 0; } @@ -807,6 +806,11 @@ again: abort(); } + /* save info needed for meta data update */ + m->offset = offset; + m->n_start = n_start; + m->nb_clusters = nb_clusters; + QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight); /* allocate a new cluster */ @@ -817,11 +821,6 @@ again: goto fail; } - /* save info needed for meta data update */ - m->offset = offset; - m->n_start = n_start; - m->nb_clusters = nb_clusters; - out: ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); if (ret < 0) { diff --git a/block/qcow2.c b/block/qcow2.c index 8aed31004d..510ff6897f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -237,7 +237,7 @@ static int qcow2_open(BlockDriverState *bs, int flags) s->cluster_cache = g_malloc(s->cluster_size); /* one more sector for decompressed data alignment */ - s->cluster_data = g_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + 512); s->cluster_cache_offset = -1; @@ -296,7 +296,7 @@ static int qcow2_open(BlockDriverState *bs, int flags) qcow2_cache_destroy(bs, s->l2_table_cache); } g_free(s->cluster_cache); - g_free(s->cluster_data); + qemu_vfree(s->cluster_data); return ret; } @@ -456,7 +456,7 @@ static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, */ if (!cluster_data) { cluster_data = - g_malloc0(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); + qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); } assert(cur_nr_sectors <= @@ -496,7 +496,7 @@ fail: qemu_co_mutex_unlock(&s->lock); qemu_iovec_destroy(&hd_qiov); - g_free(cluster_data); + qemu_vfree(cluster_data); return ret; } @@ -566,7 +566,7 @@ static int qcow2_co_writev(BlockDriverState *bs, if (s->crypt_method) { if (!cluster_data) { - cluster_data = g_malloc0(QCOW_MAX_CRYPT_CLUSTERS * + cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); } @@ -611,7 +611,7 @@ fail: qemu_co_mutex_unlock(&s->lock); qemu_iovec_destroy(&hd_qiov); - g_free(cluster_data); + qemu_vfree(cluster_data); return ret; } @@ -628,7 +628,7 @@ static void qcow2_close(BlockDriverState *bs) qcow2_cache_destroy(bs, s->refcount_block_cache); g_free(s->cluster_cache); - g_free(s->cluster_data); + qemu_vfree(s->cluster_data); qcow2_refcount_close(bs); } diff --git a/block/qcow2.h b/block/qcow2.h index c8ca3bc574..531af3948b 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -148,7 +148,6 @@ typedef struct QCowL2Meta int n_start; int nb_available; int nb_clusters; - struct QCowL2Meta *depends_on; CoQueue dependent_requests; QLIST_ENTRY(QCowL2Meta) next_in_flight; diff --git a/block/raw-posix.c b/block/raw-posix.c index bcf50b2cf7..305998ddb3 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -839,7 +839,14 @@ static int raw_create(const char *filename, QEMUOptionParameter *options) static int raw_flush(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - return qemu_fdatasync(s->fd); + int ret; + + ret = qemu_fdatasync(s->fd); + if (ret < 0) { + return -errno; + } + + return 0; } #ifdef CONFIG_XFS @@ -1362,7 +1369,7 @@ static void cdrom_eject(BlockDriverState *bs, int eject_flag) } } -static void cdrom_set_locked(BlockDriverState *bs, int locked) +static void cdrom_lock_medium(BlockDriverState *bs, bool locked) { BDRVRawState *s = bs->opaque; @@ -1400,7 +1407,7 @@ static BlockDriver bdrv_host_cdrom = { /* removable device support */ .bdrv_is_inserted = cdrom_is_inserted, .bdrv_eject = cdrom_eject, - .bdrv_set_locked = cdrom_set_locked, + .bdrv_lock_medium = cdrom_lock_medium, /* generic scsi device */ .bdrv_ioctl = hdev_ioctl, @@ -1481,7 +1488,7 @@ static void cdrom_eject(BlockDriverState *bs, int eject_flag) cdrom_reopen(bs); } -static void cdrom_set_locked(BlockDriverState *bs, int locked) +static void cdrom_lock_medium(BlockDriverState *bs, bool locked) { BDRVRawState *s = bs->opaque; @@ -1521,7 +1528,7 @@ static BlockDriver bdrv_host_cdrom = { /* removable device support */ .bdrv_is_inserted = cdrom_is_inserted, .bdrv_eject = cdrom_eject, - .bdrv_set_locked = cdrom_set_locked, + .bdrv_lock_medium = cdrom_lock_medium, }; #endif /* __FreeBSD__ */ diff --git a/block/raw.c b/block/raw.c index f197479645..63cf2d3bf3 100644 --- a/block/raw.c +++ b/block/raw.c @@ -85,9 +85,9 @@ static void raw_eject(BlockDriverState *bs, int eject_flag) bdrv_eject(bs->file, eject_flag); } -static void raw_set_locked(BlockDriverState *bs, int locked) +static void raw_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_set_locked(bs->file, locked); + bdrv_lock_medium(bs->file, locked); } static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) @@ -144,7 +144,7 @@ static BlockDriver bdrv_raw = { .bdrv_is_inserted = raw_is_inserted, .bdrv_media_changed = raw_media_changed, .bdrv_eject = raw_eject, - .bdrv_set_locked = raw_set_locked, + .bdrv_lock_medium = raw_lock_medium, .bdrv_ioctl = raw_ioctl, .bdrv_aio_ioctl = raw_aio_ioctl, diff --git a/block/rbd.c b/block/rbd.c index ce0f6ef6ee..3068c829fe 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -13,35 +13,33 @@ #include "qemu-common.h" #include "qemu-error.h" - #include "block_int.h" #include <rbd/librbd.h> - - /* * When specifying the image filename use: * * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]] * - * poolname must be the name of an existing rados pool + * poolname must be the name of an existing rados pool. * - * devicename is the basename for all objects used to - * emulate the raw device. + * devicename is the name of the rbd image. * - * Each option given is used to configure rados, and may be - * any Ceph option, or "conf". The "conf" option specifies - * a Ceph configuration file to read. + * Each option given is used to configure rados, and may be any valid + * Ceph option, "id", or "conf". * - * Metadata information (image size, ...) is stored in an - * object with the name "devicename.rbd". + * The "id" option indicates what user we should authenticate as to + * the Ceph cluster. If it is excluded we will use the Ceph default + * (normally 'admin'). * - * The raw device is split into 4MB sized objects by default. - * The sequencenumber is encoded in a 12 byte long hex-string, - * and is attached to the devicename, separated by a dot. - * e.g. "devicename.1234567890ab" + * The "conf" option specifies a Ceph configuration file to read. If + * it is not specified, we will read from the default Ceph locations + * (e.g., /etc/ceph/ceph.conf). To avoid reading _any_ configuration + * file, specify conf=/dev/null. * + * Configuration values containing :, @, or = can be escaped with a + * leading "\". */ #define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER) @@ -104,8 +102,15 @@ static int qemu_rbd_next_tok(char *dst, int dst_len, *p = NULL; if (delim != '\0') { - end = strchr(src, delim); - if (end) { + for (end = src; *end; ++end) { + if (*end == delim) { + break; + } + if (*end == '\\' && end[1] != '\0') { + end++; + } + } + if (*end == delim) { *p = end + 1; *end = '\0'; } @@ -124,6 +129,19 @@ static int qemu_rbd_next_tok(char *dst, int dst_len, return 0; } +static void qemu_rbd_unescape(char *src) +{ + char *p; + + for (p = src; *src; ++src, ++p) { + if (*src == '\\' && src[1] != '\0') { + src++; + } + *p = *src; + } + *p = '\0'; +} + static int qemu_rbd_parsename(const char *filename, char *pool, int pool_len, char *snap, int snap_len, @@ -148,6 +166,7 @@ static int qemu_rbd_parsename(const char *filename, ret = -EINVAL; goto done; } + qemu_rbd_unescape(pool); if (strchr(p, '@')) { ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p); @@ -155,9 +174,11 @@ static int qemu_rbd_parsename(const char *filename, goto done; } ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p); + qemu_rbd_unescape(snap); } else { ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p); } + qemu_rbd_unescape(name); if (ret < 0 || !p) { goto done; } @@ -169,6 +190,34 @@ done: return ret; } +static char *qemu_rbd_parse_clientname(const char *conf, char *clientname) +{ + const char *p = conf; + + while (*p) { + int len; + const char *end = strchr(p, ':'); + + if (end) { + len = end - p; + } else { + len = strlen(p); + } + + if (strncmp(p, "id=", 3) == 0) { + len -= 3; + strncpy(clientname, p + 3, len); + clientname[len] = '\0'; + return clientname; + } + if (end == NULL) { + break; + } + p = end + 1; + } + return NULL; +} + static int qemu_rbd_set_conf(rados_t cluster, const char *conf) { char *p, *buf; @@ -185,6 +234,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf) if (ret < 0) { break; } + qemu_rbd_unescape(name); if (!p) { error_report("conf option %s has no value", name); @@ -197,18 +247,21 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf) if (ret < 0) { break; } + qemu_rbd_unescape(value); - if (strcmp(name, "conf")) { - ret = rados_conf_set(cluster, name, value); + if (strcmp(name, "conf") == 0) { + ret = rados_conf_read_file(cluster, value); if (ret < 0) { - error_report("invalid conf option %s", name); - ret = -EINVAL; + error_report("error reading conf file %s", value); break; } + } else if (strcmp(name, "id") == 0) { + /* ignore, this is parsed by qemu_rbd_parse_clientname() */ } else { - ret = rados_conf_read_file(cluster, value); + ret = rados_conf_set(cluster, name, value); if (ret < 0) { - error_report("error reading conf file %s", value); + error_report("invalid conf option %s", name); + ret = -EINVAL; break; } } @@ -227,6 +280,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options) char name[RBD_MAX_IMAGE_NAME_SIZE]; char snap_buf[RBD_MAX_SNAP_NAME_SIZE]; char conf[RBD_MAX_CONF_SIZE]; + char clientname_buf[RBD_MAX_CONF_SIZE]; + char *clientname; rados_t cluster; rados_ioctx_t io_ctx; int ret; @@ -259,17 +314,15 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options) options++; } - if (rados_create(&cluster, NULL) < 0) { + clientname = qemu_rbd_parse_clientname(conf, clientname_buf); + if (rados_create(&cluster, clientname) < 0) { error_report("error initializing"); return -EIO; } if (strstr(conf, "conf=") == NULL) { - if (rados_conf_read_file(cluster, NULL) < 0) { - error_report("error reading config file"); - rados_shutdown(cluster); - return -EIO; - } + /* try default location, but ignore failure */ + rados_conf_read_file(cluster, NULL); } if (conf[0] != '\0' && @@ -358,15 +411,14 @@ static void qemu_rbd_aio_event_reader(void *opaque) char *p = (char *)&s->event_rcb; /* now read the rcb pointer that was sent from a non qemu thread */ - if ((ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos, - sizeof(s->event_rcb) - s->event_reader_pos)) > 0) { - if (ret > 0) { - s->event_reader_pos += ret; - 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--; - } + ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos, + sizeof(s->event_rcb) - s->event_reader_pos); + if (ret > 0) { + s->event_reader_pos += ret; + 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); @@ -385,6 +437,8 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags) char pool[RBD_MAX_POOL_NAME_SIZE]; char snap_buf[RBD_MAX_SNAP_NAME_SIZE]; char conf[RBD_MAX_CONF_SIZE]; + char clientname_buf[RBD_MAX_CONF_SIZE]; + char *clientname; int r; if (qemu_rbd_parsename(filename, pool, sizeof(pool), @@ -393,55 +447,48 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags) conf, sizeof(conf)) < 0) { return -EINVAL; } - s->snap = NULL; - if (snap_buf[0] != '\0') { - s->snap = g_strdup(snap_buf); - } - r = rados_create(&s->cluster, NULL); + clientname = qemu_rbd_parse_clientname(conf, clientname_buf); + r = rados_create(&s->cluster, clientname); if (r < 0) { error_report("error initializing"); return r; } + s->snap = NULL; + if (snap_buf[0] != '\0') { + s->snap = g_strdup(snap_buf); + } + if (strstr(conf, "conf=") == NULL) { - r = rados_conf_read_file(s->cluster, NULL); - if (r < 0) { - error_report("error reading config file"); - rados_shutdown(s->cluster); - return r; - } + /* try default location, but ignore failure */ + rados_conf_read_file(s->cluster, NULL); } if (conf[0] != '\0') { r = qemu_rbd_set_conf(s->cluster, conf); if (r < 0) { error_report("error setting config options"); - rados_shutdown(s->cluster); - return r; + goto failed_shutdown; } } r = rados_connect(s->cluster); if (r < 0) { error_report("error connecting"); - rados_shutdown(s->cluster); - return r; + goto failed_shutdown; } r = rados_ioctx_create(s->cluster, pool, &s->io_ctx); if (r < 0) { error_report("error opening pool %s", pool); - rados_shutdown(s->cluster); - return r; + goto failed_shutdown; } r = rbd_open(s->io_ctx, s->name, &s->image, s->snap); if (r < 0) { error_report("error reading header from %s", s->name); - rados_ioctx_destroy(s->io_ctx); - rados_shutdown(s->cluster); - return r; + goto failed_open; } bs->read_only = (s->snap != NULL); @@ -462,8 +509,11 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags) failed: rbd_close(s->image); +failed_open: rados_ioctx_destroy(s->io_ctx); +failed_shutdown: rados_shutdown(s->cluster); + g_free(s->snap); return r; } @@ -655,6 +705,17 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs, return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1); } +static int qemu_rbd_flush(BlockDriverState *bs) +{ +#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1) + /* rbd_flush added in 0.1.1 */ + BDRVRBDState *s = bs->opaque; + return rbd_flush(s->image); +#else + return 0; +#endif +} + static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVRBDState *s = bs->opaque; @@ -790,6 +851,7 @@ static BlockDriver bdrv_rbd = { .bdrv_file_open = qemu_rbd_open, .bdrv_close = qemu_rbd_close, .bdrv_create = qemu_rbd_create, + .bdrv_flush = qemu_rbd_flush, .bdrv_get_info = qemu_rbd_getinfo, .create_options = qemu_rbd_create_options, .bdrv_getlength = qemu_rbd_getlength, diff --git a/block/vmdk.c b/block/vmdk.c index 6c8edfc190..5d16ec49bc 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -179,11 +179,16 @@ static void vmdk_free_extents(BlockDriverState *bs) { int i; BDRVVmdkState *s = bs->opaque; + VmdkExtent *e; for (i = 0; i < s->num_extents; i++) { - g_free(s->extents[i].l1_table); - g_free(s->extents[i].l2_cache); - g_free(s->extents[i].l1_backup_table); + e = &s->extents[i]; + g_free(e->l1_table); + g_free(e->l2_cache); + g_free(e->l1_backup_table); + if (e->file != bs->file) { + bdrv_delete(e->file); + } } g_free(s->extents); } @@ -619,12 +624,13 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, s->desc_offset = 0; ret = vmdk_parse_extents(buf, bs, bs->file->filename); if (ret) { + vmdk_free_extents(bs); return ret; } /* try to open parent images, if exist */ if (vmdk_parent_open(bs)) { - g_free(s->extents); + vmdk_free_extents(bs); return -EINVAL; } s->parent_cid = vmdk_read_cid(bs, 1); diff --git a/block/vvfat.c b/block/vvfat.c index 187ac96f25..f567c9adb9 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1789,7 +1789,7 @@ DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)clu for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { int cluster_count = 0; -DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)); +DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i)); if (is_volume_label(direntries + i) || is_dot(direntries + i) || is_free(direntries + i)) continue; diff --git a/block_int.h b/block_int.h index 5dc0074bfc..8c3b86373c 100644 --- a/block_int.h +++ b/block_int.h @@ -120,7 +120,7 @@ struct BlockDriver { int (*bdrv_is_inserted)(BlockDriverState *bs); int (*bdrv_media_changed)(BlockDriverState *bs); void (*bdrv_eject)(BlockDriverState *bs, int eject_flag); - void (*bdrv_set_locked)(BlockDriverState *bs, int locked); + void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); /* to control generic scsi devices */ int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); @@ -155,9 +155,6 @@ struct BlockDriverState { int read_only; /* if true, the media is read only */ int keep_read_only; /* if true, the media was requested to stay read only */ int open_flags; /* flags used to open the file, re-used for re-open */ - int removable; /* if true, the media can be removed */ - int locked; /* if true, the media cannot temporarily be ejected */ - int tray_open; /* if true, the virtual tray is open */ int encrypted; /* if true, the media is encrypted */ int valid_key; /* if true, a valid encryption key has been set */ int sg; /* if true, the device is a /dev/sg* */ @@ -228,39 +225,4 @@ void qemu_aio_release(void *p); int is_windows_drive(const char *filename); #endif -typedef struct BlockConf { - BlockDriverState *bs; - uint16_t physical_block_size; - uint16_t logical_block_size; - uint16_t min_io_size; - uint32_t opt_io_size; - int32_t bootindex; - uint32_t discard_granularity; -} BlockConf; - -static inline unsigned int get_physical_block_exp(BlockConf *conf) -{ - unsigned int exp = 0, size; - - for (size = conf->physical_block_size; - size > conf->logical_block_size; - size >>= 1) { - exp++; - } - - return exp; -} - -#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \ - DEFINE_PROP_DRIVE("drive", _state, _conf.bs), \ - DEFINE_PROP_UINT16("logical_block_size", _state, \ - _conf.logical_block_size, 512), \ - DEFINE_PROP_UINT16("physical_block_size", _state, \ - _conf.physical_block_size, 512), \ - DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \ - DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \ - DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \ - DEFINE_PROP_UINT32("discard_granularity", _state, \ - _conf.discard_granularity, 0) - #endif /* BLOCK_INT_H */ diff --git a/blockdev.c b/blockdev.c index 049dda5549..0827bf7743 100644 --- a/blockdev.c +++ b/blockdev.c @@ -473,17 +473,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) } break; case MEDIA_CDROM: - bdrv_set_removable(dinfo->bdrv, 1); dinfo->media_cd = 1; break; } break; case IF_SD: - /* FIXME: This isn't really a floppy, but it's a reasonable - approximation. */ case IF_FLOPPY: - bdrv_set_removable(dinfo->bdrv, 1); - break; case IF_PFLASH: case IF_MTD: break; @@ -636,11 +631,12 @@ out: static int eject_device(Monitor *mon, BlockDriverState *bs, int force) { - if (!bdrv_is_removable(bs)) { + if (!bdrv_dev_has_removable_media(bs)) { qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs)); return -1; } - if (!force && bdrv_is_locked(bs)) { + if (!force && !bdrv_dev_is_tray_open(bs) + && bdrv_dev_is_medium_locked(bs)) { qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); return -1; } @@ -4,6 +4,7 @@ #include "config-host.h" #include <inttypes.h> +#include "softfloat.h" #ifdef CONFIG_MACHINE_BSWAP_H #include <sys/endian.h> @@ -11,8 +12,6 @@ #include <machine/bswap.h> #else -#include "softfloat.h" - #ifdef CONFIG_BYTESWAP_H #include <byteswap.h> #else @@ -389,7 +389,7 @@ cvtnum( if (sp[1] != '\0') return -1LL; - c = tolower(*sp); + c = qemu_tolower(*sp); switch (c) { default: return i; diff --git a/compiler.h b/compiler.h index a2d5959e4b..a1c0794947 100644 --- a/compiler.h +++ b/compiler.h @@ -5,8 +5,20 @@ #include "config-host.h" +/*---------------------------------------------------------------------------- +| The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler. +| The code is a copy of SOFTFLOAT_GNUC_PREREQ, see softfloat-macros.h. +*----------------------------------------------------------------------------*/ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define QEMU_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define QEMU_GNUC_PREREQ(maj, min) 0 +#endif + #define QEMU_NORETURN __attribute__ ((__noreturn__)) -#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT + +#if QEMU_GNUC_PREREQ(3, 4) #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define QEMU_WARN_UNUSED_RESULT @@ -22,8 +34,7 @@ typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1]; #if defined __GNUC__ -# if (__GNUC__ < 4) || \ - defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4) +# if !QEMU_GNUC_PREREQ(4, 4) /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */ # define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2))) # define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m))) @@ -855,6 +855,7 @@ if [ "$softmmu" = "yes" ] ; then default_target_list="\ i386-softmmu \ x86_64-softmmu \ +alpha-softmmu \ arm-softmmu \ cris-softmmu \ lm32-softmmu \ @@ -873,6 +874,8 @@ sh4eb-softmmu \ sparc-softmmu \ sparc64-softmmu \ s390x-softmmu \ +xtensa-softmmu \ +xtensaeb-softmmu \ " fi # the following are Linux specific @@ -1025,7 +1028,6 @@ echo " --disable-linux-aio disable Linux AIO support" echo " --enable-linux-aio enable Linux AIO support" echo " --disable-attr disables attr and xattr support" echo " --enable-attr enable attr and xattr support" -echo " --enable-io-thread enable IO thread" echo " --disable-blobs disable installing provided firmware blobs" echo " --enable-docs enable documentation build" echo " --disable-docs disable documentation build" @@ -1071,7 +1073,7 @@ cat > $TMPC << EOF int main(void) { return 0; } EOF for flag in $gcc_flags; do - if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then + if compile_prog "$flag -Werror" "" ; then QEMU_CFLAGS="$QEMU_CFLAGS $flag" fi done @@ -1338,8 +1340,8 @@ fi # pkg-config probe if ! has $pkg_config; then - echo warning: proceeding without "$pkg_config" >&2 - pkg_config=/bin/false + echo "Error: pkg-config binary '$pkg_config' not found" + exit 1 fi ########################################## @@ -2357,23 +2359,6 @@ if compile_prog "" "" ; then need_offsetof=no fi -########################################## -# check if the compiler understands attribute warn_unused_result -# -# This could be smarter, but gcc -Werror does not error out even when warning -# about attribute warn_unused_result - -gcc_attribute_warn_unused_result=no -cat > $TMPC << EOF -#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4) -#error gcc 3.3 or older -#endif -int main(void) { return 0;} -EOF -if compile_prog "" ""; then - gcc_attribute_warn_unused_result=yes -fi - # spice probe if test "$spice" != "no" ; then cat > $TMPC << EOF @@ -2996,9 +2981,6 @@ fi if test "$need_offsetof" = "yes" ; then echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak fi -if test "$gcc_attribute_warn_unused_result" = "yes" ; then - echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak -fi if test "$fdatasync" = "yes" ; then echo "CONFIG_FDATASYNC=y" >> $config_host_mak fi @@ -3151,7 +3133,7 @@ target_arch2=`echo $target | cut -d '-' -f 1` target_bigendian="no" case "$target_arch2" in - armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus) + armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -3346,6 +3328,10 @@ case "$target_arch2" in unicore32) target_phys_bits=32 ;; + xtensa|xtensaeb) + TARGET_ARCH=xtensa + target_phys_bits=32 + ;; *) echo "Unsupported target CPU" exit 1 @@ -3520,6 +3506,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do echo "CONFIG_SPARC_DIS=y" >> $config_target_mak echo "CONFIG_SPARC_DIS=y" >> $libdis_config_mak ;; + xtensa*) + echo "CONFIG_XTENSA_DIS=y" >> $config_target_mak + echo "CONFIG_XTENSA_DIS=y" >> $libdis_config_mak + ;; esac done @@ -3612,7 +3602,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom" DIRS="$DIRS pc-bios/spapr-rtas" DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS fsdev ui" -DIRS="$DIRS qapi" +DIRS="$DIRS qapi qapi-generated" DIRS="$DIRS qga trace" FILES="Makefile tests/Makefile qdict-test-data.txt" FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" @@ -3660,6 +3650,7 @@ fi d=libuser mkdir -p $d +mkdir -p $d/trace symlink $source_path/Makefile.user $d/Makefile if test "$static" = "no" -a "$user_pie" = "yes" ; then echo "QEMU_CFLAGS+=-fpie" > $d/config.mak @@ -115,6 +115,7 @@ typedef enum { /* ??? This is mis-named. It is used for both text and graphical consoles. */ struct TextConsole { + int index; console_type_t console_type; DisplayState *ds; /* Graphic console state. */ @@ -177,12 +178,15 @@ void vga_hw_screen_dump(const char *filename) TextConsole *previous_active_console; previous_active_console = active_console; - active_console = consoles[0]; + /* There is currently no way of specifying which screen we want to dump, so always dump the first one. */ - if (consoles[0] && consoles[0]->hw_screen_dump) + console_select(0); + if (consoles[0] && consoles[0]->hw_screen_dump) { consoles[0]->hw_screen_dump(consoles[0]->hw, filename); - active_console = previous_active_console; + } + + console_select(previous_active_console->index); } void vga_hw_text_update(console_ch_t *chardata) @@ -343,6 +347,7 @@ static const uint32_t dmask4[4] = { static uint32_t color_table[2][8]; +#ifndef CONFIG_CURSES enum color_names { COLOR_BLACK = 0, COLOR_RED = 1, @@ -353,6 +358,7 @@ enum color_names { COLOR_CYAN = 6, COLOR_WHITE = 7 }; +#endif static const uint32_t color_table_rgb[2][8] = { { /* dark */ @@ -1245,6 +1251,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) s->ds = ds; s->console_type = console_type; if (console_type != GRAPHIC_CONSOLE) { + s->index = nb_consoles; consoles[nb_consoles++] = s; } else { /* HACK: Put graphical consoles before text consoles. */ @@ -1252,7 +1259,9 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE) break; consoles[i] = consoles[i - 1]; + consoles[i]->index = i; } + s->index = i; consoles[i] = s; nb_consoles++; } @@ -328,7 +328,12 @@ static inline int ds_get_bytes_per_pixel(DisplayState *ds) return ds->surface->pf.bytes_per_pixel; } +#ifdef CONFIG_CURSES +#include <curses.h> +typedef chtype console_ch_t; +#else typedef unsigned long console_ch_t; +#endif static inline void console_write_ch(console_ch_t *dest, uint32_t ch) { if (!(ch & 0xff)) @@ -290,7 +290,6 @@ extern unsigned long reserved_va; /* ??? These should be the larger of unsigned long and target_ulong. */ extern unsigned long qemu_real_host_page_size; -extern unsigned long qemu_host_page_bits; extern unsigned long qemu_host_page_size; extern unsigned long qemu_host_page_mask; diff --git a/cpu-exec.c b/cpu-exec.c index de0d716da0..aef66f290c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -86,7 +86,7 @@ static TranslationBlock *tb_find_slow(CPUState *env, { TranslationBlock *tb, **ptb1; unsigned int h; - tb_page_addr_t phys_pc, phys_page1, phys_page2; + tb_page_addr_t phys_pc, phys_page1; target_ulong virt_page2; tb_invalidated_flag = 0; @@ -94,7 +94,6 @@ static TranslationBlock *tb_find_slow(CPUState *env, /* find translated block using physical mappings */ phys_pc = get_page_addr_code(env, pc); phys_page1 = phys_pc & TARGET_PAGE_MASK; - phys_page2 = -1; h = tb_phys_hash_func(phys_pc); ptb1 = &tb_phys_hash[h]; for(;;) { @@ -107,6 +106,8 @@ static TranslationBlock *tb_find_slow(CPUState *env, tb->flags == flags) { /* check next page if needed */ if (tb->page_addr[1] != -1) { + tb_page_addr_t phys_page2; + virt_page2 = (pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; phys_page2 = get_page_addr_code(env, virt_page2); @@ -222,6 +223,7 @@ int cpu_exec(CPUState *env) #elif defined(TARGET_SH4) #elif defined(TARGET_CRIS) #elif defined(TARGET_S390X) +#elif defined(TARGET_XTENSA) /* XXXXX */ #else #error unsupported target CPU @@ -487,6 +489,12 @@ int cpu_exec(CPUState *env) do_interrupt(env); next_tb = 0; } +#elif defined(TARGET_XTENSA) + if (interrupt_request & CPU_INTERRUPT_HARD) { + env->exception_index = EXC_IRQ; + do_interrupt(env); + next_tb = 0; + } #endif /* Don't use the cached interrupt_request value, do_interrupt may have updated the EXITTB flag. */ @@ -616,6 +624,7 @@ int cpu_exec(CPUState *env) #elif defined(TARGET_ALPHA) #elif defined(TARGET_CRIS) #elif defined(TARGET_S390X) +#elif defined(TARGET_XTENSA) /* XXXXX */ #else #error unsupported target CPU @@ -115,16 +115,16 @@ void cpu_synchronize_all_post_init(void) int cpu_is_stopped(CPUState *env) { - return !vm_running || env->stopped; + return !runstate_is_running() || env->stopped; } -static void do_vm_stop(int reason) +static void do_vm_stop(RunState state) { - if (vm_running) { + if (runstate_is_running()) { cpu_disable_ticks(); - vm_running = 0; pause_all_vcpus(); - vm_state_notify(0, reason); + runstate_set(state); + vm_state_notify(0, state); qemu_aio_flush(); bdrv_flush_all(); monitor_protocol_event(QEVENT_STOP, NULL); @@ -136,7 +136,7 @@ static int cpu_can_run(CPUState *env) if (env->stop) { return 0; } - if (env->stopped || !vm_running) { + if (env->stopped || !runstate_is_running()) { return 0; } return 1; @@ -147,7 +147,7 @@ static bool cpu_thread_is_idle(CPUState *env) if (env->stop || env->queued_work_first) { return false; } - if (env->stopped || !vm_running) { + if (env->stopped || !runstate_is_running()) { return true; } if (!env->halted || qemu_cpu_has_work(env) || @@ -380,11 +380,6 @@ static int qemu_signal_init(void) int sigfd; sigset_t set; - /* SIGUSR2 used by posix-aio-compat.c */ - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); - /* * SIG_IPI must be blocked in the main thread and must not be caught * by sigwait() in the signal thread. Otherwise, the cpu thread will @@ -878,10 +873,10 @@ void cpu_stop_current(void) } } -void vm_stop(int reason) +void vm_stop(RunState state) { if (!qemu_thread_is_self(&io_thread)) { - qemu_system_vmstop_request(reason); + qemu_system_vmstop_request(state); /* * FIXME: should not return to device code in case * vm_stop() has been requested. @@ -889,7 +884,7 @@ void vm_stop(int reason) cpu_stop_current(); return; } - do_vm_stop(reason); + do_vm_stop(state); } static int tcg_cpu_exec(CPUState *env) @@ -15,7 +15,6 @@ void cpu_synchronize_all_post_init(void); /* vl.c */ extern int smp_cores; extern int smp_threads; -void vm_state_notify(int running, int reason); bool cpu_exec_all(void); void set_numa_modes(void); void set_cpu_log(const char *optarg); diff --git a/darwin-user/machload.c b/darwin-user/machload.c index 3bc3b65559..0aa828298b 100644 --- a/darwin-user/machload.c +++ b/darwin-user/machload.c @@ -865,11 +865,11 @@ unsigned long setup_arg_pages(void * mh, char ** argv, char ** env) page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID); } - DPRINTF("pushing argc %d \n", argc); + DPRINTF("pushing argc %d\n", argc); stl(stack, argc); stack--; - DPRINTF("pushing mh 0x%x \n", (int)mh); + DPRINTF("pushing mh 0x%x\n", (int)mh); stl(stack, (int) mh); /* Stack points on the mh */ diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index f524971598..45bdefb9b2 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -26,3 +26,4 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_G364FB=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index aeab6b2c28..d43e33ca60 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -26,3 +26,4 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_G364FB=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index 8e6511cbeb..f307e8d8b0 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -28,3 +28,4 @@ CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y CONFIG_FULONG=y +CONFIG_G364FB=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index a05ac25393..1a66bc31bb 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -26,3 +26,4 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_G364FB=y diff --git a/default-configs/xtensa-softmmu.mak b/default-configs/xtensa-softmmu.mak new file mode 100644 index 0000000000..e5faa09012 --- /dev/null +++ b/default-configs/xtensa-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for Xtensa diff --git a/default-configs/xtensaeb-softmmu.mak b/default-configs/xtensaeb-softmmu.mak new file mode 100644 index 0000000000..e5faa09012 --- /dev/null +++ b/default-configs/xtensaeb-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for Xtensa diff --git a/dma-helpers.c b/dma-helpers.c index 4610ea0420..86d2d0a997 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -42,7 +42,8 @@ typedef struct { BlockDriverAIOCB *acb; QEMUSGList *sg; uint64_t sector_num; - int is_write; + bool to_dev; + bool in_cancel; int sg_cur_index; target_phys_addr_t sg_cur_byte; QEMUIOVector iov; @@ -58,7 +59,7 @@ static void reschedule_dma(void *opaque) qemu_bh_delete(dbs->bh); dbs->bh = NULL; - dma_bdrv_cb(opaque, 0); + dma_bdrv_cb(dbs, 0); } static void continue_after_map_failure(void *opaque) @@ -75,9 +76,29 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs) for (i = 0; i < dbs->iov.niov; ++i) { cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base, - dbs->iov.iov[i].iov_len, !dbs->is_write, + dbs->iov.iov[i].iov_len, !dbs->to_dev, dbs->iov.iov[i].iov_len); } + qemu_iovec_reset(&dbs->iov); +} + +static void dma_complete(DMAAIOCB *dbs, int ret) +{ + dma_bdrv_unmap(dbs); + if (dbs->common.cb) { + dbs->common.cb(dbs->common.opaque, ret); + } + qemu_iovec_destroy(&dbs->iov); + if (dbs->bh) { + qemu_bh_delete(dbs->bh); + dbs->bh = NULL; + } + if (!dbs->in_cancel) { + /* Requests may complete while dma_aio_cancel is in progress. In + * this case, the AIOCB should not be released because it is still + * referenced by dma_aio_cancel. */ + qemu_aio_release(dbs); + } } static void dma_bdrv_cb(void *opaque, int ret) @@ -89,19 +110,16 @@ static void dma_bdrv_cb(void *opaque, int ret) dbs->acb = NULL; dbs->sector_num += dbs->iov.size / 512; dma_bdrv_unmap(dbs); - qemu_iovec_reset(&dbs->iov); if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { - dbs->common.cb(dbs->common.opaque, ret); - qemu_iovec_destroy(&dbs->iov); - qemu_aio_release(dbs); + dma_complete(dbs, ret); return; } while (dbs->sg_cur_index < dbs->sg->nsg) { cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte; cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte; - mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write); + mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->to_dev); if (!mem) break; qemu_iovec_add(&dbs->iov, mem, cur_len); @@ -120,9 +138,7 @@ static void dma_bdrv_cb(void *opaque, int ret) dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov, dbs->iov.size / 512, dma_bdrv_cb, dbs); if (!dbs->acb) { - dma_bdrv_unmap(dbs); - qemu_iovec_destroy(&dbs->iov); - return; + dma_complete(dbs, -EIO); } } @@ -131,8 +147,14 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb) DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); if (dbs->acb) { - bdrv_aio_cancel(dbs->acb); + BlockDriverAIOCB *acb = dbs->acb; + dbs->acb = NULL; + dbs->in_cancel = true; + bdrv_aio_cancel(acb); + dbs->in_cancel = false; } + dbs->common.cb = NULL; + dma_complete(dbs, 0); } static AIOPool dma_aio_pool = { @@ -143,7 +165,7 @@ static AIOPool dma_aio_pool = { BlockDriverAIOCB *dma_bdrv_io( BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num, DMAIOFunc *io_func, BlockDriverCompletionFunc *cb, - void *opaque, int is_write) + void *opaque, bool to_dev) { DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque); @@ -153,15 +175,11 @@ BlockDriverAIOCB *dma_bdrv_io( dbs->sector_num = sector_num; dbs->sg_cur_index = 0; dbs->sg_cur_byte = 0; - dbs->is_write = is_write; + dbs->to_dev = to_dev; dbs->io_func = io_func; dbs->bh = NULL; qemu_iovec_init(&dbs->iov, sg->nsg); dma_bdrv_cb(dbs, 0); - if (!dbs->acb) { - qemu_aio_release(dbs); - return NULL; - } return &dbs->common; } @@ -170,12 +188,12 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs, QEMUSGList *sg, uint64_t sector, void (*cb)(void *opaque, int ret), void *opaque) { - return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, 0); + return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, false); } BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, QEMUSGList *sg, uint64_t sector, void (*cb)(void *opaque, int ret), void *opaque) { - return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1); + return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true); } @@ -15,10 +15,13 @@ #include "hw/hw.h" #include "block.h" -typedef struct { +typedef struct ScatterGatherEntry ScatterGatherEntry; + +#if defined(TARGET_PHYS_ADDR_BITS) +struct ScatterGatherEntry { target_phys_addr_t base; target_phys_addr_t len; -} ScatterGatherEntry; +}; struct QEMUSGList { ScatterGatherEntry *sg; @@ -31,6 +34,7 @@ void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint); void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base, target_phys_addr_t len); void qemu_sglist_destroy(QEMUSGList *qsg); +#endif typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *iov, int nb_sectors, @@ -39,7 +43,7 @@ typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num, BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num, DMAIOFunc *io_func, BlockDriverCompletionFunc *cb, - void *opaque, int is_write); + void *opaque, bool to_dev); BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs, QEMUSGList *sg, uint64_t sector, BlockDriverCompletionFunc *cb, void *opaque); diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt index 057c322090..136d271120 100644 --- a/docs/qdev-device-use.txt +++ b/docs/qdev-device-use.txt @@ -208,7 +208,7 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows: * con: becomes -chardev console -* COM<NUM> becomes -chardev serial,path=<NUM> +* COM<NUM> becomes -chardev serial,path=COM<NUM> * file:FNAME becomes -chardev file,path=FNAME diff --git a/docs/tracing.txt b/docs/tracing.txt index 4b27ab0c2a..95ca16c05d 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -31,8 +31,8 @@ There is a set of static trace events declared in the "trace-events" source file. Each trace event declaration names the event, its arguments, and the format string which can be used for pretty-printing: - qemu_malloc(size_t size, void *ptr) "size %zu ptr %p" - qemu_free(void *ptr) "ptr %p" + qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p" + qemu_vfree(void *ptr) "ptr %p" The "trace-events" file is processed by the "tracetool" script during build to generate code for the trace events. Trace events are invoked directly from @@ -40,14 +40,16 @@ source code like this: #include "trace.h" /* needed for trace event prototype */ - void *qemu_malloc(size_t size) + void *qemu_vmalloc(size_t size) { void *ptr; - if (!size && !allow_zero_malloc()) { - abort(); + size_t align = QEMU_VMALLOC_ALIGN; + + if (size < align) { + align = getpagesize(); } - ptr = oom_check(malloc(size ? size : 1)); - trace_qemu_malloc(size, ptr); /* <-- trace event */ + ptr = qemu_memalign(align, size); + trace_qemu_vmalloc(size, ptr); return ptr; } @@ -70,20 +72,12 @@ Trace events should use types as follows: cannot include all user-defined struct declarations and it is therefore necessary to use void * for pointers to structs. - Pointers (including char *) cannot be dereferenced easily (or at all) in - some trace backends. If pointers are used, ensure they are meaningful by - themselves and do not assume the data they point to will be traced. Do - not pass in string arguments. - * For everything else, use primitive scalar types (char, int, long) with the appropriate signedness. Format strings should reflect the types defined in the trace event. Take special care to use PRId64 and PRIu64 for int64_t and uint64_t types, -respectively. This ensures portability between 32- and 64-bit platforms. Note -that format strings must begin and end with double quotes. When using -portability macros, ensure they are preceded and followed by double quotes: -"value %"PRIx64"". +respectively. This ensures portability between 32- and 64-bit platforms. === Hints for adding new trace events === @@ -185,6 +179,9 @@ source tree. It may not be as powerful as platform-specific or third-party trace backends but it is portable. This is the recommended trace backend unless you have specific needs for more advanced backends. +The "simple" backend currently does not capture string arguments, it simply +records the char* pointer value instead of the string that is pointed to. + ==== Monitor commands ==== * info trace @@ -125,6 +125,8 @@ typedef int64_t Elf64_Sxword; #define EM_MICROBLAZE 189 #define EM_MICROBLAZE_OLD 0xBAAB +#define EM_XTENSA 94 /* Tensilica Xtensa */ + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 #define DT_NEEDED 1 @@ -183,7 +183,6 @@ typedef struct PageDesc { #define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS) unsigned long qemu_real_host_page_size; -unsigned long qemu_host_page_bits; unsigned long qemu_host_page_size; unsigned long qemu_host_page_mask; @@ -274,9 +273,6 @@ static void page_init(void) qemu_host_page_size = qemu_real_host_page_size; if (qemu_host_page_size < TARGET_PAGE_SIZE) qemu_host_page_size = TARGET_PAGE_SIZE; - qemu_host_page_bits = 0; - while ((1 << qemu_host_page_bits) < qemu_host_page_size) - qemu_host_page_bits++; qemu_host_page_mask = ~(qemu_host_page_size - 1); #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY) @@ -41,6 +41,15 @@ #include "qemu_socket.h" #include "kvm.h" +#ifndef TARGET_CPU_MEMORY_RW_DEBUG +static inline int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + return cpu_memory_rw_debug(env, addr, buf, len, is_write); +} +#else +/* target_memory_rw_debug() defined in cpu.h */ +#endif enum { GDB_SIGNAL_0 = 0, @@ -1541,6 +1550,94 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) } 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(CPUState *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 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(CPUState *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 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 @@ -1557,7 +1654,9 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) #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. */ @@ -1654,6 +1753,7 @@ static int gdb_write_register(CPUState *env, 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 @@ -1693,6 +1793,7 @@ void gdb_register_coprocessor(CPUState * env, } } } +#endif #ifndef CONFIG_USER_ONLY static const int xlat_gdb_type[] = { @@ -1818,6 +1919,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) s->c_cpu->psw.addr = pc; #elif defined (TARGET_LM32) s->c_cpu->pc = pc; +#elif defined(TARGET_XTENSA) + s->c_cpu->pc = pc; #endif } @@ -1988,6 +2091,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; case 'g': cpu_synchronize_state(s->g_cpu); + env = s->g_cpu; len = 0; for (addr = 0; addr < num_g_regs; addr++) { reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr); @@ -1998,6 +2102,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; case 'G': cpu_synchronize_state(s->g_cpu); + env = s->g_cpu; registers = mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); @@ -2013,7 +2118,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ',') p++; len = strtoull(p, NULL, 16); - if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { + if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { memtohex(buf, mem_buf, len); @@ -2028,10 +2133,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ':') p++; hextomem(mem_buf, p, len); - if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) + if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) { put_packet(s, "E14"); - else + } else { put_packet(s, "OK"); + } break; case 'p': /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable. @@ -2267,7 +2373,7 @@ void gdb_set_stop_cpu(CPUState *env) } #ifndef CONFIG_USER_ONLY -static void gdb_vm_state_change(void *opaque, int running, int reason) +static void gdb_vm_state_change(void *opaque, int running, RunState state) { GDBState *s = gdbserver_state; CPUState *env = s->c_cpu; @@ -2278,8 +2384,8 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) { return; } - switch (reason) { - case VMSTOP_DEBUG: + switch (state) { + case RSTATE_DEBUG: if (env->watchpoint_hit) { switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: @@ -2302,25 +2408,25 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) tb_flush(env); ret = GDB_SIGNAL_TRAP; break; - case VMSTOP_USER: + case RSTATE_PAUSED: ret = GDB_SIGNAL_INT; break; - case VMSTOP_SHUTDOWN: + case RSTATE_SHUTDOWN: ret = GDB_SIGNAL_QUIT; break; - case VMSTOP_DISKFULL: + case RSTATE_IO_ERROR: ret = GDB_SIGNAL_IO; break; - case VMSTOP_WATCHDOG: + case RSTATE_WATCHDOG: ret = GDB_SIGNAL_ALRM; break; - case VMSTOP_PANIC: + case RSTATE_PANICKED: ret = GDB_SIGNAL_ABRT; break; - case VMSTOP_SAVEVM: - case VMSTOP_LOADVM: + case RSTATE_SAVEVM: + case RSTATE_RESTORE: return; - case VMSTOP_MIGRATE: + case RSTATE_PRE_MIGRATE: ret = GDB_SIGNAL_XCPU; break; default: @@ -2357,7 +2463,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) gdb_current_syscall_cb = cb; s->state = RS_SYSCALL; #ifndef CONFIG_USER_ONLY - vm_stop(VMSTOP_DEBUG); + vm_stop(RSTATE_DEBUG); #endif s->state = RS_IDLE; va_start(va, fmt); @@ -2428,10 +2534,10 @@ static void gdb_read_byte(GDBState *s, int ch) if (ch != '$') return; } - if (vm_running) { + if (runstate_is_running()) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ - vm_stop(VMSTOP_USER); + vm_stop(RSTATE_PAUSED); } else #endif { @@ -2693,7 +2799,7 @@ static void gdb_chr_event(void *opaque, int event) { switch (event) { case CHR_EVENT_OPENED: - vm_stop(VMSTOP_USER); + vm_stop(RSTATE_PAUSED); gdb_has_xml = 0; break; default: @@ -2733,8 +2839,8 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) #ifndef _WIN32 static void gdb_sigterm_handler(int signal) { - if (vm_running) { - vm_stop(VMSTOP_USER); + if (runstate_is_running()) { + vm_stop(RSTATE_PAUSED); } } #endif diff --git a/host-utils.h b/host-utils.h index 0ddc176582..821db93671 100644 --- a/host-utils.h +++ b/host-utils.h @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "osdep.h" +#include "compiler.h" /* QEMU_GNUC_PREREQ */ #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c index ae05658632..25556cc6a7 100644 --- a/hw/9pfs/virtio-9p-coth.c +++ b/hw/9pfs/virtio-9p-coth.c @@ -67,10 +67,6 @@ int v9fs_init_worker_threads(void) /* Leave signal handling to the iothread. */ pthread_sigmask(SIG_SETMASK, &set, &oldset); - /* init thread system if not already initialized */ - if (!g_thread_get_initialized()) { - g_thread_init(NULL); - } if (qemu_pipe(notifier_fds) == -1) { ret = -1; goto err_out; diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c index 4636ad51f0..96925f04a4 100644 --- a/hw/9pfs/virtio-9p-debug.c +++ b/hw/9pfs/virtio-9p-debug.c @@ -295,7 +295,7 @@ static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) if (rx) { count = pdu->elem.in_num; - } else + } else { count = pdu->elem.out_num; } diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 94b7090e7d..d28edb799a 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -543,6 +543,7 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp) { size_t size; + memset(&qidp->path, 0, sizeof(qidp->path)); size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path)); memcpy(&qidp->path, &stbuf->st_ino, size); qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8); @@ -2106,6 +2107,7 @@ static void v9fs_create(void *opaque) if (err < 0) { goto out; } + v9fs_string_copy(&fidp->path, &fullname); err = v9fs_co_opendir(pdu->s, fidp); if (err < 0) { goto out; @@ -2336,6 +2338,45 @@ out_nofid: complete_pdu(pdu->s, pdu, err); } +static void v9fs_unlinkat(void *opaque) +{ + int err = 0; + V9fsString name; + int32_t dfid, flags; + size_t offset = 7; + V9fsFidState *dfidp; + V9fsPDU *pdu = opaque; + V9fsString full_name; + + pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags); + + dfidp = get_fid(pdu->s, dfid); + if (dfidp == NULL) { + err = -EINVAL; + goto out_nofid; + } + v9fs_string_init(&full_name); + v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data); + /* + * IF the file is unlinked, we cannot reopen + * the file later. So don't reclaim fd + */ + err = v9fs_mark_fids_unreclaim(pdu->s, &full_name); + if (err < 0) { + goto out_err; + } + err = v9fs_co_remove(pdu->s, &full_name); + if (!err) { + err = offset; + } +out_err: + put_fid(pdu->s, dfidp); + v9fs_string_free(&full_name); +out_nofid: + complete_pdu(pdu->s, pdu, err); + v9fs_string_free(&name); +} + static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp, int32_t newdirfid, V9fsString *name) { @@ -2438,6 +2479,87 @@ out_nofid: v9fs_string_free(&name); } +static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid, + V9fsString *old_name, int32_t newdirfid, + V9fsString *new_name) +{ + int err = 0; + V9fsString old_full_name, new_full_name; + V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL; + + olddirfidp = get_fid(s, olddirfid); + if (olddirfidp == NULL) { + err = -ENOENT; + goto out; + } + v9fs_string_init(&old_full_name); + v9fs_string_init(&new_full_name); + + v9fs_string_sprintf(&old_full_name, "%s/%s", + olddirfidp->path.data, old_name->data); + if (newdirfid != -1) { + newdirfidp = get_fid(s, newdirfid); + if (newdirfidp == NULL) { + err = -ENOENT; + goto out; + } + v9fs_string_sprintf(&new_full_name, "%s/%s", + newdirfidp->path.data, new_name->data); + } else { + v9fs_string_sprintf(&new_full_name, "%s/%s", + olddirfidp->path.data, new_name->data); + } + + if (strcmp(old_full_name.data, new_full_name.data) != 0) { + V9fsFidState *tfidp; + err = v9fs_co_rename(s, &old_full_name, &new_full_name); + if (err < 0) { + goto out; + } + /* + * Fixup fid's pointing to the old name to + * start pointing to the new name + */ + for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) { + if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) { + /* replace the name */ + v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size); + } + } + } +out: + if (olddirfidp) { + put_fid(s, olddirfidp); + } + if (newdirfidp) { + put_fid(s, newdirfidp); + } + v9fs_string_free(&old_full_name); + v9fs_string_free(&new_full_name); + return err; +} + +static void v9fs_renameat(void *opaque) +{ + ssize_t err = 0; + size_t offset = 7; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; + int32_t olddirfid, newdirfid; + V9fsString old_name, new_name; + + pdu_unmarshal(pdu, offset, "dsds", &olddirfid, + &old_name, &newdirfid, &new_name); + + err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name); + if (!err) { + err = offset; + } + complete_pdu(s, pdu, err); + v9fs_string_free(&old_name); + v9fs_string_free(&new_name); +} + static void v9fs_wstat(void *opaque) { int32_t fid; @@ -2694,6 +2816,7 @@ out_nofid: err = offset; err += pdu_marshal(pdu, offset, "b", status); complete_pdu(s, pdu, err); + v9fs_string_free(&flock->client_id); g_free(flock); } @@ -2734,6 +2857,7 @@ out: put_fid(s, fidp); out_nofid: complete_pdu(s, pdu, err); + v9fs_string_free(&glock->client_id); g_free(glock); } @@ -2953,7 +3077,9 @@ static CoroutineEntry *pdu_co_handlers[] = { [P9_TRENAME] = v9fs_rename, [P9_TLOCK] = v9fs_lock, [P9_TGETLOCK] = v9fs_getlock, + [P9_TRENAMEAT] = v9fs_renameat, [P9_TREADLINK] = v9fs_readlink, + [P9_TUNLINKAT] = v9fs_unlinkat, [P9_TMKDIR] = v9fs_mkdir, [P9_TVERSION] = v9fs_version, [P9_TLOPEN] = v9fs_open, diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 9d1b508e16..17d44b41ca 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -50,6 +50,10 @@ enum { P9_RLINK, P9_TMKDIR = 72, P9_RMKDIR, + P9_TRENAMEAT = 74, + P9_RRENAMEAT, + P9_TUNLINKAT = 76, + P9_RUNLINKAT, P9_TVERSION = 100, P9_RVERSION, P9_TAUTH = 102, @@ -1311,7 +1311,6 @@ static int ac97_initfn (PCIDevice *dev) c[PCI_SUBSYSTEM_ID + 1] = 0x00; c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */ - /* TODO: RST# value should be 0. */ c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */ memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024); diff --git a/hw/adlib.c b/hw/adlib.c index c1c46e3573..e4bfcc6420 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -119,7 +119,6 @@ static IO_WRITE_PROTO (adlib_write) { AdlibState *s = opaque; int a = nport & 3; - int status; s->active = 1; AUD_set_active_out (s->voice, 1); @@ -127,9 +126,9 @@ static IO_WRITE_PROTO (adlib_write) adlib_kill_timers (s); #ifdef HAS_YMF262 - status = YMF262Write (0, a, val); + YMF262Write (0, a, val); #else - status = OPLWrite (s->opl, a, val); + OPLWrite (s->opl, a, val); #endif } diff --git a/hw/bonito.c b/hw/bonito.c index 8708e95688..fdb8198f62 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -241,7 +241,7 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val) saddr = (addr - BONITO_REGBASE) >> 2; - DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x \n", addr, val, saddr); + DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr); switch (saddr) { case BONITO_BONPONCFG: case BONITO_IODEVCFG: @@ -287,10 +287,10 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val) break; case BONITO_INTEN: case BONITO_INTISR: - DPRINTF("write to readonly bonito register %x \n", saddr); + DPRINTF("write to readonly bonito register %x\n", saddr); break; default: - DPRINTF("write to unknown bonito register %x \n", saddr); + DPRINTF("write to unknown bonito register %x\n", saddr); break; } } @@ -302,7 +302,7 @@ static uint32_t bonito_readl(void *opaque, target_phys_addr_t addr) saddr = (addr - BONITO_REGBASE) >> 2; - DPRINTF("bonito_readl "TARGET_FMT_plx" \n", addr); + DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr); switch (saddr) { case BONITO_INTISR: return s->regs[saddr]; @@ -328,7 +328,7 @@ static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr, { PCIBonitoState *s = opaque; - DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x \n", addr, val); + DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val); s->dev.config_write(&s->dev, addr, val, 4); } @@ -443,7 +443,7 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr) exit(1); } pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno); - DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d \n", + DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n", cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno); return pciaddr; @@ -456,7 +456,7 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr, uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x \n", addr, val); + DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x\n", addr, val); pciaddr = bonito_sbridge_pciaddr(s, addr); if (pciaddr == 0xffffffff) { @@ -480,7 +480,7 @@ static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr, uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x \n", addr, val); + DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val); assert((addr&0x1)==0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -506,7 +506,7 @@ static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr, uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x \n", addr, val); + DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val); assert((addr&0x3)==0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -531,7 +531,7 @@ static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr) uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx" \n", addr); + DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"\n", addr); pciaddr = bonito_sbridge_pciaddr(s, addr); if (pciaddr == 0xffffffff) { @@ -555,7 +555,7 @@ static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr) uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx" \n", addr); + DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr); assert((addr&0x1)==0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -581,7 +581,7 @@ static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr) uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx" \n", addr); + DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr); assert((addr&0x3) == 0); pciaddr = bonito_sbridge_pciaddr(s, addr); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index ec7ea8207b..c7e365b2a6 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2401,7 +2401,7 @@ static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank) static void map_linear_vram(CirrusVGAState *s) { - if (!s->linear_vram) { + if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) { s->linear_vram = true; memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1); } @@ -2411,7 +2411,7 @@ static void map_linear_vram(CirrusVGAState *s) static void unmap_linear_vram(CirrusVGAState *s) { - if (s->linear_vram) { + if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) { s->linear_vram = false; memory_region_del_subregion(&s->pci_bar, &s->vga.vram); } diff --git a/hw/e1000.c b/hw/e1000.c index a6d12c55fb..ce8fc8b510 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1151,13 +1151,10 @@ static int pci_e1000_init(PCIDevice *pci_dev) pci_conf = d->dev.config; - /* TODO: we have no capabilities, so why is this bit set? */ - pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST); /* TODO: RST# value should be 0, PCI spec 6.2.4 */ pci_conf[PCI_CACHE_LINE_SIZE] = 0x10; - /* TODO: RST# value should be 0 if programmable, PCI spec 6.2.4 */ - pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ e1000_mmio_setup(d); diff --git a/hw/es1370.c b/hw/es1370.c index a9387d15cc..2daadde0e6 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1003,7 +1003,6 @@ static int es1370_initfn (PCIDevice *dev) c[0xdc] = 0x00; #endif - /* TODO: RST# value should be 0. */ c[PCI_INTERRUPT_PIN] = 1; c[PCI_MIN_GNT] = 0x0c; c[PCI_MAX_LAT] = 0x80; diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index e8ad9e6a0b..d3082acc8f 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -732,7 +732,7 @@ static void DMA_run(void *opaque) struct fs_dma_ctrl *etraxfs_dmac = opaque; int p = 1; - if (vm_running) + if (runstate_is_running()) p = etraxfs_dmac_run(etraxfs_dmac); if (p) @@ -36,7 +36,6 @@ #include "qdev-addr.h" #include "blockdev.h" #include "sysemu.h" -#include "block_int.h" /********************************************************/ /* debug Floppy devices */ @@ -1778,7 +1777,7 @@ static void fdctrl_result_timer(void *opaque) fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } -static void fdctrl_change_cb(void *opaque) +static void fdctrl_change_cb(void *opaque, bool load) { FDrive *drive = opaque; @@ -1813,7 +1812,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) fd_revalidate(drive); if (drive->bs) { drive->media_changed = 1; - bdrv_set_removable(drive->bs, 1); bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive); } } diff --git a/hw/fmopl.c b/hw/fmopl.c index d8a0f36b35..5ad52ab7d2 100644 --- a/hw/fmopl.c +++ b/hw/fmopl.c @@ -606,7 +606,7 @@ static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) } #if 0 for (i = 0;i < 64 ;i++){ /* make for overflow area */ - LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i, + LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i, ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate), ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) )); } diff --git a/hw/g364fb.c b/hw/g364fb.c index 5e7bcfa278..b43341f8d7 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -58,6 +58,8 @@ typedef struct G364State { #define CTLA_FORCE_BLANK 0x00000400 #define CTLA_NO_CURSOR 0x00800000 +#define G364_PAGE_SIZE 4096 + static inline int check_dirty(G364State *s, ram_addr_t page) { return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA); @@ -68,7 +70,7 @@ static inline void reset_dirty(G364State *s, { memory_region_reset_dirty(&s->mem_vram, page_min, - page_max + TARGET_PAGE_SIZE - page_min - 1, + page_max + G364_PAGE_SIZE - page_min - 1, DIRTY_MEMORY_VGA); } @@ -136,7 +138,7 @@ static void g364fb_draw_graphic8(G364State *s) page_max = page; if (x < xmin) xmin = x; - for (i = 0; i < TARGET_PAGE_SIZE; i++) { + for (i = 0; i < G364_PAGE_SIZE; i++) { uint8_t index; unsigned int color; if (unlikely((y >= ycursor && y < ycursor + 64) && @@ -200,15 +202,15 @@ static void g364fb_draw_graphic8(G364State *s) ymin = s->height; ymax = 0; } - x += TARGET_PAGE_SIZE; + x += G364_PAGE_SIZE; dy = x / s->width; x = x % s->width; y += dy; - vram += TARGET_PAGE_SIZE; + vram += G364_PAGE_SIZE; data_display += dy * ds_get_linesize(s->ds); dd = data_display + x * w; } - page += TARGET_PAGE_SIZE; + page += G364_PAGE_SIZE; } done: @@ -267,7 +269,7 @@ static inline void g364fb_invalidate_display(void *opaque) int i; s->blanked = 0; - for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) { + for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) { memory_region_set_dirty(&s->mem_vram, i); } } @@ -387,7 +389,7 @@ static void g364_invalidate_cursor_position(G364State *s) start = ymin * ds_get_linesize(s->ds); end = (ymax + 1) * ds_get_linesize(s->ds); - for (i = start; i < end; i += TARGET_PAGE_SIZE) { + for (i = start; i < end; i += G364_PAGE_SIZE) { memory_region_set_dirty(&s->mem_vram, i); } } @@ -96,7 +96,7 @@ static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, /* Windows drivers do not like the 0/0 position and ignore such * events. */ if (!(x1 | y1)) { - x1 = 1; + e->xdx = 1; } } e->dz += z1; @@ -397,7 +397,7 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr) case HPET_CFG: return s->config; case HPET_CFG + 4: - DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n"); + DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n"); return 0; case HPET_COUNTER: if (hpet_enabled(s)) { @@ -458,7 +458,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, uint8_t timer_id = (addr - 0x100) / 0x20; HPETTimer *timer = &s->timer[timer_id]; - DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id); + DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id); if (timer_id > s->num_timers) { DPRINTF("qemu: timer id out of range\n"); return; @@ -485,7 +485,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n"); break; case HPET_TN_CMP: // comparator register - DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n"); + DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n"); if (timer->config & HPET_TN_32BIT) { new_val = (uint32_t)new_val; } @@ -570,7 +570,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, } break; case HPET_CFG + 4: - DPRINTF("qemu: invalid HPET_CFG+4 write \n"); + DPRINTF("qemu: invalid HPET_CFG+4 write\n"); break; case HPET_STATUS: val = new_val & s->isr; diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index f4fa1545bd..1c7e3a00b5 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -370,6 +370,43 @@ static MemoryRegionOps ahci_mem_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + AHCIState *s = opaque; + + if (addr == s->idp_offset) { + /* index register */ + return s->idp_index; + } else if (addr == s->idp_offset + 4) { + /* data register - do memory read at location selected by index */ + return ahci_mem_read(opaque, s->idp_index, size); + } else { + return 0; + } +} + +static void ahci_idp_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + AHCIState *s = opaque; + + if (addr == s->idp_offset) { + /* index register - mask off reserved bits */ + s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3); + } else if (addr == s->idp_offset + 4) { + /* data register - do memory write at location selected by index */ + ahci_mem_write(opaque, s->idp_index, val, size); + } +} + +static MemoryRegionOps ahci_idp_ops = { + .read = ahci_idp_read, + .write = ahci_idp_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + static void ahci_reg_init(AHCIState *s) { int i; @@ -499,10 +536,7 @@ static void ahci_reset_port(AHCIState *s, int port) ide_bus_reset(&d->port); ide_state->ncq_queues = AHCI_MAX_CMDS; - pr->irq_stat = 0; - pr->irq_mask = 0; pr->scr_stat = 0; - pr->scr_ctl = 0; pr->scr_err = 0; pr->scr_act = 0; d->busy_slot = -1; @@ -754,7 +788,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, case READ_FPDMA_QUEUED: DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n", ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag); - ncq_tfs->is_read = 1; DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba); @@ -768,7 +801,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, case WRITE_FPDMA_QUEUED: DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n", ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag); - ncq_tfs->is_read = 0; DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba); @@ -1105,7 +1137,7 @@ static void ahci_irq_set(void *opaque, int n, int level) { } -static void ahci_dma_restart_cb(void *opaque, int running, int reason) +static void ahci_dma_restart_cb(void *opaque, int running, RunState state) { } @@ -1135,7 +1167,9 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports) s->dev = g_malloc0(sizeof(AHCIDevice) * ports); ahci_reg_init(s); /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */ - memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", 0x1000); + memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", AHCI_MEM_BAR_SIZE); + memory_region_init_io(&s->idp, &ahci_idp_ops, s, "ahci-idp", 32); + irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports); for (i = 0; i < s->ports; i++) { @@ -1155,18 +1189,24 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports) void ahci_uninit(AHCIState *s) { memory_region_destroy(&s->mem); + memory_region_destroy(&s->idp); g_free(s->dev); } void ahci_reset(void *opaque) { struct AHCIPCIState *d = opaque; + AHCIPortRegs *pr; int i; d->ahci.control_regs.irqstatus = 0; d->ahci.control_regs.ghc = 0; for (i = 0; i < d->ahci.ports; i++) { + pr = &d->ahci.dev[i].port_regs; + pr->irq_stat = 0; + pr->irq_mask = 0; + pr->scr_ctl = 0; ahci_reset_port(&d->ahci, i); } } diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 3c29d93b47..b223d2c055 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -24,7 +24,7 @@ #ifndef HW_IDE_AHCI_H #define HW_IDE_AHCI_H -#define AHCI_PCI_BAR 5 +#define AHCI_MEM_BAR_SIZE 0x1000 #define AHCI_MAX_PORTS 32 #define AHCI_MAX_SG 168 /* hardware max is 64K */ #define AHCI_DMA_BOUNDARY 0xffffffff @@ -212,6 +212,10 @@ #define RES_FIS_SDBFIS 0x58 #define RES_FIS_UFIS 0x60 +#define SATA_CAP_SIZE 0x8 +#define SATA_CAP_REV 0x2 +#define SATA_CAP_BAR 0x4 + typedef struct AHCIControlRegs { uint32_t cap; uint32_t ghc; @@ -259,7 +263,6 @@ typedef struct NCQTransferState { BlockDriverAIOCB *aiocb; QEMUSGList sglist; BlockAcctCookie acct; - int is_read; uint16_t sector_count; uint64_t lba; uint8_t tag; @@ -291,6 +294,9 @@ typedef struct AHCIState { AHCIDevice *dev; AHCIControlRegs control_regs; MemoryRegion mem; + MemoryRegion idp; /* Index-Data Pair I/O port space */ + unsigned idp_offset; /* Offset of index in I/O port space */ + uint32_t idp_index; /* Current IDP index */ int ports; qemu_irq irq; } AHCIState; diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index f38d2896ae..3f909c3a99 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -73,7 +73,7 @@ static void lba_to_msf(uint8_t *buf, int lba) static inline int media_present(IDEState *s) { - return (s->nb_sectors > 0); + return !s->tray_open && s->nb_sectors > 0; } /* XXX: DVDs that could fit on a CD will be reported as a CD */ @@ -521,7 +521,7 @@ static unsigned int event_status_media(IDEState *s, uint8_t event_code, media_status; media_status = 0; - if (s->bs->tray_open) { + if (s->tray_open) { media_status = MS_TRAY_OPEN; } else if (bdrv_is_inserted(s->bs)) { media_status = MS_MEDIA_PRESENT; @@ -788,8 +788,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) buf[12] = 0x71; buf[13] = 3 << 5; buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (bdrv_is_locked(s->bs)) + if (s->tray_locked) { buf[6] |= 1 << 1; + } buf[15] = 0x00; cpu_to_ube16(&buf[16], 706); buf[18] = 0; @@ -831,7 +832,8 @@ static void cmd_test_unit_ready(IDEState *s, uint8_t *buf) static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf) { - bdrv_set_locked(s->bs, buf[4] & 1); + s->tray_locked = buf[4] & 1; + bdrv_lock_medium(s->bs, buf[4] & 1); ide_atapi_cmd_ok(s); } @@ -903,29 +905,22 @@ static void cmd_seek(IDEState *s, uint8_t* buf) static void cmd_start_stop_unit(IDEState *s, uint8_t* buf) { - int start, eject, sense, err = 0; - start = buf[4] & 1; - eject = (buf[4] >> 1) & 1; - - if (eject) { - err = bdrv_eject(s->bs, !start); - } - - switch (err) { - case 0: - ide_atapi_cmd_ok(s); - break; - case -EBUSY: - sense = SENSE_NOT_READY; - if (bdrv_is_inserted(s->bs)) { - sense = SENSE_ILLEGAL_REQUEST; + int sense; + bool start = buf[4] & 1; + bool loej = buf[4] & 2; /* load on start, eject on !start */ + + if (loej) { + if (!start && !s->tray_open && s->tray_locked) { + sense = bdrv_is_inserted(s->bs) + ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST; + ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); + return; } - ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); - break; - default: - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - break; + bdrv_eject(s->bs, !start); + s->tray_open = !start; } + + ide_atapi_cmd_ok(s); } static void cmd_mechanism_status(IDEState *s, uint8_t* buf) @@ -1073,20 +1068,21 @@ static const struct { [ 0x03 ] = { cmd_request_sense, ALLOW_UA }, [ 0x12 ] = { cmd_inquiry, ALLOW_UA }, [ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 }, - [ 0x1b ] = { cmd_start_stop_unit, 0 }, + [ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */ [ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 }, [ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY }, - [ 0x28 ] = { cmd_read, /* (10) */ 0 }, + [ 0x28 ] = { cmd_read, /* (10) */ CHECK_READY }, [ 0x2b ] = { cmd_seek, CHECK_READY }, [ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY }, [ 0x46 ] = { cmd_get_configuration, ALLOW_UA }, [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA }, [ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 }, - [ 0xa8 ] = { cmd_read, /* (12) */ 0 }, - [ 0xad ] = { cmd_read_dvd_structure, 0 }, + [ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY }, + [ 0xad ] = { cmd_read_dvd_structure, CHECK_READY }, [ 0xbb ] = { cmd_set_speed, 0 }, [ 0xbd ] = { cmd_mechanism_status, 0 }, - [ 0xbe ] = { cmd_read_cd, 0 }, + [ 0xbe ] = { cmd_read_cd, CHECK_READY }, + /* [1] handler detects and reports not ready condition itself */ }; void ide_atapi_cmd(IDEState *s) @@ -1122,7 +1118,7 @@ void ide_atapi_cmd(IDEState *s) * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close * states rely on this behavior. */ - if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { + if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); s->cdrom_changed = 0; diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 4d91e2c642..5fe98b1bb3 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -27,7 +27,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/ide/core.c b/hw/ide/core.c index 1806e008bc..4e76fc78d3 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -30,6 +30,7 @@ #include "sysemu.h" #include "dma.h" #include "blockdev.h" +#include "block_int.h" #include <hw/ide/internal.h> @@ -526,7 +527,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) s->bus->dma->ops->set_unit(s->bus->dma, s->unit); s->bus->error_status = op; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(VMSTOP_DISKFULL); + vm_stop(RSTATE_IO_ERROR); } else { if (op & BM_STATUS_DMA_RETRY) { dma_buf_commit(s, 0); @@ -602,7 +603,7 @@ handle_rw_error: break; case IDE_DMA_TRIM: s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num, - ide_issue_trim, ide_dma_cb, s, 1); + ide_issue_trim, ide_dma_cb, s, true); break; } @@ -783,11 +784,12 @@ static void ide_cfata_metadata_write(IDEState *s) } /* called when the inserted state of the media has changed */ -static void ide_cd_change_cb(void *opaque) +static void ide_cd_change_cb(void *opaque, bool load) { IDEState *s = opaque; uint64_t nb_sectors; + s->tray_open = !load; bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; @@ -901,6 +903,78 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } +#define HD_OK (1u << IDE_HD) +#define CD_OK (1u << IDE_CD) +#define CFA_OK (1u << IDE_CFATA) +#define HD_CFA_OK (HD_OK | CFA_OK) +#define ALL_OK (HD_OK | CD_OK | CFA_OK) + +/* See ACS-2 T13/2015-D Table B.2 Command codes */ +static const uint8_t ide_cmd_table[0x100] = { + /* NOP not implemented, mandatory for CD */ + [CFA_REQ_EXT_ERROR_CODE] = CFA_OK, + [WIN_DSM] = ALL_OK, + [WIN_DEVICE_RESET] = CD_OK, + [WIN_RECAL] = HD_CFA_OK, + [WIN_READ] = ALL_OK, + [WIN_READ_ONCE] = ALL_OK, + [WIN_READ_EXT] = HD_CFA_OK, + [WIN_READDMA_EXT] = HD_CFA_OK, + [WIN_READ_NATIVE_MAX_EXT] = HD_CFA_OK, + [WIN_MULTREAD_EXT] = HD_CFA_OK, + [WIN_WRITE] = HD_CFA_OK, + [WIN_WRITE_ONCE] = HD_CFA_OK, + [WIN_WRITE_EXT] = HD_CFA_OK, + [WIN_WRITEDMA_EXT] = HD_CFA_OK, + [CFA_WRITE_SECT_WO_ERASE] = CFA_OK, + [WIN_MULTWRITE_EXT] = HD_CFA_OK, + [WIN_WRITE_VERIFY] = HD_CFA_OK, + [WIN_VERIFY] = HD_CFA_OK, + [WIN_VERIFY_ONCE] = HD_CFA_OK, + [WIN_VERIFY_EXT] = HD_CFA_OK, + [WIN_SEEK] = HD_CFA_OK, + [CFA_TRANSLATE_SECTOR] = CFA_OK, + [WIN_DIAGNOSE] = ALL_OK, + [WIN_SPECIFY] = HD_CFA_OK, + [WIN_STANDBYNOW2] = ALL_OK, + [WIN_IDLEIMMEDIATE2] = ALL_OK, + [WIN_STANDBY2] = ALL_OK, + [WIN_SETIDLE2] = ALL_OK, + [WIN_CHECKPOWERMODE2] = ALL_OK, + [WIN_SLEEPNOW2] = ALL_OK, + [WIN_PACKETCMD] = CD_OK, + [WIN_PIDENTIFY] = CD_OK, + [WIN_SMART] = HD_CFA_OK, + [CFA_ACCESS_METADATA_STORAGE] = CFA_OK, + [CFA_ERASE_SECTORS] = CFA_OK, + [WIN_MULTREAD] = HD_CFA_OK, + [WIN_MULTWRITE] = HD_CFA_OK, + [WIN_SETMULT] = HD_CFA_OK, + [WIN_READDMA] = HD_CFA_OK, + [WIN_READDMA_ONCE] = HD_CFA_OK, + [WIN_WRITEDMA] = HD_CFA_OK, + [WIN_WRITEDMA_ONCE] = HD_CFA_OK, + [CFA_WRITE_MULTI_WO_ERASE] = CFA_OK, + [WIN_STANDBYNOW1] = ALL_OK, + [WIN_IDLEIMMEDIATE] = ALL_OK, + [WIN_STANDBY] = ALL_OK, + [WIN_SETIDLE1] = ALL_OK, + [WIN_CHECKPOWERMODE1] = ALL_OK, + [WIN_SLEEPNOW1] = ALL_OK, + [WIN_FLUSH_CACHE] = ALL_OK, + [WIN_FLUSH_CACHE_EXT] = HD_CFA_OK, + [WIN_IDENTIFY] = ALL_OK, + [WIN_SETFEATURES] = ALL_OK, + [IBM_SENSE_CONDITION] = CFA_OK, + [CFA_WEAR_LEVEL] = CFA_OK, + [WIN_READ_NATIVE_MAX] = ALL_OK, +}; + +static bool ide_cmd_permitted(IDEState *s, uint32_t cmd) +{ + return cmd < ARRAY_SIZE(ide_cmd_table) + && (ide_cmd_table[cmd] & (1u << s->drive_kind)); +} void ide_exec_cmd(IDEBus *bus, uint32_t val) { @@ -920,6 +994,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET) return; + if (!ide_cmd_permitted(s, val)) { + goto abort_cmd; + } + switch(val) { case WIN_DSM: switch (s->feature) { @@ -983,8 +1061,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) lba48 = 1; case WIN_READ: case WIN_READ_ONCE: - if (!s->bs) + if (s->drive_kind == IDE_CD) { + ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */ goto abort_cmd; + } ide_cmd_lba48_transform(s, lba48); s->req_nb_sectors = 1; ide_sector_read(s); @@ -1138,21 +1218,15 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case WIN_SEEK: - if(s->drive_kind == IDE_CD) - goto abort_cmd; /* XXX: Check that seek is within bounds */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; /* ATAPI commands */ case WIN_PIDENTIFY: - if (s->drive_kind == IDE_CD) { - ide_atapi_identify(s); - s->status = READY_STAT | SEEK_STAT; - ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); - } else { - ide_abort_command(s); - } + ide_atapi_identify(s); + s->status = READY_STAT | SEEK_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); ide_set_irq(s->bus); break; case WIN_DIAGNOSE: @@ -1169,15 +1243,11 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case WIN_DEVICE_RESET: - if (s->drive_kind != IDE_CD) - goto abort_cmd; ide_set_signature(s); s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; break; case WIN_PACKETCMD: - if (s->drive_kind != IDE_CD) - goto abort_cmd; /* overlapping commands not supported */ if (s->feature & 0x02) goto abort_cmd; @@ -1189,16 +1259,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) break; /* CF-ATA commands */ case CFA_REQ_EXT_ERROR_CODE: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; s->error = 0x09; /* miscellaneous error */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; case CFA_ERASE_SECTORS: case CFA_WEAR_LEVEL: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; if (val == CFA_WEAR_LEVEL) s->nsector = 0; if (val == CFA_ERASE_SECTORS) @@ -1208,8 +1274,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case CFA_TRANSLATE_SECTOR: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; s->error = 0x00; s->status = READY_STAT | SEEK_STAT; memset(s->io_buffer, 0, 0x200); @@ -1228,8 +1292,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case CFA_ACCESS_METADATA_STORAGE: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; switch (s->feature) { case 0x02: /* Inquiry Metadata Storage */ ide_cfata_metadata_inquiry(s); @@ -1248,8 +1310,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case IBM_SENSE_CONDITION: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; switch (s->feature) { case 0x01: /* sense temperature in device */ s->nsector = 0x50; /* +20 C */ @@ -1262,8 +1322,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) break; case WIN_SMART: - if (s->drive_kind == IDE_CD) - goto abort_cmd; if (s->hcyl != 0xc2 || s->lcyl != 0x4f) goto abort_cmd; if (!s->smart_enabled && s->feature != SMART_ENABLE) @@ -1418,6 +1476,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) } break; default: + /* should not be reachable */ abort_cmd: ide_abort_command(s); ide_set_irq(s->bus); @@ -1738,8 +1797,20 @@ void ide_bus_reset(IDEBus *bus) bus->dma->ops->reset(bus->dma); } +static bool ide_cd_is_tray_open(void *opaque) +{ + return ((IDEState *)opaque)->tray_open; +} + +static bool ide_cd_is_medium_locked(void *opaque) +{ + return ((IDEState *)opaque)->tray_locked; +} + static const BlockDevOps ide_cd_block_ops = { .change_media_cb = ide_cd_change_cb, + .is_tray_open = ide_cd_is_tray_open, + .is_medium_locked = ide_cd_is_medium_locked, }; int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, @@ -1777,7 +1848,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, s->smart_selftest_count = 0; if (kind == IDE_CD) { bdrv_set_dev_ops(bs, &ide_cd_block_ops, s); - bs->buffer_alignment = 2048; + bdrv_set_buffer_alignment(bs, 2048); } else { if (!bdrv_is_inserted(s->bs)) { error_report("Device needs media, but drive is empty"); @@ -1801,7 +1872,6 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, } ide_reset(s); - bdrv_set_removable(bs, s->drive_kind == IDE_CD); return 0; } @@ -1840,7 +1910,7 @@ static int ide_nop_int(IDEDMA *dma, int x) return 0; } -static void ide_nop_restart(void *opaque, int x, int y) +static void ide_nop_restart(void *opaque, int x, RunState y) { } @@ -1995,6 +2065,22 @@ static bool ide_drive_pio_state_needed(void *opaque) || (s->bus->error_status & BM_STATUS_PIO_RETRY); } +static int ide_tray_state_post_load(void *opaque, int version_id) +{ + IDEState *s = opaque; + + bdrv_eject(s->bs, s->tray_open); + bdrv_lock_medium(s->bs, s->tray_locked); + return 0; +} + +static bool ide_tray_state_needed(void *opaque) +{ + IDEState *s = opaque; + + return s->tray_open || s->tray_locked; +} + static bool ide_atapi_gesn_needed(void *opaque) { IDEState *s = opaque; @@ -2022,6 +2108,19 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = { } }; +static const VMStateDescription vmstate_ide_tray_state = { + .name = "ide_drive/tray_state", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ide_tray_state_post_load, + .fields = (VMStateField[]) { + VMSTATE_BOOL(tray_open, IDEState), + VMSTATE_BOOL(tray_locked, IDEState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, @@ -2076,6 +2175,9 @@ const VMStateDescription vmstate_ide_drive = { .vmsd = &vmstate_ide_drive_pio_state, .needed = ide_drive_pio_state_needed, }, { + .vmsd = &vmstate_ide_tray_state, + .needed = ide_tray_state_needed, + }, { .vmsd = &vmstate_ide_atapi_gesn_state, .needed = ide_atapi_gesn_needed, }, { diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 5278bc4d6c..3f7510f52e 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -66,12 +66,19 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/pci.h> #include <hw/ide/ahci.h> +#define ICH9_SATA_CAP_OFFSET 0xA8 + +#define ICH9_IDP_BAR 4 +#define ICH9_MEM_BAR 5 + +#define ICH9_IDP_INDEX 0x10 +#define ICH9_IDP_INDEX_LOG2 0x04 + static const VMStateDescription vmstate_ahci = { .name = "ahci", .unmigratable = 1, @@ -80,6 +87,8 @@ static const VMStateDescription vmstate_ahci = { static int pci_ich9_ahci_init(PCIDevice *dev) { struct AHCIPCIState *d; + int sata_cap_offset; + uint8_t *sata_cap; d = DO_UPCAST(struct AHCIPCIState, card, dev); ahci_init(&d->ahci, &dev->qdev, 6); @@ -98,7 +107,22 @@ static int pci_ich9_ahci_init(PCIDevice *dev) msi_init(dev, 0x50, 1, true, false); d->ahci.irq = d->card.irq[0]; - pci_register_bar(&d->card, 5, 0, &d->ahci.mem); + pci_register_bar(&d->card, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO, + &d->ahci.idp); + pci_register_bar(&d->card, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY, + &d->ahci.mem); + + sata_cap_offset = pci_add_capability(&d->card, PCI_CAP_ID_SATA, + ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE); + if (sata_cap_offset < 0) { + return sata_cap_offset; + } + + sata_cap = d->card.config + sata_cap_offset; + pci_set_word(sata_cap + SATA_CAP_REV, 0x10); + pci_set_long(sata_cap + SATA_CAP_BAR, + (ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4)); + d->ahci.idp_offset = ICH9_IDP_INDEX; return 0; } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 111785294d..9046e96013 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -7,9 +7,9 @@ * non-internal declarations are in hw/ide.h */ #include <hw/ide.h> -#include "block_int.h" #include "iorange.h" #include "dma.h" +#include "sysemu.h" /* debug IDE devices */ //#define DEBUG_IDE @@ -388,7 +388,7 @@ typedef void EndTransferFunc(IDEState *); typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *); typedef int DMAFunc(IDEDMA *); typedef int DMAIntFunc(IDEDMA *, int); -typedef void DMARestartFunc(void *, int, int); +typedef void DMARestartFunc(void *, int, RunState); struct unreported_events { bool eject_request; @@ -442,6 +442,8 @@ struct IDEState { struct unreported_events events; uint8_t sense_key; uint8_t asc; + bool tray_open; + bool tray_locked; uint8_t cdrom_changed; int packet_transfer_size; int elementary_transfer_size; diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 4ac745324c..28b69d2cc3 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -26,7 +26,6 @@ #include <hw/pc.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/macio.c b/hw/ide/macio.c index fdf5d75082..37b8239b4d 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -26,7 +26,6 @@ #include <hw/ppc_mac.h> #include <hw/mac_dbdma.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> @@ -157,7 +156,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) break; case IDE_DMA_TRIM: m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num, - ide_issue_trim, pmac_ide_transfer_cb, s, 1); + ide_issue_trim, pmac_ide_transfer_cb, s, true); break; } diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 91c0e3c89d..9eee5b50ba 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -26,7 +26,6 @@ #include <hw/pc.h> #include <hw/pcmcia.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 132b7517ba..2ec21b0163 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -24,7 +24,6 @@ */ #include <hw/hw.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/pci.c b/hw/ide/pci.c index d1a14d7cc1..f133c422b6 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -27,7 +27,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/pci.h> @@ -223,7 +222,7 @@ static void bmdma_restart_bh(void *opaque) } } -static void bmdma_restart_cb(void *opaque, int running, int reason) +static void bmdma_restart_cb(void *opaque, int running, RunState state) { IDEDMA *dma = opaque; BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); diff --git a/hw/ide/via.c b/hw/ide/via.c index c0b9d43827..dab8a39f57 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -28,7 +28,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 3c8982ea29..9a289b4776 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -14,6 +14,7 @@ #include "arm-misc.h" #include "net.h" #include "exec-memory.h" +#include "sysemu.h" typedef struct { SysBusDevice busdev; @@ -126,15 +127,20 @@ static void integratorcm_do_remap(integratorcm_state *s, int flash) static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) { if (value & 8) { - hw_error("Board reset\n"); + qemu_system_reset_request(); } - if ((s->cm_init ^ value) & 4) { + if ((s->cm_ctrl ^ value) & 4) { integratorcm_do_remap(s, (value & 4) == 0); } - if ((s->cm_init ^ value) & 1) { - printf("Green LED %s\n", (value & 1) ? "on" : "off"); + if ((s->cm_ctrl ^ value) & 1) { + /* (value & 1) != 0 means the green "MISC LED" is lit. + * We don't have any nice place to display LEDs. printf is a bad + * idea because Linux uses the LED as a heartbeat and the output + * will swamp anything else on the terminal. + */ } - s->cm_init = (s->cm_init & ~ 5) | (value ^ 5); + /* Note that the RESET bit [3] always reads as zero */ + s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5); } static void integratorcm_update(integratorcm_state *s) @@ -90,3 +90,17 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2) s[1] = irq2; return qemu_allocate_irqs(qemu_splitirq, s, 1)[0]; } + +static void proxy_irq_handler(void *opaque, int n, int level) +{ + qemu_irq **target = opaque; + + if (*target) { + qemu_set_irq((*target)[n], level); + } +} + +qemu_irq *qemu_irq_proxy(qemu_irq **target, int n) +{ + return qemu_allocate_irqs(proxy_irq_handler, target, n); +} @@ -33,4 +33,9 @@ qemu_irq qemu_irq_invert(qemu_irq irq); /* Returns a new IRQ which feeds into both the passed IRQs */ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2); +/* Returns a new IRQ set which connects 1:1 to another IRQ set, which + * may be set later. + */ +qemu_irq *qemu_irq_proxy(qemu_irq **target, int n); + #endif diff --git a/hw/kvmclock.c b/hw/kvmclock.c index b73aec409c..5388bc489d 100644 --- a/hw/kvmclock.c +++ b/hw/kvmclock.c @@ -46,7 +46,7 @@ static void kvmclock_pre_save(void *opaque) * it on next vmsave (which would return a different value). Will be reset * when the VM is continued. */ - s->clock_valid = !vm_running; + s->clock_valid = !runstate_is_running(); } static int kvmclock_post_load(void *opaque, int version_id) @@ -59,7 +59,8 @@ static int kvmclock_post_load(void *opaque, int version_id) return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); } -static void kvmclock_vm_state_change(void *opaque, int running, int reason) +static void kvmclock_vm_state_change(void *opaque, int running, + RunState state) { KVMClockState *s = opaque; diff --git a/hw/loader.c b/hw/loader.c index 8efb1466cd..5676c18214 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -779,13 +779,13 @@ void do_info_roms(Monitor *mon) QTAILQ_FOREACH(rom, &roms, next) { if (!rom->fw_file) { monitor_printf(mon, "addr=" TARGET_FMT_plx - " size=0x%06zx mem=%s name=\"%s\" \n", + " size=0x%06zx mem=%s name=\"%s\"\n", rom->addr, rom->romsize, rom->isrom ? "rom" : "ram", rom->name); } else { monitor_printf(mon, "fw=%s/%s" - " size=0x%06zx name=\"%s\" \n", + " size=0x%06zx name=\"%s\"\n", rom->fw_dir, rom->fw_file, rom->romsize, diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 1643a63ee8..75a03a74b9 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -15,7 +15,6 @@ #include "hw.h" #include "pci.h" #include "scsi.h" -#include "block_int.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG @@ -883,7 +882,6 @@ static void lsi_do_msgout(LSIState *s) int len; uint32_t current_tag; lsi_request *current_req, *p, *p_next; - int id; if (s->current) { current_tag = s->current->tag; @@ -892,7 +890,6 @@ static void lsi_do_msgout(LSIState *s) current_tag = s->select_tag; current_req = lsi_find_by_tag(s, current_tag); } - id = (current_tag >> 8) & 0xf; DPRINTF("MSG out len=%d\n", s->dbc); while (s->dbc) { @@ -977,9 +974,8 @@ static void lsi_do_msgout(LSIState *s) device, but this is currently not implemented (and seems not to be really necessary). So let's simply clear all queued commands for the current device: */ - id = current_tag & 0x0000ff00; QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) { - if ((p->tag & 0x0000ff00) == id) { + if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) { scsi_req_cancel(p->req); } } @@ -2110,8 +2106,7 @@ static int lsi_scsi_init(PCIDevice *dev) /* PCI latency timer = 255 */ pci_conf[PCI_LATENCY_TIMER] = 0xff; - /* TODO: RST# value should be 0 */ - /* Interrupt pin 1 */ + /* Interrupt pin A */ pci_conf[PCI_INTERRUPT_PIN] = 0x01; memory_region_init_io(&s->mmio_io, &lsi_mmio_ops, s, "lsi-mmio", 0x400); @@ -8,9 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic); /* bonito.c */ PCIBus *bonito_init(qemu_irq *pic); -/* mipsnet.c */ -void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); - /* jazz_led.c */ void jazz_led_init(target_phys_addr_t base); diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index abe30569f2..f52b8c5083 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -343,7 +343,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); if (via_devfn < 0) { - fprintf(stderr, "vt82c686b_init error \n"); + fprintf(stderr, "vt82c686b_init error\n"); exit(1); } diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index f3c9f93204..7cac5da920 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -52,44 +52,42 @@ static void main_cpu_reset(void *opaque) cpu_reset(env); } -static uint32_t rtc_readb(void *opaque, target_phys_addr_t addr) +static uint64_t rtc_read(void *opaque, target_phys_addr_t addr, unsigned size) { return cpu_inw(0x71); } -static void rtc_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void rtc_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) { cpu_outw(0x71, val & 0xff); } -static CPUReadMemoryFunc * const rtc_read[3] = { - rtc_readb, - rtc_readb, - rtc_readb, +static const MemoryRegionOps rtc_ops = { + .read = rtc_read, + .write = rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static CPUWriteMemoryFunc * const rtc_write[3] = { - rtc_writeb, - rtc_writeb, - rtc_writeb, -}; - -static void dma_dummy_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static uint64_t dma_dummy_read(void *opaque, target_phys_addr_t addr, + unsigned size) { /* Nothing to do. That is only to ensure that * the current DMA acknowledge cycle is completed. */ + return 0xff; } -static CPUReadMemoryFunc * const dma_dummy_read[3] = { - NULL, - NULL, - NULL, -}; +static void dma_dummy_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + /* Nothing to do. That is only to ensure that + * the current DMA acknowledge cycle is completed. */ +} -static CPUWriteMemoryFunc * const dma_dummy_write[3] = { - dma_dummy_writeb, - dma_dummy_writeb, - dma_dummy_writeb, +static const MemoryRegionOps dma_dummy_ops = { + .read = dma_dummy_read, + .write = dma_dummy_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; #define MAGNUM_BIOS_SIZE_MAX 0x7e000 @@ -105,7 +103,7 @@ static void cpu_request_exit(void *opaque, int irq, int level) } static -void mips_jazz_init (ram_addr_t ram_size, +void mips_jazz_init (MemoryRegion *address_space, ram_addr_t ram_size, const char *cpu_model, enum jazz_model_e jazz_model) { @@ -115,7 +113,8 @@ void mips_jazz_init (ram_addr_t ram_size, qemu_irq *rc4030, *i8259; rc4030_dma *dmas; void* rc4030_opaque; - int s_rtc, s_dma_dummy; + MemoryRegion *rtc = g_new(MemoryRegion, 1); + MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); NICInfo *nd; DeviceState *dev; SysBusDevice *sysbus; @@ -123,8 +122,9 @@ void mips_jazz_init (ram_addr_t ram_size, DriveInfo *fds[MAX_FD]; qemu_irq esp_reset, dma_enable; qemu_irq *cpu_exit_irq; - ram_addr_t ram_offset; - ram_addr_t bios_offset; + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); + MemoryRegion *bios2 = g_new(MemoryRegion, 1); /* init CPUs */ if (cpu_model == NULL) { @@ -143,14 +143,15 @@ void mips_jazz_init (ram_addr_t ram_size, qemu_register_reset(main_cpu_reset, env); /* allocate RAM */ - ram_offset = qemu_ram_alloc(NULL, "mips_jazz.ram", ram_size); - cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); + memory_region_init_ram(ram, NULL, "mips_jazz.ram", ram_size); + memory_region_add_subregion(address_space, 0, ram); - bios_offset = qemu_ram_alloc(NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE); - cpu_register_physical_memory(0x1fc00000LL, - MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM); - cpu_register_physical_memory(0xfff00000LL, - MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM); + memory_region_init_ram(bios, NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE); + memory_region_set_readonly(bios, true); + memory_region_init_alias(bios2, "mips_jazz.bios", bios, + 0, MAGNUM_BIOS_SIZE); + memory_region_add_subregion(address_space, 0x1fc00000LL, bios); + memory_region_add_subregion(address_space, 0xfff00000LL, bios2); /* load the BIOS image. */ if (bios_name == NULL) @@ -175,9 +176,8 @@ void mips_jazz_init (ram_addr_t ram_size, /* Chipset */ rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas); - s_dma_dummy = cpu_register_io_memory(dma_dummy_read, dma_dummy_write, NULL, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy); + memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000); + memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); /* ISA devices */ i8259 = i8259_init(env->irq[4]); @@ -203,10 +203,11 @@ void mips_jazz_init (ram_addr_t ram_size, sysbus_connect_irq(sysbus, 0, rc4030[3]); { /* Simple ROM, so user doesn't have to provide one */ - ram_addr_t rom_offset = qemu_ram_alloc(NULL, "g364fb.rom", 0x80000); - uint8_t *rom = qemu_get_ram_ptr(rom_offset); - cpu_register_physical_memory(0x60000000, 0x80000, - rom_offset | IO_MEM_ROM); + MemoryRegion *rom_mr = g_new(MemoryRegion, 1); + memory_region_init_ram(rom_mr, NULL, "g364fb.rom", 0x80000); + memory_region_set_readonly(rom_mr, true); + uint8_t *rom = memory_region_get_ram_ptr(rom_mr); + memory_region_add_subregion(address_space, 0x60000000, rom_mr); rom[0] = 0x10; /* Mips G364 */ } break; @@ -252,9 +253,8 @@ void mips_jazz_init (ram_addr_t ram_size, /* Real time clock */ rtc_init(1980, NULL); - s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc); + memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000); + memory_region_add_subregion(address_space, 0x80004000, rtc); /* Keyboard (i8042) */ i8042_mm_init(rc4030[6], rc4030[7], 0x80005000, 0x1000, 0x1); @@ -299,7 +299,7 @@ void mips_magnum_init (ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - mips_jazz_init(ram_size, cpu_model, JAZZ_MAGNUM); + mips_jazz_init(get_system_memory(), ram_size, cpu_model, JAZZ_MAGNUM); } static @@ -308,7 +308,7 @@ void mips_pica61_init (ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - mips_jazz_init(ram_size, cpu_model, JAZZ_PICA61); + mips_jazz_init(get_system_memory(), ram_size, cpu_model, JAZZ_PICA61); } static QEMUMachine mips_magnum_machine = { diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e7cdf2091b..0110daa1a3 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -57,6 +57,9 @@ #define MAX_IDE_BUS 2 typedef struct { + MemoryRegion iomem; + MemoryRegion iomem_lo; /* 0 - 0x900 */ + MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */ uint32_t leds; uint32_t brk; uint32_t gpout; @@ -215,7 +218,8 @@ static void eeprom24c0x_write(int scl, int sda) eeprom.sda = sda; } -static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) +static uint64_t malta_fpga_read(void *opaque, target_phys_addr_t addr, + unsigned size) { MaltaFPGAState *s = opaque; uint32_t val = 0; @@ -302,8 +306,8 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) return val; } -static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) +static void malta_fpga_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) { MaltaFPGAState *s = opaque; uint32_t saddr; @@ -328,7 +332,7 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, /* ASCIIWORD Register */ case 0x00410: - snprintf(s->display_text, 9, "%08X", val); + snprintf(s->display_text, 9, "%08X", (uint32_t)val); malta_fpga_update_display(s); break; @@ -388,16 +392,10 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const malta_fpga_read[] = { - malta_fpga_readl, - malta_fpga_readl, - malta_fpga_readl -}; - -static CPUWriteMemoryFunc * const malta_fpga_write[] = { - malta_fpga_writel, - malta_fpga_writel, - malta_fpga_writel +static const MemoryRegionOps malta_fpga_ops = { + .read = malta_fpga_read, + .write = malta_fpga_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void malta_fpga_reset(void *opaque) @@ -429,20 +427,22 @@ static void malta_fpga_led_init(CharDriverState *chr) qemu_chr_fe_printf(chr, "+--------+\r\n"); } -static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr) +static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space, + target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr) { MaltaFPGAState *s; - int malta; s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState)); - malta = cpu_register_io_memory(malta_fpga_read, - malta_fpga_write, s, - DEVICE_NATIVE_ENDIAN); + memory_region_init_io(&s->iomem, &malta_fpga_ops, s, + "malta-fpga", 0x100000); + memory_region_init_alias(&s->iomem_lo, "malta-fpga", + &s->iomem, 0, 0x900); + memory_region_init_alias(&s->iomem_hi, "malta-fpga", + &s->iomem, 0xa00, 0x10000-0xa00); - cpu_register_physical_memory(base, 0x900, malta); - /* 0xa00 is less than a page, so will still get the right offsets. */ - cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta); + memory_region_add_subregion(address_space, base, &s->iomem_lo); + memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi); s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init); @@ -771,8 +771,8 @@ void mips_malta_init (ram_addr_t ram_size, { char *filename; pflash_t *fl; - ram_addr_t ram_offset; MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1); target_long bios_size; int64_t kernel_entry; @@ -828,9 +828,8 @@ void mips_malta_init (ram_addr_t ram_size, ((unsigned int)ram_size / (1 << 20))); exit(1); } - ram_offset = qemu_ram_alloc(NULL, "mips_malta.ram", ram_size); - - cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); + memory_region_init_ram(ram, NULL, "mips_malta.ram", ram_size); + memory_region_add_subregion(system_memory, 0, ram); #ifdef TARGET_WORDS_BIGENDIAN be = 1; @@ -838,7 +837,7 @@ void mips_malta_init (ram_addr_t ram_size, be = 0; #endif /* FPGA */ - malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]); + malta_fpga_init(system_memory, 0x1f000000LL, env->irq[2], serial_hds[2]); /* Load firmware in flash / BIOS unless we boot directly into a kernel. */ if (kernel_filename) { diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 0d46cc4c5a..740715854b 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -35,6 +35,8 @@ #include "mips-bios.h" #include "loader.h" #include "elf.h" +#include "sysbus.h" +#include "exec-memory.h" static struct _loaderparams { int ram_size; @@ -112,6 +114,22 @@ static void main_cpu_reset(void *opaque) } } +static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "mipsnet"); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + + s = sysbus_from_qdev(dev); + sysbus_connect_irq(s, 0, irq); + memory_region_add_subregion(get_system_io(), + base, + sysbus_mmio_get_region(s, 0)); +} + static void mips_mipssim_init (ram_addr_t ram_size, const char *boot_device, @@ -119,8 +137,9 @@ mips_mipssim_init (ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { char *filename; - ram_addr_t ram_offset; - ram_addr_t bios_offset; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); CPUState *env; ResetData *reset_info; int bios_size; @@ -144,14 +163,14 @@ mips_mipssim_init (ram_addr_t ram_size, qemu_register_reset(main_cpu_reset, reset_info); /* Allocate RAM. */ - ram_offset = qemu_ram_alloc(NULL, "mips_mipssim.ram", ram_size); - bios_offset = qemu_ram_alloc(NULL, "mips_mipssim.bios", BIOS_SIZE); + memory_region_init_ram(ram, NULL, "mips_mipssim.ram", ram_size); + memory_region_init_ram(bios, NULL, "mips_mipssim.bios", BIOS_SIZE); + memory_region_set_readonly(bios, true); - cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); + memory_region_add_subregion(address_space_mem, 0, ram); /* Map the BIOS / boot exception handler. */ - cpu_register_physical_memory(0x1fc00000LL, - BIOS_SIZE, bios_offset | IO_MEM_ROM); + memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); /* Load a BIOS / boot exception handler image. */ if (bios_name == NULL) bios_name = BIOS_FILENAME; diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5d002c5a2b..805d02a4eb 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -42,8 +42,8 @@ static struct _loaderparams { const char *initrd_filename; } loaderparams; -static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) +static void mips_qemu_write (void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) { if ((addr & 0xffff) == 0 && val == 42) qemu_system_reset_request (); @@ -51,25 +51,18 @@ static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, qemu_system_shutdown_request (); } -static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr) +static uint64_t mips_qemu_read (void *opaque, target_phys_addr_t addr, + unsigned size) { return 0; } -static CPUWriteMemoryFunc * const mips_qemu_write[] = { - &mips_qemu_writel, - &mips_qemu_writel, - &mips_qemu_writel, +static const MemoryRegionOps mips_qemu_ops = { + .read = mips_qemu_read, + .write = mips_qemu_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static CPUReadMemoryFunc * const mips_qemu_read[] = { - &mips_qemu_readl, - &mips_qemu_readl, - &mips_qemu_readl, -}; - -static int mips_qemu_iomemtype = 0; - typedef struct ResetData { CPUState *env; uint64_t vector; @@ -163,8 +156,10 @@ void mips_r4k_init (ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { char *filename; - ram_addr_t ram_offset; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios; + MemoryRegion *iomem = g_new(MemoryRegion, 1); int bios_size; CPUState *env; ResetData *reset_info; @@ -199,16 +194,12 @@ void mips_r4k_init (ram_addr_t ram_size, ((unsigned int)ram_size / (1 << 20))); exit(1); } - ram_offset = qemu_ram_alloc(NULL, "mips_r4k.ram", ram_size); + memory_region_init_ram(ram, NULL, "mips_r4k.ram", ram_size); - cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); + memory_region_add_subregion(address_space_mem, 0, ram); - if (!mips_qemu_iomemtype) { - mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read, - mips_qemu_write, NULL, - DEVICE_NATIVE_ENDIAN); - } - cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype); + memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000); + memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem); /* Try to load a BIOS image. If this fails, we continue regardless, but initialize the hardware ourselves. When a kernel gets diff --git a/hw/mipsnet.c b/hw/mipsnet.c index b889ee0062..605367bc5f 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -1,12 +1,7 @@ #include "hw.h" -#include "mips.h" #include "net.h" -#include "isa.h" - -//#define DEBUG_MIPSNET_SEND -//#define DEBUG_MIPSNET_RECEIVE -//#define DEBUG_MIPSNET_DATA -//#define DEBUG_MIPSNET_IRQ +#include "trace.h" +#include "sysbus.h" /* MIPSnet register offsets */ @@ -25,6 +20,8 @@ #define MAX_ETH_FRAME_SIZE 1514 typedef struct MIPSnetState { + SysBusDevice busdev; + uint32_t busy; uint32_t rx_count; uint32_t rx_read; @@ -33,7 +30,7 @@ typedef struct MIPSnetState { uint32_t intctl; uint8_t rx_buffer[MAX_ETH_FRAME_SIZE]; uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; - int io_base; + MemoryRegion io; qemu_irq irq; NICState *nic; NICConf conf; @@ -54,9 +51,7 @@ static void mipsnet_reset(MIPSnetState *s) static void mipsnet_update_irq(MIPSnetState *s) { int isr = !!s->intctl; -#ifdef DEBUG_MIPSNET_IRQ - printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl); -#endif + trace_mipsnet_irq(isr, s->intctl); qemu_set_irq(s->irq, isr); } @@ -80,9 +75,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s { MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; -#ifdef DEBUG_MIPSNET_RECEIVE - printf("mipsnet: receiving len=%zu\n", size); -#endif + trace_mipsnet_receive(size); if (!mipsnet_can_receive(nc)) return -1; @@ -103,7 +96,8 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s return size; } -static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr) +static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr, + unsigned int size) { MIPSnetState *s = opaque; int ret = 0; @@ -144,20 +138,17 @@ static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr) default: break; } -#ifdef DEBUG_MIPSNET_DATA - printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret); -#endif + trace_mipsnet_read(addr, ret); return ret; } -static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) { MIPSnetState *s = opaque; addr &= 0x3f; -#ifdef DEBUG_MIPSNET_DATA - printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val); -#endif + trace_mipsnet_write(addr, val); switch (addr) { case MIPSNET_TX_DATA_COUNT: s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0; @@ -181,9 +172,7 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->tx_buffer[s->tx_written++] = val; if (s->tx_written == s->tx_count) { /* Send buffer. */ -#ifdef DEBUG_MIPSNET_SEND - printf("mipsnet: sending len=%d\n", s->tx_count); -#endif + trace_mipsnet_send(s->tx_count); qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count); s->tx_count = s->tx_written = 0; s->intctl |= MIPSNET_INTCTL_TXDONE; @@ -224,11 +213,7 @@ static void mipsnet_cleanup(VLANClientState *nc) { MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - vmstate_unregister(NULL, &vmstate_mipsnet, s); - - isa_unassign_ioport(s->io_base, 36); - - g_free(s); + s->nic = NULL; } static NetClientInfo net_mipsnet_info = { @@ -239,35 +224,50 @@ static NetClientInfo net_mipsnet_info = { .cleanup = mipsnet_cleanup, }; -void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) -{ - MIPSnetState *s; - - qemu_check_nic_model(nd, "mipsnet"); +static MemoryRegionOps mipsnet_ioport_ops = { + .read = mipsnet_ioport_read, + .write = mipsnet_ioport_write, + .impl.min_access_size = 1, + .impl.max_access_size = 4, +}; - s = g_malloc0(sizeof(MIPSnetState)); +static int mipsnet_sysbus_init(SysBusDevice *dev) +{ + MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev); - register_ioport_write(base, 36, 1, mipsnet_ioport_write, s); - register_ioport_read(base, 36, 1, mipsnet_ioport_read, s); - register_ioport_write(base, 36, 2, mipsnet_ioport_write, s); - register_ioport_read(base, 36, 2, mipsnet_ioport_read, s); - register_ioport_write(base, 36, 4, mipsnet_ioport_write, s); - register_ioport_read(base, 36, 4, mipsnet_ioport_read, s); + memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36); + sysbus_init_mmio_region(dev, &s->io); + sysbus_init_irq(dev, &s->irq); - s->io_base = base; - s->irq = irq; + s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); - if (nd) { - s->conf.macaddr = nd->macaddr; - s->conf.vlan = nd->vlan; - s->conf.peer = nd->netdev; + return 0; +} - s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, - nd->model, nd->name, s); +static void mipsnet_sysbus_reset(DeviceState *dev) +{ + MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev); + mipsnet_reset(s); +} - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); +static SysBusDeviceInfo mipsnet_info = { + .init = mipsnet_sysbus_init, + .qdev.name = "mipsnet", + .qdev.desc = "MIPS Simulator network device", + .qdev.size = sizeof(MIPSnetState), + .qdev.vmsd = &vmstate_mipsnet, + .qdev.reset = mipsnet_sysbus_reset, + .qdev.props = (Property[]) { + DEFINE_NIC_PROPERTIES(MIPSnetState, conf), + DEFINE_PROP_END_OF_LIST(), } +}; - mipsnet_reset(s); - vmstate_register(NULL, 0, &vmstate_mipsnet, s); +static void mipsnet_register_devices(void) +{ + sysbus_register_withprop(&mipsnet_info); } + +device_init(mipsnet_register_devices) diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 4e47574b63..7bcd5d75e8 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -118,7 +118,7 @@ mst_fpga_readb(void *opaque, target_phys_addr_t addr) return s->pcmcia1; default: printf("Mainstone - mst_fpga_readb: Bad register offset " - "0x" TARGET_FMT_plx " \n", addr); + "0x" TARGET_FMT_plx "\n", addr); } return 0; } @@ -171,7 +171,7 @@ mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) break; default: printf("Mainstone - mst_fpga_writeb: Bad register offset " - "0x" TARGET_FMT_plx " \n", addr); + "0x" TARGET_FMT_plx "\n", addr); } } diff --git a/hw/musicpal.c b/hw/musicpal.c index ade5a91feb..9b1f38062b 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -19,6 +19,7 @@ #include "console.h" #include "i2c.h" #include "blockdev.h" +#include "exec-memory.h" #define MP_MISC_BASE 0x80002000 #define MP_MISC_SIZE 0x00001000 @@ -142,6 +143,7 @@ typedef struct mv88w8618_rx_desc { typedef struct mv88w8618_eth_state { SysBusDevice busdev; + MemoryRegion iomem; qemu_irq irq; uint32_t smir; uint32_t icr; @@ -260,7 +262,8 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) } while (desc_addr != s->tx_queue[queue_index]); } -static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset) +static uint64_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset, + unsigned size) { mv88w8618_eth_state *s = opaque; @@ -302,7 +305,7 @@ static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset) } static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { mv88w8618_eth_state *s = opaque; @@ -353,16 +356,10 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, } } -static CPUReadMemoryFunc * const mv88w8618_eth_readfn[] = { - mv88w8618_eth_read, - mv88w8618_eth_read, - mv88w8618_eth_read -}; - -static CPUWriteMemoryFunc * const mv88w8618_eth_writefn[] = { - mv88w8618_eth_write, - mv88w8618_eth_write, - mv88w8618_eth_write +static const MemoryRegionOps mv88w8618_eth_ops = { + .read = mv88w8618_eth_read, + .write = mv88w8618_eth_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void eth_cleanup(VLANClientState *nc) @@ -387,10 +384,9 @@ static int mv88w8618_eth_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, dev->qdev.info->name, dev->qdev.id, s); - s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn, - mv88w8618_eth_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index); + memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth", + MP_ETH_SIZE); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -444,6 +440,7 @@ static SysBusDeviceInfo mv88w8618_eth_info = { typedef struct musicpal_lcd_state { SysBusDevice busdev; + MemoryRegion iomem; uint32_t brightness; uint32_t mode; uint32_t irqctrl; @@ -528,7 +525,8 @@ static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) s->brightness |= level << irq; } -static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset) +static uint64_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset, + unsigned size) { musicpal_lcd_state *s = opaque; @@ -542,7 +540,7 @@ static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset) } static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { musicpal_lcd_state *s = opaque; @@ -581,29 +579,21 @@ static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset, } } -static CPUReadMemoryFunc * const musicpal_lcd_readfn[] = { - musicpal_lcd_read, - musicpal_lcd_read, - musicpal_lcd_read -}; - -static CPUWriteMemoryFunc * const musicpal_lcd_writefn[] = { - musicpal_lcd_write, - musicpal_lcd_write, - musicpal_lcd_write +static const MemoryRegionOps musicpal_lcd_ops = { + .read = musicpal_lcd_read, + .write = musicpal_lcd_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int musicpal_lcd_init(SysBusDevice *dev) { musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); - int iomemtype; s->brightness = 7; - iomemtype = cpu_register_io_memory(musicpal_lcd_readfn, - musicpal_lcd_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype); + memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s, + "musicpal-lcd", MP_LCD_SIZE); + sysbus_init_mmio_region(dev, &s->iomem); s->ds = graphic_console_init(lcd_refresh, lcd_invalidate, NULL, NULL, s); @@ -645,6 +635,7 @@ static SysBusDeviceInfo musicpal_lcd_info = { typedef struct mv88w8618_pic_state { SysBusDevice busdev; + MemoryRegion iomem; uint32_t level; uint32_t enabled; qemu_irq parent_irq; @@ -667,7 +658,8 @@ static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) mv88w8618_pic_update(s); } -static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset) +static uint64_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset, + unsigned size) { mv88w8618_pic_state *s = opaque; @@ -681,7 +673,7 @@ static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset) } static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { mv88w8618_pic_state *s = opaque; @@ -707,29 +699,21 @@ static void mv88w8618_pic_reset(DeviceState *d) s->enabled = 0; } -static CPUReadMemoryFunc * const mv88w8618_pic_readfn[] = { - mv88w8618_pic_read, - mv88w8618_pic_read, - mv88w8618_pic_read -}; - -static CPUWriteMemoryFunc * const mv88w8618_pic_writefn[] = { - mv88w8618_pic_write, - mv88w8618_pic_write, - mv88w8618_pic_write +static const MemoryRegionOps mv88w8618_pic_ops = { + .read = mv88w8618_pic_read, + .write = mv88w8618_pic_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int mv88w8618_pic_init(SysBusDevice *dev) { mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev); - int iomemtype; qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32); sysbus_init_irq(dev, &s->parent_irq); - iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn, - mv88w8618_pic_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype); + memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s, + "musicpal-pic", MP_PIC_SIZE); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -775,6 +759,7 @@ typedef struct mv88w8618_timer_state { typedef struct mv88w8618_pit_state { SysBusDevice busdev; + MemoryRegion iomem; mv88w8618_timer_state timer[4]; } mv88w8618_pit_state; @@ -797,7 +782,8 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, s->ptimer = ptimer_init(bh); } -static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset) +static uint64_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset, + unsigned size) { mv88w8618_pit_state *s = opaque; mv88w8618_timer_state *t; @@ -813,7 +799,7 @@ static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset) } static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { mv88w8618_pit_state *s = opaque; mv88w8618_timer_state *t; @@ -864,21 +850,14 @@ static void mv88w8618_pit_reset(DeviceState *d) } } -static CPUReadMemoryFunc * const mv88w8618_pit_readfn[] = { - mv88w8618_pit_read, - mv88w8618_pit_read, - mv88w8618_pit_read -}; - -static CPUWriteMemoryFunc * const mv88w8618_pit_writefn[] = { - mv88w8618_pit_write, - mv88w8618_pit_write, - mv88w8618_pit_write +static const MemoryRegionOps mv88w8618_pit_ops = { + .read = mv88w8618_pit_read, + .write = mv88w8618_pit_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int mv88w8618_pit_init(SysBusDevice *dev) { - int iomemtype; mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev); int i; @@ -888,10 +867,9 @@ static int mv88w8618_pit_init(SysBusDevice *dev) mv88w8618_timer_init(dev, &s->timer[i], 1000000); } - iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn, - mv88w8618_pit_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype); + memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s, + "musicpal-pit", MP_PIT_SIZE); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -932,11 +910,13 @@ static SysBusDeviceInfo mv88w8618_pit_info = { typedef struct mv88w8618_flashcfg_state { SysBusDevice busdev; + MemoryRegion iomem; uint32_t cfgr0; } mv88w8618_flashcfg_state; -static uint32_t mv88w8618_flashcfg_read(void *opaque, - target_phys_addr_t offset) +static uint64_t mv88w8618_flashcfg_read(void *opaque, + target_phys_addr_t offset, + unsigned size) { mv88w8618_flashcfg_state *s = opaque; @@ -950,7 +930,7 @@ static uint32_t mv88w8618_flashcfg_read(void *opaque, } static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { mv88w8618_flashcfg_state *s = opaque; @@ -961,28 +941,20 @@ static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset, } } -static CPUReadMemoryFunc * const mv88w8618_flashcfg_readfn[] = { - mv88w8618_flashcfg_read, - mv88w8618_flashcfg_read, - mv88w8618_flashcfg_read -}; - -static CPUWriteMemoryFunc * const mv88w8618_flashcfg_writefn[] = { - mv88w8618_flashcfg_write, - mv88w8618_flashcfg_write, - mv88w8618_flashcfg_write +static const MemoryRegionOps mv88w8618_flashcfg_ops = { + .read = mv88w8618_flashcfg_read, + .write = mv88w8618_flashcfg_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int mv88w8618_flashcfg_init(SysBusDevice *dev) { - int iomemtype; mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev); s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ - iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn, - mv88w8618_flashcfg_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype); + memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s, + "musicpal-flashcfg", MP_FLASHCFG_SIZE); + sysbus_init_mmio_region(dev, &s->iomem); return 0; } @@ -1009,7 +981,8 @@ static SysBusDeviceInfo mv88w8618_flashcfg_info = { #define MP_BOARD_REVISION 0x31 -static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset) +static uint64_t musicpal_misc_read(void *opaque, target_phys_addr_t offset, + unsigned size) { switch (offset) { case MP_MISC_BOARD_REVISION: @@ -1021,37 +994,31 @@ static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset) } static void musicpal_misc_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { } -static CPUReadMemoryFunc * const musicpal_misc_readfn[] = { - musicpal_misc_read, - musicpal_misc_read, - musicpal_misc_read, -}; - -static CPUWriteMemoryFunc * const musicpal_misc_writefn[] = { - musicpal_misc_write, - musicpal_misc_write, - musicpal_misc_write, +static const MemoryRegionOps musicpal_misc_ops = { + .read = musicpal_misc_read, + .write = musicpal_misc_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static void musicpal_misc_init(void) +static void musicpal_misc_init(SysBusDevice *dev) { - int iomemtype; + MemoryRegion *iomem = g_new(MemoryRegion, 1); - iomemtype = cpu_register_io_memory(musicpal_misc_readfn, - musicpal_misc_writefn, NULL, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype); + memory_region_init_io(iomem, &musicpal_misc_ops, NULL, + "musicpal-misc", MP_MISC_SIZE); + sysbus_add_memory(dev, MP_MISC_BASE, iomem); } /* WLAN register offsets */ #define MP_WLAN_MAGIC1 0x11c #define MP_WLAN_MAGIC2 0x124 -static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset) +static uint64_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset, + unsigned size) { switch (offset) { /* Workaround to allow loading the binary-only wlandrv.ko crap @@ -1067,30 +1034,23 @@ static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset) } static void mv88w8618_wlan_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { } -static CPUReadMemoryFunc * const mv88w8618_wlan_readfn[] = { - mv88w8618_wlan_read, - mv88w8618_wlan_read, - mv88w8618_wlan_read, -}; - -static CPUWriteMemoryFunc * const mv88w8618_wlan_writefn[] = { - mv88w8618_wlan_write, - mv88w8618_wlan_write, - mv88w8618_wlan_write, +static const MemoryRegionOps mv88w8618_wlan_ops = { + .read = mv88w8618_wlan_read, + .write =mv88w8618_wlan_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int mv88w8618_wlan_init(SysBusDevice *dev) { - int iomemtype; + MemoryRegion *iomem = g_new(MemoryRegion, 1); - iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn, - mv88w8618_wlan_writefn, NULL, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype); + memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL, + "musicpal-wlan", MP_WLAN_SIZE); + sysbus_init_mmio_region(dev, iomem); return 0; } @@ -1118,6 +1078,7 @@ static int mv88w8618_wlan_init(SysBusDevice *dev) typedef struct musicpal_gpio_state { SysBusDevice busdev; + MemoryRegion iomem; uint32_t lcd_brightness; uint32_t out_state; uint32_t in_state; @@ -1190,7 +1151,8 @@ static void musicpal_gpio_pin_event(void *opaque, int pin, int level) } } -static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) +static uint64_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset, + unsigned size) { musicpal_gpio_state *s = opaque; @@ -1229,7 +1191,7 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) } static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, - uint32_t value) + uint64_t value, unsigned size) { musicpal_gpio_state *s = opaque; switch (offset) { @@ -1267,16 +1229,10 @@ static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, } } -static CPUReadMemoryFunc * const musicpal_gpio_readfn[] = { - musicpal_gpio_read, - musicpal_gpio_read, - musicpal_gpio_read, -}; - -static CPUWriteMemoryFunc * const musicpal_gpio_writefn[] = { - musicpal_gpio_write, - musicpal_gpio_write, - musicpal_gpio_write, +static const MemoryRegionOps musicpal_gpio_ops = { + .read = musicpal_gpio_read, + .write = musicpal_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void musicpal_gpio_reset(DeviceState *d) @@ -1295,14 +1251,12 @@ static void musicpal_gpio_reset(DeviceState *d) static int musicpal_gpio_init(SysBusDevice *dev) { musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev); - int iomemtype; sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(musicpal_gpio_readfn, - musicpal_gpio_writefn, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype); + memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s, + "musicpal-gpio", MP_GPIO_SIZE); + sysbus_init_mmio_region(dev, &s->iomem); qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); @@ -1501,7 +1455,9 @@ static void musicpal_init(ram_addr_t ram_size, int i; unsigned long flash_size; DriveInfo *dinfo; - ram_addr_t sram_off; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); if (!cpu_model) { cpu_model = "arm926"; @@ -1514,12 +1470,11 @@ static void musicpal_init(ram_addr_t ram_size, cpu_pic = arm_pic_init_cpu(env); /* For now we use a fixed - the original - RAM size */ - cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE, - qemu_ram_alloc(NULL, "musicpal.ram", - MP_RAM_DEFAULT_SIZE)); + memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE); + memory_region_add_subregion(address_space_mem, 0, ram); - sram_off = qemu_ram_alloc(NULL, "musicpal.sram", MP_SRAM_SIZE); - cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off); + memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE); + 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]); @@ -1594,7 +1549,7 @@ static void musicpal_init(ram_addr_t ram_size, sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); - musicpal_misc_init(); + musicpal_misc_init(sysbus_from_qdev(dev)); dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); diff --git a/hw/ne2000.c b/hw/ne2000.c index a035a85244..62e082f8a9 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -749,8 +749,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev) uint8_t *pci_conf; pci_conf = d->dev.config; - /* TODO: RST# value should be 0. PCI spec 6.2.4 */ - pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ s = &d->ne2000; ne2000_setup_io(s, 0x100); @@ -678,7 +678,8 @@ void omap_uart_reset(struct omap_uart_s *s); void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr); struct omap_mpuio_s; -struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, +struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, omap_clk clk); qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); @@ -691,7 +692,8 @@ struct uWireSlave { void *opaque; }; struct omap_uwire_s; -struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, +struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq *irq, qemu_irq dma, omap_clk clk); void omap_uwire_attach(struct omap_uwire_s *s, uWireSlave *slave, int chipselect); @@ -730,7 +732,8 @@ struct I2SCodec { } in, out; }; struct omap_mcbsp_s; -struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, +struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq *irq, qemu_irq *dma, omap_clk clk); void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave); @@ -741,8 +744,7 @@ void omap_tap_init(struct omap_target_agent_s *ta, struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, - struct omap_dma_lcd_channel_s *dma, - ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk); + struct omap_dma_lcd_channel_s *dma, omap_clk clk); /* omap_dss.c */ struct rfbi_chip_s { @@ -826,6 +828,22 @@ struct omap_mpu_state_s { qemu_irq wakeup; + MemoryRegion ulpd_pm_iomem; + MemoryRegion pin_cfg_iomem; + MemoryRegion id_iomem; + MemoryRegion id_iomem_e18; + MemoryRegion id_iomem_ed4; + MemoryRegion id_iomem_e20; + MemoryRegion mpui_iomem; + MemoryRegion tcmi_iomem; + MemoryRegion clkm_iomem; + MemoryRegion clkdsp_iomem; + MemoryRegion pwl_iomem; + MemoryRegion pwt_iomem; + MemoryRegion mpui_io_iomem; + MemoryRegion imif_ram; + MemoryRegion emiff_ram; + struct omap_dma_port_if_s { uint32_t (*read[3])(struct omap_mpu_state_s *s, target_phys_addr_t offset); @@ -907,6 +925,7 @@ struct omap_mpu_state_s { uint32_t tcmi_regs[17]; struct dpll_ctl_s { + MemoryRegion iomem; uint16_t mode; omap_clk dpll; } dpll[3]; @@ -947,7 +966,8 @@ struct omap_mpu_state_s { }; /* omap1.c */ -struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, +struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, + unsigned long sdram_size, const char *core); /* omap2.c */ diff --git a/hw/omap1.c b/hw/omap1.c index 614fd31b01..f747321e97 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -84,6 +84,7 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, /* MPU OS timers */ struct omap_mpu_timer_s { + MemoryRegion iomem; qemu_irq irq; omap_clk clk; uint32_t val; @@ -179,10 +180,15 @@ static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) timer->rate = omap_clk_getrate(timer->clk); } -static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + switch (addr) { case 0x00: /* CNTL_TIMER */ return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; @@ -199,10 +205,14 @@ static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr) } static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + switch (addr) { case 0x00: /* CNTL_TIMER */ omap_timer_sync(s); @@ -226,16 +236,10 @@ static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_mpu_timer_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_mpu_timer_read, -}; - -static CPUWriteMemoryFunc * const omap_mpu_timer_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_mpu_timer_write, +static const MemoryRegionOps omap_mpu_timer_ops = { + .read = omap_mpu_timer_read, + .write = omap_mpu_timer_write, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) @@ -250,10 +254,10 @@ static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) s->it_ena = 1; } -static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, +static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq irq, omap_clk clk) { - int iomemtype; struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) g_malloc0(sizeof(struct omap_mpu_timer_s)); @@ -264,9 +268,10 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, omap_mpu_timer_reset(s); omap_timer_clk_setup(s); - iomemtype = cpu_register_io_memory(omap_mpu_timer_readfn, - omap_mpu_timer_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x100, iomemtype); + memory_region_init_io(&s->iomem, &omap_mpu_timer_ops, s, + "omap-mpu-timer", 0x100); + + memory_region_add_subregion(system_memory, base, &s->iomem); return s; } @@ -274,16 +279,22 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, /* Watchdog timer */ struct omap_watchdog_timer_s { struct omap_mpu_timer_s timer; + MemoryRegion iomem; uint8_t last_wr; int mode; int free; int reset; }; -static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (addr) { case 0x00: /* CNTL_TIMER */ return (s->timer.ptv << 9) | (s->timer.ar << 8) | @@ -301,10 +312,14 @@ static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr) } static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (addr) { case 0x00: /* CNTL_TIMER */ omap_timer_sync(&s->timer); @@ -344,16 +359,10 @@ static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_wd_timer_readfn[] = { - omap_badwidth_read16, - omap_wd_timer_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc * const omap_wd_timer_writefn[] = { - omap_badwidth_write16, - omap_wd_timer_write, - omap_badwidth_write16, +static const MemoryRegionOps omap_wd_timer_ops = { + .read = omap_wd_timer_read, + .write = omap_wd_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) @@ -374,10 +383,10 @@ static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) omap_timer_update(&s->timer); } -static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, +static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, + target_phys_addr_t base, qemu_irq irq, omap_clk clk) { - int iomemtype; struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) g_malloc0(sizeof(struct omap_watchdog_timer_s)); @@ -387,9 +396,9 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, omap_wd_timer_reset(s); omap_timer_clk_setup(&s->timer); - iomemtype = cpu_register_io_memory(omap_wd_timer_readfn, - omap_wd_timer_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x100, iomemtype); + memory_region_init_io(&s->iomem, &omap_wd_timer_ops, s, + "omap-wd-timer", 0x100); + memory_region_add_subregion(memory, base, &s->iomem); return s; } @@ -397,13 +406,19 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, /* 32-kHz timer */ struct omap_32khz_timer_s { struct omap_mpu_timer_s timer; + MemoryRegion iomem; }; -static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_os_timer_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + switch (offset) { case 0x00: /* TVR */ return s->timer.reset_val; @@ -422,11 +437,15 @@ static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr) } static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + switch (offset) { case 0x00: /* TVR */ s->timer.reset_val = value & 0x00ffffff; @@ -452,16 +471,10 @@ static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_os_timer_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_os_timer_read, -}; - -static CPUWriteMemoryFunc * const omap_os_timer_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_os_timer_write, +static const MemoryRegionOps omap_os_timer_ops = { + .read = omap_os_timer_read, + .write = omap_os_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_os_timer_reset(struct omap_32khz_timer_s *s) @@ -476,10 +489,10 @@ static void omap_os_timer_reset(struct omap_32khz_timer_s *s) s->timer.ar = 1; } -static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, +static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, + target_phys_addr_t base, qemu_irq irq, omap_clk clk) { - int iomemtype; struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) g_malloc0(sizeof(struct omap_32khz_timer_s)); @@ -489,19 +502,24 @@ static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, omap_os_timer_reset(s); omap_timer_clk_setup(&s->timer); - iomemtype = cpu_register_io_memory(omap_os_timer_readfn, - omap_os_timer_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->iomem, &omap_os_timer_ops, s, + "omap-os-timer", 0x800); + memory_region_add_subregion(memory, base, &s->iomem); return s; } /* Ultra Low-Power Device Module */ -static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; uint16_t ret; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (addr) { case 0x14: /* IT_STATUS */ ret = s->ulpd_pm_regs[addr >> 2]; @@ -560,7 +578,7 @@ static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, } static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int64_t now, ticks; @@ -568,6 +586,10 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, static const int bypass_div[4] = { 1, 2, 4, 4 }; uint16_t diff; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (addr) { case 0x00: /* COUNTER_32_LSB */ case 0x04: /* COUNTER_32_MSB */ @@ -674,16 +696,10 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_ulpd_pm_readfn[] = { - omap_badwidth_read16, - omap_ulpd_pm_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc * const omap_ulpd_pm_writefn[] = { - omap_badwidth_write16, - omap_ulpd_pm_write, - omap_badwidth_write16, +static const MemoryRegionOps omap_ulpd_pm_ops = { + .read = omap_ulpd_pm_read, + .write = omap_ulpd_pm_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) @@ -713,21 +729,26 @@ static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); } -static void omap_ulpd_pm_init(target_phys_addr_t base, +static void omap_ulpd_pm_init(MemoryRegion *system_memory, + target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(omap_ulpd_pm_readfn, - omap_ulpd_pm_writefn, mpu, DEVICE_NATIVE_ENDIAN); - - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu, + "omap-ulpd-pm", 0x800); + memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem); omap_ulpd_pm_reset(mpu); } /* OMAP Pin Configuration */ -static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + switch (addr) { case 0x00: /* FUNC_MUX_CTRL_0 */ case 0x04: /* FUNC_MUX_CTRL_1 */ @@ -827,11 +848,15 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, } static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; uint32_t diff; + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + switch (addr) { case 0x00: /* FUNC_MUX_CTRL_0 */ diff = s->func_mux_ctrl[addr >> 2] ^ value; @@ -900,16 +925,10 @@ static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_pin_cfg_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_pin_cfg_read, -}; - -static CPUWriteMemoryFunc * const omap_pin_cfg_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_pin_cfg_write, +static const MemoryRegionOps omap_pin_cfg_ops = { + .read = omap_pin_cfg_read, + .write = omap_pin_cfg_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) @@ -928,21 +947,26 @@ static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); } -static void omap_pin_cfg_init(target_phys_addr_t base, +static void omap_pin_cfg_init(MemoryRegion *system_memory, + target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(omap_pin_cfg_readfn, - omap_pin_cfg_writefn, mpu, DEVICE_NATIVE_ENDIAN); - - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu, + "omap-pin-cfg", 0x800); + memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem); omap_pin_cfg_reset(mpu); } /* Device Identification, Die Identification */ -static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_id_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + switch (addr) { case 0xfffe1800: /* DIE_ID_LSB */ return 0xc9581f0e; @@ -982,38 +1006,48 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) } static void omap_id_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + OMAP_BAD_REG(addr); } -static CPUReadMemoryFunc * const omap_id_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_id_read, +static const MemoryRegionOps omap_id_ops = { + .read = omap_id_read, + .write = omap_id_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static CPUWriteMemoryFunc * const omap_id_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_id_write, -}; - -static void omap_id_init(struct omap_mpu_state_s *mpu) +static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(omap_id_readfn, - omap_id_writefn, mpu, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory_offset(0xfffe1800, 0x800, iomemtype, 0xfffe1800); - cpu_register_physical_memory_offset(0xfffed400, 0x100, iomemtype, 0xfffed400); - if (!cpu_is_omap15xx(mpu)) - cpu_register_physical_memory_offset(0xfffe2000, 0x800, iomemtype, 0xfffe2000); + memory_region_init_io(&mpu->id_iomem, &omap_id_ops, mpu, + "omap-id", 0x100000000ULL); + memory_region_init_alias(&mpu->id_iomem_e18, "omap-id-e18", &mpu->id_iomem, + 0xfffe1800, 0x800); + memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18); + memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-ed4", &mpu->id_iomem, + 0xfffed400, 0x100); + memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4); + if (!cpu_is_omap15xx(mpu)) { + memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-e20", + &mpu->id_iomem, 0xfffe2000, 0x800); + memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20); + } } /* MPUI Control (Dummy) */ -static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_mpui_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + switch (addr) { case 0x00: /* CTRL */ return s->mpui_ctrl; @@ -1039,10 +1073,14 @@ static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr) } static void omap_mpui_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + switch (addr) { case 0x00: /* CTRL */ s->mpui_ctrl = value & 0x007fffff; @@ -1064,16 +1102,10 @@ static void omap_mpui_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_mpui_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_mpui_read, -}; - -static CPUWriteMemoryFunc * const omap_mpui_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_mpui_write, +static const MemoryRegionOps omap_mpui_ops = { + .read = omap_mpui_read, + .write = omap_mpui_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_mpui_reset(struct omap_mpu_state_s *s) @@ -1081,13 +1113,12 @@ static void omap_mpui_reset(struct omap_mpu_state_s *s) s->mpui_ctrl = 0x0003ff1b; } -static void omap_mpui_init(target_phys_addr_t base, +static void omap_mpui_init(MemoryRegion *memory, target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(omap_mpui_readfn, - omap_mpui_writefn, mpu, DEVICE_NATIVE_ENDIAN); - - cpu_register_physical_memory(base, 0x100, iomemtype); + memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu, + "omap-mpui", 0x100); + memory_region_add_subregion(memory, base, &mpu->mpui_iomem); omap_mpui_reset(mpu); } @@ -1095,6 +1126,7 @@ static void omap_mpui_init(target_phys_addr_t base, /* TIPB Bridges */ struct omap_tipb_bridge_s { qemu_irq abort; + MemoryRegion iomem; int width_intr; uint16_t control; @@ -1103,10 +1135,15 @@ struct omap_tipb_bridge_s { uint16_t enh_control; }; -static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + if (size < 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (addr) { case 0x00: /* TIPB_CNTL */ return s->control; @@ -1129,10 +1166,14 @@ static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr) } static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + if (size < 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (addr) { case 0x00: /* TIPB_CNTL */ s->control = value & 0xffff; @@ -1163,16 +1204,10 @@ static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_tipb_bridge_readfn[] = { - omap_badwidth_read16, - omap_tipb_bridge_read, - omap_tipb_bridge_read, -}; - -static CPUWriteMemoryFunc * const omap_tipb_bridge_writefn[] = { - omap_badwidth_write16, - omap_tipb_bridge_write, - omap_tipb_bridge_write, +static const MemoryRegionOps omap_tipb_bridge_ops = { + .read = omap_tipb_bridge_read, + .write = omap_tipb_bridge_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) @@ -1183,29 +1218,34 @@ static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) s->enh_control = 0x000f; } -static struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, - qemu_irq abort_irq, omap_clk clk) +static struct omap_tipb_bridge_s *omap_tipb_bridge_init( + MemoryRegion *memory, target_phys_addr_t base, + qemu_irq abort_irq, omap_clk clk) { - int iomemtype; struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) g_malloc0(sizeof(struct omap_tipb_bridge_s)); s->abort = abort_irq; omap_tipb_bridge_reset(s); - iomemtype = cpu_register_io_memory(omap_tipb_bridge_readfn, - omap_tipb_bridge_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x100, iomemtype); + memory_region_init_io(&s->iomem, &omap_tipb_bridge_ops, s, + "omap-tipb-bridge", 0x100); + memory_region_add_subregion(memory, base, &s->iomem); return s; } /* Dummy Traffic Controller's Memory Interface */ -static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_tcmi_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; uint32_t ret; + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + switch (addr) { case 0x00: /* IMIF_PRIO */ case 0x04: /* EMIFS_PRIO */ @@ -1235,10 +1275,14 @@ static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) } static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + switch (addr) { case 0x00: /* IMIF_PRIO */ case 0x04: /* EMIFS_PRIO */ @@ -1265,16 +1309,10 @@ static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_tcmi_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_tcmi_read, -}; - -static CPUWriteMemoryFunc * const omap_tcmi_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_tcmi_write, +static const MemoryRegionOps omap_tcmi_ops = { + .read = omap_tcmi_read, + .write = omap_tcmi_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) @@ -1296,21 +1334,25 @@ static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) mpu->tcmi_regs[0x40 >> 2] = 0x00000000; } -static void omap_tcmi_init(target_phys_addr_t base, +static void omap_tcmi_init(MemoryRegion *memory, target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(omap_tcmi_readfn, - omap_tcmi_writefn, mpu, DEVICE_NATIVE_ENDIAN); - - cpu_register_physical_memory(base, 0x100, iomemtype); + memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu, + "omap-tcmi", 0x100); + memory_region_add_subregion(memory, base, &mpu->tcmi_iomem); omap_tcmi_reset(mpu); } /* Digital phase-locked loops control */ -static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + if (addr == 0x00) /* CTL_REG */ return s->mode; @@ -1319,13 +1361,17 @@ static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr) } static void omap_dpll_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; uint16_t diff; static const int bypass_div[4] = { 1, 2, 4, 4 }; int div, mult; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + if (addr == 0x00) { /* CTL_REG */ /* See omap_ulpd_pm_write() too */ diff = s->mode & value; @@ -1351,16 +1397,10 @@ static void omap_dpll_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_dpll_readfn[] = { - omap_badwidth_read16, - omap_dpll_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc * const omap_dpll_writefn[] = { - omap_badwidth_write16, - omap_dpll_write, - omap_badwidth_write16, +static const MemoryRegionOps omap_dpll_ops = { + .read = omap_dpll_read, + .write = omap_dpll_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_dpll_reset(struct dpll_ctl_s *s) @@ -1369,23 +1409,27 @@ static void omap_dpll_reset(struct dpll_ctl_s *s) omap_clk_setrate(s->dpll, 1, 1); } -static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base, - omap_clk clk) +static void omap_dpll_init(MemoryRegion *memory, struct dpll_ctl_s *s, + target_phys_addr_t base, omap_clk clk) { - int iomemtype = cpu_register_io_memory(omap_dpll_readfn, - omap_dpll_writefn, s, DEVICE_NATIVE_ENDIAN); + memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100); s->dpll = clk; omap_dpll_reset(s); - cpu_register_physical_memory(base, 0x100, iomemtype); + memory_region_add_subregion(memory, base, &s->iomem); } /* MPU Clock/Reset/Power Mode Control */ -static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_clkm_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (addr) { case 0x00: /* ARM_CKCTL */ return s->clkm.arm_ckctl; @@ -1579,7 +1623,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, } static void omap_clkm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; uint16_t diff; @@ -1589,6 +1633,10 @@ static void omap_clkm_write(void *opaque, target_phys_addr_t addr, "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", }; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (addr) { case 0x00: /* ARM_CKCTL */ diff = s->clkm.arm_ckctl ^ value; @@ -1655,22 +1703,21 @@ static void omap_clkm_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_clkm_readfn[] = { - omap_badwidth_read16, - omap_clkm_read, - omap_badwidth_read16, +static const MemoryRegionOps omap_clkm_ops = { + .read = omap_clkm_read, + .write = omap_clkm_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static CPUWriteMemoryFunc * const omap_clkm_writefn[] = { - omap_badwidth_write16, - omap_clkm_write, - omap_badwidth_write16, -}; - -static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (addr) { case 0x04: /* DSP_IDLECT1 */ return s->clkm.dsp_idlect1; @@ -1707,11 +1754,15 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, } static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; uint16_t diff; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (addr) { case 0x04: /* DSP_IDLECT1 */ diff = s->clkm.dsp_idlect1 ^ value; @@ -1738,16 +1789,10 @@ static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_clkdsp_readfn[] = { - omap_badwidth_read16, - omap_clkdsp_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc * const omap_clkdsp_writefn[] = { - omap_badwidth_write16, - omap_clkdsp_write, - omap_badwidth_write16, +static const MemoryRegionOps omap_clkdsp_ops = { + .read = omap_clkdsp_read, + .write = omap_clkdsp_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_clkm_reset(struct omap_mpu_state_s *s) @@ -1773,15 +1818,13 @@ static void omap_clkm_reset(struct omap_mpu_state_s *s) s->clkm.dsp_rstct2 = 0x0000; } -static void omap_clkm_init(target_phys_addr_t mpu_base, +static void omap_clkm_init(MemoryRegion *memory, target_phys_addr_t mpu_base, target_phys_addr_t dsp_base, struct omap_mpu_state_s *s) { - int iomemtype[2] = { - cpu_register_io_memory(omap_clkm_readfn, omap_clkm_writefn, s, - DEVICE_NATIVE_ENDIAN), - cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s, - DEVICE_NATIVE_ENDIAN), - }; + memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s, + "omap-clkm", 0x100); + memory_region_init_io(&s->clkdsp_iomem, &omap_clkdsp_ops, s, + "omap-clkdsp", 0x1000); s->clkm.arm_idlect1 = 0x03ff; s->clkm.arm_idlect2 = 0x0100; @@ -1789,8 +1832,8 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, omap_clkm_reset(s); s->clkm.cold_start = 0x3a; - cpu_register_physical_memory(mpu_base, 0x100, iomemtype[0]); - cpu_register_physical_memory(dsp_base, 0x1000, iomemtype[1]); + memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem); + memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem); } /* MPU I/O */ @@ -1800,6 +1843,7 @@ struct omap_mpuio_s { qemu_irq *in; qemu_irq handler[16]; qemu_irq wakeup; + MemoryRegion iomem; uint16_t inputs; uint16_t outputs; @@ -1854,12 +1898,17 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) s->row_latch = ~rows; } -static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_mpuio_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (offset) { case 0x00: /* INPUT_LATCH */ return s->inputs; @@ -1910,13 +1959,17 @@ static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) } static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t diff; int ln; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (offset) { case 0x04: /* OUTPUT_REG */ diff = (s->outputs ^ value) & ~s->dir; @@ -1982,16 +2035,10 @@ static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_mpuio_readfn[] = { - omap_badwidth_read16, - omap_mpuio_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc * const omap_mpuio_writefn[] = { - omap_badwidth_write16, - omap_mpuio_write, - omap_badwidth_write16, +static const MemoryRegionOps omap_mpuio_ops = { + .read = omap_mpuio_read, + .write = omap_mpuio_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_mpuio_reset(struct omap_mpuio_s *s) @@ -2019,11 +2066,11 @@ static void omap_mpuio_onoff(void *opaque, int line, int on) omap_mpuio_kbd_update(s); } -struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, +struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, + target_phys_addr_t base, qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, omap_clk clk) { - int iomemtype; struct omap_mpuio_s *s = (struct omap_mpuio_s *) g_malloc0(sizeof(struct omap_mpuio_s)); @@ -2033,9 +2080,9 @@ struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); omap_mpuio_reset(s); - iomemtype = cpu_register_io_memory(omap_mpuio_readfn, - omap_mpuio_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->iomem, &omap_mpuio_ops, s, + "omap-mpuio", 0x800); + memory_region_add_subregion(memory, base, &s->iomem); omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); @@ -2069,6 +2116,7 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) /* MicroWire Interface */ struct omap_uwire_s { + MemoryRegion iomem; qemu_irq txirq; qemu_irq rxirq; qemu_irq txdrq; @@ -2106,11 +2154,16 @@ static void omap_uwire_transfer_start(struct omap_uwire_s *s) } } -static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_uwire_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (offset) { case 0x00: /* RDR */ s->control &= ~(1 << 15); /* RDRB */ @@ -2136,11 +2189,15 @@ static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) } static void omap_uwire_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + switch (offset) { case 0x00: /* TDR */ s->txbuf = value; /* TD */ @@ -2184,16 +2241,10 @@ static void omap_uwire_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_uwire_readfn[] = { - omap_badwidth_read16, - omap_uwire_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc * const omap_uwire_writefn[] = { - omap_badwidth_write16, - omap_uwire_write, - omap_badwidth_write16, +static const MemoryRegionOps omap_uwire_ops = { + .read = omap_uwire_read, + .write = omap_uwire_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_uwire_reset(struct omap_uwire_s *s) @@ -2206,10 +2257,10 @@ static void omap_uwire_reset(struct omap_uwire_s *s) s->setup[4] = 0; } -struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, +struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq *irq, qemu_irq dma, omap_clk clk) { - int iomemtype; struct omap_uwire_s *s = (struct omap_uwire_s *) g_malloc0(sizeof(struct omap_uwire_s)); @@ -2218,9 +2269,8 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, s->txdrq = dma; omap_uwire_reset(s); - iomemtype = cpu_register_io_memory(omap_uwire_readfn, - omap_uwire_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->iomem, &omap_uwire_ops, s, "omap-uwire", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); return s; } @@ -2247,11 +2297,16 @@ static void omap_pwl_update(struct omap_mpu_state_s *s) } } -static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + switch (offset) { case 0x00: /* PWL_LEVEL */ return s->pwl.level; @@ -2263,11 +2318,15 @@ static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr) } static void omap_pwl_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + switch (offset) { case 0x00: /* PWL_LEVEL */ s->pwl.level = value; @@ -2283,16 +2342,10 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_pwl_readfn[] = { - omap_pwl_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc * const omap_pwl_writefn[] = { - omap_pwl_write, - omap_badwidth_write8, - omap_badwidth_write8, +static const MemoryRegionOps omap_pwl_ops = { + .read = omap_pwl_read, + .write = omap_pwl_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_pwl_reset(struct omap_mpu_state_s *s) @@ -2312,26 +2365,30 @@ static void omap_pwl_clk_update(void *opaque, int line, int on) omap_pwl_update(s); } -static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, +static void omap_pwl_init(MemoryRegion *system_memory, + target_phys_addr_t base, struct omap_mpu_state_s *s, omap_clk clk) { - int iomemtype; - omap_pwl_reset(s); - iomemtype = cpu_register_io_memory(omap_pwl_readfn, - omap_pwl_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->pwl_iomem, &omap_pwl_ops, s, + "omap-pwl", 0x800); + memory_region_add_subregion(system_memory, base, &s->pwl_iomem); omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); } /* Pulse-Width Tone module */ -static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + switch (offset) { case 0x00: /* FRC */ return s->pwt.frc; @@ -2345,11 +2402,15 @@ static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr) } static void omap_pwt_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + switch (offset) { case 0x00: /* FRC */ s->pwt.frc = value & 0x3f; @@ -2387,16 +2448,10 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_pwt_readfn[] = { - omap_pwt_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc * const omap_pwt_writefn[] = { - omap_pwt_write, - omap_badwidth_write8, - omap_badwidth_write8, +static const MemoryRegionOps omap_pwt_ops = { + .read =omap_pwt_read, + .write = omap_pwt_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_pwt_reset(struct omap_mpu_state_s *s) @@ -2406,21 +2461,21 @@ static void omap_pwt_reset(struct omap_mpu_state_s *s) s->pwt.gcr = 0; } -static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, +static void omap_pwt_init(MemoryRegion *system_memory, + target_phys_addr_t base, struct omap_mpu_state_s *s, omap_clk clk) { - int iomemtype; - s->pwt.clk = clk; omap_pwt_reset(s); - iomemtype = cpu_register_io_memory(omap_pwt_readfn, - omap_pwt_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->pwt_iomem, &omap_pwt_ops, s, + "omap-pwt", 0x800); + memory_region_add_subregion(system_memory, base, &s->pwt_iomem); } /* Real-time Clock module */ struct omap_rtc_s { + MemoryRegion iomem; qemu_irq irq; qemu_irq alarm; QEMUTimer *clk; @@ -2453,12 +2508,17 @@ static void omap_rtc_alarm_update(struct omap_rtc_s *s) printf("%s: conversion failed\n", __FUNCTION__); } -static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_rtc_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint8_t i; + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + switch (offset) { case 0x00: /* SECONDS_REG */ return to_bcd(s->current_tm.tm_sec); @@ -2531,13 +2591,17 @@ static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) } static void omap_rtc_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; struct tm new_tm; time_t ti[2]; + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + switch (offset) { case 0x00: /* SECONDS_REG */ #ifdef ALMDEBUG @@ -2718,16 +2782,10 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_rtc_readfn[] = { - omap_rtc_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc * const omap_rtc_writefn[] = { - omap_rtc_write, - omap_badwidth_write8, - omap_badwidth_write8, +static const MemoryRegionOps omap_rtc_ops = { + .read = omap_rtc_read, + .write = omap_rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_rtc_tick(void *opaque) @@ -2814,10 +2872,10 @@ static void omap_rtc_reset(struct omap_rtc_s *s) omap_rtc_tick(s); } -static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, +static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq *irq, omap_clk clk) { - int iomemtype; struct omap_rtc_s *s = (struct omap_rtc_s *) g_malloc0(sizeof(struct omap_rtc_s)); @@ -2827,15 +2885,16 @@ static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, omap_rtc_reset(s); - iomemtype = cpu_register_io_memory(omap_rtc_readfn, - omap_rtc_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->iomem, &omap_rtc_ops, s, + "omap-rtc", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); return s; } /* Multi-channel Buffered Serial Port interfaces */ struct omap_mcbsp_s { + MemoryRegion iomem; qemu_irq txirq; qemu_irq rxirq; qemu_irq txdrq; @@ -3041,12 +3100,17 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) omap_mcbsp_rx_stop(s); } -static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + switch (offset) { case 0x00: /* DRR2 */ if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ @@ -3303,16 +3367,20 @@ static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, omap_badwidth_write16(opaque, addr, value); } -static CPUReadMemoryFunc * const omap_mcbsp_readfn[] = { - omap_badwidth_read16, - omap_mcbsp_read, - omap_badwidth_read16, -}; +static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) +{ + switch (size) { + case 2: return omap_mcbsp_writeh(opaque, addr, value); + case 4: return omap_mcbsp_writew(opaque, addr, value); + default: return omap_badwidth_write16(opaque, addr, value); + } +} -static CPUWriteMemoryFunc * const omap_mcbsp_writefn[] = { - omap_badwidth_write16, - omap_mcbsp_writeh, - omap_mcbsp_writew, +static const MemoryRegionOps omap_mcbsp_ops = { + .read = omap_mcbsp_read, + .write = omap_mcbsp_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_mcbsp_reset(struct omap_mcbsp_s *s) @@ -3334,10 +3402,10 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s) qemu_del_timer(s->sink_timer); } -struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, +struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, + target_phys_addr_t base, qemu_irq *irq, qemu_irq *dma, omap_clk clk) { - int iomemtype; struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) g_malloc0(sizeof(struct omap_mcbsp_s)); @@ -3349,9 +3417,8 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s); omap_mcbsp_reset(s); - iomemtype = cpu_register_io_memory(omap_mcbsp_readfn, - omap_mcbsp_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->iomem, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); return s; } @@ -3385,6 +3452,7 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave) /* LED Pulse Generators */ struct omap_lpg_s { + MemoryRegion iomem; QEMUTimer *tm; uint8_t control; @@ -3449,11 +3517,16 @@ static void omap_lpg_reset(struct omap_lpg_s *s) omap_lpg_update(s); } -static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_lpg_read(void *opaque, target_phys_addr_t addr, + unsigned size) { struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + switch (offset) { case 0x00: /* LCR */ return s->control; @@ -3467,11 +3540,15 @@ static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr) } static void omap_lpg_write(void *opaque, target_phys_addr_t addr, - uint32_t value) + uint64_t value, unsigned size) { struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + switch (offset) { case 0x00: /* LCR */ if (~value & (1 << 6)) /* LPGRES */ @@ -3491,16 +3568,10 @@ static void omap_lpg_write(void *opaque, target_phys_addr_t addr, } } -static CPUReadMemoryFunc * const omap_lpg_readfn[] = { - omap_lpg_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc * const omap_lpg_writefn[] = { - omap_lpg_write, - omap_badwidth_write8, - omap_badwidth_write8, +static const MemoryRegionOps omap_lpg_ops = { + .read = omap_lpg_read, + .write = omap_lpg_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void omap_lpg_clk_update(void *opaque, int line, int on) @@ -3511,9 +3582,9 @@ static void omap_lpg_clk_update(void *opaque, int line, int on) omap_lpg_update(s); } -static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) +static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, + target_phys_addr_t base, omap_clk clk) { - int iomemtype; struct omap_lpg_s *s = (struct omap_lpg_s *) g_malloc0(sizeof(struct omap_lpg_s)); @@ -3521,9 +3592,8 @@ static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) omap_lpg_reset(s); - iomemtype = cpu_register_io_memory(omap_lpg_readfn, - omap_lpg_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x800, iomemtype); + memory_region_init_io(&s->iomem, &omap_lpg_ops, s, "omap-lpg", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); @@ -3531,8 +3601,13 @@ static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) } /* MPUI Peripheral Bridge configuration */ -static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr) +static uint64_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr, + unsigned size) { + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + if (addr == OMAP_MPUI_BASE) /* CMR */ return 0xfe4d; @@ -3540,23 +3615,26 @@ static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr) return 0; } -static CPUReadMemoryFunc * const omap_mpui_io_readfn[] = { - omap_badwidth_read16, - omap_mpui_io_read, - omap_badwidth_read16, -}; +static void omap_mpui_io_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) +{ + /* FIXME: infinite loop */ + omap_badwidth_write16(opaque, addr, value); +} -static CPUWriteMemoryFunc * const omap_mpui_io_writefn[] = { - omap_badwidth_write16, - omap_badwidth_write16, - omap_badwidth_write16, +static const MemoryRegionOps omap_mpui_io_ops = { + .read = omap_mpui_io_read, + .write = omap_mpui_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu) +static void omap_setup_mpui_io(MemoryRegion *system_memory, + struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(omap_mpui_io_readfn, - omap_mpui_io_writefn, mpu, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype); + memory_region_init_io(&mpu->mpui_io_iomem, &omap_mpui_io_ops, mpu, + "omap-mpui-io", 0x7fff); + memory_region_add_subregion(system_memory, OMAP_MPUI_BASE, + &mpu->mpui_io_iomem); } /* General chip reset */ @@ -3630,14 +3708,16 @@ static const struct omap_map_s { { 0 } }; -static void omap_setup_dsp_mapping(const struct omap_map_s *map) +static void omap_setup_dsp_mapping(MemoryRegion *system_memory, + const struct omap_map_s *map) { - int io; + MemoryRegion *io; for (; map->phys_dsp; map ++) { - io = cpu_get_physical_page_desc(map->phys_mpu); - - cpu_register_physical_memory(map->phys_dsp, map->size, io); + io = g_new(MemoryRegion, 1); + memory_region_init_alias(io, map->name, + system_memory, map->phys_mpu, map->size); + memory_region_add_subregion(system_memory, map->phys_dsp, io); } } @@ -3706,13 +3786,13 @@ static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr); } -struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, +struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, + unsigned long sdram_size, const char *core) { int i; struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) g_malloc0(sizeof(struct omap_mpu_state_s)); - ram_addr_t imif_base, emiff_base; qemu_irq *cpu_irq; qemu_irq dma_irqs[6]; DriveInfo *dinfo; @@ -3736,14 +3816,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_clk_init(s); /* Memory-mapped stuff */ - cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size, - (emiff_base = qemu_ram_alloc(NULL, "omap1.dram", - s->sdram_size)) | IO_MEM_RAM); - cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size, - (imif_base = qemu_ram_alloc(NULL, "omap1.sram", - s->sram_size)) | IO_MEM_RAM); + memory_region_init_ram(&s->emiff_ram, NULL, "omap1.dram", s->sdram_size); + memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram); + memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size); + memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram); - omap_clkm_init(0xfffece00, 0xe1008000, s); + omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); cpu_irq = arm_pic_init_cpu(s->env); s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0], @@ -3767,47 +3845,46 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; /* Register SDRAM and SRAM DMA ports for fast transfers. */ - soc_dma_port_add_mem_ram(s->dma, - emiff_base, OMAP_EMIFF_BASE, s->sdram_size); - soc_dma_port_add_mem_ram(s->dma, - imif_base, OMAP_IMIF_BASE, s->sram_size); + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram), + OMAP_EMIFF_BASE, s->sdram_size); + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram), + OMAP_IMIF_BASE, s->sram_size); - s->timer[0] = omap_mpu_timer_init(0xfffec500, + s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500, s->irq[0][OMAP_INT_TIMER1], omap_findclk(s, "mputim_ck")); - s->timer[1] = omap_mpu_timer_init(0xfffec600, + s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600, s->irq[0][OMAP_INT_TIMER2], omap_findclk(s, "mputim_ck")); - s->timer[2] = omap_mpu_timer_init(0xfffec700, + s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700, s->irq[0][OMAP_INT_TIMER3], omap_findclk(s, "mputim_ck")); - s->wdt = omap_wd_timer_init(0xfffec800, + s->wdt = omap_wd_timer_init(system_memory, 0xfffec800, s->irq[0][OMAP_INT_WD_TIMER], omap_findclk(s, "armwdt_ck")); - s->os_timer = omap_os_timer_init(0xfffb9000, + s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000, s->irq[1][OMAP_INT_OS_TIMER], omap_findclk(s, "clk32-kHz")); s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL], - omap_dma_get_lcdch(s->dma), imif_base, emiff_base, - omap_findclk(s, "lcd_ck")); + omap_dma_get_lcdch(s->dma), omap_findclk(s, "lcd_ck")); - omap_ulpd_pm_init(0xfffe0800, s); - omap_pin_cfg_init(0xfffe1000, s); - omap_id_init(s); + omap_ulpd_pm_init(system_memory, 0xfffe0800, s); + omap_pin_cfg_init(system_memory, 0xfffe1000, s); + omap_id_init(system_memory, s); - omap_mpui_init(0xfffec900, s); + omap_mpui_init(system_memory, 0xfffec900, s); - s->private_tipb = omap_tipb_bridge_init(0xfffeca00, + s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00, s->irq[0][OMAP_INT_BRIDGE_PRIV], omap_findclk(s, "tipb_ck")); - s->public_tipb = omap_tipb_bridge_init(0xfffed300, + s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300, s->irq[0][OMAP_INT_BRIDGE_PUB], omap_findclk(s, "tipb_ck")); - omap_tcmi_init(0xfffecc00, s); + omap_tcmi_init(system_memory, 0xfffecc00, s); s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], omap_findclk(s, "uart1_ck"), @@ -3828,9 +3905,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, "uart3", serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); - omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1")); - omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); - omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); + omap_dpll_init(system_memory, + &s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1")); + omap_dpll_init(system_memory, + &s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); + omap_dpll_init(system_memory, + &s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { @@ -3841,7 +3921,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); - s->mpuio = omap_mpuio_init(0xfffb5000, + s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000, s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], s->wakeup, omap_findclk(s, "clk32-kHz")); @@ -3852,27 +3932,34 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[0][OMAP_INT_GPIO_BANK1]); sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000); - s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], + s->microwire = omap_uwire_init(system_memory, + 0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); - omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck")); - omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck")); + omap_pwl_init(system_memory, 0xfffb5800, s, omap_findclk(s, "armxor_ck")); + omap_pwt_init(system_memory, 0xfffb6000, s, omap_findclk(s, "armxor_ck")); s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); - s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], + s->rtc = omap_rtc_init(system_memory, 0xfffb4800, + &s->irq[1][OMAP_INT_RTC_TIMER], omap_findclk(s, "clk32-kHz")); - s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX], + s->mcbsp1 = omap_mcbsp_init(system_memory, + 0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX], &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); - s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX], + s->mcbsp2 = omap_mcbsp_init(system_memory, + 0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX], &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); - s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], + s->mcbsp3 = omap_mcbsp_init(system_memory, + 0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); - s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz")); - s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz")); + s->led[0] = omap_lpg_init(system_memory, + 0xfffbd000, omap_findclk(s, "clk32-kHz")); + s->led[1] = omap_lpg_init(system_memory, + 0xfffbd800, omap_findclk(s, "clk32-kHz")); /* Register mappings not currenlty implemented: * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) @@ -3889,8 +3976,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, * DSP MMU fffed200 - fffed2ff */ - omap_setup_dsp_mapping(omap15xx_dsp_mm); - omap_setup_mpui_io(s); + omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm); + omap_setup_mpui_io(system_memory, s); qemu_register_reset(omap1_mpu_reset, s); diff --git a/hw/omap2.c b/hw/omap2.c index ca088d9f53..3d529cefd6 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -2284,8 +2284,10 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, s->port->addr_valid = omap2_validate_addr; /* Register SDRAM and SRAM ports for fast DMA transfers. */ - soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size); - soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size); + soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(q2_base), + OMAP2_Q2_BASE, s->sdram_size); + soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(sram_base), + OMAP2_SRAM_BASE, s->sram_size); s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19), s->irq[0][OMAP_INT_24XX_UART1_IRQ], diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c index 02f0c52107..7fc82a2526 100644 --- a/hw/omap_gpmc.c +++ b/hw/omap_gpmc.c @@ -569,6 +569,13 @@ static uint64_t omap_gpmc_read(void *opaque, target_phys_addr_t addr, case 0x1ec: /* GPMC_PREFETCH_CONTROL */ return s->prefetch.startengine; case 0x1f0: /* GPMC_PREFETCH_STATUS */ + /* NB: The OMAP3 TRM is inconsistent about whether the GPMC + * FIFOTHRESHOLDSTATUS bit should be set when + * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD. + * Apparently the underlying functional spec from which the TRM was + * created states that the behaviour is ">=", and this also + * makes more conceptual sense. + */ return (s->prefetch.fifopointer << 24) | ((s->prefetch.fifopointer >= ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) | @@ -632,7 +639,7 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr, break; case 0x018: /* GPMC_IRQSTATUS */ - s->irqen &= ~value; + s->irqst &= ~value; omap_gpmc_int_update(s); break; diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index a9054227e2..29e604863d 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -24,8 +24,6 @@ struct omap_lcd_panel_s { qemu_irq irq; DisplayState *state; - ram_addr_t imif_base; - ram_addr_t emiff_base; int plm; int tft; @@ -436,8 +434,7 @@ void omap_lcdc_reset(struct omap_lcd_panel_s *s) } struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, - struct omap_dma_lcd_channel_s *dma, - ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk) + struct omap_dma_lcd_channel_s *dma, omap_clk clk) { int iomemtype; struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) @@ -445,8 +442,6 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, s->irq = irq; s->dma = dma; - s->imif_base = imif_base; - s->emiff_base = emiff_base; omap_lcdc_reset(s); iomemtype = cpu_register_io_memory(omap_lcdc_readfn, diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 15cfbb52f3..fe535459df 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -32,6 +32,7 @@ #include "arm-misc.h" #include "flash.h" #include "blockdev.h" +#include "exec-memory.h" /*****************************************************************************/ /* Siemens SX1 Cellphone V1 */ @@ -121,6 +122,7 @@ static void sx1_init(ram_addr_t ram_size, const int version) { struct omap_mpu_state_s *cpu; + MemoryRegion *address_space = get_system_memory(); int io; static uint32_t cs0val = 0x00213090; static uint32_t cs1val = 0x00215070; @@ -135,7 +137,7 @@ static void sx1_init(ram_addr_t ram_size, flash_size = flash2_size; } - cpu = omap310_mpu_init(sx1_binfo.ram_size, cpu_model); + cpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model); /* External Flash (EMIFS) */ cpu_register_physical_memory(OMAP_CS0_BASE, flash_size, @@ -25,6 +25,7 @@ #include "arm-misc.h" #include "devices.h" #include "loader.h" +#include "exec-memory.h" static uint32_t static_readb(void *opaque, target_phys_addr_t offset) { @@ -198,6 +199,7 @@ static void palmte_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + MemoryRegion *address_space_mem = get_system_memory(); struct omap_mpu_state_s *cpu; int flash_size = 0x00800000; int sdram_size = palmte_binfo.ram_size; @@ -209,7 +211,7 @@ static void palmte_init(ram_addr_t ram_size, int rom_size, rom_loaded = 0; DisplayState *ds = get_displaystate(); - cpu = omap310_mpu_init(sdram_size, cpu_model); + cpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); /* External Flash (EMIFS) */ cpu_register_physical_memory(OMAP_CS0_BASE, flash_size, @@ -965,7 +965,7 @@ void pc_memory_init(MemoryRegion *system_memory, const char *initrd_filename, ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, - MemoryRegion *pci_memory, + MemoryRegion *rom_memory, MemoryRegion **ram_memory) { char *filename; @@ -1029,7 +1029,7 @@ void pc_memory_init(MemoryRegion *system_memory, isa_bios = g_malloc(sizeof(*isa_bios)); memory_region_init_alias(isa_bios, "isa-bios", bios, bios_size - isa_bios_size, isa_bios_size); - memory_region_add_subregion_overlap(pci_memory, + memory_region_add_subregion_overlap(rom_memory, 0x100000 - isa_bios_size, isa_bios, 1); @@ -1037,13 +1037,13 @@ void pc_memory_init(MemoryRegion *system_memory, option_rom_mr = g_malloc(sizeof(*option_rom_mr)); memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE); - memory_region_add_subregion_overlap(pci_memory, + memory_region_add_subregion_overlap(rom_memory, PC_ROM_MIN_VGA, option_rom_mr, 1); /* map all the bios at the top of memory */ - memory_region_add_subregion(pci_memory, + memory_region_add_subregion(rom_memory, (uint32_t)(-bios_size), bios); @@ -137,7 +137,7 @@ void pc_memory_init(MemoryRegion *system_memory, const char *initrd_filename, ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, - MemoryRegion *pci_memory, + MemoryRegion *rom_memory, MemoryRegion **ram_memory); qemu_irq *pc_allocate_cpu_irq(void); void pc_vga_init(PCIBus *pci_bus); diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 75d96d97c6..0144534e82 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -97,6 +97,7 @@ static void pc_init1(MemoryRegion *system_memory, ISADevice *rtc_state; MemoryRegion *ram_memory; MemoryRegion *pci_memory; + MemoryRegion *rom_memory; pc_cpus_init(cpu_model); @@ -112,15 +113,21 @@ static void pc_init1(MemoryRegion *system_memory, below_4g_mem_size = ram_size; } - pci_memory = g_new(MemoryRegion, 1); - memory_region_init(pci_memory, "pci", INT64_MAX); + if (pci_enabled) { + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + rom_memory = pci_memory; + } else { + pci_memory = NULL; + rom_memory = system_memory; + } /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(system_memory, kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size, - pci_memory, &ram_memory); + pci_enabled ? rom_memory : system_memory, &ram_memory); } if (!xen_enabled()) { @@ -150,6 +157,7 @@ static void pc_init1(MemoryRegion *system_memory, pci_bus = NULL; i440fx_state = NULL; isa_bus_new(NULL); + no_hpet = 1; } isa_bus_irqs(isa_irq); @@ -312,11 +312,6 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev) bus->hotplug_qdev = qdev; } -void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base) -{ - bus->mem_base = base; -} - PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, @@ -833,12 +828,6 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, return pci_dev; } -static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus, - target_phys_addr_t addr) -{ - return addr + bus->mem_base; -} - static void pci_unregister_io_regions(PCIDevice *pci_dev) { PCIIORegion *r; @@ -889,7 +878,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, r = &pci_dev->io_regions[region_num]; r->addr = PCI_BAR_UNMAPPED; r->size = size; - r->filtered_size = size; r->type = type; r->memory = NULL; @@ -920,41 +908,6 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) return pci_dev->io_regions[region_num].addr; } -static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size, - uint8_t type) -{ - pcibus_t base = *addr; - pcibus_t limit = *addr + *size - 1; - PCIDevice *br; - - for (br = d->bus->parent_dev; br; br = br->bus->parent_dev) { - uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); - - if (type & PCI_BASE_ADDRESS_SPACE_IO) { - if (!(cmd & PCI_COMMAND_IO)) { - goto no_map; - } - } else { - if (!(cmd & PCI_COMMAND_MEMORY)) { - goto no_map; - } - } - - base = MAX(base, pci_bridge_get_base(br, type)); - limit = MIN(limit, pci_bridge_get_limit(br, type)); - } - - if (base > limit) { - goto no_map; - } - *addr = base; - *size = limit - base + 1; - return; -no_map: - *addr = PCI_BAR_UNMAPPED; - *size = 0; -} - static pcibus_t pci_bar_address(PCIDevice *d, int reg, uint8_t type, pcibus_t size) { @@ -1024,7 +977,7 @@ static void pci_update_mappings(PCIDevice *d) { PCIIORegion *r; int i; - pcibus_t new_addr, filtered_size; + pcibus_t new_addr; for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; @@ -1035,14 +988,8 @@ static void pci_update_mappings(PCIDevice *d) new_addr = pci_bar_address(d, i, r->type, r->size); - /* bridge filtering */ - filtered_size = r->size; - if (new_addr != PCI_BAR_UNMAPPED) { - pci_bridge_filter(d, &new_addr, &filtered_size, r->type); - } - /* This bar isn't changed */ - if (new_addr == r->addr && filtered_size == r->filtered_size) + if (new_addr == r->addr) continue; /* now do the real mapping */ @@ -1050,15 +997,7 @@ static void pci_update_mappings(PCIDevice *d) memory_region_del_subregion(r->address_space, r->memory); } r->addr = new_addr; - r->filtered_size = filtered_size; if (r->addr != PCI_BAR_UNMAPPED) { - /* - * TODO: currently almost all the map funcions assumes - * filtered_size == size and addr & ~(size - 1) == addr. - * However with bridge filtering, they aren't always true. - * Teach them such cases, such that filtered_size < size and - * addr & (size - 1) != 0. - */ if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { memory_region_add_subregion_overlap(r->address_space, r->addr, @@ -1066,8 +1005,7 @@ static void pci_update_mappings(PCIDevice *d) 1); } else { memory_region_add_subregion_overlap(r->address_space, - pci_to_cpu_addr(d->bus, - r->addr), + r->addr, r->memory, 1); } @@ -1576,22 +1514,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, return res; } -static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d) -{ - pci_update_mappings(d); -} - -void pci_bridge_update_mappings(PCIBus *b) -{ - PCIBus *child; - - pci_for_each_device_under_bus(b, pci_bridge_update_mappings_fn); - - QLIST_FOREACH(child, &b->child, sibling) { - pci_bridge_update_mappings(child); - } -} - /* Whether a given bus number is in range of the secondary * bus of the given bridge device. */ static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) @@ -2028,12 +1950,6 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; } -/* Reserve space for capability at a known offset (to call after load). */ -void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size) -{ - memset(pdev->used + offset, 0xff, size); -} - uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) { return pci_find_capability_list(pdev, cap_id, NULL); @@ -90,7 +90,6 @@ typedef struct PCIIORegion { pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ #define PCI_BAR_UNMAPPED (~(pcibus_t)0) pcibus_t size; - pcibus_t filtered_size; uint8_t type; MemoryRegion *memory; MemoryRegion *address_space; @@ -209,8 +208,6 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); -void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size); - uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); @@ -255,8 +252,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, void pci_device_reset(PCIDevice *dev); void pci_bus_reset(PCIBus *bus); -void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base); - PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, @@ -277,7 +272,6 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, void do_pci_info_print(Monitor *mon, const QObject *data); void do_pci_info(Monitor *mon, QObject **ret_data); -void pci_bridge_update_mappings(PCIBus *b); void pci_device_deassert_intx(PCIDevice *dev); diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index 464d89708f..b6287cdc6d 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -135,6 +135,76 @@ pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) return limit; } +static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, + uint8_t type, const char *name, + MemoryRegion *space, + 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); + /* 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; + + memory_region_init_alias(alias, name, space, base, size); + memory_region_add_subregion_overlap(parent_space, base, alias, 1); +} + +static void pci_bridge_cleanup_alias(MemoryRegion *alias, + MemoryRegion *parent_space) +{ + memory_region_del_subregion(parent_space, alias); + memory_region_destroy(alias); +} + +static void pci_bridge_region_init(PCIBridge *br) +{ + PCIBus *parent = br->dev.bus; + uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); + + pci_bridge_init_alias(br, &br->alias_pref_mem, + PCI_BASE_ADDRESS_MEM_PREFETCH, + "pci_bridge_pref_mem", + &br->address_space_mem, + parent->address_space_mem, + cmd & PCI_COMMAND_MEMORY); + pci_bridge_init_alias(br, &br->alias_mem, + PCI_BASE_ADDRESS_SPACE_MEMORY, + "pci_bridge_mem", + &br->address_space_mem, + parent->address_space_mem, + cmd & PCI_COMMAND_MEMORY); + pci_bridge_init_alias(br, &br->alias_io, + PCI_BASE_ADDRESS_SPACE_IO, + "pci_bridge_io", + &br->address_space_io, + parent->address_space_io, + cmd & PCI_COMMAND_IO); + /* TODO: optinal VGA and VGA palette snooping support. */ +} + +static void pci_bridge_region_cleanup(PCIBridge *br) +{ + PCIBus *parent = br->dev.bus; + pci_bridge_cleanup_alias(&br->alias_io, + parent->address_space_io); + pci_bridge_cleanup_alias(&br->alias_mem, + parent->address_space_mem); + pci_bridge_cleanup_alias(&br->alias_pref_mem, + parent->address_space_mem); +} + +static void pci_bridge_update_mappings(PCIBridge *br) +{ + /* Make updates atomic to: handle the case of one VCPU updating the bridge + * while another accesses an unaffected region. */ + memory_region_transaction_begin(); + pci_bridge_region_cleanup(br); + pci_bridge_region_init(br); + memory_region_transaction_commit(); +} + /* default write_config function for PCI-to-PCI bridge */ void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) @@ -145,13 +215,15 @@ void pci_bridge_write_config(PCIDevice *d, pci_default_write_config(d, address, val, len); - if (/* io base/limit */ + if (ranges_overlap(address, len, PCI_COMMAND, 2) || + + /* io base/limit */ ranges_overlap(address, len, PCI_IO_BASE, 2) || /* memory base/limit, prefetchable base/limit and io base/limit upper 16 */ ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { - pci_bridge_update_mappings(&s->sec_bus); + pci_bridge_update_mappings(s); } newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); @@ -246,7 +318,11 @@ int pci_bridge_initfn(PCIDevice *dev) br->bus_name); sec_bus->parent_dev = dev; sec_bus->map_irq = br->map_irq; - + sec_bus->address_space_mem = &br->address_space_mem; + memory_region_init(&br->address_space_mem, "pci_pridge_pci", INT64_MAX); + sec_bus->address_space_io = &br->address_space_io; + memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); + pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); return 0; @@ -258,6 +334,9 @@ int pci_bridge_exitfn(PCIDevice *pci_dev) PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); assert(QLIST_EMPTY(&s->sec_bus.child)); QLIST_REMOVE(&s->sec_bus, sibling); + pci_bridge_region_cleanup(s); + memory_region_destroy(&s->address_space_mem); + memory_region_destroy(&s->address_space_io); /* qbus_free() is called automatically by qdev_free() */ return 0; } diff --git a/hw/pci_internals.h b/hw/pci_internals.h index c7fd23dc54..96690b72d3 100644 --- a/hw/pci_internals.h +++ b/hw/pci_internals.h @@ -24,7 +24,6 @@ struct PCIBus { void *irq_opaque; PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX]; PCIDevice *parent_dev; - target_phys_addr_t mem_base; MemoryRegion *address_space_mem; MemoryRegion *address_space_io; @@ -42,6 +41,24 @@ struct PCIBridge { /* private member */ PCIBus sec_bus; + /* + * Memory regions for the bridge's address spaces. These regions are not + * directly added to system_memory/system_io or its descendants. + * Bridge's secondary bus points to these, so that devices + * under the bridge see these regions as its address spaces. + * The regions are as large as the entire address space - + * they don't take into account any windows. + */ + MemoryRegion address_space_mem; + MemoryRegion address_space_io; + /* + * Aliases for each of the address space windows that the bridge + * can forward. Mapped into the bridge's parent's address space, + * as subregions. + */ + MemoryRegion alias_pref_mem; + MemoryRegion alias_mem; + MemoryRegion alias_io; pci_map_irq_fn map_irq; const char *bus_name; }; diff --git a/hw/pci_regs.h b/hw/pci_regs.h index e8840964ac..e8357c3ea6 100644 --- a/hw/pci_regs.h +++ b/hw/pci_regs.h @@ -211,6 +211,7 @@ #define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */ #define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 51e132050f..fb2a00caad 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -285,7 +285,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev) pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0); pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0); - pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ pci_conf[PCI_MIN_GNT] = 0x06; pci_conf[PCI_MAX_LAT] = 0xff; diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 7ce95b679c..e0e54aa857 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -524,6 +524,8 @@ static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) return -EINVAL; if (fn > 7) return -EINVAL; + if (slot > 31) + return -EINVAL; *ptr = slot << 3 | fn; return 0; } @@ -207,6 +207,12 @@ int qdev_device_help(QemuOpts *opts) } error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name); } + for (prop = info->bus_info->props; prop && prop->name; prop++) { + if (!prop->info->parse) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name); + } return 1; } @@ -1453,10 +1453,11 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) } } -static void qxl_vm_change_state_handler(void *opaque, int running, int reason) +static void qxl_vm_change_state_handler(void *opaque, int running, + RunState state) { PCIQXLDevice *qxl = opaque; - qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason); + qemu_spice_vm_change_state_handler(&qxl->ssd, running, state); if (running) { /* diff --git a/hw/rtl8139.c b/hw/rtl8139.c index c5de5b48ba..37539508c5 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3464,7 +3464,7 @@ static int pci_rtl8139_init(PCIDevice *dev) uint8_t *pci_conf; pci_conf = s->dev.config; - pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */ + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ /* TODO: start of capability list, but no capability * list bit in status register, and offset 0xdc seems unused. */ pci_conf[PCI_CAPABILITY_LIST] = 0xdc; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 160eaee693..aca65a16df 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -542,15 +542,15 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) break; case 1: case 2: - cmd->xfer = buf[8] | (buf[7] << 8); + cmd->xfer = lduw_be_p(&buf[7]); cmd->len = 10; break; case 4: - cmd->xfer = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); + cmd->xfer = ldl_be_p(&buf[10]); cmd->len = 16; break; case 5: - cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); + cmd->xfer = ldl_be_p(&buf[6]); cmd->len = 12; break; default: @@ -710,23 +710,15 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd) switch (buf[0] >> 5) { case 0: - lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) | - (((uint64_t) buf[1] & 0x1f) << 16); + lba = ldl_be_p(&buf[0]) & 0x1fffff; break; case 1: case 2: - lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | - ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); + case 5: + lba = ldl_be_p(&buf[2]); break; case 4: - lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) | - ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) | - ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) | - ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56); - break; - case 5: - lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | - ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); + lba = ldq_be_p(&buf[2]); break; default: lba = -1; @@ -772,6 +764,11 @@ const struct SCSISense sense_code_NO_MEDIUM = { .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 }; +/* LUN not ready, medium removal prevented */ +const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { + .key = NOT_READY, .asc = 0x53, .ascq = 0x00 +}; + /* Hardware error, internal target failure */ const struct SCSISense sense_code_TARGET_FAILURE = { .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 @@ -807,6 +804,11 @@ const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = { .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 }; +/* Illegal request, medium removal prevented */ +const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { + .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00 +}; + /* Command aborted, I/O process terminated */ const struct SCSISense sense_code_IO_ERROR = { .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 @@ -977,13 +979,11 @@ static const char *scsi_command_name(uint8_t cmd) [ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16", [ LOCATE_16 ] = "LOCATE_16", [ WRITE_SAME_16 ] = "WRITE_SAME_16", - [ ERASE_16 ] = "ERASE_16", + /* ERASE_16 and WRITE_SAME_16 use the same operation code */ [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", [ WRITE_LONG_16 ] = "WRITE_LONG_16", [ REPORT_LUNS ] = "REPORT_LUNS", [ BLANK ] = "BLANK", - [ MAINTENANCE_IN ] = "MAINTENANCE_IN", - [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT", [ MOVE_MEDIUM ] = "MOVE_MEDIUM", [ LOAD_UNLOAD ] = "LOAD_UNLOAD", [ READ_12 ] = "READ_12", diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 9724d0fe9a..e843f712c2 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -37,6 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "scsi-defs.h" #include "sysemu.h" #include "blockdev.h" +#include "block_int.h" #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 @@ -54,6 +55,7 @@ typedef struct SCSIDiskReq { /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ uint64_t sector; uint32_t sector_count; + uint32_t buflen; struct iovec iov; QEMUIOVector qiov; uint32_t status; @@ -72,16 +74,20 @@ struct SCSIDiskState QEMUBH *bh; char *version; char *serial; + bool tray_open; + bool tray_locked; }; static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); -static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); +static int scsi_disk_emulate_command(SCSIDiskReq *r); static void scsi_free_request(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - qemu_vfree(r->iov.iov_base); + if (r->iov.iov_base) { + qemu_vfree(r->iov.iov_base); + } } /* Helper function for command completion with sense. */ @@ -105,6 +111,19 @@ static void scsi_cancel_io(SCSIRequest *req) r->req.aiocb = NULL; } +static uint32_t scsi_init_iovec(SCSIDiskReq *r) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + if (!r->iov.iov_base) { + r->buflen = SCSI_DMA_BUF_SIZE; + r->iov.iov_base = qemu_blockalign(s->bs, r->buflen); + } + r->iov.iov_len = MIN(r->sector_count * 512, r->buflen); + qemu_iovec_init_external(&r->qiov, &r->iov, 1); + return r->qiov.size / 512; +} + static void scsi_read_complete(void * opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; @@ -122,12 +141,12 @@ static void scsi_read_complete(void * opaque, int ret) } } - DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len); + DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size); - n = r->iov.iov_len / 512; + n = r->qiov.size / 512; r->sector += n; r->sector_count -= n; - scsi_req_data(&r->req, r->iov.iov_len); + scsi_req_data(&r->req, r->qiov.size); } static void scsi_flush_complete(void * opaque, int ret) @@ -178,13 +197,10 @@ static void scsi_read_data(SCSIRequest *req) return; } - n = r->sector_count; - if (n > SCSI_DMA_BUF_SIZE / 512) - n = SCSI_DMA_BUF_SIZE / 512; - - r->iov.iov_len = n * 512; - qemu_iovec_init_external(&r->qiov, &r->iov, 1); - + if (s->tray_open) { + scsi_read_complete(r, -ENOMEDIUM); + } + n = scsi_init_iovec(r); bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n, scsi_read_complete, r); @@ -211,7 +227,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) r->status |= SCSI_REQ_STATUS_RETRY | type; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(VMSTOP_DISKFULL); + vm_stop(RSTATE_IO_ERROR); } else { switch (error) { case ENOMEM: @@ -233,7 +249,6 @@ static void scsi_write_complete(void * opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - uint32_t len; uint32_t n; if (r->req.aiocb != NULL) { @@ -247,19 +262,15 @@ static void scsi_write_complete(void * opaque, int ret) } } - n = r->iov.iov_len / 512; + n = r->qiov.size / 512; r->sector += n; r->sector_count -= n; if (r->sector_count == 0) { scsi_req_complete(&r->req, GOOD); } else { - len = r->sector_count * 512; - if (len > SCSI_DMA_BUF_SIZE) { - len = SCSI_DMA_BUF_SIZE; - } - r->iov.iov_len = len; - DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len); - scsi_req_data(&r->req, len); + scsi_init_iovec(r); + DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size); + scsi_req_data(&r->req, r->qiov.size); } } @@ -278,18 +289,19 @@ static void scsi_write_data(SCSIRequest *req) return; } - n = r->iov.iov_len / 512; + n = r->qiov.size / 512; if (n) { - qemu_iovec_init_external(&r->qiov, &r->iov, 1); - + if (s->tray_open) { + scsi_write_complete(r, -ENOMEDIUM); + } bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE); r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, - scsi_write_complete, r); + scsi_write_complete, r); if (r->req.aiocb == NULL) { scsi_write_complete(r, -ENOMEM); } } else { - /* Invoke completion routine to fetch data from host. */ + /* Called for the first time. Ask the driver to send us more data. */ scsi_write_complete(r, 0); } } @@ -320,7 +332,7 @@ static void scsi_dma_restart_bh(void *opaque) scsi_write_data(&r->req); break; case SCSI_REQ_STATUS_RETRY_FLUSH: - ret = scsi_disk_emulate_command(r, r->iov.iov_base); + ret = scsi_disk_emulate_command(r); if (ret == 0) { scsi_req_complete(&r->req, GOOD); } @@ -329,7 +341,7 @@ static void scsi_dma_restart_bh(void *opaque) } } -static void scsi_dma_restart_cb(void *opaque, int running, int reason) +static void scsi_dma_restart_cb(void *opaque, int running, RunState state) { SCSIDiskState *s = opaque; @@ -664,7 +676,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, p[5] = 0xff; /* CD DA, DA accurate, RW supported, RW corrected, C2 errors, ISRC, UPC, Bar code */ - p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0); + p[6] = 0x2d | (s->tray_locked ? 2 : 0); /* Locking supported, jumper present, eject, tray */ p[7] = 0; /* no volume & mute control, no changer */ @@ -814,16 +826,55 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) return toclen; } -static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) +static int scsi_disk_emulate_start_stop(SCSIDiskReq *r) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + bool start = req->cmd.buf[4] & 1; + bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */ + + if (s->qdev.type == TYPE_ROM && loej) { + if (!start && !s->tray_open && s->tray_locked) { + scsi_check_condition(r, + bdrv_is_inserted(s->bs) + ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED) + : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED)); + return -1; + } + bdrv_eject(s->bs, !start); + s->tray_open = !start; + } + return 0; +} + +static int scsi_disk_emulate_command(SCSIDiskReq *r) { SCSIRequest *req = &r->req; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); uint64_t nb_sectors; + uint8_t *outbuf; int buflen = 0; + if (!r->iov.iov_base) { + /* + * FIXME: we shouldn't return anything bigger than 4k, but the code + * requires the buffer to be as big as req->cmd.xfer in several + * places. So, do not allow CDBs with a very large ALLOCATION + * LENGTH. The real fix would be to modify scsi_read_data and + * dma_buf_read, so that they return data beyond the buflen + * as all zeros. + */ + if (req->cmd.xfer > 65536) { + goto illegal_request; + } + r->buflen = MAX(4096, req->cmd.xfer); + r->iov.iov_base = qemu_blockalign(s->bs, r->buflen); + } + + outbuf = r->iov.iov_base; switch (req->cmd.buf[0]) { case TEST_UNIT_READY: - if (!bdrv_is_inserted(s->bs)) + if (s->tray_open || !bdrv_is_inserted(s->bs)) goto not_ready; break; case INQUIRY: @@ -859,13 +910,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) goto illegal_request; break; case START_STOP: - if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) { - /* load/eject medium */ - bdrv_eject(s->bs, !(req->cmd.buf[4] & 1)); + if (scsi_disk_emulate_start_stop(r) < 0) { + return -1; } break; case ALLOW_MEDIUM_REMOVAL: - bdrv_set_locked(s->bs, req->cmd.buf[4] & 1); + s->tray_locked = req->cmd.buf[4] & 1; + bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1); break; case READ_CAPACITY_10: /* The normal LEN field for this command is zero. */ @@ -946,7 +997,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) return buflen; not_ready: - if (!bdrv_is_inserted(s->bs)) { + if (s->tray_open || !bdrv_is_inserted(s->bs)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); } else { scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); @@ -971,11 +1022,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int32_t len; uint8_t command; - uint8_t *outbuf; int rc; command = buf[0]; - outbuf = (uint8_t *)r->iov.iov_base; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]); #ifdef DEBUG_SCSI @@ -1004,7 +1053,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) case GET_CONFIGURATION: case SERVICE_ACTION_IN_16: case VERIFY_10: - rc = scsi_disk_emulate_command(r, outbuf); + rc = scsi_disk_emulate_command(r); if (rc < 0) { return 0; } @@ -1143,6 +1192,27 @@ static void scsi_destroy(SCSIDevice *dev) blockdev_mark_auto_del(s->qdev.conf.bs); } +static void scsi_cd_change_media_cb(void *opaque, bool load) +{ + ((SCSIDiskState *)opaque)->tray_open = !load; +} + +static bool scsi_cd_is_tray_open(void *opaque) +{ + return ((SCSIDiskState *)opaque)->tray_open; +} + +static bool scsi_cd_is_medium_locked(void *opaque) +{ + return ((SCSIDiskState *)opaque)->tray_locked; +} + +static const BlockDevOps scsi_cd_block_ops = { + .change_media_cb = scsi_cd_change_media_cb, + .is_tray_open = scsi_cd_is_tray_open, + .is_medium_locked = scsi_cd_is_medium_locked, +}; + static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); @@ -1177,6 +1247,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) } if (scsi_type == TYPE_ROM) { + bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s); s->qdev.blocksize = 2048; } else if (scsi_type == TYPE_DISK) { s->qdev.blocksize = s->qdev.conf.logical_block_size; @@ -1185,11 +1256,10 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) return -1; } s->cluster_size = s->qdev.blocksize / 512; - s->bs->buffer_alignment = s->qdev.blocksize; + bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize); s->qdev.type = scsi_type; qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); - bdrv_set_removable(s->bs, scsi_type == TYPE_ROM); add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0"); return 0; } @@ -1234,11 +1304,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIRequest *req; - SCSIDiskReq *r; req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private); - r = DO_UPCAST(SCSIDiskReq, req, req); - r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); return req; } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index cb5d4f125d..8f6b70df2b 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -244,12 +244,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req) static void scsi_req_fixup(SCSIRequest *req) { switch(req->cmd.buf[0]) { - case WRITE_10: - req->cmd.buf[1] &= ~0x08; /* disable FUA */ - break; - case READ_10: - req->cmd.buf[1] &= ~0x08; /* disable FUA */ - break; case REWIND: case START_STOP: if (req->dev->type == TYPE_TAPE) { @@ -450,7 +444,6 @@ static int scsi_generic_initfn(SCSIDevice *dev) } } DPRINTF("block size %d\n", s->qdev.blocksize); - bdrv_set_removable(s->bs, 0); return 0; } @@ -3,7 +3,6 @@ #include "qdev.h" #include "block.h" -#include "block_int.h" #define MAX_SCSI_DEVS 255 @@ -136,6 +135,8 @@ extern const struct SCSISense sense_code_NO_SENSE; extern const struct SCSISense sense_code_LUN_NOT_READY; /* LUN not ready, Medium not present */ extern const struct SCSISense sense_code_NO_MEDIUM; +/* LUN not ready, medium removal prevented */ +extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED; /* Hardware error, internal target failure */ extern const struct SCSISense sense_code_TARGET_FAILURE; /* Illegal request, invalid command operation code */ @@ -150,6 +151,8 @@ extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED; /* Illegal request, Incompatible format */ extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT; +/* Illegal request, medium removal prevented */ +extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED; /* Command aborted, I/O process terminated */ extern const struct SCSISense sense_code_IO_ERROR; /* Command aborted, I_T Nexus loss occurred */ @@ -419,7 +419,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) sd->pwd_len = 0; } -static void sd_cardchange(void *opaque) +static void sd_cardchange(void *opaque, bool load) { SDState *sd = opaque; diff --git a/hw/soc_dma.h b/hw/soc_dma.h index c0ebb8d715..904b26c5a8 100644 --- a/hw/soc_dma.h +++ b/hw/soc_dma.h @@ -18,6 +18,8 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "memory.h" + struct soc_dma_s; struct soc_dma_ch_s; typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len); @@ -105,9 +107,3 @@ static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma, { return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1); } - -static inline void soc_dma_port_add_mem_ram(struct soc_dma_s *dma, - ram_addr_t offset, target_phys_addr_t virt_base, size_t size) -{ - return soc_dma_port_add_mem(dma, qemu_get_ram_ptr(offset), virt_base, size); -} diff --git a/hw/sun4u.c b/hw/sun4u.c index 32e6ab9beb..6afb0e7158 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -763,7 +763,6 @@ static void sun4uv_init(ram_addr_t RAM_size, irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2, &pci_bus3); - isa_mem_base = APB_PCI_IO_BASE; pci_vga_init(pci_bus); // XXX Should be pci_bus3 diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index e9e0789795..27376a2351 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -2291,7 +2291,7 @@ static int usb_ehci_initfn(PCIDevice *dev) pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00); //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); - pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); // interrupt pin 3 + pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */ pci_set_byte(&pci_conf[PCI_MIN_GNT], 0); pci_set_byte(&pci_conf[PCI_MAX_LAT], 0); diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 503ca2d31f..c3be65a2e9 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1780,8 +1780,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev) OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev); ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */ - /* TODO: RST# value should be 0. */ - ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ + ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0, ohci->masterbus, ohci->firstport) != 0) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 64f7b36c00..17992cf003 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1131,7 +1131,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) pci_conf[PCI_CLASS_PROG] = 0x00; /* TODO: reset value should be 0. */ - pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3 + pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */ pci_conf[USB_SBRN] = USB_RELEASE_1; // release number if (s->masterbus) { diff --git a/hw/vga-isa.c b/hw/vga-isa.c index 0d199015d7..6b5c8ed970 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -49,6 +49,7 @@ static int vga_initfn(ISADevice *dev) MemoryRegion *vga_io_memory; vga_common_init(s, VGA_RAM_SIZE); + s->legacy_address_space = isa_address_space(dev); vga_io_memory = vga_init_io(s); memory_region_add_subregion_overlap(isa_address_space(dev), isa_mem_base + 0x000a0000, @@ -149,7 +149,7 @@ static uint16_t expand2[256]; static uint8_t expand4to8[16]; static void vga_screen_dump(void *opaque, const char *filename); -static char *screen_dump_filename; +static const char *screen_dump_filename; static DisplayChangeListener *screen_dump_dcl; static void vga_update_memory_access(VGACommonState *s) @@ -181,6 +181,7 @@ static void vga_update_memory_access(VGACommonState *s) size = 0x8000; break; } + base += isa_mem_base; region = g_malloc(sizeof(*region)); memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size); memory_region_add_subregion_overlap(s->legacy_address_space, base, @@ -2318,7 +2319,6 @@ static void vga_save_dpy_update(DisplayState *ds, { if (screen_dump_filename) { ppm_save(screen_dump_filename, ds->surface); - screen_dump_filename = NULL; } } @@ -2396,8 +2396,8 @@ static void vga_screen_dump(void *opaque, const char *filename) if (!screen_dump_dcl) screen_dump_dcl = vga_screen_dump_init(s->ds); - screen_dump_filename = (char *)filename; + screen_dump_filename = filename; vga_invalidate_display(s); vga_hw_update(); + screen_dump_filename = NULL; } - diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 072a88a382..5f8f4bdb9f 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -303,6 +303,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev) void virtio_balloon_exit(VirtIODevice *vdev) { VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev); + + qemu_remove_balloon_handler(s); unregister_savevm(s->qdev, "virtio-balloon", s); virtio_cleanup(vdev); } diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 4df23f4228..daa8e42be7 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -11,7 +11,7 @@ * */ -#include <qemu-common.h> +#include "qemu-common.h" #include "qemu-error.h" #include "trace.h" #include "blockdev.h" @@ -77,7 +77,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, req->next = s->rq; s->rq = req; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(VMSTOP_DISKFULL); + vm_stop(RSTATE_IO_ERROR); } else { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); bdrv_acct_done(s->bs, &req->acct); @@ -439,7 +439,8 @@ static void virtio_blk_dma_restart_bh(void *opaque) virtio_submit_multiwrite(s->bs, &mrb); } -static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason) +static void virtio_blk_dma_restart_cb(void *opaque, int running, + RunState state) { VirtIOBlock *s = opaque; @@ -599,9 +600,8 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, s->qdev = dev; register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); - bdrv_set_removable(s->bs, 0); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); - s->bs->buffer_alignment = conf->logical_block_size; + bdrv_set_buffer_alignment(s->bs, conf->logical_block_size); add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); diff --git a/hw/virtio.c b/hw/virtio.c index 13aa0faf27..7011b5b398 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -16,20 +16,12 @@ #include "trace.h" #include "qemu-error.h" #include "virtio.h" +#include "qemu-barrier.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ #define VIRTIO_PCI_VRING_ALIGN 4096 -/* QEMU doesn't strictly need write barriers since everything runs in - * lock-step. We'll leave the calls to wmb() in though to make it obvious for - * KVM or if kqemu gets SMP support. - * In any case, we must prevent the compiler from reordering the code. - * TODO: we likely need some rmb()/mb() as well. - */ - -#define wmb() __asm__ __volatile__("": : :"memory") - typedef struct VRingDesc { uint64_t addr; @@ -264,7 +256,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count) { uint16_t old, new; /* Make sure buffer is written before we update index. */ - wmb(); + smp_wmb(); trace_virtqueue_flush(vq, count); old = vring_used_idx(vq); new = old + count; @@ -324,7 +316,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa, /* Check they're not leading us off end of descriptors. */ next = vring_desc_next(desc_pa, i); /* Make sure compiler knows to grab that: we don't want it changing! */ - wmb(); + smp_wmb(); if (next >= max) { error_report("Desc next is %u", next); @@ -498,6 +490,16 @@ void virtio_update_irq(VirtIODevice *vdev) virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); } +void virtio_set_status(VirtIODevice *vdev, uint8_t val) +{ + trace_virtio_set_status(vdev, val); + + if (vdev->set_status) { + vdev->set_status(vdev, val); + } + vdev->status = val; +} + void virtio_reset(void *opaque) { VirtIODevice *vdev = opaque; @@ -837,7 +839,7 @@ void virtio_cleanup(VirtIODevice *vdev) g_free(vdev); } -static void virtio_vmstate_change(void *opaque, int running, int reason) +static void virtio_vmstate_change(void *opaque, int running, RunState state) { VirtIODevice *vdev = opaque; bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK); @@ -870,7 +872,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, vdev->queue_sel = 0; vdev->config_vector = VIRTIO_NO_VECTOR; vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); - vdev->vm_running = vm_running; + vdev->vm_running = runstate_is_running(); for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; diff --git a/hw/virtio.h b/hw/virtio.h index c1292647fe..2d18209fb2 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -18,7 +18,7 @@ #include "net.h" #include "qdev.h" #include "sysemu.h" -#include "block_int.h" +#include "block.h" #include "event_notifier.h" #ifdef CONFIG_LINUX #include "9p.h" @@ -135,14 +135,6 @@ struct VirtIODevice VMChangeStateEntry *vmstate; }; -static inline void virtio_set_status(VirtIODevice *vdev, uint8_t val) -{ - if (vdev->set_status) { - vdev->set_status(vdev, val); - } - vdev->status = val; -} - VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, void (*handle_output)(VirtIODevice *, VirtQueue *)); @@ -190,6 +182,7 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n); void virtio_queue_notify(VirtIODevice *vdev, int n); uint16_t virtio_queue_vector(VirtIODevice *vdev, int n); void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector); +void virtio_set_status(VirtIODevice *vdev, uint8_t val); void virtio_reset(void *opaque); void virtio_update_irq(VirtIODevice *vdev); diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 5c973ed507..b9fcc0e4ac 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -49,7 +49,7 @@ static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data) int can_write; SuperIOConfig *superio_conf = opaque; - DPRINTF("superio_ioport_writeb address 0x%x val 0x%x \n", addr, data); + DPRINTF("superio_ioport_writeb address 0x%x val 0x%x\n", addr, data); if (addr == 0x3f0) { superio_conf->index = data & 0xff; } else { @@ -73,12 +73,12 @@ static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data) switch (superio_conf->index) { case 0xe7: if ((data & 0xff) != 0xfe) { - DPRINTF("chage uart 1 base. unsupported yet \n"); + DPRINTF("chage uart 1 base. unsupported yet\n"); } break; case 0xe8: if ((data & 0xff) != 0xbe) { - DPRINTF("chage uart 2 base. unsupported yet \n"); + DPRINTF("chage uart 2 base. unsupported yet\n"); } break; @@ -95,7 +95,7 @@ static uint32_t superio_ioport_readb(void *opaque, uint32_t addr) { SuperIOConfig *superio_conf = opaque; - DPRINTF("superio_ioport_readb address 0x%x \n", addr); + DPRINTF("superio_ioport_readb address 0x%x\n", addr); return (superio_conf->config[superio_conf->index]); } @@ -133,7 +133,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address, { VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d); - DPRINTF("vt82c686b_write_config address 0x%x val 0x%x len 0x%x \n", + DPRINTF("vt82c686b_write_config address 0x%x val 0x%x len 0x%x\n", address, val, len); pci_default_write_config(d, address, val, len); @@ -285,7 +285,7 @@ static void pm_io_space_update(VT686PMState *s) static void pm_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { - DPRINTF("pm_write_config address 0x%x val 0x%x len 0x%x \n", + DPRINTF("pm_write_config address 0x%x val 0x%x len 0x%x\n", address, val, len); pci_default_write_config(d, address, val, len); } diff --git a/hw/watchdog.c b/hw/watchdog.c index 1c900a1189..71c6c7df63 100644 --- a/hw/watchdog.c +++ b/hw/watchdog.c @@ -132,7 +132,7 @@ void watchdog_perform_action(void) case WDT_PAUSE: /* same as 'stop' command in monitor */ watchdog_mon_event("pause"); - vm_stop(VMSTOP_WATCHDOG); + vm_stop(RSTATE_WATCHDOG); break; case WDT_DEBUG: diff --git a/hw/xen_backend.c b/hw/xen_backend.c index aa642675f8..d876cabb12 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -421,13 +421,13 @@ static int xen_be_try_init(struct XenDevice *xendev) } /* - * Try to connect xendev. Depends on the frontend being ready + * Try to initialise xendev. Depends on the frontend being ready * for it (shared ring and evtchn info in xenstore, state being * Initialised or Connected). * * Goes to Connected on success. */ -static int xen_be_try_connect(struct XenDevice *xendev) +static int xen_be_try_initialise(struct XenDevice *xendev) { int rc = 0; @@ -441,11 +441,11 @@ static int xen_be_try_connect(struct XenDevice *xendev) } } - if (xendev->ops->connect) { - rc = xendev->ops->connect(xendev); + if (xendev->ops->initialise) { + rc = xendev->ops->initialise(xendev); } if (rc != 0) { - xen_be_printf(xendev, 0, "connect() failed\n"); + xen_be_printf(xendev, 0, "initialise() failed\n"); return rc; } @@ -454,6 +454,29 @@ static int xen_be_try_connect(struct XenDevice *xendev) } /* + * Try to let xendev know that it is connected. Depends on the + * frontend being Connected. Note that this may be called more + * than once since the backend state is not modified. + */ +static void xen_be_try_connected(struct XenDevice *xendev) +{ + if (!xendev->ops->connected) { + return; + } + + if (xendev->fe_state != XenbusStateConnected) { + if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) { + xen_be_printf(xendev, 2, "frontend not ready, ignoring\n"); + } else { + xen_be_printf(xendev, 2, "frontend not ready (yet)\n"); + return; + } + } + + xendev->ops->connected(xendev); +} + +/* * Teardown connection. * * Goes to Closed when done. @@ -508,7 +531,12 @@ void xen_be_check_state(struct XenDevice *xendev) rc = xen_be_try_init(xendev); break; case XenbusStateInitWait: - rc = xen_be_try_connect(xendev); + rc = xen_be_try_initialise(xendev); + break; + case XenbusStateConnected: + /* xendev->be_state doesn't change */ + xen_be_try_connected(xendev); + rc = -1; break; case XenbusStateClosed: rc = xen_be_try_reset(xendev); diff --git a/hw/xen_backend.h b/hw/xen_backend.h index 6401c85a7e..3305630903 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -21,7 +21,8 @@ struct XenDevOps { uint32_t flags; void (*alloc)(struct XenDevice *xendev); int (*init)(struct XenDevice *xendev); - int (*connect)(struct XenDevice *xendev); + int (*initialise)(struct XenDevice *xendev); + void (*connected)(struct XenDevice *xendev); void (*event)(struct XenDevice *xendev); void (*disconnect)(struct XenDevice *xendev); int (*free)(struct XenDevice *xendev); diff --git a/hw/xen_console.c b/hw/xen_console.c index 5789bd09a5..edcb31ce66 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -212,7 +212,7 @@ out: return ret; } -static int con_connect(struct XenDevice *xendev) +static int con_initialise(struct XenDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); int limit; @@ -273,7 +273,7 @@ struct XenDevOps xen_console_ops = { .size = sizeof(struct XenConsole), .flags = DEVOPS_FLAG_IGNORE_STATE, .init = con_init, - .connect = con_connect, + .initialise = con_initialise, .event = con_event, .disconnect = con_disconnect, }; diff --git a/hw/xen_disk.c b/hw/xen_disk.c index da531a67dd..8a9fac499b 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -852,7 +852,7 @@ struct XenDevOps xen_blkdev_ops = { .flags = DEVOPS_FLAG_NEED_GNTDEV, .alloc = blk_alloc, .init = blk_init, - .connect = blk_connect, + .initialise = blk_connect, .disconnect = blk_disconnect, .event = blk_event, .free = blk_free, diff --git a/hw/xen_nic.c b/hw/xen_nic.c index b28b15670b..ef2a2d6997 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -25,7 +25,6 @@ #include <inttypes.h> #include <fcntl.h> #include <errno.h> -#include <pthread.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/types.h> @@ -433,7 +432,7 @@ struct XenDevOps xen_netdev_ops = { .size = sizeof(struct XenNetDev), .flags = DEVOPS_FLAG_NEED_GNTDEV, .init = net_init, - .connect = net_connect, + .initialise = net_connect, .event = net_event, .disconnect = net_disconnect, .free = net_free, diff --git a/hw/xenfb.c b/hw/xenfb.c index d532d3e898..1bcf171b01 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -351,15 +351,11 @@ static int input_init(struct XenDevice *xendev) return 0; } -static int input_connect(struct XenDevice *xendev) +static int input_initialise(struct XenDevice *xendev) { struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); int rc; - if (xenstore_read_fe_int(xendev, "request-abs-pointer", - &in->abs_pointer_wanted) == -1) - in->abs_pointer_wanted = 0; - if (!in->c.ds) { char *vfb = xenstore_read_str(NULL, "device/vfb"); if (vfb == NULL) { @@ -377,10 +373,24 @@ static int input_connect(struct XenDevice *xendev) return rc; qemu_add_kbd_event_handler(xenfb_key_event, in); + return 0; +} + +static void input_connected(struct XenDevice *xendev) +{ + struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); + + if (xenstore_read_fe_int(xendev, "request-abs-pointer", + &in->abs_pointer_wanted) == -1) { + in->abs_pointer_wanted = 0; + } + + if (in->qmouse) { + qemu_remove_mouse_event_handler(in->qmouse); + } in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in, in->abs_pointer_wanted, "Xen PVFB Mouse"); - return 0; } static void input_disconnect(struct XenDevice *xendev) @@ -865,7 +875,7 @@ static int fb_init(struct XenDevice *xendev) return 0; } -static int fb_connect(struct XenDevice *xendev) +static int fb_initialise(struct XenDevice *xendev) { struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev); struct xenfb_page *fb_page; @@ -959,7 +969,8 @@ static void fb_event(struct XenDevice *xendev) struct XenDevOps xen_kbdmouse_ops = { .size = sizeof(struct XenInput), .init = input_init, - .connect = input_connect, + .initialise = input_initialise, + .connected = input_connected, .disconnect = input_disconnect, .event = input_event, }; @@ -967,7 +978,7 @@ struct XenDevOps xen_kbdmouse_ops = { struct XenDevOps xen_framebuffer_ops = { .size = sizeof(struct XenFB), .init = fb_init, - .connect = fb_connect, + .initialise = fb_initialise, .disconnect = fb_disconnect, .event = fb_event, .frontend_changed = fb_frontend_changed, @@ -29,8 +29,6 @@ #include "hw/spapr.h" #include "hw/xics.h" -#include <pthread.h> - /* * ICP: Presentation layer */ diff --git a/hw/xtensa_dc232b.c b/hw/xtensa_dc232b.c new file mode 100644 index 0000000000..015d6aaa6b --- /dev/null +++ b/hw/xtensa_dc232b.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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 "sysemu.h" +#include "boards.h" +#include "loader.h" +#include "elf.h" +#include "memory.h" +#include "exec-memory.h" + +static uint64_t translate_phys_addr(void *env, uint64_t addr) +{ + return cpu_get_phys_page_debug(env, addr); +} + +static void dc232b_reset(void *env) +{ + cpu_reset(env); +} + +static void dc232b_init(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) +{ + CPUState *env = NULL; + MemoryRegion *ram, *rom; + int n; + + for (n = 0; n < smp_cpus; n++) { + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env->sregs[PRID] = n; + qemu_register_reset(dc232b_reset, env); + /* Need MMU initialized prior to ELF loading, + * so that ELF gets loaded into virtual addresses + */ + dc232b_reset(env); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size); + memory_region_add_subregion(get_system_memory(), 0, ram); + + rom = g_malloc(sizeof(*rom)); + memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000); + memory_region_add_subregion(get_system_memory(), 0xfe000000, rom); + + if (kernel_filename) { + uint64_t elf_entry; + uint64_t elf_lowaddr; +#ifdef TARGET_WORDS_BIGENDIAN + int success = load_elf(kernel_filename, translate_phys_addr, env, + &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); +#else + int success = load_elf(kernel_filename, translate_phys_addr, env, + &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0); +#endif + if (success > 0) { + env->pc = elf_entry; + } + } +} + +static void xtensa_dc232b_init(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) +{ + if (!cpu_model) { + cpu_model = "dc232b"; + } + dc232b_init(ram_size, boot_device, kernel_filename, kernel_cmdline, + initrd_filename, cpu_model); +} + +static QEMUMachine xtensa_dc232b_machine = { + .name = "dc232b", + .desc = "Diamond 232L Standard Core Rev.B (LE) (dc232b)", + .init = xtensa_dc232b_init, + .max_cpus = 4, +}; + +static void xtensa_dc232b_machine_init(void) +{ + qemu_register_machine(&xtensa_dc232b_machine); +} + +machine_init(xtensa_dc232b_machine_init); diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c new file mode 100644 index 0000000000..3033ae214a --- /dev/null +++ b/hw/xtensa_pic.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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.h" +#include "pc.h" +#include "qemu-log.h" +#include "qemu-timer.h" + +/* Stub functions for hardware that doesn't exist. */ +void pic_info(Monitor *mon) +{ +} + +void irq_info(Monitor *mon) +{ +} + +void xtensa_advance_ccount(CPUState *env, uint32_t d) +{ + uint32_t old_ccount = env->sregs[CCOUNT]; + + env->sregs[CCOUNT] += d; + + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { + int i; + for (i = 0; i < env->config->nccompare; ++i) { + if (env->sregs[CCOMPARE + i] - old_ccount <= d) { + xtensa_timer_irq(env, i, 1); + } + } + } +} + +void check_interrupts(CPUState *env) +{ + int minlevel = xtensa_get_cintlevel(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 + * elapsed since the moment when it was advanced last time. + */ + if (env->halted) { + int64_t now = qemu_get_clock_ns(vm_clock); + + xtensa_advance_ccount(env, + muldiv64(now - env->halt_clock, + env->config->clock_freq_khz, 1000000)); + env->halt_clock = now; + } + for (level = env->config->nlevel; level > minlevel; --level) { + if (env->config->level_mask[level] & int_set_enabled) { + env->pending_irq_level = level; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + qemu_log_mask(CPU_LOG_INT, + "%s level = %d, cintlevel = %d, " + "pc = %08x, a0 = %08x, ps = %08x, " + "intset = %08x, intenable = %08x, " + "ccount = %08x\n", + __func__, level, xtensa_get_cintlevel(env), + env->pc, env->regs[0], env->sregs[PS], + env->sregs[INTSET], env->sregs[INTENABLE], + env->sregs[CCOUNT]); + return; + } + } + env->pending_irq_level = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); +} + +static void xtensa_set_irq(void *opaque, int irq, int active) +{ + CPUState *env = opaque; + + if (irq >= env->config->ninterrupt) { + qemu_log("%s: bad IRQ %d\n", __func__, irq); + } else { + uint32_t irq_bit = 1 << irq; + + if (active) { + env->sregs[INTSET] |= irq_bit; + } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { + env->sregs[INTSET] &= ~irq_bit; + } + + check_interrupts(env); + } +} + +void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active) +{ + qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); +} + +static void xtensa_ccompare_cb(void *opaque) +{ + CPUState *env = opaque; + xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); +} + +void xtensa_irq_init(CPUState *env) +{ + env->irq_inputs = (void **)qemu_allocate_irqs( + xtensa_set_irq, env, env->config->ninterrupt); + 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, env); + } +} diff --git a/hw/xtensa_sample.c b/hw/xtensa_sample.c new file mode 100644 index 0000000000..31a6f70825 --- /dev/null +++ b/hw/xtensa_sample.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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 "sysemu.h" +#include "boards.h" +#include "loader.h" +#include "elf.h" +#include "memory.h" +#include "exec-memory.h" + +static void xtensa_sample_reset(void *env) +{ + cpu_reset(env); +} + +static void xtensa_init(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) +{ + CPUState *env = NULL; + MemoryRegion *ram; + const size_t dram_size = 0x10000; + const size_t iram_size = 0x20000; + int n; + + for (n = 0; n < smp_cpus; n++) { + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + qemu_register_reset(xtensa_sample_reset, env); + env->sregs[PRID] = n; + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, NULL, "xtensa.ram", + dram_size + iram_size + ram_size); + memory_region_add_subregion(get_system_memory(), + 0x60000000 - dram_size - iram_size, ram); + + if (kernel_filename) { + uint64_t elf_entry; + uint64_t elf_lowaddr; +#ifdef TARGET_WORDS_BIGENDIAN + int success = load_elf(kernel_filename, NULL, NULL, &elf_entry, + &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); +#else + int success = load_elf(kernel_filename, NULL, NULL, &elf_entry, + &elf_lowaddr, NULL, 0, ELF_MACHINE, 0); +#endif + if (success > 0) { + env->pc = elf_entry; + } + } +} + +static void xtensa_sample_init(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) +{ + if (!cpu_model) { + cpu_model = "sample-xtensa-core"; + } + xtensa_init(ram_size, boot_device, kernel_filename, kernel_cmdline, + initrd_filename, cpu_model); +} + +static QEMUMachine xtensa_sample_machine = { + .name = "sample-xtensa-machine", + .desc = "Sample Xtensa machine (sample Xtensa core)", + .init = xtensa_sample_init, + .max_cpus = 4, +}; + +static void xtensa_sample_machine_init(void) +{ + qemu_register_machine(&xtensa_sample_machine); +} + +machine_init(xtensa_sample_machine_init); @@ -1014,7 +1014,7 @@ int kvm_cpu_exec(CPUState *env) if (ret < 0) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - vm_stop(VMSTOP_PANIC); + vm_stop(RSTATE_PANICKED); } env->exit_request = 0; diff --git a/libcacard/Makefile b/libcacard/Makefile index 81d9eb5206..a145569044 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -27,6 +27,8 @@ clean: rm -Rf .libs all: vscclient +# Dummy command so that make thinks it has done something + @true ######################################################################### # Rules for building libcacard standalone library diff --git a/linux-aio.c b/linux-aio.c index 5265a029b2..bffa6cd0e3 100644 --- a/linux-aio.c +++ b/linux-aio.c @@ -68,15 +68,6 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s, qemu_aio_release(laiocb); } -/* - * All requests are directly processed when they complete, so there's nothing - * left to do during qemu_aio_wait(). - */ -static int qemu_laio_process_requests(void *opaque) -{ - return 0; -} - static void qemu_laio_completion_cb(void *opaque) { struct qemu_laio_state *s = opaque; @@ -215,7 +206,7 @@ void *laio_init(void) goto out_close_efd; qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL, - qemu_laio_flush_cb, qemu_laio_process_requests, s); + qemu_laio_flush_cb, NULL, s); return s; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 39a34db4b1..7735008d6a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -60,7 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <netinet/ip.h> #include <netinet/tcp.h> #include <linux/wireless.h> -#include <qemu-common.h> +#include "qemu-common.h" #ifdef TARGET_GPROF #include <sys/gmon.h> #endif @@ -99,7 +99,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include "cpu-uname.h" #include "qemu.h" -#include "qemu-common.h" #if defined(CONFIG_USE_NPTL) #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ @@ -1517,7 +1516,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, break; default: unimplemented: - gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname); + gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname); ret = -TARGET_ENOPROTOOPT; } return ret; @@ -55,8 +55,8 @@ static AddrRange addrrange_shift(AddrRange range, int64_t delta) static bool addrrange_intersects(AddrRange r1, AddrRange r2) { - return (r1.start >= r2.start && r1.start < r2.start + r2.size) - || (r2.start >= r1.start && r2.start < r1.start + r1.size); + return (r1.start >= r2.start && (r1.start - r2.start) < r2.size) + || (r2.start >= r1.start && (r2.start - r1.start) < r1.size); } static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2) @@ -1190,16 +1190,19 @@ static void memory_region_add_subregion_common(MemoryRegion *mr, if (subregion->may_overlap || other->may_overlap) { continue; } - if (offset >= other->offset + other->size - || offset + subregion->size <= other->offset) { + if (offset >= other->addr + other->size + || offset + subregion->size <= other->addr) { continue; } #if 0 - printf("warning: subregion collision %llx/%llx vs %llx/%llx\n", + printf("warning: subregion collision %llx/%llx (%s) " + "vs %llx/%llx (%s)\n", (unsigned long long)offset, (unsigned long long)subregion->size, - (unsigned long long)other->offset, - (unsigned long long)other->size); + subregion->name, + (unsigned long long)other->addr, + (unsigned long long)other->size, + other->name); #endif } QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { diff --git a/migration.c b/migration.c index f5959b4391..7dd8f4eee9 100644 --- a/migration.c +++ b/migration.c @@ -70,10 +70,11 @@ void process_incoming_migration(QEMUFile *f) qemu_announce_self(); DPRINTF("successfully loaded vm state\n"); - incoming_expected = false; - - if (autostart) + if (autostart) { vm_start(); + } else { + runstate_set(RSTATE_PRE_LAUNCH); + } } int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) @@ -371,10 +372,10 @@ void migrate_fd_put_ready(void *opaque) DPRINTF("iterate\n"); if (qemu_savevm_state_iterate(s->mon, s->file) == 1) { int state; - int old_vm_running = vm_running; + int old_vm_running = runstate_is_running(); DPRINTF("done iterating\n"); - vm_stop(VMSTOP_MIGRATE); + vm_stop(RSTATE_PRE_MIGRATE); if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { if (old_vm_running) { @@ -390,6 +391,9 @@ void migrate_fd_put_ready(void *opaque) } state = MIG_STATE_ERROR; } + if (state == MIG_STATE_COMPLETED) { + runstate_set(RSTATE_POST_MIGRATE); + } s->state = state; notifier_list_notify(&migration_state_notifiers, NULL); } diff --git a/mips-dis.c b/mips-dis.c index 4d8e85bd94..e3a6e0b49e 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -4841,7 +4841,7 @@ with the -M switch (multiple options should be separated by commas):\n")); Default: based on binary being disassembled.\n")); fprintf (stream, _("\n\ - hwr-names=ARCH Print HWR names according to specified \n\ + hwr-names=ARCH Print HWR names according to specified\n\ architecture.\n\ Default: based on binary being disassembled.\n")); @@ -886,7 +886,7 @@ static void print_cpu_iter(QObject *obj, void *opaque) monitor_printf(mon, "nip=0x" TARGET_FMT_lx, (target_long) qdict_get_int(cpu, "nip")); #elif defined(TARGET_SPARC) - monitor_printf(mon, "pc=0x " TARGET_FMT_lx, + monitor_printf(mon, "pc=0x" TARGET_FMT_lx, (target_long) qdict_get_int(cpu, "pc")); monitor_printf(mon, "npc=0x" TARGET_FMT_lx, (target_long) qdict_get_int(cpu, "npc")); @@ -1293,7 +1293,7 @@ static void do_singlestep(Monitor *mon, const QDict *qdict) */ static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data) { - vm_stop(VMSTOP_USER); + vm_stop(RSTATE_PAUSED); return 0; } @@ -1311,10 +1311,15 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data) { struct bdrv_iterate_context context = { mon, 0 }; - if (incoming_expected) { + if (runstate_check(RSTATE_IN_MIGRATE)) { qerror_report(QERR_MIGRATION_EXPECTED); return -1; + } else if (runstate_check(RSTATE_PANICKED) || + runstate_check(RSTATE_SHUTDOWN)) { + qerror_report(QERR_RESET_REQUIRED); + return -1; } + bdrv_iterate(encrypted_bdrv_it, &context); /* only resume the vm if all keys are set and valid */ if (!context.err) { @@ -2613,6 +2618,7 @@ static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data) static void do_info_status_print(Monitor *mon, const QObject *data) { QDict *qdict; + const char *status; qdict = qobject_to_qdict(data); @@ -2626,13 +2632,17 @@ static void do_info_status_print(Monitor *mon, const QObject *data) monitor_printf(mon, "paused"); } + status = qdict_get_str(qdict, "status"); + if (strcmp(status, "paused") && strcmp(status, "running")) { + monitor_printf(mon, " (%s)", status); + } + monitor_printf(mon, "\n"); } static void do_info_status(Monitor *mon, QObject **ret_data) { - *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }", - vm_running, singlestep); + *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i, 'status': %s }", runstate_is_running(), singlestep, runstate_as_string()); } static qemu_acl *find_acl(Monitor *mon, const char *name) @@ -2825,10 +2835,10 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) static void do_loadvm(Monitor *mon, const QDict *qdict) { - int saved_vm_running = vm_running; + int saved_vm_running = runstate_is_running(); const char *name = qdict_get_str(qdict, "name"); - vm_stop(VMSTOP_LOADVM); + vm_stop(RSTATE_RESTORE); if (load_vmstate(name) == 0 && saved_vm_running) { vm_start(); @@ -17,6 +17,7 @@ */ #include "nbd.h" +#include "block.h" #include <errno.h> #include <string.h> @@ -29,6 +30,10 @@ #include <ctype.h> #include <inttypes.h> +#ifdef __linux__ +#include <linux/fs.h> +#endif + #include "qemu_socket.h" //#define DEBUG_NBD @@ -62,6 +67,8 @@ #define NBD_PRINT_DEBUG _IO(0xab, 6) #define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) #define NBD_DISCONNECT _IO(0xab, 8) +#define NBD_SET_TIMEOUT _IO(0xab, 9) +#define NBD_SET_FLAGS _IO(0xab, 10) #define NBD_OPT_EXPORT_NAME (1 << 0) @@ -171,7 +178,7 @@ int unix_socket_outgoing(const char *path) Request (type == 2) */ -int nbd_negotiate(int csock, off_t size) +int nbd_negotiate(int csock, off_t size, uint32_t flags) { char buf[8 + 8 + 8 + 128]; @@ -179,14 +186,16 @@ int nbd_negotiate(int csock, off_t size) [ 0 .. 7] passwd ("NBDMAGIC") [ 8 .. 15] magic (0x00420281861253) [16 .. 23] size - [24 .. 151] reserved (0) + [24 .. 27] flags + [28 .. 151] reserved (0) */ TRACE("Beginning negotiation."); memcpy(buf, "NBDMAGIC", 8); cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL); cpu_to_be64w((uint64_t*)(buf + 16), size); - memset(buf + 24, 0, 128); + cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS); + memset(buf + 28, 0, 124); if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { LOG("write failed"); @@ -336,8 +345,8 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, return 0; } -#ifndef _WIN32 -int nbd_init(int fd, int csock, off_t size, size_t blocksize) +#ifdef __linux__ +int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize) { TRACE("Setting block size to %lu", (unsigned long)blocksize); @@ -357,6 +366,26 @@ int nbd_init(int fd, int csock, off_t size, size_t blocksize) return -1; } + if (flags & NBD_FLAG_READ_ONLY) { + int read_only = 1; + TRACE("Setting readonly attribute"); + + if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { + int serrno = errno; + LOG("Failed setting read-only attribute"); + errno = serrno; + return -1; + } + } + + if (ioctl(fd, NBD_SET_FLAGS, flags) < 0 + && errno != ENOTTY) { + int serrno = errno; + LOG("Failed setting flags"); + errno = serrno; + return -1; + } + TRACE("Clearing NBD socket"); if (ioctl(fd, NBD_CLEAR_SOCK) == -1) { @@ -410,7 +439,7 @@ int nbd_client(int fd) return ret; } #else -int nbd_init(int fd, int csock, off_t size, size_t blocksize) +int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize) { errno = ENOTSUP; return -1; @@ -547,7 +576,7 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply) } int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, - off_t *offset, bool readonly, uint8_t *data, int data_size) + off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size) { struct nbd_request request; struct nbd_reply reply; @@ -631,7 +660,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, return -1; } - if (readonly) { + if (nbdflags & NBD_FLAG_READ_ONLY) { TRACE("Server is read-only, return error"); reply.error = 1; } else { @@ -21,9 +21,7 @@ #include <sys/types.h> -#include <qemu-common.h> - -#include "block_int.h" +#include "qemu-common.h" struct nbd_request { uint32_t magic; @@ -39,10 +37,22 @@ struct nbd_reply { uint64_t handle; } QEMU_PACKED; +#define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ +#define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */ +#define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */ +#define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */ +#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ +#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ + +#define NBD_CMD_MASK_COMMAND 0x0000ffff +#define NBD_CMD_FLAG_FUA (1 << 16) + enum { NBD_CMD_READ = 0, NBD_CMD_WRITE = 1, - NBD_CMD_DISC = 2 + NBD_CMD_DISC = 2, + NBD_CMD_FLUSH = 3, + NBD_CMD_TRIM = 4 }; #define NBD_DEFAULT_PORT 10809 @@ -55,14 +65,14 @@ int tcp_socket_incoming_spec(const char *address_and_port); int unix_socket_outgoing(const char *path); int unix_socket_incoming(const char *path); -int nbd_negotiate(int csock, off_t size); +int nbd_negotiate(int csock, off_t size, uint32_t flags); int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, off_t *size, size_t *blocksize); -int nbd_init(int fd, int csock, off_t size, size_t blocksize); +int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize); int nbd_send_request(int csock, struct nbd_request *request); int nbd_receive_reply(int csock, struct nbd_reply *reply); int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, - off_t *offset, bool readonly, uint8_t *data, int data_size); + off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size); int nbd_client(int fd); int nbd_disconnect(int fd); @@ -81,13 +81,6 @@ #define qemu_printf printf -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -# define QEMU_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -# define QEMU_GNUC_PREREQ(maj, min) 0 -#endif - int qemu_daemon(int nochdir, int noclose); void *qemu_memalign(size_t alignment, size_t size); void *qemu_vmalloc(size_t size); diff --git a/oslib-posix.c b/oslib-posix.c index 196099cc77..a304fb0f53 100644 --- a/oslib-posix.c +++ b/oslib-posix.c @@ -35,6 +35,13 @@ extern int daemon(int, int); #endif +#if defined(__linux__) && defined(__x86_64__) + /* Use 2MB alignment so transparent hugepages can be used by KVM */ +# define QEMU_VMALLOC_ALIGN (512 * 4096) +#else +# define QEMU_VMALLOC_ALIGN getpagesize() +#endif + #include "config-host.h" #include "sysemu.h" #include "trace.h" @@ -80,7 +87,12 @@ void *qemu_memalign(size_t alignment, size_t size) void *qemu_vmalloc(size_t size) { void *ptr; - ptr = qemu_memalign(getpagesize(), size); + size_t align = QEMU_VMALLOC_ALIGN; + + if (size < align) { + align = getpagesize(); + } + ptr = qemu_memalign(align, size); trace_qemu_vmalloc(size, ptr); return ptr; } diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 3193dbf83c..d3c1174ebf 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -42,7 +42,6 @@ struct qemu_paiocb { int aio_niov; size_t aio_nbytes; #define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */ - int ev_signo; off_t aio_offset; QTAILQ_ENTRY(qemu_paiocb) node; @@ -181,7 +180,6 @@ qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset) static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb) { - size_t offset = 0; ssize_t len; do { @@ -189,12 +187,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb) len = qemu_pwritev(aiocb->aio_fildes, aiocb->aio_iov, aiocb->aio_niov, - aiocb->aio_offset + offset); + aiocb->aio_offset); else len = qemu_preadv(aiocb->aio_fildes, aiocb->aio_iov, aiocb->aio_niov, - aiocb->aio_offset + offset); + aiocb->aio_offset); } while (len == -1 && errno == EINTR); if (len == -1) @@ -309,12 +307,10 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb) return nbytes; } +static void posix_aio_notify_event(void); + static void *aio_thread(void *unused) { - pid_t pid; - - pid = getpid(); - mutex_lock(&lock); pending_threads--; mutex_unlock(&lock); @@ -381,7 +377,7 @@ static void *aio_thread(void *unused) aiocb->ret = ret; mutex_unlock(&lock); - if (kill(pid, aiocb->ev_signo)) die("kill failed"); + posix_aio_notify_event(); } cur_threads--; @@ -548,18 +544,14 @@ static int posix_aio_flush(void *opaque) static PosixAioState *posix_aio_state; -static void aio_signal_handler(int signum) +static void posix_aio_notify_event(void) { - if (posix_aio_state) { - char byte = 0; - ssize_t ret; - - ret = write(posix_aio_state->wfd, &byte, sizeof(byte)); - if (ret < 0 && errno != EAGAIN) - die("write()"); - } + char byte = 0; + ssize_t ret; - qemu_service_io(); + ret = write(posix_aio_state->wfd, &byte, sizeof(byte)); + if (ret < 0 && errno != EAGAIN) + die("write()"); } static void paio_remove(struct qemu_paiocb *acb) @@ -623,7 +615,6 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd, return NULL; acb->aio_type = type; acb->aio_fildes = fd; - acb->ev_signo = SIGUSR2; if (qiov) { acb->aio_iov = qiov->iov; @@ -651,7 +642,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd, return NULL; acb->aio_type = QEMU_AIO_IOCTL; acb->aio_fildes = fd; - acb->ev_signo = SIGUSR2; acb->aio_offset = 0; acb->aio_ioctl_buf = buf; acb->aio_ioctl_cmd = req; @@ -665,7 +655,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd, int paio_init(void) { - struct sigaction act; PosixAioState *s; int fds[2]; int ret; @@ -675,11 +664,6 @@ int paio_init(void) s = g_malloc(sizeof(PosixAioState)); - sigfillset(&act.sa_mask); - act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ - act.sa_handler = aio_signal_handler; - sigaction(SIGUSR2, &act, NULL); - s->first_aio = NULL; if (qemu_pipe(fds) == -1) { fprintf(stderr, "failed to create pipe\n"); diff --git a/qemu-barrier.h b/qemu-barrier.h index b77fce23a9..735eea6cf9 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -1,10 +1,38 @@ #ifndef __QEMU_BARRIER_H #define __QEMU_BARRIER_H 1 -/* FIXME: arch dependant, x86 version */ -#define smp_wmb() asm volatile("" ::: "memory") - /* Compiler barrier */ #define barrier() asm volatile("" ::: "memory") +#if defined(__i386__) || defined(__x86_64__) + +/* + * Because of the strongly ordered x86 storage model, wmb() is a nop + * on x86(well, a compiler barrier only). Well, at least as long as + * qemu doesn't do accesses to write-combining memory or non-temporal + * load/stores from C code. + */ +#define smp_wmb() barrier() + +#elif defined(__powerpc__) + +/* + * We use an eieio() for a wmb() on powerpc. This assumes we don't + * need to order cacheable and non-cacheable stores with respect to + * each other + */ +#define smp_wmb() asm volatile("eieio" ::: "memory") + +#else + +/* + * For (host) platforms we don't have explicit barrier definitions + * for, we use the gcc __sync_synchronize() primitive to generate a + * full barrier. This should be safe on all platforms, though it may + * be overkill. + */ +#define smp_wmb() __sync_synchronize() + +#endif + #endif diff --git a/qemu-char.c b/qemu-char.c index c9e5c41dc1..09d2309eb6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1881,7 +1881,7 @@ static void udp_chr_close(CharDriverState *chr) { NetCharDriver *s = chr->opaque; if (s->fd >= 0) { - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); } g_free(s); @@ -2093,9 +2093,9 @@ static void tcp_chr_read(void *opaque) /* connection closed */ s->connected = 0; if (s->listen_fd >= 0) { - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); } - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); s->fd = -1; qemu_chr_event(chr, CHR_EVENT_CLOSED); @@ -2156,7 +2156,7 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd) if (s->do_nodelay) socket_set_nodelay(fd); s->fd = fd; - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL); tcp_chr_connect(chr); return 0; @@ -2202,11 +2202,11 @@ static void tcp_chr_close(CharDriverState *chr) { TCPCharDriver *s = chr->opaque; if (s->fd >= 0) { - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); } if (s->listen_fd >= 0) { - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL); closesocket(s->listen_fd); } g_free(s); @@ -2272,7 +2272,7 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) if (is_listen) { s->listen_fd = fd; - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); if (is_telnet) s->do_telnetopt = 1; diff --git a/qemu-common.h b/qemu-common.h index 404c421a5d..5e87bdf2f2 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -276,9 +276,6 @@ void cpu_exec_init_all(void); void cpu_save(QEMUFile *f, void *opaque); int cpu_load(QEMUFile *f, void *opaque, int version_id); -/* Force QEMU to stop what it's doing and service IO */ -void qemu_service_io(void); - /* Force QEMU to process pending events */ void qemu_notify_event(void); @@ -880,7 +880,7 @@ static void multiwrite_help(void) " in a batch of requests that may be merged by qemu\n" "\n" " Example:\n" -" 'multiwrite 512 1k 1k ; 4k 1k' \n" +" 'multiwrite 512 1k 1k ; 4k 1k'\n" " writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n" "\n" " Writes into a segment of the currently open file, using a buffer\n" @@ -992,7 +992,6 @@ static int multiwrite_f(int argc, char **argv) optind = j + 1; - offset += reqs[i].qiov->size; pattern++; } diff --git a/qemu-nbd.c b/qemu-nbd.c index 0b25a4dd48..d8d3e15a84 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -16,7 +16,7 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <qemu-common.h> +#include "qemu-common.h" #include "block_int.h" #include "nbd.h" @@ -185,7 +185,7 @@ int main(int argc, char **argv) BlockDriverState *bs; off_t dev_offset = 0; off_t offset = 0; - bool readonly = false; + uint32_t nbdflags = 0; bool disconnect = false; const char *bindto = "0.0.0.0"; int port = NBD_DEFAULT_PORT; @@ -230,7 +230,6 @@ int main(int argc, char **argv) int nb_fds = 0; int max_fd; int persistent = 0; - uint32_t nbdflags; while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { switch (ch) { @@ -263,7 +262,7 @@ int main(int argc, char **argv) } break; case 'r': - readonly = true; + nbdflags |= NBD_FLAG_READ_ONLY; flags &= ~BDRV_O_RDWR; break; case 'P': @@ -398,13 +397,13 @@ int main(int argc, char **argv) } ret = nbd_receive_negotiate(sock, NULL, &nbdflags, - &size, &blocksize); + &size, &blocksize); if (ret == -1) { ret = 1; goto out; } - ret = nbd_init(fd, sock, size, blocksize); + ret = nbd_init(fd, sock, nbdflags, size, blocksize); if (ret == -1) { ret = 1; goto out; @@ -463,7 +462,7 @@ int main(int argc, char **argv) for (i = 1; i < nb_fds && ret; i++) { if (FD_ISSET(sharing_fds[i], &fds)) { if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset, - &offset, readonly, data, NBD_BUFFER_SIZE) != 0) { + &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) { close(sharing_fds[i]); nb_fds--; sharing_fds[i] = sharing_fds[nb_fds]; @@ -479,7 +478,7 @@ int main(int argc, char **argv) (struct sockaddr *)&addr, &addr_len); if (sharing_fds[nb_fds] != -1 && - nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) { + nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) { if (sharing_fds[nb_fds] > max_fd) max_fd = sharing_fds[nb_fds]; nb_fds++; diff --git a/qemu-options.hx b/qemu-options.hx index 659ecb2db7..dfbabd0088 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1412,7 +1412,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname} and MODE @var{octalmode} to change default ownership and permissions for -communication port. This option is available only if QEMU has been compiled +communication port. This option is only available if QEMU has been compiled with vde support enabled. Example: @@ -2396,11 +2396,11 @@ STEXI Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only). ETEXI DEF("semihosting", 0, QEMU_OPTION_semihosting, - "-semihosting semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K) + "-semihosting semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA) STEXI @item -semihosting @findex -semihosting -Semihosting mode (ARM, M68K only). +Semihosting mode (ARM, M68K, Xtensa only). ETEXI DEF("old-param", 0, QEMU_OPTION_old_param, "-old-param old param mode\n", QEMU_ARCH_ARM) @@ -2453,13 +2453,13 @@ Specify tracing options. Immediately enable events listed in @var{file}. The file must contain one event name (as listed in the @var{trace-events} file) per line. - -This option is only available when using the @var{simple} and @var{stderr} -tracing backends. +This option is only available if QEMU has been compiled with +either @var{simple} or @var{stderr} tracing backend. @item file=@var{file} Log output traces to @var{file}. -This option is only available when using the @var{simple} tracing backend. +This option is only available if QEMU has been compiled with +the @var{simple} tracing backend. @end table ETEXI diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c index 2bd02efeff..ac3c0c9d14 100644 --- a/qemu-thread-posix.c +++ b/qemu-thread-posix.c @@ -22,7 +22,7 @@ static void error_exit(int err, const char *msg) { fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); - exit(1); + abort(); } void qemu_mutex_init(QemuMutex *mutex) diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c index a27332e669..db8e744729 100644 --- a/qemu-thread-win32.c +++ b/qemu-thread-win32.c @@ -24,7 +24,7 @@ static void error_exit(int err, const char *msg) NULL, err, 0, (LPTSTR)&pstr, 2, NULL); fprintf(stderr, "qemu: %s: %s\n", msg, pstr); LocalFree(pstr); - exit(1); + abort(); } void qemu_mutex_init(QemuMutex *mutex) diff --git a/qemu-timer.c b/qemu-timer.c index 46dd483fdd..ad1fc8b871 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -230,7 +230,7 @@ static void icount_adjust(void) int64_t delta; static int64_t last_delta; /* If the VM is not running, then do nothing. */ - if (!vm_running) + if (!runstate_is_running()) return; cur_time = cpu_get_clock(); @@ -388,7 +388,7 @@ static void icount_warp_rt(void *opaque) return; } - if (vm_running) { + if (runstate_is_running()) { int64_t clock = qemu_get_clock_ns(rt_clock); int64_t warp_delta = clock - vm_clock_warp_start; if (use_icount == 1) { @@ -710,7 +710,7 @@ void qemu_run_all_timers(void) } /* vm time timers */ - if (vm_running) { + if (runstate_is_running()) { qemu_run_timers(vm_clock); } @@ -1116,7 +1116,8 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t) #endif /* _WIN32 */ -static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason) +static void alarm_timer_on_change_state_rearm(void *opaque, int running, + RunState state) { if (running) qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque); diff --git a/qemu-tool.c b/qemu-tool.c index eb89fe0c1b..e9f7fe1e1a 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -29,10 +29,6 @@ struct QEMUBH void *opaque; }; -void qemu_service_io(void) -{ -} - Monitor *cur_mon; int monitor_cur_is_qmp(void) @@ -194,6 +194,10 @@ static const QErrorStringTable qerror_table[] = { .desc = "QMP input object member '%(member)' is unexpected", }, { + .error_fmt = QERR_RESET_REQUIRED, + .desc = "Resetting the Virtual Machine is required", + }, + { .error_fmt = QERR_SET_PASSWD_FAILED, .desc = "Could not set password", }, @@ -163,6 +163,9 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_QMP_EXTRA_MEMBER \ "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" +#define QERR_RESET_REQUIRED \ + "{ 'class': 'ResetRequired', 'data': {} }" + #define QERR_SET_PASSWD_FAILED \ "{ 'class': 'SetPasswdFailed', 'data': {} }" diff --git a/qmp-commands.hx b/qmp-commands.hx index 27cc66ebc9..d83bce5662 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1131,6 +1131,8 @@ Each json-object contain the following: - Possible values: "unknown" - "removable": true if the device is removable, false otherwise (json-bool) - "locked": true if the device is locked, false otherwise (json-bool) +- "tray-open": only present if removable, true if the device has a tray, + and it is open (json-bool) - "inserted": only present if the device is inserted, it is a json-object containing the following: - "file": device file name (json-string) @@ -1571,11 +1573,28 @@ Return a json-object with the following information: - "running": true if the VM is running, or false if it is paused (json-bool) - "singlestep": true if the VM is in single step mode, false otherwise (json-bool) +- "status": one of the following values (json-string) + "debug" - QEMU is running on a debugger + "inmigrate" - guest is paused waiting for an incoming migration + "internal-error" - An internal error that prevents further guest + execution has occurred + "io-error" - the last IOP has failed and the device is configured + to pause on I/O errors + "paused" - guest has been paused via the 'stop' command + "postmigrate" - guest is paused following a successful 'migrate' + "prelaunch" - QEMU was started with -S and guest has not started + "finish-migrate" - guest is paused to finish the migration process + "restore-vm" - guest is paused to restore VM state + "running" - guest is actively running + "save-vm" - guest is paused to save the VM state + "shutdown" - guest is shut down (and -no-shutdown is in use) + "watchdog" - the watchdog action is configured to pause and + has been triggered Example: -> { "execute": "query-status" } -<- { "return": { "running": true, "singlestep": false } } +<- { "return": { "running": true, "singlestep": false, "status": "running" } } EQMP @@ -1602,8 +1602,8 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f) int saved_vm_running; int ret; - saved_vm_running = vm_running; - vm_stop(VMSTOP_SAVEVM); + saved_vm_running = runstate_is_running(); + vm_stop(RSTATE_SAVEVM); if (qemu_savevm_state_blocked(mon)) { ret = -EINVAL; @@ -1931,8 +1931,8 @@ void do_savevm(Monitor *mon, const QDict *qdict) return; } - saved_vm_running = vm_running; - vm_stop(VMSTOP_SAVEVM); + saved_vm_running = runstate_is_running(); + vm_stop(RSTATE_SAVEVM); memset(sn, 0, sizeof(*sn)); diff --git a/scripts/tracetool b/scripts/tracetool index 743d246289..4c9951d0aa 100755 --- a/scripts/tracetool +++ b/scripts/tracetool @@ -40,6 +40,15 @@ EOF exit 1 } +# Print a line without interpreting backslash escapes +# +# The built-in echo command may interpret backslash escapes without an option +# to disable this behavior. +puts() +{ + printf "%s\n" "$1" +} + # Get the name of a trace event get_name() { @@ -111,13 +120,10 @@ get_argc() echo $argc } -# Get the format string for a trace event +# Get the format string including double quotes for a trace event get_fmt() { - local fmt - fmt=${1#*\"} - fmt=${fmt%\"*} - echo "$fmt" + puts "${1#*)}" } linetoh_begin_nop() @@ -266,7 +272,7 @@ linetoh_stderr() static inline void trace_$name($args) { if (trace_list[$stderr_event_num].state != 0) { - fprintf(stderr, "$name $fmt\n" $argnames); + fprintf(stderr, "$name " $fmt "\n" $argnames); } } EOF @@ -366,7 +372,7 @@ DEFINE_TRACE(ust_$name); static void ust_${name}_probe($args) { - trace_mark(ust, $name, "$fmt"$argnames); + trace_mark(ust, $name, $fmt$argnames); } EOF diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 67c70e32e3..a7551235e2 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -1,7 +1,7 @@ #ifndef _LIBSLIRP_H #define _LIBSLIRP_H -#include <qemu-common.h> +#include "qemu-common.h" #ifdef CONFIG_SLIRP diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index c1214c0659..2f1a196b39 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -231,7 +231,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso) Slirp *slirp; DEBUG_CALL("tcp_input"); - DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", + DEBUG_ARGS((dfd, " m = %8lx iphlen = %2d inso = %lx\n", (long )m, iphlen, (long )inso )); /* @@ -580,7 +580,7 @@ findso: if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { u_char code=ICMP_UNREACH_NET; - DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", + DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n", errno,strerror(errno))); if(errno == ECONNREFUSED) { /* ACK the SYN, send RST to refuse the connection */ @@ -610,6 +610,7 @@ findso: so->so_ti = ti; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->t_state = TCPS_SYN_RECEIVED; + tcp_template(tp); } return; @@ -910,7 +911,7 @@ trimthenstep6: if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { - DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", + DEBUG_MISC((dfd, " dup ack m = %lx so = %lx\n", (long )m, (long )so)); /* * If we have outstanding data (other than @@ -1293,7 +1294,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti) int opt, optlen; DEBUG_CALL("tcp_dooptions"); - DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); + DEBUG_ARGS((dfd, " tp = %lx cnt=%i\n", (long)tp, cnt)); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 61079b1b2d..143a2383c8 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -902,7 +902,7 @@ int tcp_ctl(struct socket *so) return 1; } do_pty = ex_ptr->ex_pty; - DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); + DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec)); return fork_exec(so, ex_ptr->ex_exec, do_pty); } } @@ -9,42 +9,56 @@ #include "notify.h" /* vl.c */ + +typedef enum { + RSTATE_NO_STATE, + RSTATE_DEBUG, /* qemu is running under gdb */ + RSTATE_IN_MIGRATE, /* paused waiting for an incoming migration */ + RSTATE_PANICKED, /* paused due to an internal error */ + RSTATE_IO_ERROR, /* paused due to an I/O error */ + RSTATE_PAUSED, /* paused by the user (ie. the 'stop' command) */ + RSTATE_POST_MIGRATE, /* paused following a successful migration */ + RSTATE_PRE_LAUNCH, /* qemu was started with -S and haven't started */ + RSTATE_PRE_MIGRATE, /* paused preparing to finish migrate */ + RSTATE_RESTORE, /* paused restoring the VM state */ + RSTATE_RUNNING, /* qemu is running */ + RSTATE_SAVEVM, /* paused saving VM state */ + RSTATE_SHUTDOWN, /* guest shut down and -no-shutdown is in use */ + RSTATE_WATCHDOG, /* watchdog fired and qemu is configured to pause */ + RSTATE_MAX +} RunState; + extern const char *bios_name; -extern int vm_running; extern const char *qemu_name; extern uint8_t qemu_uuid[]; int qemu_uuid_parse(const char *str, uint8_t *uuid); #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +void runstate_init(void); +bool runstate_check(RunState state); +void runstate_set(RunState new_state); +int runstate_is_running(void); +const char *runstate_as_string(void); typedef struct vm_change_state_entry VMChangeStateEntry; -typedef void VMChangeStateHandler(void *opaque, int running, int reason); +typedef void VMChangeStateHandler(void *opaque, int running, RunState state); VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, void *opaque); void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); - -#define VMSTOP_USER 0 -#define VMSTOP_DEBUG 1 -#define VMSTOP_SHUTDOWN 2 -#define VMSTOP_DISKFULL 3 -#define VMSTOP_WATCHDOG 4 -#define VMSTOP_PANIC 5 -#define VMSTOP_SAVEVM 6 -#define VMSTOP_LOADVM 7 -#define VMSTOP_MIGRATE 8 +void vm_state_notify(int running, RunState state); #define VMRESET_SILENT false #define VMRESET_REPORT true void vm_start(void); -void vm_stop(int reason); +void vm_stop(RunState state); void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); void qemu_system_debug_request(void); -void qemu_system_vmstop_request(int reason); +void qemu_system_vmstop_request(RunState reason); int qemu_shutdown_requested_get(void); int qemu_reset_requested_get(void); int qemu_shutdown_requested(void); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 4a6f675f98..ae36489a9a 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -991,11 +991,6 @@ static inline int cpu_mmu_index (CPUState *env) /* translate.c */ void optimize_flags_init(void); -typedef struct CCTable { - int (*compute_all)(void); /* return all the flags */ - int (*compute_c)(void); /* return the C flag */ -} CCTable; - #if defined(CONFIG_USER_ONLY) static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) { diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 70ef74b80a..b6eef047bf 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -334,7 +334,7 @@ static int kvm_inject_mce_oldstyle(CPUState *env) return 0; } -static void cpu_update_state(void *opaque, int running, int reason) +static void cpu_update_state(void *opaque, int running, RunState state) { CPUState *env = opaque; @@ -769,7 +769,7 @@ static int kvm_put_xsave(CPUState *env) xsave = qemu_memalign(4096, sizeof(struct kvm_xsave)); memset(xsave, 0, sizeof(struct kvm_xsave)); - cwd = swd = twd = 0; + twd = 0; swd = env->fpus & ~(7 << 11); swd |= (env->fpstt & 7) << 11; cwd = env->fpuc; @@ -1130,7 +1130,7 @@ static int kvm_get_msrs(CPUState *env) if (!env->tsc_valid) { msrs[n++].index = MSR_IA32_TSC; - env->tsc_valid = !vm_running; + env->tsc_valid = !runstate_is_running(); } #ifdef TARGET_X86_64 diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 703be99cd2..aa41d25968 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -859,51 +859,51 @@ void helper_insertq_i(XMMReg *d, int index, int length) void helper_haddps(XMMReg *d, XMMReg *s) { XMMReg r; - r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1); - r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3); - r.XMM_S(2) = s->XMM_S(0) + s->XMM_S(1); - r.XMM_S(3) = s->XMM_S(2) + s->XMM_S(3); + r.XMM_S(0) = float32_add(d->XMM_S(0), d->XMM_S(1), &env->sse_status); + r.XMM_S(1) = float32_add(d->XMM_S(2), d->XMM_S(3), &env->sse_status); + r.XMM_S(2) = float32_add(s->XMM_S(0), s->XMM_S(1), &env->sse_status); + r.XMM_S(3) = float32_add(s->XMM_S(2), s->XMM_S(3), &env->sse_status); *d = r; } void helper_haddpd(XMMReg *d, XMMReg *s) { XMMReg r; - r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1); - r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1); + r.XMM_D(0) = float64_add(d->XMM_D(0), d->XMM_D(1), &env->sse_status); + r.XMM_D(1) = float64_add(s->XMM_D(0), s->XMM_D(1), &env->sse_status); *d = r; } void helper_hsubps(XMMReg *d, XMMReg *s) { XMMReg r; - r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1); - r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3); - r.XMM_S(2) = s->XMM_S(0) - s->XMM_S(1); - r.XMM_S(3) = s->XMM_S(2) - s->XMM_S(3); + r.XMM_S(0) = float32_sub(d->XMM_S(0), d->XMM_S(1), &env->sse_status); + r.XMM_S(1) = float32_sub(d->XMM_S(2), d->XMM_S(3), &env->sse_status); + r.XMM_S(2) = float32_sub(s->XMM_S(0), s->XMM_S(1), &env->sse_status); + r.XMM_S(3) = float32_sub(s->XMM_S(2), s->XMM_S(3), &env->sse_status); *d = r; } void helper_hsubpd(XMMReg *d, XMMReg *s) { XMMReg r; - r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1); - r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1); + r.XMM_D(0) = float64_sub(d->XMM_D(0), d->XMM_D(1), &env->sse_status); + r.XMM_D(1) = float64_sub(s->XMM_D(0), s->XMM_D(1), &env->sse_status); *d = r; } void helper_addsubps(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0); - d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1); - d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2); - d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3); + d->XMM_S(0) = float32_sub(d->XMM_S(0), s->XMM_S(0), &env->sse_status); + d->XMM_S(1) = float32_add(d->XMM_S(1), s->XMM_S(1), &env->sse_status); + d->XMM_S(2) = float32_sub(d->XMM_S(2), s->XMM_S(2), &env->sse_status); + d->XMM_S(3) = float32_add(d->XMM_S(3), s->XMM_S(3), &env->sse_status); } void helper_addsubpd(XMMReg *d, XMMReg *s) { - d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0); - d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1); + d->XMM_D(0) = float64_sub(d->XMM_D(0), s->XMM_D(0), &env->sse_status); + d->XMM_D(1) = float64_add(d->XMM_D(1), s->XMM_D(1), &env->sse_status); } /* XXX: unordered */ diff --git a/target-i386/translate.c b/target-i386/translate.c index b9667628a0..b894e97e15 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7641,11 +7641,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) void optimize_flags_init(void) { -#if TCG_TARGET_REG_BITS == 32 - assert(sizeof(CCTable) == (1 << 3)); -#else - assert(sizeof(CCTable) == (1 << 4)); -#endif cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc_op), "cc_op"); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 5ec83f2c66..96ea46494a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -553,7 +553,7 @@ static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual, BEPIl = *BATu & 0x0FFE0000; bl = (*BATu & 0x00001FFC) << 15; LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx - " BATl " TARGET_FMT_lx " \n\t" TARGET_FMT_lx " " + " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl); diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c index 867dc1d17d..c031fcb75a 100644 --- a/target-ppc/kvm_ppc.c +++ b/target-ppc/kvm_ppc.c @@ -88,7 +88,7 @@ void kvmppc_fdt_update(void *fdt) static void kvmppc_timer_hack(void *opaque) { - qemu_service_io(); + qemu_notify_event(); qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate); } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 8654f26a4e..19de5ba334 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -495,6 +495,13 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev); void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env); +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) +int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); +#define TARGET_CPU_MEMORY_RW_DEBUG +#endif + + /* translate.c */ void gen_intermediate_code_init(CPUSPARCState *env); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 1fe1f074ef..c80531a16c 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -358,6 +358,90 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) } } +#if !defined(CONFIG_USER_ONLY) + +/* Gdb expects all registers windows to be flushed in ram. This function handles + * reads (and only reads) in stack frames as if windows were flushed. We assume + * that the sparc ABI is followed. + */ +int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + int i; + int len1; + int cwp = env->cwp; + + if (!is_write) { + for (i = 0; i < env->nwindows; i++) { + int off; + target_ulong fp = env->regbase[cwp * 16 + 22]; + + /* Assume fp == 0 means end of frame. */ + if (fp == 0) { + break; + } + + cwp = cpu_cwp_inc(env, cwp + 1); + + /* Invalid window ? */ + if (env->wim & (1 << cwp)) { + break; + } + + /* According to the ABI, the stack is growing downward. */ + if (addr + len < fp) { + break; + } + + /* Not in this frame. */ + if (addr > fp + 64) { + continue; + } + + /* Handle access before this window. */ + if (addr < fp) { + len1 = fp - addr; + if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { + return -1; + } + addr += len1; + len -= len1; + buf += len1; + } + + /* Access byte per byte to registers. Not very efficient but speed + * is not critical. + */ + off = addr - fp; + len1 = 64 - off; + + if (len1 > len) { + len1 = len; + } + + for (; len1; len1--) { + int reg = cwp * 16 + 8 + (off >> 2); + union { + uint32_t v; + uint8_t c[4]; + } u; + u.v = cpu_to_be32(env->regbase[reg]); + *buf++ = u.c[off & 3]; + addr++; + len--; + off++; + } + + if (len == 0) { + return 0; + } + } + } + return cpu_memory_rw_debug(env, addr, buf, len, is_write); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + #else /* !TARGET_SPARC64 */ // 41 bit physical address space diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index d1a8dd9939..48e1db8227 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -3901,10 +3901,8 @@ target_ulong cpu_get_ccr(CPUState *env1) static void put_ccr(target_ulong val) { - target_ulong tmp = val; - - env->xcc = (tmp >> 4) << 20; - env->psr = (tmp & 0xf) << 20; + env->xcc = (val >> 4) << 20; + env->psr = (val & 0xf) << 20; CC_OP = CC_OP_FLAGS; } diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 4ecb0f1704..4d0aa43da2 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -1788,7 +1788,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s) * E : 5 */ switch (insn >> 29) { - case 0b000: + case 0x0: if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) { do_mult(env, s, insn); break; @@ -1798,7 +1798,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s) do_misc(env, s, insn); break; } - case 0b001: + case 0x1: if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) { do_misc(env, s, insn); break; @@ -1806,7 +1806,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s) do_datap(env, s, insn); break; - case 0b010: + case 0x2: if (UCOP_SET(8) && UCOP_SET(5)) { do_ldst_hwsb(env, s, insn); break; @@ -1814,24 +1814,24 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s) if (UCOP_SET(8) || UCOP_SET(5)) { ILLEGAL; } - case 0b011: + case 0x3: do_ldst_ir(env, s, insn); break; - case 0b100: + case 0x4: if (UCOP_SET(8)) { ILLEGAL; /* extended instructions */ } do_ldst_m(env, s, insn); break; - case 0b101: + case 0x5: do_branch(env, s, insn); break; - case 0b110: + case 0x6: /* Coprocessor. */ disas_coproc_insn(env, s, insn); break; - case 0b111: + case 0x7: if (!UCOP_SET(28)) { disas_coproc_insn(env, s, insn); break; diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h new file mode 100644 index 0000000000..339075dda1 --- /dev/null +++ b/target-xtensa/cpu.h @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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. + */ + +#ifndef CPU_XTENSA_H +#define CPU_XTENSA_H + +#define TARGET_LONG_BITS 32 +#define ELF_MACHINE EM_XTENSA + +#define CPUState struct CPUXtensaState + +#include "config.h" +#include "qemu-common.h" +#include "cpu-defs.h" + +#define TARGET_HAS_ICE 1 + +#define NB_MMU_MODES 4 + +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_PAGE_BITS 12 + +enum { + /* Additional instructions */ + XTENSA_OPTION_CODE_DENSITY, + XTENSA_OPTION_LOOP, + XTENSA_OPTION_EXTENDED_L32R, + XTENSA_OPTION_16_BIT_IMUL, + XTENSA_OPTION_32_BIT_IMUL, + XTENSA_OPTION_32_BIT_IDIV, + XTENSA_OPTION_MAC16, + XTENSA_OPTION_MISC_OP, + XTENSA_OPTION_COPROCESSOR, + XTENSA_OPTION_BOOLEAN, + XTENSA_OPTION_FP_COPROCESSOR, + XTENSA_OPTION_MP_SYNCHRO, + XTENSA_OPTION_CONDITIONAL_STORE, + + /* Interrupts and exceptions */ + XTENSA_OPTION_EXCEPTION, + XTENSA_OPTION_RELOCATABLE_VECTOR, + XTENSA_OPTION_UNALIGNED_EXCEPTION, + XTENSA_OPTION_INTERRUPT, + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT, + XTENSA_OPTION_TIMER_INTERRUPT, + + /* Local memory */ + XTENSA_OPTION_ICACHE, + XTENSA_OPTION_ICACHE_TEST, + XTENSA_OPTION_ICACHE_INDEX_LOCK, + XTENSA_OPTION_DCACHE, + XTENSA_OPTION_DCACHE_TEST, + XTENSA_OPTION_DCACHE_INDEX_LOCK, + XTENSA_OPTION_IRAM, + XTENSA_OPTION_IROM, + XTENSA_OPTION_DRAM, + XTENSA_OPTION_DROM, + XTENSA_OPTION_XLMI, + XTENSA_OPTION_HW_ALIGNMENT, + XTENSA_OPTION_MEMORY_ECC_PARITY, + + /* Memory protection and translation */ + XTENSA_OPTION_REGION_PROTECTION, + XTENSA_OPTION_REGION_TRANSLATION, + XTENSA_OPTION_MMU, + + /* Other */ + XTENSA_OPTION_WINDOWED_REGISTER, + XTENSA_OPTION_PROCESSOR_INTERFACE, + XTENSA_OPTION_MISC_SR, + XTENSA_OPTION_THREAD_POINTER, + XTENSA_OPTION_PROCESSOR_ID, + XTENSA_OPTION_DEBUG, + XTENSA_OPTION_TRACE_PORT, +}; + +enum { + THREADPTR = 231, + FCR = 232, + FSR = 233, +}; + +enum { + LBEG = 0, + LEND = 1, + LCOUNT = 2, + SAR = 3, + BR = 4, + LITBASE = 5, + SCOMPARE1 = 12, + WINDOW_BASE = 72, + WINDOW_START = 73, + PTEVADDR = 83, + RASID = 90, + ITLBCFG = 91, + DTLBCFG = 92, + EPC1 = 177, + DEPC = 192, + EPS2 = 194, + EXCSAVE1 = 209, + CPENABLE = 224, + INTSET = 226, + INTCLEAR = 227, + INTENABLE = 228, + PS = 230, + VECBASE = 231, + EXCCAUSE = 232, + CCOUNT = 234, + PRID = 235, + EXCVADDR = 238, + CCOMPARE = 240, +}; + +#define PS_INTLEVEL 0xf +#define PS_INTLEVEL_SHIFT 0 + +#define PS_EXCM 0x10 +#define PS_UM 0x20 + +#define PS_RING 0xc0 +#define PS_RING_SHIFT 6 + +#define PS_OWB 0xf00 +#define PS_OWB_SHIFT 8 + +#define PS_CALLINC 0x30000 +#define PS_CALLINC_SHIFT 16 +#define PS_CALLINC_LEN 2 + +#define PS_WOE 0x40000 + +#define MAX_NAREG 64 +#define MAX_NINTERRUPT 32 +#define MAX_NLEVEL 6 +#define MAX_NNMI 1 +#define MAX_NCCOMPARE 3 +#define MAX_TLB_WAY_SIZE 8 + +#define REGION_PAGE_MASK 0xe0000000 + +enum { + /* Static vectors */ + EXC_RESET, + EXC_MEMORY_ERROR, + + /* Dynamic vectors */ + EXC_WINDOW_OVERFLOW4, + EXC_WINDOW_UNDERFLOW4, + EXC_WINDOW_OVERFLOW8, + EXC_WINDOW_UNDERFLOW8, + EXC_WINDOW_OVERFLOW12, + EXC_WINDOW_UNDERFLOW12, + EXC_IRQ, + EXC_KERNEL, + EXC_USER, + EXC_DOUBLE, + EXC_MAX +}; + +enum { + ILLEGAL_INSTRUCTION_CAUSE = 0, + SYSCALL_CAUSE, + INSTRUCTION_FETCH_ERROR_CAUSE, + LOAD_STORE_ERROR_CAUSE, + LEVEL1_INTERRUPT_CAUSE, + ALLOCA_CAUSE, + INTEGER_DIVIDE_BY_ZERO_CAUSE, + PRIVILEGED_CAUSE = 8, + LOAD_STORE_ALIGNMENT_CAUSE, + + INSTR_PIF_DATA_ERROR_CAUSE = 12, + LOAD_STORE_PIF_DATA_ERROR_CAUSE, + INSTR_PIF_ADDR_ERROR_CAUSE, + LOAD_STORE_PIF_ADDR_ERROR_CAUSE, + + INST_TLB_MISS_CAUSE, + INST_TLB_MULTI_HIT_CAUSE, + INST_FETCH_PRIVILEGE_CAUSE, + INST_FETCH_PROHIBITED_CAUSE = 20, + LOAD_STORE_TLB_MISS_CAUSE = 24, + LOAD_STORE_TLB_MULTI_HIT_CAUSE, + LOAD_STORE_PRIVILEGE_CAUSE, + LOAD_PROHIBITED_CAUSE = 28, + STORE_PROHIBITED_CAUSE, + + COPROCESSOR0_DISABLED = 32, +}; + +typedef enum { + INTTYPE_LEVEL, + INTTYPE_EDGE, + INTTYPE_NMI, + INTTYPE_SOFTWARE, + INTTYPE_TIMER, + INTTYPE_DEBUG, + INTTYPE_WRITE_ERR, + INTTYPE_MAX +} interrupt_type; + +typedef struct xtensa_tlb_entry { + uint32_t vaddr; + uint32_t paddr; + uint8_t asid; + uint8_t attr; + bool variable; +} xtensa_tlb_entry; + +typedef struct xtensa_tlb { + unsigned nways; + const unsigned way_size[10]; + bool varway56; + unsigned nrefillentries; +} xtensa_tlb; + +typedef struct XtensaGdbReg { + int targno; + int type; + int group; +} XtensaGdbReg; + +typedef struct XtensaGdbRegmap { + int num_regs; + int num_core_regs; + /* PC + a + ar + sr + ur */ + XtensaGdbReg reg[1 + 16 + 64 + 256 + 256]; +} XtensaGdbRegmap; + +typedef struct XtensaConfig { + const char *name; + uint64_t options; + XtensaGdbRegmap gdb_regmap; + unsigned nareg; + int excm_level; + int ndepc; + uint32_t vecbase; + uint32_t exception_vector[EXC_MAX]; + unsigned ninterrupt; + unsigned nlevel; + uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1]; + uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1]; + uint32_t inttype_mask[INTTYPE_MAX]; + struct { + uint32_t level; + interrupt_type inttype; + } interrupt[MAX_NINTERRUPT]; + unsigned nccompare; + uint32_t timerint[MAX_NCCOMPARE]; + uint32_t clock_freq_khz; + + xtensa_tlb itlb; + xtensa_tlb dtlb; +} XtensaConfig; + +typedef struct CPUXtensaState { + const XtensaConfig *config; + uint32_t regs[16]; + uint32_t pc; + uint32_t sregs[256]; + uint32_t uregs[256]; + uint32_t phys_regs[MAX_NAREG]; + + xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; + xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; + unsigned autorefill_idx; + + int pending_irq_level; /* level of last raised IRQ */ + void **irq_inputs; + QEMUTimer *ccompare_timer; + uint32_t wake_ccount; + int64_t halt_clock; + + int exception_taken; + + CPU_COMMON +} CPUXtensaState; + +#define cpu_init cpu_xtensa_init +#define cpu_exec cpu_xtensa_exec +#define cpu_gen_code cpu_xtensa_gen_code +#define cpu_signal_handler cpu_xtensa_signal_handler +#define cpu_list xtensa_cpu_list + +CPUXtensaState *cpu_xtensa_init(const char *cpu_model); +void xtensa_translate_init(void); +int cpu_xtensa_exec(CPUXtensaState *s); +void do_interrupt(CPUXtensaState *s); +void check_interrupts(CPUXtensaState *s); +void xtensa_irq_init(CPUState *env); +void xtensa_advance_ccount(CPUState *env, uint32_t d); +void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active); +int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc); +void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void xtensa_sync_window_from_phys(CPUState *env); +void xtensa_sync_phys_from_window(CPUState *env); +uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way); +void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb, + uint32_t *vpn, uint32_t wi, uint32_t *ei); +int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb, + uint32_t *pwi, uint32_t *pei, uint8_t *pring); +void xtensa_tlb_set_entry(CPUState *env, bool dtlb, + unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); +int xtensa_get_physical_addr(CPUState *env, + uint32_t vaddr, int is_write, int mmu_idx, + uint32_t *paddr, uint32_t *page_size, unsigned *access); + + +#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) + +static inline bool xtensa_option_bits_enabled(const XtensaConfig *config, + uint64_t opt) +{ + return (config->options & opt) != 0; +} + +static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt) +{ + return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt)); +} + +static inline int xtensa_get_cintlevel(const CPUState *env) +{ + int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT; + if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) { + level = env->config->excm_level; + } + return level; +} + +static inline int xtensa_get_ring(const CPUState *env) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT; + } else { + return 0; + } +} + +static inline int xtensa_get_cring(const CPUState *env) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) && + (env->sregs[PS] & PS_EXCM) == 0) { + return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT; + } else { + return 0; + } +} + +static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUState *env, + bool dtlb, unsigned wi, unsigned ei) +{ + return dtlb ? + env->dtlb[wi] + ei : + env->itlb[wi] + ei; +} + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _ring0 +#define MMU_MODE1_SUFFIX _ring1 +#define MMU_MODE2_SUFFIX _ring2 +#define MMU_MODE3_SUFFIX _ring3 + +static inline int cpu_mmu_index(CPUState *env) +{ + return xtensa_get_cring(env); +} + +#define XTENSA_TBFLAG_RING_MASK 0x3 +#define XTENSA_TBFLAG_EXCM 0x4 +#define XTENSA_TBFLAG_LITBASE 0x8 + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = 0; + *flags |= xtensa_get_ring(env); + if (env->sregs[PS] & PS_EXCM) { + *flags |= XTENSA_TBFLAG_EXCM; + } + if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) && + (env->sregs[LITBASE] & 1)) { + *flags |= XTENSA_TBFLAG_LITBASE; + } +} + +#include "cpu-all.h" +#include "exec-all.h" + +static inline int cpu_has_work(CPUState *env) +{ + return env->pending_irq_level; +} + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; +} + +#endif diff --git a/target-xtensa/gdb-config-dc232b.c b/target-xtensa/gdb-config-dc232b.c new file mode 100644 index 0000000000..13aba5edec --- /dev/null +++ b/target-xtensa/gdb-config-dc232b.c @@ -0,0 +1,261 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + + Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + + This file is part of GDB. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + + XTREG(0, 0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc, + 0, 0, 0, 0, 0, 0) + XTREG(1, 4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0, + 0, 0, 0, 0, 0, 0) + XTREG(2, 8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1, + 0, 0, 0, 0, 0, 0) + XTREG(3, 12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2, + 0, 0, 0, 0, 0, 0) + XTREG(4, 16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3, + 0, 0, 0, 0, 0, 0) + XTREG(5, 20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4, + 0, 0, 0, 0, 0, 0) + XTREG(6, 24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5, + 0, 0, 0, 0, 0, 0) + XTREG(7, 28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6, + 0, 0, 0, 0, 0, 0) + XTREG(8, 32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7, + 0, 0, 0, 0, 0, 0) + XTREG(9, 36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8, + 0, 0, 0, 0, 0, 0) + XTREG(10, 40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9, + 0, 0, 0, 0, 0, 0) + XTREG(11, 44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10, + 0, 0, 0, 0, 0, 0) + XTREG(12, 48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11, + 0, 0, 0, 0, 0, 0) + XTREG(13, 52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12, + 0, 0, 0, 0, 0, 0) + XTREG(14, 56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13, + 0, 0, 0, 0, 0, 0) + XTREG(15, 60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14, + 0, 0, 0, 0, 0, 0) + XTREG(16, 64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15, + 0, 0, 0, 0, 0, 0) + XTREG(17, 68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16, + 0, 0, 0, 0, 0, 0) + XTREG(18, 72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17, + 0, 0, 0, 0, 0, 0) + XTREG(19, 76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18, + 0, 0, 0, 0, 0, 0) + XTREG(20, 80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19, + 0, 0, 0, 0, 0, 0) + XTREG(21, 84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20, + 0, 0, 0, 0, 0, 0) + XTREG(22, 88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21, + 0, 0, 0, 0, 0, 0) + XTREG(23, 92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22, + 0, 0, 0, 0, 0, 0) + XTREG(24, 96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23, + 0, 0, 0, 0, 0, 0) + XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24, + 0, 0, 0, 0, 0, 0) + XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25, + 0, 0, 0, 0, 0, 0) + XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26, + 0, 0, 0, 0, 0, 0) + XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27, + 0, 0, 0, 0, 0, 0) + XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28, + 0, 0, 0, 0, 0, 0) + XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29, + 0, 0, 0, 0, 0, 0) + XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30, + 0, 0, 0, 0, 0, 0) + XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31, + 0, 0, 0, 0, 0, 0) + XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg, + 0, 0, 0, 0, 0, 0) + XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend, + 0, 0, 0, 0, 0, 0) + XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount, + 0, 0, 0, 0, 0, 0) + XTREG(36, 144, 6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar, + 0, 0, 0, 0, 0, 0) + XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase, + 0, 0, 0, 0, 0, 0) + XTREG(38, 152, 3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase, + 0, 0, 0, 0, 0, 0) + XTREG(39, 156, 8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart, + 0, 0, 0, 0, 0, 0) + XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176, + 0, 0, 0, 0, 0, 0) + XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208, + 0, 0, 0, 0, 0, 0) + XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps, + 0, 0, 0, 0, 0, 0) + XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr, + 0, 0, 0, 0, 0, 0) + XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1, + 0, 0, 0, 0, 0, 0) + XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo, + 0, 0, 0, 0, 0, 0) + XTREG(46, 184, 8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi, + 0, 0, 0, 0, 0, 0) + XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0, + 0, 0, 0, 0, 0, 0) + XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1, + 0, 0, 0, 0, 0, 0) + XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2, + 0, 0, 0, 0, 0, 0) + XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3, + 0, 0, 0, 0, 0, 0) + XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate, + 0, 0, 0, 0, 0, 0) + XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr, + 0, 0, 0, 0, 0, 0) + XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid, + 0, 0, 0, 0, 0, 0) + XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid, + 0, 0, 0, 0, 0, 0) + XTREG(55, 220, 18, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg, + 0, 0, 0, 0, 0, 0) + XTREG(56, 224, 18, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg, + 0, 0, 0, 0, 0, 0) + XTREG(57, 228, 2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable, + 0, 0, 0, 0, 0, 0) + XTREG(58, 232, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr, + 0, 0, 0, 0, 0, 0) + XTREG(59, 236, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0, + 0, 0, 0, 0, 0, 0) + XTREG(60, 240, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1, + 0, 0, 0, 0, 0, 0) + XTREG(61, 244, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0, + 0, 0, 0, 0, 0, 0) + XTREG(62, 248, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1, + 0, 0, 0, 0, 0, 0) + XTREG(63, 252, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0, + 0, 0, 0, 0, 0, 0) + XTREG(64, 256, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1, + 0, 0, 0, 0, 0, 0) + XTREG(65, 260, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1, + 0, 0, 0, 0, 0, 0) + XTREG(66, 264, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2, + 0, 0, 0, 0, 0, 0) + XTREG(67, 268, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3, + 0, 0, 0, 0, 0, 0) + XTREG(68, 272, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4, + 0, 0, 0, 0, 0, 0) + XTREG(69, 276, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5, + 0, 0, 0, 0, 0, 0) + XTREG(70, 280, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6, + 0, 0, 0, 0, 0, 0) + XTREG(71, 284, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7, + 0, 0, 0, 0, 0, 0) + XTREG(72, 288, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc, + 0, 0, 0, 0, 0, 0) + XTREG(73, 292, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2, + 0, 0, 0, 0, 0, 0) + XTREG(74, 296, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3, + 0, 0, 0, 0, 0, 0) + XTREG(75, 300, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4, + 0, 0, 0, 0, 0, 0) + XTREG(76, 304, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5, + 0, 0, 0, 0, 0, 0) + XTREG(77, 308, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6, + 0, 0, 0, 0, 0, 0) + XTREG(78, 312, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7, + 0, 0, 0, 0, 0, 0) + XTREG(79, 316, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1, + 0, 0, 0, 0, 0, 0) + XTREG(80, 320, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2, + 0, 0, 0, 0, 0, 0) + XTREG(81, 324, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3, + 0, 0, 0, 0, 0, 0) + XTREG(82, 328, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4, + 0, 0, 0, 0, 0, 0) + XTREG(83, 332, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5, + 0, 0, 0, 0, 0, 0) + XTREG(84, 336, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6, + 0, 0, 0, 0, 0, 0) + XTREG(85, 340, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7, + 0, 0, 0, 0, 0, 0) + XTREG(86, 344, 8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable, + 0, 0, 0, 0, 0, 0) + XTREG(87, 348, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt, + 0, 0, 0, 0, 0, 0) + XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset, + 0, 0, 0, 0, 0, 0) + XTREG(89, 356, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear, + 0, 0, 0, 0, 0, 0) + XTREG(90, 360, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable, + 0, 0, 0, 0, 0, 0) + XTREG(91, 364, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase, + 0, 0, 0, 0, 0, 0) + XTREG(92, 368, 6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause, + 0, 0, 0, 0, 0, 0) + XTREG(93, 372, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause, + 0, 0, 0, 0, 0, 0) + XTREG(94, 376, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount, + 0, 0, 0, 0, 0, 0) + XTREG(95, 380, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid, + 0, 0, 0, 0, 0, 0) + XTREG(96, 384, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount, + 0, 0, 0, 0, 0, 0) + XTREG(97, 388, 4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel, + 0, 0, 0, 0, 0, 0) + XTREG(98, 392, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr, + 0, 0, 0, 0, 0, 0) + XTREG(99, 396, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0, + 0, 0, 0, 0, 0, 0) + XTREG(100, 400, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1, + 0, 0, 0, 0, 0, 0) + XTREG(101, 404, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2, + 0, 0, 0, 0, 0, 0) + XTREG(102, 408, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0, + 0, 0, 0, 0, 0, 0) + XTREG(103, 412, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1, + 0, 0, 0, 0, 0, 0) + XTREG(104, 416, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0, + 0, 0, 0, 0, 0, 0) + XTREG(105, 420, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1, + 0, 0, 0, 0, 0, 0) + XTREG(106, 424, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2, + 0, 0, 0, 0, 0, 0) + XTREG(107, 428, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3, + 0, 0, 0, 0, 0, 0) + XTREG(108, 432, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4, + 0, 0, 0, 0, 0, 0) + XTREG(109, 436, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5, + 0, 0, 0, 0, 0, 0) + XTREG(110, 440, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6, + 0, 0, 0, 0, 0, 0) + XTREG(111, 444, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7, + 0, 0, 0, 0, 0, 0) + XTREG(112, 448, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8, + 0, 0, 0, 0, 0, 0) + XTREG(113, 452, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9, + 0, 0, 0, 0, 0, 0) + XTREG(114, 456, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10, + 0, 0, 0, 0, 0, 0) + XTREG(115, 460, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11, + 0, 0, 0, 0, 0, 0) + XTREG(116, 464, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12, + 0, 0, 0, 0, 0, 0) + XTREG(117, 468, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13, + 0, 0, 0, 0, 0, 0) + XTREG(118, 472, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14, + 0, 0, 0, 0, 0, 0) + XTREG(119, 476, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15, + 0, 0, 0, 0, 0, 0) diff --git a/target-xtensa/gdb-config-sample-xtensa-core.c b/target-xtensa/gdb-config-sample-xtensa-core.c new file mode 100644 index 0000000000..bfbd7be30a --- /dev/null +++ b/target-xtensa/gdb-config-sample-xtensa-core.c @@ -0,0 +1,375 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + + Copyright (c) 2003-2010 Tensilica 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. */ + + XTREG(0, 0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc, + 0, 0, 0, 0, 0, 0) + XTREG(1, 4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0, + 0, 0, 0, 0, 0, 0) + XTREG(2, 8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1, + 0, 0, 0, 0, 0, 0) + XTREG(3, 12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2, + 0, 0, 0, 0, 0, 0) + XTREG(4, 16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3, + 0, 0, 0, 0, 0, 0) + XTREG(5, 20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4, + 0, 0, 0, 0, 0, 0) + XTREG(6, 24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5, + 0, 0, 0, 0, 0, 0) + XTREG(7, 28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6, + 0, 0, 0, 0, 0, 0) + XTREG(8, 32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7, + 0, 0, 0, 0, 0, 0) + XTREG(9, 36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8, + 0, 0, 0, 0, 0, 0) + XTREG(10, 40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9, + 0, 0, 0, 0, 0, 0) + XTREG(11, 44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10, + 0, 0, 0, 0, 0, 0) + XTREG(12, 48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11, + 0, 0, 0, 0, 0, 0) + XTREG(13, 52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12, + 0, 0, 0, 0, 0, 0) + XTREG(14, 56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13, + 0, 0, 0, 0, 0, 0) + XTREG(15, 60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14, + 0, 0, 0, 0, 0, 0) + XTREG(16, 64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15, + 0, 0, 0, 0, 0, 0) + XTREG(17, 68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16, + 0, 0, 0, 0, 0, 0) + XTREG(18, 72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17, + 0, 0, 0, 0, 0, 0) + XTREG(19, 76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18, + 0, 0, 0, 0, 0, 0) + XTREG(20, 80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19, + 0, 0, 0, 0, 0, 0) + XTREG(21, 84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20, + 0, 0, 0, 0, 0, 0) + XTREG(22, 88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21, + 0, 0, 0, 0, 0, 0) + XTREG(23, 92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22, + 0, 0, 0, 0, 0, 0) + XTREG(24, 96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23, + 0, 0, 0, 0, 0, 0) + XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24, + 0, 0, 0, 0, 0, 0) + XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25, + 0, 0, 0, 0, 0, 0) + XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26, + 0, 0, 0, 0, 0, 0) + XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27, + 0, 0, 0, 0, 0, 0) + XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28, + 0, 0, 0, 0, 0, 0) + XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29, + 0, 0, 0, 0, 0, 0) + XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30, + 0, 0, 0, 0, 0, 0) + XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31, + 0, 0, 0, 0, 0, 0) + XTREG(33, 132, 32, 4, 4, 0x0120, 0x0006, -2, 1, 0x0002, ar32, + 0, 0, 0, 0, 0, 0) + XTREG(34, 136, 32, 4, 4, 0x0121, 0x0006, -2, 1, 0x0002, ar33, + 0, 0, 0, 0, 0, 0) + XTREG(35, 140, 32, 4, 4, 0x0122, 0x0006, -2, 1, 0x0002, ar34, + 0, 0, 0, 0, 0, 0) + XTREG(36, 144, 32, 4, 4, 0x0123, 0x0006, -2, 1, 0x0002, ar35, + 0, 0, 0, 0, 0, 0) + XTREG(37, 148, 32, 4, 4, 0x0124, 0x0006, -2, 1, 0x0002, ar36, + 0, 0, 0, 0, 0, 0) + XTREG(38, 152, 32, 4, 4, 0x0125, 0x0006, -2, 1, 0x0002, ar37, + 0, 0, 0, 0, 0, 0) + XTREG(39, 156, 32, 4, 4, 0x0126, 0x0006, -2, 1, 0x0002, ar38, + 0, 0, 0, 0, 0, 0) + XTREG(40, 160, 32, 4, 4, 0x0127, 0x0006, -2, 1, 0x0002, ar39, + 0, 0, 0, 0, 0, 0) + XTREG(41, 164, 32, 4, 4, 0x0128, 0x0006, -2, 1, 0x0002, ar40, + 0, 0, 0, 0, 0, 0) + XTREG(42, 168, 32, 4, 4, 0x0129, 0x0006, -2, 1, 0x0002, ar41, + 0, 0, 0, 0, 0, 0) + XTREG(43, 172, 32, 4, 4, 0x012a, 0x0006, -2, 1, 0x0002, ar42, + 0, 0, 0, 0, 0, 0) + XTREG(44, 176, 32, 4, 4, 0x012b, 0x0006, -2, 1, 0x0002, ar43, + 0, 0, 0, 0, 0, 0) + XTREG(45, 180, 32, 4, 4, 0x012c, 0x0006, -2, 1, 0x0002, ar44, + 0, 0, 0, 0, 0, 0) + XTREG(46, 184, 32, 4, 4, 0x012d, 0x0006, -2, 1, 0x0002, ar45, + 0, 0, 0, 0, 0, 0) + XTREG(47, 188, 32, 4, 4, 0x012e, 0x0006, -2, 1, 0x0002, ar46, + 0, 0, 0, 0, 0, 0) + XTREG(48, 192, 32, 4, 4, 0x012f, 0x0006, -2, 1, 0x0002, ar47, + 0, 0, 0, 0, 0, 0) + XTREG(49, 196, 32, 4, 4, 0x0130, 0x0006, -2, 1, 0x0002, ar48, + 0, 0, 0, 0, 0, 0) + XTREG(50, 200, 32, 4, 4, 0x0131, 0x0006, -2, 1, 0x0002, ar49, + 0, 0, 0, 0, 0, 0) + XTREG(51, 204, 32, 4, 4, 0x0132, 0x0006, -2, 1, 0x0002, ar50, + 0, 0, 0, 0, 0, 0) + XTREG(52, 208, 32, 4, 4, 0x0133, 0x0006, -2, 1, 0x0002, ar51, + 0, 0, 0, 0, 0, 0) + XTREG(53, 212, 32, 4, 4, 0x0134, 0x0006, -2, 1, 0x0002, ar52, + 0, 0, 0, 0, 0, 0) + XTREG(54, 216, 32, 4, 4, 0x0135, 0x0006, -2, 1, 0x0002, ar53, + 0, 0, 0, 0, 0, 0) + XTREG(55, 220, 32, 4, 4, 0x0136, 0x0006, -2, 1, 0x0002, ar54, + 0, 0, 0, 0, 0, 0) + XTREG(56, 224, 32, 4, 4, 0x0137, 0x0006, -2, 1, 0x0002, ar55, + 0, 0, 0, 0, 0, 0) + XTREG(57, 228, 32, 4, 4, 0x0138, 0x0006, -2, 1, 0x0002, ar56, + 0, 0, 0, 0, 0, 0) + XTREG(58, 232, 32, 4, 4, 0x0139, 0x0006, -2, 1, 0x0002, ar57, + 0, 0, 0, 0, 0, 0) + XTREG(59, 236, 32, 4, 4, 0x013a, 0x0006, -2, 1, 0x0002, ar58, + 0, 0, 0, 0, 0, 0) + XTREG(60, 240, 32, 4, 4, 0x013b, 0x0006, -2, 1, 0x0002, ar59, + 0, 0, 0, 0, 0, 0) + XTREG(61, 244, 32, 4, 4, 0x013c, 0x0006, -2, 1, 0x0002, ar60, + 0, 0, 0, 0, 0, 0) + XTREG(62, 248, 32, 4, 4, 0x013d, 0x0006, -2, 1, 0x0002, ar61, + 0, 0, 0, 0, 0, 0) + XTREG(63, 252, 32, 4, 4, 0x013e, 0x0006, -2, 1, 0x0002, ar62, + 0, 0, 0, 0, 0, 0) + XTREG(64, 256, 32, 4, 4, 0x013f, 0x0006, -2, 1, 0x0002, ar63, + 0, 0, 0, 0, 0, 0) + XTREG(65, 260, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg, + 0, 0, 0, 0, 0, 0) + XTREG(66, 264, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend, + 0, 0, 0, 0, 0, 0) + XTREG(67, 268, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount, + 0, 0, 0, 0, 0, 0) + XTREG(68, 272, 6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar, + 0, 0, 0, 0, 0, 0) + XTREG(69, 276, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase, + 0, 0, 0, 0, 0, 0) + XTREG(70, 280, 4, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase, + 0, 0, 0, 0, 0, 0) + XTREG(71, 284, 16, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart, + 0, 0, 0, 0, 0, 0) + XTREG(72, 288, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176, + 0, 0, 0, 0, 0, 0) + XTREG(73, 292, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208, + 0, 0, 0, 0, 0, 0) + XTREG(74, 296, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps, + 0, 0, 0, 0, 0, 0) + XTREG(75, 300, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr, + 0, 0, 0, 0, 0, 0) + XTREG(76, 304, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1, + 0, 0, 0, 0, 0, 0) + XTREG(77, 308, 32, 4, 4, 0x0327, 0x000e, -1, 3, 0x0210, expstate, + 0, 0, 0, 0, 0, 0) + XTREG(78, 312, 32, 4, 4, 0x0300, 0x0006, 2, 3, 0x0210, stage1, + 0, 0, 0, 0, 0, 0) + XTREG(79, 316, 32, 4, 4, 0x0301, 0x0006, 2, 3, 0x0210, stage2, + 0, 0, 0, 0, 0, 0) + XTREG(80, 320, 32, 4, 4, 0x0302, 0x0006, 2, 3, 0x0210, input_align_reg, + 0, 0, 0, 0, 0, 0) + XTREG(81, 324, 6, 4, 4, 0x0303, 0x0006, 2, 3, 0x0210, input_align_reg_pos, + 0, 0, 0, 0, 0, 0) + XTREG(82, 328, 32, 4, 4, 0x0304, 0x0006, 2, 3, 0x0210, data_reg, + 0, 0, 0, 0, 0, 0) + XTREG(83, 332, 7, 4, 4, 0x0305, 0x0006, 2, 3, 0x0210, data_reg_pos, + 0, 0, 0, 0, 0, 0) + XTREG(84, 336, 32, 4, 4, 0x0306, 0x0006, 2, 3, 0x0210, crc_reg, + 0, 0, 0, 0, 0, 0) + XTREG(85, 340, 32, 4, 4, 0x0307, 0x0006, 2, 3, 0x0210, pol_reg00, + 0, 0, 0, 0, 0, 0) + XTREG(86, 344, 32, 4, 4, 0x0308, 0x0006, 2, 3, 0x0210, pol_reg01, + 0, 0, 0, 0, 0, 0) + XTREG(87, 348, 32, 4, 4, 0x0309, 0x0006, 2, 3, 0x0210, pol_reg02, + 0, 0, 0, 0, 0, 0) + XTREG(88, 352, 32, 4, 4, 0x030a, 0x0006, 2, 3, 0x0210, pol_reg03, + 0, 0, 0, 0, 0, 0) + XTREG(89, 356, 32, 4, 4, 0x030b, 0x0006, 2, 3, 0x0210, pol_reg04, + 0, 0, 0, 0, 0, 0) + XTREG(90, 360, 32, 4, 4, 0x030c, 0x0006, 2, 3, 0x0210, pol_reg05, + 0, 0, 0, 0, 0, 0) + XTREG(91, 364, 32, 4, 4, 0x030d, 0x0006, 2, 3, 0x0210, pol_reg06, + 0, 0, 0, 0, 0, 0) + XTREG(92, 368, 32, 4, 4, 0x030e, 0x0006, 2, 3, 0x0210, pol_reg07, + 0, 0, 0, 0, 0, 0) + XTREG(93, 372, 32, 4, 4, 0x030f, 0x0006, 2, 3, 0x0210, pol_reg08, + 0, 0, 0, 0, 0, 0) + XTREG(94, 376, 32, 4, 4, 0x0310, 0x0006, 2, 3, 0x0210, pol_reg09, + 0, 0, 0, 0, 0, 0) + XTREG(95, 380, 32, 4, 4, 0x0311, 0x0006, 2, 3, 0x0210, pol_reg10, + 0, 0, 0, 0, 0, 0) + XTREG(96, 384, 32, 4, 4, 0x0312, 0x0006, 2, 3, 0x0210, pol_reg11, + 0, 0, 0, 0, 0, 0) + XTREG(97, 388, 32, 4, 4, 0x0313, 0x0006, 2, 3, 0x0210, pol_reg12, + 0, 0, 0, 0, 0, 0) + XTREG(98, 392, 32, 4, 4, 0x0314, 0x0006, 2, 3, 0x0210, pol_reg13, + 0, 0, 0, 0, 0, 0) + XTREG(99, 396, 32, 4, 4, 0x0315, 0x0006, 2, 3, 0x0210, pol_reg14, + 0, 0, 0, 0, 0, 0) + XTREG(100, 400, 32, 4, 4, 0x0316, 0x0006, 2, 3, 0x0210, pol_reg15, + 0, 0, 0, 0, 0, 0) + XTREG(101, 404, 32, 4, 4, 0x0317, 0x0006, 2, 3, 0x0210, pol_reg16, + 0, 0, 0, 0, 0, 0) + XTREG(102, 408, 32, 4, 4, 0x0318, 0x0006, 2, 3, 0x0210, pol_reg17, + 0, 0, 0, 0, 0, 0) + XTREG(103, 412, 32, 4, 4, 0x0319, 0x0006, 2, 3, 0x0210, pol_reg18, + 0, 0, 0, 0, 0, 0) + XTREG(104, 416, 32, 4, 4, 0x031a, 0x0006, 2, 3, 0x0210, pol_reg19, + 0, 0, 0, 0, 0, 0) + XTREG(105, 420, 32, 4, 4, 0x031b, 0x0006, 2, 3, 0x0210, pol_reg20, + 0, 0, 0, 0, 0, 0) + XTREG(106, 424, 32, 4, 4, 0x031c, 0x0006, 2, 3, 0x0210, pol_reg21, + 0, 0, 0, 0, 0, 0) + XTREG(107, 428, 32, 4, 4, 0x031d, 0x0006, 2, 3, 0x0210, pol_reg22, + 0, 0, 0, 0, 0, 0) + XTREG(108, 432, 32, 4, 4, 0x031e, 0x0006, 2, 3, 0x0210, pol_reg23, + 0, 0, 0, 0, 0, 0) + XTREG(109, 436, 32, 4, 4, 0x031f, 0x0006, 2, 3, 0x0210, pol_reg24, + 0, 0, 0, 0, 0, 0) + XTREG(110, 440, 32, 4, 4, 0x0320, 0x0006, 2, 3, 0x0210, pol_reg25, + 0, 0, 0, 0, 0, 0) + XTREG(111, 444, 32, 4, 4, 0x0321, 0x0006, 2, 3, 0x0210, pol_reg26, + 0, 0, 0, 0, 0, 0) + XTREG(112, 448, 32, 4, 4, 0x0322, 0x0006, 2, 3, 0x0210, pol_reg27, + 0, 0, 0, 0, 0, 0) + XTREG(113, 452, 32, 4, 4, 0x0323, 0x0006, 2, 3, 0x0210, pol_reg28, + 0, 0, 0, 0, 0, 0) + XTREG(114, 456, 32, 4, 4, 0x0324, 0x0006, 2, 3, 0x0210, pol_reg29, + 0, 0, 0, 0, 0, 0) + XTREG(115, 460, 32, 4, 4, 0x0325, 0x0006, 2, 3, 0x0210, pol_reg30, + 0, 0, 0, 0, 0, 0) + XTREG(116, 464, 32, 4, 4, 0x0326, 0x0006, 2, 3, 0x0210, pol_reg31, + 0, 0, 0, 0, 0, 0) + XTREG(117, 468, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid, + 0, 0, 0, 0, 0, 0) + XTREG(118, 472, 2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable, + 0, 0, 0, 0, 0, 0) + XTREG(119, 476, 6, 4, 4, 0x0263, 0x0007, -2, 2, 0x1000, atomctl, + 0, 0, 0, 0, 0, 0) + XTREG(120, 480, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr, + 0, 0, 0, 0, 0, 0) + XTREG(121, 484, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0, + 0, 0, 0, 0, 0, 0) + XTREG(122, 488, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1, + 0, 0, 0, 0, 0, 0) + XTREG(123, 492, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0, + 0, 0, 0, 0, 0, 0) + XTREG(124, 496, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1, + 0, 0, 0, 0, 0, 0) + XTREG(125, 500, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0, + 0, 0, 0, 0, 0, 0) + XTREG(126, 504, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1, + 0, 0, 0, 0, 0, 0) + XTREG(127, 508, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1, + 0, 0, 0, 0, 0, 0) + XTREG(128, 512, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2, + 0, 0, 0, 0, 0, 0) + XTREG(129, 516, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3, + 0, 0, 0, 0, 0, 0) + XTREG(130, 520, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4, + 0, 0, 0, 0, 0, 0) + XTREG(131, 524, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5, + 0, 0, 0, 0, 0, 0) + XTREG(132, 528, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6, + 0, 0, 0, 0, 0, 0) + XTREG(133, 532, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc, + 0, 0, 0, 0, 0, 0) + XTREG(134, 536, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2, + 0, 0, 0, 0, 0, 0) + XTREG(135, 540, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3, + 0, 0, 0, 0, 0, 0) + XTREG(136, 544, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4, + 0, 0, 0, 0, 0, 0) + XTREG(137, 548, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5, + 0, 0, 0, 0, 0, 0) + XTREG(138, 552, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6, + 0, 0, 0, 0, 0, 0) + XTREG(139, 556, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1, + 0, 0, 0, 0, 0, 0) + XTREG(140, 560, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2, + 0, 0, 0, 0, 0, 0) + XTREG(141, 564, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3, + 0, 0, 0, 0, 0, 0) + XTREG(142, 568, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4, + 0, 0, 0, 0, 0, 0) + XTREG(143, 572, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5, + 0, 0, 0, 0, 0, 0) + XTREG(144, 576, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6, + 0, 0, 0, 0, 0, 0) + XTREG(145, 580, 4, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable, + 0, 0, 0, 0, 0, 0) + XTREG(146, 584, 13, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt, + 0, 0, 0, 0, 0, 0) + XTREG(147, 588, 13, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset, + 0, 0, 0, 0, 0, 0) + XTREG(148, 592, 13, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear, + 0, 0, 0, 0, 0, 0) + XTREG(149, 596, 13, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable, + 0, 0, 0, 0, 0, 0) + XTREG(150, 600, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase, + 0, 0, 0, 0, 0, 0) + XTREG(151, 604, 6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause, + 0, 0, 0, 0, 0, 0) + XTREG(152, 608, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause, + 0, 0, 0, 0, 0, 0) + XTREG(153, 612, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount, + 0, 0, 0, 0, 0, 0) + XTREG(154, 616, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid, + 0, 0, 0, 0, 0, 0) + XTREG(155, 620, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount, + 0, 0, 0, 0, 0, 0) + XTREG(156, 624, 4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel, + 0, 0, 0, 0, 0, 0) + XTREG(157, 628, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr, + 0, 0, 0, 0, 0, 0) + XTREG(158, 632, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0, + 0, 0, 0, 0, 0, 0) + XTREG(159, 636, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1, + 0, 0, 0, 0, 0, 0) + XTREG(160, 640, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0, + 0, 0, 0, 0, 0, 0) + XTREG(161, 644, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1, + 0, 0, 0, 0, 0, 0) + XTREG(162, 648, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2, + 0, 0, 0, 0, 0, 0) + XTREG(163, 652, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3, + 0, 0, 0, 0, 0, 0) + XTREG(164, 656, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4, + 0, 0, 0, 0, 0, 0) + XTREG(165, 660, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5, + 0, 0, 0, 0, 0, 0) + XTREG(166, 664, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6, + 0, 0, 0, 0, 0, 0) + XTREG(167, 668, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7, + 0, 0, 0, 0, 0, 0) + XTREG(168, 672, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8, + 0, 0, 0, 0, 0, 0) + XTREG(169, 676, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9, + 0, 0, 0, 0, 0, 0) + XTREG(170, 680, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10, + 0, 0, 0, 0, 0, 0) + XTREG(171, 684, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11, + 0, 0, 0, 0, 0, 0) + XTREG(172, 688, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12, + 0, 0, 0, 0, 0, 0) + XTREG(173, 692, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13, + 0, 0, 0, 0, 0, 0) + XTREG(174, 696, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14, + 0, 0, 0, 0, 0, 0) + XTREG(175, 700, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15, + 0, 0, 0, 0, 0, 0) diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c new file mode 100644 index 0000000000..c8ba74e145 --- /dev/null +++ b/target-xtensa/helper.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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 "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "qemu-common.h" +#include "host-utils.h" +#if !defined(CONFIG_USER_ONLY) +#include "hw/loader.h" +#endif + +#define XTREG(idx, ofs, bi, sz, al, no, flags, cp, typ, grp, name, \ + a1, a2, a3, a4, a5, a6) \ + { .targno = (no), .type = (typ), .group = (grp) }, + +static void reset_mmu(CPUState *env); + +void cpu_reset(CPUXtensaState *env) +{ + env->exception_taken = 0; + env->pc = env->config->exception_vector[EXC_RESET]; + env->sregs[LITBASE] &= ~1; + env->sregs[PS] = xtensa_option_enabled(env->config, + XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; + env->sregs[VECBASE] = env->config->vecbase; + + env->pending_irq_level = 0; + reset_mmu(env); +} + +static const XtensaConfig core_config[] = { + { + .name = "sample-xtensa-core", + .options = -1 ^ + (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) | + XTENSA_OPTION_BIT(XTENSA_OPTION_MMU)), + .gdb_regmap = { + .num_regs = 176, + .num_core_regs = 117, + .reg = { +#include "gdb-config-sample-xtensa-core.c" + } + }, + .nareg = 64, + .ndepc = 1, + .excm_level = 16, + .vecbase = 0x5fff8400, + .exception_vector = { + [EXC_RESET] = 0x5fff8000, + [EXC_WINDOW_OVERFLOW4] = 0x5fff8400, + [EXC_WINDOW_UNDERFLOW4] = 0x5fff8440, + [EXC_WINDOW_OVERFLOW8] = 0x5fff8480, + [EXC_WINDOW_UNDERFLOW8] = 0x5fff84c0, + [EXC_WINDOW_OVERFLOW12] = 0x5fff8500, + [EXC_WINDOW_UNDERFLOW12] = 0x5fff8540, + [EXC_KERNEL] = 0x5fff861c, + [EXC_USER] = 0x5fff863c, + [EXC_DOUBLE] = 0x5fff865c, + }, + .ninterrupt = 13, + .nlevel = 6, + .interrupt_vector = { + 0, + 0, + 0x5fff857c, + 0x5fff859c, + 0x5fff85bc, + 0x5fff85dc, + 0x5fff85fc, + }, + .level_mask = { + [4] = 1, + }, + .interrupt = { + [0] = { + .level = 4, + .inttype = INTTYPE_TIMER, + }, + }, + .nccompare = 1, + .timerint = { + [0] = 0, + }, + .clock_freq_khz = 912000, + }, { + .name = "dc232b", + .options = -1 ^ + (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) | + XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | + XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)), + .gdb_regmap = { + .num_regs = 120, + .num_core_regs = 52, + .reg = { +#include "gdb-config-dc232b.c" + } + }, + .nareg = 32, + .ndepc = 1, + .excm_level = 3, + .vecbase = 0xd0000000, + .exception_vector = { + [EXC_RESET] = 0xfe000000, + [EXC_WINDOW_OVERFLOW4] = 0xd0000000, + [EXC_WINDOW_UNDERFLOW4] = 0xd0000040, + [EXC_WINDOW_OVERFLOW8] = 0xd0000080, + [EXC_WINDOW_UNDERFLOW8] = 0xd00000c0, + [EXC_WINDOW_OVERFLOW12] = 0xd0000100, + [EXC_WINDOW_UNDERFLOW12] = 0xd0000140, + [EXC_KERNEL] = 0xd0000300, + [EXC_USER] = 0xd0000340, + [EXC_DOUBLE] = 0xd00003c0, + }, + .ninterrupt = 22, + .nlevel = 6, + .interrupt_vector = { + 0, + 0, + 0xd0000180, + 0xd00001c0, + 0xd0000200, + 0xd0000240, + 0xd0000280, + 0xd00002c0, + }, + .level_mask = { + [1] = 0x1f80ff, + [2] = 0x000100, + [3] = 0x200e00, + [4] = 0x001000, + [5] = 0x002000, + [6] = 0x000000, + [7] = 0x004000, + }, + .inttype_mask = { + [INTTYPE_EDGE] = 0x3f8000, + [INTTYPE_NMI] = 0x4000, + [INTTYPE_SOFTWARE] = 0x880, + }, + .interrupt = { + [0] = { + .level = 1, + .inttype = INTTYPE_LEVEL, + }, + [1] = { + .level = 1, + .inttype = INTTYPE_LEVEL, + }, + [2] = { + .level = 1, + .inttype = INTTYPE_LEVEL, + }, + [3] = { + .level = 1, + .inttype = INTTYPE_LEVEL, + }, + [4] = { + .level = 1, + .inttype = INTTYPE_LEVEL, + }, + [5] = { + .level = 1, + .inttype = INTTYPE_LEVEL, + }, + [6] = { + .level = 1, + .inttype = INTTYPE_TIMER, + }, + [7] = { + .level = 1, + .inttype = INTTYPE_SOFTWARE, + }, + [8] = { + .level = 2, + .inttype = INTTYPE_LEVEL, + }, + [9] = { + .level = 3, + .inttype = INTTYPE_LEVEL, + }, + [10] = { + .level = 3, + .inttype = INTTYPE_TIMER, + }, + [11] = { + .level = 3, + .inttype = INTTYPE_SOFTWARE, + }, + [12] = { + .level = 4, + .inttype = INTTYPE_LEVEL, + }, + [13] = { + .level = 5, + .inttype = INTTYPE_TIMER, + }, + [14] = { + .level = 7, + .inttype = INTTYPE_NMI, + }, + [15] = { + .level = 1, + .inttype = INTTYPE_EDGE, + }, + [16] = { + .level = 1, + .inttype = INTTYPE_EDGE, + }, + [17] = { + .level = 1, + .inttype = INTTYPE_EDGE, + }, + [18] = { + .level = 1, + .inttype = INTTYPE_EDGE, + }, + [19] = { + .level = 1, + .inttype = INTTYPE_EDGE, + }, + [20] = { + .level = 1, + .inttype = INTTYPE_EDGE, + }, + [21] = { + .level = 3, + .inttype = INTTYPE_EDGE, + }, + }, + .nccompare = 3, + .timerint = { + [0] = 6, + [1] = 10, + [2] = 13, + }, + .clock_freq_khz = 912000, + .itlb = { + .nways = 7, + .way_size = { + 4, 4, 4, 4, 4, 2, 2, + }, + .varway56 = false, + .nrefillentries = 16, + }, + .dtlb = { + .nways = 10, + .way_size = { + 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, + }, + .varway56 = false, + .nrefillentries = 16, + }, + }, +}; + +CPUXtensaState *cpu_xtensa_init(const char *cpu_model) +{ + static int tcg_inited; + CPUXtensaState *env; + const XtensaConfig *config = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(core_config); ++i) + if (strcmp(core_config[i].name, cpu_model) == 0) { + config = core_config + i; + break; + } + + if (config == NULL) { + return NULL; + } + + env = g_malloc0(sizeof(*env)); + env->config = config; + cpu_exec_init(env); + + if (!tcg_inited) { + tcg_inited = 1; + xtensa_translate_init(); + } + + xtensa_irq_init(env); + qemu_init_vcpu(env); + return env; +} + + +void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + int i; + cpu_fprintf(f, "Available CPUs:\n"); + for (i = 0; i < ARRAY_SIZE(core_config); ++i) { + cpu_fprintf(f, " %s\n", core_config[i].name); + } +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t paddr; + uint32_t page_size; + unsigned access; + + if (xtensa_get_physical_addr(env, addr, 0, 0, + &paddr, &page_size, &access) == 0) { + return paddr; + } + if (xtensa_get_physical_addr(env, addr, 2, 0, + &paddr, &page_size, &access) == 0) { + return paddr; + } + return ~0; +} + +static uint32_t relocated_vector(CPUState *env, uint32_t vector) +{ + if (xtensa_option_enabled(env->config, + XTENSA_OPTION_RELOCATABLE_VECTOR)) { + return vector - env->config->vecbase + env->sregs[VECBASE]; + } else { + return vector; + } +} + +/*! + * Handle penging IRQ. + * For the high priority interrupt jump to the corresponding interrupt vector. + * For the level-1 interrupt convert it to either user, kernel or double + * exception with the 'level-1 interrupt' exception cause. + */ +static void handle_interrupt(CPUState *env) +{ + int level = env->pending_irq_level; + + if (level > xtensa_get_cintlevel(env) && + level <= env->config->nlevel && + (env->config->level_mask[level] & + env->sregs[INTSET] & + env->sregs[INTENABLE])) { + if (level > 1) { + env->sregs[EPC1 + level - 1] = env->pc; + env->sregs[EPS2 + level - 2] = env->sregs[PS]; + env->sregs[PS] = + (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM; + env->pc = relocated_vector(env, + env->config->interrupt_vector[level]); + } else { + env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE; + + if (env->sregs[PS] & PS_EXCM) { + if (env->config->ndepc) { + env->sregs[DEPC] = env->pc; + } else { + env->sregs[EPC1] = env->pc; + } + env->exception_index = EXC_DOUBLE; + } else { + env->sregs[EPC1] = env->pc; + env->exception_index = + (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; + } + env->sregs[PS] |= PS_EXCM; + } + env->exception_taken = 1; + } +} + +void do_interrupt(CPUState *env) +{ + if (env->exception_index == EXC_IRQ) { + qemu_log_mask(CPU_LOG_INT, + "%s(EXC_IRQ) level = %d, cintlevel = %d, " + "pc = %08x, a0 = %08x, ps = %08x, " + "intset = %08x, intenable = %08x, " + "ccount = %08x\n", + __func__, env->pending_irq_level, xtensa_get_cintlevel(env), + env->pc, env->regs[0], env->sregs[PS], + env->sregs[INTSET], env->sregs[INTENABLE], + env->sregs[CCOUNT]); + handle_interrupt(env); + } + + switch (env->exception_index) { + case EXC_WINDOW_OVERFLOW4: + case EXC_WINDOW_UNDERFLOW4: + case EXC_WINDOW_OVERFLOW8: + case EXC_WINDOW_UNDERFLOW8: + case EXC_WINDOW_OVERFLOW12: + case EXC_WINDOW_UNDERFLOW12: + case EXC_KERNEL: + case EXC_USER: + case EXC_DOUBLE: + qemu_log_mask(CPU_LOG_INT, "%s(%d) " + "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n", + __func__, env->exception_index, + env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]); + if (env->config->exception_vector[env->exception_index]) { + env->pc = relocated_vector(env, + env->config->exception_vector[env->exception_index]); + env->exception_taken = 1; + } else { + qemu_log("%s(pc = %08x) bad exception_index: %d\n", + __func__, env->pc, env->exception_index); + } + break; + + case EXC_IRQ: + break; + + default: + qemu_log("%s(pc = %08x) unknown exception_index: %d\n", + __func__, env->pc, env->exception_index); + break; + } + check_interrupts(env); +} + +static void reset_tlb_mmu_all_ways(CPUState *env, + const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) +{ + unsigned wi, ei; + + for (wi = 0; wi < tlb->nways; ++wi) { + for (ei = 0; ei < tlb->way_size[wi]; ++ei) { + entry[wi][ei].asid = 0; + entry[wi][ei].variable = true; + } + } +} + +static void reset_tlb_mmu_ways56(CPUState *env, + const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) +{ + if (!tlb->varway56) { + static const xtensa_tlb_entry way5[] = { + { + .vaddr = 0xd0000000, + .paddr = 0, + .asid = 1, + .attr = 7, + .variable = false, + }, { + .vaddr = 0xd8000000, + .paddr = 0, + .asid = 1, + .attr = 3, + .variable = false, + } + }; + static const xtensa_tlb_entry way6[] = { + { + .vaddr = 0xe0000000, + .paddr = 0xf0000000, + .asid = 1, + .attr = 7, + .variable = false, + }, { + .vaddr = 0xf0000000, + .paddr = 0xf0000000, + .asid = 1, + .attr = 3, + .variable = false, + } + }; + memcpy(entry[5], way5, sizeof(way5)); + memcpy(entry[6], way6, sizeof(way6)); + } else { + uint32_t ei; + for (ei = 0; ei < 8; ++ei) { + entry[6][ei].vaddr = ei << 29; + entry[6][ei].paddr = ei << 29; + entry[6][ei].asid = 1; + entry[6][ei].attr = 2; + } + } +} + +static void reset_tlb_region_way0(CPUState *env, + xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) +{ + unsigned ei; + + for (ei = 0; ei < 8; ++ei) { + entry[0][ei].vaddr = ei << 29; + entry[0][ei].paddr = ei << 29; + entry[0][ei].asid = 1; + entry[0][ei].attr = 2; + entry[0][ei].variable = true; + } +} + +static void reset_mmu(CPUState *env) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + env->sregs[RASID] = 0x04030201; + env->sregs[ITLBCFG] = 0; + env->sregs[DTLBCFG] = 0; + env->autorefill_idx = 0; + reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb); + reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb); + reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb); + reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb); + } else { + reset_tlb_region_way0(env, env->itlb); + reset_tlb_region_way0(env, env->dtlb); + } +} + +static unsigned get_ring(const CPUState *env, uint8_t asid) +{ + unsigned i; + for (i = 0; i < 4; ++i) { + if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) { + return i; + } + } + return 0xff; +} + +/*! + * Lookup xtensa TLB for the given virtual address. + * See ISA, 4.6.2.2 + * + * \param pwi: [out] way index + * \param pei: [out] entry index + * \param pring: [out] access ring + * \return 0 if ok, exception cause code otherwise + */ +int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb, + uint32_t *pwi, uint32_t *pei, uint8_t *pring) +{ + const xtensa_tlb *tlb = dtlb ? + &env->config->dtlb : &env->config->itlb; + const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ? + env->dtlb : env->itlb; + + int nhits = 0; + unsigned wi; + + for (wi = 0; wi < tlb->nways; ++wi) { + uint32_t vpn; + uint32_t ei; + split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei); + if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) { + unsigned ring = get_ring(env, entry[wi][ei].asid); + if (ring < 4) { + if (++nhits > 1) { + return dtlb ? + LOAD_STORE_TLB_MULTI_HIT_CAUSE : + INST_TLB_MULTI_HIT_CAUSE; + } + *pwi = wi; + *pei = ei; + *pring = ring; + } + } + } + return nhits ? 0 : + (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE); +} + +/*! + * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask. + * See ISA, 4.6.5.10 + */ +static unsigned mmu_attr_to_access(uint32_t attr) +{ + unsigned access = 0; + if (attr < 12) { + access |= PAGE_READ; + if (attr & 0x1) { + access |= PAGE_EXEC; + } + if (attr & 0x2) { + access |= PAGE_WRITE; + } + } else if (attr == 13) { + access |= PAGE_READ | PAGE_WRITE; + } + return access; +} + +/*! + * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask. + * See ISA, 4.6.3.3 + */ +static unsigned region_attr_to_access(uint32_t attr) +{ + unsigned access = 0; + if ((attr < 6 && attr != 3) || attr == 14) { + access |= PAGE_READ | PAGE_WRITE; + } + if (attr > 0 && attr < 6) { + access |= PAGE_EXEC; + } + return access; +} + +static bool is_access_granted(unsigned access, int is_write) +{ + switch (is_write) { + case 0: + return access & PAGE_READ; + + case 1: + return access & PAGE_WRITE; + + case 2: + return access & PAGE_EXEC; + + default: + return 0; + } +} + +static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb, + uint32_t *wi, uint32_t *ei, uint8_t *ring); + +static int get_physical_addr_mmu(CPUState *env, + uint32_t vaddr, int is_write, int mmu_idx, + uint32_t *paddr, uint32_t *page_size, unsigned *access) +{ + bool dtlb = is_write != 2; + uint32_t wi; + uint32_t ei; + uint8_t ring; + int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring); + + if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) && + (mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) && + autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) { + ret = 0; + } + if (ret != 0) { + return ret; + } + + const xtensa_tlb_entry *entry = + xtensa_tlb_get_entry(env, dtlb, wi, ei); + + if (ring < mmu_idx) { + return dtlb ? + LOAD_STORE_PRIVILEGE_CAUSE : + INST_FETCH_PRIVILEGE_CAUSE; + } + + *access = mmu_attr_to_access(entry->attr); + if (!is_access_granted(*access, is_write)) { + return dtlb ? + (is_write ? + STORE_PROHIBITED_CAUSE : + LOAD_PROHIBITED_CAUSE) : + INST_FETCH_PROHIBITED_CAUSE; + } + + *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi)); + *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1; + + return 0; +} + +static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb, + uint32_t *wi, uint32_t *ei, uint8_t *ring) +{ + uint32_t paddr; + uint32_t page_size; + unsigned access; + uint32_t pt_vaddr = + (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc; + int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0, + &paddr, &page_size, &access); + + qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__, + vaddr, ret ? ~0 : paddr); + + if (ret == 0) { + uint32_t vpn; + uint32_t pte = ldl_phys(paddr); + + *ring = (pte >> 4) & 0x3; + *wi = (++env->autorefill_idx) & 0x3; + split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, *wi, ei); + xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vpn, pte); + qemu_log("%s: autorefill(%08x): %08x -> %08x\n", + __func__, vaddr, vpn, pte); + } + return ret; +} + +static int get_physical_addr_region(CPUState *env, + uint32_t vaddr, int is_write, int mmu_idx, + uint32_t *paddr, uint32_t *page_size, unsigned *access) +{ + bool dtlb = is_write != 2; + uint32_t wi = 0; + uint32_t ei = (vaddr >> 29) & 0x7; + const xtensa_tlb_entry *entry = + xtensa_tlb_get_entry(env, dtlb, wi, ei); + + *access = region_attr_to_access(entry->attr); + if (!is_access_granted(*access, is_write)) { + return dtlb ? + (is_write ? + STORE_PROHIBITED_CAUSE : + LOAD_PROHIBITED_CAUSE) : + INST_FETCH_PROHIBITED_CAUSE; + } + + *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK); + *page_size = ~REGION_PAGE_MASK + 1; + + return 0; +} + +/*! + * Convert virtual address to physical addr. + * MMU may issue pagewalk and change xtensa autorefill TLB way entry. + * + * \return 0 if ok, exception cause code otherwise + */ +int xtensa_get_physical_addr(CPUState *env, + uint32_t vaddr, int is_write, int mmu_idx, + uint32_t *paddr, uint32_t *page_size, unsigned *access) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx, + paddr, page_size, access); + } else if (xtensa_option_bits_enabled(env->config, + XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | + XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) { + return get_physical_addr_region(env, vaddr, is_write, mmu_idx, + paddr, page_size, access); + } else { + *paddr = vaddr; + *page_size = TARGET_PAGE_SIZE; + *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return 0; + } +} diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h new file mode 100644 index 0000000000..09ab3325c9 --- /dev/null +++ b/target-xtensa/helpers.h @@ -0,0 +1,32 @@ +#include "def-helper.h" + +DEF_HELPER_1(exception, void, i32) +DEF_HELPER_2(exception_cause, void, i32, i32) +DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32) +DEF_HELPER_1(nsa, i32, i32) +DEF_HELPER_1(nsau, i32, i32) +DEF_HELPER_1(wsr_windowbase, void, i32) +DEF_HELPER_3(entry, void, i32, i32, i32) +DEF_HELPER_1(retw, i32, i32) +DEF_HELPER_1(rotw, void, i32) +DEF_HELPER_2(window_check, void, i32, i32) +DEF_HELPER_0(restore_owb, void) +DEF_HELPER_1(movsp, void, i32) +DEF_HELPER_1(wsr_lbeg, void, i32) +DEF_HELPER_1(wsr_lend, void, i32) +DEF_HELPER_1(simcall, void, env) +DEF_HELPER_0(dump_state, void) + +DEF_HELPER_2(waiti, void, i32, i32) +DEF_HELPER_2(timer_irq, void, i32, i32) +DEF_HELPER_1(advance_ccount, void, i32) +DEF_HELPER_1(check_interrupts, void, env) + +DEF_HELPER_1(wsr_rasid, void, i32) +DEF_HELPER_2(rtlb0, i32, i32, i32) +DEF_HELPER_2(rtlb1, i32, i32, i32) +DEF_HELPER_2(itlb, void, i32, i32) +DEF_HELPER_2(ptlb, i32, i32, i32) +DEF_HELPER_3(wtlb, void, i32, i32, i32) + +#include "def-helper.h" diff --git a/target-xtensa/machine.c b/target-xtensa/machine.c new file mode 100644 index 0000000000..ddeffb2da4 --- /dev/null +++ b/target-xtensa/machine.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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/boards.h" + +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c new file mode 100644 index 0000000000..d02706db62 --- /dev/null +++ b/target-xtensa/op_helper.c @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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 "cpu.h" +#include "dyngen-exec.h" +#include "helpers.h" +#include "host-utils.h" + +static void do_unaligned_access(target_ulong addr, int is_write, int is_user, + void *retaddr); + +#define ALIGNED_ONLY +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +static void do_restore_state(void *pc_ptr) +{ + TranslationBlock *tb; + uint32_t pc = (uint32_t)(intptr_t)pc_ptr; + + tb = tb_find_pc(pc); + if (tb) { + cpu_restore_state(tb, env, pc); + } +} + +static void do_unaligned_access(target_ulong addr, int is_write, int is_user, + void *retaddr) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) && + !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) { + do_restore_state(retaddr); + HELPER(exception_cause_vaddr)( + env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr); + } +} + +void tlb_fill(target_ulong vaddr, int is_write, int mmu_idx, void *retaddr) +{ + CPUState *saved_env = env; + + env = cpu_single_env; + { + uint32_t paddr; + uint32_t page_size; + unsigned access; + int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx, + &paddr, &page_size, &access); + + qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__, + vaddr, is_write, mmu_idx, paddr, ret); + + if (ret == 0) { + tlb_set_page(env, + vaddr & TARGET_PAGE_MASK, + paddr & TARGET_PAGE_MASK, + access, mmu_idx, page_size); + } else { + do_restore_state(retaddr); + HELPER(exception_cause_vaddr)(env->pc, ret, vaddr); + } + } + env = saved_env; +} + +void HELPER(exception)(uint32_t excp) +{ + env->exception_index = excp; + cpu_loop_exit(env); +} + +void HELPER(exception_cause)(uint32_t pc, uint32_t cause) +{ + uint32_t vector; + + env->pc = pc; + if (env->sregs[PS] & PS_EXCM) { + if (env->config->ndepc) { + env->sregs[DEPC] = pc; + } else { + env->sregs[EPC1] = pc; + } + vector = EXC_DOUBLE; + } else { + env->sregs[EPC1] = pc; + vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; + } + + env->sregs[EXCCAUSE] = cause; + env->sregs[PS] |= PS_EXCM; + + HELPER(exception)(vector); +} + +void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr) +{ + env->sregs[EXCVADDR] = vaddr; + HELPER(exception_cause)(pc, cause); +} + +uint32_t HELPER(nsa)(uint32_t v) +{ + if (v & 0x80000000) { + v = ~v; + } + return v ? clz32(v) - 1 : 31; +} + +uint32_t HELPER(nsau)(uint32_t v) +{ + return v ? clz32(v) : 32; +} + +static void copy_window_from_phys(CPUState *env, + uint32_t window, uint32_t phys, uint32_t n) +{ + assert(phys < env->config->nareg); + if (phys + n <= env->config->nareg) { + memcpy(env->regs + window, env->phys_regs + phys, + n * sizeof(uint32_t)); + } else { + uint32_t n1 = env->config->nareg - phys; + memcpy(env->regs + window, env->phys_regs + phys, + n1 * sizeof(uint32_t)); + memcpy(env->regs + window + n1, env->phys_regs, + (n - n1) * sizeof(uint32_t)); + } +} + +static void copy_phys_from_window(CPUState *env, + uint32_t phys, uint32_t window, uint32_t n) +{ + assert(phys < env->config->nareg); + if (phys + n <= env->config->nareg) { + memcpy(env->phys_regs + phys, env->regs + window, + n * sizeof(uint32_t)); + } else { + uint32_t n1 = env->config->nareg - phys; + memcpy(env->phys_regs + phys, env->regs + window, + n1 * sizeof(uint32_t)); + memcpy(env->phys_regs, env->regs + window + n1, + (n - n1) * sizeof(uint32_t)); + } +} + + +static inline unsigned windowbase_bound(unsigned a, const CPUState *env) +{ + return a & (env->config->nareg / 4 - 1); +} + +static inline unsigned windowstart_bit(unsigned a, const CPUState *env) +{ + return 1 << windowbase_bound(a, env); +} + +void xtensa_sync_window_from_phys(CPUState *env) +{ + copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16); +} + +void xtensa_sync_phys_from_window(CPUState *env) +{ + copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16); +} + +static void rotate_window_abs(uint32_t position) +{ + xtensa_sync_phys_from_window(env); + env->sregs[WINDOW_BASE] = windowbase_bound(position, env); + xtensa_sync_window_from_phys(env); +} + +static void rotate_window(uint32_t delta) +{ + rotate_window_abs(env->sregs[WINDOW_BASE] + delta); +} + +void HELPER(wsr_windowbase)(uint32_t v) +{ + rotate_window_abs(v); +} + +void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm) +{ + int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT; + if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) { + qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n", + pc, env->sregs[PS]); + HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE); + } else { + env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3); + rotate_window(callinc); + env->sregs[WINDOW_START] |= + windowstart_bit(env->sregs[WINDOW_BASE], env); + } +} + +void HELPER(window_check)(uint32_t pc, uint32_t w) +{ + uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); + uint32_t windowstart = env->sregs[WINDOW_START]; + uint32_t m, n; + + if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) { + return; + } + + for (n = 1; ; ++n) { + if (n > w) { + return; + } + if (windowstart & windowstart_bit(windowbase + n, env)) { + break; + } + } + + m = windowbase_bound(windowbase + n, env); + rotate_window(n); + env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) | + (windowbase << PS_OWB_SHIFT) | PS_EXCM; + env->sregs[EPC1] = env->pc = pc; + + if (windowstart & windowstart_bit(m + 1, env)) { + HELPER(exception)(EXC_WINDOW_OVERFLOW4); + } else if (windowstart & windowstart_bit(m + 2, env)) { + HELPER(exception)(EXC_WINDOW_OVERFLOW8); + } else { + HELPER(exception)(EXC_WINDOW_OVERFLOW12); + } +} + +uint32_t HELPER(retw)(uint32_t pc) +{ + int n = (env->regs[0] >> 30) & 0x3; + int m = 0; + uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); + uint32_t windowstart = env->sregs[WINDOW_START]; + uint32_t ret_pc = 0; + + if (windowstart & windowstart_bit(windowbase - 1, env)) { + m = 1; + } else if (windowstart & windowstart_bit(windowbase - 2, env)) { + m = 2; + } else if (windowstart & windowstart_bit(windowbase - 3, env)) { + m = 3; + } + + if (n == 0 || (m != 0 && m != n) || + ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) { + qemu_log("Illegal retw instruction(pc = %08x), " + "PS = %08x, m = %d, n = %d\n", + pc, env->sregs[PS], m, n); + HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE); + } else { + int owb = windowbase; + + ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff); + + rotate_window(-n); + if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) { + env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env); + } else { + /* window underflow */ + env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) | + (windowbase << PS_OWB_SHIFT) | PS_EXCM; + env->sregs[EPC1] = env->pc = pc; + + if (n == 1) { + HELPER(exception)(EXC_WINDOW_UNDERFLOW4); + } else if (n == 2) { + HELPER(exception)(EXC_WINDOW_UNDERFLOW8); + } else if (n == 3) { + HELPER(exception)(EXC_WINDOW_UNDERFLOW12); + } + } + } + return ret_pc; +} + +void HELPER(rotw)(uint32_t imm4) +{ + rotate_window(imm4); +} + +void HELPER(restore_owb)(void) +{ + rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT); +} + +void HELPER(movsp)(uint32_t pc) +{ + if ((env->sregs[WINDOW_START] & + (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) | + windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) | + windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) { + HELPER(exception_cause)(pc, ALLOCA_CAUSE); + } +} + +void HELPER(wsr_lbeg)(uint32_t v) +{ + if (env->sregs[LBEG] != v) { + tb_invalidate_phys_page_range( + env->sregs[LEND] - 1, env->sregs[LEND], 0); + env->sregs[LBEG] = v; + } +} + +void HELPER(wsr_lend)(uint32_t v) +{ + if (env->sregs[LEND] != v) { + tb_invalidate_phys_page_range( + env->sregs[LEND] - 1, env->sregs[LEND], 0); + env->sregs[LEND] = v; + tb_invalidate_phys_page_range( + env->sregs[LEND] - 1, env->sregs[LEND], 0); + } +} + +void HELPER(dump_state)(void) +{ + cpu_dump_state(env, stderr, fprintf, 0); +} + +void HELPER(waiti)(uint32_t pc, uint32_t intlevel) +{ + env->pc = pc; + env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | + (intlevel << PS_INTLEVEL_SHIFT); + check_interrupts(env); + if (env->pending_irq_level) { + cpu_loop_exit(env); + return; + } + + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { + int i; + uint32_t wake_ccount = env->sregs[CCOUNT] - 1; + + for (i = 0; i < env->config->nccompare; ++i) { + if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] < + wake_ccount - env->sregs[CCOUNT]) { + wake_ccount = env->sregs[CCOMPARE + i]; + } + } + env->wake_ccount = wake_ccount; + qemu_mod_timer(env->ccompare_timer, qemu_get_clock_ns(vm_clock) + + muldiv64(wake_ccount - env->sregs[CCOUNT], + 1000000, env->config->clock_freq_khz)); + } + env->halt_clock = qemu_get_clock_ns(vm_clock); + env->halted = 1; + HELPER(exception)(EXCP_HLT); +} + +void HELPER(timer_irq)(uint32_t id, uint32_t active) +{ + xtensa_timer_irq(env, id, active); +} + +void HELPER(advance_ccount)(uint32_t d) +{ + xtensa_advance_ccount(env, d); +} + +void HELPER(check_interrupts)(CPUState *env) +{ + check_interrupts(env); +} + +void HELPER(wsr_rasid)(uint32_t v) +{ + v = (v & 0xffffff00) | 0x1; + if (v != env->sregs[RASID]) { + env->sregs[RASID] = v; + tlb_flush(env, 1); + } +} + +static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way) +{ + uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG]; + + switch (way) { + case 4: + return (tlbcfg >> 16) & 0x3; + + case 5: + return (tlbcfg >> 20) & 0x1; + + case 6: + return (tlbcfg >> 24) & 0x1; + + default: + return 0; + } +} + +/*! + * Get bit mask for the virtual address bits translated by the TLB way + */ +uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + bool varway56 = dtlb ? + env->config->dtlb.varway56 : + env->config->itlb.varway56; + + switch (way) { + case 4: + return 0xfff00000 << get_page_size(env, dtlb, way) * 2; + + case 5: + if (varway56) { + return 0xf8000000 << get_page_size(env, dtlb, way); + } else { + return 0xf8000000; + } + + case 6: + if (varway56) { + return 0xf0000000 << (1 - get_page_size(env, dtlb, way)); + } else { + return 0xf0000000; + } + + default: + return 0xfffff000; + } + } else { + return REGION_PAGE_MASK; + } +} + +/*! + * Get bit mask for the 'VPN without index' field. + * See ISA, 4.6.5.6, data format for RxTLB0 + */ +static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way) +{ + if (way < 4) { + bool is32 = (dtlb ? + env->config->dtlb.nrefillentries : + env->config->itlb.nrefillentries) == 32; + return is32 ? 0xffff8000 : 0xffffc000; + } else if (way == 4) { + return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2; + } else if (way <= 6) { + uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way); + bool varway56 = dtlb ? + env->config->dtlb.varway56 : + env->config->itlb.varway56; + + if (varway56) { + return mask << (way == 5 ? 2 : 3); + } else { + return mask << 1; + } + } else { + return 0xfffff000; + } +} + +/*! + * Split virtual address into VPN (with index) and entry index + * for the given TLB way + */ +void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb, + uint32_t *vpn, uint32_t wi, uint32_t *ei) +{ + bool varway56 = dtlb ? + env->config->dtlb.varway56 : + env->config->itlb.varway56; + + if (!dtlb) { + wi &= 7; + } + + if (wi < 4) { + bool is32 = (dtlb ? + env->config->dtlb.nrefillentries : + env->config->itlb.nrefillentries) == 32; + *ei = (v >> 12) & (is32 ? 0x7 : 0x3); + } else { + switch (wi) { + case 4: + { + uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2; + *ei = (v >> eibase) & 0x3; + } + break; + + case 5: + if (varway56) { + uint32_t eibase = 27 + get_page_size(env, dtlb, wi); + *ei = (v >> eibase) & 0x3; + } else { + *ei = (v >> 27) & 0x1; + } + break; + + case 6: + if (varway56) { + uint32_t eibase = 29 - get_page_size(env, dtlb, wi); + *ei = (v >> eibase) & 0x7; + } else { + *ei = (v >> 28) & 0x1; + } + break; + + default: + *ei = 0; + break; + } + } + *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi); +} + +/*! + * Split TLB address into TLB way, entry index and VPN (with index). + * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format + */ +static void split_tlb_entry_spec(uint32_t v, bool dtlb, + uint32_t *vpn, uint32_t *wi, uint32_t *ei) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + *wi = v & (dtlb ? 0xf : 0x7); + split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei); + } else { + *vpn = v & REGION_PAGE_MASK; + *wi = 0; + *ei = (v >> 29) & 0x7; + } +} + +static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi) +{ + uint32_t vpn; + uint32_t wi; + uint32_t ei; + + split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei); + if (pwi) { + *pwi = wi; + } + return xtensa_tlb_get_entry(env, dtlb, wi, ei); +} + +uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + uint32_t wi; + const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi); + return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid; + } else { + return v & REGION_PAGE_MASK; + } +} + +uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb) +{ + const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL); + return entry->paddr | entry->attr; +} + +void HELPER(itlb)(uint32_t v, uint32_t dtlb) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + uint32_t wi; + xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi); + if (entry->variable && entry->asid) { + tlb_flush_page(env, entry->vaddr); + entry->asid = 0; + } + } +} + +uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + uint32_t wi; + uint32_t ei; + uint8_t ring; + int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring); + + switch (res) { + case 0: + if (ring >= xtensa_get_ring(env)) { + return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8); + } + break; + + case INST_TLB_MULTI_HIT_CAUSE: + case LOAD_STORE_TLB_MULTI_HIT_CAUSE: + HELPER(exception_cause_vaddr)(env->pc, res, v); + break; + } + return 0; + } else { + return (v & REGION_PAGE_MASK) | 0x1; + } +} + +void xtensa_tlb_set_entry(CPUState *env, bool dtlb, + unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) +{ + xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei); + + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + if (entry->variable) { + if (entry->asid) { + tlb_flush_page(env, entry->vaddr); + } + entry->vaddr = vpn; + entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi); + entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff; + entry->attr = pte & 0xf; + } else { + qemu_log("%s %d, %d, %d trying to set immutable entry\n", + __func__, dtlb, wi, ei); + } + } else { + tlb_flush_page(env, entry->vaddr); + if (xtensa_option_enabled(env->config, + XTENSA_OPTION_REGION_TRANSLATION)) { + entry->paddr = pte & REGION_PAGE_MASK; + } + entry->attr = pte & 0xf; + } +} + +void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb) +{ + uint32_t vpn; + uint32_t wi; + uint32_t ei; + split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei); + xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p); +} diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c new file mode 100644 index 0000000000..93a807e8c0 --- /dev/null +++ b/target-xtensa/translate.c @@ -0,0 +1,2414 @@ +/* + * Xtensa ISA: + * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm + * + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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 <stdio.h> + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" +#include "sysemu.h" + +#include "helpers.h" +#define GEN_HELPER 1 +#include "helpers.h" + +typedef struct DisasContext { + const XtensaConfig *config; + TranslationBlock *tb; + uint32_t pc; + uint32_t next_pc; + int cring; + int ring; + uint32_t lbeg; + uint32_t lend; + TCGv_i32 litbase; + int is_jmp; + int singlestep_enabled; + + bool sar_5bit; + bool sar_m32_5bit; + bool sar_m32_allocated; + TCGv_i32 sar_m32; + + uint32_t ccount_delta; + unsigned used_window; +} DisasContext; + +static TCGv_ptr cpu_env; +static TCGv_i32 cpu_pc; +static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_SR[256]; +static TCGv_i32 cpu_UR[256]; + +#include "gen-icount.h" + +static const char * const sregnames[256] = { + [LBEG] = "LBEG", + [LEND] = "LEND", + [LCOUNT] = "LCOUNT", + [SAR] = "SAR", + [BR] = "BR", + [LITBASE] = "LITBASE", + [SCOMPARE1] = "SCOMPARE1", + [WINDOW_BASE] = "WINDOW_BASE", + [WINDOW_START] = "WINDOW_START", + [PTEVADDR] = "PTEVADDR", + [RASID] = "RASID", + [ITLBCFG] = "ITLBCFG", + [DTLBCFG] = "DTLBCFG", + [EPC1] = "EPC1", + [EPC1 + 1] = "EPC2", + [EPC1 + 2] = "EPC3", + [EPC1 + 3] = "EPC4", + [EPC1 + 4] = "EPC5", + [EPC1 + 5] = "EPC6", + [EPC1 + 6] = "EPC7", + [DEPC] = "DEPC", + [EPS2] = "EPS2", + [EPS2 + 1] = "EPS3", + [EPS2 + 2] = "EPS4", + [EPS2 + 3] = "EPS5", + [EPS2 + 4] = "EPS6", + [EPS2 + 5] = "EPS7", + [EXCSAVE1] = "EXCSAVE1", + [EXCSAVE1 + 1] = "EXCSAVE2", + [EXCSAVE1 + 2] = "EXCSAVE3", + [EXCSAVE1 + 3] = "EXCSAVE4", + [EXCSAVE1 + 4] = "EXCSAVE5", + [EXCSAVE1 + 5] = "EXCSAVE6", + [EXCSAVE1 + 6] = "EXCSAVE7", + [CPENABLE] = "CPENABLE", + [INTSET] = "INTSET", + [INTCLEAR] = "INTCLEAR", + [INTENABLE] = "INTENABLE", + [PS] = "PS", + [VECBASE] = "VECBASE", + [EXCCAUSE] = "EXCCAUSE", + [CCOUNT] = "CCOUNT", + [PRID] = "PRID", + [EXCVADDR] = "EXCVADDR", + [CCOMPARE] = "CCOMPARE0", + [CCOMPARE + 1] = "CCOMPARE1", + [CCOMPARE + 2] = "CCOMPARE2", +}; + +static const char * const uregnames[256] = { + [THREADPTR] = "THREADPTR", + [FCR] = "FCR", + [FSR] = "FSR", +}; + +void xtensa_translate_init(void) +{ + static const char * const regnames[] = { + "ar0", "ar1", "ar2", "ar3", + "ar4", "ar5", "ar6", "ar7", + "ar8", "ar9", "ar10", "ar11", + "ar12", "ar13", "ar14", "ar15", + }; + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + cpu_pc = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, pc), "pc"); + + for (i = 0; i < 16; i++) { + cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, regs[i]), + regnames[i]); + } + + for (i = 0; i < 256; ++i) { + if (sregnames[i]) { + cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, sregs[i]), + sregnames[i]); + } + } + + for (i = 0; i < 256; ++i) { + if (uregnames[i]) { + cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, uregs[i]), + uregnames[i]); + } + } +#define GEN_HELPER 2 +#include "helpers.h" +} + +static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt) +{ + return xtensa_option_bits_enabled(dc->config, opt); +} + +static inline bool option_enabled(DisasContext *dc, int opt) +{ + return xtensa_option_enabled(dc->config, opt); +} + +static void init_litbase(DisasContext *dc) +{ + if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { + dc->litbase = tcg_temp_local_new_i32(); + tcg_gen_andi_i32(dc->litbase, cpu_SR[LITBASE], 0xfffff000); + } +} + +static void reset_litbase(DisasContext *dc) +{ + if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { + tcg_temp_free(dc->litbase); + } +} + +static void init_sar_tracker(DisasContext *dc) +{ + dc->sar_5bit = false; + dc->sar_m32_5bit = false; + dc->sar_m32_allocated = false; +} + +static void reset_sar_tracker(DisasContext *dc) +{ + if (dc->sar_m32_allocated) { + tcg_temp_free(dc->sar_m32); + } +} + +static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa) +{ + tcg_gen_andi_i32(cpu_SR[SAR], sa, 0x1f); + if (dc->sar_m32_5bit) { + tcg_gen_discard_i32(dc->sar_m32); + } + dc->sar_5bit = true; + dc->sar_m32_5bit = false; +} + +static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) +{ + TCGv_i32 tmp = tcg_const_i32(32); + if (!dc->sar_m32_allocated) { + dc->sar_m32 = tcg_temp_local_new_i32(); + dc->sar_m32_allocated = true; + } + tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f); + tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32); + dc->sar_5bit = false; + dc->sar_m32_5bit = true; + tcg_temp_free(tmp); +} + +static void gen_advance_ccount(DisasContext *dc) +{ + if (dc->ccount_delta > 0) { + TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta); + dc->ccount_delta = 0; + gen_helper_advance_ccount(tmp); + tcg_temp_free(tmp); + } +} + +static void reset_used_window(DisasContext *dc) +{ + dc->used_window = 0; +} + +static void gen_exception(DisasContext *dc, int excp) +{ + TCGv_i32 tmp = tcg_const_i32(excp); + gen_advance_ccount(dc); + gen_helper_exception(tmp); + tcg_temp_free(tmp); +} + +static void gen_exception_cause(DisasContext *dc, uint32_t cause) +{ + TCGv_i32 tpc = tcg_const_i32(dc->pc); + TCGv_i32 tcause = tcg_const_i32(cause); + gen_advance_ccount(dc); + gen_helper_exception_cause(tpc, tcause); + tcg_temp_free(tpc); + tcg_temp_free(tcause); +} + +static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause, + TCGv_i32 vaddr) +{ + TCGv_i32 tpc = tcg_const_i32(dc->pc); + TCGv_i32 tcause = tcg_const_i32(cause); + gen_advance_ccount(dc); + gen_helper_exception_cause_vaddr(tpc, tcause, vaddr); + tcg_temp_free(tpc); + tcg_temp_free(tcause); +} + +static void gen_check_privilege(DisasContext *dc) +{ + if (dc->cring) { + gen_exception_cause(dc, PRIVILEGED_CAUSE); + } +} + +static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot) +{ + tcg_gen_mov_i32(cpu_pc, dest); + if (dc->singlestep_enabled) { + gen_exception(dc, EXCP_DEBUG); + } else { + gen_advance_ccount(dc); + if (slot >= 0) { + tcg_gen_goto_tb(slot); + tcg_gen_exit_tb((tcg_target_long)dc->tb + slot); + } else { + tcg_gen_exit_tb(0); + } + } + dc->is_jmp = DISAS_UPDATE; +} + +static void gen_jump(DisasContext *dc, TCGv dest) +{ + gen_jump_slot(dc, dest, -1); +} + +static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot) +{ + TCGv_i32 tmp = tcg_const_i32(dest); + if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) { + slot = -1; + } + gen_jump_slot(dc, tmp, slot); + tcg_temp_free(tmp); +} + +static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest, + int slot) +{ + TCGv_i32 tcallinc = tcg_const_i32(callinc); + + tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS], + tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN); + tcg_temp_free(tcallinc); + tcg_gen_movi_i32(cpu_R[callinc << 2], + (callinc << 30) | (dc->next_pc & 0x3fffffff)); + gen_jump_slot(dc, dest, slot); +} + +static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest) +{ + gen_callw_slot(dc, callinc, dest, -1); +} + +static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot) +{ + TCGv_i32 tmp = tcg_const_i32(dest); + if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) { + slot = -1; + } + gen_callw_slot(dc, callinc, tmp, slot); + tcg_temp_free(tmp); +} + +static bool gen_check_loop_end(DisasContext *dc, int slot) +{ + if (option_enabled(dc, XTENSA_OPTION_LOOP) && + !(dc->tb->flags & XTENSA_TBFLAG_EXCM) && + dc->next_pc == dc->lend) { + int label = gen_new_label(); + + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label); + tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1); + gen_jumpi(dc, dc->lbeg, slot); + gen_set_label(label); + gen_jumpi(dc, dc->next_pc, -1); + return true; + } + return false; +} + +static void gen_jumpi_check_loop_end(DisasContext *dc, int slot) +{ + if (!gen_check_loop_end(dc, slot)) { + gen_jumpi(dc, dc->next_pc, slot); + } +} + +static void gen_brcond(DisasContext *dc, TCGCond cond, + TCGv_i32 t0, TCGv_i32 t1, uint32_t offset) +{ + int label = gen_new_label(); + + tcg_gen_brcond_i32(cond, t0, t1, label); + gen_jumpi_check_loop_end(dc, 0); + gen_set_label(label); + gen_jumpi(dc, dc->pc + offset, 1); +} + +static void gen_brcondi(DisasContext *dc, TCGCond cond, + TCGv_i32 t0, uint32_t t1, uint32_t offset) +{ + TCGv_i32 tmp = tcg_const_i32(t1); + gen_brcond(dc, cond, t0, tmp, offset); + tcg_temp_free(tmp); +} + +static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) +{ + gen_advance_ccount(dc); + tcg_gen_mov_i32(d, cpu_SR[sr]); +} + +static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr) +{ + tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10); + tcg_gen_or_i32(d, d, cpu_SR[sr]); + tcg_gen_andi_i32(d, d, 0xfffffffc); +} + +static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) +{ + static void (* const rsr_handler[256])(DisasContext *dc, + TCGv_i32 d, uint32_t sr) = { + [CCOUNT] = gen_rsr_ccount, + [PTEVADDR] = gen_rsr_ptevaddr, + }; + + if (sregnames[sr]) { + if (rsr_handler[sr]) { + rsr_handler[sr](dc, d, sr); + } else { + tcg_gen_mov_i32(d, cpu_SR[sr]); + } + } else { + qemu_log("RSR %d not implemented, ", sr); + } +} + +static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ + gen_helper_wsr_lbeg(s); +} + +static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ + gen_helper_wsr_lend(s); +} + +static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ + tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f); + if (dc->sar_m32_5bit) { + tcg_gen_discard_i32(dc->sar_m32); + } + dc->sar_5bit = false; + dc->sar_m32_5bit = false; +} + +static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ + tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff); +} + +static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ + tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001); + /* This can change tb->flags, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + gen_helper_wsr_windowbase(v); + reset_used_window(dc); +} + +static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_mov_i32(cpu_SR[sr], v); + reset_used_window(dc); +} + +static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000); +} + +static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + gen_helper_wsr_rasid(v); + /* This can change tb->flags, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000); +} + +static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_andi_i32(cpu_SR[sr], v, + dc->config->inttype_mask[INTTYPE_SOFTWARE]); + gen_helper_check_interrupts(cpu_env); + gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_andi_i32(tmp, v, + dc->config->inttype_mask[INTTYPE_EDGE] | + dc->config->inttype_mask[INTTYPE_NMI] | + dc->config->inttype_mask[INTTYPE_SOFTWARE]); + tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp); + tcg_temp_free(tmp); + gen_helper_check_interrupts(cpu_env); +} + +static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_mov_i32(cpu_SR[sr], v); + gen_helper_check_interrupts(cpu_env); + gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB | + PS_UM | PS_EXCM | PS_INTLEVEL; + + if (option_enabled(dc, XTENSA_OPTION_MMU)) { + mask |= PS_RING; + } + tcg_gen_andi_i32(cpu_SR[sr], v, mask); + reset_used_window(dc); + gen_helper_check_interrupts(cpu_env); + /* This can change mmu index and tb->flags, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_prid(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +} + +static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + uint32_t id = sr - CCOMPARE; + if (id < dc->config->nccompare) { + uint32_t int_bit = 1 << dc->config->timerint[id]; + gen_advance_ccount(dc); + tcg_gen_mov_i32(cpu_SR[sr], v); + tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit); + gen_helper_check_interrupts(cpu_env); + } +} + +static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ + static void (* const wsr_handler[256])(DisasContext *dc, + uint32_t sr, TCGv_i32 v) = { + [LBEG] = gen_wsr_lbeg, + [LEND] = gen_wsr_lend, + [SAR] = gen_wsr_sar, + [BR] = gen_wsr_br, + [LITBASE] = gen_wsr_litbase, + [WINDOW_BASE] = gen_wsr_windowbase, + [WINDOW_START] = gen_wsr_windowstart, + [PTEVADDR] = gen_wsr_ptevaddr, + [RASID] = gen_wsr_rasid, + [ITLBCFG] = gen_wsr_tlbcfg, + [DTLBCFG] = gen_wsr_tlbcfg, + [INTSET] = gen_wsr_intset, + [INTCLEAR] = gen_wsr_intclear, + [INTENABLE] = gen_wsr_intenable, + [PS] = gen_wsr_ps, + [PRID] = gen_wsr_prid, + [CCOMPARE] = gen_wsr_ccompare, + [CCOMPARE + 1] = gen_wsr_ccompare, + [CCOMPARE + 2] = gen_wsr_ccompare, + }; + + if (sregnames[sr]) { + if (wsr_handler[sr]) { + wsr_handler[sr](dc, sr, s); + } else { + tcg_gen_mov_i32(cpu_SR[sr], s); + } + } else { + qemu_log("WSR %d not implemented, ", sr); + } +} + +static void gen_load_store_alignment(DisasContext *dc, int shift, + TCGv_i32 addr, bool no_hw_alignment) +{ + if (!option_enabled(dc, XTENSA_OPTION_UNALIGNED_EXCEPTION)) { + tcg_gen_andi_i32(addr, addr, ~0 << shift); + } else if (option_enabled(dc, XTENSA_OPTION_HW_ALIGNMENT) && + no_hw_alignment) { + int label = gen_new_label(); + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, addr, ~(~0 << shift)); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + gen_exception_cause_vaddr(dc, LOAD_STORE_ALIGNMENT_CAUSE, addr); + gen_set_label(label); + tcg_temp_free(tmp); + } +} + +static void gen_waiti(DisasContext *dc, uint32_t imm4) +{ + TCGv_i32 pc = tcg_const_i32(dc->next_pc); + TCGv_i32 intlevel = tcg_const_i32(imm4); + gen_advance_ccount(dc); + gen_helper_waiti(pc, intlevel); + tcg_temp_free(pc); + tcg_temp_free(intlevel); +} + +static void gen_window_check1(DisasContext *dc, unsigned r1) +{ + if (dc->tb->flags & XTENSA_TBFLAG_EXCM) { + return; + } + 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); + + dc->used_window = r1 / 4; + gen_advance_ccount(dc); + gen_helper_window_check(pc, w); + + tcg_temp_free(w); + tcg_temp_free(pc); + } +} + +static void gen_window_check2(DisasContext *dc, unsigned r1, unsigned r2) +{ + gen_window_check1(dc, r1 > r2 ? r1 : r2); +} + +static void gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2, + unsigned r3) +{ + gen_window_check2(dc, r1, r2 > r3 ? r2 : r3); +} + +static void disas_xtensa_insn(DisasContext *dc) +{ +#define HAS_OPTION_BITS(opt) do { \ + if (!option_bits_enabled(dc, opt)) { \ + qemu_log("Option is not enabled %s:%d\n", \ + __FILE__, __LINE__); \ + goto invalid_opcode; \ + } \ + } while (0) + +#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt)) + +#define TBD() qemu_log("TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__) +#define RESERVED() do { \ + qemu_log("RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \ + dc->pc, b0, b1, b2, __FILE__, __LINE__); \ + goto invalid_opcode; \ + } while (0) + + +#ifdef TARGET_WORDS_BIGENDIAN +#define OP0 (((b0) & 0xf0) >> 4) +#define OP1 (((b2) & 0xf0) >> 4) +#define OP2 ((b2) & 0xf) +#define RRR_R ((b1) & 0xf) +#define RRR_S (((b1) & 0xf0) >> 4) +#define RRR_T ((b0) & 0xf) +#else +#define OP0 (((b0) & 0xf)) +#define OP1 (((b2) & 0xf)) +#define OP2 (((b2) & 0xf0) >> 4) +#define RRR_R (((b1) & 0xf0) >> 4) +#define RRR_S (((b1) & 0xf)) +#define RRR_T (((b0) & 0xf0) >> 4) +#endif + +#define RRRN_R RRR_R +#define RRRN_S RRR_S +#define RRRN_T RRR_T + +#define RRI8_R RRR_R +#define RRI8_S RRR_S +#define RRI8_T RRR_T +#define RRI8_IMM8 (b2) +#define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8) + +#ifdef TARGET_WORDS_BIGENDIAN +#define RI16_IMM16 (((b1) << 8) | (b2)) +#else +#define RI16_IMM16 (((b2) << 8) | (b1)) +#endif + +#ifdef TARGET_WORDS_BIGENDIAN +#define CALL_N (((b0) & 0xc) >> 2) +#define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2)) +#else +#define CALL_N (((b0) & 0x30) >> 4) +#define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10)) +#endif +#define CALL_OFFSET_SE \ + (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET) + +#define CALLX_N CALL_N +#ifdef TARGET_WORDS_BIGENDIAN +#define CALLX_M ((b0) & 0x3) +#else +#define CALLX_M (((b0) & 0xc0) >> 6) +#endif +#define CALLX_S RRR_S + +#define BRI12_M CALLX_M +#define BRI12_S RRR_S +#ifdef TARGET_WORDS_BIGENDIAN +#define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2)) +#else +#define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4)) +#endif +#define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12) + +#define BRI8_M BRI12_M +#define BRI8_R RRI8_R +#define BRI8_S RRI8_S +#define BRI8_IMM8 RRI8_IMM8 +#define BRI8_IMM8_SE RRI8_IMM8_SE + +#define RSR_SR (b1) + + uint8_t b0 = ldub_code(dc->pc); + uint8_t b1 = ldub_code(dc->pc + 1); + uint8_t b2 = ldub_code(dc->pc + 2); + + static const uint32_t B4CONST[] = { + 0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 + }; + + static const uint32_t B4CONSTU[] = { + 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 + }; + + if (OP0 >= 8) { + dc->next_pc = dc->pc + 2; + HAS_OPTION(XTENSA_OPTION_CODE_DENSITY); + } else { + dc->next_pc = dc->pc + 3; + } + + switch (OP0) { + case 0: /*QRST*/ + switch (OP1) { + case 0: /*RST0*/ + switch (OP2) { + case 0: /*ST0*/ + if ((RRR_R & 0xc) == 0x8) { + HAS_OPTION(XTENSA_OPTION_BOOLEAN); + } + + switch (RRR_R) { + case 0: /*SNM0*/ + switch (CALLX_M) { + case 0: /*ILL*/ + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + break; + + case 1: /*reserved*/ + RESERVED(); + break; + + case 2: /*JR*/ + switch (CALLX_N) { + case 0: /*RET*/ + case 2: /*JX*/ + gen_window_check1(dc, CALLX_S); + gen_jump(dc, cpu_R[CALLX_S]); + break; + + case 1: /*RETWw*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + { + TCGv_i32 tmp = tcg_const_i32(dc->pc); + gen_advance_ccount(dc); + gen_helper_retw(tmp, tmp); + gen_jump(dc, tmp); + tcg_temp_free(tmp); + } + break; + + case 3: /*reserved*/ + RESERVED(); + break; + } + break; + + case 3: /*CALLX*/ + gen_window_check2(dc, CALLX_S, CALLX_N << 2); + switch (CALLX_N) { + case 0: /*CALLX0*/ + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]); + tcg_gen_movi_i32(cpu_R[0], dc->next_pc); + gen_jump(dc, tmp); + tcg_temp_free(tmp); + } + break; + + case 1: /*CALLX4w*/ + case 2: /*CALLX8w*/ + case 3: /*CALLX12w*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]); + gen_callw(dc, CALLX_N, tmp); + tcg_temp_free(tmp); + } + break; + } + break; + } + break; + + case 1: /*MOVSPw*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_window_check2(dc, RRR_T, RRR_S); + { + TCGv_i32 pc = tcg_const_i32(dc->pc); + gen_advance_ccount(dc); + gen_helper_movsp(pc); + tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]); + tcg_temp_free(pc); + } + break; + + case 2: /*SYNC*/ + switch (RRR_T) { + case 0: /*ISYNC*/ + break; + + case 1: /*RSYNC*/ + break; + + case 2: /*ESYNC*/ + break; + + case 3: /*DSYNC*/ + break; + + case 8: /*EXCW*/ + HAS_OPTION(XTENSA_OPTION_EXCEPTION); + break; + + case 12: /*MEMW*/ + break; + + case 13: /*EXTW*/ + break; + + case 15: /*NOP*/ + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 3: /*RFEIx*/ + switch (RRR_T) { + case 0: /*RFETx*/ + HAS_OPTION(XTENSA_OPTION_EXCEPTION); + switch (RRR_S) { + case 0: /*RFEx*/ + gen_check_privilege(dc); + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); + gen_helper_check_interrupts(cpu_env); + gen_jump(dc, cpu_SR[EPC1]); + break; + + case 1: /*RFUEx*/ + RESERVED(); + break; + + case 2: /*RFDEx*/ + gen_check_privilege(dc); + gen_jump(dc, cpu_SR[ + dc->config->ndepc ? DEPC : EPC1]); + break; + + case 4: /*RFWOw*/ + case 5: /*RFWUw*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_check_privilege(dc); + { + TCGv_i32 tmp = tcg_const_i32(1); + + tcg_gen_andi_i32( + cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); + tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]); + + if (RRR_S == 4) { + tcg_gen_andc_i32(cpu_SR[WINDOW_START], + cpu_SR[WINDOW_START], tmp); + } else { + tcg_gen_or_i32(cpu_SR[WINDOW_START], + cpu_SR[WINDOW_START], tmp); + } + + gen_helper_restore_owb(); + gen_helper_check_interrupts(cpu_env); + gen_jump(dc, cpu_SR[EPC1]); + + tcg_temp_free(tmp); + } + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 1: /*RFIx*/ + HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT); + if (RRR_S >= 2 && RRR_S <= dc->config->nlevel) { + gen_check_privilege(dc); + tcg_gen_mov_i32(cpu_SR[PS], + cpu_SR[EPS2 + RRR_S - 2]); + gen_helper_check_interrupts(cpu_env); + gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]); + } else { + qemu_log("RFI %d is illegal\n", RRR_S); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + } + break; + + case 2: /*RFME*/ + TBD(); + break; + + default: /*reserved*/ + RESERVED(); + break; + + } + break; + + case 4: /*BREAKx*/ + HAS_OPTION(XTENSA_OPTION_EXCEPTION); + TBD(); + break; + + case 5: /*SYSCALLx*/ + HAS_OPTION(XTENSA_OPTION_EXCEPTION); + switch (RRR_S) { + case 0: /*SYSCALLx*/ + gen_exception_cause(dc, SYSCALL_CAUSE); + break; + + case 1: /*SIMCALL*/ + if (semihosting_enabled) { + gen_check_privilege(dc); + gen_helper_simcall(cpu_env); + } else { + qemu_log("SIMCALL but semihosting is disabled\n"); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + } + break; + + default: + RESERVED(); + break; + } + break; + + case 6: /*RSILx*/ + HAS_OPTION(XTENSA_OPTION_INTERRUPT); + gen_check_privilege(dc); + gen_window_check1(dc, RRR_T); + tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]); + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); + tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); + gen_helper_check_interrupts(cpu_env); + gen_jumpi_check_loop_end(dc, 0); + break; + + case 7: /*WAITIx*/ + HAS_OPTION(XTENSA_OPTION_INTERRUPT); + gen_check_privilege(dc); + gen_waiti(dc, RRR_S); + break; + + case 8: /*ANY4p*/ + case 9: /*ALL4p*/ + case 10: /*ANY8p*/ + case 11: /*ALL8p*/ + HAS_OPTION(XTENSA_OPTION_BOOLEAN); + { + const unsigned shift = (RRR_R & 2) ? 8 : 4; + TCGv_i32 mask = tcg_const_i32( + ((1 << shift) - 1) << RRR_S); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_and_i32(tmp, cpu_SR[BR], mask); + if (RRR_R & 1) { /*ALL*/ + tcg_gen_addi_i32(tmp, tmp, 1 << RRR_S); + } else { /*ANY*/ + tcg_gen_add_i32(tmp, tmp, mask); + } + tcg_gen_shri_i32(tmp, tmp, RRR_S + shift); + tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], + tmp, RRR_T, 1); + tcg_temp_free(mask); + tcg_temp_free(tmp); + } + break; + + default: /*reserved*/ + RESERVED(); + break; + + } + break; + + case 1: /*AND*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 2: /*OR*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 3: /*XOR*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 4: /*ST1*/ + switch (RRR_R) { + case 0: /*SSR*/ + gen_window_check1(dc, RRR_S); + gen_right_shift_sar(dc, cpu_R[RRR_S]); + break; + + case 1: /*SSL*/ + gen_window_check1(dc, RRR_S); + gen_left_shift_sar(dc, cpu_R[RRR_S]); + break; + + case 2: /*SSA8L*/ + gen_window_check1(dc, RRR_S); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); + gen_right_shift_sar(dc, tmp); + tcg_temp_free(tmp); + } + break; + + case 3: /*SSA8B*/ + gen_window_check1(dc, RRR_S); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); + gen_left_shift_sar(dc, tmp); + tcg_temp_free(tmp); + } + break; + + case 4: /*SSAI*/ + { + TCGv_i32 tmp = tcg_const_i32( + RRR_S | ((RRR_T & 1) << 4)); + gen_right_shift_sar(dc, tmp); + tcg_temp_free(tmp); + } + break; + + case 6: /*RER*/ + TBD(); + break; + + case 7: /*WER*/ + TBD(); + break; + + case 8: /*ROTWw*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_check_privilege(dc); + { + TCGv_i32 tmp = tcg_const_i32( + RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0)); + gen_helper_rotw(tmp); + tcg_temp_free(tmp); + reset_used_window(dc); + } + break; + + case 14: /*NSAu*/ + HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_S, RRR_T); + gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]); + break; + + case 15: /*NSAUu*/ + HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_S, RRR_T); + gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]); + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 5: /*TLB*/ + HAS_OPTION_BITS( + XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) | + XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | + XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)); + gen_check_privilege(dc); + gen_window_check2(dc, RRR_S, RRR_T); + { + TCGv_i32 dtlb = tcg_const_i32((RRR_R & 8) != 0); + + switch (RRR_R & 7) { + case 3: /*RITLB0*/ /*RDTLB0*/ + gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); + break; + + case 4: /*IITLB*/ /*IDTLB*/ + gen_helper_itlb(cpu_R[RRR_S], dtlb); + /* This could change memory mapping, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); + break; + + case 5: /*PITLB*/ /*PDTLB*/ + tcg_gen_movi_i32(cpu_pc, dc->pc); + gen_helper_ptlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); + break; + + case 6: /*WITLB*/ /*WDTLB*/ + gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); + /* This could change memory mapping, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); + break; + + case 7: /*RITLB1*/ /*RDTLB1*/ + gen_helper_rtlb1(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); + break; + + default: + tcg_temp_free(dtlb); + RESERVED(); + break; + } + tcg_temp_free(dtlb); + } + break; + + case 6: /*RT0*/ + gen_window_check2(dc, RRR_R, RRR_T); + switch (RRR_S) { + case 0: /*NEG*/ + tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]); + break; + + case 1: /*ABS*/ + { + int label = gen_new_label(); + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]); + tcg_gen_brcondi_i32( + TCG_COND_GE, cpu_R[RRR_R], 0, label); + tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]); + gen_set_label(label); + } + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 7: /*reserved*/ + RESERVED(); + break; + + case 8: /*ADD*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 9: /*ADD**/ + case 10: + case 11: + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8); + tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]); + tcg_temp_free(tmp); + } + break; + + case 12: /*SUB*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 13: /*SUB**/ + case 14: + case 15: + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12); + tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]); + tcg_temp_free(tmp); + } + break; + } + break; + + case 1: /*RST1*/ + switch (OP2) { + case 0: /*SLLI*/ + case 1: + gen_window_check2(dc, RRR_R, RRR_S); + tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S], + 32 - (RRR_T | ((OP2 & 1) << 4))); + break; + + case 2: /*SRAI*/ + case 3: + gen_window_check2(dc, RRR_R, RRR_T); + tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T], + RRR_S | ((OP2 & 1) << 4)); + break; + + case 4: /*SRLI*/ + gen_window_check2(dc, RRR_R, RRR_T); + tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S); + break; + + case 6: /*XSR*/ + { + TCGv_i32 tmp = tcg_temp_new_i32(); + if (RSR_SR >= 64) { + gen_check_privilege(dc); + } + gen_window_check1(dc, RRR_T); + tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); + gen_rsr(dc, cpu_R[RRR_T], RSR_SR); + gen_wsr(dc, RSR_SR, tmp); + tcg_temp_free(tmp); + if (!sregnames[RSR_SR]) { + TBD(); + } + } + break; + + /* + * Note: 64 bit ops are used here solely because SAR values + * have range 0..63 + */ +#define gen_shift_reg(cmd, reg) do { \ + TCGv_i64 tmp = tcg_temp_new_i64(); \ + tcg_gen_extu_i32_i64(tmp, reg); \ + tcg_gen_##cmd##_i64(v, v, tmp); \ + tcg_gen_trunc_i64_i32(cpu_R[RRR_R], v); \ + tcg_temp_free_i64(v); \ + tcg_temp_free_i64(tmp); \ + } while (0) + +#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR]) + + case 8: /*SRC*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + TCGv_i64 v = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]); + gen_shift(shr); + } + break; + + case 9: /*SRL*/ + gen_window_check2(dc, RRR_R, RRR_T); + if (dc->sar_5bit) { + tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); + } else { + TCGv_i64 v = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(v, cpu_R[RRR_T]); + gen_shift(shr); + } + break; + + case 10: /*SLL*/ + gen_window_check2(dc, RRR_R, RRR_S); + if (dc->sar_m32_5bit) { + tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32); + } else { + TCGv_i64 v = tcg_temp_new_i64(); + TCGv_i32 s = tcg_const_i32(32); + tcg_gen_sub_i32(s, s, cpu_SR[SAR]); + tcg_gen_andi_i32(s, s, 0x3f); + tcg_gen_extu_i32_i64(v, cpu_R[RRR_S]); + gen_shift_reg(shl, s); + tcg_temp_free(s); + } + break; + + case 11: /*SRA*/ + gen_window_check2(dc, RRR_R, RRR_T); + if (dc->sar_5bit) { + tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); + } else { + TCGv_i64 v = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(v, cpu_R[RRR_T]); + gen_shift(sar); + } + break; +#undef gen_shift +#undef gen_shift_reg + + case 12: /*MUL16U*/ + HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + TCGv_i32 v1 = tcg_temp_new_i32(); + TCGv_i32 v2 = tcg_temp_new_i32(); + tcg_gen_ext16u_i32(v1, cpu_R[RRR_S]); + tcg_gen_ext16u_i32(v2, cpu_R[RRR_T]); + tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2); + tcg_temp_free(v2); + tcg_temp_free(v1); + } + break; + + case 13: /*MUL16S*/ + HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + TCGv_i32 v1 = tcg_temp_new_i32(); + TCGv_i32 v2 = tcg_temp_new_i32(); + tcg_gen_ext16s_i32(v1, cpu_R[RRR_S]); + tcg_gen_ext16s_i32(v2, cpu_R[RRR_T]); + tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2); + tcg_temp_free(v2); + tcg_temp_free(v1); + } + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 2: /*RST2*/ + if (OP2 >= 8) { + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + } + + if (OP2 >= 12) { + HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV); + int label = gen_new_label(); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0, label); + gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE); + gen_set_label(label); + } + + switch (OP2) { +#define BOOLEAN_LOGIC(fn, r, s, t) \ + do { \ + HAS_OPTION(XTENSA_OPTION_BOOLEAN); \ + TCGv_i32 tmp1 = tcg_temp_new_i32(); \ + TCGv_i32 tmp2 = tcg_temp_new_i32(); \ + \ + tcg_gen_shri_i32(tmp1, cpu_SR[BR], s); \ + tcg_gen_shri_i32(tmp2, cpu_SR[BR], t); \ + tcg_gen_##fn##_i32(tmp1, tmp1, tmp2); \ + tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, r, 1); \ + tcg_temp_free(tmp1); \ + tcg_temp_free(tmp2); \ + } while (0) + + case 0: /*ANDBp*/ + BOOLEAN_LOGIC(and, RRR_R, RRR_S, RRR_T); + break; + + case 1: /*ANDBCp*/ + BOOLEAN_LOGIC(andc, RRR_R, RRR_S, RRR_T); + break; + + case 2: /*ORBp*/ + BOOLEAN_LOGIC(or, RRR_R, RRR_S, RRR_T); + break; + + case 3: /*ORBCp*/ + BOOLEAN_LOGIC(orc, RRR_R, RRR_S, RRR_T); + break; + + case 4: /*XORBp*/ + BOOLEAN_LOGIC(xor, RRR_R, RRR_S, RRR_T); + break; + +#undef BOOLEAN_LOGIC + + case 8: /*MULLi*/ + HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL); + tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 10: /*MULUHi*/ + case 11: /*MULSHi*/ + HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL); + { + TCGv_i64 r = tcg_temp_new_i64(); + TCGv_i64 s = tcg_temp_new_i64(); + TCGv_i64 t = tcg_temp_new_i64(); + + if (OP2 == 10) { + tcg_gen_extu_i32_i64(s, cpu_R[RRR_S]); + tcg_gen_extu_i32_i64(t, cpu_R[RRR_T]); + } else { + tcg_gen_ext_i32_i64(s, cpu_R[RRR_S]); + tcg_gen_ext_i32_i64(t, cpu_R[RRR_T]); + } + tcg_gen_mul_i64(r, s, t); + tcg_gen_shri_i64(r, r, 32); + tcg_gen_trunc_i64_i32(cpu_R[RRR_R], r); + + tcg_temp_free_i64(r); + tcg_temp_free_i64(s); + tcg_temp_free_i64(t); + } + break; + + case 12: /*QUOUi*/ + tcg_gen_divu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + case 13: /*QUOSi*/ + case 15: /*REMSi*/ + { + int label1 = gen_new_label(); + int label2 = gen_new_label(); + + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_S], 0x80000000, + label1); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0xffffffff, + label1); + tcg_gen_movi_i32(cpu_R[RRR_R], + OP2 == 13 ? 0x80000000 : 0); + tcg_gen_br(label2); + gen_set_label(label1); + if (OP2 == 13) { + tcg_gen_div_i32(cpu_R[RRR_R], + cpu_R[RRR_S], cpu_R[RRR_T]); + } else { + tcg_gen_rem_i32(cpu_R[RRR_R], + cpu_R[RRR_S], cpu_R[RRR_T]); + } + gen_set_label(label2); + } + break; + + case 14: /*REMUi*/ + tcg_gen_remu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 3: /*RST3*/ + switch (OP2) { + case 0: /*RSR*/ + if (RSR_SR >= 64) { + gen_check_privilege(dc); + } + gen_window_check1(dc, RRR_T); + gen_rsr(dc, cpu_R[RRR_T], RSR_SR); + if (!sregnames[RSR_SR]) { + TBD(); + } + break; + + case 1: /*WSR*/ + if (RSR_SR >= 64) { + gen_check_privilege(dc); + } + gen_window_check1(dc, RRR_T); + gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); + if (!sregnames[RSR_SR]) { + TBD(); + } + break; + + case 2: /*SEXTu*/ + HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_R, RRR_S); + { + int shift = 24 - RRR_T; + + if (shift == 24) { + tcg_gen_ext8s_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + } else if (shift == 16) { + tcg_gen_ext16s_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + } else { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[RRR_S], shift); + tcg_gen_sari_i32(cpu_R[RRR_R], tmp, shift); + tcg_temp_free(tmp); + } + } + break; + + case 3: /*CLAMPSu*/ + HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_R, RRR_S); + { + TCGv_i32 tmp1 = tcg_temp_new_i32(); + TCGv_i32 tmp2 = tcg_temp_new_i32(); + int label = gen_new_label(); + + tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 24 - RRR_T); + tcg_gen_xor_i32(tmp2, tmp1, cpu_R[RRR_S]); + tcg_gen_andi_i32(tmp2, tmp2, 0xffffffff << (RRR_T + 7)); + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp2, 0, label); + + tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31); + tcg_gen_xori_i32(cpu_R[RRR_R], tmp1, + 0xffffffff >> (25 - RRR_T)); + + gen_set_label(label); + + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + } + break; + + case 4: /*MINu*/ + case 5: /*MAXu*/ + case 6: /*MINUu*/ + case 7: /*MAXUu*/ + HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + static const TCGCond cond[] = { + TCG_COND_LE, + TCG_COND_GE, + TCG_COND_LEU, + TCG_COND_GEU + }; + int label = gen_new_label(); + + if (RRR_R != RRR_T) { + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + tcg_gen_brcond_i32(cond[OP2 - 4], + cpu_R[RRR_S], cpu_R[RRR_T], label); + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]); + } else { + tcg_gen_brcond_i32(cond[OP2 - 4], + cpu_R[RRR_T], cpu_R[RRR_S], label); + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + } + gen_set_label(label); + } + break; + + case 8: /*MOVEQZ*/ + case 9: /*MOVNEZ*/ + case 10: /*MOVLTZ*/ + case 11: /*MOVGEZ*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + { + static const TCGCond cond[] = { + TCG_COND_NE, + TCG_COND_EQ, + TCG_COND_GE, + TCG_COND_LT + }; + int label = gen_new_label(); + tcg_gen_brcondi_i32(cond[OP2 - 8], cpu_R[RRR_T], 0, label); + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + gen_set_label(label); + } + break; + + case 12: /*MOVFp*/ + case 13: /*MOVTp*/ + HAS_OPTION(XTENSA_OPTION_BOOLEAN); + gen_window_check2(dc, RRR_R, RRR_S); + { + int label = gen_new_label(); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T); + tcg_gen_brcondi_i32( + OP2 & 1 ? TCG_COND_EQ : TCG_COND_NE, + tmp, 0, label); + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); + gen_set_label(label); + tcg_temp_free(tmp); + } + break; + + case 14: /*RUR*/ + gen_window_check1(dc, RRR_R); + { + int st = (RRR_S << 4) + RRR_T; + if (uregnames[st]) { + tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]); + } else { + qemu_log("RUR %d not implemented, ", st); + TBD(); + } + } + break; + + case 15: /*WUR*/ + gen_window_check1(dc, RRR_T); + { + if (uregnames[RSR_SR]) { + tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]); + } else { + qemu_log("WUR %d not implemented, ", RSR_SR); + TBD(); + } + } + break; + + } + break; + + case 4: /*EXTUI*/ + case 5: + gen_window_check2(dc, RRR_R, RRR_T); + { + int shiftimm = RRR_S | (OP1 << 4); + int maskimm = (1 << (OP2 + 1)) - 1; + + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); + tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); + tcg_temp_free(tmp); + } + break; + + case 6: /*CUST0*/ + RESERVED(); + break; + + case 7: /*CUST1*/ + RESERVED(); + break; + + case 8: /*LSCXp*/ + HAS_OPTION(XTENSA_OPTION_COPROCESSOR); + TBD(); + break; + + case 9: /*LSC4*/ + gen_window_check2(dc, RRR_S, RRR_T); + switch (OP2) { + case 0: /*L32E*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_check_privilege(dc); + { + TCGv_i32 addr = tcg_temp_new_i32(); + tcg_gen_addi_i32(addr, cpu_R[RRR_S], + (0xffffffc0 | (RRR_R << 2))); + tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring); + tcg_temp_free(addr); + } + break; + + case 4: /*S32E*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_check_privilege(dc); + { + TCGv_i32 addr = tcg_temp_new_i32(); + tcg_gen_addi_i32(addr, cpu_R[RRR_S], + (0xffffffc0 | (RRR_R << 2))); + tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring); + tcg_temp_free(addr); + } + break; + + default: + RESERVED(); + break; + } + break; + + case 10: /*FP0*/ + HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); + TBD(); + break; + + case 11: /*FP1*/ + HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); + TBD(); + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 1: /*L32R*/ + gen_window_check1(dc, RRR_T); + { + TCGv_i32 tmp = tcg_const_i32( + ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ? + 0 : ((dc->pc + 3) & ~3)) + + (0xfffc0000 | (RI16_IMM16 << 2))); + + if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { + tcg_gen_add_i32(tmp, tmp, dc->litbase); + } + tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring); + tcg_temp_free(tmp); + } + break; + + case 2: /*LSAI*/ +#define gen_load_store(type, shift) do { \ + TCGv_i32 addr = tcg_temp_new_i32(); \ + gen_window_check2(dc, RRI8_S, RRI8_T); \ + tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \ + if (shift) { \ + gen_load_store_alignment(dc, shift, addr, false); \ + } \ + tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ + tcg_temp_free(addr); \ + } while (0) + + switch (RRI8_R) { + case 0: /*L8UI*/ + gen_load_store(ld8u, 0); + break; + + case 1: /*L16UI*/ + gen_load_store(ld16u, 1); + break; + + case 2: /*L32I*/ + gen_load_store(ld32u, 2); + break; + + case 4: /*S8I*/ + gen_load_store(st8, 0); + break; + + case 5: /*S16I*/ + gen_load_store(st16, 1); + break; + + case 6: /*S32I*/ + gen_load_store(st32, 2); + break; + + case 7: /*CACHEc*/ + if (RRI8_T < 8) { + HAS_OPTION(XTENSA_OPTION_DCACHE); + } + + switch (RRI8_T) { + case 0: /*DPFRc*/ + break; + + case 1: /*DPFWc*/ + break; + + case 2: /*DPFROc*/ + break; + + case 3: /*DPFWOc*/ + break; + + case 4: /*DHWBc*/ + break; + + case 5: /*DHWBIc*/ + break; + + case 6: /*DHIc*/ + break; + + case 7: /*DIIc*/ + break; + + case 8: /*DCEc*/ + switch (OP1) { + case 0: /*DPFLl*/ + HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); + break; + + case 2: /*DHUl*/ + HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); + break; + + case 3: /*DIUl*/ + HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); + break; + + case 4: /*DIWBc*/ + HAS_OPTION(XTENSA_OPTION_DCACHE); + break; + + case 5: /*DIWBIc*/ + HAS_OPTION(XTENSA_OPTION_DCACHE); + break; + + default: /*reserved*/ + RESERVED(); + break; + + } + break; + + case 12: /*IPFc*/ + HAS_OPTION(XTENSA_OPTION_ICACHE); + break; + + case 13: /*ICEc*/ + switch (OP1) { + case 0: /*IPFLl*/ + HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); + break; + + case 2: /*IHUl*/ + HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); + break; + + case 3: /*IIUl*/ + HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 14: /*IHIc*/ + HAS_OPTION(XTENSA_OPTION_ICACHE); + break; + + case 15: /*IIIc*/ + HAS_OPTION(XTENSA_OPTION_ICACHE); + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 9: /*L16SI*/ + gen_load_store(ld16s, 1); + break; +#undef gen_load_store + + case 10: /*MOVI*/ + gen_window_check1(dc, RRI8_T); + tcg_gen_movi_i32(cpu_R[RRI8_T], + RRI8_IMM8 | (RRI8_S << 8) | + ((RRI8_S & 0x8) ? 0xfffff000 : 0)); + break; + +#define gen_load_store_no_hw_align(type) do { \ + TCGv_i32 addr = tcg_temp_local_new_i32(); \ + gen_window_check2(dc, RRI8_S, RRI8_T); \ + tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \ + gen_load_store_alignment(dc, 2, addr, true); \ + tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ + tcg_temp_free(addr); \ + } while (0) + + case 11: /*L32AIy*/ + HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); + gen_load_store_no_hw_align(ld32u); /*TODO acquire?*/ + break; + + case 12: /*ADDI*/ + gen_window_check2(dc, RRI8_S, RRI8_T); + tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE); + break; + + case 13: /*ADDMI*/ + gen_window_check2(dc, RRI8_S, RRI8_T); + tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE << 8); + break; + + case 14: /*S32C1Iy*/ + HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); + gen_window_check2(dc, RRI8_S, RRI8_T); + { + int label = gen_new_label(); + TCGv_i32 tmp = tcg_temp_local_new_i32(); + TCGv_i32 addr = tcg_temp_local_new_i32(); + + tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]); + tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); + gen_load_store_alignment(dc, 2, addr, true); + tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring); + tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T], + cpu_SR[SCOMPARE1], label); + + tcg_gen_qemu_st32(tmp, addr, dc->cring); + + gen_set_label(label); + tcg_temp_free(addr); + tcg_temp_free(tmp); + } + break; + + case 15: /*S32RIy*/ + HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); + gen_load_store_no_hw_align(st32); /*TODO release?*/ + break; +#undef gen_load_store_no_hw_align + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + case 3: /*LSCIp*/ + HAS_OPTION(XTENSA_OPTION_COPROCESSOR); + TBD(); + break; + + case 4: /*MAC16d*/ + HAS_OPTION(XTENSA_OPTION_MAC16); + TBD(); + break; + + case 5: /*CALLN*/ + switch (CALL_N) { + case 0: /*CALL0*/ + tcg_gen_movi_i32(cpu_R[0], dc->next_pc); + gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); + break; + + case 1: /*CALL4w*/ + case 2: /*CALL8w*/ + case 3: /*CALL12w*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_window_check1(dc, CALL_N << 2); + gen_callwi(dc, CALL_N, + (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); + break; + } + break; + + case 6: /*SI*/ + switch (CALL_N) { + case 0: /*J*/ + gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0); + break; + + case 1: /*BZ*/ + gen_window_check1(dc, BRI12_S); + { + static const TCGCond cond[] = { + TCG_COND_EQ, /*BEQZ*/ + TCG_COND_NE, /*BNEZ*/ + TCG_COND_LT, /*BLTZ*/ + TCG_COND_GE, /*BGEZ*/ + }; + + gen_brcondi(dc, cond[BRI12_M & 3], cpu_R[BRI12_S], 0, + 4 + BRI12_IMM12_SE); + } + break; + + case 2: /*BI0*/ + gen_window_check1(dc, BRI8_S); + { + static const TCGCond cond[] = { + TCG_COND_EQ, /*BEQI*/ + TCG_COND_NE, /*BNEI*/ + TCG_COND_LT, /*BLTI*/ + TCG_COND_GE, /*BGEI*/ + }; + + gen_brcondi(dc, cond[BRI8_M & 3], + cpu_R[BRI8_S], B4CONST[BRI8_R], 4 + BRI8_IMM8_SE); + } + break; + + case 3: /*BI1*/ + switch (BRI8_M) { + case 0: /*ENTRYw*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + { + TCGv_i32 pc = tcg_const_i32(dc->pc); + TCGv_i32 s = tcg_const_i32(BRI12_S); + TCGv_i32 imm = tcg_const_i32(BRI12_IMM12); + gen_advance_ccount(dc); + gen_helper_entry(pc, s, imm); + tcg_temp_free(imm); + tcg_temp_free(s); + tcg_temp_free(pc); + reset_used_window(dc); + } + break; + + case 1: /*B1*/ + switch (BRI8_R) { + case 0: /*BFp*/ + case 1: /*BTp*/ + HAS_OPTION(XTENSA_OPTION_BOOLEAN); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRI8_S); + gen_brcondi(dc, + BRI8_R == 1 ? TCG_COND_NE : TCG_COND_EQ, + tmp, 0, 4 + RRI8_IMM8_SE); + tcg_temp_free(tmp); + } + break; + + case 8: /*LOOP*/ + case 9: /*LOOPNEZ*/ + case 10: /*LOOPGTZ*/ + HAS_OPTION(XTENSA_OPTION_LOOP); + gen_window_check1(dc, RRI8_S); + { + uint32_t lend = dc->pc + RRI8_IMM8 + 4; + TCGv_i32 tmp = tcg_const_i32(lend); + + tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1); + tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc); + gen_wsr_lend(dc, LEND, tmp); + tcg_temp_free(tmp); + + if (BRI8_R > 8) { + int label = gen_new_label(); + tcg_gen_brcondi_i32( + BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT, + cpu_R[RRI8_S], 0, label); + gen_jumpi(dc, lend, 1); + gen_set_label(label); + } + + gen_jumpi(dc, dc->next_pc, 0); + } + break; + + default: /*reserved*/ + RESERVED(); + break; + + } + break; + + case 2: /*BLTUI*/ + case 3: /*BGEUI*/ + gen_window_check1(dc, BRI8_S); + gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU, + cpu_R[BRI8_S], B4CONSTU[BRI8_R], 4 + BRI8_IMM8_SE); + break; + } + break; + + } + break; + + case 7: /*B*/ + { + TCGCond eq_ne = (RRI8_R & 8) ? TCG_COND_NE : TCG_COND_EQ; + + switch (RRI8_R & 7) { + case 0: /*BNONE*/ /*BANY*/ + gen_window_check2(dc, RRI8_S, RRI8_T); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); + gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); + tcg_temp_free(tmp); + } + break; + + case 1: /*BEQ*/ /*BNE*/ + case 2: /*BLT*/ /*BGE*/ + case 3: /*BLTU*/ /*BGEU*/ + gen_window_check2(dc, RRI8_S, RRI8_T); + { + static const TCGCond cond[] = { + [1] = TCG_COND_EQ, + [2] = TCG_COND_LT, + [3] = TCG_COND_LTU, + [9] = TCG_COND_NE, + [10] = TCG_COND_GE, + [11] = TCG_COND_GEU, + }; + gen_brcond(dc, cond[RRI8_R], cpu_R[RRI8_S], cpu_R[RRI8_T], + 4 + RRI8_IMM8_SE); + } + break; + + case 4: /*BALL*/ /*BNALL*/ + gen_window_check2(dc, RRI8_S, RRI8_T); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); + gen_brcond(dc, eq_ne, tmp, cpu_R[RRI8_T], + 4 + RRI8_IMM8_SE); + tcg_temp_free(tmp); + } + break; + + case 5: /*BBC*/ /*BBS*/ + gen_window_check2(dc, RRI8_S, RRI8_T); + { + TCGv_i32 bit = tcg_const_i32(1); + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f); + tcg_gen_shl_i32(bit, bit, tmp); + tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit); + gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); + tcg_temp_free(tmp); + tcg_temp_free(bit); + } + break; + + case 6: /*BBCI*/ /*BBSI*/ + case 7: + gen_window_check1(dc, RRI8_S); + { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, cpu_R[RRI8_S], + 1 << (((RRI8_R & 1) << 4) | RRI8_T)); + gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); + tcg_temp_free(tmp); + } + break; + + } + } + break; + +#define gen_narrow_load_store(type) do { \ + TCGv_i32 addr = tcg_temp_new_i32(); \ + gen_window_check2(dc, RRRN_S, RRRN_T); \ + tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \ + gen_load_store_alignment(dc, 2, addr, false); \ + tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \ + tcg_temp_free(addr); \ + } while (0) + + case 8: /*L32I.Nn*/ + gen_narrow_load_store(ld32u); + break; + + case 9: /*S32I.Nn*/ + gen_narrow_load_store(st32); + break; +#undef gen_narrow_load_store + + case 10: /*ADD.Nn*/ + gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T); + tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]); + break; + + case 11: /*ADDI.Nn*/ + gen_window_check2(dc, RRRN_R, RRRN_S); + tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], RRRN_T ? RRRN_T : -1); + break; + + case 12: /*ST2n*/ + gen_window_check1(dc, RRRN_S); + if (RRRN_T < 8) { /*MOVI.Nn*/ + tcg_gen_movi_i32(cpu_R[RRRN_S], + RRRN_R | (RRRN_T << 4) | + ((RRRN_T & 6) == 6 ? 0xffffff80 : 0)); + } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/ + TCGCond eq_ne = (RRRN_T & 4) ? TCG_COND_NE : TCG_COND_EQ; + + gen_brcondi(dc, eq_ne, cpu_R[RRRN_S], 0, + 4 + (RRRN_R | ((RRRN_T & 3) << 4))); + } + break; + + case 13: /*ST3n*/ + switch (RRRN_R) { + case 0: /*MOV.Nn*/ + gen_window_check2(dc, RRRN_S, RRRN_T); + tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]); + break; + + case 15: /*S3*/ + switch (RRRN_T) { + case 0: /*RET.Nn*/ + gen_jump(dc, cpu_R[0]); + break; + + case 1: /*RETW.Nn*/ + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + { + TCGv_i32 tmp = tcg_const_i32(dc->pc); + gen_advance_ccount(dc); + gen_helper_retw(tmp, tmp); + gen_jump(dc, tmp); + tcg_temp_free(tmp); + } + break; + + case 2: /*BREAK.Nn*/ + TBD(); + break; + + case 3: /*NOP.Nn*/ + break; + + case 6: /*ILL.Nn*/ + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + default: /*reserved*/ + RESERVED(); + break; + } + break; + + default: /*reserved*/ + RESERVED(); + break; + } + + gen_check_loop_end(dc, 0); + dc->pc = dc->next_pc; + + return; + +invalid_opcode: + qemu_log("INVALID(pc = %08x)\n", dc->pc); + dc->pc = dc->next_pc; +#undef HAS_OPTION +} + +static void check_breakpoint(CPUState *env, DisasContext *dc) +{ + CPUBreakpoint *bp; + + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + tcg_gen_movi_i32(cpu_pc, dc->pc); + gen_exception(dc, EXCP_DEBUG); + dc->is_jmp = DISAS_UPDATE; + } + } + } +} + +static void gen_intermediate_code_internal( + CPUState *env, TranslationBlock *tb, int search_pc) +{ + DisasContext dc; + int insn_count = 0; + int j, lj = -1; + uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + int max_insns = tb->cflags & CF_COUNT_MASK; + uint32_t pc_start = tb->pc; + uint32_t next_page_start = + (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + + dc.config = env->config; + dc.singlestep_enabled = env->singlestep_enabled; + dc.tb = tb; + dc.pc = pc_start; + dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK; + dc.cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc.ring; + dc.lbeg = env->sregs[LBEG]; + dc.lend = env->sregs[LEND]; + dc.is_jmp = DISAS_NEXT; + dc.ccount_delta = 0; + + init_litbase(&dc); + init_sar_tracker(&dc); + reset_used_window(&dc); + + gen_icount_start(); + + if (env->singlestep_enabled && env->exception_taken) { + env->exception_taken = 0; + tcg_gen_movi_i32(cpu_pc, dc.pc); + gen_exception(&dc, EXCP_DEBUG); + } + + do { + check_breakpoint(env, &dc); + + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) { + gen_opc_instr_start[lj++] = 0; + } + } + gen_opc_pc[lj] = dc.pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = insn_count; + } + + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + tcg_gen_debug_insn_start(dc.pc); + } + + ++dc.ccount_delta; + + if (insn_count + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); + } + + disas_xtensa_insn(&dc); + ++insn_count; + if (env->singlestep_enabled) { + tcg_gen_movi_i32(cpu_pc, dc.pc); + gen_exception(&dc, EXCP_DEBUG); + break; + } + } while (dc.is_jmp == DISAS_NEXT && + insn_count < max_insns && + dc.pc < next_page_start && + gen_opc_ptr < gen_opc_end); + + reset_litbase(&dc); + reset_sar_tracker(&dc); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + + if (dc.is_jmp == DISAS_NEXT) { + gen_jumpi(&dc, dc.pc, 0); + } + gen_icount_end(tb, insn_count); + *gen_opc_ptr = INDEX_op_end; + + if (!search_pc) { + tb->size = dc.pc - pc_start; + tb->icount = insn_count; + } +} + +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + int i, j; + + cpu_fprintf(f, "PC=%08x\n\n", env->pc); + + for (i = j = 0; i < 256; ++i) { + if (sregnames[i]) { + cpu_fprintf(f, "%s=%08x%c", sregnames[i], env->sregs[i], + (j++ % 4) == 3 ? '\n' : ' '); + } + } + + cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); + + for (i = j = 0; i < 256; ++i) { + if (uregnames[i]) { + cpu_fprintf(f, "%s=%08x%c", uregnames[i], env->uregs[i], + (j++ % 4) == 3 ? '\n' : ' '); + } + } + + cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); + + for (i = 0; i < 16; ++i) { + cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i], + (i % 4) == 3 ? '\n' : ' '); + } + + cpu_fprintf(f, "\n"); + + for (i = 0; i < env->config->nareg; ++i) { + cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i], + (i % 4) == 3 ? '\n' : ' '); + } +} + +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) +{ + env->pc = gen_opc_pc[pc_pos]; +} diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 7529677fe2..281f87d3c6 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -76,9 +76,11 @@ static const int tcg_target_call_iarg_regs[] = { #endif }; -static const int tcg_target_call_oarg_regs[2] = { +static const int tcg_target_call_oarg_regs[] = { TCG_REG_EAX, +#if TCG_TARGET_REG_BITS == 32 TCG_REG_EDX +#endif }; static uint8_t *tb_ret_addr; diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 9db205d4cc..3803ab6bfa 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -172,9 +172,8 @@ static const int tcg_target_call_iarg_regs[8] = { TCG_REG_R63, }; -static const int tcg_target_call_oarg_regs[2] = { - TCG_REG_R8, - TCG_REG_R9 +static const int tcg_target_call_oarg_regs[] = { + TCG_REG_R8 }; /* maximum number of register used for input function arguments */ diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index d831684803..3d24cd4da4 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -130,7 +130,7 @@ static const int tcg_target_call_iarg_regs[] = { TCG_REG_R10 }; -static const int tcg_target_call_oarg_regs[2] = { +static const int tcg_target_call_oarg_regs[] = { TCG_REG_R3 }; @@ -1560,7 +1560,7 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args, break; case INDEX_op_ext32u_i64: - tcg_out_rld (s, RLDICR, args[0], args[1], 0, 32); + tcg_out_rld (s, RLDICL, args[0], args[1], 0, 32); break; case INDEX_op_setcond_i32: diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 2fc5646400..b58df719a6 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -252,7 +252,9 @@ static const int tcg_target_call_iarg_regs[] = { static const int tcg_target_call_oarg_regs[] = { TCG_REG_R2, - TCG_REG_R3, +#if TCG_TARGET_REG_BITS == 32 + TCG_REG_R3 +#endif }; #define S390_CC_EQ 8 diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index ac76e1198d..fc3fd7ffce 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -84,9 +84,11 @@ static const int tcg_target_call_iarg_regs[6] = { TCG_REG_O5, }; -static const int tcg_target_call_oarg_regs[2] = { +static const int tcg_target_call_oarg_regs[] = { TCG_REG_O0, - TCG_REG_O1, +#if TCG_TARGET_REG_BITS == 32 + TCG_REG_O1 +#endif }; static inline int check_fit_tl(tcg_target_long val, unsigned int bits) diff --git a/tests/test-i386.c b/tests/test-i386.c index 9cb5b51b76..8e64bbaf38 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -802,7 +802,7 @@ void test_fcmp(double a, double b) "fstsw %%ax\n" : "=a" (fpus) : "t" (a), "u" (b)); - printf("fcom(%f %f)=%04lx \n", + printf("fcom(%f %f)=%04lx\n", a, b, fpus & (0x4500 | FPUS_EMASK)); fpu_clear_exceptions(); asm("fucom %2\n" diff --git a/tests/xtensa/Makefile b/tests/xtensa/Makefile new file mode 100644 index 0000000000..70bd097ec4 --- /dev/null +++ b/tests/xtensa/Makefile @@ -0,0 +1,74 @@ +-include ../../config-host.mak + +CROSS=xtensa-dc232b-elf- + +ifndef XT +SIM = qemu-system-xtensa +SIMFLAGS = -M dc232b -nographic -semihosting $(EXTFLAGS) -kernel +SIMDEBUG = -s -S +else +SIM = xt-run +SIMFLAGS = --xtensa-core=DC_B_232L --exit_with_target_code $(EXTFLAGS) +SIMDEBUG = --gdbserve=0 +endif + +CC = $(CROSS)gcc +AS = $(CROSS)gcc -x assembler +LD = $(CROSS)ld + +LDFLAGS = -Tlinker.ld + +CRT = crt.o vectors.o + +TESTCASES += test_b.tst +TESTCASES += test_bi.tst +#TESTCASES += test_boolean.tst +TESTCASES += test_bz.tst +TESTCASES += test_clamps.tst +TESTCASES += test_fail.tst +TESTCASES += test_interrupt.tst +TESTCASES += test_loop.tst +TESTCASES += test_max.tst +TESTCASES += test_min.tst +TESTCASES += test_mmu.tst +TESTCASES += test_mul16.tst +TESTCASES += test_mul32.tst +TESTCASES += test_nsa.tst +ifdef XT +TESTCASES += test_pipeline.tst +endif +TESTCASES += test_quo.tst +TESTCASES += test_rem.tst +TESTCASES += test_rst0.tst +TESTCASES += test_sar.tst +TESTCASES += test_sext.tst +TESTCASES += test_shift.tst +TESTCASES += test_timer.tst +TESTCASES += test_windowed.tst + +all: build + +%.o: $(SRC_PATH)/tests/xtensa/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: $(SRC_PATH)/tests/xtensa/%.S + $(AS) $(ASFLAGS) -c $< -o $@ + +%.tst: %.o macros.inc $(CRT) Makefile + $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@ + +build: $(TESTCASES) + +check: $(addprefix run-, $(TESTCASES)) + +run-%.tst: %.tst + $(SIM) $(SIMFLAGS) ./$< + +run-test_fail.tst: test_fail.tst + ! $(SIM) $(SIMFLAGS) ./$< + +debug-%.tst: %.tst + $(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$< + +clean: + $(RM) -fr $(TESTCASES) $(CRT) diff --git a/tests/xtensa/crt.S b/tests/xtensa/crt.S new file mode 100644 index 0000000000..d9846acace --- /dev/null +++ b/tests/xtensa/crt.S @@ -0,0 +1,24 @@ +.section .init + j 1f +.section .init.text +1: + movi a2, _start + jx a2 + +.text +.global _start +_start: + movi a2, 1 + wsr a2, windowstart + movi a2, 0 + wsr a2, windowbase + movi a1, _fstack + movi a2, 0x4000f + wsr a2, ps + isync + + call0 main + + mov a3, a2 + movi a2, 1 + simcall diff --git a/tests/xtensa/linker.ld b/tests/xtensa/linker.ld new file mode 100644 index 0000000000..4d0b307fd2 --- /dev/null +++ b/tests/xtensa/linker.ld @@ -0,0 +1,112 @@ +OUTPUT_FORMAT("elf32-xtensa-le") +ENTRY(_start) + +__DYNAMIC = 0; + +MEMORY { + ram : ORIGIN = 0xd0000000, LENGTH = 0x08000000 /* 128M */ + rom : ORIGIN = 0xfe000000, LENGTH = 0x00001000 /* 4k */ +} + +SECTIONS +{ + .init : + { + *(.init) + *(.init.*) + } > rom + + .vector : + { + . = 0x00000000; + *(.vector.window_overflow_4) + *(.vector.window_overflow_4.*) + . = 0x00000040; + *(.vector.window_underflow_4) + *(.vector.window_underflow_4.*) + . = 0x00000080; + *(.vector.window_overflow_8) + *(.vector.window_overflow_8.*) + . = 0x000000c0; + *(.vector.window_underflow_8) + *(.vector.window_underflow_8.*) + . = 0x00000100; + *(.vector.window_overflow_12) + *(.vector.window_overflow_12.*) + . = 0x00000140; + *(.vector.window_underflow_12) + *(.vector.window_underflow_12.*) + + . = 0x00000180; + *(.vector.level2) + *(.vector.level2.*) + . = 0x000001c0; + *(.vector.level3) + *(.vector.level3.*) + . = 0x00000200; + *(.vector.level4) + *(.vector.level4.*) + . = 0x00000240; + *(.vector.level5) + *(.vector.level5.*) + . = 0x00000280; + *(.vector.level6) + *(.vector.level6.*) + . = 0x000002c0; + *(.vector.level7) + *(.vector.level7.*) + + . = 0x00000300; + *(.vector.kernel) + *(.vector.kernel.*) + . = 0x00000340; + *(.vector.user) + *(.vector.user.*) + . = 0x000003c0; + *(.vector.double) + *(.vector.double.*) + } > ram + + .text : + { + _ftext = .; + *(.text .stub .text.* .gnu.linkonce.t.* .literal .literal.*) + _etext = .; + } > ram + + .rodata : + { + . = ALIGN(4); + _frodata = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + _erodata = .; + } > ram + + .data : + { + . = ALIGN(4); + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + _gp = ALIGN(16); + *(.sdata .sdata.* .gnu.linkonce.s.*) + _edata = .; + } > ram + + .bss : + { + . = ALIGN(4); + _fbss = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + _ebss = .; + _end = .; + } > ram +} + +PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4); diff --git a/tests/xtensa/macros.inc b/tests/xtensa/macros.inc new file mode 100644 index 0000000000..2d4515e14f --- /dev/null +++ b/tests/xtensa/macros.inc @@ -0,0 +1,68 @@ +.macro test_suite name +.data +status: .word result +result: .space 20 +.text +.global main +.align 4 +main: +.endm + +.macro reset_ps + movi a2, 0x4000f + wsr a2, ps + isync +.endm + +.macro test_suite_end + reset_ps + movi a0, status + l32i a2, a0, 0 + movi a0, result + sub a2, a2, a0 + movi a3, 0 + loopnez a2, 1f + l8ui a2, a0, 0 + or a3, a3, a2 + addi a0, a0, 1 +1: + exit +.endm + +.macro test name +.endm + +.macro test_end +99: + reset_ps + movi a2, status + l32i a3, a2, 0 + addi a3, a3, 1 + s32i a3, a2, 0 +.endm + +.macro exit + movi a2, 1 + simcall +.endm + +.macro test_fail + movi a2, status + l32i a2, a2, 0 + movi a3, 1 + s8i a3, a2, 0 + j 99f +.endm + +.macro assert cond, arg1, arg2 + b\cond \arg1, \arg2, 90f + test_fail +90: + nop +.endm + +.macro set_vector vector, addr + movi a2, handler_\vector + movi a3, \addr + s32i a3, a2, 0 +.endm diff --git a/tests/xtensa/test_b.S b/tests/xtensa/test_b.S new file mode 100644 index 0000000000..6cbe5f1fca --- /dev/null +++ b/tests/xtensa/test_b.S @@ -0,0 +1,221 @@ +.include "macros.inc" + +test_suite b + +test bnone + movi a2, 0xa5a5ff00 + movi a3, 0x5a5a00ff + bnone a2, a3, 1f + test_fail +1: + movi a2, 0xa5a5ff01 + bnone a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test beq + movi a2, 0 + movi a3, 0 + beq a2, a3, 1f + test_fail +1: + movi a2, 1 + beq a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test blt + movi a2, 6 + movi a3, 7 + blt a2, a3, 1f + test_fail +1: + movi a2, 0xffffffff + blt a2, a3, 1f + test_fail +1: + movi a2, 7 + blt a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bltu + movi a2, 6 + movi a3, 7 + bltu a2, a3, 1f + test_fail +1: + movi a2, 7 + bltu a2, a3, 1f + j 2f +1: + test_fail +2: + movi a2, 0xffffffff + bltu a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test ball + movi a2, 0xa5a5ffa5 + movi a3, 0xa5a5ff00 + ball a2, a3, 1f + test_fail +1: + movi a2, 0xa5a5a5a5 + ball a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bbc + movi a2, 0xfffffffd + movi a3, 0xffffff01 + bbc a2, a3, 1f + test_fail +1: + movi a2, 8 + movi a3, 0xffffff03 + bbc a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bbci + movi a2, 0xfffdffff + bbci a2, 17, 1f + test_fail +1: + movi a2, 0x00020000 + bbci a2, 17, 1f + j 2f +1: + test_fail +2: +test_end + +test bany + movi a2, 0xa5a5ff01 + movi a3, 0x5a5a00ff + bany a2, a3, 1f + test_fail +1: + movi a2, 0xa5a5ff00 + bany a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bne + movi a2, 1 + movi a3, 0 + bne a2, a3, 1f + test_fail +1: + movi a2, 0 + bne a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bge + movi a2, 7 + movi a3, 7 + bge a2, a3, 1f + test_fail +1: + movi a2, 6 + bge a2, a3, 1f + j 2f +1: + test_fail +2: + movi a2, 0xffffffff + bge a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bgeu + movi a2, 7 + movi a3, 7 + bgeu a2, a3, 1f + test_fail +1: + movi a2, 0xffffffff + bgeu a2, a3, 1f + test_fail +1: + movi a2, 6 + bgeu a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bnall + movi a2, 0xa5a5a5a5 + movi a3, 0xa5a5ff00 + bnall a2, a3, 1f + test_fail +1: + movi a2, 0xa5a5ffa5 + bnall a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bbs + movi a2, 8 + movi a3, 0xffffff03 + bbs a2, a3, 1f + test_fail +1: + movi a2, 0xfffffffd + movi a3, 0xffffff01 + bbs a2, a3, 1f + j 2f +1: + test_fail +2: +test_end + +test bbsi + movi a2, 0x00020000 + bbsi a2, 17, 1f + test_fail +1: + movi a2, 0xfffdffff + bbsi a2, 17, 1f + j 2f +1: + test_fail +2: +test_end + +test_suite_end diff --git a/tests/xtensa/test_bi.S b/tests/xtensa/test_bi.S new file mode 100644 index 0000000000..6a5f1dffc9 --- /dev/null +++ b/tests/xtensa/test_bi.S @@ -0,0 +1,103 @@ +.include "macros.inc" + +test_suite bi + +test beqi + movi a2, 7 + beqi a2, 7, 1f + test_fail +1: + movi a2, 1 + beqi a2, 7, 1f + j 2f +1: + test_fail +2: +test_end + +test bnei + movi a2, 1 + bnei a2, 7, 1f + test_fail +1: + movi a2, 7 + bnei a2, 7, 1f + j 2f +1: + test_fail +2: +test_end + +test blti + movi a2, 6 + blti a2, 7, 1f + test_fail +1: + movi a2, 0xffffffff + blti a2, 7, 1f + test_fail +1: + movi a2, 7 + blti a2, 7, 1f + j 2f +1: + test_fail +2: +test_end + +test bgei + movi a2, 7 + bgei a2, 7, 1f + test_fail +1: + movi a2, 6 + bgei a2, 7, 1f + j 2f +1: + test_fail +2: + movi a2, 0xffffffff + bgei a2, 7, 1f + j 2f +1: + test_fail +2: +test_end + +test bltui + movi a2, 6 + bltui a2, 7, 1f + test_fail +1: + movi a2, 7 + bltui a2, 7, 1f + j 2f +1: + test_fail +2: + movi a2, 0xffffffff + bltui a2, 7, 1f + j 2f +1: + test_fail +2: +test_end + +test bgeui + movi a2, 7 + bgeui a2, 7, 1f + test_fail +1: + movi a2, 0xffffffff + bgeui a2, 7, 1f + test_fail +1: + movi a2, 6 + bgeui a2, 7, 1f + j 2f +1: + test_fail +2: +test_end + +test_suite_end diff --git a/tests/xtensa/test_boolean.S b/tests/xtensa/test_boolean.S new file mode 100644 index 0000000000..50e6d2c22a --- /dev/null +++ b/tests/xtensa/test_boolean.S @@ -0,0 +1,23 @@ +.include "macros.inc" + +test_suite boolean + +test all4 + movi a2, 0xfec0 + wsr a2, br + all4 b0, b0 + rsr a3, br + assert eq, a2, a3 + all4 b0, b4 + rsr a3, br + assert eq, a2, a3 + all4 b0, b8 + rsr a3, br + assert eq, a2, a3 + all4 b0, b12 + rsr a3, br + addi a2, a2, 1 + assert eq, a2, a3 +test_end + +test_suite_end diff --git a/tests/xtensa/test_bz.S b/tests/xtensa/test_bz.S new file mode 100644 index 0000000000..f9ba6e22e8 --- /dev/null +++ b/tests/xtensa/test_bz.S @@ -0,0 +1,57 @@ +.include "macros.inc" + +test_suite bz + +test beqz + movi a2, 0 + _beqz a2, 1f + test_fail +1: + movi a2, 1 + _beqz a2, 1f + j 2f +1: + test_fail +2: +test_end + +test bnez + movi a2, 1 + _bnez a2, 1f + test_fail +1: + movi a2, 0 + _bnez a2, 1f + j 2f +1: + test_fail +2: +test_end + +test bltz + movi a2, 0xffffffff + bltz a2, 1f + test_fail +1: + movi a2, 0 + bltz a2, 1f + j 2f +1: + test_fail +2: +test_end + +test bgez + movi a2, 0 + bgez a2, 1f + test_fail +1: + movi a2, 0xffffffff + bgez a2, 1f + j 2f +1: + test_fail +2: +test_end + +test_suite_end diff --git a/tests/xtensa/test_clamps.S b/tests/xtensa/test_clamps.S new file mode 100644 index 0000000000..c186cc98d8 --- /dev/null +++ b/tests/xtensa/test_clamps.S @@ -0,0 +1,42 @@ +.include "macros.inc" + +test_suite clamps + +test clamps + movi a2, 0 + movi a3, 0 + clamps a4, a2, 7 + assert eq, a3, a4 + + movi a2, 0x7f + movi a3, 0x7f + clamps a4, a2, 7 + assert eq, a3, a4 + + movi a2, 0xffffff80 + movi a3, 0xffffff80 + clamps a4, a2, 7 + assert eq, a3, a4 + + movi a2, 0x80 + movi a3, 0x7f + clamps a2, a2, 7 + assert eq, a3, a2 + + movi a2, 0xffffff7f + movi a3, 0xffffff80 + clamps a2, a2, 7 + assert eq, a3, a2 + + movi a2, 0x7fffffff + movi a3, 0x7f + clamps a2, a2, 7 + assert eq, a3, a2 + + movi a2, 0x80000000 + movi a3, 0xffffff80 + clamps a2, a2, 7 + assert eq, a3, a2 +test_end + +test_suite_end diff --git a/tests/xtensa/test_fail.S b/tests/xtensa/test_fail.S new file mode 100644 index 0000000000..e8d1b425bc --- /dev/null +++ b/tests/xtensa/test_fail.S @@ -0,0 +1,9 @@ +.include "macros.inc" + +test_suite fail + +test fail + test_fail +test_end + +test_suite_end diff --git a/tests/xtensa/test_interrupt.S b/tests/xtensa/test_interrupt.S new file mode 100644 index 0000000000..68b3ee1492 --- /dev/null +++ b/tests/xtensa/test_interrupt.S @@ -0,0 +1,194 @@ +.include "macros.inc" + +test_suite interrupt + +.macro clear_interrupts + movi a2, 0 + wsr a2, intenable + wsr a2, ccompare0 + wsr a2, ccompare1 + wsr a2, ccompare2 + esync + rsr a2, interrupt + wsr a2, intclear + + esync + rsr a2, interrupt + assert eqi, a2, 0 +.endm + +.macro check_l1 + rsr a2, ps + movi a3, 0x1f /* EXCM | INTMASK */ + and a2, a2, a3 + assert eqi, a2, 0x10 /* only EXCM is set for level-1 interrupt */ + rsr a2, exccause + assert eqi, a2, 4 +.endm + +test rsil + clear_interrupts + + rsr a2, ps + rsil a3, 7 + rsr a4, ps + assert eq, a2, a3 + movi a2, 0xf + and a2, a4, a2 + assert eqi, a2, 7 + xor a3, a3, a4 + movi a2, 0xfffffff0 + and a2, a3, a2 + assert eqi, a2, 0 +test_end + +test soft_disabled + set_vector kernel, 1f + clear_interrupts + + movi a2, 0x80 + wsr a2, intset + esync + rsr a3, interrupt + assert eq, a2, a3 + wsr a2, intclear + esync + rsr a3, interrupt + assert eqi, a3, 0 + j 2f +1: + test_fail +2: +test_end + +test soft_intenable + set_vector kernel, 1f + clear_interrupts + + movi a2, 0x80 + wsr a2, intset + esync + rsr a3, interrupt + assert eq, a2, a3 + rsil a3, 0 + wsr a2, intenable + esync + test_fail +1: + check_l1 +test_end + +test soft_rsil + set_vector kernel, 1f + clear_interrupts + + movi a2, 0x80 + wsr a2, intset + esync + rsr a3, interrupt + assert eq, a2, a3 + wsr a2, intenable + rsil a3, 0 + esync + test_fail +1: + check_l1 +test_end + +test soft_waiti + set_vector kernel, 1f + clear_interrupts + + movi a2, 0x80 + wsr a2, intset + esync + rsr a3, interrupt + assert eq, a2, a3 + wsr a2, intenable + waiti 0 + test_fail +1: + check_l1 +test_end + +test soft_user + set_vector kernel, 1f + set_vector user, 2f + clear_interrupts + + movi a2, 0x80 + wsr a2, intset + esync + rsr a3, interrupt + assert eq, a2, a3 + wsr a2, intenable + + rsr a2, ps + movi a3, 0x20 + or a2, a2, a3 + wsr a2, ps + waiti 0 +1: + test_fail +2: + check_l1 +test_end + +test soft_priority + set_vector kernel, 1f + set_vector level3, 2f + clear_interrupts + + movi a2, 0x880 + wsr a2, intenable + rsil a3, 0 + esync + wsr a2, intset + esync +1: + test_fail +2: + rsr a2, ps + movi a3, 0x1f /* EXCM | INTMASK */ + and a2, a2, a3 + movi a3, 0x13 + assert eq, a2, a3 /* EXCM and INTMASK are set + for high-priority interrupt */ +test_end + +test eps_epc_rfi + set_vector level3, 3f + clear_interrupts + reset_ps + + movi a2, 0x880 + wsr a2, intenable + rsil a3, 0 + rsr a3, ps + esync + wsr a2, intset +1: + esync +2: + test_fail +3: + rsr a2, eps3 + assert eq, a2, a3 + rsr a2, epc3 + movi a3, 1b + assert ge, a2, a3 + movi a3, 2b + assert ge, a3, a2 + movi a2, 4f + wsr a2, epc3 + movi a2, 0x40003 + wsr a2, eps3 + rfi 3 + test_fail +4: + rsr a2, ps + movi a3, 0x40003 + assert eq, a2, a3 +test_end + +test_suite_end diff --git a/tests/xtensa/test_loop.S b/tests/xtensa/test_loop.S new file mode 100644 index 0000000000..a5ea933913 --- /dev/null +++ b/tests/xtensa/test_loop.S @@ -0,0 +1,77 @@ +.include "macros.inc" + +test_suite loop + +test loop + movi a2, 0 + movi a3, 5 + loop a3, 1f + addi a2, a2, 1 +1: + assert eqi, a2, 5 +test_end + +test loop0 + movi a2, 0 + loop a2, 1f + rsr a2, lcount + assert eqi, a2, -1 + j 1f +1: +test_end + +test loop_jump + movi a2, 0 + movi a3, 5 + loop a3, 1f + addi a2, a2, 1 + j 1f +1: + assert eqi, a2, 1 +test_end + +test loop_branch + movi a2, 0 + movi a3, 5 + loop a3, 1f + addi a2, a2, 1 + beqi a2, 3, 1f +1: + assert eqi, a2, 3 +test_end + +test loop_manual + movi a2, 0 + movi a3, 5 + movi a4, 1f + movi a5, 2f + wsr a3, lcount + wsr a4, lbeg + wsr a5, lend + isync + j 1f +.align 4 +1: + addi a2, a2, 1 +2: + assert eqi, a2, 6 +test_end + +test loop_excm + movi a2, 0 + movi a3, 5 + rsr a4, ps + movi a5, 0x10 + or a4, a4, a5 + wsr a4, ps + isync + loop a3, 1f + addi a2, a2, 1 +1: + xor a4, a4, a5 + isync + wsr a4, ps + assert eqi, a2, 1 +test_end + +test_suite_end diff --git a/tests/xtensa/test_max.S b/tests/xtensa/test_max.S new file mode 100644 index 0000000000..2534c9d90b --- /dev/null +++ b/tests/xtensa/test_max.S @@ -0,0 +1,81 @@ +.include "macros.inc" + +test_suite max + +test max + movi a2, 0xffffffff + movi a3, 1 + movi a4, 1 + max a5, a2, a3 + assert eq, a5, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 1 + max a5, a2, a3 + assert eq, a5, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 1 + max a2, a2, a3 + assert eq, a2, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 1 + max a3, a2, a3 + assert eq, a3, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 1 + max a2, a2, a3 + assert eq, a2, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 1 + max a3, a2, a3 + assert eq, a3, a4 +test_end + +test maxu + movi a2, 0xffffffff + movi a3, 1 + movi a4, 0xffffffff + maxu a5, a2, a3 + assert eq, a5, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 0xffffffff + maxu a5, a2, a3 + assert eq, a5, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 0xffffffff + maxu a2, a2, a3 + assert eq, a2, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 0xffffffff + maxu a3, a2, a3 + assert eq, a3, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 0xffffffff + maxu a2, a2, a3 + assert eq, a2, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 0xffffffff + maxu a3, a2, a3 + assert eq, a3, a4 +test_end + +test_suite_end diff --git a/tests/xtensa/test_min.S b/tests/xtensa/test_min.S new file mode 100644 index 0000000000..6d9ddeb1ac --- /dev/null +++ b/tests/xtensa/test_min.S @@ -0,0 +1,81 @@ +.include "macros.inc" + +test_suite min + +test min + movi a2, 0xffffffff + movi a3, 1 + movi a4, 0xffffffff + min a5, a2, a3 + assert eq, a5, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 0xffffffff + min a5, a2, a3 + assert eq, a5, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 0xffffffff + min a2, a2, a3 + assert eq, a2, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 0xffffffff + min a3, a2, a3 + assert eq, a3, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 0xffffffff + min a2, a2, a3 + assert eq, a2, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 0xffffffff + min a3, a2, a3 + assert eq, a3, a4 +test_end + +test minu + movi a2, 0xffffffff + movi a3, 1 + movi a4, 1 + minu a5, a2, a3 + assert eq, a5, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 1 + minu a5, a2, a3 + assert eq, a5, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 1 + minu a2, a2, a3 + assert eq, a2, a4 + + movi a2, 0xffffffff + movi a3, 1 + movi a4, 1 + minu a3, a2, a3 + assert eq, a3, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 1 + minu a2, a2, a3 + assert eq, a2, a4 + + movi a2, 1 + movi a3, 0xffffffff + movi a4, 1 + minu a3, a2, a3 + assert eq, a3, a4 +test_end + +test_suite_end diff --git a/tests/xtensa/test_mmu.S b/tests/xtensa/test_mmu.S new file mode 100644 index 0000000000..52d5774212 --- /dev/null +++ b/tests/xtensa/test_mmu.S @@ -0,0 +1,318 @@ +.include "macros.inc" + +test_suite mmu + +.purgem test + +.macro test name + movi a2, 0x00000004 + idtlb a2 + movi a2, 0x00100004 + idtlb a2 + movi a2, 0x00200004 + idtlb a2 + movi a2, 0x00300004 + idtlb a2 + movi a2, 0x00000007 + idtlb a2 +.endm + +test tlb_group + movi a2, 0x04000002 /* PPN */ + movi a3, 0x01200004 /* VPN */ + wdtlb a2, a3 + witlb a2, a3 + movi a3, 0x00200004 + rdtlb0 a1, a3 + ritlb0 a2, a3 + movi a3, 0x01000001 + assert eq, a1, a3 + assert eq, a2, a3 + movi a3, 0x00200004 + rdtlb1 a1, a3 + ritlb1 a2, a3 + movi a3, 0x04000002 + assert eq, a1, a3 + assert eq, a2, a3 + movi a3, 0x01234567 + pdtlb a1, a3 + pitlb a2, a3 + movi a3, 0x01234014 + assert eq, a1, a3 + movi a3, 0x0123400c + assert eq, a2, a3 + movi a3, 0x00200004 + idtlb a3 + iitlb a3 + movi a3, 0x01234567 + pdtlb a1, a3 + pitlb a2, a3 + movi a3, 0x00000010 + and a1, a1, a3 + assert eqi, a1, 0 + movi a3, 0x00000008 + and a2, a2, a3 + assert eqi, a2, 0 +test_end + +test itlb_miss + set_vector kernel, 1f + + movi a3, 0x00100000 + jx a3 + test_fail +1: + rsr a2, excvaddr + assert eq, a2, a3 + rsr a2, exccause + movi a3, 16 + assert eq, a2, a3 +test_end + +test dtlb_miss + set_vector kernel, 1f + + movi a3, 0x00100000 + l8ui a2, a3, 0 + test_fail +1: + rsr a2, excvaddr + assert eq, a2, a3 + rsr a2, exccause + movi a3, 24 + assert eq, a2, a3 +test_end + +test itlb_multi_hit + set_vector kernel, 1f + + movi a2, 0x04000002 /* PPN */ + movi a3, 0xf0000004 /* VPN */ + witlb a2, a3 + movi a3, 0xf0000000 + pitlb a2, a3 + test_fail +1: + rsr a2, exccause + movi a3, 17 + assert eq, a2, a3 +test_end + +test dtlb_multi_hit + set_vector kernel, 1f + + movi a2, 0x04000002 /* PPN */ + movi a3, 0x01200004 /* VPN */ + wdtlb a2, a3 + movi a3, 0x01200007 /* VPN */ + wdtlb a2, a3 + movi a3, 0x01200000 + pdtlb a2, a3 + test_fail +1: + rsr a2, exccause + movi a3, 25 + assert eq, a2, a3 +test_end + +test inst_fetch_privilege + set_vector kernel, 3f + + movi a2, 0x4004f + wsr a2, ps +1: + isync + nop +2: + test_fail +3: + movi a1, 1b + rsr a2, excvaddr + rsr a3, epc1 + assert ge, a2, a1 + assert ge, a3, a1 + movi a1, 2b + assert lt, a2, a1 + assert lt, a3, a1 + rsr a2, exccause + movi a3, 18 + assert eq, a2, a3 + rsr a2, ps + movi a3, 0x4005f + assert eq, a2, a3 +test_end + +test load_store_privilege + set_vector kernel, 2f + + movi a3, 10f + pitlb a3, a3 + ritlb1 a2, a3 + movi a1, 0x10 + or a2, a2, a1 + movi a1, 0x000ff000 + and a3, a3, a1 + movi a1, 4 + or a3, a3, a1 + witlb a2, a3 + movi a3, 10f + movi a1, 0x000fffff + and a1, a3, a1 + + movi a2, 0x04000003 /* PPN */ + movi a3, 0x01200004 /* VPN */ + wdtlb a2, a3 + movi a3, 0x01200001 + movi a2, 0x4004f + jx a1 +10: + wsr a2, ps + isync +1: + l8ui a2, a3, 0 + test_fail +2: + rsr a2, excvaddr + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 1b + movi a1, 0x000fffff + and a3, a3, a1 + assert eq, a2, a3 + rsr a2, exccause + movi a3, 26 + assert eq, a2, a3 + rsr a2, ps + movi a3, 0x4005f + assert eq, a2, a3 +test_end + +test cring_load_store_privilege + set_vector kernel, 0 + set_vector double, 2f + + movi a2, 0x04000003 /* PPN */ + movi a3, 0x01200004 /* VPN */ + wdtlb a2, a3 + movi a3, 0x01200004 + movi a2, 0x4005f /* ring 1 + excm => cring == 0 */ + wsr a2, ps + isync + l8ui a2, a3, 0 /* cring used */ +1: + l32e a2, a3, -4 /* ring used */ + test_fail +2: + rsr a2, excvaddr + addi a2, a2, 4 + assert eq, a2, a3 + rsr a2, depc + movi a3, 1b + assert eq, a2, a3 + rsr a2, exccause + movi a3, 26 + assert eq, a2, a3 + rsr a2, ps + movi a3, 0x4005f + assert eq, a2, a3 +test_end + +test inst_fetch_prohibited + set_vector kernel, 2f + + movi a3, 10f + pitlb a3, a3 + ritlb1 a2, a3 + movi a1, 0xfffff000 + and a2, a2, a1 + movi a1, 0x4 + or a2, a2, a1 + movi a1, 0x000ff000 + and a3, a3, a1 + movi a1, 4 + or a3, a3, a1 + witlb a2, a3 + movi a3, 10f + movi a1, 0x000fffff + and a1, a3, a1 + jx a1 + .align 4 +10: + nop + test_fail +2: + rsr a2, excvaddr + assert eq, a2, a1 + rsr a2, epc1 + assert eq, a2, a1 + rsr a2, exccause + movi a3, 20 + assert eq, a2, a3 +test_end + +test load_prohibited + set_vector kernel, 2f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x01200004 /* VPN */ + wdtlb a2, a3 + movi a3, 0x01200002 +1: + l8ui a2, a3, 0 + test_fail +2: + rsr a2, excvaddr + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 + rsr a2, exccause + movi a3, 28 + assert eq, a2, a3 +test_end + +test store_prohibited + set_vector kernel, 2f + + movi a2, 0x04000001 /* PPN */ + movi a3, 0x01200004 /* VPN */ + wdtlb a2, a3 + movi a3, 0x01200003 + l8ui a2, a3, 0 +1: + s8i a2, a3, 0 + test_fail +2: + rsr a2, excvaddr + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 + rsr a2, exccause + movi a3, 29 + assert eq, a2, a3 +test_end + +test dtlb_autoload + set_vector kernel, 0 + + movi a2, 0xd4000000 + wsr a2, ptevaddr + movi a3, 0x00001013 + s32i a3, a2, 4 + pdtlb a2, a3 + movi a1, 0x10 + and a1, a1, a2 + assert eqi, a1, 0 + l8ui a1, a3, 0 + pdtlb a2, a3 + movi a1, 0xfffff010 + and a1, a1, a2 + movi a3, 0x00001010 + assert eq, a1, a3 + movi a1, 0xf + and a1, a1, a2 + assert lti, a1, 4 +test_end + +test_suite_end diff --git a/tests/xtensa/test_mul16.S b/tests/xtensa/test_mul16.S new file mode 100644 index 0000000000..bf94376649 --- /dev/null +++ b/tests/xtensa/test_mul16.S @@ -0,0 +1,83 @@ +.include "macros.inc" + +test_suite mul16 + +test mul16u_pp + movi a2, 0x137f5a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x06e180a6 + mul16u a5, a2, a4 + assert eq, a5, a6 + mul16u a2, a2, a4 + assert eq, a2, a6 + mul16u a3, a4, a3 + assert eq, a3, a6 +test_end + +test mul16u_np + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x0c9d6bdb + mul16u a5, a2, a4 + assert eq, a5, a6 + mul16u a2, a2, a4 + assert eq, a2, a6 + mul16u a3, a4, a3 + assert eq, a3, a6 +test_end + +test mul16u_nn + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5f731 + movi a6, 0x9ff1e795 + mul16u a5, a2, a4 + assert eq, a5, a6 + mul16u a2, a2, a4 + assert eq, a2, a6 + mul16u a3, a4, a3 + assert eq, a3, a6 +test_end + +test mul16s_pp + movi a2, 0x137f5a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x06e180a6 + mul16s a5, a2, a4 + assert eq, a5, a6 + mul16s a2, a2, a4 + assert eq, a2, a6 + mul16s a3, a4, a3 + assert eq, a3, a6 +test_end + +test mul16s_np + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xf91e6bdb + mul16s a5, a2, a4 + assert eq, a5, a6 + mul16s a2, a2, a4 + assert eq, a2, a6 + mul16s a3, a4, a3 + assert eq, a3, a6 +test_end + +test mul16s_nn + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5f731 + movi a6, 0x031be795 + mul16s a5, a2, a4 + assert eq, a5, a6 + mul16s a2, a2, a4 + assert eq, a2, a6 + mul16s a3, a4, a3 + assert eq, a3, a6 +test_end + +test_suite_end diff --git a/tests/xtensa/test_mul32.S b/tests/xtensa/test_mul32.S new file mode 100644 index 0000000000..fdaf57331b --- /dev/null +++ b/tests/xtensa/test_mul32.S @@ -0,0 +1,20 @@ +.include "macros.inc" + +test_suite mul32 + +test mull + movi a2, 0x137f5a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x5de480a6 + mull a5, a2, a4 + assert eq, a5, a6 + mull a2, a2, a4 + assert eq, a2, a6 + mull a3, a4, a3 + assert eq, a3, a6 +test_end + +/* unfortunately dc232b doesn't have muluh/mulsh*/ + +test_suite_end diff --git a/tests/xtensa/test_nsa.S b/tests/xtensa/test_nsa.S new file mode 100644 index 0000000000..a5fe5debe4 --- /dev/null +++ b/tests/xtensa/test_nsa.S @@ -0,0 +1,59 @@ +.include "macros.inc" + +test_suite nsa + +test nsa + movi a2, 0 + movi a3, 31 + nsa a4, a2 + assert eq, a3, a4 + + movi a2, 0xffffffff + movi a3, 31 + nsa a4, a2 + assert eq, a3, a4 + + movi a2, 1 + movi a3, 30 + nsa a2, a2 + assert eq, a3, a2 + + movi a2, 0xfffffffe + movi a3, 30 + nsa a2, a2 + assert eq, a3, a2 + + movi a2, 0x5a5a5a5a + movi a3, 0 + nsa a4, a2 + assert eq, a3, a4 + + movi a2, 0xa5a5a5a5 + movi a3, 0 + nsa a4, a2 + assert eq, a3, a4 +test_end + +test nsau + movi a2, 0 + movi a3, 32 + nsau a4, a2 + assert eq, a3, a4 + + movi a2, 0xffffffff + movi a3, 0 + nsau a4, a2 + assert eq, a3, a4 + + movi a2, 1 + movi a3, 31 + nsau a2, a2 + assert eq, a3, a2 + + movi a2, 0x5a5a5a5a + movi a3, 1 + nsau a2, a2 + assert eq, a3, a2 +test_end + +test_suite_end diff --git a/tests/xtensa/test_pipeline.S b/tests/xtensa/test_pipeline.S new file mode 100644 index 0000000000..6be6085fc3 --- /dev/null +++ b/tests/xtensa/test_pipeline.S @@ -0,0 +1,157 @@ +.include "macros.inc" + +.purgem test +.macro test name + movi a2, 1f + movi a3, 99f +0: + ipf a2, 0 + ipf a2, 4 + ipf a2, 8 + ipf a2, 12 + addi a2, a2, 16 + blt a2, a3, 0b + j 1f + .align 4 +1: +.endm + +test_suite pipeline + +test register_no_stall + rsr a3, ccount + add a5, a6, a6 + add a6, a5, a5 + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 3 +test_end + +test register_stall + l32i a5, a1, 0 /* data cache preload */ + nop + rsr a3, ccount + l32i a5, a1, 0 + add a6, a5, a5 /* M-to-E interlock */ + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 4 +test_end + +test j0_stall + rsr a3, ccount + j 1f /* E + 2-cycle penalty */ +1: + rsr a4, ccount /* E */ + sub a3, a4, a3 + assert eqi, a3, 4 +test_end + +test j1_stall + rsr a3, ccount + j 1f + nop +1: + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 4 +test_end + +test j5_stall + rsr a3, ccount + j 1f + nop + nop + nop + nop + nop +1: + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 4 +test_end + +test b_no_stall + movi a5, 1 + rsr a3, ccount + beqi a5, 2, 1f + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 2 +1: +test_end + +test b1_stall + movi a5, 1 + rsr a3, ccount + beqi a5, 1, 1f + nop +1: + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 4 +test_end + +test b5_stall + movi a5, 1 + rsr a3, ccount + beqi a5, 1, 1f + nop + nop + nop + nop + nop +1: + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 4 +test_end + +/* PS *SYNC */ + +test ps_dsync + rsr a5, ps + isync + rsr a3, ccount + wsr a5, ps + dsync + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 5 +test_end + +test ps_esync + rsr a5, ps + isync + rsr a3, ccount + wsr a5, ps + esync + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 5 +test_end + +test ps_rsync + rsr a5, ps + isync + rsr a3, ccount + wsr a5, ps + rsync + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 5 +test_end + +test ps_isync + rsr a5, ps + isync + rsr a3, ccount + wsr a5, ps + isync + rsr a4, ccount + sub a3, a4, a3 + movi a4, 9 + assert eq, a3, a4 +test_end + +test_suite_end diff --git a/tests/xtensa/test_quo.S b/tests/xtensa/test_quo.S new file mode 100644 index 0000000000..12debf1fe0 --- /dev/null +++ b/tests/xtensa/test_quo.S @@ -0,0 +1,147 @@ +.include "macros.inc" + +test_suite quo + +test quou_pp + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0x4 + quou a5, a2, a4 + assert eq, a5, a6 + quou a2, a2, a4 + assert eq, a2, a6 + quou a4, a3, a4 + assert eq, a4, a6 +test_end + +test quou_np + movi a2, 0xa5a5137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0x8 + quou a5, a2, a4 + assert eq, a5, a6 + quou a2, a2, a4 + assert eq, a2, a6 + quou a4, a3, a4 + assert eq, a4, a6 +test_end + +test quou_pn + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0xf7315a5a + movi a6, 0 + quou a5, a2, a4 + assert eq, a5, a6 + quou a2, a2, a4 + assert eq, a2, a6 + quou a4, a3, a4 + assert eq, a4, a6 +test_end + +test quou_nn + movi a2, 0xf7315a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x1 + quou a5, a2, a4 + assert eq, a5, a6 + quou a2, a2, a4 + assert eq, a2, a6 + quou a4, a3, a4 + assert eq, a4, a6 +test_end + +test quou_exc + set_vector kernel, 2f + movi a2, 0xf7315a5a + movi a4, 0x00000000 +1: + quou a5, a2, a4 + test_fail +2: + rsr a2, exccause + assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 +test_end + +test quos_pp + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0x4 + quos a5, a2, a4 + assert eq, a5, a6 + quos a2, a2, a4 + assert eq, a2, a6 + quos a4, a3, a4 + assert eq, a4, a6 +test_end + +test quos_np + movi a2, 0xa5a5137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0xfffffffc + quos a5, a2, a4 + assert eq, a5, a6 + quos a2, a2, a4 + assert eq, a2, a6 + quos a4, a3, a4 + assert eq, a4, a6 +test_end + +test quos_pn + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0xf7315a5a + movi a6, 0xfffffff6 + quos a5, a2, a4 + assert eq, a5, a6 + quos a2, a2, a4 + assert eq, a2, a6 + quos a4, a3, a4 + assert eq, a4, a6 +test_end + +test quos_nn + movi a2, 0xf7315a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0 + quos a5, a2, a4 + assert eq, a5, a6 + quos a2, a2, a4 + assert eq, a2, a6 + quos a4, a3, a4 + assert eq, a4, a6 +test_end + +test quos_over + movi a2, 0x80000000 + movi a4, 0xffffffff + movi a6, 0x80000000 + quos a5, a2, a4 + assert eq, a5, a6 +test_end + +test quos_exc + set_vector kernel, 2f + movi a2, 0xf7315a5a + movi a4, 0x00000000 +1: + quos a5, a2, a4 + test_fail +2: + rsr a2, exccause + assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 +test_end + +test_suite_end diff --git a/tests/xtensa/test_rem.S b/tests/xtensa/test_rem.S new file mode 100644 index 0000000000..bb0d5fe202 --- /dev/null +++ b/tests/xtensa/test_rem.S @@ -0,0 +1,147 @@ +.include "macros.inc" + +test_suite rem + +test remu_pp + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0x0c5caa17 + remu a5, a2, a4 + assert eq, a5, a6 + remu a2, a2, a4 + assert eq, a2, a6 + remu a4, a3, a4 + assert eq, a4, a6 +test_end + +test remu_np + movi a2, 0xa5a5137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0x9aa40af + remu a5, a2, a4 + assert eq, a5, a6 + remu a2, a2, a4 + assert eq, a2, a6 + remu a4, a3, a4 + assert eq, a4, a6 +test_end + +test remu_pn + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0xf7315a5a + movi a6, 0x5a5a137f + remu a5, a2, a4 + assert eq, a5, a6 + remu a2, a2, a4 + assert eq, a2, a6 + remu a4, a3, a4 + assert eq, a4, a6 +test_end + +test remu_nn + movi a2, 0xf7315a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x518c46db + remu a5, a2, a4 + assert eq, a5, a6 + remu a2, a2, a4 + assert eq, a2, a6 + remu a4, a3, a4 + assert eq, a4, a6 +test_end + +test remu_exc + set_vector kernel, 2f + movi a2, 0xf7315a5a + movi a4, 0x00000000 +1: + remu a5, a2, a4 + test_fail +2: + rsr a2, exccause + assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 +test_end + +test rems_pp + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0x0c5caa17 + rems a5, a2, a4 + assert eq, a5, a6 + rems a2, a2, a4 + assert eq, a2, a6 + rems a4, a3, a4 + assert eq, a4, a6 +test_end + +test rems_np + movi a2, 0xa5a5137f + mov a3, a2 + movi a4, 0x137f5a5a + movi a6, 0xf3a27ce7 + rems a5, a2, a4 + assert eq, a5, a6 + rems a2, a2, a4 + assert eq, a2, a6 + rems a4, a3, a4 + assert eq, a4, a6 +test_end + +test rems_pn + movi a2, 0x5a5a137f + mov a3, a2 + movi a4, 0xf7315a5a + movi a6, 0x02479b03 + rems a5, a2, a4 + assert eq, a5, a6 + rems a2, a2, a4 + assert eq, a2, a6 + rems a4, a3, a4 + assert eq, a4, a6 +test_end + +test rems_nn + movi a2, 0xf7315a5a + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xf7315a5a + rems a5, a2, a4 + assert eq, a5, a6 + rems a2, a2, a4 + assert eq, a2, a6 + rems a4, a3, a4 + assert eq, a4, a6 +test_end + +test rems_over + movi a2, 0x80000000 + movi a4, 0xffffffff + movi a6, 0 + rems a5, a2, a4 + assert eq, a5, a6 +test_end + +test rems_exc + set_vector kernel, 2f + movi a2, 0xf7315a5a + movi a4, 0x00000000 +1: + rems a5, a2, a4 + test_fail +2: + rsr a2, exccause + assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 +test_end + +test_suite_end diff --git a/tests/xtensa/test_rst0.S b/tests/xtensa/test_rst0.S new file mode 100644 index 0000000000..3eda565e8a --- /dev/null +++ b/tests/xtensa/test_rst0.S @@ -0,0 +1,148 @@ +.include "macros.inc" + +test_suite rst0 + +test and + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x01250125 + and a5, a2, a4 + assert eq, a5, a6 + and a2, a2, a4 + assert eq, a2, a6 + and a3, a4, a3 + assert eq, a3, a6 +test_end + +test or + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xb7ffb7ff + or a5, a2, a4 + assert eq, a5, a6 + or a2, a2, a4 + assert eq, a2, a6 + or a3, a4, a3 + assert eq, a3, a6 +test_end + +test xor + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xb6dab6da + xor a5, a2, a4 + assert eq, a5, a6 + xor a2, a2, a4 + assert eq, a2, a6 + xor a3, a4, a3 + assert eq, a3, a6 +test_end + +test add + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xb924b924 + add a5, a2, a4 + assert eq, a5, a6 + add a2, a2, a4 + assert eq, a2, a6 + add a4, a3, a4 + assert eq, a4, a6 +test_end + +test addx2 + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xcca45ec9 + addx2 a5, a2, a4 + assert eq, a5, a6 + addx2 a2, a2, a4 + assert eq, a2, a6 + addx2 a4, a3, a4 + assert eq, a4, a6 +test_end + +test addx4 + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xf3a3aa13 + addx4 a5, a2, a4 + assert eq, a5, a6 + addx4 a2, a2, a4 + assert eq, a2, a6 + addx4 a4, a3, a4 + assert eq, a4, a6 +test_end + +test addx8 + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x41a240a7 + addx8 a5, a2, a4 + assert eq, a5, a6 + addx8 a2, a2, a4 + assert eq, a2, a6 + addx8 a4, a3, a4 + assert eq, a4, a6 +test_end + +test sub + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x6dda9226 + sub a5, a2, a4 + assert eq, a5, a6 + sub a2, a2, a4 + assert eq, a2, a6 + sub a4, a3, a4 + assert eq, a4, a6 +test_end + +test subx2 + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0x815a37cb + subx2 a5, a2, a4 + assert eq, a5, a6 + subx2 a2, a2, a4 + assert eq, a2, a6 + subx2 a4, a3, a4 + assert eq, a4, a6 +test_end + +test subx4 + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xa8598315 + subx4 a5, a2, a4 + assert eq, a5, a6 + subx4 a2, a2, a4 + assert eq, a2, a6 + subx4 a4, a3, a4 + assert eq, a4, a6 +test_end + +test subx8 + movi a2, 0x137fa5a5 + mov a3, a2 + movi a4, 0xa5a5137f + movi a6, 0xf65819a9 + subx8 a5, a2, a4 + assert eq, a5, a6 + subx8 a2, a2, a4 + assert eq, a2, a6 + subx8 a4, a3, a4 + assert eq, a4, a6 +test_end + +test_suite_end diff --git a/tests/xtensa/test_sar.S b/tests/xtensa/test_sar.S new file mode 100644 index 0000000000..40c649ffb8 --- /dev/null +++ b/tests/xtensa/test_sar.S @@ -0,0 +1,111 @@ +.include "macros.inc" + +test_suite sar + +.macro test_sar prefix, imm + \prefix\()_set \imm + \prefix\()_ver \imm +.endm + +.macro tests_sar prefix + test_sar \prefix, 0 + test_sar \prefix, 1 + test_sar \prefix, 2 + test_sar \prefix, 3 + test_sar \prefix, 0x1f + test_sar \prefix, 0x20 + test_sar \prefix, 0x3f + test_sar \prefix, 0x40 + test_sar \prefix, 0xfffffffe +.endm + +.macro sar_set imm + movi a2, \imm + wsr a2, sar +.endm + +.macro sar_ver imm + rsr a3, sar + movi a2, \imm & 0x3f + assert eq, a2, a3 +.endm + +test sar + tests_sar sar +test_end + +.macro ssr_set imm + movi a2, \imm + ssr a2 +.endm + +.macro ssr_ver imm + rsr a3, sar + movi a2, \imm & 0x1f + assert eq, a2, a3 +.endm + +test ssr + tests_sar ssr +test_end + +.macro ssl_set imm + movi a2, \imm + ssl a2 +.endm + +.macro ssl_ver imm + rsr a3, sar + movi a2, 32 - (\imm & 0x1f) + assert eq, a2, a3 +.endm + +test ssl + tests_sar ssl +test_end + +.macro ssa8l_set imm + movi a2, \imm + ssa8l a2 +.endm + +.macro ssa8l_ver imm + rsr a3, sar + movi a2, (\imm & 0x3) << 3 + assert eq, a2, a3 +.endm + +test ssa8l + tests_sar ssa8l +test_end + +.macro ssa8b_set imm + movi a2, \imm + ssa8b a2 +.endm + +.macro ssa8b_ver imm + rsr a3, sar + movi a2, 32 - ((\imm & 0x3) << 3) + assert eq, a2, a3 +.endm + +test ssa8b + tests_sar ssa8b +test_end + +.macro ssai_set imm + ssai \imm & 0x1f +.endm + +.macro ssai_ver imm + rsr a3, sar + movi a2, \imm & 0x1f + assert eq, a2, a3 +.endm + +test ssai + tests_sar ssai +test_end + +test_suite_end diff --git a/tests/xtensa/test_sext.S b/tests/xtensa/test_sext.S new file mode 100644 index 0000000000..04dc6500c1 --- /dev/null +++ b/tests/xtensa/test_sext.S @@ -0,0 +1,69 @@ +.include "macros.inc" + +test_suite sext + +test sext + movi a2, 0xffffff5a + movi a3, 0x0000005a + sext a4, a2, 7 + assert eq, a3, a4 + + movi a2, 0x000000a5 + movi a3, 0xffffffa5 + sext a4, a2, 7 + assert eq, a3, a4 + + movi a2, 0xfffffaa5 + movi a3, 0x000000a5 + sext a4, a2, 8 + assert eq, a3, a4 + + movi a2, 0x0000055a + movi a3, 0xffffff5a + sext a4, a2, 8 + assert eq, a3, a4 + + movi a2, 0xffff5a5a + movi a3, 0x00005a5a + sext a4, a2, 15 + assert eq, a3, a4 + + movi a2, 0x0000a5a5 + movi a3, 0xffffa5a5 + sext a4, a2, 15 + assert eq, a3, a4 + + movi a2, 0x00055a5a + movi a3, 0xffff5a5a + sext a4, a2, 16 + assert eq, a3, a4 + + movi a2, 0x000aa5a5 + movi a3, 0x0000a5a5 + sext a4, a2, 16 + assert eq, a3, a4 + + movi a2, 0x005a5a5a + movi a3, 0xffda5a5a + sext a4, a2, 22 + assert eq, a3, a4 + + movi a2, 0xffa5a5a5 + movi a3, 0x0025a5a5 + sext a4, a2, 22 + assert eq, a3, a4 +test_end + +test sext_same_rs + movi a2, 0xffffff5a + movi a3, 0x0000005a + sext a2, a2, 7 + assert eq, a3, a2 + + movi a2, 0x000000a5 + movi a3, 0xffffffa5 + sext a2, a2, 7 + assert eq, a3, a2 +test_end + +test_suite_end diff --git a/tests/xtensa/test_shift.S b/tests/xtensa/test_shift.S new file mode 100644 index 0000000000..a8e43645b7 --- /dev/null +++ b/tests/xtensa/test_shift.S @@ -0,0 +1,206 @@ +.include "macros.inc" + +test_suite shift + +.macro test_shift prefix, dst, src, v, imm + \prefix\()_set \dst, \src, \v, \imm + \prefix\()_ver \dst, \v, \imm +.endm + +.macro test_shift_sd prefix, v, imm + test_shift \prefix, a3, a2, \v, \imm + test_shift \prefix, a2, a2, \v, \imm +.endm + +.macro tests_imm_shift prefix, v + test_shift_sd \prefix, \v, 1 + test_shift_sd \prefix, \v, 2 + test_shift_sd \prefix, \v, 7 + test_shift_sd \prefix, \v, 8 + test_shift_sd \prefix, \v, 15 + test_shift_sd \prefix, \v, 16 + test_shift_sd \prefix, \v, 31 +.endm + +.macro tests_shift prefix, v + test_shift_sd \prefix, \v, 0 + tests_imm_shift \prefix, \v + test_shift_sd \prefix, \v, 32 +.endm + + +.macro slli_set dst, src, v, imm + movi \src, \v + slli \dst, \src, \imm +.endm + +.macro slli_ver dst, v, imm + mov a2, \dst + movi a3, ((\v) << (\imm)) & 0xffffffff + assert eq, a2, a3 +.endm + +test slli + tests_imm_shift slli, 0xa3c51249 +test_end + + +.macro srai_set dst, src, v, imm + movi \src, \v + srai \dst, \src, \imm +.endm + +.macro srai_ver dst, v, imm + mov a2, \dst + .if (\imm) + movi a3, (((\v) >> (\imm)) & 0xffffffff) | \ + ~((((\v) & 0x80000000) >> ((\imm) - 1)) - 1) + .else + movi a3, \v + .endif + assert eq, a2, a3 +.endm + +test srai + tests_imm_shift srai, 0x49a3c512 + tests_imm_shift srai, 0xa3c51249 +test_end + + +.macro srli_set dst, src, v, imm + movi \src, \v + srli \dst, \src, \imm +.endm + +.macro srli_ver dst, v, imm + mov a2, \dst + movi a3, (((\v) >> (\imm)) & 0xffffffff) + assert eq, a2, a3 +.endm + +test srli + tests_imm_shift srli, 0x49a3c512 + tests_imm_shift srli, 0xa3c51249 +test_end + + +.macro sll_set dst, src, v, imm + movi a2, \imm + ssl a2 + movi \src, \v + sll \dst, \src +.endm + +.macro sll_sar_set dst, src, v, imm + movi a2, 32 - \imm + wsr a2, sar + movi \src, \v + sll \dst, \src +.endm + +.macro sll_ver dst, v, imm + slli_ver \dst, \v, (\imm) & 0x1f +.endm + +.macro sll_sar_ver dst, v, imm + slli_ver \dst, \v, \imm +.endm + +test sll + tests_shift sll, 0xa3c51249 + tests_shift sll_sar, 0xa3c51249 +test_end + + +.macro srl_set dst, src, v, imm + movi a2, \imm + ssr a2 + movi \src, \v + srl \dst, \src +.endm + +.macro srl_sar_set dst, src, v, imm + movi a2, \imm + wsr a2, sar + movi \src, \v + srl \dst, \src +.endm + +.macro srl_ver dst, v, imm + srli_ver \dst, \v, (\imm) & 0x1f +.endm + +.macro srl_sar_ver dst, v, imm + srli_ver \dst, \v, \imm +.endm + +test srl + tests_shift srl, 0xa3c51249 + tests_shift srl_sar, 0xa3c51249 + tests_shift srl, 0x49a3c512 + tests_shift srl_sar, 0x49a3c512 +test_end + + +.macro sra_set dst, src, v, imm + movi a2, \imm + ssr a2 + movi \src, \v + sra \dst, \src +.endm + +.macro sra_sar_set dst, src, v, imm + movi a2, \imm + wsr a2, sar + movi \src, \v + sra \dst, \src +.endm + +.macro sra_ver dst, v, imm + srai_ver \dst, \v, (\imm) & 0x1f +.endm + +.macro sra_sar_ver dst, v, imm + srai_ver \dst, \v, \imm +.endm + +test sra + tests_shift sra, 0xa3c51249 + tests_shift sra_sar, 0xa3c51249 + tests_shift sra, 0x49a3c512 + tests_shift sra_sar, 0x49a3c512 +test_end + + +.macro src_set dst, src, v, imm + movi a2, \imm + ssr a2 + movi \src, (\v) & 0xffffffff + movi a4, (\v) >> 32 + src \dst, a4, \src +.endm + +.macro src_sar_set dst, src, v, imm + movi a2, \imm + wsr a2, sar + movi \src, (\v) & 0xffffffff + movi a4, (\v) >> 32 + src \dst, a4, \src +.endm + +.macro src_ver dst, v, imm + src_sar_ver \dst, \v, (\imm) & 0x1f +.endm + +.macro src_sar_ver dst, v, imm + mov a2, \dst + movi a3, ((\v) >> (\imm)) & 0xffffffff + assert eq, a2, a3 +.endm + +test src + tests_shift src, 0xa3c51249215c3a94 + tests_shift src_sar, 0xa3c51249215c3a94 +test_end + +test_suite_end diff --git a/tests/xtensa/test_timer.S b/tests/xtensa/test_timer.S new file mode 100644 index 0000000000..ede63955cc --- /dev/null +++ b/tests/xtensa/test_timer.S @@ -0,0 +1,115 @@ +.include "macros.inc" + +test_suite timer + +test ccount + rsr a3, ccount + rsr a4, ccount + sub a3, a4, a3 + assert eqi, a3, 1 +test_end + +test ccompare + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + wsr a2, ccompare1 + wsr a2, ccompare2 + + movi a3, 20 + rsr a2, ccount + addi a2, a2, 20 + wsr a2, ccompare0 + rsr a2, interrupt + assert eqi, a2, 0 + loop a3, 1f + rsr a3, interrupt + bnez a3, 2f +1: + test_fail +2: +test_end + +test ccompare0_interrupt + set_vector kernel, 2f + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + wsr a2, ccompare1 + wsr a2, ccompare2 + + movi a3, 20 + rsr a2, ccount + addi a2, a2, 20 + wsr a2, ccompare0 + rsync + rsr a2, interrupt + assert eqi, a2, 0 + + movi a2, 0x40 + wsr a2, intenable + rsil a2, 0 + loop a3, 1f + nop +1: + test_fail +2: + rsr a2, exccause + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +test_end + +test ccompare1_interrupt + set_vector level3, 2f + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + wsr a2, ccompare0 + wsr a2, ccompare2 + + movi a3, 20 + rsr a2, ccount + addi a2, a2, 20 + wsr a2, ccompare1 + rsync + rsr a2, interrupt + assert eqi, a2, 0 + movi a2, 0x400 + wsr a2, intenable + rsil a2, 2 + loop a3, 1f + nop +1: + test_fail +2: +test_end + +test ccompare2_interrupt + set_vector level5, 2f + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + wsr a2, ccompare0 + wsr a2, ccompare1 + + movi a3, 20 + rsr a2, ccount + addi a2, a2, 20 + wsr a2, ccompare2 + rsync + rsr a2, interrupt + assert eqi, a2, 0 + movi a2, 0x2000 + wsr a2, intenable + rsil a2, 4 + loop a3, 1f + nop +1: + test_fail +2: +test_end + +test_suite_end diff --git a/tests/xtensa/test_windowed.S b/tests/xtensa/test_windowed.S new file mode 100644 index 0000000000..cb2d39e1fd --- /dev/null +++ b/tests/xtensa/test_windowed.S @@ -0,0 +1,302 @@ +.include "macros.inc" + +test_suite windowed + +.altmacro + +.macro reset_window start + movi a2, 0xff + wsr a2, windowstart + rsync + movi a2, 0 + wsr a2, windowbase + rsync + movi a2, \start + wsr a2, windowstart + rsync +.endm + +.macro overflow_test shift, window, probe_ok, probe_ex + set_vector window_overflow_4, 0 + set_vector window_overflow_8, 0 + set_vector window_overflow_12, 0 + + movi a2, 1 | (((1 << ((\window) / 4)) | 1) << ((\shift) / 4)) + wsr a2, windowstart + reset_ps + + mov a2, a\probe_ok + set_vector window_overflow_\window, 10f +1: + mov a2, a\probe_ex + test_fail +10: + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 + movi a2, 2f + wsr a2, epc1 + + rsr a2, windowbase + movi a3, (\shift) / 4 + assert eq, a2, a3 + rsr a2, ps + movi a3, 0x4001f + assert eq, a2, a3 + rfwo + test_fail +2: + rsr a2, windowbase + assert eqi, a2, 0 + rsr a2, windowstart + movi a3, 1 | ((1 << ((\window) / 4)) << ((\shift) / 4)) + assert eq, a2, a3 + rsr a2, ps + movi a3, 0x4000f + assert eq, a2, a3 +.endm + +.macro overflow_tests shift, window, probe + .if \probe < 15 + overflow_test \shift, \window, %((\shift) - 1), \probe + overflow_tests \shift, \window, %((\probe) + 1) + .endif +.endm + +.macro all_overflow_tests + .irp shift, 4, 8, 12 + .irp window, 4, 8, 12 + overflow_tests \shift, \window, \shift + .endr + .endr +.endm + +test overflow + all_overflow_tests +test_end + + +.macro underflow_test window + set_vector window_underflow_4, 0 + set_vector window_underflow_8, 0 + set_vector window_underflow_12, 0 + + set_vector window_underflow_\window, 10f + + reset_window 1 + reset_ps + + ssai 2 + movi a2, 2f + slli a2, a2, 2 + movi a3, (\window) / 4 + src a0, a3, a2 +1: + retw + test_fail +10: + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 + movi a2, 2f + wsr a2, epc1 + + rsr a2, ps + movi a3, 0x4001f + assert eq, a2, a3 + rsr a2, windowbase + assert eqi, a2, 8 - ((\window) / 4) + rsr a2, windowstart + assert eqi, a2, 1 + rfwu +2: + rsr a2, ps + movi a3, 0x4000f + assert eq, a2, a3 + rsr a2, windowbase + assert eqi, a2, 0 + rsr a2, windowstart + assert bsi, a2, 0 + assert bsi, a2, 8 - ((\window) / 4) +.endm + +test underflow + set_vector window_overflow_4, 0 + set_vector window_overflow_8, 0 + set_vector window_overflow_12, 0 + + underflow_test 4 + underflow_test 8 + underflow_test 12 +test_end + + +.macro retw_test window + reset_window %(1 | (1 << (8 - (\window) / 4))) + reset_ps + + ssai 2 + movi a2, 1f + slli a2, a2, 2 + movi a3, (\window) / 4 + src a0, a3, a2 + retw + test_fail +1: + rsr a2, ps + movi a3, 0x4000f + assert eq, a2, a3 + rsr a2, windowbase + assert eqi, a2, 8 - ((\window) / 4) + rsr a2, windowstart + assert bci, a2, 0 + assert bsi, a2, 8 - ((\window) / 4) +.endm + +test retw + set_vector window_underflow_4, 0 + set_vector window_underflow_8, 0 + set_vector window_underflow_12, 0 + + retw_test 4 + retw_test 8 + retw_test 12 +test_end + +test movsp + set_vector kernel, 2f + + reset_window 1 + reset_ps +1: + movsp a2, a3 + test_fail +2: + rsr a2, exccause + assert eqi, a2, 5 + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 + + set_vector kernel, 0 + + reset_window 0x81 + reset_ps + + movsp a2, a3 +test_end + +test rotw + reset_window 0x4b + reset_ps + + movi a3, 0x10 + + rotw 1 + rsr a2, windowbase + assert eqi, a2, 1 + movi a3, 0x11 + movi a7, 0x12 + + rotw 2 + rsr a2, windowbase + assert eqi, a2, 3 + movi a3, 0x13 + movi a7, 0x14 + movi a11, 0x15 + + rotw 3 + rsr a2, windowbase + assert eqi, a2, 6 + movi a3, 0x16 + movi a7, 0x17 + + movi a2, 0x44 + wsr a2, windowstart + rsync + + movi a2, 0x10 + assert eq, a2, a11 + movi a11, 0x18 + movi a2, 0x11 + assert eq, a2, a15 + movi a15, 0x19 + + rotw 4 + movi a2, 0x12 + assert eq, a2, a3 + movi a2, 0x13 + assert eq, a2, a7 + movi a2, 0x14 + assert eq, a2, a11 + movi a2, 0x15 + assert eq, a2, a15 + + movi a2, 0x5 + wsr a2, windowstart + rsync + + rotw -2 + movi a2, 0x18 + assert eq, a2, a3 + movi a2, 0x19 + assert eq, a2, a7 +test_end + +.macro callw_test window + call\window 2f +1: + test_fail + .align 4 +2: + rsr a2, windowbase + assert eqi, a2, 0 + rsr a2, ps + movi a3, 0x4000f | ((\window) << 14) + assert eq, a2, a3 + movi a2, 1b + slli a2, a2, 2 + ssai 2 + movi a3, (\window) / 4 + src a2, a3, a2 + assert eq, a2, a\window +.endm + +test callw + reset_window 0x1 + reset_ps + + callw_test 4 + callw_test 8 + callw_test 12 +test_end + + +.macro entry_test window + reset_window 0x1 + reset_ps + movi a2, 0x4000f | ((\window) << 14) + wsr a2, ps + isync + movi a3, 0x12345678 + j 1f + .align 4 +1: + entry a3, 0x5678 + movi a2, 0x12340000 + assert eq, a2, a3 + rsr a2, windowbase + assert eqi, a2, (\window) / 4 + rsr a2, windowstart + movi a3, 1 | (1 << ((\window) / 4)) + assert eq, a2, a3 + rotw -(\window) / 4 +.endm + +test entry + entry_test 4 + entry_test 8 + entry_test 12 +test_end + +test_suite_end diff --git a/tests/xtensa/vectors.S b/tests/xtensa/vectors.S new file mode 100644 index 0000000000..265a181239 --- /dev/null +++ b/tests/xtensa/vectors.S @@ -0,0 +1,39 @@ +.macro vector name + +.section .vector.\name + j 1f +.section .vector.\name\().text +1: + wsr a2, excsave1 + movi a2, handler_\name + l32i a2, a2, 0 + beqz a2, 1f + jx a2 +1: + movi a3, 1b + movi a2, 1 + simcall + +.align 4 +.global handler_\name +handler_\name\(): .word 0 + +.endm + +vector window_overflow_4 +vector window_overflow_8 +vector window_overflow_12 +vector window_underflow_4 +vector window_underflow_8 +vector window_underflow_12 + +vector level2 +vector level3 +vector level4 +vector level5 +vector level6 +vector level7 + +vector kernel +vector user +vector double diff --git a/trace-events b/trace-events index 3fdd60faa4..a31d9aa2ae 100644 --- a/trace-events +++ b/trace-events @@ -42,6 +42,7 @@ virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) " virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p" virtio_irq(void *vq) "vq %p" virtio_notify(void *vdev, void *vq) "vdev %p vq %p" +virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u" # hw/virtio-serial-bus.c virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u" @@ -62,7 +63,7 @@ bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d" bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p" bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" -bdrv_set_locked(void *bs, int locked) "bs %p locked %d" +bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_io(int is_write, void *acb) "is_write %d acb %p" @@ -88,8 +89,8 @@ balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu" # hw/apic.c apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d" apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d" -cpu_set_apic_base(uint64_t val) "%016"PRIx64"" -cpu_get_apic_base(uint64_t val) "%016"PRIx64"" +cpu_set_apic_base(uint64_t val) "%016"PRIx64 +cpu_get_apic_base(uint64_t val) "%016"PRIx64 apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x" apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x" # coalescing @@ -169,21 +170,21 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x" # hw/slavio_timer.c slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x" slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x" -slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64"" +slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64 slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x" slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x" -slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64"" +slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64 slavio_timer_mem_writel_counter_invalid(void) "not user timer" slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started" slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped" slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer" slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter" slavio_timer_mem_writel_mode_invalid(void) "not system timer" -slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64"" +slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64 # hw/sparc32_dma.c -ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64"" -ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64"" +ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64 +ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64 sparc32_dma_set_irq_raise(void) "Raise IRQ" sparc32_dma_set_irq_lower(void) "Lower IRQ" espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x" @@ -202,12 +203,12 @@ sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d" # hw/sun4m_iommu.c sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x" sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x" -sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64"" +sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64 sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x" sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x" sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x" sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x" -sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64"" +sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64 # hw/usb-bus.c usb_port_claim(int bus, const char *port) "bus %d, port %s" @@ -278,7 +279,7 @@ scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d le scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d" scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d" scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d" -scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64"" +scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64 scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x" scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d" @@ -306,11 +307,11 @@ qed_start_need_check_timer(void *s) "s %p" qed_cancel_need_check_timer(void *s) "s %p" qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d" qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d" -qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64"" +qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64 qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu" qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu" -qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64"" -qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64"" +qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64 +qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64 qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu" # hw/g364fb.c @@ -327,10 +328,10 @@ grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" # hw/grlib_irqmp.c -grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n" +grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x" grlib_irqmp_ack(int intno) "interrupt:%d" grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d" -grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64"" +grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" # hw/grlib_apbuart.c @@ -450,15 +451,22 @@ milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX" milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +# hw/mipsnet.c +mipsnet_send(uint32_t size) "sending len=%u" +mipsnet_receive(uint32_t size) "receiving len=%u" +mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x" +mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 "" +mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)" + # xen-all.c xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx" xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i" # xen-mapcache.c -xen_map_cache(uint64_t phys_addr) "want %#"PRIx64"" -xen_remap_bucket(uint64_t index) "index %#"PRIx64"" +xen_map_cache(uint64_t phys_addr) "want %#"PRIx64 +xen_remap_bucket(uint64_t index) "index %#"PRIx64 xen_map_cache_return(void* ptr) "%p" -xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64"" +xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64 xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx" # exec.c diff --git a/trace/simple.c b/trace/simple.c index a6093682dd..b639dda806 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -12,8 +12,10 @@ #include <stdint.h> #include <stdio.h> #include <time.h> +#ifndef _WIN32 #include <signal.h> #include <pthread.h> +#endif #include "qemu-timer.h" #include "trace.h" #include "trace/control.h" @@ -54,9 +56,9 @@ enum { * Trace records are written out by a dedicated thread. The thread waits for * records to become available, writes them out, and then waits again. */ -static pthread_mutex_t trace_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t trace_available_cond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t trace_empty_cond = PTHREAD_COND_INITIALIZER; +static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT; +static GCond *trace_available_cond; +static GCond *trace_empty_cond; static bool trace_available; static bool trace_writeout_enabled; @@ -93,29 +95,30 @@ static bool get_trace_record(unsigned int idx, TraceRecord *record) */ static void flush_trace_file(bool wait) { - pthread_mutex_lock(&trace_lock); + g_static_mutex_lock(&trace_lock); trace_available = true; - pthread_cond_signal(&trace_available_cond); + g_cond_signal(trace_available_cond); if (wait) { - pthread_cond_wait(&trace_empty_cond, &trace_lock); + g_cond_wait(trace_empty_cond, g_static_mutex_get_mutex(&trace_lock)); } - pthread_mutex_unlock(&trace_lock); + g_static_mutex_unlock(&trace_lock); } static void wait_for_trace_records_available(void) { - pthread_mutex_lock(&trace_lock); + g_static_mutex_lock(&trace_lock); while (!(trace_available && trace_writeout_enabled)) { - pthread_cond_signal(&trace_empty_cond); - pthread_cond_wait(&trace_available_cond, &trace_lock); + g_cond_signal(trace_empty_cond); + g_cond_wait(trace_available_cond, + g_static_mutex_get_mutex(&trace_lock)); } trace_available = false; - pthread_mutex_unlock(&trace_lock); + g_static_mutex_unlock(&trace_lock); } -static void *writeout_thread(void *opaque) +static gpointer writeout_thread(gpointer opaque) { TraceRecord record; unsigned int writeout_idx = 0; @@ -159,7 +162,7 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, timestamp = get_clock(); - idx = __sync_fetch_and_add(&trace_idx, 1) % TRACE_BUF_LEN; + idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; trace_buf[idx] = (TraceRecord){ .event = event, .timestamp_ns = timestamp, @@ -231,7 +234,7 @@ void st_set_trace_file_enabled(bool enable) .x1 = HEADER_VERSION, }; - trace_fp = fopen(trace_file_name, "w"); + trace_fp = fopen(trace_file_name, "wb"); if (!trace_fp) { return; } @@ -331,28 +334,47 @@ bool trace_event_set_state(const char *name, bool state) return false; } -bool trace_backend_init(const char *events, const char *file) +/* Helper function to create a thread with signals blocked. Use glib's + * portable threads since QEMU abstractions cannot be used due to reentrancy in + * the tracer. Also note the signal masking on POSIX hosts so that the thread + * does not steal signals when the rest of the program wants them blocked. + */ +static GThread *trace_thread_create(GThreadFunc fn) { - pthread_t thread; - pthread_attr_t attr; + GThread *thread; +#ifndef _WIN32 sigset_t set, oldset; - int ret; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, &oldset); - ret = pthread_create(&thread, &attr, writeout_thread, NULL); +#endif + thread = g_thread_create(writeout_thread, NULL, FALSE, NULL); +#ifndef _WIN32 pthread_sigmask(SIG_SETMASK, &oldset, NULL); +#endif - if (ret != 0) { + return thread; +} + +bool trace_backend_init(const char *events, const char *file) +{ + GThread *thread; + + if (!g_thread_supported()) { + g_thread_init(NULL); + } + + trace_available_cond = g_cond_new(); + trace_empty_cond = g_cond_new(); + + thread = trace_thread_create(writeout_thread); + if (!thread) { fprintf(stderr, "warning: unable to initialize simple trace backend\n"); - } else { - atexit(st_flush_trace_buffer); - trace_backend_init_events(events); - st_set_trace_file(file); + return false; } + atexit(st_flush_trace_buffer); + trace_backend_init_events(events); + st_set_trace_file(file); return true; } diff --git a/ui/keymaps.c b/ui/keymaps.c index 81003bb5ca..f54a11437b 100644 --- a/ui/keymaps.c +++ b/ui/keymaps.c @@ -146,7 +146,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, if (rest && strstr(rest, "addupper")) { char *c; for (c = line; *c; c++) - *c = toupper(*c); + *c = qemu_toupper(*c); keysym = get_keysym(table, line); if (keysym) add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k); @@ -409,7 +409,7 @@ static void sdl_update_caption(void) char icon_title[1024]; const char *status = ""; - if (!vm_running) + if (!runstate_is_running()) status = " [Stopped]"; else if (gui_grab) { if (alt_grab) @@ -853,8 +853,8 @@ static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; - if (last_vm_running != vm_running) { - last_vm_running = vm_running; + if (last_vm_running != runstate_is_running()) { + last_vm_running = runstate_is_running(); sdl_update_caption(); } diff --git a/ui/spice-display.c b/ui/spice-display.c index e38536114b..6c302a3909 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -15,8 +15,6 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <pthread.h> - #include "qemu-common.h" #include "qemu-spice.h" #include "qemu-timer.h" @@ -255,7 +253,8 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); } -void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) +void qemu_spice_vm_change_state_handler(void *opaque, int running, + RunState state) { SimpleSpiceDisplay *ssd = opaque; diff --git a/ui/spice-display.h b/ui/spice-display.h index 1388641370..5e52df99be 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -22,6 +22,7 @@ #include "qemu-thread.h" #include "console.h" #include "pflib.h" +#include "sysemu.h" #define NUM_MEMSLOTS 8 #define MEMSLOT_GENERATION_BITS 8 @@ -88,7 +89,8 @@ void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *upda void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); -void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason); +void qemu_spice_vm_change_state_handler(void *opaque, int running, + RunState state); void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds); void qemu_spice_display_update(SimpleSpiceDisplay *ssd, diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c index 2e2456e3ac..ffbd1725a4 100644 --- a/ui/vnc-tls.c +++ b/ui/vnc-tls.c @@ -283,13 +283,57 @@ int vnc_tls_validate_certificate(struct VncState *vs) return 0; } +#if defined(GNUTLS_VERSION_NUMBER) && \ + GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */ + +static int vnc_set_gnutls_priority(gnutls_session_t s, int x509) +{ + const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH"; + int rc; + + rc = gnutls_priority_set_direct(s, priority, NULL); + if (rc != GNUTLS_E_SUCCESS) { + return -1; + } + return 0; +} + +#else + +static int vnc_set_gnutls_priority(gnutls_session_t s, int x509) +{ + static const int cert_types[] = { GNUTLS_CRT_X509, 0 }; + static const int protocols[] = { + GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 + }; + static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 }; + static const int kx_x509[] = { + GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, + GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0 + }; + int rc; + + rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon); + if (rc != GNUTLS_E_SUCCESS) { + return -1; + } + + rc = gnutls_certificate_type_set_priority(s, cert_types); + if (rc != GNUTLS_E_SUCCESS) { + return -1; + } + + rc = gnutls_protocol_set_priority(s, protocols); + if (rc != GNUTLS_E_SUCCESS) { + return -1; + } + return 0; +} + +#endif int vnc_tls_client_setup(struct VncState *vs, int needX509Creds) { - static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; - static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; - static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0}; VNC_DEBUG("Do TLS setup\n"); if (vnc_tls_initialize() < 0) { @@ -310,21 +354,7 @@ int vnc_tls_client_setup(struct VncState *vs, return -1; } - if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) { - gnutls_deinit(vs->tls.session); - vs->tls.session = NULL; - vnc_client_error(vs); - return -1; - } - - if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) { - gnutls_deinit(vs->tls.session); - vs->tls.session = NULL; - vnc_client_error(vs); - return -1; - } - - if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) { + if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) { gnutls_deinit(vs->tls.session); vs->tls.session = NULL; vnc_client_error(vs); @@ -185,9 +185,7 @@ int mem_prealloc = 0; /* force preallocation of physical target memory */ #endif int nb_nics; NICInfo nd_table[MAX_NICS]; -int vm_running; int autostart; -int incoming_expected; /* Started with -incoming and waiting for incoming */ static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ QEMUClock *rtc_clock; @@ -323,6 +321,120 @@ static int default_driver_check(QemuOpts *opts, void *opaque) } /***********************************************************/ +/* QEMU state */ + +static RunState current_run_state = RSTATE_NO_STATE; + +typedef struct { + RunState from; + RunState to; +} RunStateTransition; + +static const RunStateTransition runstate_transitions_def[] = { + /* from -> to */ + { RSTATE_NO_STATE, RSTATE_RUNNING }, + { RSTATE_NO_STATE, RSTATE_IN_MIGRATE }, + { RSTATE_NO_STATE, RSTATE_PRE_LAUNCH }, + + { RSTATE_DEBUG, RSTATE_RUNNING }, + + { RSTATE_IN_MIGRATE, RSTATE_RUNNING }, + { RSTATE_IN_MIGRATE, RSTATE_PRE_LAUNCH }, + + { RSTATE_PANICKED, RSTATE_PAUSED }, + + { RSTATE_IO_ERROR, RSTATE_RUNNING }, + + { RSTATE_PAUSED, RSTATE_RUNNING }, + + { RSTATE_POST_MIGRATE, RSTATE_RUNNING }, + + { RSTATE_PRE_LAUNCH, RSTATE_RUNNING }, + { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE }, + + { RSTATE_PRE_MIGRATE, RSTATE_RUNNING }, + { RSTATE_PRE_MIGRATE, RSTATE_POST_MIGRATE }, + + { RSTATE_RESTORE, RSTATE_RUNNING }, + + { RSTATE_RUNNING, RSTATE_DEBUG }, + { RSTATE_RUNNING, RSTATE_PANICKED }, + { RSTATE_RUNNING, RSTATE_IO_ERROR }, + { RSTATE_RUNNING, RSTATE_PAUSED }, + { RSTATE_RUNNING, RSTATE_PRE_MIGRATE }, + { RSTATE_RUNNING, RSTATE_RESTORE }, + { RSTATE_RUNNING, RSTATE_SAVEVM }, + { RSTATE_RUNNING, RSTATE_SHUTDOWN }, + { RSTATE_RUNNING, RSTATE_WATCHDOG }, + + { RSTATE_SAVEVM, RSTATE_RUNNING }, + + { RSTATE_SHUTDOWN, RSTATE_PAUSED }, + + { RSTATE_WATCHDOG, RSTATE_RUNNING }, + + { RSTATE_MAX, RSTATE_MAX }, +}; + +static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_MAX]; + +static const char *const runstate_name_tbl[RSTATE_MAX] = { + [RSTATE_DEBUG] = "debug", + [RSTATE_IN_MIGRATE] = "incoming-migration", + [RSTATE_PANICKED] = "internal-error", + [RSTATE_IO_ERROR] = "io-error", + [RSTATE_PAUSED] = "paused", + [RSTATE_POST_MIGRATE] = "post-migrate", + [RSTATE_PRE_LAUNCH] = "prelaunch", + [RSTATE_PRE_MIGRATE] = "finish-migrate", + [RSTATE_RESTORE] = "restore-vm", + [RSTATE_RUNNING] = "running", + [RSTATE_SAVEVM] = "save-vm", + [RSTATE_SHUTDOWN] = "shutdown", + [RSTATE_WATCHDOG] = "watchdog", +}; + +bool runstate_check(RunState state) +{ + return current_run_state == state; +} + +void runstate_init(void) +{ + const RunStateTransition *p; + + memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions)); + + for (p = &runstate_transitions_def[0]; p->from != RSTATE_MAX; p++) { + runstate_valid_transitions[p->from][p->to] = true; + } +} + +/* This function will abort() on invalid state transitions */ +void runstate_set(RunState new_state) +{ + if (new_state >= RSTATE_MAX || + !runstate_valid_transitions[current_run_state][new_state]) { + fprintf(stderr, "invalid runstate transition\n"); + abort(); + } + + current_run_state = new_state; +} + +const char *runstate_as_string(void) +{ + assert(current_run_state > RSTATE_NO_STATE && + current_run_state < RSTATE_MAX); + return runstate_name_tbl[current_run_state]; +} + +int runstate_is_running(void) +{ + return runstate_check(RSTATE_RUNNING); +} + +/***********************************************************/ /* real time host monotonic timer */ /***********************************************************/ @@ -1145,23 +1257,23 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) g_free (e); } -void vm_state_notify(int running, int reason) +void vm_state_notify(int running, RunState state) { VMChangeStateEntry *e; - trace_vm_state_notify(running, reason); + trace_vm_state_notify(running, state); for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) { - e->cb(e->opaque, running, reason); + e->cb(e->opaque, running, state); } } void vm_start(void) { - if (!vm_running) { + if (!runstate_is_running()) { cpu_enable_ticks(); - vm_running = 1; - vm_state_notify(1, 0); + runstate_set(RSTATE_RUNNING); + vm_state_notify(1, RSTATE_RUNNING); resume_all_vcpus(); monitor_protocol_event(QEVENT_RESUME, NULL); } @@ -1182,7 +1294,7 @@ static int shutdown_requested, shutdown_signal = -1; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; -static int vmstop_requested; +static RunState vmstop_requested = RSTATE_NO_STATE; int qemu_shutdown_requested_get(void) { @@ -1238,11 +1350,11 @@ static int qemu_debug_requested(void) return r; } -static int qemu_vmstop_requested(void) +static RunState qemu_vmstop_requested(void) { - int r = vmstop_requested; - vmstop_requested = 0; - return r; + RunState s = vmstop_requested; + vmstop_requested = RSTATE_NO_STATE; + return s; } void qemu_register_reset(QEMUResetHandler *func, void *opaque) @@ -1296,6 +1408,7 @@ void qemu_system_killed(int signal, pid_t pid) { shutdown_signal = signal; shutdown_pid = pid; + no_shutdown = 0; qemu_system_shutdown_request(); } @@ -1317,9 +1430,9 @@ void qemu_system_debug_request(void) qemu_notify_event(); } -void qemu_system_vmstop_request(int reason) +void qemu_system_vmstop_request(RunState state) { - vmstop_requested = reason; + vmstop_requested = state; qemu_notify_event(); } @@ -1469,13 +1582,13 @@ static void main_loop(void) #endif if (qemu_debug_requested()) { - vm_stop(VMSTOP_DEBUG); + vm_stop(RSTATE_DEBUG); } if (qemu_shutdown_requested()) { qemu_kill_report(); monitor_protocol_event(QEVENT_SHUTDOWN, NULL); if (no_shutdown) { - vm_stop(VMSTOP_SHUTDOWN); + vm_stop(RSTATE_SHUTDOWN); } else break; } @@ -1484,6 +1597,10 @@ static void main_loop(void) cpu_synchronize_all_states(); qemu_system_reset(VMRESET_REPORT); resume_all_vcpus(); + if (runstate_check(RSTATE_PANICKED) || + runstate_check(RSTATE_SHUTDOWN)) { + runstate_set(RSTATE_PAUSED); + } } if (qemu_powerdown_requested()) { monitor_protocol_event(QEVENT_POWERDOWN, NULL); @@ -2200,6 +2317,9 @@ int main(int argc, char **argv, char **envp) error_set_progname(argv[0]); g_mem_set_vtable(&mem_trace); + g_thread_init(NULL); + + runstate_init(); init_clocks(); @@ -2951,7 +3071,6 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_incoming: incoming = optarg; - incoming_expected = true; break; case QEMU_OPTION_nodefaults: default_serial = 0; @@ -3061,7 +3180,7 @@ int main(int argc, char **argv, char **envp) if (!data_dir) { data_dir = os_find_datadir(argv[0]); } - /* If all else fails use the install patch specified when building. */ + /* If all else fails use the install path specified when building. */ if (!data_dir) { data_dir = CONFIG_QEMU_DATADIR; } @@ -3437,6 +3556,7 @@ int main(int argc, char **argv, char **envp) } if (incoming) { + runstate_set(RSTATE_IN_MIGRATE); int ret = qemu_start_incoming_migration(incoming); if (ret < 0) { fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", @@ -3445,6 +3565,8 @@ int main(int argc, char **argv, char **envp) } } else if (autostart) { vm_start(); + } else { + runstate_set(RSTATE_PRE_LAUNCH); } os_setup_post(); @@ -620,7 +620,7 @@ static void cpu_ioreq_move(ioreq_t *req) } } } else { - target_ulong tmp; + uint64_t tmp; if (req->dir == IOREQ_READ) { for (i = 0; i < req->count; i++) { @@ -736,7 +736,7 @@ static void cpu_handle_ioreq(void *opaque) * guest resumes and does a hlt with interrupts disabled which * causes Xen to powerdown the domain. */ - if (vm_running) { + if (runstate_is_running()) { if (qemu_shutdown_requested_get()) { destroy_hvm_domain(); } @@ -846,7 +846,8 @@ static void xen_main_loop_prepare(XenIOState *state) /* Initialise Xen */ -static void xen_change_state_handler(void *opaque, int running, int reason) +static void xen_change_state_handler(void *opaque, int running, + RunState state) { if (running) { /* record state running */ @@ -854,11 +855,12 @@ static void xen_change_state_handler(void *opaque, int running, int reason) } } -static void xen_hvm_change_state_handler(void *opaque, int running, int reason) +static void xen_hvm_change_state_handler(void *opaque, int running, + RunState rstate) { - XenIOState *state = opaque; + XenIOState *xstate = opaque; if (running) { - xen_main_loop_prepare(state); + xen_main_loop_prepare(xstate); } } diff --git a/xen-mapcache.c b/xen-mapcache.c index 5b247ee092..7bcb86e4f8 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -40,6 +40,13 @@ #endif #define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) +/* This is the size of the virtual address space reserve to QEMU that will not + * be use by MapCache. + * From empirical tests I observed that qemu use 75MB more than the + * max_mcache_size. + */ +#define NON_MCACHE_MEMORY_SIZE (80 * 1024 * 1024) + #define mapcache_lock() ((void)0) #define mapcache_unlock() ((void)0) @@ -92,15 +99,27 @@ void xen_map_cache_init(void) QTAILQ_INIT(&mapcache->locked_entries); mapcache->last_address_index = -1; - getrlimit(RLIMIT_AS, &rlimit_as); - if (rlimit_as.rlim_max < MCACHE_MAX_SIZE) { - rlimit_as.rlim_cur = rlimit_as.rlim_max; + if (geteuid() == 0) { + rlimit_as.rlim_cur = RLIM_INFINITY; + rlimit_as.rlim_max = RLIM_INFINITY; + mapcache->max_mcache_size = MCACHE_MAX_SIZE; } else { - rlimit_as.rlim_cur = MCACHE_MAX_SIZE; + getrlimit(RLIMIT_AS, &rlimit_as); + rlimit_as.rlim_cur = rlimit_as.rlim_max; + + if (rlimit_as.rlim_max != RLIM_INFINITY) { + fprintf(stderr, "Warning: QEMU's maximum size of virtual" + " memory is not infinity.\n"); + } + if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) { + mapcache->max_mcache_size = rlimit_as.rlim_max - + NON_MCACHE_MEMORY_SIZE; + } else { + mapcache->max_mcache_size = MCACHE_MAX_SIZE; + } } setrlimit(RLIMIT_AS, &rlimit_as); - mapcache->max_mcache_size = rlimit_as.rlim_cur; mapcache->nr_buckets = (((mapcache->max_mcache_size >> XC_PAGE_SHIFT) + diff --git a/xtensa-semi.c b/xtensa-semi.c new file mode 100644 index 0000000000..ba0e828b32 --- /dev/null +++ b/xtensa-semi.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * 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. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 AUTHOR 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 <errno.h> +#include <unistd.h> +#include <string.h> +#include <stddef.h> +#include "cpu.h" +#include "dyngen-exec.h" +#include "helpers.h" +#include "qemu-log.h" + +enum { + TARGET_SYS_exit = 1, + TARGET_SYS_read = 3, + TARGET_SYS_write = 4, + TARGET_SYS_open = 5, + TARGET_SYS_close = 6, + TARGET_SYS_lseek = 19, + TARGET_SYS_select_one = 29, + + TARGET_SYS_argc = 1000, + TARGET_SYS_argv_sz = 1001, + TARGET_SYS_argv = 1002, + TARGET_SYS_memset = 1004, +}; + +enum { + SELECT_ONE_READ = 1, + SELECT_ONE_WRITE = 2, + SELECT_ONE_EXCEPT = 3, +}; + +void HELPER(simcall)(CPUState *env) +{ + uint32_t *regs = env->regs; + + switch (regs[2]) { + case TARGET_SYS_exit: + qemu_log("exit(%d) simcall\n", regs[3]); + exit(regs[3]); + break; + + case TARGET_SYS_read: + case TARGET_SYS_write: + { + bool is_write = regs[2] == TARGET_SYS_write; + uint32_t fd = regs[3]; + uint32_t vaddr = regs[4]; + uint32_t len = regs[5]; + + while (len > 0) { + target_phys_addr_t paddr = + cpu_get_phys_page_debug(env, vaddr); + uint32_t page_left = + TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1)); + uint32_t io_sz = page_left < len ? page_left : len; + target_phys_addr_t sz = io_sz; + void *buf = cpu_physical_memory_map(paddr, &sz, is_write); + + if (buf) { + vaddr += io_sz; + len -= io_sz; + regs[2] = is_write ? + write(fd, buf, io_sz) : + read(fd, buf, io_sz); + regs[3] = errno; + cpu_physical_memory_unmap(buf, sz, is_write, sz); + if (regs[2] == -1) { + break; + } + } else { + regs[2] = -1; + regs[3] = EINVAL; + break; + } + } + } + break; + + case TARGET_SYS_open: + { + char name[1024]; + int rc; + int i; + + for (i = 0; i < ARRAY_SIZE(name); ++i) { + rc = cpu_memory_rw_debug( + env, regs[3] + i, (uint8_t *)name + i, 1, 0); + if (rc != 0 || name[i] == 0) { + break; + } + } + + if (rc == 0 && i < ARRAY_SIZE(name)) { + regs[2] = open(name, regs[4], regs[5]); + regs[3] = errno; + } else { + regs[2] = -1; + regs[3] = EINVAL; + } + } + break; + + case TARGET_SYS_close: + if (regs[3] < 3) { + regs[2] = regs[3] = 0; + } else { + regs[2] = close(regs[3]); + regs[3] = errno; + } + break; + + case TARGET_SYS_lseek: + regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]); + regs[3] = errno; + break; + + case TARGET_SYS_select_one: + { + uint32_t fd = regs[3]; + uint32_t rq = regs[4]; + uint32_t target_tv = regs[5]; + uint32_t target_tvv[2]; + + struct timeval tv = {0}; + fd_set fdset; + + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + + if (target_tv) { + cpu_memory_rw_debug(env, target_tv, + (uint8_t *)target_tvv, sizeof(target_tvv), 0); + tv.tv_sec = (int32_t)tswap32(target_tvv[0]); + tv.tv_usec = (int32_t)tswap32(target_tvv[1]); + } + regs[2] = select(fd + 1, + rq == SELECT_ONE_READ ? &fdset : NULL, + rq == SELECT_ONE_WRITE ? &fdset : NULL, + rq == SELECT_ONE_EXCEPT ? &fdset : NULL, + target_tv ? &tv : NULL); + regs[3] = errno; + } + break; + + case TARGET_SYS_argc: + regs[2] = 1; + regs[3] = 0; + break; + + case TARGET_SYS_argv_sz: + regs[2] = 128; + regs[3] = 0; + break; + + case TARGET_SYS_argv: + { + struct Argv { + uint32_t argptr[2]; + char text[120]; + } argv = { + {0, 0}, + "test" + }; + + argv.argptr[0] = tswap32(regs[3] + offsetof(struct Argv, text)); + cpu_memory_rw_debug( + env, regs[3], (uint8_t *)&argv, sizeof(argv), 1); + } + break; + + case TARGET_SYS_memset: + { + uint32_t base = regs[3]; + uint32_t sz = regs[5]; + + while (sz) { + target_phys_addr_t len = sz; + void *buf = cpu_physical_memory_map(base, &len, 1); + + if (buf && len) { + memset(buf, regs[4], len); + cpu_physical_memory_unmap(buf, len, 1, len); + } else { + len = 1; + } + base += len; + sz -= len; + } + regs[2] = regs[3]; + regs[3] = 0; + } + break; + + default: + qemu_log("%s(%d): not implemented\n", __func__, regs[2]); + break; + } +} |