diff options
69 files changed, 2080 insertions, 1290 deletions
diff --git a/Makefile.target b/Makefile.target index 45cbe56bde..95c9d23439 100644 --- a/Makefile.target +++ b/Makefile.target @@ -161,10 +161,11 @@ endif #CONFIG_BSD_USER # System emulator target ifdef CONFIG_SOFTMMU -obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o vl.o +obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o vl.o balloon.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly -obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o +obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o +obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o obj-y += event_notifier.o obj-y += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o diff --git a/arm-dis.c b/arm-dis.c index 4fb899e388..50285550c0 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -3149,14 +3149,14 @@ print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given) if (started) func (stream, ", "); started = 1; - func (stream, arm_regnames[14] /* "lr" */); + func (stream, "%s", arm_regnames[14] /* "lr" */); } if (domaskpc) { if (started) func (stream, ", "); - func (stream, arm_regnames[15] /* "pc" */); + func (stream, "%s", arm_regnames[15] /* "pc" */); } func (stream, "}"); @@ -3699,7 +3699,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) } else { - func (stream, psr_name (given & 0xff)); + func (stream, "%s", psr_name (given & 0xff)); } break; @@ -3707,7 +3707,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) if ((given & 0xff) == 0) func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C'); else - func (stream, psr_name (given & 0xff)); + func (stream, "%s", psr_name (given & 0xff)); break; case '0': case '1': case '2': case '3': case '4': diff --git a/balloon.c b/balloon.c new file mode 100644 index 0000000000..8e0b7f18de --- /dev/null +++ b/balloon.c @@ -0,0 +1,146 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysemu.h" +#include "monitor.h" +#include "qjson.h" +#include "qint.h" +#include "cpu-common.h" +#include "kvm.h" +#include "balloon.h" + + +static QEMUBalloonEvent *qemu_balloon_event; +void *qemu_balloon_event_opaque; + +void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque) +{ + qemu_balloon_event = func; + qemu_balloon_event_opaque = opaque; +} + +int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque) +{ + if (qemu_balloon_event) { + qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque); + return 1; + } else { + return 0; + } +} + +int qemu_balloon_status(MonitorCompletion cb, void *opaque) +{ + if (qemu_balloon_event) { + qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque); + return 1; + } else { + return 0; + } +} + +static void print_balloon_stat(const char *key, QObject *obj, void *opaque) +{ + Monitor *mon = opaque; + + if (strcmp(key, "actual")) + monitor_printf(mon, ",%s=%" PRId64, key, + qint_get_int(qobject_to_qint(obj))); +} + +void monitor_print_balloon(Monitor *mon, const QObject *data) +{ + QDict *qdict; + + qdict = qobject_to_qdict(data); + if (!qdict_haskey(qdict, "actual")) + return; + + monitor_printf(mon, "balloon: actual=%" PRId64, + qdict_get_int(qdict, "actual") >> 20); + qdict_iter(qdict, print_balloon_stat, mon); + monitor_printf(mon, "\n"); +} + +/** + * do_info_balloon(): Balloon information + * + * Make an asynchronous request for balloon info. When the request completes + * a QDict will be returned according to the following specification: + * + * - "actual": current balloon value in bytes + * The following fields may or may not be present: + * - "mem_swapped_in": Amount of memory swapped in (bytes) + * - "mem_swapped_out": Amount of memory swapped out (bytes) + * - "major_page_faults": Number of major faults + * - "minor_page_faults": Number of minor faults + * - "free_mem": Total amount of free and unused memory (bytes) + * - "total_mem": Total amount of available memory (bytes) + * + * Example: + * + * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0, + * "major_page_faults": 142, "minor_page_faults": 239245, + * "free_mem": 1014185984, "total_mem": 1044668416 } + */ +int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque) +{ + int ret; + + if (kvm_enabled() && !kvm_has_sync_mmu()) { + qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); + return -1; + } + + ret = qemu_balloon_status(cb, opaque); + if (!ret) { + qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); + return -1; + } + + return 0; +} + +/** + * do_balloon(): Request VM to change its memory allocation + */ +int do_balloon(Monitor *mon, const QDict *params, + MonitorCompletion cb, void *opaque) +{ + int ret; + + if (kvm_enabled() && !kvm_has_sync_mmu()) { + qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); + return -1; + } + + ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque); + if (ret == 0) { + qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); + return -1; + } + + cb(opaque, NULL); + return 0; +} diff --git a/balloon.h b/balloon.h index 8c019eb78b..d478e28475 100644 --- a/balloon.h +++ b/balloon.h @@ -14,6 +14,8 @@ #ifndef _QEMU_BALLOON_H #define _QEMU_BALLOON_H +#include "monitor.h" + typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target, MonitorCompletion cb, void *cb_data); @@ -23,4 +25,9 @@ int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque); int qemu_balloon_status(MonitorCompletion cb, void *opaque); +void monitor_print_balloon(Monitor *mon, const QObject *data); +int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque); +int do_balloon(Monitor *mon, const QDict *params, + MonitorCompletion cb, void *opaque); + #endif diff --git a/block.c b/block.c index e891544dd1..0881c93cf9 100644 --- a/block.c +++ b/block.c @@ -1740,7 +1740,7 @@ static void multiwrite_cb(void *opaque, int ret) { MultiwriteCB *mcb = opaque; - if (ret < 0) { + if (ret < 0 && !mcb->error) { mcb->error = ret; multiwrite_user_cb(mcb); } @@ -1881,10 +1881,11 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) // submitted yet. Otherwise we'll wait for the submitted AIOs to // complete and report the error in the callback. if (mcb->num_requests == 0) { - reqs[i].error = EIO; + reqs[i].error = -EIO; goto fail; } else { - mcb->error = EIO; + mcb->num_requests++; + multiwrite_cb(mcb, -EIO); break; } } else { diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index b13b6935f8..c7057b1664 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -811,6 +811,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size); if (cluster_offset < 0) { + QLIST_REMOVE(m, next_in_flight); return cluster_offset; } diff --git a/block/qcow2.c b/block/qcow2.c index 5b6dad9d59..4e97eb605d 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -468,8 +468,10 @@ static void qcow_aio_read_cb(void *opaque, int ret) (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->cur_nr_sectors, qcow_aio_read_cb, acb); - if (acb->hd_aiocb == NULL) + if (acb->hd_aiocb == NULL) { + ret = -EIO; goto done; + } } return; @@ -621,11 +623,17 @@ static void qcow_aio_write_cb(void *opaque, int ret) (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->cur_nr_sectors, qcow_aio_write_cb, acb); - if (acb->hd_aiocb == NULL) - goto done; + if (acb->hd_aiocb == NULL) { + ret = -EIO; + goto fail; + } return; +fail: + if (acb->l2meta.nb_clusters != 0) { + QLIST_REMOVE(&acb->l2meta, next_in_flight); + } done: if (acb->qiov->niov > 1) qemu_vfree(acb->orig_buf); diff --git a/block/raw-posix.c b/block/raw-posix.c index ed8db5ed1a..6521ca442a 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -142,7 +142,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, s->open_flags |= O_RDWR; } else { s->open_flags |= O_RDONLY; - bs->read_only = 1; } /* Use O_DSYNC for write-through caching, no flags for write-back caching, diff --git a/configure b/configure index 1d5fb17ec7..7c06719539 100755 --- a/configure +++ b/configure @@ -722,6 +722,9 @@ case "$cpu" in ia64*) host_guest_base="yes" ;; + hppa*) + host_guest_base="yes" + ;; esac [ -z "$guest_base" ] && guest_base="$host_guest_base" @@ -1485,7 +1488,7 @@ EOF kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include" fi else - kvm_cflags=`pkg-config --cflags kvm-kmod 2> /dev/null` + kvm_cflags=`$pkgconfig --cflags kvm-kmod 2>/dev/null` fi if compile_prog "$kvm_cflags" "" ; then kvm=yes @@ -2744,7 +2747,7 @@ if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then # -static is used to avoid g1/g3 usage by the dynamic linker ldflags="$linker_script -static $ldflags" ;; - i386|x86_64|ppc|ppc64|s390|sparc64|alpha|arm|m68k|mips|mips64|ia64) + *) ldflags="$linker_script $ldflags" ;; esac diff --git a/cpu-all.h b/cpu-all.h index 927445c49a..3004d0fd31 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -888,6 +888,11 @@ static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; } +static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS]; +} + static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, int dirty_flags) { @@ -899,6 +904,27 @@ static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; } +static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr, + int dirty_flags) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags; +} + +static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start, + int length, + int dirty_flags) +{ + int i, mask, len; + uint8_t *p; + + len = length >> TARGET_PAGE_BITS; + mask = ~dirty_flags; + p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); + for (i = 0; i < len; i++) { + p[i] &= mask; + } +} + void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, int dirty_flags); void cpu_tlb_update_dirty(CPUState *env); diff --git a/cpu-common.h b/cpu-common.h index ce0221b197..b730ca033d 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -7,6 +7,14 @@ #define WORDS_ALIGNED #endif +#ifdef TARGET_PHYS_ADDR_BITS +#include "targphys.h" +#endif + +#ifndef NEED_CPU_H +#include "poison.h" +#endif + #include "bswap.h" #include "qemu-queue.h" diff --git a/cpu-exec.c b/cpu-exec.c index 372aeac1a3..0f84857b1f 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1197,15 +1197,39 @@ int cpu_signal_handler(int host_signum, void *pinfo, { struct siginfo *info = pinfo; struct ucontext *uc = puc; - unsigned long pc; - int is_write; + unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; + uint32_t insn = *(uint32_t *)pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster. */ + switch (insn >> 26) { + case 0x1a: /* STW */ + case 0x19: /* STH */ + case 0x18: /* STB */ + case 0x1b: /* STWM */ + is_write = 1; + break; + + case 0x09: /* CSTWX, FSTWX, FSTWS */ + case 0x0b: /* CSTDX, FSTDX, FSTDS */ + /* Distinguish from coprocessor load ... */ + is_write = (insn >> 9) & 1; + break; + + case 0x03: + switch ((insn >> 6) & 15) { + case 0xa: /* STWS */ + case 0x9: /* STHS */ + case 0x8: /* STBS */ + case 0xe: /* STWAS */ + case 0xc: /* STBYS */ + is_write = 1; + } + break; + } - pc = uc->uc_mcontext.sc_iaoq[0]; - /* FIXME: compute is_write */ - is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask, puc); } #else diff --git a/cpus.c b/cpus.c index a2e0642a46..8450ee4ff4 100644 --- a/cpus.c +++ b/cpus.c @@ -33,6 +33,12 @@ #include "cpus.h" +#ifdef SIGRTMIN +#define SIG_IPI (SIGRTMIN+4) +#else +#define SIG_IPI SIGUSR1 +#endif + static CPUState *cur_cpu; static CPUState *next_cpu; @@ -100,9 +106,7 @@ static int cpu_can_run(CPUState *env) { if (env->stop) return 0; - if (env->stopped) - return 0; - if (!vm_running) + if (env->stopped || !vm_running) return 0; return 1; } @@ -111,7 +115,7 @@ static int cpu_has_work(CPUState *env) { if (env->stop) return 1; - if (env->stopped) + if (env->stopped || !vm_running) return 0; if (!env->halted) return 1; @@ -228,6 +232,10 @@ int qemu_init_main_loop(void) return qemu_event_init(); } +void qemu_main_loop_start(void) +{ +} + void qemu_init_vcpu(void *_env) { CPUState *env = _env; @@ -320,6 +328,12 @@ int qemu_init_main_loop(void) return 0; } +void qemu_main_loop_start(void) +{ + qemu_system_ready = 1; + qemu_cond_broadcast(&qemu_system_cond); +} + static void qemu_wait_io_event_common(CPUState *env) { if (env->stop) { diff --git a/cpus.h b/cpus.h index 67c9a3b45e..4ebad3a36f 100644 --- a/cpus.h +++ b/cpus.h @@ -1,8 +1,9 @@ #ifndef QEMU_CPUS_H #define QEMU_CPUS_H -/* cpu-common.c */ +/* cpus.c */ int qemu_init_main_loop(void); +void qemu_main_loop_start(void); void resume_all_vcpus(void); void pause_all_vcpus(void); @@ -10,6 +11,7 @@ void pause_all_vcpus(void); extern int smp_cores; extern int smp_threads; extern int debug_requested; +extern int vmstop_requested; void vm_state_notify(int running, int reason); bool tcg_cpu_exec(void); void set_numa_modes(void); diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak index 15f4670215..866ed7de34 100644 --- a/default-configs/sh4-softmmu.mak +++ b/default-configs/sh4-softmmu.mak @@ -5,3 +5,5 @@ CONFIG_SERIAL=y CONFIG_PTIMER=y CONFIG_VIRTIO_PCI=y CONFIG_IDE_CORE=y +CONFIG_PFLASH_CFI02=y +CONFIG_ISA_MMIO=y diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak index 7fd5c47e61..e3e08b7f1a 100644 --- a/default-configs/sh4eb-softmmu.mak +++ b/default-configs/sh4eb-softmmu.mak @@ -5,3 +5,5 @@ CONFIG_SERIAL=y CONFIG_PTIMER=y CONFIG_VIRTIO_PCI=y CONFIG_IDE_CORE=y +CONFIG_PFLASH_CFI02=y +CONFIG_ISA_MMIO=y diff --git a/dyngen-exec.h b/dyngen-exec.h index d04eda8a91..0700a2d9bb 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -59,7 +59,7 @@ extern int printf(const char *, ...); #elif defined(__hppa__) #define AREG0 "r17" #elif defined(__mips__) -#define AREG0 "fp" +#define AREG0 "s0" #elif defined(__sparc__) #ifdef CONFIG_SOLARIS #define AREG0 "g2" diff --git a/exec-all.h b/exec-all.h index ff3b24015f..4bae1e207e 100644 --- a/exec-all.h +++ b/exec-all.h @@ -58,12 +58,8 @@ typedef struct TranslationBlock TranslationBlock; #define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; -extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; -extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; -extern target_ulong gen_opc_jump_pc[2]; -extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; #include "qemu-log.h" @@ -143,7 +139,7 @@ struct TranslationBlock { the code of this one. */ uint16_t tb_next_offset[2]; /* offset of original jump target */ #ifdef USE_DIRECT_JUMP - uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ + uint16_t tb_jmp_offset[2]; /* offset of jump instruction */ #else unsigned long tb_next[2]; /* address of jump generated code */ #endif @@ -234,9 +230,6 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, offset = tb->tb_jmp_offset[n]; tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); - offset = tb->tb_jmp_offset[n + 2]; - if (offset != 0xffff) - tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); } #else diff --git a/exec.c b/exec.c index 33854e18db..43366acfb9 100644 --- a/exec.c +++ b/exec.c @@ -2030,7 +2030,7 @@ static void tlb_protect_code(ram_addr_t ram_addr) static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr) { - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG; + cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG); } static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, @@ -2051,8 +2051,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, { CPUState *env; unsigned long length, start1; - int i, mask, len; - uint8_t *p; + int i; start &= TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); @@ -2060,11 +2059,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, length = end - start; if (length == 0) return; - len = length >> TARGET_PAGE_BITS; - mask = ~dirty_flags; - p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); - for(i = 0; i < len; i++) - p[i] &= mask; + cpu_physical_memory_mask_dirty_range(start, length, dirty_flags); /* we modify the TLB cache so that the dirty bit will be set again when accessing the range */ @@ -2889,15 +2884,12 @@ void *qemu_get_ram_ptr(ram_addr_t addr) (typically a TLB entry) back to a ram offset. */ ram_addr_t qemu_ram_addr_from_host(void *ptr) { - RAMBlock *prev; RAMBlock *block; uint8_t *host = ptr; - prev = NULL; block = ram_blocks; while (block && (block->host > host || block->host + block->length <= host)) { - prev = block; block = block->next; } if (!block) { @@ -2986,16 +2978,16 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, uint32_t val) { int dirty_flags; - dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(ram_addr, 1); - dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); #endif } stb_p(qemu_get_ram_ptr(ram_addr), val); dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags); /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) @@ -3006,16 +2998,16 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, uint32_t val) { int dirty_flags; - dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(ram_addr, 2); - dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); #endif } stw_p(qemu_get_ram_ptr(ram_addr), val); dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags); /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) @@ -3026,16 +3018,16 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, uint32_t val) { int dirty_flags; - dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(ram_addr, 4); - dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); #endif } stl_p(qemu_get_ram_ptr(ram_addr), val); dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags); /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) @@ -3486,8 +3478,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= - (0xff & ~CODE_DIRTY_FLAG); + cpu_physical_memory_set_dirty_flags( + addr1, (0xff & ~CODE_DIRTY_FLAG)); } } } else { @@ -3693,8 +3685,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= - (0xff & ~CODE_DIRTY_FLAG); + cpu_physical_memory_set_dirty_flags( + addr1, (0xff & ~CODE_DIRTY_FLAG)); } addr1 += l; access_len -= l; @@ -3828,8 +3820,8 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= - (0xff & ~CODE_DIRTY_FLAG); + cpu_physical_memory_set_dirty_flags( + addr1, (0xff & ~CODE_DIRTY_FLAG)); } } } @@ -3897,8 +3889,8 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= - (0xff & ~CODE_DIRTY_FLAG); + cpu_physical_memory_set_dirty_flags(addr1, + (0xff & ~CODE_DIRTY_FLAG)); } } } diff --git a/hw/baum.c b/hw/baum.c index 18633f4842..21326ae82b 100644 --- a/hw/baum.c +++ b/hw/baum.c @@ -564,6 +564,18 @@ static void baum_chr_read(void *opaque) } } +static void baum_close(struct CharDriverState *chr) +{ + BaumDriverState *baum = chr->opaque; + + qemu_free_timer(baum->cellCount_timer); + if (baum->brlapi) { + brlapi__closeConnection(baum->brlapi); + qemu_free(baum->brlapi); + } + qemu_free(baum); +} + CharDriverState *chr_baum_init(QemuOpts *opts) { BaumDriverState *baum; @@ -581,6 +593,7 @@ CharDriverState *chr_baum_init(QemuOpts *opts) chr->chr_write = baum_write; chr->chr_send_event = baum_send_event; chr->chr_accept_input = baum_accept_input; + chr->chr_close = baum_close; handle = qemu_mallocz(brlapi_getHandleSize()); baum->brlapi = handle; diff --git a/hw/debugcon.c b/hw/debugcon.c index d549091658..5ee6821206 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -60,7 +60,7 @@ static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) DebugconState *s = opaque; #ifdef DEBUG_DEBUGCON - printf("debugcon: read addr=0x%04x\n", addr, val); + printf("debugcon: read addr=0x%04x\n", addr); #endif return s->readback; diff --git a/hw/e1000.c b/hw/e1000.c index fd3059ad8a..34cc451cf7 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -642,7 +642,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) if (vlan_enabled(s) && is_vlan_packet(s, buf)) { vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14))); - memmove((void *)(buf + 4), buf, 12); + memmove((uint8_t *)buf + 4, buf, 12); vlan_status = E1000_RXD_STAT_VP; vlan_offset = 4; size -= 4; diff --git a/hw/hw.h b/hw/hw.h index 7b500f4e44..328b704fd8 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -5,8 +5,6 @@ #include "qemu-common.h" #if defined(TARGET_PHYS_ADDR_BITS) && !defined(NEED_CPU_H) -#include "targphys.h" -#include "poison.h" #include "cpu-common.h" #endif diff --git a/hw/i8259.c b/hw/i8259.c index 3de22e343e..37ef04e519 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -68,6 +68,7 @@ static int irq_level[16]; #ifdef DEBUG_IRQ_COUNT static uint64_t irq_count[16]; #endif +PicState2 *isa_pic; /* set irq level. If an edge is detected, then the IRR is set to 1 */ static inline void pic_set_irq1(PicState *s, int irq, int level) diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 4d489d2059..4e306de9cf 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -28,6 +28,7 @@ struct ISABus { uint32_t assigned; }; static ISABus *isabus; +target_phys_addr_t isa_mem_base = 0; static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 0daea400a8..98b7f541ce 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -679,7 +679,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, return; } - if (s->waiting == 1 || tag != s->current->tag || + if (s->waiting == 1 || !s->current || tag != s->current->tag || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { if (lsi_queue_tag(s, tag, arg)) return; diff --git a/hw/r2d.c b/hw/r2d.c index ec075db331..74b718a5cd 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -35,14 +35,20 @@ #include "ide.h" #include "loader.h" #include "usb.h" +#include "flash.h" + +#define FLASH_BASE 0x00000000 +#define FLASH_SIZE 0x02000000 #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000 #define SM501_VRAM_SIZE 0x800000 +#define BOOT_PARAMS_OFFSET 0x0010000 /* CONFIG_BOOT_LINK_OFFSET of Linux kernel */ -#define LINUX_LOAD_OFFSET 0x800000 +#define LINUX_LOAD_OFFSET 0x0800000 +#define INITRD_LOAD_OFFSET 0x1800000 #define PA_IRLMSK 0x00 #define PA_POWOFF 0x30 @@ -200,6 +206,20 @@ static int r2d_pci_map_irq(PCIDevice *d, int irq_num) return intx[d->devfn >> 3]; } +static struct __attribute__((__packed__)) +{ + int mount_root_rdonly; + int ramdisk_flags; + int orig_root_dev; + int loader_type; + int initrd_start; + int initrd_size; + + char pad[232]; + + char kernel_cmdline[256]; +} boot_params; + static void r2d_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, @@ -233,9 +253,16 @@ static void r2d_init(ram_addr_t ram_size, sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]); /* onboard CF (True IDE mode, Master only). */ - if ((dinfo = drive_get(IF_IDE, 0, 0)) != NULL) - mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1, - dinfo, NULL); + dinfo = drive_get(IF_IDE, 0, 0); + mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1, + dinfo, NULL); + + /* onboard flash memory */ + pflash_cfi02_register(0x0, qemu_ram_alloc(FLASH_SIZE), + dinfo ? dinfo->bdrv : NULL, (16 * 1024), + FLASH_SIZE >> 16, + 1, 4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x555, 0x2aa, 0); /* NIC: rtl8139 on-board, and 2 slots. */ for (i = 0; i < nb_nics; i++) @@ -245,28 +272,50 @@ static void r2d_init(ram_addr_t ram_size, usbdevice_create("keyboard"); /* Todo: register on board registers */ + memset(&boot_params, 0, sizeof(boot_params)); + if (kernel_filename) { - int kernel_size; - /* initialization which should be done by firmware */ - stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */ - stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */ - - if (kernel_cmdline) { - kernel_size = load_image_targphys(kernel_filename, - SDRAM_BASE + LINUX_LOAD_OFFSET, - SDRAM_SIZE - LINUX_LOAD_OFFSET); - env->pc = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; - pstrcpy_targphys("cmdline", SDRAM_BASE + 0x10100, 256, kernel_cmdline); - } else { - kernel_size = load_image_targphys(kernel_filename, SDRAM_BASE, SDRAM_SIZE); - env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */ - } - - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } + int kernel_size; + + kernel_size = load_image_targphys(kernel_filename, + SDRAM_BASE + LINUX_LOAD_OFFSET, + INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + /* initialization which should be done by firmware */ + stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */ + stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */ + env->pc = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */ } + + if (initrd_filename) { + int initrd_size; + + initrd_size = load_image_targphys(initrd_filename, + SDRAM_BASE + INITRD_LOAD_OFFSET, + SDRAM_SIZE - INITRD_LOAD_OFFSET); + + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); + exit(1); + } + + /* initialization which should be done by firmware */ + boot_params.loader_type = 1; + boot_params.initrd_start = INITRD_LOAD_OFFSET; + boot_params.initrd_size = initrd_size; + } + + if (kernel_cmdline) { + strncpy(boot_params.kernel_cmdline, kernel_cmdline, + sizeof(boot_params.kernel_cmdline)); + } + + rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params), + SDRAM_BASE + BOOT_PARAMS_OFFSET); } static QEMUMachine r2d_machine = { diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 3efbaabb66..fe6884d47d 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -56,7 +56,6 @@ typedef struct { static const VirtIOBindings virtio_s390_bindings; static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev); -static void s390_virtio_device_sync(VirtIOS390Device *dev); VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size) { @@ -185,7 +184,7 @@ static ram_addr_t s390_virtio_next_ring(VirtIOS390Bus *bus) return r; } -static void s390_virtio_device_sync(VirtIOS390Device *dev) +void s390_virtio_device_sync(VirtIOS390Device *dev) { VirtIOS390Bus *bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus); ram_addr_t cur_offs; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 0ea8f54745..333fea8963 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -65,3 +65,4 @@ extern VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus, int *vq_num); extern VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem); +extern void s390_virtio_device_sync(VirtIOS390Device *dev); diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index ad3386f607..c36a8b2336 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -99,10 +99,11 @@ int s390_virtio_hypercall(CPUState *env) break; case KVM_S390_VIRTIO_RESET: { - /* Virtio_reset resets the internal addresses, so we'd have to sync - them up again. We don't want to reallocate a vring though, so let's - just not reset. */ - /* virtio_reset(dev->vdev); */ + VirtIOS390Device *dev; + + dev = s390_virtio_bus_find_mem(s390_bus, mem); + virtio_reset(dev->vdev); + s390_virtio_device_sync(dev); break; } case KVM_S390_VIRTIO_SET_STATUS: diff --git a/hw/sh_pci.c b/hw/sh_pci.c index abe4c7568b..cc2f190529 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -47,10 +47,15 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val) pcic->par = val; break; case 0x1c4: - pcic->mbr = val; + pcic->mbr = val & 0xff000001; break; case 0x1c8: - pcic->iobr = val; + if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) { + cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000, + IO_MEM_UNASSIGNED); + pcic->iobr = val & 0xfffc0001; + isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000, 0); + } break; case 0x220: pci_data_write(pcic->bus, pcic->par, val, 4); @@ -66,89 +71,16 @@ static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr) return le32_to_cpup((uint32_t*)(pcic->dev->config + addr)); case 0x1c0: return pcic->par; + case 0x1c4: + return pcic->mbr; + case 0x1c8: + return pcic->iobr; case 0x220: return pci_data_read(pcic->bus, pcic->par, 4); } return 0; } -static void sh_pci_data_write (SHPCIC *pcic, target_phys_addr_t addr, - uint32_t val, int size) -{ - pci_data_write(pcic->bus, addr + pcic->mbr, val, size); -} - -static uint32_t sh_pci_mem_read (SHPCIC *pcic, target_phys_addr_t addr, - int size) -{ - return pci_data_read(pcic->bus, addr + pcic->mbr, size); -} - -static void sh_pci_writeb (void *p, target_phys_addr_t addr, uint32_t val) -{ - sh_pci_data_write(p, addr, val, 1); -} - -static void sh_pci_writew (void *p, target_phys_addr_t addr, uint32_t val) -{ - sh_pci_data_write(p, addr, val, 2); -} - -static void sh_pci_writel (void *p, target_phys_addr_t addr, uint32_t val) -{ - sh_pci_data_write(p, addr, val, 4); -} - -static uint32_t sh_pci_readb (void *p, target_phys_addr_t addr) -{ - return sh_pci_mem_read(p, addr, 1); -} - -static uint32_t sh_pci_readw (void *p, target_phys_addr_t addr) -{ - return sh_pci_mem_read(p, addr, 2); -} - -static uint32_t sh_pci_readl (void *p, target_phys_addr_t addr) -{ - return sh_pci_mem_read(p, addr, 4); -} - -static int sh_pci_addr2port(SHPCIC *pcic, target_phys_addr_t addr) -{ - return addr + pcic->iobr; -} - -static void sh_pci_outb (void *p, target_phys_addr_t addr, uint32_t val) -{ - cpu_outb(sh_pci_addr2port(p, addr), val); -} - -static void sh_pci_outw (void *p, target_phys_addr_t addr, uint32_t val) -{ - cpu_outw(sh_pci_addr2port(p, addr), val); -} - -static void sh_pci_outl (void *p, target_phys_addr_t addr, uint32_t val) -{ - cpu_outl(sh_pci_addr2port(p, addr), val); -} - -static uint32_t sh_pci_inb (void *p, target_phys_addr_t addr) -{ - return cpu_inb(sh_pci_addr2port(p, addr)); -} - -static uint32_t sh_pci_inw (void *p, target_phys_addr_t addr) -{ - return cpu_inw(sh_pci_addr2port(p, addr)); -} - -static uint32_t sh_pci_inl (void *p, target_phys_addr_t addr) -{ - return cpu_inl(sh_pci_addr2port(p, addr)); -} - typedef struct { CPUReadMemoryFunc * const r[3]; CPUWriteMemoryFunc * const w[3]; @@ -159,21 +91,11 @@ static MemOp sh_pci_reg = { { NULL, NULL, sh_pci_reg_write }, }; -static MemOp sh_pci_mem = { - { sh_pci_readb, sh_pci_readw, sh_pci_readl }, - { sh_pci_writeb, sh_pci_writew, sh_pci_writel }, -}; - -static MemOp sh_pci_iop = { - { sh_pci_inb, sh_pci_inw, sh_pci_inl }, - { sh_pci_outb, sh_pci_outw, sh_pci_outl }, -}; - PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *opaque, int devfn_min, int nirq) { SHPCIC *p; - int mem, reg, iop; + int reg; p = qemu_mallocz(sizeof(SHPCIC)); p->bus = pci_register_bus(NULL, "pci", @@ -182,14 +104,11 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice), -1, NULL, NULL); reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p); - iop = cpu_register_io_memory(sh_pci_iop.r, sh_pci_iop.w, p); - mem = cpu_register_io_memory(sh_pci_mem.r, sh_pci_mem.w, p); cpu_register_physical_memory(0x1e200000, 0x224, reg); - cpu_register_physical_memory(0x1e240000, 0x40000, iop); - cpu_register_physical_memory(0x1d000000, 0x1000000, mem); cpu_register_physical_memory(0xfe200000, 0x224, reg); - cpu_register_physical_memory(0xfe240000, 0x40000, iop); - cpu_register_physical_memory(0xfd000000, 0x1000000, mem); + + p->iobr = 0xfe240000; + isa_mmio_init(p->iobr, 0x40000, 0); pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI); pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index c1a88c9e56..e4a24476e8 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -250,6 +250,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, { smc91c111_state *s = (smc91c111_state *)opaque; + offset = offset & 0xf; if (offset == 14) { s->bank = value; return; @@ -276,6 +277,8 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, case 10: case 11: /* RPCR */ /* Ignored */ return; + case 12: case 13: /* Reserved */ + return; } break; @@ -421,6 +424,7 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) { smc91c111_state *s = (smc91c111_state *)opaque; + offset = offset & 0xf; if (offset == 14) { return s->bank; } @@ -461,6 +465,8 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) case 10: case 11: /* RPCR */ /* Not implemented. */ return 0; + case 12: case 13: /* Reserved */ + return 0; } break; diff --git a/hw/vga.c b/hw/vga.c index 6a1a0597d5..bb65677e89 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -522,7 +522,7 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) VGACommonState *s = opaque; uint32_t val; - if (s->vbe_index <= VBE_DISPI_INDEX_NB) { + if (s->vbe_index < VBE_DISPI_INDEX_NB) { if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { switch(s->vbe_index) { /* XXX: do not hardcode ? */ @@ -542,6 +542,8 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) } else { val = s->vbe_regs[s->vbe_index]; } + } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) { + val = s->vram_size / (64 * 1024); } else { val = 0; } @@ -1955,7 +1957,7 @@ void vga_common_reset(VGACommonState *s) #ifdef CONFIG_BOCHS_VBE s->vbe_index = 0; memset(s->vbe_regs, '\0', sizeof(s->vbe_regs)); - s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; + s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5; s->vbe_start_addr = 0; s->vbe_line_offset = 0; s->vbe_bank_mask = (s->vram_size >> 16) - 1; diff --git a/hw/vga_int.h b/hw/vga_int.h index 23a42efce1..6a46a434fe 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -47,13 +47,15 @@ #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 #define VBE_DISPI_INDEX_X_OFFSET 0x8 #define VBE_DISPI_INDEX_Y_OFFSET 0x9 -#define VBE_DISPI_INDEX_NB 0xa +#define VBE_DISPI_INDEX_NB 0xa /* size of vbe_regs[] */ +#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */ #define VBE_DISPI_ID0 0xB0C0 #define VBE_DISPI_ID1 0xB0C1 #define VBE_DISPI_ID2 0xB0C2 #define VBE_DISPI_ID3 0xB0C3 #define VBE_DISPI_ID4 0xB0C4 +#define VBE_DISPI_ID5 0xB0C5 #define VBE_DISPI_DISABLED 0x00 #define VBE_DISPI_ENABLED 0x01 diff --git a/kvm.h b/kvm.h index 1e5be27a38..b90c67a498 100644 --- a/kvm.h +++ b/kvm.h @@ -36,6 +36,10 @@ struct kvm_run; int kvm_init(int smp_cpus); +int kvm_has_sync_mmu(void); +int kvm_has_vcpu_events(void); +int kvm_has_robust_singlestep(void); + #ifdef NEED_CPU_H int kvm_init_vcpu(CPUState *env); @@ -45,10 +49,6 @@ int kvm_cpu_exec(CPUState *env); int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size); int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); -int kvm_has_sync_mmu(void); -int kvm_has_vcpu_events(void); -int kvm_has_robust_singlestep(void); - void kvm_setup_guest_memory(void *start, size_t size); int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); diff --git a/linux-user/main.c b/linux-user/main.c index ca49cc4891..b394c00829 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2788,7 +2788,7 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_PPC) #ifdef TARGET_PPC64 - cpu_model = "970"; + cpu_model = "970fx"; #else cpu_model = "750"; #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a03e4329e8..26c0fb4dc6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2752,7 +2752,7 @@ static inline abi_long do_shmdt(abi_ulong shmaddr) for (i = 0; i < N_SHM_REGIONS; ++i) { if (shm_regions[i].start == shmaddr) { shm_regions[i].start = 0; - page_set_flags(shmaddr, shm_regions[i].size, 0); + page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0); break; } } diff --git a/m68k-dis.c b/m68k-dis.c index d38d5a2591..7cd88f8509 100644 --- a/m68k-dis.c +++ b/m68k-dis.c @@ -1104,7 +1104,7 @@ print_insn_arg (const char *d, { static const char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; val = fetch_arg (buffer, place, 2, info); - (*info->fprintf_func) (info->stream, cacheFieldName[val]); + (*info->fprintf_func) (info->stream, "%s", cacheFieldName[val]); break; } @@ -1199,7 +1199,7 @@ print_insn_arg (const char *d, { static const char *const scalefactor_name[] = { "<<", ">>" }; val = fetch_arg (buffer, place, 1, info); - (*info->fprintf_func) (info->stream, scalefactor_name[val]); + (*info->fprintf_func) (info->stream, "%s", scalefactor_name[val]); } else { @@ -1804,7 +1804,7 @@ match_insn_m68k (bfd_vma memaddr, save_p = p; info->print_address_func = dummy_print_address; - info->fprintf_func = (fprintf_ftype) dummy_printer; + info->fprintf_func = dummy_printer; /* We scan the operands twice. The first time we don't print anything, but look for errors. */ diff --git a/monitor.c b/monitor.c index 822dc27642..5659991b87 100644 --- a/monitor.c +++ b/monitor.c @@ -2266,91 +2266,6 @@ static void do_info_status(Monitor *mon, QObject **ret_data) vm_running, singlestep); } -static void print_balloon_stat(const char *key, QObject *obj, void *opaque) -{ - Monitor *mon = opaque; - - if (strcmp(key, "actual")) - monitor_printf(mon, ",%s=%" PRId64, key, - qint_get_int(qobject_to_qint(obj))); -} - -static void monitor_print_balloon(Monitor *mon, const QObject *data) -{ - QDict *qdict; - - qdict = qobject_to_qdict(data); - if (!qdict_haskey(qdict, "actual")) - return; - - monitor_printf(mon, "balloon: actual=%" PRId64, - qdict_get_int(qdict, "actual") >> 20); - qdict_iter(qdict, print_balloon_stat, mon); - monitor_printf(mon, "\n"); -} - -/** - * do_info_balloon(): Balloon information - * - * Make an asynchronous request for balloon info. When the request completes - * a QDict will be returned according to the following specification: - * - * - "actual": current balloon value in bytes - * The following fields may or may not be present: - * - "mem_swapped_in": Amount of memory swapped in (bytes) - * - "mem_swapped_out": Amount of memory swapped out (bytes) - * - "major_page_faults": Number of major faults - * - "minor_page_faults": Number of minor faults - * - "free_mem": Total amount of free and unused memory (bytes) - * - "total_mem": Total amount of available memory (bytes) - * - * Example: - * - * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0, - * "major_page_faults": 142, "minor_page_faults": 239245, - * "free_mem": 1014185984, "total_mem": 1044668416 } - */ -static int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque) -{ - int ret; - - if (kvm_enabled() && !kvm_has_sync_mmu()) { - qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); - return -1; - } - - ret = qemu_balloon_status(cb, opaque); - if (!ret) { - qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); - return -1; - } - - return 0; -} - -/** - * do_balloon(): Request VM to change its memory allocation - */ -static int do_balloon(Monitor *mon, const QDict *params, - MonitorCompletion cb, void *opaque) -{ - int ret; - - if (kvm_enabled() && !kvm_has_sync_mmu()) { - qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); - return -1; - } - - ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque); - if (ret == 0) { - qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); - return -1; - } - - cb(opaque, NULL); - return 0; -} - static qemu_acl *find_acl(Monitor *mon, const char *name) { qemu_acl *acl = qemu_acl_find(name); diff --git a/net.c b/net.c index 3ede738cac..b66ec7dba5 100644 --- a/net.c +++ b/net.c @@ -1198,26 +1198,6 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict) qemu_del_vlan_client(vc); } -void net_set_boot_mask(int net_boot_mask) -{ - int i; - - /* Only the first four NICs may be bootable */ - net_boot_mask = net_boot_mask & 0xF; - - for (i = 0; i < nb_nics; i++) { - if (net_boot_mask & (1 << i)) { - nd_table[i].bootable = 1; - net_boot_mask &= ~(1 << i); - } - } - - if (net_boot_mask) { - fprintf(stderr, "Cannot boot from non-existent NIC\n"); - exit(1); - } -} - void do_info_network(Monitor *mon) { VLANState *vlan; diff --git a/net.h b/net.h index 16f19c5ce1..20be8d7ea9 100644 --- a/net.h +++ b/net.h @@ -132,7 +132,6 @@ struct NICInfo { VLANState *vlan; VLANClientState *netdev; int used; - int bootable; int nvectors; }; @@ -163,7 +162,6 @@ int net_client_parse(QemuOptsList *opts_list, const char *str); int net_init_clients(void); void net_check_clients(void); void net_cleanup(void); -void net_set_boot_mask(int boot_mask); void net_host_device_add(Monitor *mon, const QDict *qdict); void net_host_device_remove(Monitor *mon, const QDict *qdict); diff --git a/hw/poison.h b/poison.h index d7db7f43b6..d7db7f43b6 100644 --- a/hw/poison.h +++ b/poison.h diff --git a/qemu-char.c b/qemu-char.c index 048da3fec1..05df971412 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -109,6 +109,16 @@ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = static void qemu_chr_event(CharDriverState *s, int event) { + /* Keep track if the char device is open */ + switch (event) { + case CHR_EVENT_OPENED: + s->opened = 1; + break; + case CHR_EVENT_CLOSED: + s->opened = 0; + break; + } + if (!s->chr_event) return; s->chr_event(s->handler_opaque, event); @@ -193,6 +203,12 @@ void qemu_chr_add_handlers(CharDriverState *s, s->handler_opaque = opaque; if (s->chr_update_read_handler) s->chr_update_read_handler(s); + + /* We're connecting to an already opened device, so let's make sure we + also get the open event */ + if (s->opened) { + qemu_chr_generic_open(s); + } } static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) @@ -465,6 +481,10 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; chr->chr_accept_input = mux_chr_accept_input; + + /* Muxes are always open on creation */ + qemu_chr_generic_open(chr); + return chr; } @@ -1220,7 +1240,7 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) return chr; } #else /* ! __linux__ && ! __sun__ */ -static CharDriverState *qemu_chr_open_pty(void) +static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) { return NULL; } diff --git a/qemu-char.h b/qemu-char.h index 3a9427be67..e3a07838a4 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -67,6 +67,7 @@ struct CharDriverState { QEMUBH *bh; char *label; char *filename; + int opened; QTAILQ_ENTRY(CharDriverState) next; }; diff --git a/qemu-sockets.c b/qemu-sockets.c index 23c3def2a4..a7399aa945 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -648,3 +648,27 @@ int unix_connect(const char *path) } #endif + +#ifdef _WIN32 +static void socket_cleanup(void) +{ + WSACleanup(); +} +#endif + +int socket_init(void) +{ +#ifdef _WIN32 + WSADATA Data; + int ret, err; + + ret = WSAStartup(MAKEWORD(2,2), &Data); + if (ret != 0) { + err = WSAGetLastError(); + fprintf(stderr, "WSAStartup: %d\n", err); + return -1; + } + atexit(socket_cleanup); +#endif + return 0; +} diff --git a/qemu_socket.h b/qemu_socket.h index 7ee46ac4ec..164ae3eb4e 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -56,5 +56,6 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str); int parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *str); +int socket_init(void); #endif /* QEMU_SOCKET_H */ diff --git a/sh4-dis.c b/sh4-dis.c index 41fd8667b8..078a6b206b 100644 --- a/sh4-dis.c +++ b/sh4-dis.c @@ -1493,10 +1493,10 @@ print_insn_ppi (int field_b, struct disassemble_info *info) print_dsp_reg (field_b & 0xf, fprintf_fn, stream); break; case DSP_REG_X: - fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]); + fprintf_fn (stream, "%s", sx_tab[(field_b >> 6) & 3]); break; case DSP_REG_Y: - fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]); + fprintf_fn (stream, "%s", sy_tab[(field_b >> 4) & 3]); break; case A_MACH: fprintf_fn (stream, "mach"); diff --git a/sparc-dis.c b/sparc-dis.c index 83a12ae99d..611e74f8ae 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -2778,7 +2778,7 @@ print_insn_sparc (bfd_vma memaddr, disassemble_info *info) /* Can't do simple format if source and dest are different. */ continue; - (*info->fprintf_func) (stream, opcode->name); + (*info->fprintf_func) (stream, "%s", opcode->name); { const char *s; diff --git a/target-alpha/helper.h b/target-alpha/helper.h index 79cf375a6d..6072a26b92 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -1,9 +1,9 @@ #include "def-helper.h" DEF_HELPER_2(excp, void, int, int) -DEF_HELPER_0(load_pcc, i64) -DEF_HELPER_0(rc, i64) -DEF_HELPER_0(rs, i64) +DEF_HELPER_FLAGS_0(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64) +DEF_HELPER_FLAGS_0(rc, TCG_CALL_CONST, i64) +DEF_HELPER_FLAGS_0(rs, TCG_CALL_CONST, i64) DEF_HELPER_2(addqv, i64, i64, i64) DEF_HELPER_2(addlv, i64, i64, i64) @@ -11,98 +11,94 @@ DEF_HELPER_2(subqv, i64, i64, i64) DEF_HELPER_2(sublv, i64, i64, i64) DEF_HELPER_2(mullv, i64, i64, i64) DEF_HELPER_2(mulqv, i64, i64, i64) -DEF_HELPER_2(umulh, i64, i64, i64) - -DEF_HELPER_1(ctpop, i64, i64) -DEF_HELPER_1(ctlz, i64, i64) -DEF_HELPER_1(cttz, i64, i64) - -DEF_HELPER_2(zap, i64, i64, i64) -DEF_HELPER_2(zapnot, i64, i64, i64) - -DEF_HELPER_2(cmpbge, i64, i64, i64) - -DEF_HELPER_2(minub8, i64, i64, i64) -DEF_HELPER_2(minsb8, i64, i64, i64) -DEF_HELPER_2(minuw4, i64, i64, i64) -DEF_HELPER_2(minsw4, i64, i64, i64) -DEF_HELPER_2(maxub8, i64, i64, i64) -DEF_HELPER_2(maxsb8, i64, i64, i64) -DEF_HELPER_2(maxuw4, i64, i64, i64) -DEF_HELPER_2(maxsw4, i64, i64, i64) -DEF_HELPER_2(perr, i64, i64, i64) -DEF_HELPER_1(pklb, i64, i64) -DEF_HELPER_1(pkwb, i64, i64) -DEF_HELPER_1(unpkbl, i64, i64) -DEF_HELPER_1(unpkbw, i64, i64) - -DEF_HELPER_0(load_fpcr, i64) -DEF_HELPER_1(store_fpcr, void, i64) - -DEF_HELPER_1(f_to_memory, i32, i64) -DEF_HELPER_1(memory_to_f, i64, i32) -DEF_HELPER_2(addf, i64, i64, i64) -DEF_HELPER_2(subf, i64, i64, i64) -DEF_HELPER_2(mulf, i64, i64, i64) -DEF_HELPER_2(divf, i64, i64, i64) -DEF_HELPER_1(sqrtf, i64, i64) - -DEF_HELPER_1(g_to_memory, i64, i64) -DEF_HELPER_1(memory_to_g, i64, i64) -DEF_HELPER_2(addg, i64, i64, i64) -DEF_HELPER_2(subg, i64, i64, i64) -DEF_HELPER_2(mulg, i64, i64, i64) -DEF_HELPER_2(divg, i64, i64, i64) -DEF_HELPER_1(sqrtg, i64, i64) - -DEF_HELPER_1(s_to_memory, i32, i64) -DEF_HELPER_1(memory_to_s, i64, i32) -DEF_HELPER_2(adds, i64, i64, i64) -DEF_HELPER_2(subs, i64, i64, i64) -DEF_HELPER_2(muls, i64, i64, i64) -DEF_HELPER_2(divs, i64, i64, i64) -DEF_HELPER_1(sqrts, i64, i64) - -DEF_HELPER_2(addt, i64, i64, i64) -DEF_HELPER_2(subt, i64, i64, i64) -DEF_HELPER_2(mult, i64, i64, i64) -DEF_HELPER_2(divt, i64, i64, i64) -DEF_HELPER_1(sqrtt, i64, i64) - -DEF_HELPER_2(cmptun, i64, i64, i64) -DEF_HELPER_2(cmpteq, i64, i64, i64) -DEF_HELPER_2(cmptle, i64, i64, i64) -DEF_HELPER_2(cmptlt, i64, i64, i64) -DEF_HELPER_2(cmpgeq, i64, i64, i64) -DEF_HELPER_2(cmpgle, i64, i64, i64) -DEF_HELPER_2(cmpglt, i64, i64, i64) - -DEF_HELPER_2(cpys, i64, i64, i64) -DEF_HELPER_2(cpysn, i64, i64, i64) -DEF_HELPER_2(cpyse, i64, i64, i64) - -DEF_HELPER_1(cvtts, i64, i64) -DEF_HELPER_1(cvtst, i64, i64) -DEF_HELPER_1(cvtqs, i64, i64) -DEF_HELPER_1(cvtqt, i64, i64) -DEF_HELPER_1(cvtqf, i64, i64) -DEF_HELPER_1(cvtgf, i64, i64) -DEF_HELPER_1(cvtgq, i64, i64) -DEF_HELPER_1(cvtqg, i64, i64) -DEF_HELPER_1(cvtlq, i64, i64) - -DEF_HELPER_1(cvttq, i64, i64) -DEF_HELPER_1(cvttq_c, i64, i64) -DEF_HELPER_1(cvttq_svic, i64, i64) - -DEF_HELPER_1(cvtql, i64, i64) -DEF_HELPER_1(cvtql_v, i64, i64) -DEF_HELPER_1(cvtql_sv, i64, i64) - -DEF_HELPER_1(setroundmode, void, i32) -DEF_HELPER_1(setflushzero, void, i32) -DEF_HELPER_0(fp_exc_clear, void) -DEF_HELPER_0(fp_exc_get, i32) +DEF_HELPER_FLAGS_2(umulh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) + +DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_1(cttz, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) + +DEF_HELPER_FLAGS_2(zap, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) + +DEF_HELPER_FLAGS_2(cmpbge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) + +DEF_HELPER_FLAGS_2(minub8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(minsb8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(minuw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(minsw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxub8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxsb8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxuw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxsw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(perr, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_1(pklb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_1(pkwb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) + +DEF_HELPER_FLAGS_0(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64) +DEF_HELPER_FLAGS_1(store_fpcr, TCG_CALL_CONST, void, i64) + +DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64) +DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32) +DEF_HELPER_FLAGS_2(addf, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(subf, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(mulf, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(divf, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_1(sqrtf, TCG_CALL_CONST, i64, i64) + +DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_2(addg, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(subg, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(mulg, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(divg, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_1(sqrtg, TCG_CALL_CONST, i64, i64) + +DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64) +DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32) +DEF_HELPER_FLAGS_2(adds, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(subs, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(muls, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(divs, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_1(sqrts, TCG_CALL_CONST, i64, i64) + +DEF_HELPER_FLAGS_2(addt, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(subt, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(mult, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_2(divt, TCG_CALL_CONST, i64, i64, i64) +DEF_HELPER_FLAGS_1(sqrtt, TCG_CALL_CONST, i64, i64) + +DEF_HELPER_FLAGS_2(cmptun, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmpteq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmptle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmptlt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmpgeq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmpgle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmpglt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) + +DEF_HELPER_FLAGS_2(cpys, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cpysn, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cpyse, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) + +DEF_HELPER_FLAGS_1(cvtts, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtst, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtqs, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtqt, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtqf, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtgf, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtgq, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtqg, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvtlq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) + +DEF_HELPER_FLAGS_1(cvttq, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvttq_c, TCG_CALL_CONST, i64, i64) +DEF_HELPER_FLAGS_1(cvttq_svic, TCG_CALL_CONST, i64, i64) + +DEF_HELPER_FLAGS_1(setroundmode, TCG_CALL_CONST, void, i32) +DEF_HELPER_FLAGS_1(setflushzero, TCG_CALL_CONST, void, i32) +DEF_HELPER_FLAGS_0(fp_exc_clear, TCG_CALL_CONST, void) +DEF_HELPER_FLAGS_0(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32) DEF_HELPER_2(fp_exc_raise, void, i32, i32) DEF_HELPER_2(fp_exc_raise_s, void, i32, i32) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 4d2c2ee58e..dd1af849c4 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1203,26 +1203,6 @@ uint64_t helper_cvtlq (uint64_t a) return (lo & 0x3FFFFFFF) | (hi & 0xc0000000); } -uint64_t helper_cvtql (uint64_t a) -{ - return ((a & 0xC0000000) << 32) | ((a & 0x7FFFFFFF) << 29); -} - -uint64_t helper_cvtql_v (uint64_t a) -{ - if ((int32_t)a != (int64_t)a) - helper_excp(EXCP_ARITH, EXC_M_IOV); - return helper_cvtql(a); -} - -uint64_t helper_cvtql_sv (uint64_t a) -{ - /* ??? I'm pretty sure there's nothing that /sv needs to do that /v - doesn't do. The only thing I can think is that /sv is a valid - instruction merely for completeness in the ISA. */ - return helper_cvtql_v(a); -} - /* PALcode support special instructions */ #if !defined (CONFIG_USER_ONLY) void helper_hw_rei (void) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 719b42319a..d903800dc0 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -394,9 +394,10 @@ static void gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, int32_t disp) gen_bcond_pcload(ctx, disp, lab_true); } -static inline void gen_cmov(TCGCond inv_cond, int ra, int rb, int rc, - int islit, uint8_t lit, int mask) +static void gen_cmov(TCGCond cond, int ra, int rb, int rc, + int islit, uint8_t lit, int mask) { + TCGCond inv_cond = tcg_invert_cond(cond); int l1; if (unlikely(rc == 31)) @@ -426,7 +427,7 @@ static inline void gen_cmov(TCGCond inv_cond, int ra, int rb, int rc, gen_set_label(l1); } -static void gen_fcmov(TCGCond inv_cond, int ra, int rb, int rc) +static void gen_fcmov(TCGCond cond, int ra, int rb, int rc) { TCGv va = cpu_fir[ra]; int l1; @@ -439,7 +440,7 @@ static void gen_fcmov(TCGCond inv_cond, int ra, int rb, int rc) } l1 = gen_new_label(); - gen_fbcond_internal(inv_cond, va, l1); + gen_fbcond_internal(tcg_invert_cond(cond), va, l1); if (rb != 31) tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[rb]); @@ -597,6 +598,41 @@ static inline void gen_fp_exc_raise(int rc, int fn11) gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : float_flag_inexact); } +static void gen_fcvtql(int rb, int rc) +{ + if (unlikely(rc == 31)) { + return; + } + if (unlikely(rb == 31)) { + tcg_gen_movi_i64(cpu_fir[rc], 0); + } else { + TCGv tmp = tcg_temp_new(); + + tcg_gen_andi_i64(tmp, cpu_fir[rb], 0xC0000000); + tcg_gen_andi_i64(cpu_fir[rc], cpu_fir[rb], 0x3FFFFFFF); + tcg_gen_shli_i64(tmp, tmp, 32); + tcg_gen_shli_i64(cpu_fir[rc], cpu_fir[rc], 29); + tcg_gen_or_i64(cpu_fir[rc], cpu_fir[rc], tmp); + + tcg_temp_free(tmp); + } +} + +static void gen_fcvtql_v(DisasContext *ctx, int rb, int rc) +{ + if (rb != 31) { + int lab = gen_new_label(); + TCGv tmp = tcg_temp_new(); + + tcg_gen_ext32s_i64(tmp, cpu_fir[rb]); + tcg_gen_brcond_i64(TCG_COND_EQ, tmp, cpu_fir[rb], lab); + gen_excp(ctx, EXCP_ARITH, EXC_M_IOV); + + gen_set_label(lab); + } + gen_fcvtql(rb, rc); +} + #define FARITH2(name) \ static inline void glue(gen_f, name)(int rb, int rc) \ { \ @@ -612,9 +648,6 @@ static inline void glue(gen_f, name)(int rb, int rc) \ } \ } FARITH2(cvtlq) -FARITH2(cvtql) -FARITH2(cvtql_v) -FARITH2(cvtql_sv) /* ??? VAX instruction qualifiers ignored. */ FARITH2(sqrtf) @@ -1167,33 +1200,34 @@ MVIOP2(pkwb) MVIOP2(unpkbl) MVIOP2(unpkbw) -static inline void gen_cmp(TCGCond cond, int ra, int rb, int rc, int islit, - uint8_t lit) +static void gen_cmp(TCGCond cond, int ra, int rb, int rc, + int islit, uint8_t lit) { - int l1, l2; - TCGv tmp; + TCGv va, vb; - if (unlikely(rc == 31)) + if (unlikely(rc == 31)) { return; + } - l1 = gen_new_label(); - l2 = gen_new_label(); + if (ra == 31) { + va = tcg_const_i64(0); + } else { + va = cpu_ir[ra]; + } + if (islit) { + vb = tcg_const_i64(lit); + } else { + vb = cpu_ir[rb]; + } - if (ra != 31) { - tmp = tcg_temp_new(); - tcg_gen_mov_i64(tmp, cpu_ir[ra]); - } else - tmp = tcg_const_i64(0); - if (islit) - tcg_gen_brcondi_i64(cond, tmp, lit, l1); - else - tcg_gen_brcond_i64(cond, tmp, cpu_ir[rb], l1); + tcg_gen_setcond_i64(cond, cpu_ir[rc], va, vb); - tcg_gen_movi_i64(cpu_ir[rc], 0); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_movi_i64(cpu_ir[rc], 1); - gen_set_label(l2); + if (ra == 31) { + tcg_temp_free(va); + } + if (islit) { + tcg_temp_free(vb); + } } static inline int translate_one(DisasContext *ctx, uint32_t insn) @@ -1630,11 +1664,11 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x14: /* CMOVLBS */ - gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 1); + gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 1); break; case 0x16: /* CMOVLBC */ - gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 1); + gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 1); break; case 0x20: /* BIS */ @@ -1654,11 +1688,11 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x24: /* CMOVEQ */ - gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 0); + gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 0); break; case 0x26: /* CMOVNE */ - gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 0); + gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 0); break; case 0x28: /* ORNOT */ @@ -1694,11 +1728,11 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x44: /* CMOVLT */ - gen_cmov(TCG_COND_GE, ra, rb, rc, islit, lit, 0); + gen_cmov(TCG_COND_LT, ra, rb, rc, islit, lit, 0); break; case 0x46: /* CMOVGE */ - gen_cmov(TCG_COND_LT, ra, rb, rc, islit, lit, 0); + gen_cmov(TCG_COND_GE, ra, rb, rc, islit, lit, 0); break; case 0x48: /* EQV */ @@ -1738,11 +1772,11 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x64: /* CMOVLE */ - gen_cmov(TCG_COND_GT, ra, rb, rc, islit, lit, 0); + gen_cmov(TCG_COND_LE, ra, rb, rc, islit, lit, 0); break; case 0x66: /* CMOVGT */ - gen_cmov(TCG_COND_LE, ra, rb, rc, islit, lit, 0); + gen_cmov(TCG_COND_GT, ra, rb, rc, islit, lit, 0); break; case 0x6C: /* IMPLVER */ @@ -2216,27 +2250,27 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x02A: /* FCMOVEQ */ - gen_fcmov(TCG_COND_NE, ra, rb, rc); + gen_fcmov(TCG_COND_EQ, ra, rb, rc); break; case 0x02B: /* FCMOVNE */ - gen_fcmov(TCG_COND_EQ, ra, rb, rc); + gen_fcmov(TCG_COND_NE, ra, rb, rc); break; case 0x02C: /* FCMOVLT */ - gen_fcmov(TCG_COND_GE, ra, rb, rc); + gen_fcmov(TCG_COND_LT, ra, rb, rc); break; case 0x02D: /* FCMOVGE */ - gen_fcmov(TCG_COND_LT, ra, rb, rc); + gen_fcmov(TCG_COND_GE, ra, rb, rc); break; case 0x02E: /* FCMOVLE */ - gen_fcmov(TCG_COND_GT, ra, rb, rc); + gen_fcmov(TCG_COND_LE, ra, rb, rc); break; case 0x02F: /* FCMOVGT */ - gen_fcmov(TCG_COND_LE, ra, rb, rc); + gen_fcmov(TCG_COND_GT, ra, rb, rc); break; case 0x030: /* CVTQL */ @@ -2244,11 +2278,12 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x130: /* CVTQL/V */ - gen_fcvtql_v(rb, rc); - break; case 0x530: /* CVTQL/SV */ - gen_fcvtql_sv(rb, rc); + /* ??? I'm pretty sure there's nothing that /sv needs to do that + /v doesn't do. The only thing I can think is that /sv is a + valid instruction merely for completeness in the ISA. */ + gen_fcvtql_v(ctx, rb, rc); break; default: goto invalid_opc; diff --git a/target-arm/translate.c b/target-arm/translate.c index 3b84c1dabd..5c54919c38 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1131,6 +1131,7 @@ static inline TCGv iwmmxt_load_creg(int reg) static inline void iwmmxt_store_creg(int reg, TCGv var) { tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); + dead_tmp(var); } static inline void gen_op_iwmmxt_movq_wRn_M0(int rn) @@ -1415,6 +1416,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) } } } + dead_tmp(addr); return 0; } @@ -4888,7 +4890,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) imm = (imm << 8) | (imm << 24); break; case 12: - imm = (imm < 8) | 0xff; + imm = (imm << 8) | 0xff; break; case 13: imm = (imm << 16) | 0xffff; diff --git a/target-i386/helper.c b/target-i386/helper.c index 35ab72090a..3835835103 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -214,9 +214,10 @@ cpu_x86_dump_seg_cache(CPUState *env, FILE *f, "Reserved", "IntGate64", "TrapGate64" } }; - cpu_fprintf(f, sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0] - [(sc->flags & DESC_TYPE_MASK) - >> DESC_TYPE_SHIFT]); + cpu_fprintf(f, "%s", + sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0] + [(sc->flags & DESC_TYPE_MASK) + >> DESC_TYPE_SHIFT]); } done: cpu_fprintf(f, "\n"); diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 22259dfcd7..dcbdfe7e0b 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -1231,7 +1231,7 @@ void do_interrupt(int intno, int is_int, int error_code, #if 0 { int i; - uint8_t *ptr; + target_ulong ptr; qemu_log(" code="); ptr = env->segs[R_CS].base + env->eip; for(i = 0; i < 16; i++) { diff --git a/target-i386/translate.c b/target-i386/translate.c index 28d9940ef6..307aabdd30 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -72,6 +72,8 @@ static TCGv_i32 cpu_tmp2_i32, cpu_tmp3_i32; static TCGv_i64 cpu_tmp1_i64; static TCGv cpu_tmp5; +static uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; + #include "gen-icount.h" #ifdef TARGET_X86_64 diff --git a/target-mips/translate.c b/target-mips/translate.c index 0ade3bd48c..7cb539d407 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -442,6 +442,8 @@ static TCGv cpu_dspctrl, btarget, bcond; static TCGv_i32 hflags; static TCGv_i32 fpu_fcr0, fpu_fcr31; +static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + #include "gen-icount.h" #define gen_helper_0i(name, arg) do { \ @@ -9563,20 +9565,26 @@ static void fpu_dump_state(CPUState *env, FILE *f, int i; int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); -#define printfpr(fp) \ - do { \ - if (is_fpu64) \ - fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n", \ - (fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd, \ - (fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \ - else { \ - fpr_t tmp; \ - tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ - tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ - fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n", \ - tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd, \ - tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]); \ - } \ +#define printfpr(fp) \ + do { \ + if (is_fpu64) \ + fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu: %13g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ + (double)(fp)->fd, \ + (double)(fp)->fs[FP_ENDIAN_IDX], \ + (double)(fp)->fs[!FP_ENDIAN_IDX]); \ + else { \ + fpr_t tmp; \ + tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ + tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ + fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu:%13g\n", \ + tmp.w[FP_ENDIAN_IDX], tmp.d, \ + (double)tmp.fd, \ + (double)tmp.fs[FP_ENDIAN_IDX], \ + (double)tmp.fs[!FP_ENDIAN_IDX]); \ + } \ } while(0) @@ -9631,7 +9639,9 @@ void cpu_dump_state (CPUState *env, FILE *f, { int i; - cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", + cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx + " LO=0x" TARGET_FMT_lx " ds %04x " + TARGET_FMT_lx " " TARGET_FMT_ld "\n", env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { diff --git a/target-sh4/translate.c b/target-sh4/translate.c index bff3188575..3537f8c2bd 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -77,6 +77,8 @@ static TCGv cpu_fregs[32]; /* internal register indexes */ static TCGv cpu_flags, cpu_delayed_pc; +static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + #include "gen-icount.h" static void sh4_translate_init(void) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1164feb882..2c07385d50 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -66,6 +66,9 @@ static TCGv_i64 cpu_tmp64; /* Floating point registers */ static TCGv_i32 cpu_fpr[TARGET_FPREGS]; +static target_ulong gen_opc_npc[OPC_BUF_SIZE]; +static target_ulong gen_opc_jump_pc[2]; + #include "gen-icount.h" typedef struct DisasContext { @@ -4929,12 +4932,12 @@ void gen_pc_load(CPUState *env, TranslationBlock *tb, if (npc == 1) { /* dynamic NPC: already stored */ } else if (npc == 2) { - target_ulong t2 = (target_ulong)(unsigned long)puc; - /* jump PC: use T2 and the jump targets of the translation */ - if (t2) + /* jump PC: use 'cond' and the jump targets of the translation */ + if (env->cond) { env->npc = gen_opc_jump_pc[0]; - else + } else { env->npc = gen_opc_jump_pc[1]; + } } else { env->npc = npc; } diff --git a/tcg/README b/tcg/README index 3433908460..68d27ffa6d 100644 --- a/tcg/README +++ b/tcg/README @@ -268,13 +268,13 @@ ext32u_i64 t0, t1 * bswap16_i32/i64 t0, t1 -16 bit byte swap on a 32/64 bit value. The two/six high order bytes must be -set to zero. +16 bit byte swap on a 32/64 bit value. It assumes that the two/six high order +bytes are set to zero. * bswap32_i32/i64 t0, t1 -32 bit byte swap on a 32/64 bit value. With a 64 bit value, the four high -order bytes must be set to zero. +32 bit byte swap on a 32/64 bit value. With a 64 bit value, it assumes that +the four high order bytes are set to zero. * bswap64_i64 t0, t1 diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index f9ae898fff..daddaab71d 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -24,41 +24,26 @@ #ifndef NDEBUG static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { - "%r0", - "%r1", - "%rp", - "%r3", - "%r4", - "%r5", - "%r6", - "%r7", - "%r8", - "%r9", - "%r10", - "%r11", - "%r12", - "%r13", - "%r14", - "%r15", - "%r16", - "%r17", - "%r18", - "%r19", - "%r20", - "%r21", - "%r22", - "%r23", - "%r24", - "%r25", - "%r26", - "%dp", - "%ret0", - "%ret1", - "%sp", - "%r31", + "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", + "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23", + "%r24", "%r25", "%r26", "%dp", "%ret0", "%ret1", "%sp", "%r31", }; #endif +/* This is an 8 byte temp slot in the stack frame. */ +#define STACK_TEMP_OFS -16 + +#ifndef GUEST_BASE +#define GUEST_BASE 0 +#endif + +#ifdef CONFIG_USE_GUEST_BASE +#define TCG_GUEST_BASE_REG TCG_REG_R16 +#else +#define TCG_GUEST_BASE_REG TCG_REG_R0 +#endif + static const int tcg_target_reg_alloc_order[] = { TCG_REG_R4, TCG_REG_R5, @@ -75,6 +60,14 @@ static const int tcg_target_reg_alloc_order[] = { TCG_REG_R14, TCG_REG_R15, TCG_REG_R16, + + TCG_REG_R26, + TCG_REG_R25, + TCG_REG_R24, + TCG_REG_R23, + + TCG_REG_RET0, + TCG_REG_RET1, }; static const int tcg_target_call_iarg_regs[4] = { @@ -89,16 +82,98 @@ static const int tcg_target_call_oarg_regs[2] = { TCG_REG_RET1, }; +/* True iff val fits a signed field of width BITS. */ +static inline int check_fit_tl(tcg_target_long val, unsigned int bits) +{ + return (val << ((sizeof(tcg_target_long) * 8 - bits)) + >> (sizeof(tcg_target_long) * 8 - bits)) == val; +} + +/* True iff depi can be used to compute (reg | MASK). + Accept a bit pattern like: + 0....01....1 + 1....10....0 + 0..01..10..0 + Copied from gcc sources. */ +static inline int or_mask_p(tcg_target_ulong mask) +{ + mask += mask & -mask; + return (mask & (mask - 1)) == 0; +} + +/* True iff depi or extru can be used to compute (reg & mask). + Accept a bit pattern like these: + 0....01....1 + 1....10....0 + 1..10..01..1 + Copied from gcc sources. */ +static inline int and_mask_p(tcg_target_ulong mask) +{ + return or_mask_p(~mask); +} + +static int low_sign_ext(int val, int len) +{ + return (((val << 1) & ~(-1u << len)) | ((val >> (len - 1)) & 1)); +} + +static int reassemble_12(int as12) +{ + return (((as12 & 0x800) >> 11) | + ((as12 & 0x400) >> 8) | + ((as12 & 0x3ff) << 3)); +} + +static int reassemble_17(int as17) +{ + return (((as17 & 0x10000) >> 16) | + ((as17 & 0x0f800) << 5) | + ((as17 & 0x00400) >> 8) | + ((as17 & 0x003ff) << 3)); +} + +static int reassemble_21(int as21) +{ + return (((as21 & 0x100000) >> 20) | + ((as21 & 0x0ffe00) >> 8) | + ((as21 & 0x000180) << 7) | + ((as21 & 0x00007c) << 14) | + ((as21 & 0x000003) << 12)); +} + +/* ??? Bizzarely, there is no PCREL12F relocation type. I guess all + such relocations are simply fully handled by the assembler. */ +#define R_PARISC_PCREL12F R_PARISC_NONE + static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend) { + uint32_t *insn_ptr = (uint32_t *)code_ptr; + uint32_t insn = *insn_ptr; + tcg_target_long pcrel; + + value += addend; + pcrel = (value - ((tcg_target_long)code_ptr + 8)) >> 2; + switch (type) { + case R_PARISC_PCREL12F: + assert(check_fit_tl(pcrel, 12)); + /* ??? We assume all patches are forward. See tcg_out_brcond + re setting the NUL bit on the branch and eliding the nop. */ + assert(pcrel >= 0); + insn &= ~0x1ffdu; + insn |= reassemble_12(pcrel); + break; case R_PARISC_PCREL17F: - hppa_patch17f((uint32_t *)code_ptr, value, addend); + assert(check_fit_tl(pcrel, 17)); + insn &= ~0x1f1ffdu; + insn |= reassemble_17(pcrel); break; default: tcg_abort(); } + + *insn_ptr = insn; } /* maximum number of register used for input function arguments */ @@ -126,6 +201,18 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23); break; + case 'Z': + ct->ct |= TCG_CT_CONST_0; + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S5; + break; + case 'K': + ct->ct |= TCG_CT_CONST_MS11; + break; default: return -1; } @@ -135,15 +222,21 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) } /* test if a constant matches the constraint */ -static inline int tcg_target_const_match(tcg_target_long val, - const TCGArgConstraint *arg_ct) +static int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) { - int ct; - - ct = arg_ct->ct; - - /* TODO */ - + int ct = arg_ct->ct; + if (ct & TCG_CT_CONST) { + return 1; + } else if (ct & TCG_CT_CONST_0) { + return val == 0; + } else if (ct & TCG_CT_CONST_S5) { + return check_fit_tl(val, 5); + } else if (ct & TCG_CT_CONST_S11) { + return check_fit_tl(val, 11); + } else if (ct & TCG_CT_CONST_MS11) { + return check_fit_tl(-val, 11); + } return 0; } @@ -163,191 +256,624 @@ static inline int tcg_target_const_match(tcg_target_long val, #define INSN_SHDEP_CP(x) ((31 - (x)) << 5) #define INSN_SHDEP_P(x) ((x) << 5) #define INSN_COND(x) ((x) << 13) +#define INSN_IM11(x) low_sign_ext(x, 11) +#define INSN_IM14(x) low_sign_ext(x, 14) +#define INSN_IM5(x) (low_sign_ext(x, 5) << 16) + +#define COND_NEVER 0 +#define COND_EQ 1 +#define COND_LT 2 +#define COND_LE 3 +#define COND_LTU 4 +#define COND_LEU 5 +#define COND_SV 6 +#define COND_OD 7 +#define COND_FALSE 8 + +#define INSN_ADD (INSN_OP(0x02) | INSN_EXT6(0x18)) +#define INSN_ADDC (INSN_OP(0x02) | INSN_EXT6(0x1c)) +#define INSN_ADDI (INSN_OP(0x2d)) +#define INSN_ADDIL (INSN_OP(0x0a)) +#define INSN_ADDL (INSN_OP(0x02) | INSN_EXT6(0x28)) +#define INSN_AND (INSN_OP(0x02) | INSN_EXT6(0x08)) +#define INSN_ANDCM (INSN_OP(0x02) | INSN_EXT6(0x00)) +#define INSN_COMCLR (INSN_OP(0x02) | INSN_EXT6(0x22)) +#define INSN_COMICLR (INSN_OP(0x24)) +#define INSN_DEP (INSN_OP(0x35) | INSN_EXT3SH(3)) +#define INSN_DEPI (INSN_OP(0x35) | INSN_EXT3SH(7)) +#define INSN_EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7)) +#define INSN_EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6)) +#define INSN_LDIL (INSN_OP(0x08)) +#define INSN_LDO (INSN_OP(0x0d)) +#define INSN_MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2)) +#define INSN_OR (INSN_OP(0x02) | INSN_EXT6(0x09)) +#define INSN_SHD (INSN_OP(0x34) | INSN_EXT3SH(2)) +#define INSN_SUB (INSN_OP(0x02) | INSN_EXT6(0x10)) +#define INSN_SUBB (INSN_OP(0x02) | INSN_EXT6(0x14)) +#define INSN_SUBI (INSN_OP(0x25)) +#define INSN_VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5)) +#define INSN_VEXTRU (INSN_OP(0x34) | INSN_EXT3SH(4)) +#define INSN_VSHD (INSN_OP(0x34) | INSN_EXT3SH(0)) +#define INSN_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a)) +#define INSN_ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2)) +#define INSN_ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0)) + +#define INSN_BL (INSN_OP(0x3a) | INSN_EXT3BR(0)) +#define INSN_BL_N (INSN_OP(0x3a) | INSN_EXT3BR(0) | 2) +#define INSN_BLR (INSN_OP(0x3a) | INSN_EXT3BR(2)) +#define INSN_BV (INSN_OP(0x3a) | INSN_EXT3BR(6)) +#define INSN_BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2) +#define INSN_BLE_SR4 (INSN_OP(0x39) | (1 << 13)) + +#define INSN_LDB (INSN_OP(0x10)) +#define INSN_LDH (INSN_OP(0x11)) +#define INSN_LDW (INSN_OP(0x12)) +#define INSN_LDWM (INSN_OP(0x13)) +#define INSN_FLDDS (INSN_OP(0x0b) | INSN_EXT4(0) | (1 << 12)) + +#define INSN_LDBX (INSN_OP(0x03) | INSN_EXT4(0)) +#define INSN_LDHX (INSN_OP(0x03) | INSN_EXT4(1)) +#define INSN_LDWX (INSN_OP(0x03) | INSN_EXT4(2)) + +#define INSN_STB (INSN_OP(0x18)) +#define INSN_STH (INSN_OP(0x19)) +#define INSN_STW (INSN_OP(0x1a)) +#define INSN_STWM (INSN_OP(0x1b)) +#define INSN_FSTDS (INSN_OP(0x0b) | INSN_EXT4(8) | (1 << 12)) + +#define INSN_COMBT (INSN_OP(0x20)) +#define INSN_COMBF (INSN_OP(0x22)) +#define INSN_COMIBT (INSN_OP(0x21)) +#define INSN_COMIBF (INSN_OP(0x23)) + +/* supplied by libgcc */ +extern void *__canonicalize_funcptr_for_compare(void *); + +static void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + /* PA1.1 defines COPY as OR r,0,t; PA2.0 defines COPY as LDO 0(r),t + but hppa-dis.c is unaware of this definition */ + if (ret != arg) { + tcg_out32(s, INSN_OR | INSN_T(ret) | INSN_R1(arg) + | INSN_R2(TCG_REG_R0)); + } +} + +static void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (check_fit_tl(arg, 14)) { + tcg_out32(s, INSN_LDO | INSN_R1(ret) + | INSN_R2(TCG_REG_R0) | INSN_IM14(arg)); + } else { + uint32_t hi, lo; + hi = arg >> 11; + lo = arg & 0x7ff; + + tcg_out32(s, INSN_LDIL | INSN_R2(ret) | reassemble_21(hi)); + if (lo) { + tcg_out32(s, INSN_LDO | INSN_R1(ret) + | INSN_R2(ret) | INSN_IM14(lo)); + } + } +} + +static void tcg_out_ldst(TCGContext *s, int ret, int addr, + tcg_target_long offset, int op) +{ + if (!check_fit_tl(offset, 14)) { + uint32_t hi, lo, op; + + hi = offset >> 11; + lo = offset & 0x7ff; + + if (addr == TCG_REG_R0) { + op = INSN_LDIL | INSN_R2(TCG_REG_R1); + } else { + op = INSN_ADDIL | INSN_R2(addr); + } + tcg_out32(s, op | reassemble_21(hi)); -#define COND_NEVER 0 -#define COND_EQUAL 1 -#define COND_LT 2 -#define COND_LTEQ 3 -#define COND_LTU 4 -#define COND_LTUEQ 5 -#define COND_SV 6 -#define COND_OD 7 + addr = TCG_REG_R1; + offset = lo; + } + + if (ret != addr || offset != 0 || op != INSN_LDO) { + tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | INSN_IM14(offset)); + } +} + +/* This function is required by tcg.c. */ +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, ret, arg1, arg2, INSN_LDW); +} +/* This function is required by tcg.c. */ +static inline void tcg_out_st(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, ret, arg1, arg2, INSN_STW); +} -/* Logical ADD */ -#define ARITH_ADD (INSN_OP(0x02) | INSN_EXT6(0x28)) -#define ARITH_AND (INSN_OP(0x02) | INSN_EXT6(0x08)) -#define ARITH_OR (INSN_OP(0x02) | INSN_EXT6(0x09)) -#define ARITH_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a)) -#define ARITH_SUB (INSN_OP(0x02) | INSN_EXT6(0x10)) +static void tcg_out_ldst_index(TCGContext *s, int data, + int base, int index, int op) +{ + tcg_out32(s, op | INSN_T(data) | INSN_R1(index) | INSN_R2(base)); +} -#define SHD (INSN_OP(0x34) | INSN_EXT3SH(2)) -#define VSHD (INSN_OP(0x34) | INSN_EXT3SH(0)) -#define DEP (INSN_OP(0x35) | INSN_EXT3SH(3)) -#define ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2)) -#define ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0)) -#define EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6)) -#define EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7)) -#define VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5)) +static inline void tcg_out_addi2(TCGContext *s, int ret, int arg1, + tcg_target_long val) +{ + tcg_out_ldst(s, ret, arg1, val, INSN_LDO); +} + +/* This function is required by tcg.c. */ +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_out_addi2(s, reg, reg, val); +} + +static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op) +{ + tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int t, int r1, + tcg_target_long val, int op) +{ + assert(check_fit_tl(val, 11)); + tcg_out32(s, op | INSN_R1(t) | INSN_R2(r1) | INSN_IM11(val)); +} -#define SUBI (INSN_OP(0x25)) -#define MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2)) +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out_arith(s, TCG_REG_R0, TCG_REG_R0, TCG_REG_R0, INSN_OR); +} -#define BL (INSN_OP(0x3a) | INSN_EXT3BR(0)) -#define BLE_SR4 (INSN_OP(0x39) | (1 << 13)) -#define BV (INSN_OP(0x3a) | INSN_EXT3BR(6)) -#define BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2) -#define LDIL (INSN_OP(0x08)) -#define LDO (INSN_OP(0x0d)) +static inline void tcg_out_mtctl_sar(TCGContext *s, int arg) +{ + tcg_out32(s, INSN_MTCTL | INSN_R2(11) | INSN_R1(arg)); +} -#define LDB (INSN_OP(0x10)) -#define LDH (INSN_OP(0x11)) -#define LDW (INSN_OP(0x12)) -#define LDWM (INSN_OP(0x13)) +/* Extract LEN bits at position OFS from ARG and place in RET. + Note that here the bit ordering is reversed from the PA-RISC + standard, such that the right-most bit is 0. */ +static inline void tcg_out_extr(TCGContext *s, int ret, int arg, + unsigned ofs, unsigned len, int sign) +{ + assert(ofs < 32 && len <= 32 - ofs); + tcg_out32(s, (sign ? INSN_EXTRS : INSN_EXTRU) + | INSN_R1(ret) | INSN_R2(arg) + | INSN_SHDEP_P(31 - ofs) | INSN_DEP_LEN(len)); +} -#define STB (INSN_OP(0x18)) -#define STH (INSN_OP(0x19)) -#define STW (INSN_OP(0x1a)) -#define STWM (INSN_OP(0x1b)) +/* Likewise with OFS interpreted little-endian. */ +static inline void tcg_out_dep(TCGContext *s, int ret, int arg, + unsigned ofs, unsigned len) +{ + assert(ofs < 32 && len <= 32 - ofs); + tcg_out32(s, INSN_DEP | INSN_R2(ret) | INSN_R1(arg) + | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len)); +} -#define COMBT (INSN_OP(0x20)) -#define COMBF (INSN_OP(0x22)) +static inline void tcg_out_shd(TCGContext *s, int ret, int hi, int lo, + unsigned count) +{ + assert(count < 32); + tcg_out32(s, INSN_SHD | INSN_R1(hi) | INSN_R2(lo) | INSN_T(ret) + | INSN_SHDEP_CP(count)); +} -static int lowsignext(uint32_t val, int start, int length) +static void tcg_out_vshd(TCGContext *s, int ret, int hi, int lo, int creg) { - return (((val << 1) & ~(~0 << length)) | - ((val >> (length - 1)) & 1)) << start; + tcg_out_mtctl_sar(s, creg); + tcg_out32(s, INSN_VSHD | INSN_T(ret) | INSN_R1(hi) | INSN_R2(lo)); } -static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m) { - /* PA1.1 defines COPY as OR r,0,t */ - tcg_out32(s, ARITH_OR | INSN_T(ret) | INSN_R1(arg) | INSN_R2(TCG_REG_R0)); + if (m == 0) { + tcg_out_mov(s, ret, arg); + } else if (m == -1) { + tcg_out_movi(s, TCG_TYPE_I32, ret, -1); + } else if (or_mask_p(m)) { + int bs0, bs1; + + for (bs0 = 0; bs0 < 32; bs0++) { + if ((m & (1u << bs0)) != 0) { + break; + } + } + for (bs1 = bs0; bs1 < 32; bs1++) { + if ((m & (1u << bs1)) == 0) { + break; + } + } + assert(bs1 == 32 || (1ul << bs1) > m); - /* PA2.0 defines COPY as LDO 0(r),t - * but hppa-dis.c is unaware of this definition */ - /* tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(arg) | reassemble_14(0)); */ + tcg_out_mov(s, ret, arg); + tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1) + | INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0)); + } else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R1, m); + tcg_out_arith(s, ret, arg, TCG_REG_R1, INSN_OR); + } } -static inline void tcg_out_movi(TCGContext *s, TCGType type, - int ret, tcg_target_long arg) +static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m) { - if (arg == (arg & 0x1fff)) { - tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(TCG_REG_R0) | - reassemble_14(arg)); + if (m == 0) { + tcg_out_mov(s, ret, TCG_REG_R0); + } else if (m == -1) { + tcg_out_mov(s, ret, arg); + } else if (and_mask_p(m)) { + int ls0, ls1, ms0; + + for (ls0 = 0; ls0 < 32; ls0++) { + if ((m & (1u << ls0)) == 0) { + break; + } + } + for (ls1 = ls0; ls1 < 32; ls1++) { + if ((m & (1u << ls1)) != 0) { + break; + } + } + for (ms0 = ls1; ms0 < 32; ms0++) { + if ((m & (1u << ms0)) == 0) { + break; + } + } + assert (ms0 == 32); + + if (ls1 == 32) { + tcg_out_extr(s, ret, arg, 0, ls0, 0); + } else { + tcg_out_mov(s, ret, arg); + tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0) + | INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0)); + } } else { - tcg_out32(s, LDIL | INSN_R2(ret) | - reassemble_21(lrsel((uint32_t)arg, 0))); - if (arg & 0x7ff) - tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(ret) | - reassemble_14(rrsel((uint32_t)arg, 0))); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R1, m); + tcg_out_arith(s, ret, arg, TCG_REG_R1, INSN_AND); } } -static inline void tcg_out_ld_raw(TCGContext *s, int ret, - tcg_target_long arg) +static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) { - tcg_out32(s, LDIL | INSN_R2(ret) | - reassemble_21(lrsel((uint32_t)arg, 0))); - tcg_out32(s, LDW | INSN_R1(ret) | INSN_R2(ret) | - reassemble_14(rrsel((uint32_t)arg, 0))); + tcg_out_extr(s, ret, arg, 0, 8, 1); } -static inline void tcg_out_ld_ptr(TCGContext *s, int ret, - tcg_target_long arg) +static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) { - tcg_out_ld_raw(s, ret, arg); + tcg_out_extr(s, ret, arg, 0, 16, 1); } -static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, - int op) +static void tcg_out_shli(TCGContext *s, int ret, int arg, int count) { - if (offset == (offset & 0xfff)) - tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | - reassemble_14(offset)); - else { - fprintf(stderr, "unimplemented %s with offset %d\n", __func__, offset); - tcg_abort(); + count &= 31; + tcg_out32(s, INSN_ZDEP | INSN_R2(ret) | INSN_R1(arg) + | INSN_SHDEP_CP(31 - count) | INSN_DEP_LEN(32 - count)); +} + +static void tcg_out_shl(TCGContext *s, int ret, int arg, int creg) +{ + tcg_out_arithi(s, TCG_REG_R20, creg, 31, INSN_SUBI); + tcg_out_mtctl_sar(s, TCG_REG_R20); + tcg_out32(s, INSN_ZVDEP | INSN_R2(ret) | INSN_R1(arg) | INSN_DEP_LEN(32)); +} + +static void tcg_out_shri(TCGContext *s, int ret, int arg, int count) +{ + count &= 31; + tcg_out_extr(s, ret, arg, count, 32 - count, 0); +} + +static void tcg_out_shr(TCGContext *s, int ret, int arg, int creg) +{ + tcg_out_vshd(s, ret, TCG_REG_R0, arg, creg); +} + +static void tcg_out_sari(TCGContext *s, int ret, int arg, int count) +{ + count &= 31; + tcg_out_extr(s, ret, arg, count, 32 - count, 1); +} + +static void tcg_out_sar(TCGContext *s, int ret, int arg, int creg) +{ + tcg_out_arithi(s, TCG_REG_R20, creg, 31, INSN_SUBI); + tcg_out_mtctl_sar(s, TCG_REG_R20); + tcg_out32(s, INSN_VEXTRS | INSN_R1(ret) | INSN_R2(arg) | INSN_DEP_LEN(32)); +} + +static void tcg_out_rotli(TCGContext *s, int ret, int arg, int count) +{ + count &= 31; + tcg_out_shd(s, ret, arg, arg, 32 - count); +} + +static void tcg_out_rotl(TCGContext *s, int ret, int arg, int creg) +{ + tcg_out_arithi(s, TCG_REG_R20, creg, 32, INSN_SUBI); + tcg_out_vshd(s, ret, arg, arg, TCG_REG_R20); +} + +static void tcg_out_rotri(TCGContext *s, int ret, int arg, int count) +{ + count &= 31; + tcg_out_shd(s, ret, arg, arg, count); +} + +static void tcg_out_rotr(TCGContext *s, int ret, int arg, int creg) +{ + tcg_out_vshd(s, ret, arg, arg, creg); +} + +static void tcg_out_bswap16(TCGContext *s, int ret, int arg, int sign) +{ + if (ret != arg) { + tcg_out_mov(s, ret, arg); /* arg = xxAB */ } + tcg_out_dep(s, ret, ret, 16, 8); /* ret = xBAB */ + tcg_out_extr(s, ret, ret, 8, 16, sign); /* ret = ..BA */ } -static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, - int arg1, tcg_target_long arg2) +static void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp) { - fprintf(stderr, "unimplemented %s\n", __func__); - tcg_abort(); + /* arg = ABCD */ + tcg_out_rotri(s, temp, arg, 16); /* temp = CDAB */ + tcg_out_dep(s, temp, temp, 16, 8); /* temp = CBAB */ + tcg_out_shd(s, ret, arg, temp, 8); /* ret = DCBA */ } -static inline void tcg_out_st(TCGContext *s, TCGType type, int ret, - int arg1, tcg_target_long arg2) +static void tcg_out_call(TCGContext *s, void *func) { - fprintf(stderr, "unimplemented %s\n", __func__); - tcg_abort(); + tcg_target_long val, hi, lo, disp; + + val = (uint32_t)__canonicalize_funcptr_for_compare(func); + disp = (val - ((tcg_target_long)s->code_ptr + 8)) >> 2; + + if (check_fit_tl(disp, 17)) { + tcg_out32(s, INSN_BL_N | INSN_R2(TCG_REG_RP) | reassemble_17(disp)); + } else { + hi = val >> 11; + lo = val & 0x7ff; + + tcg_out32(s, INSN_LDIL | INSN_R2(TCG_REG_R20) | reassemble_21(hi)); + tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R20) + | reassemble_17(lo >> 2)); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); + } } -static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op) +static void tcg_out_xmpyu(TCGContext *s, int retl, int reth, + int arg1, int arg2) { - tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2)); + /* Store both words into the stack for copy to the FPU. */ + tcg_out_ldst(s, arg1, TCG_REG_SP, STACK_TEMP_OFS, INSN_STW); + tcg_out_ldst(s, arg2, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_STW); + + /* Load both words into the FPU at the same time. We get away + with this because we can address the left and right half of the + FPU registers individually once loaded. */ + /* fldds stack_temp(sp),fr22 */ + tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_SP) + | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22)); + + /* xmpyu fr22r,fr22,fr22 */ + tcg_out32(s, 0x3ad64796); + + /* Store the 64-bit result back into the stack. */ + /* fstds stack_temp(sp),fr22 */ + tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_SP) + | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22)); + + /* Load the pieces of the result that the caller requested. */ + if (reth) { + tcg_out_ldst(s, reth, TCG_REG_SP, STACK_TEMP_OFS, INSN_LDW); + } + if (retl) { + tcg_out_ldst(s, retl, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_LDW); + } } -static inline void tcg_out_arithi(TCGContext *s, int t, int r1, - tcg_target_long val, int op) +static void tcg_out_add2(TCGContext *s, int destl, int desth, + int al, int ah, int bl, int bh, int blconst) { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, val); - tcg_out_arith(s, t, r1, TCG_REG_R20, op); + int tmp = (destl == ah || destl == bh ? TCG_REG_R20 : destl); + + if (blconst) { + tcg_out_arithi(s, tmp, al, bl, INSN_ADDI); + } else { + tcg_out_arith(s, tmp, al, bl, INSN_ADD); + } + tcg_out_arith(s, desth, ah, bh, INSN_ADDC); + + tcg_out_mov(s, destl, tmp); } -static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +static void tcg_out_sub2(TCGContext *s, int destl, int desth, int al, int ah, + int bl, int bh, int alconst, int blconst) { - tcg_out_arithi(s, reg, reg, val, ARITH_ADD); + int tmp = (destl == ah || destl == bh ? TCG_REG_R20 : destl); + + if (alconst) { + if (blconst) { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R20, bl); + bl = TCG_REG_R20; + } + tcg_out_arithi(s, tmp, bl, al, INSN_SUBI); + } else if (blconst) { + tcg_out_arithi(s, tmp, al, -bl, INSN_ADDI); + } else { + tcg_out_arith(s, tmp, al, bl, INSN_SUB); + } + tcg_out_arith(s, desth, ah, bh, INSN_SUBB); + + tcg_out_mov(s, destl, tmp); } -static inline void tcg_out_nop(TCGContext *s) +static void tcg_out_branch(TCGContext *s, int label_index, int nul) { - tcg_out32(s, ARITH_OR | INSN_T(TCG_REG_R0) | INSN_R1(TCG_REG_R0) | - INSN_R2(TCG_REG_R0)); + TCGLabel *l = &s->labels[label_index]; + uint32_t op = nul ? INSN_BL_N : INSN_BL; + + if (l->has_value) { + tcg_target_long val = l->u.value; + + val -= (tcg_target_long)s->code_ptr + 8; + val >>= 2; + assert(check_fit_tl(val, 17)); + + tcg_out32(s, op | reassemble_17(val)); + } else { + tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL17F, label_index, 0); + tcg_out32(s, op); + } } -static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) { - tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | - INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); +static const uint8_t tcg_cond_to_cmp_cond[10] = +{ + [TCG_COND_EQ] = COND_EQ, + [TCG_COND_NE] = COND_EQ | COND_FALSE, + [TCG_COND_LT] = COND_LT, + [TCG_COND_GE] = COND_LT | COND_FALSE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_LE | COND_FALSE, + [TCG_COND_LTU] = COND_LTU, + [TCG_COND_GEU] = COND_LTU | COND_FALSE, + [TCG_COND_LEU] = COND_LEU, + [TCG_COND_GTU] = COND_LEU | COND_FALSE, +}; + +static void tcg_out_brcond(TCGContext *s, int cond, TCGArg c1, + TCGArg c2, int c2const, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + int op, pacond; + + /* Note that COMIB operates as if the immediate is the first + operand. We model brcond with the immediate in the second + to better match what targets are likely to give us. For + consistency, model COMB with reversed operands as well. */ + pacond = tcg_cond_to_cmp_cond[tcg_swap_cond(cond)]; + + if (c2const) { + op = (pacond & COND_FALSE ? INSN_COMIBF : INSN_COMIBT); + op |= INSN_IM5(c2); + } else { + op = (pacond & COND_FALSE ? INSN_COMBF : INSN_COMBT); + op |= INSN_R1(c2); + } + op |= INSN_R2(c1); + op |= INSN_COND(pacond & 7); + + if (l->has_value) { + tcg_target_long val = l->u.value; + + val -= (tcg_target_long)s->code_ptr + 8; + val >>= 2; + assert(check_fit_tl(val, 12)); + + /* ??? Assume that all branches to defined labels are backward. + Which means that if the nul bit is set, the delay slot is + executed if the branch is taken, and not executed in fallthru. */ + tcg_out32(s, op | reassemble_12(val)); + tcg_out_nop(s); + } else { + tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL12F, label_index, 0); + /* ??? Assume that all branches to undefined labels are forward. + Which means that if the nul bit is set, the delay slot is + not executed if the branch is taken, which is what we want. */ + tcg_out32(s, op | 2); + } } -static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) { - tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | - INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); +static void tcg_out_comclr(TCGContext *s, int cond, TCGArg ret, + TCGArg c1, TCGArg c2, int c2const) +{ + int op, pacond; + + /* Note that COMICLR operates as if the immediate is the first + operand. We model setcond with the immediate in the second + to better match what targets are likely to give us. For + consistency, model COMCLR with reversed operands as well. */ + pacond = tcg_cond_to_cmp_cond[tcg_swap_cond(cond)]; + + if (c2const) { + op = INSN_COMICLR | INSN_R2(c1) | INSN_R1(ret) | INSN_IM11(c2); + } else { + op = INSN_COMCLR | INSN_R2(c1) | INSN_R1(c2) | INSN_T(ret); + } + op |= INSN_COND(pacond & 7); + op |= pacond & COND_FALSE ? 1 << 12 : 0; + + tcg_out32(s, op); } -static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) { - if(ret != arg) - tcg_out_mov(s, ret, arg); - tcg_out32(s, DEP | INSN_R2(ret) | INSN_R1(ret) | - INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); - tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(TCG_REG_R0) | - INSN_R2(ret) | INSN_SHDEP_CP(8)); +static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, + TCGArg bl, int blconst, TCGArg bh, int bhconst, + int label_index) +{ + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + tcg_out_comclr(s, tcg_invert_cond(cond), TCG_REG_R0, al, bl, blconst); + tcg_out_brcond(s, cond, ah, bh, bhconst, label_index); + break; + + default: + tcg_out_brcond(s, cond, ah, bh, bhconst, label_index); + tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, ah, bh, bhconst); + tcg_out_brcond(s, tcg_unsigned_cond(cond), + al, bl, blconst, label_index); + break; + } } -static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp) { - tcg_out32(s, SHD | INSN_T(temp) | INSN_R1(arg) | - INSN_R2(arg) | INSN_SHDEP_CP(16)); - tcg_out32(s, DEP | INSN_R2(temp) | INSN_R1(temp) | - INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); - tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(arg) | - INSN_R2(temp) | INSN_SHDEP_CP(8)); +static void tcg_out_setcond(TCGContext *s, int cond, TCGArg ret, + TCGArg c1, TCGArg c2, int c2const) +{ + tcg_out_comclr(s, tcg_invert_cond(cond), ret, c1, c2, c2const); + tcg_out_movi(s, TCG_TYPE_I32, ret, 1); } -static inline void tcg_out_call(TCGContext *s, void *func) +static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, + TCGArg al, TCGArg ah, TCGArg bl, int blconst, + TCGArg bh, int bhconst) { - uint32_t val = (uint32_t)__canonicalize_funcptr_for_compare(func); - tcg_out32(s, LDIL | INSN_R2(TCG_REG_R20) | - reassemble_21(lrsel(val, 0))); - tcg_out32(s, BLE_SR4 | INSN_R2(TCG_REG_R20) | - reassemble_17(rrsel(val, 0) >> 2)); - tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); + int scratch = TCG_REG_R20; + + if (ret != al && ret != ah + && (blconst || ret != bl) + && (bhconst || ret != bh)) { + scratch = ret; + } + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + tcg_out_setcond(s, cond, scratch, al, bl, blconst); + tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst); + tcg_out_movi(s, TCG_TYPE_I32, scratch, cond == TCG_COND_NE); + break; + + default: + tcg_out_setcond(s, tcg_unsigned_cond(cond), scratch, al, bl, blconst); + tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst); + tcg_out_movi(s, TCG_TYPE_I32, scratch, 0); + tcg_out_comclr(s, cond, TCG_REG_R0, ah, bh, bhconst); + tcg_out_movi(s, TCG_TYPE_I32, scratch, 1); + break; + } + + tcg_out_mov(s, ret, scratch); } #if defined(CONFIG_SOFTMMU) - #include "../../softmmu_defs.h" static void *qemu_ld_helpers[4] = { @@ -363,30 +889,77 @@ static void *qemu_st_helpers[4] = { __stl_mmu, __stq_mmu, }; + +/* Load and compare a TLB entry, and branch if TLB miss. OFFSET is set to + the offset of the first ADDR_READ or ADDR_WRITE member of the appropriate + TLB for the memory index. The return value is the offset from ENV + contained in R1 afterward (to be used when loading ADDEND); if the + return value is 0, R1 is not used. */ + +static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo, + int addrhi, int s_bits, int lab_miss, int offset) +{ + int ret; + + /* Extracting the index into the TLB. The "normal C operation" is + r1 = addr_reg >> TARGET_PAGE_BITS; + r1 &= CPU_TLB_SIZE - 1; + r1 <<= CPU_TLB_ENTRY_BITS; + What this does is extract CPU_TLB_BITS beginning at TARGET_PAGE_BITS + and place them at CPU_TLB_ENTRY_BITS. We can combine the first two + operations with an EXTRU. Unfortunately, the current value of + CPU_TLB_ENTRY_BITS is > 3, so we can't merge that shift with the + add that follows. */ + tcg_out_extr(s, r1, addrlo, TARGET_PAGE_BITS, CPU_TLB_BITS, 0); + tcg_out_andi(s, r0, addrlo, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + tcg_out_shli(s, r1, r1, CPU_TLB_ENTRY_BITS); + tcg_out_arith(s, r1, r1, TCG_AREG0, INSN_ADDL); + + /* Make sure that both the addr_{read,write} and addend can be + read with a 14-bit offset from the same base register. */ + if (check_fit_tl(offset + CPU_TLB_SIZE, 14)) { + ret = 0; + } else { + ret = (offset + 0x400) & ~0x7ff; + offset = ret - offset; + tcg_out_addi2(s, TCG_REG_R1, r1, ret); + r1 = TCG_REG_R1; + } + + /* Load the entry from the computed slot. */ + if (TARGET_LONG_BITS == 64) { + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R23, r1, offset); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset + 4); + } else { + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset); + } + + /* If not equal, jump to lab_miss. */ + if (TARGET_LONG_BITS == 64) { + tcg_out_brcond2(s, TCG_COND_NE, TCG_REG_R20, TCG_REG_R23, + r0, 0, addrhi, 0, lab_miss); + } else { + tcg_out_brcond(s, TCG_COND_NE, TCG_REG_R20, r0, 0, lab_miss); + } + + return ret; +} #endif static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) { - int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; -#if defined(CONFIG_SOFTMMU) - uint32_t *label1_ptr, *label2_ptr; -#endif -#if TARGET_LONG_BITS == 64 + int addr_reg, addr_reg2; + int data_reg, data_reg2; + int r0, r1, mem_index, s_bits, bswap; + tcg_target_long offset; #if defined(CONFIG_SOFTMMU) - uint32_t *label3_ptr; -#endif - int addr_reg2; + int lab1, lab2, argreg; #endif data_reg = *args++; - if (opc == 3) - data_reg2 = *args++; - else - data_reg2 = 0; /* suppress warning */ + data_reg2 = (opc == 3 ? *args++ : TCG_REG_R0); addr_reg = *args++; -#if TARGET_LONG_BITS == 64 - addr_reg2 = *args++; -#endif + addr_reg2 = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0); mem_index = *args; s_bits = opc & 3; @@ -394,96 +967,22 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) r1 = TCG_REG_R25; #if defined(CONFIG_SOFTMMU) - tcg_out_mov(s, r1, addr_reg); - - tcg_out_mov(s, r0, addr_reg); - - tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | - INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); - - tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), - ARITH_AND); - - tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, - ARITH_AND); - - tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); - tcg_out_arithi(s, r1, r1, - offsetof(CPUState, tlb_table[mem_index][0].addr_read), - ARITH_ADD); - - tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); - -#if TARGET_LONG_BITS == 32 - /* if equal, jump to label1 */ - label1_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | - INSN_COND(COND_EQUAL)); - tcg_out_mov(s, r0, addr_reg); /* delay slot */ -#else - /* if not equal, jump to label3 */ - label3_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | - INSN_COND(COND_EQUAL)); - tcg_out_mov(s, r0, addr_reg); /* delay slot */ - - tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); - - /* if equal, jump to label1 */ - label1_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | - INSN_COND(COND_EQUAL)); - tcg_out_nop(s); /* delay slot */ - - /* label3: */ - *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); -#endif - -#if TARGET_LONG_BITS == 32 - tcg_out_mov(s, TCG_REG_R26, addr_reg); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R25, mem_index); -#else - tcg_out_mov(s, TCG_REG_R26, addr_reg); - tcg_out_mov(s, TCG_REG_R25, addr_reg2); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); -#endif - - tcg_out_call(s, qemu_ld_helpers[s_bits]); - - switch(opc) { - case 0 | 4: - tcg_out_ext8s(s, data_reg, TCG_REG_RET0); - break; - case 1 | 4: - tcg_out_ext16s(s, data_reg, TCG_REG_RET0); - break; - case 0: - case 1: - case 2: - default: - tcg_out_mov(s, data_reg, TCG_REG_RET0); - break; - case 3: - tcg_abort(); - tcg_out_mov(s, data_reg, TCG_REG_RET0); - tcg_out_mov(s, data_reg2, TCG_REG_RET1); - break; - } + lab1 = gen_new_label(); + lab2 = gen_new_label(); - /* jump to label2 */ - label2_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + offset = tcg_out_tlb_read(s, r0, r1, addr_reg, addr_reg2, s_bits, lab1, + offsetof(CPUState, + tlb_table[mem_index][0].addr_read)); - /* label1: */ - *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + /* TLB Hit. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : r1), + offsetof(CPUState, tlb_table[mem_index][0].addend) - offset); - tcg_out_arithi(s, TCG_REG_R20, r1, - offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read), - ARITH_ADD); - tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); - tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); + tcg_out_arith(s, r0, addr_reg, TCG_REG_R20, INSN_ADDL); + offset = TCG_REG_R0; #else r0 = addr_reg; + offset = GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_R0; #endif #ifdef TARGET_WORDS_BIGENDIAN @@ -492,191 +991,152 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) bswap = 1; #endif switch (opc) { - case 0: - tcg_out_ldst(s, data_reg, r0, 0, LDB); - break; - case 0 | 4: - tcg_out_ldst(s, data_reg, r0, 0, LDB); - tcg_out_ext8s(s, data_reg, data_reg); - break; - case 1: - tcg_out_ldst(s, data_reg, r0, 0, LDH); - if (bswap) - tcg_out_bswap16(s, data_reg, data_reg); - break; - case 1 | 4: - tcg_out_ldst(s, data_reg, r0, 0, LDH); - if (bswap) - tcg_out_bswap16(s, data_reg, data_reg); + case 0: + tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDBX); + break; + case 0 | 4: + tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDBX); + tcg_out_ext8s(s, data_reg, data_reg); + break; + case 1: + tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDHX); + if (bswap) { + tcg_out_bswap16(s, data_reg, data_reg, 0); + } + break; + case 1 | 4: + tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDHX); + if (bswap) { + tcg_out_bswap16(s, data_reg, data_reg, 1); + } else { tcg_out_ext16s(s, data_reg, data_reg); - break; - case 2: - tcg_out_ldst(s, data_reg, r0, 0, LDW); - if (bswap) - tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); - break; - case 3: - tcg_abort(); - if (!bswap) { - tcg_out_ldst(s, data_reg, r0, 0, LDW); - tcg_out_ldst(s, data_reg2, r0, 4, LDW); + } + break; + case 2: + tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDWX); + if (bswap) { + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + } + break; + case 3: + if (bswap) { + int t = data_reg2; + data_reg2 = data_reg; + data_reg = t; + } + if (offset == TCG_REG_R0) { + /* Make sure not to clobber the base register. */ + if (data_reg2 == r0) { + tcg_out_ldst(s, data_reg, r0, 4, INSN_LDW); + tcg_out_ldst(s, data_reg2, r0, 0, INSN_LDW); } else { - tcg_out_ldst(s, data_reg, r0, 4, LDW); - tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); - tcg_out_ldst(s, data_reg2, r0, 0, LDW); - tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20); + tcg_out_ldst(s, data_reg2, r0, 0, INSN_LDW); + tcg_out_ldst(s, data_reg, r0, 4, INSN_LDW); } - break; - default: - tcg_abort(); + } else { + tcg_out_addi2(s, TCG_REG_R20, r0, 4); + tcg_out_ldst_index(s, data_reg2, r0, offset, INSN_LDWX); + tcg_out_ldst_index(s, data_reg, TCG_REG_R20, offset, INSN_LDWX); + } + if (bswap) { + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20); + } + break; + default: + tcg_abort(); } #if defined(CONFIG_SOFTMMU) + tcg_out_branch(s, lab2, 1); + + /* TLB Miss. */ + /* label1: */ + tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr); + + argreg = TCG_REG_R26; + tcg_out_mov(s, argreg--, addr_reg); + if (TARGET_LONG_BITS == 64) { + tcg_out_mov(s, argreg--, addr_reg2); + } + tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); + + tcg_out_call(s, qemu_ld_helpers[s_bits]); + + switch (opc) { + case 0: + tcg_out_andi(s, data_reg, TCG_REG_RET0, 0xff); + break; + case 0 | 4: + tcg_out_ext8s(s, data_reg, TCG_REG_RET0); + break; + case 1: + tcg_out_andi(s, data_reg, TCG_REG_RET0, 0xffff); + break; + case 1 | 4: + tcg_out_ext16s(s, data_reg, TCG_REG_RET0); + break; + case 2: + case 2 | 4: + tcg_out_mov(s, data_reg, TCG_REG_RET0); + break; + case 3: + tcg_out_mov(s, data_reg, TCG_REG_RET0); + tcg_out_mov(s, data_reg2, TCG_REG_RET1); + break; + default: + tcg_abort(); + } + /* label2: */ - *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); + tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr); #endif } static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) { - int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; -#if defined(CONFIG_SOFTMMU) - uint32_t *label1_ptr, *label2_ptr; -#endif -#if TARGET_LONG_BITS == 64 + int addr_reg, addr_reg2; + int data_reg, data_reg2; + int r0, r1, mem_index, s_bits, bswap; #if defined(CONFIG_SOFTMMU) - uint32_t *label3_ptr; -#endif - int addr_reg2; + tcg_target_long offset; + int lab1, lab2, argreg; #endif data_reg = *args++; - if (opc == 3) - data_reg2 = *args++; - else - data_reg2 = 0; /* suppress warning */ + data_reg2 = (opc == 3 ? *args++ : 0); addr_reg = *args++; -#if TARGET_LONG_BITS == 64 - addr_reg2 = *args++; -#endif + addr_reg2 = (TARGET_LONG_BITS == 64 ? *args++ : 0); mem_index = *args; - s_bits = opc; r0 = TCG_REG_R26; r1 = TCG_REG_R25; #if defined(CONFIG_SOFTMMU) - tcg_out_mov(s, r1, addr_reg); - - tcg_out_mov(s, r0, addr_reg); - - tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | - INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); - - tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), - ARITH_AND); - - tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, - ARITH_AND); + lab1 = gen_new_label(); + lab2 = gen_new_label(); - tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); - tcg_out_arithi(s, r1, r1, - offsetof(CPUState, tlb_table[mem_index][0].addr_write), - ARITH_ADD); + offset = tcg_out_tlb_read(s, r0, r1, addr_reg, addr_reg2, s_bits, lab1, + offsetof(CPUState, + tlb_table[mem_index][0].addr_write)); - tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + /* TLB Hit. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : r1), + offsetof(CPUState, tlb_table[mem_index][0].addend) - offset); -#if TARGET_LONG_BITS == 32 - /* if equal, jump to label1 */ - label1_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | - INSN_COND(COND_EQUAL)); - tcg_out_mov(s, r0, addr_reg); /* delay slot */ + tcg_out_arith(s, r0, addr_reg, TCG_REG_R20, INSN_ADDL); #else - /* if not equal, jump to label3 */ - label3_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | - INSN_COND(COND_EQUAL)); - tcg_out_mov(s, r0, addr_reg); /* delay slot */ - - tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); - - /* if equal, jump to label1 */ - label1_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | - INSN_COND(COND_EQUAL)); - tcg_out_nop(s); /* delay slot */ - - /* label3: */ - *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); -#endif - - tcg_out_mov(s, TCG_REG_R26, addr_reg); -#if TARGET_LONG_BITS == 64 - tcg_out_mov(s, TCG_REG_R25, addr_reg2); - if (opc == 3) { - tcg_abort(); - tcg_out_mov(s, TCG_REG_R24, data_reg); - tcg_out_mov(s, TCG_REG_R23, data_reg2); - /* TODO: push mem_index */ - tcg_abort(); + /* There are no indexed stores, so if GUEST_BASE is set + we must do the add explicitly. Careful to avoid R20, + which is used for the bswaps to follow. */ + if (GUEST_BASE == 0) { + r0 = addr_reg; } else { - switch(opc) { - case 0: - tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | - INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); - break; - case 1: - tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | - INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); - break; - case 2: - tcg_out_mov(s, TCG_REG_R24, data_reg); - break; - } - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); - } -#else - if (opc == 3) { - tcg_abort(); - tcg_out_mov(s, TCG_REG_R25, data_reg); - tcg_out_mov(s, TCG_REG_R24, data_reg2); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); - } else { - switch(opc) { - case 0: - tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | - INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); - break; - case 1: - tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | - INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); - break; - case 2: - tcg_out_mov(s, TCG_REG_R25, data_reg); - break; - } - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); + tcg_out_arith(s, TCG_REG_R31, addr_reg, TCG_GUEST_BASE_REG, INSN_ADDL); + r0 = TCG_REG_R31; } #endif - tcg_out_call(s, qemu_st_helpers[s_bits]); - - /* jump to label2 */ - label2_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); - - /* label1: */ - *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); - - tcg_out_arithi(s, TCG_REG_R20, r1, - offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write), - ARITH_ADD); - tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); - tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); -#else - r0 = addr_reg; -#endif #ifdef TARGET_WORDS_BIGENDIAN bswap = 0; @@ -685,170 +1145,338 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) #endif switch (opc) { case 0: - tcg_out_ldst(s, data_reg, r0, 0, STB); + tcg_out_ldst(s, data_reg, r0, 0, INSN_STB); break; case 1: if (bswap) { - tcg_out_bswap16(s, TCG_REG_R20, data_reg); + tcg_out_bswap16(s, TCG_REG_R20, data_reg, 0); data_reg = TCG_REG_R20; } - tcg_out_ldst(s, data_reg, r0, 0, STH); + tcg_out_ldst(s, data_reg, r0, 0, INSN_STH); break; case 2: if (bswap) { tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); data_reg = TCG_REG_R20; } - tcg_out_ldst(s, data_reg, r0, 0, STW); + tcg_out_ldst(s, data_reg, r0, 0, INSN_STW); break; case 3: - tcg_abort(); - if (!bswap) { - tcg_out_ldst(s, data_reg, r0, 0, STW); - tcg_out_ldst(s, data_reg2, r0, 4, STW); - } else { + if (bswap) { tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); - tcg_out_ldst(s, TCG_REG_R20, r0, 4, STW); - tcg_out_bswap32(s, TCG_REG_R20, data_reg2, TCG_REG_R20); - tcg_out_ldst(s, TCG_REG_R20, r0, 0, STW); + tcg_out_bswap32(s, TCG_REG_R23, data_reg2, TCG_REG_R23); + data_reg2 = TCG_REG_R20; + data_reg = TCG_REG_R23; } + tcg_out_ldst(s, data_reg2, r0, 0, INSN_STW); + tcg_out_ldst(s, data_reg, r0, 4, INSN_STW); break; default: tcg_abort(); } #if defined(CONFIG_SOFTMMU) + tcg_out_branch(s, lab2, 1); + + /* TLB Miss. */ + /* label1: */ + tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr); + + argreg = TCG_REG_R26; + tcg_out_mov(s, argreg--, addr_reg); + if (TARGET_LONG_BITS == 64) { + tcg_out_mov(s, argreg--, addr_reg2); + } + + switch(opc) { + case 0: + tcg_out_andi(s, argreg--, data_reg, 0xff); + tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); + break; + case 1: + tcg_out_andi(s, argreg--, data_reg, 0xffff); + tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); + break; + case 2: + tcg_out_mov(s, argreg--, data_reg); + tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); + break; + case 3: + /* Because of the alignment required by the 64-bit data argument, + we will always use R23/R24. Also, we will always run out of + argument registers for storing mem_index, so that will have + to go on the stack. */ + if (mem_index == 0) { + argreg = TCG_REG_R0; + } else { + argreg = TCG_REG_R20; + tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); + } + tcg_out_mov(s, TCG_REG_R23, data_reg2); + tcg_out_mov(s, TCG_REG_R24, data_reg); + tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_SP, + TCG_TARGET_CALL_STACK_OFFSET - 4); + break; + default: + tcg_abort(); + } + + tcg_out_call(s, qemu_st_helpers[s_bits]); + /* label2: */ - *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); + tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr); #endif } +static void tcg_out_exit_tb(TCGContext *s, TCGArg arg) +{ + if (!check_fit_tl(arg, 14)) { + uint32_t hi, lo; + hi = arg & ~0x7ff; + lo = arg & 0x7ff; + if (lo) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, hi); + tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_R18)); + tcg_out_addi(s, TCG_REG_RET0, lo); + return; + } + arg = hi; + } + tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_R18)); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, arg); +} + +static void tcg_out_goto_tb(TCGContext *s, TCGArg arg) +{ + if (s->tb_jmp_offset) { + /* direct jump method */ + fprintf(stderr, "goto_tb direct\n"); + tcg_abort(); + } else { + /* indirect jump method */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, TCG_REG_R0, + (tcg_target_long)(s->tb_next + arg)); + tcg_out32(s, INSN_BV_N | INSN_R2(TCG_REG_R20)); + } + s->tb_next_offset[arg] = s->code_ptr - s->code_buf; +} + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) { - int c; - switch (opc) { case INDEX_op_exit_tb: - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, args[0]); - tcg_out32(s, BV_N | INSN_R2(TCG_REG_R18)); + tcg_out_exit_tb(s, args[0]); break; case INDEX_op_goto_tb: - if (s->tb_jmp_offset) { - /* direct jump method */ - fprintf(stderr, "goto_tb direct\n"); - tcg_abort(); - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, args[0]); - tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; - } else { - /* indirect jump method */ - tcg_out_ld_ptr(s, TCG_REG_R20, - (tcg_target_long)(s->tb_next + args[0])); - tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); - } - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out_goto_tb(s, args[0]); break; + case INDEX_op_call: - tcg_out32(s, BLE_SR4 | INSN_R2(args[0])); - tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); + if (const_args[0]) { + tcg_out_call(s, (void *)args[0]); + } else { + /* ??? FIXME: the value in the register in args[0] is almost + certainly a procedure descriptor, not a code address. We + probably need to use the millicode $$dyncall routine. */ + tcg_abort(); + } break; + case INDEX_op_jmp: fprintf(stderr, "unimplemented jmp\n"); tcg_abort(); break; + case INDEX_op_br: - fprintf(stderr, "unimplemented br\n"); - tcg_abort(); + tcg_out_branch(s, args[0], 1); break; + case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); break; case INDEX_op_ld8u_i32: - tcg_out_ldst(s, args[0], args[1], args[2], LDB); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDB); break; case INDEX_op_ld8s_i32: - tcg_out_ldst(s, args[0], args[1], args[2], LDB); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDB); tcg_out_ext8s(s, args[0], args[0]); break; case INDEX_op_ld16u_i32: - tcg_out_ldst(s, args[0], args[1], args[2], LDH); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDH); break; case INDEX_op_ld16s_i32: - tcg_out_ldst(s, args[0], args[1], args[2], LDH); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDH); tcg_out_ext16s(s, args[0], args[0]); break; case INDEX_op_ld_i32: - tcg_out_ldst(s, args[0], args[1], args[2], LDW); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDW); break; case INDEX_op_st8_i32: - tcg_out_ldst(s, args[0], args[1], args[2], STB); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_STB); break; case INDEX_op_st16_i32: - tcg_out_ldst(s, args[0], args[1], args[2], STH); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_STH); break; case INDEX_op_st_i32: - tcg_out_ldst(s, args[0], args[1], args[2], STW); + tcg_out_ldst(s, args[0], args[1], args[2], INSN_STW); + break; + + case INDEX_op_add_i32: + if (const_args[2]) { + tcg_out_addi2(s, args[0], args[1], args[2]); + } else { + tcg_out_arith(s, args[0], args[1], args[2], INSN_ADDL); + } break; case INDEX_op_sub_i32: - c = ARITH_SUB; - goto gen_arith; + if (const_args[1]) { + if (const_args[2]) { + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1] - args[2]); + } else { + /* Recall that SUBI is a reversed subtract. */ + tcg_out_arithi(s, args[0], args[2], args[1], INSN_SUBI); + } + } else if (const_args[2]) { + tcg_out_addi2(s, args[0], args[1], -args[2]); + } else { + tcg_out_arith(s, args[0], args[1], args[2], INSN_SUB); + } + break; + case INDEX_op_and_i32: - c = ARITH_AND; - goto gen_arith; + if (const_args[2]) { + tcg_out_andi(s, args[0], args[1], args[2]); + } else { + tcg_out_arith(s, args[0], args[1], args[2], INSN_AND); + } + break; + case INDEX_op_or_i32: - c = ARITH_OR; - goto gen_arith; + if (const_args[2]) { + tcg_out_ori(s, args[0], args[1], args[2]); + } else { + tcg_out_arith(s, args[0], args[1], args[2], INSN_OR); + } + break; + case INDEX_op_xor_i32: - c = ARITH_XOR; - goto gen_arith; - case INDEX_op_add_i32: - c = ARITH_ADD; - goto gen_arith; + tcg_out_arith(s, args[0], args[1], args[2], INSN_XOR); + break; + + case INDEX_op_andc_i32: + if (const_args[2]) { + tcg_out_andi(s, args[0], args[1], ~args[2]); + } else { + tcg_out_arith(s, args[0], args[1], args[2], INSN_ANDCM); + } + break; case INDEX_op_shl_i32: - tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | - lowsignext(0x1f, 0, 11)); - tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); - tcg_out32(s, ZVDEP | INSN_R2(args[0]) | INSN_R1(args[1]) | - INSN_DEP_LEN(32)); + if (const_args[2]) { + tcg_out_shli(s, args[0], args[1], args[2]); + } else { + tcg_out_shl(s, args[0], args[1], args[2]); + } break; + case INDEX_op_shr_i32: - tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(args[2])); - tcg_out32(s, VSHD | INSN_T(args[0]) | INSN_R1(TCG_REG_R0) | - INSN_R2(args[1])); + if (const_args[2]) { + tcg_out_shri(s, args[0], args[1], args[2]); + } else { + tcg_out_shr(s, args[0], args[1], args[2]); + } break; + case INDEX_op_sar_i32: - tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | - lowsignext(0x1f, 0, 11)); - tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); - tcg_out32(s, VEXTRS | INSN_R1(args[0]) | INSN_R2(args[1]) | - INSN_DEP_LEN(32)); + if (const_args[2]) { + tcg_out_sari(s, args[0], args[1], args[2]); + } else { + tcg_out_sar(s, args[0], args[1], args[2]); + } + break; + + case INDEX_op_rotl_i32: + if (const_args[2]) { + tcg_out_rotli(s, args[0], args[1], args[2]); + } else { + tcg_out_rotl(s, args[0], args[1], args[2]); + } + break; + + case INDEX_op_rotr_i32: + if (const_args[2]) { + tcg_out_rotri(s, args[0], args[1], args[2]); + } else { + tcg_out_rotr(s, args[0], args[1], args[2]); + } break; case INDEX_op_mul_i32: - fprintf(stderr, "unimplemented mul\n"); - tcg_abort(); + tcg_out_xmpyu(s, args[0], TCG_REG_R0, args[1], args[2]); break; case INDEX_op_mulu2_i32: - fprintf(stderr, "unimplemented mulu2\n"); - tcg_abort(); + tcg_out_xmpyu(s, args[0], args[1], args[2], args[3]); break; - case INDEX_op_div2_i32: - fprintf(stderr, "unimplemented div2\n"); - tcg_abort(); + + case INDEX_op_bswap16_i32: + tcg_out_bswap16(s, args[0], args[1], 0); break; - case INDEX_op_divu2_i32: - fprintf(stderr, "unimplemented divu2\n"); - tcg_abort(); + case INDEX_op_bswap32_i32: + tcg_out_bswap32(s, args[0], args[1], TCG_REG_R20); + break; + + case INDEX_op_not_i32: + tcg_out_arithi(s, args[0], args[1], -1, INSN_SUBI); + break; + case INDEX_op_ext8s_i32: + tcg_out_ext8s(s, args[0], args[1]); + break; + case INDEX_op_ext16s_i32: + tcg_out_ext16s(s, args[0], args[1]); + break; + + /* These three correspond exactly to the fallback implementation. + But by including them we reduce the number of TCG ops that + need to be generated, and these opcodes are fairly common. */ + case INDEX_op_neg_i32: + tcg_out_arith(s, args[0], TCG_REG_R0, args[1], INSN_SUB); + break; + case INDEX_op_ext8u_i32: + tcg_out_andi(s, args[0], args[1], 0xff); + break; + case INDEX_op_ext16u_i32: + tcg_out_andi(s, args[0], args[1], 0xffff); break; case INDEX_op_brcond_i32: - fprintf(stderr, "unimplemented brcond\n"); - tcg_abort(); + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args[4], args[0], args[1], + args[2], const_args[2], + args[3], const_args[3], args[5]); + break; + + case INDEX_op_setcond_i32: + tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]); + break; + case INDEX_op_setcond2_i32: + tcg_out_setcond2(s, args[5], args[0], args[1], args[2], + args[3], const_args[3], args[4], const_args[4]); + break; + + case INDEX_op_add2_i32: + tcg_out_add2(s, args[0], args[1], args[2], args[3], + args[4], args[5], const_args[4]); + break; + + case INDEX_op_sub2_i32: + tcg_out_sub2(s, args[0], args[1], args[2], args[3], + args[4], args[5], const_args[2], const_args[4]); break; case INDEX_op_qemu_ld8u: @@ -866,6 +1494,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_qemu_ld32: tcg_out_qemu_ld(s, args, 2); break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; case INDEX_op_qemu_st8: tcg_out_qemu_st(s, args, 0); @@ -876,47 +1507,70 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_qemu_st32: tcg_out_qemu_st(s, args, 2); break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; default: fprintf(stderr, "unknown opcode 0x%x\n", opc); tcg_abort(); } - return; - -gen_arith: - tcg_out_arith(s, args[0], args[1], args[2], c); } static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "r" } }, + { INDEX_op_call, { "ri" } }, { INDEX_op_jmp, { "r" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, { INDEX_op_ld16s_i32, { "r", "r" } }, { INDEX_op_ld_i32, { "r", "r" } }, - { INDEX_op_st8_i32, { "r", "r" } }, - { INDEX_op_st16_i32, { "r", "r" } }, - { INDEX_op_st_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "rZ", "r" } }, + { INDEX_op_st16_i32, { "rZ", "r" } }, + { INDEX_op_st_i32, { "rZ", "r" } }, + + { INDEX_op_add_i32, { "r", "rZ", "ri" } }, + { INDEX_op_sub_i32, { "r", "rI", "ri" } }, + { INDEX_op_and_i32, { "r", "rZ", "ri" } }, + { INDEX_op_or_i32, { "r", "rZ", "ri" } }, + { INDEX_op_xor_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_andc_i32, { "r", "rZ", "ri" } }, - { INDEX_op_add_i32, { "r", "r", "r" } }, - { INDEX_op_sub_i32, { "r", "r", "r" } }, - { INDEX_op_and_i32, { "r", "r", "r" } }, - { INDEX_op_or_i32, { "r", "r", "r" } }, - { INDEX_op_xor_i32, { "r", "r", "r" } }, + { INDEX_op_mul_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, - { INDEX_op_shl_i32, { "r", "r", "r" } }, - { INDEX_op_shr_i32, { "r", "r", "r" } }, - { INDEX_op_sar_i32, { "r", "r", "r" } }, + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + { INDEX_op_rotl_i32, { "r", "r", "ri" } }, + { INDEX_op_rotr_i32, { "r", "r", "ri" } }, - { INDEX_op_brcond_i32, { "r", "r" } }, + { INDEX_op_bswap16_i32, { "r", "r" } }, + { INDEX_op_bswap32_i32, { "r", "r" } }, + { INDEX_op_neg_i32, { "r", "r" } }, + { INDEX_op_not_i32, { "r", "r" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext8u_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext16u_i32, { "r", "r" } }, + + { INDEX_op_brcond_i32, { "rZ", "rJ" } }, + { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } }, + + { INDEX_op_setcond_i32, { "r", "rZ", "rI" } }, + { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rI", "rI" } }, + + { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rI", "rZ" } }, + { INDEX_op_sub2_i32, { "r", "r", "rI", "rZ", "rK", "rZ" } }, #if TARGET_LONG_BITS == 32 { INDEX_op_qemu_ld8u, { "r", "L" } }, @@ -926,10 +1580,10 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_qemu_ld32, { "r", "L" } }, { INDEX_op_qemu_ld64, { "r", "r", "L" } }, - { INDEX_op_qemu_st8, { "L", "L" } }, - { INDEX_op_qemu_st16, { "L", "L" } }, - { INDEX_op_qemu_st32, { "L", "L" } }, - { INDEX_op_qemu_st64, { "L", "L", "L" } }, + { INDEX_op_qemu_st8, { "LZ", "L" } }, + { INDEX_op_qemu_st16, { "LZ", "L" } }, + { INDEX_op_qemu_st32, { "LZ", "L" } }, + { INDEX_op_qemu_st64, { "LZ", "LZ", "L" } }, #else { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, @@ -938,25 +1592,98 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_qemu_ld32, { "r", "L", "L" } }, { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, - { INDEX_op_qemu_st8, { "L", "L", "L" } }, - { INDEX_op_qemu_st16, { "L", "L", "L" } }, - { INDEX_op_qemu_st32, { "L", "L", "L" } }, - { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, + { INDEX_op_qemu_st8, { "LZ", "L", "L" } }, + { INDEX_op_qemu_st16, { "LZ", "L", "L" } }, + { INDEX_op_qemu_st32, { "LZ", "L", "L" } }, + { INDEX_op_qemu_st64, { "LZ", "LZ", "L", "L" } }, #endif { -1 }, }; +static int tcg_target_callee_save_regs[] = { + /* R2, the return address register, is saved specially + in the caller's frame. */ + /* R3, the frame pointer, is not currently modified. */ + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + /* R17 is the global env, so no need to save. */ + TCG_REG_R18 +}; + +void tcg_target_qemu_prologue(TCGContext *s) +{ + int frame_size, i; + + /* Allocate space for the fixed frame marker. */ + frame_size = -TCG_TARGET_CALL_STACK_OFFSET; + frame_size += TCG_TARGET_STATIC_CALL_ARGS_SIZE; + + /* Allocate space for the saved registers. */ + frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4; + + /* Align the allocated space. */ + frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1) + & -TCG_TARGET_STACK_ALIGN); + + /* The return address is stored in the caller's frame. */ + tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -20); + + /* Allocate stack frame, saving the first register at the same time. */ + tcg_out_ldst(s, tcg_target_callee_save_regs[0], + TCG_REG_SP, frame_size, INSN_STWM); + + /* Save all callee saved registers. */ + for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_st(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i], + TCG_REG_SP, -frame_size + i * 4); + } + + if (GUEST_BASE != 0) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE); + } + + /* Jump to TB, and adjust R18 to be the return address. */ + tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R26)); + tcg_out_mov(s, TCG_REG_R18, TCG_REG_R31); + + /* Restore callee saved registers. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -frame_size - 20); + for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i], + TCG_REG_SP, -frame_size + i * 4); + } + + /* Deallocate stack frame and return. */ + tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_RP)); + tcg_out_ldst(s, tcg_target_callee_save_regs[0], + TCG_REG_SP, -frame_size, INSN_LDWM); +} + void tcg_target_init(TCGContext *s) { tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); - tcg_regset_set32(tcg_target_call_clobber_regs, 0, - (1 << TCG_REG_R20) | - (1 << TCG_REG_R21) | - (1 << TCG_REG_R22) | - (1 << TCG_REG_R23) | - (1 << TCG_REG_R24) | - (1 << TCG_REG_R25) | - (1 << TCG_REG_R26)); + + tcg_regset_clear(tcg_target_call_clobber_regs); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R20); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R21); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R22); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R23); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R24); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R25); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R26); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RET0); + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RET1); tcg_regset_clear(s->reserved_regs); tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* hardwired to zero */ @@ -969,6 +1696,9 @@ void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */ + if (GUEST_BASE != 0) { + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); + } tcg_add_target_add_op_defs(hppa_op_defs); } diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index e956e71e8e..b76e389c38 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -69,17 +69,34 @@ enum { TCG_REG_R31, }; +#define TCG_CT_CONST_0 0x0100 +#define TCG_CT_CONST_S5 0x0200 +#define TCG_CT_CONST_S11 0x0400 +#define TCG_CT_CONST_MS11 0x0800 + /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_SP -#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_STACK_ALIGN 64 +#define TCG_TARGET_CALL_STACK_OFFSET -48 +#define TCG_TARGET_STATIC_CALL_ARGS_SIZE 8*4 +#define TCG_TARGET_CALL_ALIGN_ARGS 1 #define TCG_TARGET_STACK_GROWSUP /* optional instructions */ -#define TCG_TARGET_HAS_div2_i32 -//#define TCG_TARGET_HAS_ext8s_i32 -//#define TCG_TARGET_HAS_ext16s_i32 -//#define TCG_TARGET_HAS_bswap16_i32 -//#define TCG_TARGET_HAS_bswap32_i32 +// #define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8u_i32 +#define TCG_TARGET_HAS_ext16u_i32 +#define TCG_TARGET_HAS_bswap16_i32 +#define TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_not_i32 +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_andc_i32 +// #define TCG_TARGET_HAS_orc_i32 + +#define TCG_TARGET_HAS_GUEST_BASE /* Note: must be synced with dyngen-exec.h */ #define TCG_AREG0 TCG_REG_R17 @@ -87,116 +104,12 @@ enum { static inline void flush_icache_range(unsigned long start, unsigned long stop) { start &= ~31; - while (start <= stop) - { - asm volatile ("fdc 0(%0)\n" - "sync\n" - "fic 0(%%sr4, %0)\n" - "sync\n" + while (start <= stop) { + asm volatile ("fdc 0(%0)\n\t" + "sync\n\t" + "fic 0(%%sr4, %0)\n\t" + "sync" : : "r"(start) : "memory"); start += 32; } } - -/* supplied by libgcc */ -extern void *__canonicalize_funcptr_for_compare(void *); - -/* Field selection types defined by hppa */ -#define rnd(x) (((x)+0x1000)&~0x1fff) -/* lsel: select left 21 bits */ -#define lsel(v,a) (((v)+(a))>>11) -/* rsel: select right 11 bits */ -#define rsel(v,a) (((v)+(a))&0x7ff) -/* lrsel with rounding of addend to nearest 8k */ -#define lrsel(v,a) (((v)+rnd(a))>>11) -/* rrsel with rounding of addend to nearest 8k */ -#define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a))) - -#define mask(x,sz) ((x) & ~((1<<(sz))-1)) - -static inline int reassemble_12(int as12) -{ - return (((as12 & 0x800) >> 11) | - ((as12 & 0x400) >> 8) | - ((as12 & 0x3ff) << 3)); -} - -static inline int reassemble_14(int as14) -{ - return (((as14 & 0x1fff) << 1) | - ((as14 & 0x2000) >> 13)); -} - -static inline int reassemble_17(int as17) -{ - return (((as17 & 0x10000) >> 16) | - ((as17 & 0x0f800) << 5) | - ((as17 & 0x00400) >> 8) | - ((as17 & 0x003ff) << 3)); -} - -static inline int reassemble_21(int as21) -{ - return (((as21 & 0x100000) >> 20) | - ((as21 & 0x0ffe00) >> 8) | - ((as21 & 0x000180) << 7) | - ((as21 & 0x00007c) << 14) | - ((as21 & 0x000003) << 12)); -} - -static inline void hppa_patch21l(uint32_t *insn, int val, int addend) -{ - val = lrsel(val, addend); - *insn = mask(*insn, 21) | reassemble_21(val); -} - -static inline void hppa_patch14r(uint32_t *insn, int val, int addend) -{ - val = rrsel(val, addend); - *insn = mask(*insn, 14) | reassemble_14(val); -} - -static inline void hppa_patch17r(uint32_t *insn, int val, int addend) -{ - val = rrsel(val, addend); - *insn = (*insn & ~0x1f1ffd) | reassemble_17(val); -} - - -static inline void hppa_patch21l_dprel(uint32_t *insn, int val, int addend) -{ - register unsigned int dp asm("r27"); - hppa_patch21l(insn, val - dp, addend); -} - -static inline void hppa_patch14r_dprel(uint32_t *insn, int val, int addend) -{ - register unsigned int dp asm("r27"); - hppa_patch14r(insn, val - dp, addend); -} - -static inline void hppa_patch17f(uint32_t *insn, int val, int addend) -{ - int dot = (int)insn & ~0x3; - int v = ((val + addend) - dot - 8) / 4; - if (v > (1 << 16) || v < -(1 << 16)) { - printf("cannot fit branch to offset %d [%08x->%08x]\n", v, dot, val); - abort(); - } - *insn = (*insn & ~0x1f1ffd) | reassemble_17(v); -} - -static inline void hppa_load_imm21l(uint32_t *insn, int val, int addend) -{ - /* Transform addil L'sym(%dp) to ldil L'val, %r1 */ - *insn = 0x20200000 | reassemble_21(lrsel(val, 0)); -} - -static inline void hppa_load_imm14r(uint32_t *insn, int val, int addend) -{ - /* Transform ldw R'sym(%r1), %rN to ldo R'sym(%r1), %rN */ - hppa_patch14r(insn, val, addend); - /* HACK */ - if (addend == 0) - *insn = (*insn & ~0xfc000000) | (0x0d << 26); -} diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 113f245dcb..6e69ef4b49 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1449,13 +1449,8 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2, TCG_REG_R2, TCG_AREG0)); tcg_out_bundle(s, mII, -#if TARGET_LONG_BITS == 32 - tcg_opc_m3 (TCG_REG_P0, OPC_LD4_M3, TCG_REG_R57, - TCG_REG_R2, offset_addend - offset_rw), -#else tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R57, TCG_REG_R2, offset_addend - offset_rw), -#endif tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, TCG_REG_R3, TCG_REG_R3, TCG_REG_R56), tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6, diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index f4fb615bf0..f38eb2888d 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1450,7 +1450,9 @@ static const TCGTargetOpDef mips_op_defs[] = { }; static int tcg_target_callee_save_regs[] = { +#if 0 /* used for the global env (TCG_AREG0), so no need to save */ TCG_REG_S0, +#endif TCG_REG_S1, TCG_REG_S2, TCG_REG_S3, @@ -1459,8 +1461,7 @@ static int tcg_target_callee_save_regs[] = { TCG_REG_S6, TCG_REG_S7, TCG_REG_GP, - /* TCG_REG_FP, */ /* currently used for the global env, so np - need to save */ + TCG_REG_FP, TCG_REG_RA, /* should be last for ABI compliance */ }; diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 0292d3360d..0028bfa562 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -97,7 +97,7 @@ enum { #undef TCG_TARGET_HAS_ext16u_i32 /* andi rt, rs, 0xffff */ /* Note: must be synced with dyngen-exec.h */ -#define TCG_AREG0 TCG_REG_FP +#define TCG_AREG0 TCG_REG_S0 /* guest base is supported */ #define TCG_TARGET_HAS_GUEST_BASE diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 2725c6e165..0b6c61fbd1 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -50,7 +50,7 @@ static uint8_t *tb_ret_addr; static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { "r0", "r1", - "rp", + "r2", "r3", "r4", "r5", diff --git a/translate-all.c b/translate-all.c index 6f8136b62c..91cbbc4929 100644 --- a/translate-all.c +++ b/translate-all.c @@ -40,14 +40,6 @@ TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; target_ulong gen_opc_pc[OPC_BUF_SIZE]; uint16_t gen_opc_icount[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; -#if defined(TARGET_I386) -uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; -#elif defined(TARGET_SPARC) -target_ulong gen_opc_npc[OPC_BUF_SIZE]; -target_ulong gen_opc_jump_pc[2]; -#elif defined(TARGET_MIPS) || defined(TARGET_SH4) -uint32_t gen_opc_hflags[OPC_BUF_SIZE]; -#endif /* XXX: suppress that */ unsigned long code_gen_max_block_size(void) @@ -104,10 +96,6 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) #ifdef USE_DIRECT_JUMP s->tb_jmp_offset = tb->tb_jmp_offset; s->tb_next = NULL; - /* the following two entries are optional (only used for string ops) */ - /* XXX: not used ? */ - tb->tb_jmp_offset[2] = 0xffff; - tb->tb_jmp_offset[3] = 0xffff; #else s->tb_jmp_offset = NULL; s->tb_next = tb->tb_next; diff --git a/vl.c b/vl.c index 6768cf1251..4fb55b89e8 100644 --- a/vl.c +++ b/vl.c @@ -146,7 +146,6 @@ int main(int argc, char **argv) #include "audio/audio.h" #include "migration.h" #include "kvm.h" -#include "balloon.h" #include "qemu-option.h" #include "qemu-config.h" #include "qemu-objects.h" @@ -245,12 +244,6 @@ int kvm_allowed = 0; uint32_t xen_domid; enum xen_mode xen_mode = XEN_EMULATE; -#ifdef SIGRTMIN -#define SIG_IPI (SIGRTMIN+4) -#else -#define SIG_IPI SIGUSR1 -#endif - static int default_serial = 1; static int default_parallel = 1; static int default_virtcon = 1; @@ -292,10 +285,6 @@ static int default_driver_check(QemuOpts *opts, void *opaque) } /***********************************************************/ -/* x86 ISA bus support */ - -target_phys_addr_t isa_mem_base = 0; -PicState2 *isa_pic; static void set_proc_name(const char *s) { @@ -311,39 +300,6 @@ static void set_proc_name(const char *s) #endif } -/***************/ -/* ballooning */ - -static QEMUBalloonEvent *qemu_balloon_event; -void *qemu_balloon_event_opaque; - -void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque) -{ - qemu_balloon_event = func; - qemu_balloon_event_opaque = opaque; -} - -int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque) -{ - if (qemu_balloon_event) { - qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque); - return 1; - } else { - return 0; - } -} - -int qemu_balloon_status(MonitorCompletion cb, void *opaque) -{ - if (qemu_balloon_event) { - qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque); - return 1; - } else { - return 0; - } -} - - /***********************************************************/ /* real time host monotonic timer */ @@ -494,28 +450,6 @@ static void configure_rtc(QemuOpts *opts) } } -#ifdef _WIN32 -static void socket_cleanup(void) -{ - WSACleanup(); -} - -static int socket_init(void) -{ - WSADATA Data; - int ret, err; - - ret = WSAStartup(MAKEWORD(2,2), &Data); - if (ret != 0) { - err = WSAGetLastError(); - fprintf(stderr, "WSAStartup: %d\n", err); - return -1; - } - atexit(socket_cleanup); - return 0; -} -#endif - /***********************************************************/ /* Bluetooth support */ static int nb_hcis; @@ -1185,19 +1119,16 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, bdrv_flags &= ~BDRV_O_NATIVE_AIO; } - if (ro == 1) { + if (media == MEDIA_CDROM) { + /* CDROM is fine for any interface, don't check. */ + ro = 1; + } else if (ro == 1) { if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY) { fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n"); return NULL; } } - /* - * cdrom is read-only. Set it now, after above interface checking - * since readonly attribute not explicitly required, so no error. - */ - if (media == MEDIA_CDROM) { - ro = 1; - } + bdrv_flags |= ro ? 0 : BDRV_O_RDWR; if (bdrv_open2(dinfo->bdrv, file, bdrv_flags, drv) < 0) { @@ -1246,7 +1177,7 @@ int qemu_boot_set(const char *boot_devices) return boot_set_handler(boot_set_opaque, boot_devices); } -static int parse_bootdevices(char *devices) +static void validate_bootdevices(char *devices) { /* We just do some generic consistency checks */ const char *p; @@ -1272,7 +1203,6 @@ static int parse_bootdevices(char *devices) } bitmap |= 1 << (*p - 'a'); } - return bitmap; } static void restore_boot_devices(void *opaque) @@ -1781,7 +1711,7 @@ static int reset_requested; static int shutdown_requested; static int powerdown_requested; int debug_requested; -static int vmstop_requested; +int vmstop_requested; int qemu_shutdown_requested(void) { @@ -2019,10 +1949,7 @@ static void main_loop(void) { int r; -#ifdef CONFIG_IOTHREAD - qemu_system_ready = 1; - qemu_cond_broadcast(&qemu_system_cond); -#endif + qemu_main_loop_start(); for (;;) { do { @@ -2619,9 +2546,8 @@ static const QEMUOption *lookup_opt(int argc, char **argv, int main(int argc, char **argv, char **envp) { const char *gdbstub_dev = NULL; - uint32_t boot_devices_bitmap = 0; int i; - int snapshot, linux_boot, net_boot; + int snapshot, linux_boot; const char *icount_option = NULL; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; @@ -2938,13 +2864,13 @@ int main(int argc, char **argv, char **envp) if (legacy || get_param_value(buf, sizeof(buf), "order", optarg)) { - boot_devices_bitmap = parse_bootdevices(buf); + validate_bootdevices(buf); pstrcpy(boot_devices, sizeof(boot_devices), buf); } if (!legacy) { if (get_param_value(buf, sizeof(buf), "once", optarg)) { - boot_devices_bitmap |= parse_bootdevices(buf); + validate_bootdevices(buf); standard_boot_devices = qemu_strdup(boot_devices); pstrcpy(boot_devices, sizeof(boot_devices), buf); qemu_register_reset(restore_boot_devices, @@ -3622,17 +3548,12 @@ int main(int argc, char **argv, char **envp) } configure_icount(icount_option); -#ifdef _WIN32 socket_init(); -#endif if (net_init_clients() < 0) { exit(1); } - net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF; - net_set_boot_mask(net_boot); - /* init the bluetooth world */ if (foreach_device_config(DEV_BT, bt_parse)) exit(1); diff --git a/vnc.c b/vnc.c index e678fccac0..9ba603c690 100644 --- a/vnc.c +++ b/vnc.c @@ -541,7 +541,7 @@ static void vnc_dpy_resize(DisplayState *ds) vnc_colordepth(vs); if (size_changed) { if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { - vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), @@ -844,7 +844,7 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { /* send bitblit op to the vnc client */ - vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT); @@ -964,7 +964,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) * send them to the client. */ n_rectangles = 0; - vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); saved_offset = vs->output.offset; vnc_write_u16(vs, 0); @@ -1013,16 +1013,16 @@ static void audio_capture_notify(void *opaque, audcnotification_e cmd) switch (cmd) { case AUD_CNOTIFY_DISABLE: - vnc_write_u8(vs, 255); - vnc_write_u8(vs, 1); - vnc_write_u16(vs, 0); + vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); + vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); + vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END); vnc_flush(vs); break; case AUD_CNOTIFY_ENABLE: - vnc_write_u8(vs, 255); - vnc_write_u8(vs, 1); - vnc_write_u16(vs, 1); + vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); + vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); + vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN); vnc_flush(vs); break; } @@ -1036,9 +1036,9 @@ static void audio_capture(void *opaque, void *buf, int size) { VncState *vs = opaque; - vnc_write_u8(vs, 255); - vnc_write_u8(vs, 1); - vnc_write_u16(vs, 2); + vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); + vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); + vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); vnc_write_u32(vs, size); vnc_write(vs, buf, size); vnc_flush(vs); @@ -1434,7 +1434,7 @@ static void check_pointer_type_change(Notifier *notifier) int absolute = kbd_mouse_is_absolute(); if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) { - vnc_write_u8(vs, 0); + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); vnc_framebuffer_update(vs, absolute, 0, @@ -1747,7 +1747,7 @@ static void framebuffer_update_request(VncState *vs, int incremental, static void send_ext_key_event_ack(VncState *vs) { - vnc_write_u8(vs, 0); + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), @@ -1757,7 +1757,7 @@ static void send_ext_key_event_ack(VncState *vs) static void send_ext_audio_ack(VncState *vs) { - vnc_write_u8(vs, 0); + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), @@ -1930,7 +1930,7 @@ static void vnc_colordepth(VncState *vs) { if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) { /* Sending a WMVi message to notify the client*/ - vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), @@ -1955,7 +1955,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) } switch (data[0]) { - case 0: + case VNC_MSG_CLIENT_SET_PIXEL_FORMAT: if (len == 1) return 20; @@ -1965,7 +1965,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) read_u16(data, 12), read_u8(data, 14), read_u8(data, 15), read_u8(data, 16)); break; - case 2: + case VNC_MSG_CLIENT_SET_ENCODINGS: if (len == 1) return 4; @@ -1983,7 +1983,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) set_encodings(vs, (int32_t *)(data + 4), limit); break; - case 3: + case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST: if (len == 1) return 10; @@ -1991,19 +1991,19 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) read_u8(data, 1), read_u16(data, 2), read_u16(data, 4), read_u16(data, 6), read_u16(data, 8)); break; - case 4: + case VNC_MSG_CLIENT_KEY_EVENT: if (len == 1) return 8; key_event(vs, read_u8(data, 1), read_u32(data, 4)); break; - case 5: + case VNC_MSG_CLIENT_POINTER_EVENT: if (len == 1) return 6; pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); break; - case 6: + case VNC_MSG_CLIENT_CUT_TEXT: if (len == 1) return 8; @@ -2015,30 +2015,30 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) client_cut_text(vs, read_u32(data, 4), data + 8); break; - case 255: + case VNC_MSG_CLIENT_QEMU: if (len == 1) return 2; switch (read_u8(data, 1)) { - case 0: + case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT: if (len == 2) return 12; ext_key_event(vs, read_u16(data, 2), read_u32(data, 4), read_u32(data, 8)); break; - case 1: + case VNC_MSG_CLIENT_QEMU_AUDIO: if (len == 2) return 4; switch (read_u16 (data, 2)) { - case 0: + case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE: audio_add(vs); break; - case 1: + case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE: audio_del(vs); break; - case 2: + case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT: if (len == 4) return 10; switch (read_u8(data, 4)) { diff --git a/vnc.h b/vnc.h index 0a7487bdb2..b593608066 100644 --- a/vnc.h +++ b/vnc.h @@ -276,6 +276,57 @@ enum { #define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT) +/* Client -> Server message IDs */ +#define VNC_MSG_CLIENT_SET_PIXEL_FORMAT 0 +#define VNC_MSG_CLIENT_SET_ENCODINGS 2 +#define VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST 3 +#define VNC_MSG_CLIENT_KEY_EVENT 4 +#define VNC_MSG_CLIENT_POINTER_EVENT 5 +#define VNC_MSG_CLIENT_CUT_TEXT 6 +#define VNC_MSG_CLIENT_VMWARE_0 127 +#define VNC_MSG_CLIENT_CALL_CONTROL 249 +#define VNC_MSG_CLIENT_XVP 250 +#define VNC_MSG_CLIENT_SET_DESKTOP_SIZE 251 +#define VNC_MSG_CLIENT_TIGHT 252 +#define VNC_MSG_CLIENT_GII 253 +#define VNC_MSG_CLIENT_VMWARE_1 254 +#define VNC_MSG_CLIENT_QEMU 255 + +/* Server -> Client message IDs */ +#define VNC_MSG_SERVER_FRAMEBUFFER_UPDATE 0 +#define VNC_MSG_SERVER_SET_COLOUR_MAP_ENTRIES 1 +#define VNC_MSG_SERVER_BELL 2 +#define VNC_MSG_SERVER_CUT_TEXT 3 +#define VNC_MSG_SERVER_VMWARE_0 127 +#define VNC_MSG_SERVER_CALL_CONTROL 249 +#define VNC_MSG_SERVER_XVP 250 +#define VNC_MSG_SERVER_TIGHT 252 +#define VNC_MSG_SERVER_GII 253 +#define VNC_MSG_SERVER_VMWARE_1 254 +#define VNC_MSG_SERVER_QEMU 255 + + + +/* QEMU client -> server message IDs */ +#define VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT 0 +#define VNC_MSG_CLIENT_QEMU_AUDIO 1 + +/* QEMU server -> client message IDs */ +#define VNC_MSG_SERVER_QEMU_AUDIO 1 + + + +/* QEMU client -> server audio message IDs */ +#define VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE 0 +#define VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE 1 +#define VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT 2 + +/* QEMU server -> client audio message IDs */ +#define VNC_MSG_SERVER_QEMU_AUDIO_END 0 +#define VNC_MSG_SERVER_QEMU_AUDIO_BEGIN 1 +#define VNC_MSG_SERVER_QEMU_AUDIO_DATA 2 + + /***************************************************************************** * * Internal APIs |