diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | MAINTAINERS | 11 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | Makefile.target | 1 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | acl.c | 4 | ||||
-rwxr-xr-x | configure | 11 | ||||
-rw-r--r-- | cpu-all.h | 4 | ||||
-rw-r--r-- | cpus.c | 14 | ||||
-rw-r--r-- | cpus.h | 1 | ||||
-rw-r--r-- | cutils.c | 12 | ||||
-rw-r--r-- | darwin-user/main.c | 2 | ||||
-rw-r--r-- | dma-helpers.c | 5 | ||||
-rw-r--r-- | dma.h | 18 | ||||
-rw-r--r-- | docs/qapi-code-gen.txt | 4 | ||||
-rw-r--r-- | docs/tracing.txt | 9 | ||||
-rw-r--r-- | event_notifier.c (renamed from hw/event_notifier.c) | 1 | ||||
-rw-r--r-- | event_notifier.h (renamed from hw/event_notifier.h) | 0 | ||||
-rw-r--r-- | exec.c | 13 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.c | 103 | ||||
-rw-r--r-- | hw/ac97.c | 7 | ||||
-rw-r--r-- | hw/e1000.c | 29 | ||||
-rw-r--r-- | hw/eepro100.c | 121 | ||||
-rw-r--r-- | hw/es1370.c | 5 | ||||
-rw-r--r-- | hw/fw_cfg.c | 102 | ||||
-rw-r--r-- | hw/ide/pci.c | 19 | ||||
-rw-r--r-- | hw/intel-hda.c | 16 | ||||
-rw-r--r-- | hw/lance.c | 1 | ||||
-rw-r--r-- | hw/lsi53c895a.c | 33 | ||||
-rw-r--r-- | hw/opencores_eth.c | 29 | ||||
-rw-r--r-- | hw/pc.c | 1 | ||||
-rw-r--r-- | hw/pci.h | 67 | ||||
-rw-r--r-- | hw/pcnet-pci.c | 59 | ||||
-rw-r--r-- | hw/pcnet.c | 25 | ||||
-rw-r--r-- | hw/pcnet.h | 20 | ||||
-rw-r--r-- | hw/ppc.c | 6 | ||||
-rw-r--r-- | hw/ppce500_pci.c | 82 | ||||
-rw-r--r-- | hw/ps2.c | 46 | ||||
-rw-r--r-- | hw/qxl-render.c | 36 | ||||
-rw-r--r-- | hw/qxl.c | 26 | ||||
-rw-r--r-- | hw/qxl.h | 3 | ||||
-rw-r--r-- | hw/rtl8139.c | 106 | ||||
-rw-r--r-- | hw/spapr.c | 135 | ||||
-rw-r--r-- | hw/spapr.h | 2 | ||||
-rw-r--r-- | hw/spapr_pci.c | 508 | ||||
-rw-r--r-- | hw/spapr_pci.h | 61 | ||||
-rw-r--r-- | hw/spapr_vio.c | 8 | ||||
-rw-r--r-- | hw/spapr_vio.h | 1 | ||||
-rw-r--r-- | hw/sysbus.c | 2 | ||||
-rw-r--r-- | hw/usb-ehci.c | 44 | ||||
-rw-r--r-- | hw/usb-hub.c | 5 | ||||
-rw-r--r-- | hw/usb-msd.c | 4 | ||||
-rw-r--r-- | hw/usb-uhci.c | 22 | ||||
-rw-r--r-- | hw/virtio-blk.c | 16 | ||||
-rw-r--r-- | ia64-dis.c | 3 | ||||
-rw-r--r-- | int128.h | 116 | ||||
-rw-r--r-- | kvm-all.c | 3 | ||||
-rw-r--r-- | memory.c | 193 | ||||
-rw-r--r-- | memory.h | 3 | ||||
-rw-r--r-- | migration-fd.c | 23 | ||||
-rw-r--r-- | migration.c | 2 | ||||
-rw-r--r-- | monitor.c | 30 | ||||
-rw-r--r-- | net.c | 7 | ||||
-rw-r--r-- | net/tap-linux.c | 6 | ||||
-rw-r--r-- | oslib-posix.c | 22 | ||||
-rw-r--r-- | pc-bios/README | 2 | ||||
-rw-r--r-- | pc-bios/slof.bin | bin | 579072 -> 738744 bytes | |||
-rw-r--r-- | qemu-barrier.h | 2 | ||||
-rw-r--r-- | qemu-common.h | 1 | ||||
-rw-r--r-- | qemu-tls.h | 52 | ||||
m--------- | roms/SLOF | 0 | ||||
-rw-r--r-- | savevm.c | 2 | ||||
-rwxr-xr-x | scripts/checkpatch.pl | 6 | ||||
-rw-r--r-- | target-i386/helper.c | 1 | ||||
-rw-r--r-- | target-ppc/cpu.h | 49 | ||||
-rw-r--r-- | target-ppc/helper.c | 11 | ||||
-rw-r--r-- | target-ppc/kvm.c | 197 | ||||
-rw-r--r-- | target-ppc/kvm_ppc.h | 50 | ||||
-rw-r--r-- | target-ppc/translate.c | 500 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 106 | ||||
-rw-r--r-- | tcg/tcg-op.h | 10 | ||||
-rw-r--r-- | trace/simple.c | 19 | ||||
-rw-r--r-- | trace/stderr.c | 17 | ||||
-rw-r--r-- | ui/cocoa.m | 2 | ||||
-rw-r--r-- | ui/vnc-auth-sasl.c | 8 | ||||
-rw-r--r-- | ui/vnc-enc-hextile.c | 4 | ||||
-rw-r--r-- | ui/vnc-tls.c | 2 | ||||
-rw-r--r-- | ui/vnc.c | 8 | ||||
-rw-r--r-- | usb-linux.c | 6 | ||||
-rw-r--r-- | vl.c | 4 |
90 files changed, 2408 insertions, 935 deletions
diff --git a/.gitignore b/.gitignore index 6d2acab09a..406f75f2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,10 @@ libhw64 libuser linux-headers/asm qapi-generated +qapi-types.[ch] +qapi-visit.[ch] +qmp-commands.h +qmp-marshal.c qemu-doc.html qemu-tech.html qemu-doc.info diff --git a/MAINTAINERS b/MAINTAINERS index 4535eeb61f..7ee301e787 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -303,9 +303,9 @@ M: Alexander Graf <agraf@suse.de> S: Maintained F: hw/ppc_oldworld.c -Prep -M: qemu-devel@nongnu.org -S: Orphan +PReP +M: Andreas Färber <andreas.faerber@web.de> +S: Odd Fixes F: hw/ppc_prep.c SH4 Machines @@ -451,6 +451,11 @@ M: Anthony Liguori <aliguori@us.ibm.com> S: Maintained F: ui/ +Cocoa graphics +M: Andreas Färber <andreas.faerber@web.de> +S: Odd Fixes +F: ui/cocoa.m + Main loop M: Anthony Liguori <aliguori@us.ibm.com> S: Supported @@ -75,7 +75,7 @@ defconfig: -include config-all-devices.mak -build-all: $(DOCS) $(TOOLS) recurse-all +build-all: $(DOCS) $(TOOLS) $(CHECKS) recurse-all config-host.h: config-host.h-timestamp config-host.h-timestamp: config-host.mak @@ -219,7 +219,7 @@ clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f qemu-options.def - rm -f *.o *.d *.a *.lo $(TOOLS) qemu-ga TAGS cscope.* *.pod *~ */*~ + rm -f *.o *.d *.a *.lo $(TOOLS) $(CHECKS) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -Rf .libs rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d rm -f qemu-img-cmds.h @@ -305,6 +305,12 @@ endif test speed: all $(MAKE) -C tests $@ +.PHONY: check +check: $(patsubst %,run-check-%,$(CHECKS)) + +run-check-%: % + ./$< + .PHONY: TAGS TAGS: find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags diff --git a/Makefile.target b/Makefile.target index 406b12525c..a111521dbf 100644 --- a/Makefile.target +++ b/Makefile.target @@ -252,6 +252,7 @@ obj-ppc-y += ppc_newworld.o # IBM pSeries (sPAPR) obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o +obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-ppc-y += ppc440.o ppc440_bamboo.o @@ -1 +1 @@ -0.15.50 +0.15.90 @@ -95,13 +95,13 @@ int qemu_acl_party_is_allowed(qemu_acl *acl, void qemu_acl_reset(qemu_acl *acl) { - qemu_acl_entry *entry; + qemu_acl_entry *entry, *next_entry; /* Put back to deny by default, so there is no window * of "open access" while the user re-initializes the * access control list */ acl->defaultDeny = 1; - QTAILQ_FOREACH(entry, &acl->entries, next) { + QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) { QTAILQ_REMOVE(&acl->entries, entry, next); free(entry->match); free(entry); @@ -170,7 +170,7 @@ mixemu="no" aix="no" blobs="yes" pkgversion="" -check_utests="no" +check_utests="" user_pie="no" zero_malloc="" trace_backend="nop" @@ -1834,7 +1834,7 @@ if test "$check_utests" != "no" ; then #include <check.h> int main(void) { suite_create("qemu test"); return 0; } EOF - check_libs=`$pkg_config --libs check` + check_libs=`$pkg_config --libs check 2>/dev/null` if compile_prog "" $check_libs ; then check_utests=yes libs_tools="$check_libs $libs_tools" @@ -2674,8 +2674,8 @@ if test "$softmmu" = yes ; then tools="qemu-ga\$(EXESUF) $tools" fi if [ "$check_utests" = "yes" ]; then - tools="check-qint check-qstring check-qdict check-qlist $tools" - tools="check-qfloat check-qjson $tools" + checks="check-qint check-qstring check-qdict check-qlist" + checks="check-qfloat check-qjson test-coroutine $checks" fi fi fi @@ -3162,6 +3162,7 @@ if test "$trace_default" = "yes"; then fi echo "TOOLS=$tools" >> $config_host_mak +echo "CHECKS=$checks" >> $config_host_mak echo "ROMS=$roms" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak echo "INSTALL=$install" >> $config_host_mak @@ -3359,7 +3360,7 @@ case "$target_arch2" in ;; ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_phys_bits=32 + target_phys_bits=64 target_nptl="yes" target_libs_softmmu="$fdt_libs" ;; @@ -20,6 +20,7 @@ #define CPU_ALL_H #include "qemu-common.h" +#include "qemu-tls.h" #include "cpu-common.h" /* some important defines: @@ -334,7 +335,8 @@ void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf, void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) GCC_FMT_ATTR(2, 3); extern CPUState *first_cpu; -extern CPUState *cpu_single_env; +DECLARE_TLS(CPUState *,cpu_single_env); +#define cpu_single_env get_tls(cpu_single_env) /* Flags for use in ENV->INTERRUPT_PENDING. @@ -748,6 +748,8 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) return NULL; } +static void tcg_exec_all(void); + static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *env = arg; @@ -769,7 +771,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } while (1) { - cpu_exec_all(); + tcg_exec_all(); if (use_icount && qemu_clock_deadline(vm_clock) <= 0) { qemu_notify_event(); } @@ -1016,7 +1018,7 @@ static int tcg_cpu_exec(CPUState *env) return ret; } -bool cpu_exec_all(void) +static void tcg_exec_all(void) { int r; @@ -1033,12 +1035,7 @@ bool cpu_exec_all(void) (env->singlestep_enabled & SSTEP_NOTIMER) == 0); if (cpu_can_run(env)) { - if (kvm_enabled()) { - r = kvm_cpu_exec(env); - qemu_kvm_eat_signals(env); - } else { - r = tcg_cpu_exec(env); - } + r = tcg_cpu_exec(env); if (r == EXCP_DEBUG) { cpu_handle_guest_debug(env); break; @@ -1048,7 +1045,6 @@ bool cpu_exec_all(void) } } exit_request = 0; - return !all_cpu_threads_idle(); } void set_numa_modes(void) @@ -14,7 +14,6 @@ void cpu_synchronize_all_post_init(void); /* vl.c */ extern int smp_cores; extern int smp_threads; -bool cpu_exec_all(void); void set_numa_modes(void); void set_cpu_log(const char *optarg); void set_cpu_log_filename(const char *optarg); @@ -415,3 +415,15 @@ int64_t strtosz(const char *nptr, char **end) { return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB); } + +int qemu_parse_fd(const char *param) +{ + int fd; + char *endptr = NULL; + + fd = strtol(param, &endptr, 10); + if (*endptr || (fd == 0 && param == endptr)) { + return -1; + } + return fd; +} diff --git a/darwin-user/main.c b/darwin-user/main.c index 1a881a0a60..c0f14f8260 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -729,8 +729,6 @@ static void usage(void) /* XXX: currently only used for async signals (see signal.c) */ CPUState *global_env; -/* used only if single thread */ -CPUState *cpu_single_env = NULL; /* used to free thread contexts */ TaskState *first_task_state; diff --git a/dma-helpers.c b/dma-helpers.c index 86d2d0a997..bdcd38cd27 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -18,8 +18,7 @@ void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint) qsg->size = 0; } -void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base, - target_phys_addr_t len) +void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len) { if (qsg->nsg == qsg->nalloc) { qsg->nalloc = 2 * qsg->nalloc + 1; @@ -45,7 +44,7 @@ typedef struct { bool to_dev; bool in_cancel; int sg_cur_index; - target_phys_addr_t sg_cur_byte; + dma_addr_t sg_cur_byte; QEMUIOVector iov; QEMUBH *bh; DMAIOFunc *io_func; @@ -18,21 +18,29 @@ typedef struct ScatterGatherEntry ScatterGatherEntry; #if defined(TARGET_PHYS_ADDR_BITS) +typedef target_phys_addr_t dma_addr_t; + +#define DMA_ADDR_FMT TARGET_FMT_plx + +typedef enum { + DMA_DIRECTION_TO_DEVICE = 0, + DMA_DIRECTION_FROM_DEVICE = 1, +} DMADirection; + struct ScatterGatherEntry { - target_phys_addr_t base; - target_phys_addr_t len; + dma_addr_t base; + dma_addr_t len; }; struct QEMUSGList { ScatterGatherEntry *sg; int nsg; int nalloc; - target_phys_addr_t size; + dma_addr_t size; }; 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_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len); void qemu_sglist_destroy(QEMUSGList *qsg); #endif diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index f345866f57..c0a9325db8 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -41,7 +41,7 @@ dictionary. This corresponds to a struct in C or an Object in JSON. An example of a complex type is: { 'type': 'MyType', - 'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } } + 'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } } The use of '*' as a prefix to the name means the member is optional. Optional members should always be added to the end of the dictionary to preserve @@ -63,7 +63,7 @@ An example command is: { 'command': 'my-command', 'data': { 'arg1': 'str', '*arg2': 'str' }, - 'returns': 'str' ] + 'returns': 'str' } Command names should be all lower case with words separated by a hyphen. diff --git a/docs/tracing.txt b/docs/tracing.txt index 95ca16c05d..ea29f2c222 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -132,12 +132,19 @@ This functionality is also provided through monitor commands: means disabled. * trace-event NAME on|off - Enable/disable a given trace event. + Enable/disable a given trace event or a group of events having common prefix + through wildcard. The "-trace events=<file>" command line argument can be used to enable the events listed in <file> from the very beginning of the program. This file must contain one event name per line. +A basic wildcard matching is supported in both the monitor command "trace +-event" and the events list file. That means you can enable/disable the events +having a common prefix in a batch. For example, virtio-blk trace events could +be enabled using: + trace-event virtio_blk_* on + == Trace backends == The "tracetool" script automates tedious trace event code generation and also diff --git a/hw/event_notifier.c b/event_notifier.c index 13f3656460..2c735556a1 100644 --- a/hw/event_notifier.c +++ b/event_notifier.c @@ -10,7 +10,6 @@ * the COPYING file in the top-level directory. */ -#include "hw.h" #include "event_notifier.h" #ifdef CONFIG_EVENTFD #include <sys/eventfd.h> diff --git a/hw/event_notifier.h b/event_notifier.h index 24117ea97b..24117ea97b 100644 --- a/hw/event_notifier.h +++ b/event_notifier.h @@ -120,7 +120,7 @@ static MemoryRegion *system_io; CPUState *first_cpu; /* current CPU in the current thread. It is only valid inside cpu_exec() */ -CPUState *cpu_single_env; +DEFINE_TLS(CPUState *,cpu_single_env); /* 0 = Do not count executed instructions. 1 = Precise instruction counting. 2 = Adaptive rate instruction counting. */ @@ -2873,7 +2873,7 @@ static void *file_ram_alloc(RAMBlock *block, static ram_addr_t find_ram_offset(ram_addr_t size) { RAMBlock *block, *next_block; - ram_addr_t offset = 0, mingap = RAM_ADDR_MAX; + ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX; if (QLIST_EMPTY(&ram_list.blocks)) return 0; @@ -2889,10 +2889,17 @@ static ram_addr_t find_ram_offset(ram_addr_t size) } } if (next - end >= size && next - end < mingap) { - offset = end; + offset = end; mingap = next - end; } } + + if (offset == RAM_ADDR_MAX) { + fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n", + (uint64_t)size); + abort(); + } + return offset; } diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 0777ece816..01cf337e36 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -11,6 +11,9 @@ * */ +#include <glib.h> +#include <glib/gprintf.h> + #include "hw/virtio.h" #include "hw/pc.h" #include "qemu_socket.h" @@ -161,114 +164,16 @@ void v9fs_string_null(V9fsString *str) v9fs_string_free(str); } -static int number_to_string(void *arg, char type) -{ - unsigned int ret = 0; - - switch (type) { - case 'u': { - unsigned int num = *(unsigned int *)arg; - - do { - ret++; - num = num/10; - } while (num); - break; - } - case 'U': { - unsigned long num = *(unsigned long *)arg; - do { - ret++; - num = num/10; - } while (num); - break; - } - default: - printf("Number_to_string: Unknown number format\n"); - return -1; - } - - return ret; -} - -static int GCC_FMT_ATTR(2, 0) -v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap) -{ - va_list ap2; - char *iter = (char *)fmt; - int len = 0; - int nr_args = 0; - char *arg_char_ptr; - unsigned int arg_uint; - unsigned long arg_ulong; - - /* Find the number of %'s that denotes an argument */ - for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) { - nr_args++; - iter++; - } - - len = strlen(fmt) - 2*nr_args; - - if (!nr_args) { - goto alloc_print; - } - - va_copy(ap2, ap); - - iter = (char *)fmt; - - /* Now parse the format string */ - for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) { - iter++; - switch (*iter) { - case 'u': - arg_uint = va_arg(ap2, unsigned int); - len += number_to_string((void *)&arg_uint, 'u'); - break; - case 'l': - if (*++iter == 'u') { - arg_ulong = va_arg(ap2, unsigned long); - len += number_to_string((void *)&arg_ulong, 'U'); - } else { - return -1; - } - break; - case 's': - arg_char_ptr = va_arg(ap2, char *); - len += strlen(arg_char_ptr); - break; - case 'c': - len += 1; - break; - default: - fprintf(stderr, - "v9fs_string_alloc_printf:Incorrect format %c", *iter); - return -1; - } - iter++; - } - -alloc_print: - *strp = g_malloc((len + 1) * sizeof(**strp)); - - return vsprintf(*strp, fmt, ap); -} - void GCC_FMT_ATTR(2, 3) v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) { va_list ap; - int err; v9fs_string_free(str); va_start(ap, fmt); - err = v9fs_string_alloc_printf(&str->data, fmt, ap); - BUG_ON(err == -1); + str->size = g_vasprintf(&str->data, fmt, ap); va_end(ap); - - str->size = err; } void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs) @@ -18,6 +18,7 @@ #include "audiodev.h" #include "audio/audio.h" #include "pci.h" +#include "dma.h" enum { AC97_Reset = 0x00, @@ -224,7 +225,7 @@ static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) { uint8_t b[8]; - cpu_physical_memory_read (r->bdbar + r->civ * 8, b, 8); + pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8); r->bd_valid = 1; r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3; r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]); @@ -973,7 +974,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int copied; to_copy = audio_MIN (temp, sizeof (tmpbuf)); - cpu_physical_memory_read (addr, tmpbuf, to_copy); + pci_dma_read (&s->dev, addr, tmpbuf, to_copy); copied = AUD_write (s->voice_po, tmpbuf, to_copy); dolog ("write_audio max=%x to_copy=%x copied=%x\n", max, to_copy, copied); @@ -1054,7 +1055,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, *stop = 1; break; } - cpu_physical_memory_write (addr, tmpbuf, acquired); + pci_dma_write (&s->dev, addr, tmpbuf, acquired); temp -= acquired; addr += acquired; nread += acquired; diff --git a/hw/e1000.c b/hw/e1000.c index ce8fc8b510..986ed9cf79 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -31,6 +31,7 @@ #include "net/checksum.h" #include "loader.h" #include "sysemu.h" +#include "dma.h" #include "e1000_hw.h" @@ -465,7 +466,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) bytes = split_size; if (tp->size + bytes > msh) bytes = msh - tp->size; - cpu_physical_memory_read(addr, tp->data + tp->size, bytes); + pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes); if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) memmove(tp->header, tp->data, hdr); tp->size = sz; @@ -480,7 +481,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentaion Error\n"); } else { - cpu_physical_memory_read(addr, tp->data + tp->size, split_size); + pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size); tp->size += split_size; } @@ -496,7 +497,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } static uint32_t -txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp) +txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp) { uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data); @@ -505,8 +506,8 @@ txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp) txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) & ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU); dp->upper.data = cpu_to_le32(txd_upper); - cpu_physical_memory_write(base + ((char *)&dp->upper - (char *)dp), - (void *)&dp->upper, sizeof(dp->upper)); + pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp), + (void *)&dp->upper, sizeof(dp->upper)); return E1000_ICR_TXDW; } @@ -521,7 +522,7 @@ static uint64_t tx_desc_base(E1000State *s) static void start_xmit(E1000State *s) { - target_phys_addr_t base; + dma_addr_t base; struct e1000_tx_desc desc; uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE; @@ -533,14 +534,14 @@ start_xmit(E1000State *s) while (s->mac_reg[TDH] != s->mac_reg[TDT]) { base = tx_desc_base(s) + sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; - cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); + pci_dma_read(&s->dev, base, (void *)&desc, sizeof(desc)); DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH], (void *)(intptr_t)desc.buffer_addr, desc.lower.data, desc.upper.data); process_tx_desc(s, &desc); - cause |= txdesc_writeback(base, &desc); + cause |= txdesc_writeback(s, base, &desc); if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN]) s->mac_reg[TDH] = 0; @@ -668,7 +669,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; struct e1000_rx_desc desc; - target_phys_addr_t base; + dma_addr_t base; unsigned int n, rdt; uint32_t rdh_start; uint16_t vlan_special = 0; @@ -713,7 +714,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) desc_size = s->rxbuf_size; } base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH]; - cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); + pci_dma_read(&s->dev, base, (void *)&desc, sizeof(desc)); desc.special = vlan_special; desc.status |= (vlan_status | E1000_RXD_STAT_DD); if (desc.buffer_addr) { @@ -722,9 +723,9 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) if (copy_size > s->rxbuf_size) { copy_size = s->rxbuf_size; } - cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr), - (void *)(buf + desc_offset + vlan_offset), - copy_size); + pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr), + (void *)(buf + desc_offset + vlan_offset), + copy_size); } desc_offset += desc_size; desc.length = cpu_to_le16(desc_size); @@ -738,7 +739,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) } else { // as per intel docs; skip descriptors with null buf addr DBGOUT(RX, "Null RX descriptor!!\n"); } - cpu_physical_memory_write(base, (void *)&desc, sizeof(desc)); + pci_dma_write(&s->dev, base, (void *)&desc, sizeof(desc)); if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) s->mac_reg[RDH] = 0; diff --git a/hw/eepro100.c b/hw/eepro100.c index 4e3c52f50a..7d59e7136d 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -46,6 +46,7 @@ #include "net.h" #include "eeprom93xx.h" #include "sysemu.h" +#include "dma.h" /* QEMU sends frames smaller than 60 bytes to ethernet nics. * Such frames are rejected by real nics and their emulations. @@ -315,38 +316,6 @@ static const uint16_t eepro100_mdi_mask[] = { 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; -/* Read a 16 bit little endian value from physical memory. */ -static uint16_t e100_ldw_le_phys(target_phys_addr_t addr) -{ - /* Load 16 bit (little endian) word from emulated hardware. */ - uint16_t val; - cpu_physical_memory_read(addr, &val, sizeof(val)); - return le16_to_cpu(val); -} - -/* Read a 32 bit little endian value from physical memory. */ -static uint32_t e100_ldl_le_phys(target_phys_addr_t addr) -{ - /* Load 32 bit (little endian) word from emulated hardware. */ - uint32_t val; - cpu_physical_memory_read(addr, &val, sizeof(val)); - return le32_to_cpu(val); -} - -/* Write a 16 bit little endian value to physical memory. */ -static void e100_stw_le_phys(target_phys_addr_t addr, uint16_t val) -{ - val = cpu_to_le16(val); - cpu_physical_memory_write(addr, &val, sizeof(val)); -} - -/* Write a 32 bit little endian value to physical memory. */ -static void e100_stl_le_phys(target_phys_addr_t addr, uint32_t val) -{ - val = cpu_to_le32(val); - cpu_physical_memory_write(addr, &val, sizeof(val)); -} - #define POLYNOMIAL 0x04c11db6 /* From FreeBSD */ @@ -744,21 +713,26 @@ static void dump_statistics(EEPRO100State * s) * values which really matter. * Number of data should check configuration!!! */ - cpu_physical_memory_write(s->statsaddr, &s->statistics, s->stats_size); - e100_stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames); - e100_stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames); - e100_stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors); - e100_stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors); + pci_dma_write(&s->dev, s->statsaddr, + (uint8_t *) &s->statistics, s->stats_size); + stl_le_pci_dma(&s->dev, s->statsaddr + 0, + s->statistics.tx_good_frames); + stl_le_pci_dma(&s->dev, s->statsaddr + 36, + s->statistics.rx_good_frames); + stl_le_pci_dma(&s->dev, s->statsaddr + 48, + s->statistics.rx_resource_errors); + stl_le_pci_dma(&s->dev, s->statsaddr + 60, + s->statistics.rx_short_frame_errors); #if 0 - e100_stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames); - e100_stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames); + stw_le_pci_dma(&s->dev, s->statsaddr + 76, s->statistics.xmt_tco_frames); + stw_le_pci_dma(&s->dev, s->statsaddr + 78, s->statistics.rcv_tco_frames); missing("CU dump statistical counters"); #endif } static void read_cb(EEPRO100State *s) { - cpu_physical_memory_read(s->cb_address, &s->tx, sizeof(s->tx)); + pci_dma_read(&s->dev, s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx)); s->tx.status = le16_to_cpu(s->tx.status); s->tx.command = le16_to_cpu(s->tx.command); s->tx.link = le32_to_cpu(s->tx.link); @@ -788,18 +762,17 @@ static void tx_command(EEPRO100State *s) } assert(tcb_bytes <= sizeof(buf)); while (size < tcb_bytes) { - uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address); - uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4); + uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address); + uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4); #if 0 - uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6); + uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6); #endif tbd_address += 8; TRACE(RXTX, logout ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n", tx_buffer_address, tx_buffer_size)); tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size); - cpu_physical_memory_read(tx_buffer_address, &buf[size], - tx_buffer_size); + pci_dma_read(&s->dev, tx_buffer_address, &buf[size], tx_buffer_size); size += tx_buffer_size; } if (tbd_array == 0xffffffff) { @@ -810,16 +783,19 @@ static void tx_command(EEPRO100State *s) if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) { /* Extended Flexible TCB. */ for (; tbd_count < 2; tbd_count++) { - uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address); - uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4); - uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6); + uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, + tbd_address); + uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, + tbd_address + 4); + uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, + tbd_address + 6); tbd_address += 8; TRACE(RXTX, logout ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n", tx_buffer_address, tx_buffer_size)); tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size); - cpu_physical_memory_read(tx_buffer_address, &buf[size], - tx_buffer_size); + pci_dma_read(&s->dev, tx_buffer_address, + &buf[size], tx_buffer_size); size += tx_buffer_size; if (tx_buffer_el & 1) { break; @@ -828,16 +804,16 @@ static void tx_command(EEPRO100State *s) } tbd_address = tbd_array; for (; tbd_count < s->tx.tbd_count; tbd_count++) { - uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address); - uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4); - uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6); + uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address); + uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4); + uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6); tbd_address += 8; TRACE(RXTX, logout ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n", tx_buffer_address, tx_buffer_size)); tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size); - cpu_physical_memory_read(tx_buffer_address, &buf[size], - tx_buffer_size); + pci_dma_read(&s->dev, tx_buffer_address, + &buf[size], tx_buffer_size); size += tx_buffer_size; if (tx_buffer_el & 1) { break; @@ -862,7 +838,7 @@ static void set_multicast_list(EEPRO100State *s) TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count)); for (i = 0; i < multicast_count; i += 6) { uint8_t multicast_addr[6]; - cpu_physical_memory_read(s->cb_address + 10 + i, multicast_addr, 6); + pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6); TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6))); unsigned mcast_idx = compute_mcast_idx(multicast_addr); assert(mcast_idx < 64); @@ -896,12 +872,12 @@ static void action_command(EEPRO100State *s) /* Do nothing. */ break; case CmdIASetup: - cpu_physical_memory_read(s->cb_address + 8, &s->conf.macaddr.a[0], 6); + pci_dma_read(&s->dev, s->cb_address + 8, &s->conf.macaddr.a[0], 6); TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6))); break; case CmdConfigure: - cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0], - sizeof(s->configuration)); + pci_dma_read(&s->dev, s->cb_address + 8, + &s->configuration[0], sizeof(s->configuration)); TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16))); TRACE(OTHER, logout("configuration: %s\n", @@ -938,7 +914,8 @@ static void action_command(EEPRO100State *s) break; } /* Write new status. */ - e100_stw_le_phys(s->cb_address, s->tx.status | ok_status | STATUS_C); + stw_le_pci_dma(&s->dev, s->cb_address, + s->tx.status | ok_status | STATUS_C); if (bit_i) { /* CU completed action. */ eepro100_cx_interrupt(s); @@ -1005,7 +982,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) /* Dump statistical counters. */ TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val)); dump_statistics(s); - e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa005); + stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005); break; case CU_CMD_BASE: /* Load CU base. */ @@ -1016,7 +993,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) /* Dump and reset statistical counters. */ TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val)); dump_statistics(s); - e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa007); + stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007); memset(&s->statistics, 0, sizeof(s->statistics)); break; case CU_SRESUME: @@ -1310,10 +1287,10 @@ static void eepro100_write_port(EEPRO100State *s) case PORT_SELFTEST: TRACE(OTHER, logout("selftest address=0x%08x\n", address)); eepro100_selftest_t data; - cpu_physical_memory_read(address, &data, sizeof(data)); + pci_dma_read(&s->dev, address, (uint8_t *) &data, sizeof(data)); data.st_sign = 0xffffffff; data.st_result = 0; - cpu_physical_memory_write(address, &data, sizeof(data)); + pci_dma_write(&s->dev, address, (uint8_t *) &data, sizeof(data)); break; case PORT_SELECTIVE_RESET: TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address)); @@ -1729,8 +1706,8 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size } /* !!! */ eepro100_rx_t rx; - cpu_physical_memory_read(s->ru_base + s->ru_offset, &rx, - sizeof(eepro100_rx_t)); + pci_dma_read(&s->dev, s->ru_base + s->ru_offset, + (uint8_t *) &rx, sizeof(eepro100_rx_t)); uint16_t rfd_command = le16_to_cpu(rx.command); uint16_t rfd_size = le16_to_cpu(rx.size); @@ -1746,10 +1723,10 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size #endif TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", rfd_command, rx.link, rx.rx_buf_addr, rfd_size)); - e100_stw_le_phys(s->ru_base + s->ru_offset + - offsetof(eepro100_rx_t, status), rfd_status); - e100_stw_le_phys(s->ru_base + s->ru_offset + - offsetof(eepro100_rx_t, count), size); + stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset + + offsetof(eepro100_rx_t, status), rfd_status); + stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset + + offsetof(eepro100_rx_t, count), size); /* Early receive interrupt not supported. */ #if 0 eepro100_er_interrupt(s); @@ -1763,8 +1740,8 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size #if 0 assert(!(s->configuration[17] & BIT(0))); #endif - cpu_physical_memory_write(s->ru_base + s->ru_offset + - sizeof(eepro100_rx_t), buf, size); + pci_dma_write(&s->dev, s->ru_base + s->ru_offset + + sizeof(eepro100_rx_t), buf, size); s->statistics.rx_good_frames++; eepro100_fr_interrupt(s); s->ru_offset = le32_to_cpu(rx.link); diff --git a/hw/es1370.c b/hw/es1370.c index 2daadde0e6..c5c16b0484 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -30,6 +30,7 @@ #include "audiodev.h" #include "audio/audio.h" #include "pci.h" +#include "dma.h" /* Missing stuff: SCTRL_P[12](END|ST)INC @@ -802,7 +803,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, if (!acquired) break; - cpu_physical_memory_write (addr, tmpbuf, acquired); + pci_dma_write (&s->dev, addr, tmpbuf, acquired); temp -= acquired; addr += acquired; @@ -816,7 +817,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, int copied, to_copy; to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); - cpu_physical_memory_read (addr, tmpbuf, to_copy); + pci_dma_read (&s->dev, addr, tmpbuf, to_copy); copied = AUD_write (voice, tmpbuf, to_copy); if (!copied) break; diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 8df265c61d..dbcb888bbd 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -60,71 +60,55 @@ struct FWCfgState { #define JPG_FILE 0 #define BMP_FILE 1 -static FILE *probe_splashfile(char *filename, int *file_sizep, int *file_typep) +static char *read_splashfile(char *filename, int *file_sizep, int *file_typep) { - FILE *fp = NULL; - int fop_ret; - int file_size; + GError *err = NULL; + gboolean res; + gchar *content; int file_type = -1; - unsigned char buf[2] = {0, 0}; - unsigned int filehead_value = 0; + unsigned int filehead = 0; int bmp_bpp; - fp = fopen(filename, "rb"); - if (fp == NULL) { - error_report("failed to open file '%s'.", filename); - return fp; + res = g_file_get_contents(filename, &content, (gsize *)file_sizep, &err); + if (res == FALSE) { + error_report("failed to read splash file '%s'", filename); + g_error_free(err); + return NULL; } + /* check file size */ - fseek(fp, 0L, SEEK_END); - file_size = ftell(fp); - if (file_size < 2) { - error_report("file size is less than 2 bytes '%s'.", filename); - fclose(fp); - fp = NULL; - return fp; + if (*file_sizep < 30) { + goto error; } + /* check magic ID */ - fseek(fp, 0L, SEEK_SET); - fop_ret = fread(buf, 1, 2, fp); - if (fop_ret != 2) { - error_report("Could not read header from '%s': %s", - filename, strerror(errno)); - fclose(fp); - fp = NULL; - return fp; - } - filehead_value = (buf[0] + (buf[1] << 8)) & 0xffff; - if (filehead_value == 0xd8ff) { + filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff; + if (filehead == 0xd8ff) { file_type = JPG_FILE; + } else if (filehead == 0x4d42) { + file_type = BMP_FILE; } else { - if (filehead_value == 0x4d42) { - file_type = BMP_FILE; - } - } - if (file_type < 0) { - error_report("'%s' not jpg/bmp file,head:0x%x.", - filename, filehead_value); - fclose(fp); - fp = NULL; - return fp; + goto error; } + /* check BMP bpp */ if (file_type == BMP_FILE) { - fseek(fp, 28, SEEK_SET); - fop_ret = fread(buf, 1, 2, fp); - bmp_bpp = (buf[0] + (buf[1] << 8)) & 0xffff; + bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff; if (bmp_bpp != 24) { - error_report("only 24bpp bmp file is supported."); - fclose(fp); - fp = NULL; - return fp; + goto error; } } + /* return values */ - *file_sizep = file_size; *file_typep = file_type; - return fp; + + return content; + +error: + error_report("splash file '%s' format not recognized; must be JPEG " + "or 24 bit BMP", filename); + g_free(content); + return NULL; } static void fw_cfg_bootsplash(FWCfgState *s) @@ -132,9 +116,7 @@ static void fw_cfg_bootsplash(FWCfgState *s) int boot_splash_time = -1; const char *boot_splash_filename = NULL; char *p; - char *filename; - FILE *fp; - int fop_ret; + char *filename, *file_data; int file_size; int file_type = -1; const char *temp; @@ -174,27 +156,19 @@ static void fw_cfg_bootsplash(FWCfgState *s) error_report("failed to find file '%s'.", boot_splash_filename); return; } - /* probing the file */ - fp = probe_splashfile(filename, &file_size, &file_type); - if (fp == NULL) { + + /* loading file data */ + file_data = read_splashfile(filename, &file_size, &file_type); + if (file_data == NULL) { g_free(filename); return; } - /* loading file data */ if (boot_splash_filedata != NULL) { g_free(boot_splash_filedata); } - boot_splash_filedata = g_malloc(file_size); + boot_splash_filedata = (uint8_t *)file_data; boot_splash_filedata_size = file_size; - fseek(fp, 0L, SEEK_SET); - fop_ret = fread(boot_splash_filedata, 1, file_size, fp); - if (fop_ret != file_size) { - error_report("failed to read data from '%s'.", - boot_splash_filename); - fclose(fp); - return; - } - fclose(fp); + /* insert data */ if (file_type == JPG_FILE) { fw_cfg_add_file(s, "bootsplash.jpg", diff --git a/hw/ide/pci.c b/hw/ide/pci.c index f133c422b6..49b823df79 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -62,7 +62,8 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write) } prd; int l, len; - qemu_sglist_init(&s->sg, s->nsector / (BMDMA_PAGE_SIZE / 512) + 1); + pci_dma_sglist_init(&s->sg, &bm->pci_dev->dev, + s->nsector / (BMDMA_PAGE_SIZE / 512) + 1); s->io_buffer_size = 0; for(;;) { if (bm->cur_prd_len == 0) { @@ -70,7 +71,7 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write) if (bm->cur_prd_last || (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) return s->io_buffer_size != 0; - cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); + pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, (uint8_t *)&prd, 8); bm->cur_addr += 8; prd.addr = le32_to_cpu(prd.addr); prd.size = le32_to_cpu(prd.size); @@ -112,7 +113,7 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write) if (bm->cur_prd_last || (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) return 0; - cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); + pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, (uint8_t *)&prd, 8); bm->cur_addr += 8; prd.addr = le32_to_cpu(prd.addr); prd.size = le32_to_cpu(prd.size); @@ -127,11 +128,11 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write) l = bm->cur_prd_len; if (l > 0) { if (is_write) { - cpu_physical_memory_write(bm->cur_prd_addr, - s->io_buffer + s->io_buffer_index, l); + pci_dma_write(&bm->pci_dev->dev, bm->cur_prd_addr, + s->io_buffer + s->io_buffer_index, l); } else { - cpu_physical_memory_read(bm->cur_prd_addr, - s->io_buffer + s->io_buffer_index, l); + pci_dma_read(&bm->pci_dev->dev, bm->cur_prd_addr, + s->io_buffer + s->io_buffer_index, l); } bm->cur_prd_addr += l; bm->cur_prd_len -= l; @@ -326,7 +327,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) bm->cmd = val & 0x09; } -static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr, +static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr, unsigned width) { BMDMAState *bm = opaque; @@ -340,7 +341,7 @@ static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr, return data; } -static void bmdma_addr_write(void *opaque, target_phys_addr_t addr, +static void bmdma_addr_write(void *opaque, dma_addr_t addr, uint64_t data, unsigned width) { BMDMAState *bm = opaque; diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 675b6591e9..10769e0f49 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -24,6 +24,7 @@ #include "audiodev.h" #include "intel-hda.h" #include "intel-hda-defs.h" +#include "dma.h" /* --------------------------------------------------------------------- */ /* hda bus */ @@ -328,7 +329,7 @@ static void intel_hda_corb_run(IntelHDAState *d) rp = (d->corb_rp + 1) & 0xff; addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); - verb = ldl_le_phys(addr + 4*rp); + verb = ldl_le_pci_dma(&d->pci, addr + 4*rp); d->corb_rp = rp; dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb); @@ -360,8 +361,8 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res ex = (solicited ? 0 : (1 << 4)) | dev->cad; wp = (d->rirb_wp + 1) & 0xff; addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); - stl_le_phys(addr + 8*wp, response); - stl_le_phys(addr + 8*wp + 4, ex); + stl_le_pci_dma(&d->pci, addr + 8*wp, response); + stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex); d->rirb_wp = wp; dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n", @@ -401,7 +402,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, break; } } - if (st == NULL) { + if (s == 4) { return false; } if (st->bpl == NULL) { @@ -426,8 +427,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n", st->be, st->bp, st->bpl[st->be].len, copy); - cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp, - buf, copy, !output); + pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output); st->lpib += copy; st->bp += copy; buf += copy; @@ -449,7 +449,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, } if (d->dp_lbase & 0x01) { addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase); - stl_le_phys(addr + 8*s, st->lpib); + stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib); } dprint(d, 3, "dma: --\n"); @@ -471,7 +471,7 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st) g_free(st->bpl); st->bpl = g_malloc(sizeof(bpl) * st->bentries); for (i = 0; i < st->bentries; i++, addr += 16) { - cpu_physical_memory_read(addr, buf, 16); + pci_dma_read(&d->pci, addr, buf, 16); st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf); st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8)); st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12)); diff --git a/hw/lance.c b/hw/lance.c index d83e7f57a9..93d5fda35b 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -97,6 +97,7 @@ static NetClientInfo net_lance_info = { .size = sizeof(NICState), .can_receive = pcnet_can_receive, .receive = pcnet_receive, + .link_status_changed = pcnet_set_link_status, .cleanup = lance_cleanup, }; diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 2984cea633..fcc27d726f 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -15,6 +15,8 @@ #include "hw.h" #include "pci.h" #include "scsi.h" +#include "block_int.h" +#include "dma.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG @@ -390,10 +392,7 @@ static inline uint32_t read_dword(LSIState *s, uint32_t addr) { uint32_t buf; - /* XXX: an optimization here used to fast-path the read from scripts - * memory. But that bypasses any iommu. - */ - cpu_physical_memory_read(addr, (uint8_t *)&buf, 4); + pci_dma_read(&s->dev, addr, (uint8_t *)&buf, 4); return cpu_to_le32(buf); } @@ -532,7 +531,7 @@ static void lsi_bad_selection(LSIState *s, uint32_t id) static void lsi_do_dma(LSIState *s, int out) { uint32_t count; - target_phys_addr_t addr; + dma_addr_t addr; SCSIDevice *dev; assert(s->current); @@ -558,7 +557,7 @@ static void lsi_do_dma(LSIState *s, int out) else if (s->sbms) addr |= ((uint64_t)s->sbms << 32); - DPRINTF("DMA addr=0x" TARGET_FMT_plx " len=%d\n", addr, count); + DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count); s->csbc += count; s->dnad += count; s->dbc -= count; @@ -567,9 +566,9 @@ static void lsi_do_dma(LSIState *s, int out) } /* ??? Set SFBR to first data byte. */ if (out) { - cpu_physical_memory_read(addr, s->current->dma_buf, count); + pci_dma_read(&s->dev, addr, s->current->dma_buf, count); } else { - cpu_physical_memory_write(addr, s->current->dma_buf, count); + pci_dma_write(&s->dev, addr, s->current->dma_buf, count); } s->current->dma_len -= count; if (s->current->dma_len == 0) { @@ -762,7 +761,7 @@ static void lsi_do_command(LSIState *s) DPRINTF("Send command len=%d\n", s->dbc); if (s->dbc > 16) s->dbc = 16; - cpu_physical_memory_read(s->dnad, buf, s->dbc); + pci_dma_read(&s->dev, s->dnad, buf, s->dbc); s->sfbr = buf[0]; s->command_complete = 0; @@ -813,7 +812,7 @@ static void lsi_do_status(LSIState *s) s->dbc = 1; status = s->status; s->sfbr = status; - cpu_physical_memory_write(s->dnad, &status, 1); + pci_dma_write(&s->dev, s->dnad, &status, 1); lsi_set_phase(s, PHASE_MI); s->msg_action = 1; lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */ @@ -827,7 +826,7 @@ static void lsi_do_msgin(LSIState *s) len = s->msg_len; if (len > s->dbc) len = s->dbc; - cpu_physical_memory_write(s->dnad, s->msg, len); + pci_dma_write(&s->dev, s->dnad, s->msg, len); /* Linux drivers rely on the last byte being in the SIDL. */ s->sidl = s->msg[len - 1]; s->msg_len -= len; @@ -859,7 +858,7 @@ static void lsi_do_msgin(LSIState *s) static uint8_t lsi_get_msgbyte(LSIState *s) { uint8_t data; - cpu_physical_memory_read(s->dnad, &data, 1); + pci_dma_read(&s->dev, s->dnad, &data, 1); s->dnad++; s->dbc--; return data; @@ -1011,8 +1010,8 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); while (count) { n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count; - cpu_physical_memory_read(src, buf, n); - cpu_physical_memory_write(dest, buf, n); + pci_dma_read(&s->dev, src, buf, n); + pci_dma_write(&s->dev, dest, buf, n); src += n; dest += n; count -= n; @@ -1080,7 +1079,7 @@ again: /* 32-bit Table indirect */ offset = sxt24(addr); - cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8); + pci_dma_read(&s->dev, s->dsa + offset, (uint8_t *)buf, 8); /* byte count is stored in bits 0:23 only */ s->dbc = cpu_to_le32(buf[0]) & 0xffffff; s->rbc = s->dbc; @@ -1439,7 +1438,7 @@ again: n = (insn & 7); reg = (insn >> 16) & 0xff; if (insn & (1 << 24)) { - cpu_physical_memory_read(addr, data, n); + pci_dma_read(&s->dev, addr, data, n); DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, addr, *(int *)data); for (i = 0; i < n; i++) { @@ -1450,7 +1449,7 @@ again: for (i = 0; i < n; i++) { data[i] = lsi_reg_readb(s, reg + i); } - cpu_physical_memory_write(addr, data, n); + pci_dma_write(&s->dev, addr, data, n); } } } diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index 64b616ec1c..2c1e475395 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -382,6 +382,7 @@ static ssize_t open_eth_receive(VLANClientState *nc, OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque; size_t maxfl = GET_REGFIELD(s, PACKETLEN, MAXFL); size_t minfl = GET_REGFIELD(s, PACKETLEN, MINFL); + size_t fcsl = 4; bool miss = true; trace_open_eth_receive((unsigned)size); @@ -418,6 +419,7 @@ static ssize_t open_eth_receive(VLANClientState *nc, #else { #endif + static const uint8_t zero[64] = {0}; desc *desc = rx_desc(s); size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl; @@ -426,11 +428,13 @@ static ssize_t open_eth_receive(VLANClientState *nc, if (copy_size > size) { copy_size = size; + } else { + fcsl = 0; } if (miss) { desc->len_flags |= RXD_M; } - if (size > maxfl) { + if (GET_REGBIT(s, MODER, HUGEN) && size > maxfl) { desc->len_flags |= RXD_TL; } #ifdef USE_RECSMALL @@ -442,13 +446,28 @@ static ssize_t open_eth_receive(VLANClientState *nc, cpu_physical_memory_write(desc->buf_ptr, buf, copy_size); if (GET_REGBIT(s, MODER, PAD) && copy_size < minfl) { - static const uint8_t zero[65536] = {0}; + if (minfl - copy_size > fcsl) { + fcsl = 0; + } else { + fcsl -= minfl - copy_size; + } + while (copy_size < minfl) { + size_t zero_sz = minfl - copy_size < sizeof(zero) ? + minfl - copy_size : sizeof(zero); - cpu_physical_memory_write(desc->buf_ptr + copy_size, - zero, minfl - copy_size); - copy_size = minfl; + cpu_physical_memory_write(desc->buf_ptr + copy_size, + zero, zero_sz); + copy_size += zero_sz; + } } + /* There's no FCS in the frames handed to us by the QEMU, zero fill it. + * Don't do it if the frame is cut at the MAXFL or padded with 4 or + * more bytes to the MINFL. + */ + cpu_physical_memory_write(desc->buf_ptr + copy_size, zero, fcsl); + copy_size += fcsl; + SET_FIELD(desc->len_flags, RXD_LEN, copy_size); if ((desc->len_flags & RXD_WRAP) || s->rx_desc == 0x7f) { @@ -941,7 +941,6 @@ static CPUState *pc_new_cpu(const char *cpu_model) exit(1); } if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) { - env->cpuid_apic_id = env->cpu_index; env->apic_state = apic_init(env, env->cpuid_apic_id); } qemu_register_reset(pc_cpu_reset, env); @@ -5,6 +5,7 @@ #include "qdev.h" #include "memory.h" +#include "dma.h" /* PCI includes legacy ISA access. */ #include "isa.h" @@ -483,4 +484,70 @@ static inline uint32_t pci_config_size(const PCIDevice *d) return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; } +/* DMA access functions */ +static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len, DMADirection dir) +{ + cpu_physical_memory_rw(addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE); + return 0; +} + +static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len) +{ + return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); +} + +static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr, + const void *buf, dma_addr_t len) +{ + return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); +} + +#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr) \ + { \ + return ld##_l##_phys(addr); \ + } \ + static inline void st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, uint##_bits##_t val) \ + { \ + st##_s##_phys(addr, val); \ + } + +PCI_DMA_DEFINE_LDST(ub, b, 8); +PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) +PCI_DMA_DEFINE_LDST(l_le, l_le, 32); +PCI_DMA_DEFINE_LDST(q_le, q_le, 64); +PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) +PCI_DMA_DEFINE_LDST(l_be, l_be, 32); +PCI_DMA_DEFINE_LDST(q_be, q_be, 64); + +#undef PCI_DMA_DEFINE_LDST + +static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, + dma_addr_t *plen, DMADirection dir) +{ + target_phys_addr_t len = *plen; + void *buf; + + buf = cpu_physical_memory_map(addr, &len, dir == DMA_DIRECTION_FROM_DEVICE); + *plen = len; + return buf; +} + +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, + DMADirection dir, dma_addr_t access_len) +{ + cpu_physical_memory_unmap(buffer, len, dir == DMA_DIRECTION_FROM_DEVICE, + access_len); +} + +static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, + int alloc_hint) +{ + qemu_sglist_init(qsg, alloc_hint); +} + #endif diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index fb2a00caad..4e164da3ac 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -31,6 +31,7 @@ #include "net.h" #include "loader.h" #include "qemu-timer.h" +#include "dma.h" #include "pcnet.h" @@ -55,9 +56,9 @@ static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) #ifdef PCNET_DEBUG printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); #endif - /* Check APROMWE bit to enable write access */ - if (pcnet_bcr_readw(s,2) & 0x100) + if (BCR_APROMWE(s)) { s->prom[addr & 15] = val; + } } static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) @@ -75,12 +76,24 @@ static uint64_t pcnet_ioport_read(void *opaque, target_phys_addr_t addr, { PCNetState *d = opaque; - if (addr < 16 && size == 1) { - return pcnet_aprom_readb(d, addr); - } else if (addr >= 0x10 && addr < 0x20 && size == 2) { - return pcnet_ioport_readw(d, addr); - } else if (addr >= 0x10 && addr < 0x20 && size == 4) { - return pcnet_ioport_readl(d, addr); + if (addr < 0x10) { + if (!BCR_DWIO(d) && size == 1) { + return pcnet_aprom_readb(d, addr); + } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) { + return pcnet_aprom_readb(d, addr) | + (pcnet_aprom_readb(d, addr + 1) << 8); + } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) { + return pcnet_aprom_readb(d, addr) | + (pcnet_aprom_readb(d, addr + 1) << 8) | + (pcnet_aprom_readb(d, addr + 2) << 16) | + (pcnet_aprom_readb(d, addr + 3) << 24); + } + } else { + if (size == 2) { + return pcnet_ioport_readw(d, addr); + } else if (size == 4) { + return pcnet_ioport_readl(d, addr); + } } return ((uint64_t)1 << (size * 8)) - 1; } @@ -90,12 +103,24 @@ static void pcnet_ioport_write(void *opaque, target_phys_addr_t addr, { PCNetState *d = opaque; - if (addr < 16 && size == 1) { - return pcnet_aprom_writeb(d, addr, data); - } else if (addr >= 0x10 && addr < 0x20 && size == 2) { - return pcnet_ioport_writew(d, addr, data); - } else if (addr >= 0x10 && addr < 0x20 && size == 4) { - return pcnet_ioport_writel(d, addr, data); + if (addr < 0x10) { + if (!BCR_DWIO(d) && size == 1) { + pcnet_aprom_writeb(d, addr, data); + } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) { + pcnet_aprom_writeb(d, addr, data & 0xff); + pcnet_aprom_writeb(d, addr + 1, data >> 8); + } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) { + pcnet_aprom_writeb(d, addr, data & 0xff); + pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff); + pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff); + pcnet_aprom_writeb(d, addr + 3, data >> 24); + } + } else { + if (size == 2) { + pcnet_ioport_writew(d, addr, data); + } else if (size == 4) { + pcnet_ioport_writel(d, addr, data); + } } } @@ -230,13 +255,13 @@ static const MemoryRegionOps pcnet_mmio_ops = { static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap) { - cpu_physical_memory_write(addr, buf, len); + pci_dma_write(dma_opaque, addr, buf, len); } static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap) { - cpu_physical_memory_read(addr, buf, len); + pci_dma_read(dma_opaque, addr, buf, len); } static void pci_pcnet_cleanup(VLANClientState *nc) @@ -263,6 +288,7 @@ static NetClientInfo net_pci_pcnet_info = { .size = sizeof(NICState), .can_receive = pcnet_can_receive, .receive = pcnet_receive, + .link_status_changed = pcnet_set_link_status, .cleanup = pci_pcnet_cleanup, }; @@ -302,6 +328,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev) s->irq = pci_dev->irq[0]; s->phys_mem_read = pci_physical_memory_read; s->phys_mem_write = pci_physical_memory_write; + s->dma_opaque = pci_dev; if (!pci_dev->qdev.hotplugged) { static int loaded = 0; diff --git a/hw/pcnet.c b/hw/pcnet.c index cf16fd4d01..cba253ba7b 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -58,24 +58,6 @@ struct qemu_ether_header { uint16_t ether_type; }; -/* BUS CONFIGURATION REGISTERS */ -#define BCR_MSRDA 0 -#define BCR_MSWRA 1 -#define BCR_MC 2 -#define BCR_LNKST 4 -#define BCR_LED1 5 -#define BCR_LED2 6 -#define BCR_LED3 7 -#define BCR_FDC 9 -#define BCR_BSBC 18 -#define BCR_EECAS 19 -#define BCR_SWS 20 -#define BCR_PLAT 22 - -#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) -#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) -#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) - #define CSR_INIT(S) !!(((S)->csr[0])&0x0001) #define CSR_STRT(S) !!(((S)->csr[0])&0x0002) #define CSR_STOP(S) !!(((S)->csr[0])&0x0004) @@ -1215,6 +1197,13 @@ ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_) return size_; } +void pcnet_set_link_status(VLANClientState *nc) +{ + PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; + + d->lnkst = nc->link_down ? 0 : 0x40; +} + static void pcnet_transmit(PCNetState *s) { target_phys_addr_t xmit_cxda = 0; diff --git a/hw/pcnet.h b/hw/pcnet.h index cd86bde9d0..edc81c90ac 100644 --- a/hw/pcnet.h +++ b/hw/pcnet.h @@ -6,6 +6,25 @@ #include "memory.h" +/* BUS CONFIGURATION REGISTERS */ +#define BCR_MSRDA 0 +#define BCR_MSWRA 1 +#define BCR_MC 2 +#define BCR_LNKST 4 +#define BCR_LED1 5 +#define BCR_LED2 6 +#define BCR_LED3 7 +#define BCR_FDC 9 +#define BCR_BSBC 18 +#define BCR_EECAS 19 +#define BCR_SWS 20 +#define BCR_PLAT 22 + +#define BCR_APROMWE(S) !!((S)->bcr[BCR_MC ] & 0x0100) +#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) +#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) +#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) + typedef struct PCNetState_st PCNetState; struct PCNetState_st { @@ -39,6 +58,7 @@ uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr); uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); int pcnet_can_receive(VLANClientState *nc); ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_); +void pcnet_set_link_status(VLANClientState *nc); void pcnet_common_cleanup(PCNetState *d); int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info); extern const VMStateDescription vmstate_pcnet; @@ -662,6 +662,12 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__, decr, value); + + if (kvm_enabled()) { + /* KVM handles decrementer exceptions, we don't need our own timer */ + return; + } + now = qemu_get_clock_ns(vm_clock); next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq); if (is_excp) { diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 2db365d0b6..960a5d0c60 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -89,6 +89,7 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) PPCE500PCIState *pci = opaque; unsigned long win; uint32_t value = 0; + int idx; win = addr & 0xfe0; @@ -97,24 +98,44 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) case PPCE500_PCI_OW2: case PPCE500_PCI_OW3: case PPCE500_PCI_OW4: + idx = (addr >> 5) & 0x7; switch (addr & 0xC) { - case PCI_POTAR: value = pci->pob[(addr >> 5) & 0x7].potar; break; - case PCI_POTEAR: value = pci->pob[(addr >> 5) & 0x7].potear; break; - case PCI_POWBAR: value = pci->pob[(addr >> 5) & 0x7].powbar; break; - case PCI_POWAR: value = pci->pob[(addr >> 5) & 0x7].powar; break; - default: break; + case PCI_POTAR: + value = pci->pob[idx].potar; + break; + case PCI_POTEAR: + value = pci->pob[idx].potear; + break; + case PCI_POWBAR: + value = pci->pob[idx].powbar; + break; + case PCI_POWAR: + value = pci->pob[idx].powar; + break; + default: + break; } break; case PPCE500_PCI_IW3: case PPCE500_PCI_IW2: case PPCE500_PCI_IW1: + idx = ((addr >> 5) & 0x3) - 1; switch (addr & 0xC) { - case PCI_PITAR: value = pci->pib[(addr >> 5) & 0x3].pitar; break; - case PCI_PIWBAR: value = pci->pib[(addr >> 5) & 0x3].piwbar; break; - case PCI_PIWBEAR: value = pci->pib[(addr >> 5) & 0x3].piwbear; break; - case PCI_PIWAR: value = pci->pib[(addr >> 5) & 0x3].piwar; break; - default: break; + case PCI_PITAR: + value = pci->pib[idx].pitar; + break; + case PCI_PIWBAR: + value = pci->pib[idx].piwbar; + break; + case PCI_PIWBEAR: + value = pci->pib[idx].piwbear; + break; + case PCI_PIWAR: + value = pci->pib[idx].piwar; + break; + default: + break; }; break; @@ -142,6 +163,7 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, { PPCE500PCIState *pci = opaque; unsigned long win; + int idx; win = addr & 0xfe0; @@ -153,24 +175,44 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, case PPCE500_PCI_OW2: case PPCE500_PCI_OW3: case PPCE500_PCI_OW4: + idx = (addr >> 5) & 0x7; switch (addr & 0xC) { - case PCI_POTAR: pci->pob[(addr >> 5) & 0x7].potar = value; break; - case PCI_POTEAR: pci->pob[(addr >> 5) & 0x7].potear = value; break; - case PCI_POWBAR: pci->pob[(addr >> 5) & 0x7].powbar = value; break; - case PCI_POWAR: pci->pob[(addr >> 5) & 0x7].powar = value; break; - default: break; + case PCI_POTAR: + pci->pob[idx].potar = value; + break; + case PCI_POTEAR: + pci->pob[idx].potear = value; + break; + case PCI_POWBAR: + pci->pob[idx].powbar = value; + break; + case PCI_POWAR: + pci->pob[idx].powar = value; + break; + default: + break; }; break; case PPCE500_PCI_IW3: case PPCE500_PCI_IW2: case PPCE500_PCI_IW1: + idx = ((addr >> 5) & 0x3) - 1; switch (addr & 0xC) { - case PCI_PITAR: pci->pib[(addr >> 5) & 0x3].pitar = value; break; - case PCI_PIWBAR: pci->pib[(addr >> 5) & 0x3].piwbar = value; break; - case PCI_PIWBEAR: pci->pib[(addr >> 5) & 0x3].piwbear = value; break; - case PCI_PIWAR: pci->pib[(addr >> 5) & 0x3].piwar = value; break; - default: break; + case PCI_PITAR: + pci->pib[idx].pitar = value; + break; + case PCI_PIWBAR: + pci->pib[idx].piwbar = value; + break; + case PCI_PIWBEAR: + pci->pib[idx].piwbear = value; + break; + case PCI_PIWAR: + pci->pib[idx].piwar = value; + break; + default: + break; }; break; @@ -92,6 +92,7 @@ typedef struct { not the keyboard controller. */ int translate; int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ + int ledstate; } PS2KbdState; typedef struct { @@ -195,11 +196,17 @@ uint32_t ps2_read_data(void *opaque) return val; } +static void ps2_set_ledstate(PS2KbdState *s, int ledstate) +{ + s->ledstate = ledstate; + kbd_put_ledstate(ledstate); +} + static void ps2_reset_keyboard(PS2KbdState *s) { s->scan_enabled = 1; s->scancode_set = 2; - kbd_put_ledstate(0); + ps2_set_ledstate(s, 0); } void ps2_write_keyboard(void *opaque, int val) @@ -274,7 +281,7 @@ void ps2_write_keyboard(void *opaque, int val) s->common.write_cmd = -1; break; case KBD_CMD_SET_LEDS: - kbd_put_ledstate(val); + ps2_set_ledstate(s, val); ps2_queue(&s->common, KBD_REPLY_ACK); s->common.write_cmd = -1; break; @@ -557,6 +564,33 @@ static const VMStateDescription vmstate_ps2_common = { } }; +static bool ps2_keyboard_ledstate_needed(void *opaque) +{ + PS2KbdState *s = opaque; + + return s->ledstate != 0; /* 0 is default state */ +} + +static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) +{ + PS2KbdState *s = opaque; + + kbd_put_ledstate(s->ledstate); + return 0; +} + +static const VMStateDescription vmstate_ps2_keyboard_ledstate = { + .name = "ps2kbd/ledstate", + .version_id = 3, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .post_load = ps2_kbd_ledstate_post_load, + .fields = (VMStateField []) { + VMSTATE_INT32(ledstate, PS2KbdState), + VMSTATE_END_OF_LIST() + } +}; + static int ps2_kbd_post_load(void* opaque, int version_id) { PS2KbdState *s = (PS2KbdState*)opaque; @@ -578,6 +612,14 @@ static const VMStateDescription vmstate_ps2_keyboard = { VMSTATE_INT32(translate, PS2KbdState), VMSTATE_INT32_V(scancode_set, PS2KbdState,3), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_ps2_keyboard_ledstate, + .needed = ps2_keyboard_ledstate_needed, + }, { + /* empty */ + } } }; diff --git a/hw/qxl-render.c b/hw/qxl-render.c index c290739de0..2c51ba9806 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -28,16 +28,16 @@ static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) int len, i; src += (qxl->guest_primary.surface.height - rect->top - 1) * - qxl->guest_primary.stride; - dst += rect->top * qxl->guest_primary.stride; + qxl->guest_primary.abs_stride; + dst += rect->top * qxl->guest_primary.abs_stride; src += rect->left * qxl->guest_primary.bytes_pp; dst += rect->left * qxl->guest_primary.bytes_pp; len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp; for (i = rect->top; i < rect->bottom; i++) { memcpy(dst, src, len); - dst += qxl->guest_primary.stride; - src -= qxl->guest_primary.stride; + dst += qxl->guest_primary.abs_stride; + src -= qxl->guest_primary.abs_stride; } } @@ -45,7 +45,8 @@ void qxl_render_resize(PCIQXLDevice *qxl) { QXLSurfaceCreate *sc = &qxl->guest_primary.surface; - qxl->guest_primary.stride = sc->stride; + qxl->guest_primary.qxl_stride = sc->stride; + qxl->guest_primary.abs_stride = abs(sc->stride); qxl->guest_primary.resized++; switch (sc->format) { case SPICE_SURFACE_FMT_16_555: @@ -75,7 +76,14 @@ void qxl_render_update(PCIQXLDevice *qxl) VGACommonState *vga = &qxl->vga; QXLRect dirty[32], update; void *ptr; - int i; + int i, redraw = 0; + + if (!is_buffer_shared(vga->ds->surface)) { + dprint(qxl, 1, "%s: restoring shared displaysurface\n", __func__); + qxl->guest_primary.resized++; + qxl->guest_primary.commands++; + redraw = 1; + } if (qxl->guest_primary.resized) { qxl->guest_primary.resized = 0; @@ -87,11 +95,11 @@ void qxl_render_update(PCIQXLDevice *qxl) qemu_free_displaysurface(vga->ds); qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); - if (qxl->guest_primary.stride < 0) { + if (qxl->guest_primary.qxl_stride < 0) { /* spice surface is upside down -> need extra buffer to flip */ - qxl->guest_primary.stride = -qxl->guest_primary.stride; - qxl->guest_primary.flipped = g_malloc(qxl->guest_primary.surface.width * - qxl->guest_primary.stride); + qxl->guest_primary.flipped = + g_malloc(qxl->guest_primary.surface.width * + qxl->guest_primary.abs_stride); ptr = qxl->guest_primary.flipped; } else { ptr = qxl->guest_primary.data; @@ -100,7 +108,7 @@ void qxl_render_update(PCIQXLDevice *qxl) __FUNCTION__, qxl->guest_primary.surface.width, qxl->guest_primary.surface.height, - qxl->guest_primary.stride, + qxl->guest_primary.qxl_stride, qxl->guest_primary.bytes_pp, qxl->guest_primary.bits_pp, qxl->guest_primary.flipped ? "yes" : "no"); @@ -108,7 +116,7 @@ void qxl_render_update(PCIQXLDevice *qxl) qemu_create_displaysurface_from(qxl->guest_primary.surface.width, qxl->guest_primary.surface.height, qxl->guest_primary.bits_pp, - qxl->guest_primary.stride, + qxl->guest_primary.abs_stride, ptr); dpy_resize(vga->ds); } @@ -126,6 +134,10 @@ void qxl_render_update(PCIQXLDevice *qxl) memset(dirty, 0, sizeof(dirty)); qxl_spice_update_area(qxl, 0, &update, dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); + if (redraw) { + memset(dirty, 0, sizeof(dirty)); + dirty[0] = update; + } for (i = 0; i < ARRAY_SIZE(dirty); i++) { if (qemu_spice_rect_is_empty(dirty+i)) { @@ -1663,12 +1663,25 @@ static int qxl_pre_load(void *opaque) return 0; } +static void qxl_create_memslots(PCIQXLDevice *d) +{ + int i; + + for (i = 0; i < NUM_MEMSLOTS; i++) { + if (!d->guest_slots[i].active) { + continue; + } + dprint(d, 1, "%s: restoring guest slot %d\n", __func__, i); + qxl_add_memslot(d, i, 0, QXL_SYNC); + } +} + static int qxl_post_load(void *opaque, int version) { PCIQXLDevice* d = opaque; uint8_t *ram_start = d->vga.vram_ptr; QXLCommandExt *cmds; - int in, out, i, newmode; + int in, out, newmode; dprint(d, 1, "%s: start\n", __FUNCTION__); @@ -1685,19 +1698,16 @@ static int qxl_post_load(void *opaque, int version) qxl_mode_to_string(d->mode)); newmode = d->mode; d->mode = QXL_MODE_UNDEFINED; + switch (newmode) { case QXL_MODE_UNDEFINED: break; case QXL_MODE_VGA: + qxl_create_memslots(d); qxl_enter_vga_mode(d); break; case QXL_MODE_NATIVE: - for (i = 0; i < NUM_MEMSLOTS; i++) { - if (!d->guest_slots[i].active) { - continue; - } - qxl_add_memslot(d, i, 0, QXL_SYNC); - } + qxl_create_memslots(d); qxl_create_guest_primary(d, 1, QXL_SYNC); /* replay surface-create and cursor-set commands */ @@ -1722,6 +1732,8 @@ static int qxl_post_load(void *opaque, int version) break; case QXL_MODE_COMPAT: + /* note: no need to call qxl_create_memslots, qxl_set_mode + * creates the mem slot. */ qxl_set_mode(d, d->shadow_rom.mode, 1); break; } @@ -48,7 +48,8 @@ typedef struct PCIQXLDevice { QXLSurfaceCreate surface; uint32_t commands; uint32_t resized; - int32_t stride; + int32_t qxl_stride; + uint32_t abs_stride; uint32_t bits_pp; uint32_t bytes_pp; uint8_t *data, *flipped; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 37539508c5..4c379932e3 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -53,6 +53,7 @@ #include "hw.h" #include "pci.h" +#include "dma.h" #include "qemu-timer.h" #include "net.h" #include "loader.h" @@ -427,9 +428,6 @@ typedef struct RTL8139TallyCounters /* Clears all tally counters */ static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters); -/* Writes tally counters to specified physical memory address */ -static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters); - typedef struct RTL8139State { PCIDevice dev; uint8_t phys[8]; /* mac address */ @@ -512,6 +510,9 @@ typedef struct RTL8139State { int rtl8139_mmio_io_addr_dummy; } RTL8139State; +/* Writes tally counters to memory via DMA */ +static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr); + static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time); static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) @@ -773,15 +774,15 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) if (size > wrapped) { - cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, - buf, size-wrapped ); + pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, + buf, size-wrapped); } /* reset buffer pointer */ s->RxBufAddr = 0; - cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, - buf + (size-wrapped), wrapped ); + pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, + buf + (size-wrapped), wrapped); s->RxBufAddr = wrapped; @@ -790,13 +791,13 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) } /* non-wrapping path or overwrapping enabled */ - cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size ); + pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size); s->RxBufAddr += size; } #define MIN_BUF_SIZE 60 -static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) +static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high) { #if TARGET_PHYS_ADDR_BITS > 32 return low | ((target_phys_addr_t)high << 32); @@ -979,24 +980,24 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ /* w3 high 32bit of Rx buffer ptr */ int descriptor = s->currCPlusRxDesc; - target_phys_addr_t cplus_rx_ring_desc; + dma_addr_t cplus_rx_ring_desc; cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); cplus_rx_ring_desc += 16 * descriptor; DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at " - "%08x %08x = "TARGET_FMT_plx"\n", descriptor, s->RxRingAddrHI, + "%08x %08x = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc); uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; - cpu_physical_memory_read(cplus_rx_ring_desc, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4); rxdw0 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4); rxdw1 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_rx_ring_desc+8, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_rx_ring_desc+8, (uint8_t *)&val, 4); rxbufLO = le32_to_cpu(val); - cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_rx_ring_desc+12, (uint8_t *)&val, 4); rxbufHI = le32_to_cpu(val); DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", @@ -1060,16 +1061,16 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ return size_; } - target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); + dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); /* receive/copy to target memory */ if (dot1q_buf) { - cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN); - cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN, - buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN, - size - 2 * ETHER_ADDR_LEN); + pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN); + pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN, + buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN, + size - 2 * ETHER_ADDR_LEN); } else { - cpu_physical_memory_write(rx_addr, buf, size); + pci_dma_write(&s->dev, rx_addr, buf, size); } if (s->CpCmd & CPlusRxChkSum) @@ -1079,7 +1080,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ /* write checksum */ val = cpu_to_le32(crc32(0, buf, size_)); - cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4); + pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4); /* first segment of received packet flag */ #define CP_RX_STATUS_FS (1<<29) @@ -1125,9 +1126,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ /* update ring data */ val = cpu_to_le32(rxdw0); - cpu_physical_memory_write(cplus_rx_ring_desc, (uint8_t *)&val, 4); + pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4); val = cpu_to_le32(rxdw1); - cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4); /* update tally counter */ ++s->tally_counters.RxOk; @@ -1307,50 +1308,51 @@ static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) counters->TxUndrn = 0; } -static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters) +static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr) { + RTL8139TallyCounters *tally_counters = &s->tally_counters; uint16_t val16; uint32_t val32; uint64_t val64; val64 = cpu_to_le64(tally_counters->TxOk); - cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8); + pci_dma_write(&s->dev, tc_addr + 0, (uint8_t *)&val64, 8); val64 = cpu_to_le64(tally_counters->RxOk); - cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8); + pci_dma_write(&s->dev, tc_addr + 8, (uint8_t *)&val64, 8); val64 = cpu_to_le64(tally_counters->TxERR); - cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8); + pci_dma_write(&s->dev, tc_addr + 16, (uint8_t *)&val64, 8); val32 = cpu_to_le32(tally_counters->RxERR); - cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4); + pci_dma_write(&s->dev, tc_addr + 24, (uint8_t *)&val32, 4); val16 = cpu_to_le16(tally_counters->MissPkt); - cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2); + pci_dma_write(&s->dev, tc_addr + 28, (uint8_t *)&val16, 2); val16 = cpu_to_le16(tally_counters->FAE); - cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2); + pci_dma_write(&s->dev, tc_addr + 30, (uint8_t *)&val16, 2); val32 = cpu_to_le32(tally_counters->Tx1Col); - cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4); + pci_dma_write(&s->dev, tc_addr + 32, (uint8_t *)&val32, 4); val32 = cpu_to_le32(tally_counters->TxMCol); - cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4); + pci_dma_write(&s->dev, tc_addr + 36, (uint8_t *)&val32, 4); val64 = cpu_to_le64(tally_counters->RxOkPhy); - cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8); + pci_dma_write(&s->dev, tc_addr + 40, (uint8_t *)&val64, 8); val64 = cpu_to_le64(tally_counters->RxOkBrd); - cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8); + pci_dma_write(&s->dev, tc_addr + 48, (uint8_t *)&val64, 8); val32 = cpu_to_le32(tally_counters->RxOkMul); - cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4); + pci_dma_write(&s->dev, tc_addr + 56, (uint8_t *)&val32, 4); val16 = cpu_to_le16(tally_counters->TxAbt); - cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2); + pci_dma_write(&s->dev, tc_addr + 60, (uint8_t *)&val16, 2); val16 = cpu_to_le16(tally_counters->TxUndrn); - cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2); + pci_dma_write(&s->dev, tc_addr + 62, (uint8_t *)&val16, 2); } /* Loads values of tally counters from VM state file */ @@ -1842,7 +1844,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); - cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); + pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize); /* Mark descriptor as transferred */ s->TxStatus[descriptor] |= TxHostOwns; @@ -1963,25 +1965,24 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) int descriptor = s->currCPlusTxDesc; - target_phys_addr_t cplus_tx_ring_desc = - rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]); + dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]); /* Normal priority ring */ cplus_tx_ring_desc += 16 * descriptor; DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at " - "%08x0x%08x = 0x"TARGET_FMT_plx"\n", descriptor, s->TxAddr[1], + "%08x0x%08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; - cpu_physical_memory_read(cplus_tx_ring_desc, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4); txdw0 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_tx_ring_desc+4, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_tx_ring_desc+4, (uint8_t *)&val, 4); txdw1 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_tx_ring_desc+8, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_tx_ring_desc+8, (uint8_t *)&val, 4); txbufLO = le32_to_cpu(val); - cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); + pci_dma_read(&s->dev, cplus_tx_ring_desc+12, (uint8_t *)&val, 4); txbufHI = le32_to_cpu(val); DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor, @@ -2047,7 +2048,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) } int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK; - target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); + dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); /* make sure we have enough space to assemble the packet */ if (!s->cplus_txbuffer) @@ -2086,10 +2087,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* append more data to the packet */ DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at " - TARGET_FMT_plx" to offset %d\n", txsize, tx_addr, - s->cplus_txbuffer_offset); + DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr, + s->cplus_txbuffer_offset); - cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); + pci_dma_read(&s->dev, tx_addr, + s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); s->cplus_txbuffer_offset += txsize; /* seek to next Rx descriptor */ @@ -2116,7 +2118,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* update ring data */ val = cpu_to_le32(txdw0); - cpu_physical_memory_write(cplus_tx_ring_desc, (uint8_t *)&val, 4); + pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4); /* Now decide if descriptor being processed is holding the last segment of packet */ if (txdw0 & CP_TX_LS) @@ -2475,7 +2477,7 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); /* dump tally counters to specified memory location */ - RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters); + RTL8139TallyCounters_dma_write(s, tc_addr); /* mark dump completed */ s->TxStatus[0] &= ~0x8; diff --git a/hw/spapr.c b/hw/spapr.c index 63e5d336ea..bdaa938b6b 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -29,6 +29,9 @@ #include "elf.h" #include "net.h" #include "blockdev.h" +#include "cpus.h" +#include "kvm.h" +#include "kvm_ppc.h" #include "hw/boards.h" #include "hw/ppc.h" @@ -36,10 +39,12 @@ #include "hw/spapr.h" #include "hw/spapr_vio.h" +#include "hw/spapr_pci.h" #include "hw/xics.h" #include "kvm.h" #include "kvm_ppc.h" +#include "pci.h" #include "exec-memory.h" @@ -59,6 +64,11 @@ #define MAX_CPUS 256 #define XICS_IRQS 1024 +#define SPAPR_PCI_BUID 0x800000020000001ULL +#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) +#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000 +#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000) + #define PHANDLE_XICP 0x00001111 sPAPREnvironment *spapr; @@ -88,6 +98,7 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num) } static void *spapr_create_fdt_skel(const char *cpu_model, + target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *boot_device, @@ -96,7 +107,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, { void *fdt; CPUState *env; - uint64_t mem_reg_property[] = { 0, cpu_to_be64(ram_size) }; + uint64_t mem_reg_property_rma[] = { 0, cpu_to_be64(rma_size) }; + uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size), + cpu_to_be64(ram_size - rma_size) }; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; @@ -105,6 +118,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; + int smt = kvmppc_smt_threads(); #define _FDT(exp) \ do { \ @@ -139,17 +153,35 @@ static void *spapr_create_fdt_skel(const char *cpu_model, &end_prop, sizeof(end_prop)))); _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + /* + * Because we don't always invoke any firmware, we can't rely on + * that to do BAR allocation. Long term, we should probably do + * that ourselves, but for now, this setting (plus advertising the + * current BARs as 0) causes sufficiently recent kernels to to the + * BAR assignment themselves */ + _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0))); + _FDT((fdt_end_node(fdt))); - /* memory node */ + /* memory node(s) */ _FDT((fdt_begin_node(fdt, "memory@0"))); _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", - mem_reg_property, sizeof(mem_reg_property)))); - + _FDT((fdt_property(fdt, "reg", mem_reg_property_rma, + sizeof(mem_reg_property_rma)))); _FDT((fdt_end_node(fdt))); + if (ram_size > rma_size) { + char mem_name[32]; + + sprintf(mem_name, "memory@%" PRIx64, (uint64_t)rma_size); + _FDT((fdt_begin_node(fdt, mem_name))); + _FDT((fdt_property_string(fdt, "device_type", "memory"))); + _FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma, + sizeof(mem_reg_property_nonrma)))); + _FDT((fdt_end_node(fdt))); + } + /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -164,13 +196,18 @@ static void *spapr_create_fdt_skel(const char *cpu_model, for (env = first_cpu; env != NULL; env = env->next_cpu) { int index = env->cpu_index; - uint32_t gserver_prop[] = {cpu_to_be32(index), 0}; /* HACK! */ + uint32_t servers_prop[smp_threads]; + uint32_t gservers_prop[smp_threads * 2]; char *nodename; uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; + if ((index % smt) != 0) { + continue; + } + if (asprintf(&nodename, "%s@%x", modelname, index) < 0) { fprintf(stderr, "Allocation failure\n"); exit(1); @@ -195,15 +232,41 @@ static void *spapr_create_fdt_skel(const char *cpu_model, pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); - _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", index))); + + /* Build interrupt servers and gservers properties */ + for (i = 0; i < smp_threads; i++) { + servers_prop[i] = cpu_to_be32(index + i); + /* Hack, direct the group queues back to cpu 0 */ + gservers_prop[i*2] = cpu_to_be32(index + i); + gservers_prop[i*2 + 1] = 0; + } + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", + servers_prop, sizeof(servers_prop)))); _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", - gserver_prop, sizeof(gserver_prop)))); + gservers_prop, sizeof(gservers_prop)))); if (env->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", segs, sizeof(segs)))); } + /* Advertise VMX/VSX (vector extensions) if available + * 0 / no property == no vector extensions + * 1 == VMX / Altivec available + * 2 == VSX available */ + if (env->insns_flags & PPC_ALTIVEC) { + uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; + + _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx))); + } + + /* Advertise DFP (Decimal Floating Point) if available + * 0 / no property == no DFP + * 1 == DFP available */ + if (env->insns_flags2 & PPC2_DFP) { + _FDT((fdt_property_cell(fdt, "ibm,dfp", 1))); + } + _FDT((fdt_end_node(fdt))); } @@ -260,6 +323,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, { int ret; void *fdt; + sPAPRPHBState *phb; fdt = g_malloc(FDT_MAX_SIZE); @@ -272,6 +336,15 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, exit(1); } + QLIST_FOREACH(phb, &spapr->phbs, list) { + ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt); + } + + if (ret < 0) { + fprintf(stderr, "couldn't setup PCI devices in fdt\n"); + exit(1); + } + /* RTAS */ ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); if (ret < 0) { @@ -328,6 +401,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); + target_phys_addr_t rma_alloc_size, rma_size; uint32_t initrd_base; long kernel_size, initrd_size, fw_size; long pteg_shift = 17; @@ -336,15 +410,28 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr = g_malloc(sizeof(*spapr)); cpu_ppc_hypercall = emulate_spapr_hypercall; - /* We place the device tree just below either the top of RAM, or - * 2GB, so that it can be processed with 32-bit code if - * necessary */ - spapr->fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE; + /* Allocate RMA if necessary */ + rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem); + + if (rma_alloc_size == -1) { + hw_error("qemu: Unable to create RMA\n"); + exit(1); + } + if (rma_alloc_size && (rma_alloc_size < ram_size)) { + rma_size = rma_alloc_size; + } else { + rma_size = ram_size; + } + + /* We place the device tree just below either the top of the RMA, + * or just below 2GB, whichever is lowere, so that it can be + * processed with 32-bit real mode code if necessary */ + spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE; spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE; /* init CPUs */ if (cpu_model == NULL) { - cpu_model = "POWER7"; + cpu_model = kvm_enabled() ? "host" : "POWER7"; } for (i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); @@ -364,8 +451,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* allocate RAM */ spapr->ram_limit = ram_size; - memory_region_init_ram(ram, NULL, "ppc_spapr.ram", spapr->ram_limit); - memory_region_add_subregion(sysmem, 0, ram); + if (spapr->ram_limit > rma_alloc_size) { + ram_addr_t nonrma_base = rma_alloc_size; + ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size; + + memory_region_init_ram(ram, NULL, "ppc_spapr.ram", nonrma_size); + memory_region_add_subregion(sysmem, nonrma_base, ram); + } /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest @@ -411,6 +503,12 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } + /* Set up PCI */ + spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID, + SPAPR_PCI_MEM_WIN_ADDR, + SPAPR_PCI_MEM_WIN_SIZE, + SPAPR_PCI_IO_WIN_ADDR); + for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -421,10 +519,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, if (strcmp(nd->model, "ibmveth") == 0) { spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd); } else { - fprintf(stderr, "pSeries (sPAPR) platform does not support " - "NIC model '%s' (only ibmveth is supported)\n", - nd->model); - exit(1); + pci_nic_init_nofail(&nd_table[i], nd->model, NULL); } } @@ -489,7 +584,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, } /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, initrd_base, initrd_size, boot_device, kernel_cmdline, pteg_shift + 7); diff --git a/hw/spapr.h b/hw/spapr.h index 6657c336f6..df88f6abad 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -4,10 +4,12 @@ #include "hw/xics.h" struct VIOsPAPRBus; +struct sPAPRPHBState; struct icp_state; typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; + QLIST_HEAD(, sPAPRPHBState) phbs; struct icp_state *icp; target_phys_addr_t ram_limit; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c new file mode 100644 index 0000000000..7162588543 --- /dev/null +++ b/hw/spapr_pci.c @@ -0,0 +1,508 @@ +/* + * QEMU sPAPR PCI host originated from Uninorth PCI host + * + * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation. + * Copyright (C) 2011 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "pci.h" +#include "pci_host.h" +#include "hw/spapr.h" +#include "hw/spapr_pci.h" +#include "exec-memory.h" +#include <libfdt.h> + +#include "hw/pci_internals.h" + +static const uint32_t bars[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5 + /*, PCI_ROM_ADDRESS*/ +}; + +static PCIDevice *find_dev(sPAPREnvironment *spapr, + uint64_t buid, uint32_t config_addr) +{ + DeviceState *qdev; + int devfn = (config_addr >> 8) & 0xFF; + sPAPRPHBState *phb; + + QLIST_FOREACH(phb, &spapr->phbs, list) { + if (phb->buid != buid) { + continue; + } + + QTAILQ_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) { + PCIDevice *dev = (PCIDevice *)qdev; + if (dev->devfn == devfn) { + return dev; + } + } + } + + return NULL; +} + +static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); + PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + size = rtas_ld(args, 3); + addr = rtas_ld(args, 0) & 0xFF; + val = pci_default_read_config(dev, addr, size); + rtas_st(rets, 0, 0); + rtas_st(rets, 1, val); +} + +static void rtas_read_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + size = rtas_ld(args, 1); + addr = rtas_ld(args, 0) & 0xFF; + val = pci_default_read_config(dev, addr, size); + rtas_st(rets, 0, 0); + rtas_st(rets, 1, val); +} + +static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); + PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + val = rtas_ld(args, 4); + size = rtas_ld(args, 3); + addr = rtas_ld(args, 0) & 0xFF; + pci_default_write_config(dev, addr, val, size); + rtas_st(rets, 0, 0); +} + +static void rtas_write_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + val = rtas_ld(args, 2); + size = rtas_ld(args, 1); + addr = rtas_ld(args, 0) & 0xFF; + pci_default_write_config(dev, addr, val, size); + rtas_st(rets, 0, 0); +} + +static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) +{ + /* + * Here we need to convert pci_dev + irq_num to some unique value + * which is less than number of IRQs on the specific bus (now it + * is 16). At the moment irq_num == device_id (number of the + * slot?) + * FIXME: we should swizzle in fn and irq_num + */ + return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI; +} + +static void pci_spapr_set_irq(void *opaque, int irq_num, int level) +{ + /* + * Here we use the number returned by pci_spapr_map_irq to find a + * corresponding qemu_irq. + */ + sPAPRPHBState *phb = opaque; + + qemu_set_irq(phb->lsi_table[irq_num].qirq, level); +} + +static int spapr_phb_init(SysBusDevice *s) +{ + sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s); + int i; + + /* Initialize the LSI table */ + for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) { + qemu_irq qirq; + uint32_t num; + + qirq = spapr_allocate_irq(0, &num); + if (!qirq) { + return -1; + } + + phb->lsi_table[i].dt_irq = num; + phb->lsi_table[i].qirq = qirq; + } + + return 0; +} + +static int spapr_main_pci_host_init(PCIDevice *d) +{ + return 0; +} + +static PCIDeviceInfo spapr_main_pci_host_info = { + .qdev.name = "spapr-pci-host-bridge", + .qdev.size = sizeof(PCIDevice), + .init = spapr_main_pci_host_init, +}; + +static void spapr_register_devices(void) +{ + sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState), + spapr_phb_init); + pci_qdev_register(&spapr_main_pci_host_info); +} + +device_init(spapr_register_devices) + +static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + switch (size) { + case 1: + return cpu_inb(addr); + case 2: + return cpu_inw(addr); + case 4: + return cpu_inl(addr); + } + assert(0); +} + +static void spapr_io_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + switch (size) { + case 1: + cpu_outb(addr, data); + return; + case 2: + cpu_outw(addr, data); + return; + case 4: + cpu_outl(addr, data); + return; + } + assert(0); +} + +static MemoryRegionOps spapr_io_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + .read = spapr_io_read, + .write = spapr_io_write +}; + +void spapr_create_phb(sPAPREnvironment *spapr, + const char *busname, uint64_t buid, + uint64_t mem_win_addr, uint64_t mem_win_size, + uint64_t io_win_addr) +{ + DeviceState *dev; + SysBusDevice *s; + sPAPRPHBState *phb; + PCIBus *bus; + char namebuf[strlen(busname)+11]; + + dev = qdev_create(NULL, "spapr-pci-host-bridge"); + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + phb = FROM_SYSBUS(sPAPRPHBState, s); + + phb->mem_win_addr = mem_win_addr; + + sprintf(namebuf, "%s-mem", busname); + memory_region_init(&phb->memspace, namebuf, INT64_MAX); + + sprintf(namebuf, "%s-memwindow", busname); + memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace, + SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size); + memory_region_add_subregion(get_system_memory(), mem_win_addr, + &phb->memwindow); + + phb->io_win_addr = io_win_addr; + + /* On ppc, we only have MMIO no specific IO space from the CPU + * perspective. In theory we ought to be able to embed the PCI IO + * memory region direction in the system memory space. However, + * if any of the IO BAR subregions use the old_portio mechanism, + * that won't be processed properly unless accessed from the + * system io address space. This hack to bounce things via + * system_io works around the problem until all the users of + * old_portion are updated */ + sprintf(namebuf, "%s-io", busname); + memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); + /* FIXME: fix to support multiple PHBs */ + memory_region_add_subregion(get_system_io(), 0, &phb->iospace); + + sprintf(namebuf, "%s-iowindow", busname); + memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb, + namebuf, SPAPR_PCI_IO_WIN_SIZE); + memory_region_add_subregion(get_system_memory(), io_win_addr, + &phb->iowindow); + + phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname, + pci_spapr_set_irq, + pci_spapr_map_irq, + phb, + &phb->memspace, &phb->iospace, + PCI_DEVFN(0, 0), + SPAPR_PCI_NUM_LSI); + + spapr_rtas_register("read-pci-config", rtas_read_pci_config); + spapr_rtas_register("write-pci-config", rtas_write_pci_config); + spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); + spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config); + + QLIST_INSERT_HEAD(&spapr->phbs, phb, list); + + /* pci_bus_set_mem_base(bus, mem_va_start - SPAPR_PCI_MEM_BAR_START); */ +} + +/* Macros to operate with address in OF binding to PCI */ +#define b_x(x, p, l) (((x) & ((1<<(l))-1)) << (p)) +#define b_n(x) b_x((x), 31, 1) /* 0 if relocatable */ +#define b_p(x) b_x((x), 30, 1) /* 1 if prefetchable */ +#define b_t(x) b_x((x), 29, 1) /* 1 if the address is aliased */ +#define b_ss(x) b_x((x), 24, 2) /* the space code */ +#define b_bbbbbbbb(x) b_x((x), 16, 8) /* bus number */ +#define b_ddddd(x) b_x((x), 11, 5) /* device number */ +#define b_fff(x) b_x((x), 8, 3) /* function number */ +#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ + +static uint32_t regtype_to_ss(uint8_t type) +{ + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + return 3; + } + if (type == PCI_BASE_ADDRESS_SPACE_IO) { + return 1; + } + return 2; +} + +int spapr_populate_pci_devices(sPAPRPHBState *phb, + uint32_t xics_phandle, + void *fdt) +{ + PCIBus *bus = phb->host_state.bus; + int bus_off, node_off = 0, devid, fn, i, n, devices; + DeviceState *qdev; + char nodename[256]; + struct { + uint32_t hi; + uint64_t addr; + uint64_t size; + } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1], + assigned_addresses[PCI_NUM_REGIONS]; + uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; + struct { + uint32_t hi; + uint64_t child; + uint64_t parent; + uint64_t size; + } __attribute__((packed)) ranges[] = { + { + cpu_to_be32(b_ss(1)), cpu_to_be64(0), + cpu_to_be64(phb->io_win_addr), + cpu_to_be64(memory_region_size(&phb->iospace)), + }, + { + cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET), + cpu_to_be64(phb->mem_win_addr), + cpu_to_be64(memory_region_size(&phb->memwindow)), + }, + }; + uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; + uint32_t interrupt_map_mask[] = { + cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0}; + uint32_t interrupt_map[bus->nirq][7]; + + /* Start populating the FDT */ + sprintf(nodename, "pci@%" PRIx64, phb->buid); + bus_off = fdt_add_subnode(fdt, 0, nodename); + if (bus_off < 0) { + return bus_off; + } + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + return ret; \ + } \ + } while (0) + + /* Write PHB properties */ + _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci")); + _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB")); + _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3)); + _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2)); + _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1)); + _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0)); + _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range))); + _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges))); + _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); + _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", + &interrupt_map_mask, sizeof(interrupt_map_mask))); + + /* Populate PCI devices and allocate IRQs */ + devices = 0; + QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) { + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); + int irq_index = pci_spapr_map_irq(dev, 0); + uint32_t *irqmap = interrupt_map[devices]; + uint8_t *config = dev->config; + + devid = dev->devfn >> 3; + fn = dev->devfn & 7; + + sprintf(nodename, "pci@%u,%u", devid, fn); + + /* Allocate interrupt from the map */ + if (devid > bus->nirq) { + printf("Unexpected behaviour in spapr_populate_pci_devices," + "wrong devid %u\n", devid); + exit(-1); + } + irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn)); + irqmap[1] = 0; + irqmap[2] = 0; + irqmap[3] = 0; + irqmap[4] = cpu_to_be32(xics_phandle); + irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq); + irqmap[6] = cpu_to_be32(0x8); + + /* Add node to FDT */ + node_off = fdt_add_subnode(fdt, bus_off, nodename); + if (node_off < 0) { + return node_off; + } + + _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id", + pci_get_word(&config[PCI_VENDOR_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "device-id", + pci_get_word(&config[PCI_DEVICE_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "revision-id", + pci_get_byte(&config[PCI_REVISION_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "class-code", + pci_get_long(&config[PCI_CLASS_REVISION]) >> 8)); + _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id", + pci_get_word(&config[PCI_SUBSYSTEM_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id", + pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID]))); + + /* Config space region comes first */ + reg[0].hi = cpu_to_be32( + b_n(0) | + b_p(0) | + b_t(0) | + b_ss(0/*config*/) | + b_bbbbbbbb(0) | + b_ddddd(devid) | + b_fff(fn)); + reg[0].addr = 0; + reg[0].size = 0; + + n = 0; + for (i = 0; i < PCI_NUM_REGIONS; ++i) { + if (0 == dev->io_regions[i].size) { + continue; + } + + reg[n+1].hi = cpu_to_be32( + b_n(0) | + b_p(0) | + b_t(0) | + b_ss(regtype_to_ss(dev->io_regions[i].type)) | + b_bbbbbbbb(0) | + b_ddddd(devid) | + b_fff(fn) | + b_rrrrrrrr(bars[i])); + reg[n+1].addr = 0; + reg[n+1].size = cpu_to_be64(dev->io_regions[i].size); + + assigned_addresses[n].hi = cpu_to_be32( + b_n(1) | + b_p(0) | + b_t(0) | + b_ss(regtype_to_ss(dev->io_regions[i].type)) | + b_bbbbbbbb(0) | + b_ddddd(devid) | + b_fff(fn) | + b_rrrrrrrr(bars[i])); + + /* + * Writing zeroes to assigned_addresses causes the guest kernel to + * reassign BARs + */ + assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr); + assigned_addresses[n].size = reg[n+1].size; + + ++n; + } + _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1))); + _FDT(fdt_setprop(fdt, node_off, "assigned-addresses", + assigned_addresses, + sizeof(assigned_addresses[0])*(n))); + _FDT(fdt_setprop_cell(fdt, node_off, "interrupts", + pci_get_byte(&config[PCI_INTERRUPT_PIN]))); + + ++devices; + } + + /* Write interrupt map */ + _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, + devices * sizeof(interrupt_map[0]))); + + return 0; +} diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h new file mode 100644 index 0000000000..213340c915 --- /dev/null +++ b/hw/spapr_pci.h @@ -0,0 +1,61 @@ +/* + * QEMU SPAPR PCI BUS definitions + * + * Copyright (c) 2011 Alexey Kardashevskiy <aik@au1.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#if !defined(__HW_SPAPR_H__) +#error Please include spapr.h before this file! +#endif + +#if !defined(__HW_SPAPR_PCI_H__) +#define __HW_SPAPR_PCI_H__ + +#include "hw/pci_host.h" +#include "hw/xics.h" + +#define SPAPR_PCI_NUM_LSI 16 + +typedef struct sPAPRPHBState { + SysBusDevice busdev; + PCIHostState host_state; + + uint64_t buid; + + MemoryRegion memspace, iospace; + target_phys_addr_t mem_win_addr, io_win_addr; + MemoryRegion memwindow, iowindow; + + struct { + uint32_t dt_irq; + qemu_irq qirq; + } lsi_table[SPAPR_PCI_NUM_LSI]; + + QLIST_ENTRY(sPAPRPHBState) list; +} sPAPRPHBState; + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + +void spapr_create_phb(sPAPREnvironment *spapr, + const char *busname, uint64_t buid, + uint64_t mem_win_addr, uint64_t mem_win_size, + uint64_t io_win_addr); + +int spapr_populate_pci_devices(sPAPRPHBState *phb, + uint32_t xics_phandle, + void *fdt); + +#endif /* __HW_SPAPR_PCI_H__ */ diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 977603f81e..25cfc9d912 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -165,7 +165,13 @@ static void rtce_init(VIOsPAPRDevice *dev) * sizeof(VIOsPAPR_RTCE); if (size) { - dev->rtce_table = g_malloc0(size); + dev->rtce_table = kvmppc_create_spapr_tce(dev->reg, + dev->rtce_window_size, + &dev->kvmtce_fd); + + if (!dev->rtce_table) { + dev->rtce_table = g_malloc0(size); + } } } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 4fe5f742c2..a325a5f4b3 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -57,6 +57,7 @@ typedef struct VIOsPAPRDevice { target_ulong signal_state; uint32_t rtce_window_size; VIOsPAPR_RTCE *rtce_table; + int kvmtce_fd; VIOsPAPR_CRQ crq; } VIOsPAPRDevice; diff --git a/hw/sysbus.c b/hw/sysbus.c index 4fab5a41b2..fd2fc6a51d 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -198,6 +198,7 @@ DeviceState *sysbus_create_varargs(const char *name, sysbus_connect_irq(s, n, irq); n++; } + va_end(va); return dev; } @@ -229,6 +230,7 @@ DeviceState *sysbus_try_create_varargs(const char *name, sysbus_connect_irq(s, n, irq); n++; } + va_end(va); return dev; } diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index bd374c1de6..cdd5aae1e9 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1101,12 +1101,13 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) // TODO : Put in common header file, duplication from usb-ohci.c /* Get an array of dwords from main memory */ -static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) +static inline int get_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) { int i; for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - cpu_physical_memory_rw(addr,(uint8_t *)buf, sizeof(*buf), 0); + pci_dma_read(&ehci->dev, addr, (uint8_t *)buf, sizeof(*buf)); *buf = le32_to_cpu(*buf); } @@ -1114,13 +1115,14 @@ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) } /* Put an array of dwords in to main memory */ -static inline int put_dwords(uint32_t addr, uint32_t *buf, int num) +static inline int put_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) { int i; for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint32_t tmp = cpu_to_le32(*buf); - cpu_physical_memory_rw(addr,(uint8_t *)&tmp, sizeof(tmp), 1); + pci_dma_write(&ehci->dev, addr, (uint8_t *)&tmp, sizeof(tmp)); } return 1; @@ -1169,7 +1171,8 @@ static int ehci_qh_do_overlay(EHCIQueue *q) q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK; q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK; - put_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); + put_dwords(q->ehci, NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, + sizeof(EHCIqh) >> 2); return 0; } @@ -1177,12 +1180,12 @@ static int ehci_qh_do_overlay(EHCIQueue *q) static int ehci_init_transfer(EHCIQueue *q) { uint32_t cpage, offset, bytes, plen; - target_phys_addr_t page; + dma_addr_t page; cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); bytes = get_field(q->qh.token, QTD_TOKEN_TBYTES); offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK; - qemu_sglist_init(&q->sgl, 5); + pci_dma_sglist_init(&q->sgl, &q->ehci->dev, 5); while (bytes > 0) { if (cpage > 4) { @@ -1428,7 +1431,7 @@ static int ehci_process_itd(EHCIState *ehci, return USB_RET_PROCERR; } - qemu_sglist_init(&ehci->isgl, 2); + pci_dma_sglist_init(&ehci->isgl, &ehci->dev, 2); if (off + len > 4096) { /* transfer crosses page border */ uint32_t len2 = off + len - 4096; @@ -1532,7 +1535,8 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) /* Find the head of the list (4.9.1.1) */ for(i = 0; i < MAX_QH; i++) { - get_dwords(NLPTR_GET(entry), (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh, + sizeof(EHCIqh) >> 2); ehci_trace_qh(NULL, NLPTR_GET(entry), &qh); if (qh.epchar & QH_EPCHAR_H) { @@ -1629,7 +1633,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) goto out; } - get_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); + get_dwords(ehci, NLPTR_GET(q->qhaddr), + (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); if (q->async == EHCI_ASYNC_INFLIGHT) { @@ -1698,7 +1703,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); - get_dwords(NLPTR_GET(entry),(uint32_t *) &itd, + get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, sizeof(EHCIitd) >> 2); ehci_trace_itd(ehci, entry, &itd); @@ -1706,8 +1711,8 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) return -1; } - put_dwords(NLPTR_GET(entry), (uint32_t *) &itd, - sizeof(EHCIitd) >> 2); + put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, + sizeof(EHCIitd) >> 2); ehci_set_fetch_addr(ehci, async, itd.next); ehci_set_state(ehci, async, EST_FETCHENTRY); @@ -1722,7 +1727,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); - get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd, + get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd, sizeof(EHCIsitd) >> 2); ehci_trace_sitd(ehci, entry, &sitd); @@ -1784,7 +1789,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q, int async) { int again = 0; - get_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qtd, sizeof(EHCIqtd) >> 2); + get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qtd, + sizeof(EHCIqtd) >> 2); ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd); if (q->qtd.token & QTD_TOKEN_ACTIVE) { @@ -1827,7 +1833,7 @@ static void ehci_flush_qh(EHCIQueue *q) uint32_t dwords = sizeof(EHCIqh) >> 2; uint32_t addr = NLPTR_GET(q->qhaddr); - put_dwords(addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); + put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); } static int ehci_state_execute(EHCIQueue *q, int async) @@ -1947,8 +1953,8 @@ static int ehci_state_writeback(EHCIQueue *q, int async) /* Write back the QTD from the QH area */ ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd); - put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd, - sizeof(EHCIqtd) >> 2); + put_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qh.next_qtd, + sizeof(EHCIqtd) >> 2); /* * EHCI specs say go horizontal here. @@ -2148,7 +2154,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } list |= ((ehci->frindex & 0x1ff8) >> 1); - cpu_physical_memory_rw(list, (uint8_t *) &entry, sizeof entry, 0); + pci_dma_read(&ehci->dev, list, (uint8_t *) &entry, sizeof entry); entry = le32_to_cpu(entry); DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n", diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 09c65160c2..3eb0f1aa0a 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -127,8 +127,8 @@ static const USBDescDevice desc_device_hub = { static const USBDesc desc_hub = { .id = { - .idVendor = 0, - .idProduct = 0, + .idVendor = 0x0409, + .idProduct = 0x55aa, .bcdDevice = 0x0101, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT, @@ -163,6 +163,7 @@ static void usb_hub_attach(USBPort *port1) } else { port->wPortStatus &= ~PORT_STAT_LOW_SPEED; } + usb_wakeup(&s->dev); } static void usb_hub_detach(USBPort *port1) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 1a0815a136..b7341778e6 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -162,8 +162,8 @@ static const USBDescDevice desc_device_high = { static const USBDesc desc = { .id = { - .idVendor = 0, - .idProduct = 0, + .idVendor = 0x46f4, /* CRC16() of "QEMU" */ + .idProduct = 0x0001, .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT, diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 171d7870b7..f9e3ea5bfc 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -178,7 +178,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s) async->done = 0; async->isoc = 0; usb_packet_init(&async->packet); - qemu_sglist_init(&async->sgl, 1); + pci_dma_sglist_init(&async->sgl, &s->dev, 1); return async; } @@ -876,7 +876,7 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) uint32_t link = async->td; uint32_t int_mask = 0, val; - cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td)); + pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &td, sizeof(td)); le32_to_cpus(&td.link); le32_to_cpus(&td.ctrl); le32_to_cpus(&td.token); @@ -888,8 +888,8 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) /* update the status bits of the TD */ val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, sizeof(val)); + pci_dma_write(&s->dev, (link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); uhci_async_free(s, async); } else { async->done = 1; @@ -952,7 +952,7 @@ static void uhci_process_frame(UHCIState *s) DPRINTF("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr); - cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); + pci_dma_read(&s->dev, frame_addr, (uint8_t *)&link, 4); le32_to_cpus(&link); int_mask = 0; @@ -976,7 +976,7 @@ static void uhci_process_frame(UHCIState *s) break; } - cpu_physical_memory_read(link & ~0xf, (uint8_t *) &qh, sizeof(qh)); + pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &qh, sizeof(qh)); le32_to_cpus(&qh.link); le32_to_cpus(&qh.el_link); @@ -996,7 +996,7 @@ static void uhci_process_frame(UHCIState *s) } /* TD */ - cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td)); + pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &td, sizeof(td)); le32_to_cpus(&td.link); le32_to_cpus(&td.ctrl); le32_to_cpus(&td.token); @@ -1010,8 +1010,8 @@ static void uhci_process_frame(UHCIState *s) if (old_td_ctrl != td.ctrl) { /* update the status bits of the TD */ val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, sizeof(val)); + pci_dma_write(&s->dev, (link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); } if (ret < 0) { @@ -1039,8 +1039,8 @@ static void uhci_process_frame(UHCIState *s) /* update QH element link */ qh.el_link = link; val = cpu_to_le32(qh.el_link); - cpu_physical_memory_write((curr_qh & ~0xf) + 4, - (const uint8_t *)&val, sizeof(val)); + pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); if (!depth_first(link)) { /* done with this QH */ diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 2a5d1a92b3..19e89e71ee 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -16,6 +16,7 @@ #include "trace.h" #include "blockdev.h" #include "virtio-blk.h" +#include "scsi-defs.h" #ifdef __linux__ # include <scsi/sg.h> #endif @@ -231,7 +232,20 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) status = VIRTIO_BLK_S_OK; } - stl_p(&req->scsi->errors, hdr.status); + /* + * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi) + * clear the masked_status field [hence status gets cleared too, see + * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED + * status has occurred. However they do set DRIVER_SENSE in driver_status + * field. Also a (sb_len_wr > 0) indicates there is a sense buffer. + */ + if (hdr.status == 0 && hdr.sb_len_wr > 0) { + hdr.status = CHECK_CONDITION; + } + + stl_p(&req->scsi->errors, + hdr.status | (hdr.msg_status << 8) | + (hdr.host_status << 16) | (hdr.driver_status << 24)); stl_p(&req->scsi->residual, hdr.resid); stl_p(&req->scsi->sense_len, hdr.sb_len_wr); stl_p(&req->scsi->data_len, hdr.dxfer_len); diff --git a/ia64-dis.c b/ia64-dis.c index 2886df3614..2a103e6b5c 100644 --- a/ia64-dis.c +++ b/ia64-dis.c @@ -781,6 +781,9 @@ ext_inc3 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) return 0; } +/* glib.h defines ABS so we must undefine it to avoid a clash */ +#undef ABS + #define CST IA64_OPND_CLASS_CST #define REG IA64_OPND_CLASS_REG #define IND IA64_OPND_CLASS_IND diff --git a/int128.h b/int128.h new file mode 100644 index 0000000000..b3864b6cd4 --- /dev/null +++ b/int128.h @@ -0,0 +1,116 @@ +#ifndef INT128_H +#define INT128_H + +typedef struct Int128 Int128; + +struct Int128 { + uint64_t lo; + int64_t hi; +}; + +static inline Int128 int128_make64(uint64_t a) +{ + return (Int128) { a, 0 }; +} + +static inline uint64_t int128_get64(Int128 a) +{ + assert(!a.hi); + return a.lo; +} + +static inline Int128 int128_zero(void) +{ + return int128_make64(0); +} + +static inline Int128 int128_one(void) +{ + return int128_make64(1); +} + +static inline Int128 int128_2_64(void) +{ + return (Int128) { 0, 1 }; +} + +static inline Int128 int128_add(Int128 a, Int128 b) +{ + Int128 r = { a.lo + b.lo, a.hi + b.hi }; + r.hi += (r.lo < a.lo) || (r.lo < b.lo); + return r; +} + +static inline Int128 int128_neg(Int128 a) +{ + a.lo = ~a.lo; + a.hi = ~a.hi; + return int128_add(a, int128_one()); +} + +static inline Int128 int128_sub(Int128 a, Int128 b) +{ + return int128_add(a, int128_neg(b)); +} + +static inline bool int128_nonneg(Int128 a) +{ + return a.hi >= 0; +} + +static inline bool int128_eq(Int128 a, Int128 b) +{ + return a.lo == b.lo && a.hi == b.hi; +} + +static inline bool int128_ne(Int128 a, Int128 b) +{ + return !int128_eq(a, b); +} + +static inline bool int128_ge(Int128 a, Int128 b) +{ + return int128_nonneg(int128_sub(a, b)); +} + +static inline bool int128_lt(Int128 a, Int128 b) +{ + return !int128_ge(a, b); +} + +static inline bool int128_le(Int128 a, Int128 b) +{ + return int128_ge(b, a); +} + +static inline bool int128_gt(Int128 a, Int128 b) +{ + return !int128_le(a, b); +} + +static inline bool int128_nz(Int128 a) +{ + return a.lo || a.hi; +} + +static inline Int128 int128_min(Int128 a, Int128 b) +{ + return int128_le(a, b) ? a : b; +} + +static inline Int128 int128_max(Int128 a, Int128 b) +{ + return int128_ge(a, b) ? a : b; +} + +static inline void int128_addto(Int128 *a, Int128 b) +{ + *a = int128_add(*a, b); +} + +static inline void int128_subfrom(Int128 *a, Int128 b) +{ + *a = int128_sub(*a, b); +} + +#endif @@ -740,6 +740,7 @@ int kvm_init(void) fprintf(stderr, "Please add the 'switch_amode' kernel parameter to " "your host kernel command line\n"); #endif + ret = s->vmfd; goto err; } @@ -798,7 +799,7 @@ int kvm_init(void) err: if (s) { - if (s->vmfd != -1) { + if (s->vmfd >= 0) { close(s->vmfd); } if (s->fd != -1) { @@ -28,43 +28,48 @@ typedef struct AddrRange AddrRange; * (large MemoryRegion::alias_offset). */ struct AddrRange { - int64_t start; - int64_t size; + Int128 start; + Int128 size; }; -static AddrRange addrrange_make(int64_t start, int64_t size) +static AddrRange addrrange_make(Int128 start, Int128 size) { return (AddrRange) { start, size }; } static bool addrrange_equal(AddrRange r1, AddrRange r2) { - return r1.start == r2.start && r1.size == r2.size; + return int128_eq(r1.start, r2.start) && int128_eq(r1.size, r2.size); } -static int64_t addrrange_end(AddrRange r) +static Int128 addrrange_end(AddrRange r) { - return r.start + r.size; + return int128_add(r.start, r.size); } -static AddrRange addrrange_shift(AddrRange range, int64_t delta) +static AddrRange addrrange_shift(AddrRange range, Int128 delta) { - range.start += delta; + int128_addto(&range.start, delta); return range; } +static bool addrrange_contains(AddrRange range, Int128 addr) +{ + return int128_ge(addr, range.start) + && int128_lt(addr, addrrange_end(range)); +} + 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 addrrange_contains(r1, r2.start) + || addrrange_contains(r2, r1.start); } static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2) { - int64_t start = MAX(r1.start, r2.start); - /* off-by-one arithmetic to prevent overflow */ - int64_t end = MIN(addrrange_end(r1) - 1, addrrange_end(r2) - 1); - return addrrange_make(start, end - start + 1); + Int128 start = int128_max(r1.start, r2.start); + Int128 end = int128_min(addrrange_end(r1), addrrange_end(r2)); + return addrrange_make(start, int128_sub(end, start)); } struct CoalescedMemoryRange { @@ -82,13 +87,13 @@ struct MemoryRegionIoeventfd { static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a, MemoryRegionIoeventfd b) { - if (a.addr.start < b.addr.start) { + if (int128_lt(a.addr.start, b.addr.start)) { return true; - } else if (a.addr.start > b.addr.start) { + } else if (int128_gt(a.addr.start, b.addr.start)) { return false; - } else if (a.addr.size < b.addr.size) { + } else if (int128_lt(a.addr.size, b.addr.size)) { return true; - } else if (a.addr.size > b.addr.size) { + } else if (int128_gt(a.addr.size, b.addr.size)) { return false; } else if (a.match_data < b.match_data) { return true; @@ -201,9 +206,11 @@ static void flatview_destroy(FlatView *view) static bool can_merge(FlatRange *r1, FlatRange *r2) { - return addrrange_end(r1->addr) == r2->addr.start + return int128_eq(addrrange_end(r1->addr), r2->addr.start) && r1->mr == r2->mr - && r1->offset_in_region + r1->addr.size == r2->offset_in_region + && int128_eq(int128_add(int128_make64(r1->offset_in_region), + r1->addr.size), + int128_make64(r2->offset_in_region)) && r1->dirty_log_mask == r2->dirty_log_mask && r1->readable == r2->readable && r1->readonly == r2->readonly; @@ -219,7 +226,7 @@ static void flatview_simplify(FlatView *view) j = i + 1; while (j < view->nr && can_merge(&view->ranges[j-1], &view->ranges[j])) { - view->ranges[i].addr.size += view->ranges[j].addr.size; + int128_addto(&view->ranges[i].addr.size, view->ranges[j].addr.size); ++j; } ++i; @@ -314,8 +321,8 @@ static void as_memory_range_add(AddressSpace *as, FlatRange *fr) phys_offset |= IO_MEM_ROM; } - cpu_register_physical_memory_log(fr->addr.start, - fr->addr.size, + cpu_register_physical_memory_log(int128_get64(fr->addr.start), + int128_get64(fr->addr.size), phys_offset, region_offset, fr->dirty_log_mask); @@ -324,30 +331,35 @@ static void as_memory_range_add(AddressSpace *as, FlatRange *fr) static void as_memory_range_del(AddressSpace *as, FlatRange *fr) { if (fr->dirty_log_mask) { - cpu_physical_sync_dirty_bitmap(fr->addr.start, - fr->addr.start + fr->addr.size); + Int128 end = addrrange_end(fr->addr); + cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), + int128_get64(end)); } - cpu_register_physical_memory(fr->addr.start, fr->addr.size, + cpu_register_physical_memory(int128_get64(fr->addr.start), + int128_get64(fr->addr.size), IO_MEM_UNASSIGNED); } static void as_memory_log_start(AddressSpace *as, FlatRange *fr) { - cpu_physical_log_start(fr->addr.start, fr->addr.size); + cpu_physical_log_start(int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); } static void as_memory_log_stop(AddressSpace *as, FlatRange *fr) { - cpu_physical_log_stop(fr->addr.start, fr->addr.size); + cpu_physical_log_stop(int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); } static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd) { int r; - assert(fd->match_data && fd->addr.size == 4); + assert(fd->match_data && int128_get64(fd->addr.size) == 4); - r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, true); + r = kvm_set_ioeventfd_mmio_long(fd->fd, int128_get64(fd->addr.start), + fd->data, true); if (r < 0) { abort(); } @@ -357,7 +369,8 @@ static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd) { int r; - r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, false); + r = kvm_set_ioeventfd_mmio_long(fd->fd, int128_get64(fd->addr.start), + fd->data, false); if (r < 0) { abort(); } @@ -453,22 +466,24 @@ static const IORangeOps memory_region_iorange_ops = { static void as_io_range_add(AddressSpace *as, FlatRange *fr) { iorange_init(&fr->mr->iorange, &memory_region_iorange_ops, - fr->addr.start,fr->addr.size); + int128_get64(fr->addr.start), int128_get64(fr->addr.size)); ioport_register(&fr->mr->iorange); } static void as_io_range_del(AddressSpace *as, FlatRange *fr) { - isa_unassign_ioport(fr->addr.start, fr->addr.size); + isa_unassign_ioport(int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); } static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd) { int r; - assert(fd->match_data && fd->addr.size == 2); + assert(fd->match_data && int128_get64(fd->addr.size) == 2); - r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, true); + r = kvm_set_ioeventfd_pio_word(fd->fd, int128_get64(fd->addr.start), + fd->data, true); if (r < 0) { abort(); } @@ -478,7 +493,8 @@ static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd) { int r; - r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, false); + r = kvm_set_ioeventfd_pio_word(fd->fd, int128_get64(fd->addr.start), + fd->data, false); if (r < 0) { abort(); } @@ -500,19 +516,19 @@ static AddressSpace address_space_io = { */ static void render_memory_region(FlatView *view, MemoryRegion *mr, - target_phys_addr_t base, + Int128 base, AddrRange clip, bool readonly) { MemoryRegion *subregion; unsigned i; target_phys_addr_t offset_in_region; - int64_t remain; - int64_t now; + Int128 remain; + Int128 now; FlatRange fr; AddrRange tmp; - base += mr->addr; + int128_addto(&base, int128_make64(mr->addr)); readonly |= mr->readonly; tmp = addrrange_make(base, mr->size); @@ -524,8 +540,8 @@ static void render_memory_region(FlatView *view, clip = addrrange_intersection(tmp, clip); if (mr->alias) { - base -= mr->alias->addr; - base -= mr->alias_offset; + int128_subfrom(&base, int128_make64(mr->alias->addr)); + int128_subfrom(&base, int128_make64(mr->alias_offset)); render_memory_region(view, mr->alias, base, clip, readonly); return; } @@ -539,17 +555,18 @@ static void render_memory_region(FlatView *view, return; } - offset_in_region = clip.start - base; + offset_in_region = int128_get64(int128_sub(clip.start, base)); base = clip.start; remain = clip.size; /* Render the region itself into any gaps left by the current view. */ - for (i = 0; i < view->nr && remain; ++i) { - if (base >= addrrange_end(view->ranges[i].addr)) { + for (i = 0; i < view->nr && int128_nz(remain); ++i) { + if (int128_ge(base, addrrange_end(view->ranges[i].addr))) { continue; } - if (base < view->ranges[i].addr.start) { - now = MIN(remain, view->ranges[i].addr.start - base); + if (int128_lt(base, view->ranges[i].addr.start)) { + now = int128_min(remain, + int128_sub(view->ranges[i].addr.start, base)); fr.mr = mr; fr.offset_in_region = offset_in_region; fr.addr = addrrange_make(base, now); @@ -558,18 +575,18 @@ static void render_memory_region(FlatView *view, fr.readonly = readonly; flatview_insert(view, i, &fr); ++i; - base += now; - offset_in_region += now; - remain -= now; + int128_addto(&base, now); + offset_in_region += int128_get64(now); + int128_subfrom(&remain, now); } - if (base == view->ranges[i].addr.start) { - now = MIN(remain, view->ranges[i].addr.size); - base += now; - offset_in_region += now; - remain -= now; + if (int128_eq(base, view->ranges[i].addr.start)) { + now = int128_min(remain, view->ranges[i].addr.size); + int128_addto(&base, now); + offset_in_region += int128_get64(now); + int128_subfrom(&remain, now); } } - if (remain) { + if (int128_nz(remain)) { fr.mr = mr; fr.offset_in_region = offset_in_region; fr.addr = addrrange_make(base, remain); @@ -587,7 +604,8 @@ static FlatView generate_memory_topology(MemoryRegion *mr) flatview_init(&view); - render_memory_region(&view, mr, 0, addrrange_make(0, INT64_MAX), false); + render_memory_region(&view, mr, int128_zero(), + addrrange_make(int128_zero(), int128_2_64()), false); flatview_simplify(&view); return view; @@ -637,7 +655,8 @@ static void address_space_update_ioeventfds(AddressSpace *as) FOR_EACH_FLAT_RANGE(fr, &as->current_map) { for (i = 0; i < fr->mr->ioeventfd_nb; ++i) { tmp = addrrange_shift(fr->mr->ioeventfds[i].addr, - fr->addr.start - fr->offset_in_region); + int128_sub(fr->addr.start, + int128_make64(fr->offset_in_region))); if (addrrange_intersects(fr->addr, tmp)) { ++ioeventfd_nb; ioeventfds = g_realloc(ioeventfds, @@ -682,8 +701,8 @@ static void address_space_update_topology_pass(AddressSpace *as, if (frold && (!frnew - || frold->addr.start < frnew->addr.start - || (frold->addr.start == frnew->addr.start + || int128_lt(frold->addr.start, frnew->addr.start) + || (int128_eq(frold->addr.start, frnew->addr.start) && !flatrange_equal(frold, frnew)))) { /* In old, but (not in new, or in new but attributes changed). */ @@ -788,7 +807,10 @@ void memory_region_init(MemoryRegion *mr, { mr->ops = NULL; mr->parent = NULL; - mr->size = size; + mr->size = int128_make64(size); + if (size == UINT64_MAX) { + mr->size = int128_2_64(); + } mr->addr = 0; mr->offset = 0; mr->terminates = false; @@ -1014,7 +1036,10 @@ void memory_region_destroy(MemoryRegion *mr) uint64_t memory_region_size(MemoryRegion *mr) { - return mr->size; + if (int128_eq(mr->size, int128_2_64())) { + return UINT64_MAX; + } + return int128_get64(mr->size); } void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset) @@ -1049,8 +1074,8 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { - cpu_physical_sync_dirty_bitmap(fr->addr.start, - fr->addr.start + fr->addr.size); + cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), + int128_get64(addrrange_end(fr->addr))); } } } @@ -1099,15 +1124,18 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { - qemu_unregister_coalesced_mmio(fr->addr.start, fr->addr.size); + qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); QTAILQ_FOREACH(cmr, &mr->coalesced, link) { tmp = addrrange_shift(cmr->addr, - fr->addr.start - fr->offset_in_region); + int128_sub(fr->addr.start, + int128_make64(fr->offset_in_region))); if (!addrrange_intersects(tmp, fr->addr)) { continue; } tmp = addrrange_intersection(tmp, fr->addr); - qemu_register_coalesced_mmio(tmp.start, tmp.size); + qemu_register_coalesced_mmio(int128_get64(tmp.start), + int128_get64(tmp.size)); } } } @@ -1116,7 +1144,7 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr) void memory_region_set_coalescing(MemoryRegion *mr) { memory_region_clear_coalescing(mr); - memory_region_add_coalescing(mr, 0, mr->size); + memory_region_add_coalescing(mr, 0, int128_get64(mr->size)); } void memory_region_add_coalescing(MemoryRegion *mr, @@ -1125,7 +1153,7 @@ void memory_region_add_coalescing(MemoryRegion *mr, { CoalescedMemoryRange *cmr = g_malloc(sizeof(*cmr)); - cmr->addr = addrrange_make(offset, size); + cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size)); QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link); memory_region_update_coalesced_range(mr); } @@ -1150,8 +1178,8 @@ void memory_region_add_eventfd(MemoryRegion *mr, int fd) { MemoryRegionIoeventfd mrfd = { - .addr.start = addr, - .addr.size = size, + .addr.start = int128_make64(addr), + .addr.size = int128_make64(size), .match_data = match_data, .data = data, .fd = fd, @@ -1180,8 +1208,8 @@ void memory_region_del_eventfd(MemoryRegion *mr, int fd) { MemoryRegionIoeventfd mrfd = { - .addr.start = addr, - .addr.size = size, + .addr.start = int128_make64(addr), + .addr.size = int128_make64(size), .match_data = match_data, .data = data, .fd = fd, @@ -1215,18 +1243,20 @@ static void memory_region_add_subregion_common(MemoryRegion *mr, if (subregion->may_overlap || other->may_overlap) { continue; } - if (offset >= other->addr + other->size - || offset + subregion->size <= other->addr) { + if (int128_gt(int128_make64(offset), + int128_add(int128_make64(other->addr), other->size)) + || int128_le(int128_add(int128_make64(offset), subregion->size), + int128_make64(other->addr))) { continue; } #if 0 printf("warning: subregion collision %llx/%llx (%s) " "vs %llx/%llx (%s)\n", (unsigned long long)offset, - (unsigned long long)subregion->size, + (unsigned long long)int128_get64(subregion->size), subregion->name, (unsigned long long)other->addr, - (unsigned long long)other->size, + (unsigned long long)int128_get64(other->size), other->name); #endif } @@ -1330,16 +1360,19 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): alias %s @%s " TARGET_FMT_plx "-" TARGET_FMT_plx "\n", base + mr->addr, - base + mr->addr + (target_phys_addr_t)mr->size - 1, + base + mr->addr + + (target_phys_addr_t)int128_get64(mr->size) - 1, mr->priority, mr->name, mr->alias->name, mr->alias_offset, - mr->alias_offset + (target_phys_addr_t)mr->size - 1); + mr->alias_offset + + (target_phys_addr_t)int128_get64(mr->size) - 1); } else { mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): %s\n", base + mr->addr, - base + mr->addr + (target_phys_addr_t)mr->size - 1, + base + mr->addr + + (target_phys_addr_t)int128_get64(mr->size) - 1, mr->priority, mr->name); } @@ -24,6 +24,7 @@ #include "qemu-queue.h" #include "iorange.h" #include "ioport.h" +#include "int128.h" typedef struct MemoryRegionOps MemoryRegionOps; typedef struct MemoryRegion MemoryRegion; @@ -105,7 +106,7 @@ struct MemoryRegion { const MemoryRegionOps *ops; void *opaque; MemoryRegion *parent; - uint64_t size; + Int128 size; target_phys_addr_t addr; target_phys_addr_t offset; bool backend_registered; diff --git a/migration-fd.c b/migration-fd.c index d0aec89e8d..6211124a05 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -42,10 +42,31 @@ static int fd_write(MigrationState *s, const void * buf, size_t size) static int fd_close(MigrationState *s) { + struct stat st; + int ret; + DPRINTF("fd_close\n"); if (s->fd != -1) { - close(s->fd); + ret = fstat(s->fd, &st); + if (ret == 0 && S_ISREG(st.st_mode)) { + /* + * If the file handle is a regular file make sure the + * data is flushed to disk before signaling success. + */ + ret = fsync(s->fd); + if (ret != 0) { + ret = -errno; + perror("migration-fd: fsync"); + return ret; + } + } + ret = close(s->fd); s->fd = -1; + if (ret != 0) { + ret = -errno; + perror("migration-fd: close"); + return ret; + } } return 0; } diff --git a/migration.c b/migration.c index 3b4abbde64..4b17566857 100644 --- a/migration.c +++ b/migration.c @@ -216,7 +216,7 @@ static void migrate_fd_put_notify(void *opaque) qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); qemu_file_put_notify(s->file); - if (qemu_file_get_error(s->file)) { + if (s->file && qemu_file_get_error(s->file)) { migrate_fd_error(s); } } @@ -199,8 +199,8 @@ static inline int mon_print_count_get(const Monitor *mon) { return 0; } static QLIST_HEAD(mon_list, Monitor) mon_list; -static const mon_cmd_t mon_cmds[]; -static const mon_cmd_t info_cmds[]; +static mon_cmd_t mon_cmds[]; +static mon_cmd_t info_cmds[]; static const mon_cmd_t qmp_cmds[]; @@ -2591,13 +2591,14 @@ int monitor_get_fd(Monitor *mon, const char *fdname) return -1; } -static const mon_cmd_t mon_cmds[] = { +/* mon_cmds and info_cmds would be sorted at runtime */ +static mon_cmd_t mon_cmds[] = { #include "hmp-commands.h" { NULL, NULL, }, }; /* Please update hmp-commands.hx when adding or changing commands */ -static const mon_cmd_t info_cmds[] = { +static mon_cmd_t info_cmds[] = { { .name = "version", .args_type = "", @@ -4832,6 +4833,25 @@ static void monitor_event(void *opaque, int event) } } +static int +compare_mon_cmd(const void *a, const void *b) +{ + return strcmp(((const mon_cmd_t *)a)->name, + ((const mon_cmd_t *)b)->name); +} + +static void sortcmdlist(void) +{ + int array_num; + int elem_size = sizeof(mon_cmd_t); + + array_num = sizeof(mon_cmds)/elem_size-1; + qsort((void *)mon_cmds, array_num, elem_size, compare_mon_cmd); + + array_num = sizeof(info_cmds)/elem_size-1; + qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd); +} + /* * Local variables: @@ -4874,6 +4894,8 @@ void monitor_init(CharDriverState *chr, int flags) QLIST_INSERT_HEAD(&mon_list, mon, entry); if (!default_mon || (flags & MONITOR_IS_DEFAULT)) default_mon = mon; + + sortcmdlist(); } static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque) @@ -733,12 +733,7 @@ int net_handle_fd_param(Monitor *mon, const char *param) return -1; } } else { - char *endptr = NULL; - - fd = strtol(param, &endptr, 10); - if (*endptr || (fd == 0 && param == endptr)) { - return -1; - } + fd = qemu_parse_fd(param); } return fd; diff --git a/net/tap-linux.c b/net/tap-linux.c index ff8cad0ea0..41d581b734 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -73,7 +73,11 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); ret = ioctl(fd, TUNSETIFF, (void *) &ifr); if (ret != 0) { - error_report("could not configure %s (%s): %m", PATH_NET_TUN, ifr.ifr_name); + if (ifname[0] != '\0') { + error_report("could not configure %s (%s): %m", PATH_NET_TUN, ifr.ifr_name); + } else { + error_report("could not configure %s: %m", PATH_NET_TUN); + } close(fd); return -1; } diff --git a/oslib-posix.c b/oslib-posix.c index dbc8ee8960..6f297626c7 100644 --- a/oslib-posix.c +++ b/oslib-posix.c @@ -36,8 +36,11 @@ extern int daemon(int, int); #endif #if defined(__linux__) && defined(__x86_64__) - /* Use 2MB alignment so transparent hugepages can be used by KVM */ + /* Use 2 MiB alignment so transparent hugepages can be used by KVM. + Valgrind does not support alignments larger than 1 MiB, + therefore we need special code which handles running on Valgrind. */ # define QEMU_VMALLOC_ALIGN (512 * 4096) +# define CONFIG_VALGRIND #else # define QEMU_VMALLOC_ALIGN getpagesize() #endif @@ -47,7 +50,11 @@ extern int daemon(int, int); #include "trace.h" #include "qemu_socket.h" - +#if defined(CONFIG_VALGRIND) +static int running_on_valgrind = -1; +#else +# define running_on_valgrind 0 +#endif int qemu_daemon(int nochdir, int noclose) { @@ -89,7 +96,16 @@ void *qemu_vmalloc(size_t size) void *ptr; size_t align = QEMU_VMALLOC_ALIGN; - if (size < align) { +#if defined(CONFIG_VALGRIND) + if (running_on_valgrind < 0) { + /* First call, test whether we are running on Valgrind. + This is a substitute for RUNNING_ON_VALGRIND from valgrind.h. */ + const char *ld = getenv("LD_PRELOAD"); + running_on_valgrind = (ld != NULL && strstr(ld, "vgpreload")); + } +#endif + + if (size < align || running_on_valgrind) { align = getpagesize(); } ptr = qemu_memalign(align, size); diff --git a/pc-bios/README b/pc-bios/README index 4d1d816fdb..0668559842 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/dgibson/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20110323. + built from git tag qemu-slof-20111013. - The PXE roms come from the iPXE project. Built with BANNER_TIME 0. Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping: diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex 22c4c7f5c4..1e84582cc6 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/qemu-barrier.h b/qemu-barrier.h index 735eea6cf9..c11bb2b59f 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -14,7 +14,7 @@ */ #define smp_wmb() barrier() -#elif defined(__powerpc__) +#elif defined(_ARCH_PPC) /* * We use an eieio() for a wmb() on powerpc. This assumes we don't diff --git a/qemu-common.h b/qemu-common.h index 1c15cb17a7..2ce47aa12d 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -129,6 +129,7 @@ time_t mktimegm(struct tm *tm); int qemu_fls(int i); int qemu_fdatasync(int fd); int fcntl_setfl(int fd, int flag); +int qemu_parse_fd(const char *param); /* * strtosz() suffixes used to specify the default treatment of an diff --git a/qemu-tls.h b/qemu-tls.h new file mode 100644 index 0000000000..5b70f10f8f --- /dev/null +++ b/qemu-tls.h @@ -0,0 +1,52 @@ +/* + * Abstraction layer for defining and using TLS variables + * + * Copyright (c) 2011 Red Hat, Inc + * Copyright (c) 2011 Linaro Limited + * + * Authors: + * Paolo Bonzini <pbonzini@redhat.com> + * Peter Maydell <peter.maydell@linaro.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_TLS_H +#define QEMU_TLS_H + +/* Per-thread variables. Note that we only have implementations + * which are really thread-local on Linux; the dummy implementations + * define plain global variables. + * + * This means that for the moment use should be restricted to + * per-VCPU variables, which are OK because: + * - the only -user mode supporting multiple VCPU threads is linux-user + * - TCG system mode is single-threaded regarding VCPUs + * - KVM system mode is multi-threaded but limited to Linux + * + * TODO: proper implementations via Win32 .tls sections and + * POSIX pthread_getspecific. + */ +#ifdef __linux__ +#define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x) +#define DEFINE_TLS(type, x) __thread __typeof__(type) tls__##x +#define get_tls(x) tls__##x +#else +/* Dummy implementations which define plain global variables */ +#define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x) +#define DEFINE_TLS(type, x) __typeof__(type) tls__##x +#define get_tls(x) tls__##x +#endif + +#endif diff --git a/roms/SLOF b/roms/SLOF -Subproject d1d6b53b713a2b7c2c25685268fa932d28a4b4c +Subproject 32e3430c018ceb8413cb808477449d1968c4249 @@ -476,6 +476,8 @@ static void qemu_fill_buffer(QEMUFile *f) if (len > 0) { f->buf_size += len; f->buf_offset += len; + } else if (len == 0) { + f->last_error = -EIO; } else if (len != -EAGAIN) f->last_error = len; } diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 0eba357cc2..7a71324f6a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2206,12 +2206,6 @@ sub process { ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr); } -#goto labels aren't indented, allow a single space however - if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and - !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { - WARN("labels should not be indented\n" . $herecurr); - } - # Return is not a function. if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { my $spacing = $1; diff --git a/target-i386/helper.c b/target-i386/helper.c index 6c6a1675df..2586aff700 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1257,6 +1257,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model) cpu_x86_close(env); return NULL; } + env->cpuid_apic_id = env->cpu_index; mce_init(env); qemu_init_vcpu(env); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3f77e308a6..e84108c49a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -66,7 +66,7 @@ #define TARGET_PAGE_BITS 12 #endif /* defined(TARGET_PPCEMB) */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif /* defined (TARGET_PPC64) */ @@ -858,6 +858,22 @@ enum { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 +struct ppc_def_t { + const char *name; + uint32_t pvr; + uint32_t svr; + uint64_t insns_flags; + uint64_t insns_flags2; + uint64_t msr_mask; + powerpc_mmu_t mmu_model; + powerpc_excp_t excp_model; + powerpc_input_t bus_model; + uint32_t flags; + int bfd_mach; + void (*init_proc)(CPUPPCState *env); + int (*check_pow)(CPUPPCState *env); +}; + struct CPUPPCState { /* First are the most commonly used resources * during translated code execution @@ -1107,6 +1123,7 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); +const ppc_def_t *ppc_find_by_pvr(uint32_t pvr); const ppc_def_t *cpu_ppc_find_by_name (const char *name); int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); @@ -1839,10 +1856,40 @@ enum { /* popcntw and popcntd instructions */ PPC_POPCNTWD = 0x8000000000000000ULL, +#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \ + | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \ + | PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \ + | PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \ + | PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \ + | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \ + | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \ + | PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX \ + | PPC_ALTIVEC | PPC_SPE | PPC_SPE_SINGLE \ + | PPC_SPE_DOUBLE | PPC_MEM_TLBIA \ + | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC \ + | PPC_MEM_SYNC | PPC_MEM_EIEIO \ + | PPC_CACHE | PPC_CACHE_ICBI \ + | PPC_CACHE_DCBZ | PPC_CACHE_DCBZT \ + | PPC_CACHE_DCBA | PPC_CACHE_LOCK \ + | PPC_EXTERN | PPC_SEGMENT | PPC_6xx_TLB \ + | PPC_74xx_TLB | PPC_40x_TLB | PPC_SEGMENT_64B \ + | PPC_SLBI | PPC_WRTEE | PPC_40x_EXCP \ + | PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \ + | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ + | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \ + | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \ + | PPC_POPCNTWD) + /* extended type values */ /* BookE 2.06 PowerPC specification */ PPC2_BOOKE206 = 0x0000000000000001ULL, + /* VSX (extensions to Altivec / VMX) */ + PPC2_VSX = 0x0000000000000002ULL, + /* Decimal Floating Point (DFP) */ + PPC2_DFP = 0x0000000000000004ULL, + +#define PPC_TCG_INSNS2 (PPC2_BOOKE206) }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6339be3a75..137a494201 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -26,6 +26,8 @@ #include "helper_regs.h" #include "qemu-common.h" #include "kvm.h" +#include "kvm_ppc.h" +#include "cpus.h" //#define DEBUG_MMU //#define DEBUG_BATS @@ -3189,6 +3191,15 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) if (tcg_enabled()) { ppc_translate_init(); } + /* Adjust cpu index for SMT */ +#if !defined(CONFIG_USER_ONLY) + if (kvm_enabled()) { + int smt = kvmppc_smt_threads(); + + env->cpu_index = (env->cpu_index / smp_threads)*smt + + (env->cpu_index % smp_threads); + } +#endif /* !CONFIG_USER_ONLY */ env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 75832d83b8..429349fb94 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -28,6 +28,8 @@ #include "kvm_ppc.h" #include "cpu.h" #include "device_tree.h" +#include "hw/sysbus.h" +#include "hw/spapr.h" #include "hw/sysbus.h" #include "hw/spapr.h" @@ -53,6 +55,9 @@ static int cap_interrupt_unset = false; static int cap_interrupt_level = false; static int cap_segstate; static int cap_booke_sregs; +static int cap_ppc_smt; +static int cap_ppc_rma; +static int cap_spapr_tce; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -76,6 +81,9 @@ int kvm_arch_init(KVMState *s) cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); + cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); + cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); + cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -642,37 +650,60 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) return 0; } -uint64_t kvmppc_get_clockfreq(void) +/* Read a CPU node property from the host device tree that's a single + * integer (32-bit or 64-bit). Returns 0 if anything goes wrong + * (can't find or open the property, or doesn't understand the + * format) */ +static uint64_t kvmppc_read_int_cpu_dt(const char *propname) { - char buf[512]; - uint32_t tb[2]; + char buf[PATH_MAX]; + union { + uint32_t v32; + uint64_t v64; + } u; FILE *f; int len; if (kvmppc_find_cpu_dt(buf, sizeof(buf))) { - return 0; + return -1; } - strncat(buf, "/clock-frequency", sizeof(buf) - strlen(buf)); + strncat(buf, "/", sizeof(buf) - strlen(buf)); + strncat(buf, propname, sizeof(buf) - strlen(buf)); f = fopen(buf, "rb"); if (!f) { return -1; } - len = fread(tb, sizeof(tb[0]), 2, f); + len = fread(&u, 1, sizeof(u), f); fclose(f); switch (len) { - case 1: - /* freq is only a single cell */ - return tb[0]; - case 2: - return *(uint64_t*)tb; + case 4: + /* property is a 32-bit quantity */ + return be32_to_cpu(u.v32); + case 8: + return be64_to_cpu(u.v64); } return 0; } +uint64_t kvmppc_get_clockfreq(void) +{ + return kvmppc_read_int_cpu_dt("clock-frequency"); +} + +uint32_t kvmppc_get_vmx(void) +{ + return kvmppc_read_int_cpu_dt("ibm,vmx"); +} + +uint32_t kvmppc_get_dfp(void) +{ + return kvmppc_read_int_cpu_dt("ibm,dfp"); +} + int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { uint32_t *hc = (uint32_t*)buf; @@ -750,6 +781,150 @@ fail: cpu_abort(env, "This KVM version does not support PAPR\n"); } +int kvmppc_smt_threads(void) +{ + return cap_ppc_smt ? cap_ppc_smt : 1; +} + +off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) +{ + void *rma; + off_t size; + int fd; + struct kvm_allocate_rma ret; + MemoryRegion *rma_region; + + /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported + * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but + * not necessary on this hardware + * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware + * + * FIXME: We should allow the user to force contiguous RMA + * allocation in the cap_ppc_rma==1 case. + */ + if (cap_ppc_rma < 2) { + return 0; + } + + fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret); + if (fd < 0) { + fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n", + strerror(errno)); + return -1; + } + + size = MIN(ret.rma_size, 256ul << 20); + + rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (rma == MAP_FAILED) { + fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno)); + return -1; + }; + + rma_region = g_new(MemoryRegion, 1); + memory_region_init_ram_ptr(rma_region, NULL, name, size, rma); + memory_region_add_subregion(sysmem, 0, rma_region); + + return size; +} + +void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) +{ + struct kvm_create_spapr_tce args = { + .liobn = liobn, + .window_size = window_size, + }; + long len; + int fd; + void *table; + + if (!cap_spapr_tce) { + return NULL; + } + + fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args); + if (fd < 0) { + return NULL; + } + + len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE); + /* FIXME: round this up to page size */ + + table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (table == MAP_FAILED) { + close(fd); + return NULL; + } + + *pfd = fd; + return table; +} + +int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) +{ + long len; + + if (fd < 0) { + return -1; + } + + len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE); + if ((munmap(table, len) < 0) || + (close(fd) < 0)) { + fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE " + "table: %s", strerror(errno)); + /* Leak the table */ + } + + return 0; +} + +static inline uint32_t mfpvr(void) +{ + uint32_t pvr; + + asm ("mfpvr %0" + : "=r"(pvr)); + return pvr; +} + +static void alter_insns(uint64_t *word, uint64_t flags, bool on) +{ + if (on) { + *word |= flags; + } else { + *word &= ~flags; + } +} + +const ppc_def_t *kvmppc_host_cpu_def(void) +{ + uint32_t host_pvr = mfpvr(); + const ppc_def_t *base_spec; + ppc_def_t *spec; + uint32_t vmx = kvmppc_get_vmx(); + uint32_t dfp = kvmppc_get_dfp(); + + base_spec = ppc_find_by_pvr(host_pvr); + + spec = g_malloc0(sizeof(*spec)); + memcpy(spec, base_spec, sizeof(*spec)); + + /* Now fix up the spec with information we can query from the host */ + + if (vmx != -1) { + /* Only override when we know what the host supports */ + alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); + alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); + } + if (dfp != -1) { + /* Only override when we know what the host supports */ + alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + } + + return spec; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index c484e60bcb..f9c0198311 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -9,15 +9,26 @@ #ifndef __KVM_PPC_H__ #define __KVM_PPC_H__ +#include "memory.h" + void kvmppc_init(void); #ifdef CONFIG_KVM uint32_t kvmppc_get_tbfreq(void); uint64_t kvmppc_get_clockfreq(void); +uint32_t kvmppc_get_vmx(void); +uint32_t kvmppc_get_dfp(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); +int kvmppc_smt_threads(void); +#ifndef CONFIG_USER_ONLY +off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); +void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); +int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +#endif /* !CONFIG_USER_ONLY */ +const ppc_def_t *kvmppc_host_cpu_def(void); #else @@ -31,6 +42,16 @@ static inline uint64_t kvmppc_get_clockfreq(void) return 0; } +static inline uint32_t kvmppc_get_vmx(void) +{ + return 0; +} + +static inline uint32_t kvmppc_get_dfp(void) +{ + return 0; +} + static inline int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { return -1; @@ -45,6 +66,35 @@ static inline void kvmppc_set_papr(CPUState *env) { } +static inline int kvmppc_smt_threads(void) +{ + return 1; +} + +#ifndef CONFIG_USER_ONLY +static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) +{ + return 0; +} + +static inline void *kvmppc_create_spapr_tce(uint32_t liobn, + uint32_t window_size, int *fd) +{ + return NULL; +} + +static inline int kvmppc_remove_spapr_tce(void *table, int pfd, + uint32_t window_size) +{ + return -1; +} +#endif /* !CONFIG_USER_ONLY */ + +static inline const ppc_def_t *kvmppc_host_cpu_def(void) +{ + return NULL; +} + #endif #ifndef CONFIG_KVM diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1e362fc238..99e995c7b6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -205,8 +205,10 @@ typedef struct DisasContext { } DisasContext; struct opc_handler_t { - /* invalid bits */ - uint32_t inval; + /* invalid bits for instruction 1 (Rc(opcode) == 0) */ + uint32_t inval1; + /* invalid bits for instruction 2 (Rc(opcode) == 1) */ + uint32_t inval2; /* instruction type */ uint64_t type; /* extended instruction type */ @@ -478,7 +480,23 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + .oname = stringify(name), \ + }, \ + .oname = stringify(name), \ +} +#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl1, \ + .inval2 = invl2, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -493,7 +511,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -509,7 +527,22 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} +#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl1, \ + .inval2 = invl2, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -523,7 +556,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -550,7 +583,8 @@ static void gen_invalid(DisasContext *ctx) } static opc_handler_t invalid_handler = { - .inval = 0xFFFFFFFF, + .inval1 = 0xFFFFFFFF, + .inval2 = 0xFFFFFFFF, .type = PPC_NONE, .type2 = PPC_NONE, .handler = gen_invalid, @@ -6693,7 +6727,7 @@ static inline void gen_store_gpr64(int reg, TCGv_i64 t) #endif } -#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ { \ if (Rc(ctx->opcode)) \ @@ -7416,35 +7450,35 @@ static inline void gen_evmwsmiaa(DisasContext *ctx) tcg_temp_free_i64(tmp); } -GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE); //// -GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE); //// -GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE); //// -GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE); // -GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE); // -GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE); //// -GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); //// -GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); //// +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); // +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); // +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE); +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); //// /* SPE load and stores */ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) @@ -7803,74 +7837,74 @@ GEN_SPEOP_LDST(evstwwo, 0x1E, 2); /* Multiply and add - TODO */ #if 0 -GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0x00000000, PPC_SPE); - -GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0x00000000, PPC_SPE); - -GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, PPC_SPE); - -GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0x00000000, PPC_SPE); - -GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0x00000000, PPC_SPE); - -GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0x00000000, PPC_SPE); - -GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);// +GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); #endif /*** SPE floating-point extension ***/ @@ -8131,20 +8165,20 @@ GEN_SPEFPUOP_COMP_64(evfststlt); GEN_SPEFPUOP_COMP_64(evfststeq); /* Opcodes definitions */ -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // /* Single precision floating-point operations */ /* Arithmetic */ @@ -8199,20 +8233,20 @@ GEN_SPEFPUOP_COMP_32(efststlt); GEN_SPEFPUOP_COMP_32(efststeq); /* Opcodes definitions */ -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // /* Double precision floating-point operations */ /* Arithmetic */ @@ -8286,22 +8320,22 @@ GEN_SPEFPUOP_COMP_64(efdtstlt); GEN_SPEFPUOP_COMP_64(efdtsteq); /* Opcodes definitions */ -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); // +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), @@ -9070,84 +9104,84 @@ GEN_VAFORM_PAIRED(vsel, vperm, 21), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), #undef GEN_SPE -#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ -GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) -GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE), -GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE), -GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE), -GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, PPC_SPE), -GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE), -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE), -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE), -GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE), -GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE), -GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE), - -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE), - -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE), - -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE), +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ + GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE), +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE), + +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), + +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), + +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE), +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE), #undef GEN_SPEOP_LDST #define GEN_SPEOP_LDST(name, opc2, sh) \ @@ -9484,11 +9518,19 @@ static inline void gen_intermediate_code_internal(CPUState *env, opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { - if (unlikely((ctx.opcode & handler->inval) != 0)) { + uint32_t inval; + + if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE) && Rc(ctx.opcode))) { + inval = handler->inval2; + } else { + inval = handler->inval1; + } + + if (unlikely((ctx.opcode & inval) != 0)) { if (qemu_log_enabled()) { qemu_log("invalid bits: %08x for opcode: " "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", - ctx.opcode & handler->inval, opc1(ctx.opcode), + ctx.opcode & inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ca0d8525c8..8a7233fc82 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -24,6 +24,8 @@ #include "dis-asm.h" #include "gdbstub.h" +#include <kvm.h> +#include "kvm_ppc.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -32,22 +34,6 @@ #define TODO_USER_ONLY 1 #endif -struct ppc_def_t { - const char *name; - uint32_t pvr; - uint32_t svr; - uint64_t insns_flags; - uint64_t insns_flags2; - uint64_t msr_mask; - powerpc_mmu_t mmu_model; - powerpc_excp_t excp_model; - powerpc_input_t bus_model; - uint32_t flags; - int bfd_mach; - void (*init_proc)(CPUPPCState *env); - int (*check_pow)(CPUPPCState *env); -}; - /* For user-mode emulation, we don't emulate any IRQ controller */ #if defined(CONFIG_USER_ONLY) #define PPC_IRQ_INIT_FN(name) \ @@ -6533,7 +6519,7 @@ static void init_proc_970MP (CPUPPCState *env) PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI | \ PPC_POPCNTB | PPC_POPCNTWD) -#define POWERPC_INSNS2_POWER7 (PPC_NONE) +#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) #define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) @@ -7331,6 +7317,8 @@ enum { CPU_POWERPC_POWER6A = 0x0F000002, #define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20 CPU_POWERPC_POWER7_v20 = 0x003F0200, + CPU_POWERPC_POWER7_v21 = 0x003F0201, + CPU_POWERPC_POWER7_v23 = 0x003F0203, CPU_POWERPC_970 = 0x00390202, #define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 CPU_POWERPC_970FX_v10 = 0x00391100, @@ -9137,6 +9125,8 @@ static const ppc_def_t ppc_defs[] = { /* POWER7 */ POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7), POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7), + POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7), + POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7), /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ @@ -9856,6 +9846,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) env->bus_model = def->bus_model; env->insns_flags = def->insns_flags; env->insns_flags2 = def->insns_flags2; + if (!kvm_enabled()) { + /* TCG doesn't (yet) emulate some groups of instructions that + * are implemented on some otherwise supported CPUs (e.g. VSX + * and decimal floating point instructions on POWER7). We + * remove unsupported instruction groups from the cpu state's + * instruction masks and hope the guest can cope. For at + * least the pseries machine, the unavailability of these + * instructions can be advertise to the guest via the device + * tree. + * + * FIXME: we should have a similar masking for CPU features + * not accessible under KVM, but so far, there aren't any of + * those. */ + env->insns_flags &= PPC_TCG_INSNS; + env->insns_flags2 &= PPC_TCG_INSNS2; + } env->flags = def->flags; env->bfd_mach = def->bfd_mach; env->check_pow = def->check_pow; @@ -10041,42 +10047,34 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) return 0; } -static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) +static bool ppc_cpu_usable(const ppc_def_t *def) { - const ppc_def_t *ret; - uint32_t pvr_rev; - int i, best, match, best_match, max; +#if defined(TARGET_PPCEMB) + /* When using the ppcemb target, we only support 440 style cores */ + if (def->mmu_model != POWERPC_MMU_BOOKE) { + return false; + } +#endif - ret = NULL; - max = ARRAY_SIZE(ppc_defs); - best = -1; - pvr_rev = pvr & 0xFFFF; - /* We want all specified bits to match */ - best_match = 32 - ctz32(pvr_rev); - for (i = 0; i < max; i++) { - /* We check that the 16 higher bits are the same to ensure the CPU - * model will be the choosen one. - */ - if (((pvr ^ ppc_defs[i].pvr) >> 16) == 0) { - /* We want as much as possible of the low-level 16 bits - * to be the same but we allow inexact matches. - */ - match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF)); - /* We check '>=' instead of '>' because the PPC_defs table - * is ordered by increasing revision. - * Then, we will match the higher revision compatible - * with the requested PVR - */ - if (match >= best_match) { - best = i; - best_match = match; - } + return true; +} + +const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + + /* If we have an exact match, we're done */ + if (pvr == ppc_defs[i].pvr) { + return &ppc_defs[i]; } } - if (best != -1) - ret = &ppc_defs[best]; - return ret; + return NULL; } #include <ctype.h> @@ -10087,6 +10085,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) const char *p; int i, max, len; + if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { + return kvmppc_host_cpu_def(); + } + /* Check if the given name is a PVR */ len = strlen(name); if (len == 10 && name[0] == '0' && name[1] == 'x') { @@ -10105,6 +10107,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) ret = NULL; max = ARRAY_SIZE(ppc_defs); for (i = 0; i < max; i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + if (strcasecmp(name, ppc_defs[i].name) == 0) { ret = &ppc_defs[i]; break; @@ -10120,6 +10126,10 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) max = ARRAY_SIZE(ppc_defs); for (i = 0; i < max; i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", ppc_defs[i].name, ppc_defs[i].pvr); } diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 24ec7fc128..82e04e7f30 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2042,8 +2042,8 @@ static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) } static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, - TCGv_i32 arg2, unsigned int ofs, - unsigned int len) + TCGv_i32 arg2, unsigned int ofs, + unsigned int len) { uint32_t mask; TCGv_i32 t1; @@ -2073,8 +2073,8 @@ static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, } static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, - TCGv_i64 arg2, unsigned int ofs, - unsigned int len) + TCGv_i64 arg2, unsigned int ofs, + unsigned int len) { uint64_t mask; TCGv_i64 t1; @@ -2090,6 +2090,7 @@ static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, #if TCG_TARGET_REG_BITS == 32 if (ofs >= 32) { + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_LOW(arg2), ofs - 32, len); return; @@ -2097,6 +2098,7 @@ static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, if (ofs + len <= 32) { tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2), ofs, len); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); return; } #endif diff --git a/trace/simple.c b/trace/simple.c index b639dda806..6339152d27 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -324,14 +324,29 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf) bool trace_event_set_state(const char *name, bool state) { unsigned int i; - + unsigned int len; + bool wildcard = false; + bool matched = false; + + len = strlen(name); + if (len > 0 && name[len - 1] == '*') { + wildcard = true; + len -= 1; + } for (i = 0; i < NR_TRACE_EVENTS; i++) { + if (wildcard) { + if (!strncmp(trace_list[i].tp_name, name, len)) { + trace_list[i].state = state; + matched = true; + } + continue; + } if (!strcmp(trace_list[i].tp_name, name)) { trace_list[i].state = state; return true; } } - return false; + return matched; } /* Helper function to create a thread with signals blocked. Use glib's diff --git a/trace/stderr.c b/trace/stderr.c index 7107c4a131..0810d6f956 100644 --- a/trace/stderr.c +++ b/trace/stderr.c @@ -15,14 +15,29 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf) bool trace_event_set_state(const char *name, bool state) { unsigned int i; + unsigned int len; + bool wildcard = false; + bool matched = false; + len = strlen(name); + if (len > 0 && name[len - 1] == '*') { + wildcard = true; + len -= 1; + } for (i = 0; i < NR_TRACE_EVENTS; i++) { + if (wildcard) { + if (!strncmp(trace_list[i].tp_name, name, len)) { + trace_list[i].state = state; + matched = true; + } + continue; + } if (!strcmp(trace_list[i].tp_name, name)) { trace_list[i].state = state; return true; } } - return false; + return matched; } bool trace_backend_init(const char *events, const char *file) diff --git a/ui/cocoa.m b/ui/cocoa.m index d9e4e3dcaa..0711205cbe 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -811,6 +811,8 @@ QemuCocoaView *cocoaView; char **argv = (char**)malloc( sizeof(char*)*3 ); + [sheet close]; + asprintf(&argv[0], "%s", bin); asprintf(&argv[1], "-hda"); asprintf(&argv[2], "%s", img); diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c index e96095ab94..23b1bf5c4d 100644 --- a/ui/vnc-auth-sasl.c +++ b/ui/vnc-auth-sasl.c @@ -34,7 +34,7 @@ void vnc_sasl_client_cleanup(VncState *vs) vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0; vs->sasl.encodedLength = vs->sasl.encodedOffset = 0; vs->sasl.encoded = NULL; - free(vs->sasl.username); + g_free(vs->sasl.username); free(vs->sasl.mechlist); vs->sasl.username = vs->sasl.mechlist = NULL; sasl_dispose(&vs->sasl.conn); @@ -506,7 +506,7 @@ void start_auth_sasl(VncState *vs) goto authabort; if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) { - free(localAddr); + g_free(localAddr); goto authabort; } @@ -518,8 +518,8 @@ void start_auth_sasl(VncState *vs) NULL, /* Callbacks, not needed */ SASL_SUCCESS_DATA, &vs->sasl.conn); - free(localAddr); - free(remoteAddr); + g_free(localAddr); + g_free(remoteAddr); localAddr = remoteAddr = NULL; if (err != SASL_OK) { diff --git a/ui/vnc-enc-hextile.c b/ui/vnc-enc-hextile.c index d2905c88f0..c860dbb2e5 100644 --- a/ui/vnc-enc-hextile.c +++ b/ui/vnc-enc-hextile.c @@ -80,8 +80,8 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x, last_bg, last_fg, &has_bg, &has_fg); } } - free(last_fg); - free(last_bg); + g_free(last_fg); + g_free(last_bg); return 1; } diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c index ffbd1725a4..3aaa93928a 100644 --- a/ui/vnc-tls.c +++ b/ui/vnc-tls.c @@ -413,7 +413,7 @@ void vnc_tls_client_cleanup(struct VncState *vs) vs->tls.session = NULL; } vs->tls.wiremode = VNC_WIREMODE_CLEAR; - free(vs->tls.dname); + g_free(vs->tls.dname); } @@ -2911,7 +2911,7 @@ int vnc_display_open(DisplayState *ds, const char *display) if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { fprintf(stderr, "Failed to initialize SASL auth %s", sasl_errstring(saslErr, NULL, NULL)); - free(vs->display); + g_free(vs->display); vs->display = NULL; return -1; } @@ -2925,7 +2925,7 @@ int vnc_display_open(DisplayState *ds, const char *display) else vs->lsock = inet_connect(display, SOCK_STREAM); if (-1 == vs->lsock) { - free(vs->display); + g_free(vs->display); vs->display = NULL; return -1; } else { @@ -2946,10 +2946,10 @@ int vnc_display_open(DisplayState *ds, const char *display) vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900); } if (-1 == vs->lsock) { - free(dpy); + g_free(dpy); return -1; } else { - free(vs->display); + g_free(vs->display); vs->display = dpy; } } diff --git a/usb-linux.c b/usb-linux.c index 7d4d1d7bcf..f086d57edb 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -1349,7 +1349,7 @@ static int usb_host_close(USBHostDevice *dev) { int i; - if (dev->fd == -1 || !dev->dev.attached) { + if (dev->fd == -1) { return -1; } @@ -1367,7 +1367,9 @@ static int usb_host_close(USBHostDevice *dev) } async_complete(dev); dev->closing = 0; - usb_device_detach(&dev->dev); + if (dev->dev.attached) { + usb_device_detach(&dev->dev); + } ioctl(dev->fd, USBDEVFS_RESET); close(dev->fd); dev->fd = -1; @@ -2185,7 +2185,9 @@ int main(int argc, char **argv, char **envp) error_set_progname(argv[0]); g_mem_set_vtable(&mem_trace); - g_thread_init(NULL); + if (!g_thread_supported()) { + g_thread_init(NULL); + } runstate_init(); |