diff options
199 files changed, 10424 insertions, 1155 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 30ed56dd77..2d219d2ea0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -560,9 +560,10 @@ F: monitor.c Network device layer M: Anthony Liguori <aliguori@us.ibm.com> -M: Mark McLoughlin <markmc@redhat.com> +M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> S: Maintained F: net/ +T: git git://github.com/stefanha/qemu.git net Network Block Device (NBD) M: Paolo Bonzini <pbonzini@redhat.com> @@ -173,7 +173,7 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") qemu-ga$(EXESUF): LIBS = $(LIBS_QGA) -qemu-ga$(EXESUF): QEMU_CFLAGS += -I qapi-generated +qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated gen-out-type = $(subst .,-,$(suffix $@)) @@ -181,15 +181,15 @@ ifneq ($(wildcard config-host.mak),) include $(SRC_PATH)/tests/Makefile endif -qapi-generated/qga-qapi-types.c qapi-generated/qga-qapi-types.h :\ +qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, " GEN $@") -qapi-generated/qga-qapi-visit.c qapi-generated/qga-qapi-visit.h :\ + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") +qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, " GEN $@") -qapi-generated/qga-qmp-commands.h qapi-generated/qga-qmp-marshal.c :\ + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") +qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") qapi-types.c qapi-types.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py @@ -201,12 +201,10 @@ qmp-commands.h qmp-marshal.c :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") -QGALIB_OBJ=$(addprefix qapi-generated/, qga-qapi-types.o qga-qapi-visit.o qga-qmp-marshal.o) -QGALIB_GEN=$(addprefix qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) -$(QGALIB_OBJ): $(QGALIB_GEN) +QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ) +qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) QEMULIBS=libhw32 libhw64 libuser libdis libdis-user @@ -227,6 +225,7 @@ clean: rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp) rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp) rm -rf qapi-generated + rm -rf qga/qapi-generated $(MAKE) -C tests/tcg clean for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ @@ -403,5 +402,5 @@ qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \ Makefile: $(GENERATED_HEADERS) # Include automatically generated dependency files -# All subdir dependencies come automatically from our recursive subdir rules --include $(wildcard *.d) +# Dependencies in Makefile.objs files come from our recursive subdir rules +-include $(wildcard *.d tests/*.d) diff --git a/Makefile.dis b/Makefile.dis index 09060f0a1a..2cfec6a358 100644 --- a/Makefile.dis +++ b/Makefile.dis @@ -18,6 +18,3 @@ all: $(libdis-y) clean: rm -f *.o *.d *.a *~ - -# Include automatically generated dependency files --include $(wildcard *.d) diff --git a/Makefile.hw b/Makefile.hw index 28fe100fbe..59f5b48350 100644 --- a/Makefile.hw +++ b/Makefile.hw @@ -21,6 +21,3 @@ all: $(hw-obj-y) clean: rm -f $(addsuffix *.o, $(sort $(dir $(hw-obj-y)))) rm -f $(addsuffix *.d, $(sort $(dir $(hw-obj-y)))) - -# Include automatically generated dependency files --include $(patsubst %.o, %.d, $(hw-obj-y)) diff --git a/Makefile.target b/Makefile.target index 74f7a4a170..7892a8df63 100644 --- a/Makefile.target +++ b/Makefile.target @@ -214,6 +214,3 @@ endif GENERATED_HEADERS += config-target.h Makefile: $(GENERATED_HEADERS) - -# Include automatically generated dependency files --include $(wildcard *.d fpu/*.d tcg/*.d) diff --git a/Makefile.user b/Makefile.user index 1783b2a257..9302d33245 100644 --- a/Makefile.user +++ b/Makefile.user @@ -22,6 +22,3 @@ clean: for d in . trace; do \ rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \ done - -# Include automatically generated dependency files --include $(wildcard *.d) diff --git a/arch_init.c b/arch_init.c index 78cdf50c52..26f30ef987 100644 --- a/arch_init.c +++ b/arch_init.c @@ -79,6 +79,8 @@ int graphic_depth = 15; #define QEMU_ARCH QEMU_ARCH_MICROBLAZE #elif defined(TARGET_MIPS) #define QEMU_ARCH QEMU_ARCH_MIPS +#elif defined(TARGET_OPENRISC) +#define QEMU_ARCH QEMU_ARCH_OPENRISC #elif defined(TARGET_PPC) #define QEMU_ARCH QEMU_ARCH_PPC #elif defined(TARGET_S390X) diff --git a/arch_init.h b/arch_init.h index c7cb94a932..3dfea3b4f3 100644 --- a/arch_init.h +++ b/arch_init.h @@ -16,6 +16,7 @@ enum { QEMU_ARCH_SH4 = 1024, QEMU_ARCH_SPARC = 2048, QEMU_ARCH_XTENSA = 4096, + QEMU_ARCH_OPENRISC = 8192, }; extern const uint32_t arch_type; @@ -2609,7 +2609,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) return; } - return drv->bdrv_debug_event(bs, event); + drv->bdrv_debug_event(bs, event); } @@ -924,6 +924,7 @@ mips-softmmu \ mipsel-softmmu \ mips64-softmmu \ mips64el-softmmu \ +or32-softmmu \ ppc-softmmu \ ppcemb-softmmu \ ppc64-softmmu \ @@ -950,6 +951,7 @@ microblaze-linux-user \ microblazeel-linux-user \ mips-linux-user \ mipsel-linux-user \ +or32-linux-user \ ppc-linux-user \ ppc64-linux-user \ ppc64abi32-linux-user \ @@ -3520,7 +3522,7 @@ target_arch2=`echo $target | cut -d '-' -f 1` target_bigendian="no" case "$target_arch2" in - armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -3636,6 +3638,11 @@ case "$target_arch2" in target_phys_bits=64 target_long_alignment=8 ;; + or32) + TARGET_ARCH=openrisc + TARGET_BASE_ARCH=openrisc + target_phys_bits=32 + ;; ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_phys_bits=64 @@ -3714,7 +3721,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" case "$target_arch2" in - alpha | sparc* | xtensa* | ppc*) + alpha | or32 | sparc* | xtensa* | ppc*) echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak ;; esac @@ -3888,6 +3895,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do echo "CONFIG_MIPS_DIS=y" >> $config_target_mak echo "CONFIG_MIPS_DIS=y" >> $libdis_config_mak ;; + or32) + echo "CONFIG_OPENRISC_DIS=y" >> $config_target_mak + echo "CONFIG_OPENRISC_DIS=y" >> $libdis_config_mak + ;; ppc*) echo "CONFIG_PPC_DIS=y" >> $config_target_mak echo "CONFIG_PPC_DIS=y" >> $libdis_config_mak diff --git a/cpu-exec.c b/cpu-exec.c index fc185a4f04..543460c34c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -225,6 +225,7 @@ int cpu_exec(CPUArchState *env) #elif defined(TARGET_LM32) #elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) +#elif defined(TARGET_OPENRISC) #elif defined(TARGET_SH4) #elif defined(TARGET_CRIS) #elif defined(TARGET_S390X) @@ -387,6 +388,23 @@ int cpu_exec(CPUArchState *env) do_interrupt(env); next_tb = 0; } +#elif defined(TARGET_OPENRISC) + { + int idx = -1; + if ((interrupt_request & CPU_INTERRUPT_HARD) + && (env->sr & SR_IEE)) { + idx = EXCP_INT; + } + if ((interrupt_request & CPU_INTERRUPT_TIMER) + && (env->sr & SR_TEE)) { + idx = EXCP_TICK; + } + if (idx >= 0) { + env->exception_index = idx; + do_interrupt(env); + next_tb = 0; + } + } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && @@ -640,6 +658,7 @@ int cpu_exec(CPUArchState *env) | env->cc_dest | (env->cc_x << 4); #elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) +#elif defined(TARGET_OPENRISC) #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) #elif defined(TARGET_CRIS) @@ -61,6 +61,32 @@ static CPUArchState *next_cpu; +static bool cpu_thread_is_idle(CPUArchState *env) +{ + if (env->stop || env->queued_work_first) { + return false; + } + if (env->stopped || !runstate_is_running()) { + return true; + } + if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) { + return false; + } + return true; +} + +static bool all_cpu_threads_idle(void) +{ + CPUArchState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (!cpu_thread_is_idle(env)) { + return false; + } + } + return true; +} + /***********************************************************/ /* guest cycle counter */ @@ -433,32 +459,6 @@ static int cpu_can_run(CPUArchState *env) return 1; } -static bool cpu_thread_is_idle(CPUArchState *env) -{ - if (env->stop || env->queued_work_first) { - return false; - } - if (env->stopped || !runstate_is_running()) { - return true; - } - if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) { - return false; - } - return true; -} - -bool all_cpu_threads_idle(void) -{ - CPUArchState *env; - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (!cpu_thread_is_idle(env)) { - return false; - } - } - return true; -} - static void cpu_handle_guest_debug(CPUArchState *env) { gdb_set_stop_cpu(env); diff --git a/default-configs/or32-linux-user.mak b/default-configs/or32-linux-user.mak new file mode 100644 index 0000000000..808c1f9b83 --- /dev/null +++ b/default-configs/or32-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for or32-linux-user diff --git a/default-configs/or32-softmmu.mak b/default-configs/or32-softmmu.mak new file mode 100644 index 0000000000..cce474672a --- /dev/null +++ b/default-configs/or32-softmmu.mak @@ -0,0 +1,4 @@ +# Default configuration for or32-softmmu + +CONFIG_SERIAL=y +CONFIG_OPENCORES_ETH=y diff --git a/device_tree.c b/device_tree.c index b366fddeaf..d7a9b6bb89 100644 --- a/device_tree.c +++ b/device_tree.c @@ -178,6 +178,36 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, return r; } +const void *qemu_devtree_getprop(void *fdt, const char *node_path, + const char *property, int *lenp) +{ + int len; + const void *r; + if (!lenp) { + lenp = &len; + } + r = fdt_getprop(fdt, findnode_nofail(fdt, node_path), property, lenp); + if (!r) { + fprintf(stderr, "%s: Couldn't get %s/%s: %s\n", __func__, + node_path, property, fdt_strerror(*lenp)); + exit(1); + } + return r; +} + +uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path, + const char *property) +{ + int len; + const uint32_t *p = qemu_devtree_getprop(fdt, node_path, property, &len); + if (len != 4) { + fprintf(stderr, "%s: %s/%s not 4 bytes long (not a cell?)\n", + __func__, node_path, property); + exit(1); + } + return be32_to_cpu(*p); +} + uint32_t qemu_devtree_get_phandle(void *fdt, const char *path) { uint32_t r; diff --git a/device_tree.h b/device_tree.h index 2244270b2d..f7a3e6cfc5 100644 --- a/device_tree.h +++ b/device_tree.h @@ -28,6 +28,10 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, const char *property, const char *target_node_path); +const void *qemu_devtree_getprop(void *fdt, const char *node_path, + const char *property, int *lenp); +uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path, + const char *property); uint32_t qemu_devtree_get_phandle(void *fdt, const char *path); uint32_t qemu_devtree_alloc_phandle(void *fdt); int qemu_devtree_nop_node(void *fdt, const char *node_path); @@ -196,9 +196,9 @@ static inline void dma_memory_unmap(DMAContext *dma, DMADirection dir, dma_addr_t access_len) { if (!dma_has_iommu(dma)) { - return cpu_physical_memory_unmap(buffer, (target_phys_addr_t)len, - dir == DMA_DIRECTION_FROM_DEVICE, - access_len); + cpu_physical_memory_unmap(buffer, (target_phys_addr_t)len, + dir == DMA_DIRECTION_FROM_DEVICE, + access_len); } else { iommu_dma_memory_unmap(dma, buffer, len, dir, access_len); } diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index ad11767a2f..cccb11e562 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -220,6 +220,8 @@ Example: #endif mdroth@illuin:~/w/qemu2.git$ +(The actual structure of the visit_type_* functions is a bit more complex +in order to propagate errors correctly and avoid leaking memory). === scripts/qapi-commands.py === diff --git a/docs/usb-storage.txt b/docs/usb-storage.txt index ff9755920d..e58e849d4d 100644 --- a/docs/usb-storage.txt +++ b/docs/usb-storage.txt @@ -2,7 +2,7 @@ qemu usb storage emulation -------------------------- -Qemu has two emulations for usb storage devices. +QEMU has two emulations for usb storage devices. Number one emulates the classic bulk-only transport protocol which is used by 99% of the usb sticks on the marked today and is called @@ -106,6 +106,8 @@ typedef int64_t Elf64_Sxword; #define EM_H8S 48 /* Hitachi H8S */ #define EM_LATTICEMICO32 138 /* LatticeMico32 */ +#define EM_OPENRISC 92 /* OpenCores OpenRISC */ + #define EM_UNICORE32 110 /* UniCore32 */ /* @@ -32,6 +32,7 @@ void error_set(Error **errp, const char *fmt, ...) if (errp == NULL) { return; } + assert(*errp == NULL); err = g_malloc0(sizeof(*err)); @@ -132,7 +133,7 @@ bool error_is_type(Error *err, const char *fmt) void error_propagate(Error **dst_err, Error *local_err) { - if (dst_err) { + if (dst_err && !*dst_err) { *dst_err = local_err; } else if (local_err) { error_free(local_err); @@ -57,7 +57,7 @@ void error_set_field(Error *err, const char *field, const char *value); /** * Propagate an error to an indirect pointer to an error. This function will * always transfer ownership of the error reference and handles the case where - * dst_err is NULL correctly. + * dst_err is NULL correctly. Errors after the first are discarded. */ void error_propagate(Error **dst_err, Error *local_err); @@ -1155,6 +1155,68 @@ static int cpu_gdb_write_register(CPUMIPSState *env, uint8_t *mem_buf, int n) return sizeof(target_ulong); } +#elif defined(TARGET_OPENRISC) + +#define NUM_CORE_REGS (32 + 3) + +static int cpu_gdb_read_register(CPUOpenRISCState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + GET_REG32(env->gpr[n]); + } else { + switch (n) { + case 32: /* PPC */ + GET_REG32(env->ppc); + break; + + case 33: /* NPC */ + GET_REG32(env->npc); + break; + + case 34: /* SR */ + GET_REG32(env->sr); + break; + + default: + break; + } + } + return 0; +} + +static int cpu_gdb_write_register(CPUOpenRISCState *env, + uint8_t *mem_buf, int n) +{ + uint32_t tmp; + + if (n > NUM_CORE_REGS) { + return 0; + } + + tmp = ldl_p(mem_buf); + + if (n < 32) { + env->gpr[n] = tmp; + } else { + switch (n) { + case 32: /* PPC */ + env->ppc = tmp; + break; + + case 33: /* NPC */ + env->npc = tmp; + break; + + case 34: /* SR */ + env->sr = tmp; + break; + + default: + break; + } + } + return 4; +} #elif defined (TARGET_SH4) /* Hint: Use "set architecture sh4" in GDB to see fpu registers */ @@ -1924,6 +1986,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) } #elif defined (TARGET_MICROBLAZE) s->c_cpu->sregs[SR_PC] = pc; +#elif defined(TARGET_OPENRISC) + s->c_cpu->pc = pc; #elif defined (TARGET_CRIS) s->c_cpu->pc = pc; #elif defined (TARGET_ALPHA) diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 1f96229d3c..bdd8fecc99 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -25,7 +25,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, /* arm_boot.c */ struct arm_boot_info { - int ram_size; + uint64_t ram_size; const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 236786eb5a..c413780784 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -11,7 +11,7 @@ obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o -obj-y += exynos4210_rtc.o +obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_l2x0.o obj-y += arm_mptimer.o a15mpcore.o obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o diff --git a/hw/arm_boot.c b/hw/arm_boot.c index a1e6ddbc1c..a6e9143662 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -216,11 +216,12 @@ static void set_kernel_args_old(const struct arm_boot_info *info) static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo) { #ifdef CONFIG_FDT - uint32_t mem_reg_property[] = { cpu_to_be32(binfo->loader_start), - cpu_to_be32(binfo->ram_size) }; + uint32_t *mem_reg_property; + uint32_t mem_reg_propsize; void *fdt = NULL; char *filename; int size, rc; + uint32_t acells, scells, hival; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename); if (!filename) { @@ -236,8 +237,36 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo) } g_free(filename); + acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells"); + scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells"); + if (acells == 0 || scells == 0) { + fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); + return -1; + } + + mem_reg_propsize = acells + scells; + mem_reg_property = g_new0(uint32_t, mem_reg_propsize); + mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start); + hival = cpu_to_be32(binfo->loader_start >> 32); + if (acells > 1) { + mem_reg_property[acells - 2] = hival; + } else if (hival != 0) { + fprintf(stderr, "qemu: dtb file not compatible with " + "RAM start address > 4GB\n"); + exit(1); + } + mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size); + hival = cpu_to_be32(binfo->ram_size >> 32); + if (scells > 1) { + mem_reg_property[acells + scells - 2] = hival; + } else if (hival != 0) { + fprintf(stderr, "qemu: dtb file not compatible with " + "RAM size > 4GB\n"); + exit(1); + } + rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, - sizeof(mem_reg_property)); + mem_reg_propsize * sizeof(uint32_t)); if (rc < 0) { fprintf(stderr, "couldn't set /memory/reg\n"); } @@ -357,7 +386,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) if (kernel_size < 0) { entry = info->loader_start + KERNEL_LOAD_ADDR; kernel_size = load_image_targphys(info->kernel_filename, entry, - ram_size - KERNEL_LOAD_ADDR); + info->ram_size - KERNEL_LOAD_ADDR); is_linux = 1; } if (kernel_size < 0) { @@ -371,7 +400,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) initrd_size = load_image_targphys(info->initrd_filename, info->loader_start + INITRD_LOAD_ADDR, - ram_size - INITRD_LOAD_ADDR); + info->ram_size + - INITRD_LOAD_ADDR); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initrd '%s'\n", info->initrd_filename); @@ -398,6 +428,12 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) bootloader[5] = dtb_start; } else { bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; + if (info->ram_size >= (1ULL << 32)) { + fprintf(stderr, "qemu: RAM size must be less than 4GB to boot" + " Linux kernel using ATAGS (try passing a device tree" + " using -dtb)\n"); + exit(1); + } } bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) { diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c index 2ccba6071c..cb43ee7733 100644 --- a/hw/bt-l2cap.c +++ b/hw/bt-l2cap.c @@ -1000,7 +1000,8 @@ static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, /* TODO: Signal an error? */ return; } - return l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data)); + l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data)); + return; } switch (hdr->data[1] >> 6) { /* SAR */ @@ -1010,7 +1011,8 @@ static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, if (len - 4 > ch->mps) goto len_error; - return ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4); + ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4); + break; case L2CAP_SAR_START: if (ch->len_total || len < 6) @@ -1033,7 +1035,8 @@ static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, goto len_error; memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4); - return ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total); + ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total); + break; case L2CAP_SAR_CONT: if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total) @@ -1136,7 +1139,7 @@ static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms) { struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms; - return l2cap_pdu_submit(chan->l2cap); + l2cap_pdu_submit(chan->l2cap); } #if 0 diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 87143caf2d..a0f51dea80 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -1161,7 +1161,7 @@ static void gem_set_link(VLANClientState *nc) } static NetClientInfo net_gem_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = gem_can_receive, .receive = gem_receive, diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 017d0742ae..756d6301b0 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -872,7 +872,7 @@ static void nic_cleanup(VLANClientState *nc) } static NetClientInfo net_dp83932_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = nic_can_receive, .receive = nic_receive, diff --git a/hw/e1000.c b/hw/e1000.c index 4573f1301e..ad242981cc 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1206,7 +1206,7 @@ pci_e1000_uninit(PCIDevice *dev) } static NetClientInfo net_e1000_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = e1000_can_receive, .receive = e1000_receive, diff --git a/hw/eepro100.c b/hw/eepro100.c index 6279ae36ec..e083e0ed14 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1596,10 +1596,17 @@ static void eepro100_write(void *opaque, target_phys_addr_t addr, EEPRO100State *s = opaque; switch (size) { - case 1: return eepro100_write1(s, addr, data); - case 2: return eepro100_write2(s, addr, data); - case 4: return eepro100_write4(s, addr, data); - default: abort(); + case 1: + eepro100_write1(s, addr, data); + break; + case 2: + eepro100_write2(s, addr, data); + break; + case 4: + eepro100_write4(s, addr, data); + break; + default: + abort(); } } @@ -1845,7 +1852,7 @@ static int pci_nic_uninit(PCIDevice *pci_dev) } static NetClientInfo net_eepro100_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = nic_can_receive, .receive = nic_receive, @@ -905,7 +905,6 @@ static Property escc_properties[] = { DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0), DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0), DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0), - DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0), DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0), DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0), DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr), diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 16a0637a4a..45fb40ce76 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -579,7 +579,7 @@ static void eth_cleanup(VLANClientState *nc) } static NetClientInfo net_etraxfs_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = eth_can_receive, .receive = eth_receive, diff --git a/hw/exynos4210.c b/hw/exynos4210.c index 7c58c906de..00d4db8871 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -39,6 +39,13 @@ /* MCT */ #define EXYNOS4210_MCT_BASE_ADDR 0x10050000 +/* I2C */ +#define EXYNOS4210_I2C_SHIFT 0x00010000 +#define EXYNOS4210_I2C_BASE_ADDR 0x13860000 +/* Interrupt Group of External Interrupt Combiner for I2C */ +#define EXYNOS4210_I2C_INTG 27 +#define EXYNOS4210_HDMI_INTG 16 + /* UART's definitions */ #define EXYNOS4210_UART0_BASE_ADDR 0x13800000 #define EXYNOS4210_UART1_BASE_ADDR 0x13810000 @@ -283,6 +290,26 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, s->irq_table[exynos4210_get_irq(35, 3)]); sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR); + /*** I2C ***/ + for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) { + uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n; + qemu_irq i2c_irq; + + if (n < 8) { + i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)]; + } else { + i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)]; + } + + dev = qdev_create(NULL, "exynos4210.i2c"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_connect_irq(busdev, 0, i2c_irq); + sysbus_mmio_map(busdev, 0, addr); + s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + } + + /*** UARTs ***/ exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR, EXYNOS4210_UART0_FIFO_SIZE, 0, NULL, diff --git a/hw/exynos4210.h b/hw/exynos4210.h index 9b1ae4c8b1..a43ba3aedc 100644 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@ -74,6 +74,8 @@ #define EXYNOS4210_EXT_GIC_NIRQ (160-32) #define EXYNOS4210_INT_GIC_NIRQ 64 +#define EXYNOS4210_I2C_NUMBER 9 + typedef struct Exynos4210Irq { qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ]; @@ -95,6 +97,7 @@ typedef struct Exynos4210State { MemoryRegion dram1_mem; MemoryRegion boot_secondary; MemoryRegion bootreg_mem; + i2c_bus *i2c_if[EXYNOS4210_I2C_NUMBER]; } Exynos4210State; void exynos4210_write_secondary(ARMCPU *cpu, diff --git a/hw/exynos4210_i2c.c b/hw/exynos4210_i2c.c new file mode 100644 index 0000000000..3f72a5c464 --- /dev/null +++ b/hw/exynos4210_i2c.c @@ -0,0 +1,334 @@ +/* + * Exynos4210 I2C Bus Serial Interface Emulation + * + * Copyright (C) 2012 Samsung Electronics Co Ltd. + * Maksim Kozlov, <m.kozlov@samsung.com> + * Igor Mitsyanko, <i.mitsyanko@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu-timer.h" +#include "sysbus.h" +#include "i2c.h" + +#ifndef EXYNOS4_I2C_DEBUG +#define EXYNOS4_I2C_DEBUG 0 +#endif + +#define TYPE_EXYNOS4_I2C "exynos4210.i2c" +#define EXYNOS4_I2C(obj) \ + OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C) + +/* Exynos4210 I2C memory map */ +#define EXYNOS4_I2C_MEM_SIZE 0x14 +#define I2CCON_ADDR 0x00 /* control register */ +#define I2CSTAT_ADDR 0x04 /* control/status register */ +#define I2CADD_ADDR 0x08 /* address register */ +#define I2CDS_ADDR 0x0c /* data shift register */ +#define I2CLC_ADDR 0x10 /* line control register */ + +#define I2CCON_ACK_GEN (1 << 7) +#define I2CCON_INTRS_EN (1 << 5) +#define I2CCON_INT_PEND (1 << 4) + +#define EXYNOS4_I2C_MODE(reg) (((reg) >> 6) & 3) +#define I2C_IN_MASTER_MODE(reg) (((reg) >> 6) & 2) +#define I2CMODE_MASTER_Rx 0x2 +#define I2CMODE_MASTER_Tx 0x3 +#define I2CSTAT_LAST_BIT (1 << 0) +#define I2CSTAT_OUTPUT_EN (1 << 4) +#define I2CSTAT_START_BUSY (1 << 5) + + +#if EXYNOS4_I2C_DEBUG +#define DPRINT(fmt, args...) \ + do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0) + +static const char *exynos4_i2c_get_regname(unsigned offset) +{ + switch (offset) { + case I2CCON_ADDR: + return "I2CCON"; + case I2CSTAT_ADDR: + return "I2CSTAT"; + case I2CADD_ADDR: + return "I2CADD"; + case I2CDS_ADDR: + return "I2CDS"; + case I2CLC_ADDR: + return "I2CLC"; + default: + return "[?]"; + } +} + +#else +#define DPRINT(fmt, args...) do { } while (0) +#endif + +typedef struct Exynos4210I2CState { + SysBusDevice busdev; + MemoryRegion iomem; + i2c_bus *bus; + qemu_irq irq; + + uint8_t i2ccon; + uint8_t i2cstat; + uint8_t i2cadd; + uint8_t i2cds; + uint8_t i2clc; + bool scl_free; +} Exynos4210I2CState; + +static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s) +{ + if (s->i2ccon & I2CCON_INTRS_EN) { + s->i2ccon |= I2CCON_INT_PEND; + qemu_irq_raise(s->irq); + } +} + +static void exynos4210_i2c_data_receive(void *opaque) +{ + Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; + int ret; + + s->i2cstat &= ~I2CSTAT_LAST_BIT; + s->scl_free = false; + ret = i2c_recv(s->bus); + if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { + s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */ + } else { + s->i2cds = ret; + } + exynos4210_i2c_raise_interrupt(s); +} + +static void exynos4210_i2c_data_send(void *opaque) +{ + Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; + + s->i2cstat &= ~I2CSTAT_LAST_BIT; + s->scl_free = false; + if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { + s->i2cstat |= I2CSTAT_LAST_BIT; + } + exynos4210_i2c_raise_interrupt(s); +} + +static uint64_t exynos4210_i2c_read(void *opaque, target_phys_addr_t offset, + unsigned size) +{ + Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; + uint8_t value; + + switch (offset) { + case I2CCON_ADDR: + value = s->i2ccon; + break; + case I2CSTAT_ADDR: + value = s->i2cstat; + break; + case I2CADD_ADDR: + value = s->i2cadd; + break; + case I2CDS_ADDR: + value = s->i2cds; + s->scl_free = true; + if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx && + (s->i2cstat & I2CSTAT_START_BUSY) && + !(s->i2ccon & I2CCON_INT_PEND)) { + exynos4210_i2c_data_receive(s); + } + break; + case I2CLC_ADDR: + value = s->i2clc; + break; + default: + value = 0; + DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset); + break; + } + + DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset), + (unsigned int)offset, value); + return value; +} + +static void exynos4210_i2c_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) +{ + Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; + uint8_t v = value & 0xff; + + DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset), + (unsigned int)offset, v); + + switch (offset) { + case I2CCON_ADDR: + s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND); + if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) { + s->i2ccon &= ~I2CCON_INT_PEND; + qemu_irq_lower(s->irq); + if (!(s->i2ccon & I2CCON_INTRS_EN)) { + s->i2cstat &= ~I2CSTAT_START_BUSY; + } + + if (s->i2cstat & I2CSTAT_START_BUSY) { + if (s->scl_free) { + if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) { + exynos4210_i2c_data_send(s); + } else if (EXYNOS4_I2C_MODE(s->i2cstat) == + I2CMODE_MASTER_Rx) { + exynos4210_i2c_data_receive(s); + } + } else { + s->i2ccon |= I2CCON_INT_PEND; + qemu_irq_raise(s->irq); + } + } + } + break; + case I2CSTAT_ADDR: + s->i2cstat = + (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY); + + if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) { + s->i2cstat &= ~I2CSTAT_START_BUSY; + s->scl_free = true; + qemu_irq_lower(s->irq); + break; + } + + /* Nothing to do if in i2c slave mode */ + if (!I2C_IN_MASTER_MODE(s->i2cstat)) { + break; + } + + if (v & I2CSTAT_START_BUSY) { + s->i2cstat &= ~I2CSTAT_LAST_BIT; + s->i2cstat |= I2CSTAT_START_BUSY; /* Line is busy */ + s->scl_free = false; + + /* Generate start bit and send slave address */ + if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) && + (s->i2ccon & I2CCON_ACK_GEN)) { + s->i2cstat |= I2CSTAT_LAST_BIT; + } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) { + exynos4210_i2c_data_receive(s); + } + exynos4210_i2c_raise_interrupt(s); + } else { + i2c_end_transfer(s->bus); + if (!(s->i2ccon & I2CCON_INT_PEND)) { + s->i2cstat &= ~I2CSTAT_START_BUSY; + } + s->scl_free = true; + } + break; + case I2CADD_ADDR: + if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) { + s->i2cadd = v; + } + break; + case I2CDS_ADDR: + if (s->i2cstat & I2CSTAT_OUTPUT_EN) { + s->i2cds = v; + s->scl_free = true; + if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx && + (s->i2cstat & I2CSTAT_START_BUSY) && + !(s->i2ccon & I2CCON_INT_PEND)) { + exynos4210_i2c_data_send(s); + } + } + break; + case I2CLC_ADDR: + s->i2clc = v; + break; + default: + DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset); + break; + } +} + +static const MemoryRegionOps exynos4210_i2c_ops = { + .read = exynos4210_i2c_read, + .write = exynos4210_i2c_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription exynos4210_i2c_vmstate = { + .name = TYPE_EXYNOS4_I2C, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(i2ccon, Exynos4210I2CState), + VMSTATE_UINT8(i2cstat, Exynos4210I2CState), + VMSTATE_UINT8(i2cds, Exynos4210I2CState), + VMSTATE_UINT8(i2cadd, Exynos4210I2CState), + VMSTATE_UINT8(i2clc, Exynos4210I2CState), + VMSTATE_BOOL(scl_free, Exynos4210I2CState), + VMSTATE_END_OF_LIST() + } +}; + +static void exynos4210_i2c_reset(DeviceState *d) +{ + Exynos4210I2CState *s = EXYNOS4_I2C(d); + + s->i2ccon = 0x00; + s->i2cstat = 0x00; + s->i2cds = 0xFF; + s->i2clc = 0x00; + s->i2cadd = 0xFF; + s->scl_free = true; +} + +static int exynos4210_i2c_realize(SysBusDevice *dev) +{ + Exynos4210I2CState *s = EXYNOS4_I2C(dev); + + memory_region_init_io(&s->iomem, &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C, + EXYNOS4_I2C_MEM_SIZE); + sysbus_init_mmio(dev, &s->iomem); + sysbus_init_irq(dev, &s->irq); + s->bus = i2c_init_bus(&dev->qdev, "i2c"); + return 0; +} + +static void exynos4210_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); + + dc->vmsd = &exynos4210_i2c_vmstate; + dc->reset = exynos4210_i2c_reset; + sbdc->init = exynos4210_i2c_realize; +} + +static const TypeInfo exynos4210_i2c_type_info = { + .name = TYPE_EXYNOS4_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Exynos4210I2CState), + .class_init = exynos4210_i2c_class_init, +}; + +static void exynos4210_i2c_register_types(void) +{ + type_register_static(&exynos4210_i2c_type_info); +} + +type_init(exynos4210_i2c_register_types) diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c index f78102049b..42a4ddc327 100644 --- a/hw/exynos4210_rtc.c +++ b/hw/exynos4210_rtc.c @@ -142,7 +142,7 @@ static const VMStateDescription vmstate_exynos4210_rtc_state = { }; #define BCD3DIGITS(x) \ - ((uint32_t)to_bcd((uint8_t)x) + \ + ((uint32_t)to_bcd((uint8_t)(x % 100)) + \ ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8)) static void check_alarm_raise(Exynos4210RTCState *s) @@ -510,10 +510,7 @@ static void exynos4210_rtc_reset(DeviceState *d) { Exynos4210RTCState *s = (Exynos4210RTCState *)d; - struct tm tm; - - qemu_get_timedate(&tm, 0); - s->current_tm = tm; + qemu_get_timedate(&s->current_tm, 0); DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n", s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday, diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index bf8ece4708..087b4f922d 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -94,12 +94,12 @@ static void cmd646_data_write(void *opaque, target_phys_addr_t addr, CMD646BAR *cmd646bar = opaque; if (size == 1) { - return ide_ioport_write(cmd646bar->bus, addr, data); + ide_ioport_write(cmd646bar->bus, addr, data); } else if (addr == 0) { if (size == 2) { - return ide_data_writew(cmd646bar->bus, addr, data); + ide_data_writew(cmd646bar->bus, addr, data); } else { - return ide_data_writel(cmd646bar->bus, addr, data); + ide_data_writel(cmd646bar->bus, addr, data); } } } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index f5a74c293a..66527610a8 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -73,7 +73,8 @@ static void bmdma_write(void *opaque, target_phys_addr_t addr, #endif switch(addr & 3) { case 0: - return bmdma_cmd_writeb(bm, val); + bmdma_cmd_writeb(bm, val); + break; case 2: bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); break; diff --git a/hw/ide/via.c b/hw/ide/via.c index eec5136019..a17f2e2dd5 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -74,7 +74,8 @@ static void bmdma_write(void *opaque, target_phys_addr_t addr, #endif switch (addr & 3) { case 0: - return bmdma_cmd_writeb(bm, val); + bmdma_cmd_writeb(bm, val); + break; case 2: bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); break; diff --git a/hw/lan9118.c b/hw/lan9118.c index 7b4fe87fca..61f1c0e63b 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -1166,9 +1166,11 @@ static void lan9118_16bit_mode_write(void *opaque, target_phys_addr_t offset, { switch (size) { case 2: - return lan9118_writew(opaque, offset, (uint32_t)val); + lan9118_writew(opaque, offset, (uint32_t)val); + return; case 4: - return lan9118_writel(opaque, offset, val, size); + lan9118_writel(opaque, offset, val, size); + return; } hw_error("lan9118_write: Bad size 0x%x\n", size); @@ -1310,7 +1312,7 @@ static void lan9118_cleanup(VLANClientState *nc) } static NetClientInfo net_lan9118_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = lan9118_can_receive, .receive = lan9118_receive, diff --git a/hw/lance.c b/hw/lance.c index ce3d46c17b..91c0e16237 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -93,7 +93,7 @@ static void lance_cleanup(VLANClientState *nc) } static NetClientInfo net_lance_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = pcnet_can_receive, .receive = pcnet_receive, diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index ae37bef0f0..4ab4ff583d 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -450,7 +450,7 @@ static void mcf_fec_cleanup(VLANClientState *nc) } static NetClientInfo net_mcf_fec_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = mcf_fec_can_receive, .receive = mcf_fec_receive, @@ -435,24 +435,24 @@ typedef enum { struct mfi_sg32 { uint32_t addr; uint32_t len; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_sg64 { uint64_t addr; uint32_t len; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_sg_skinny { uint64_t addr; uint32_t len; uint32_t flag; -} __attribute__ ((packed)); +} QEMU_PACKED; union mfi_sgl { struct mfi_sg32 sg32[1]; struct mfi_sg64 sg64[1]; struct mfi_sg_skinny sg_skinny[1]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Message frames. All messages have a common header */ struct mfi_frame_header { @@ -468,7 +468,7 @@ struct mfi_frame_header { uint16_t flags; uint16_t timeout; uint32_t data_len; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_init_frame { struct mfi_frame_header header; @@ -487,7 +487,7 @@ struct mfi_io_frame { uint32_t lba_lo; uint32_t lba_hi; union mfi_sgl sgl; -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_PASS_FRAME_SIZE 48 struct mfi_pass_frame { @@ -496,7 +496,7 @@ struct mfi_pass_frame { uint32_t sense_addr_hi; uint8_t cdb[16]; union mfi_sgl sgl; -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_DCMD_FRAME_SIZE 40 struct mfi_dcmd_frame { @@ -504,7 +504,7 @@ struct mfi_dcmd_frame { uint32_t opcode; uint8_t mbox[MFI_MBOX_SIZE]; union mfi_sgl sgl; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_abort_frame { struct mfi_frame_header header; @@ -512,7 +512,7 @@ struct mfi_abort_frame { uint32_t abort_mfi_addr_lo; uint32_t abort_mfi_addr_hi; uint32_t reserved1[6]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_smp_frame { struct mfi_frame_header header; @@ -521,7 +521,7 @@ struct mfi_smp_frame { struct mfi_sg32 sg32[2]; struct mfi_sg64 sg64[2]; } sgl; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_stp_frame { struct mfi_frame_header header; @@ -531,7 +531,7 @@ struct mfi_stp_frame { struct mfi_sg32 sg32[2]; struct mfi_sg64 sg64[2]; } sgl; -} __attribute__ ((packed)); +} QEMU_PACKED; union mfi_frame { struct mfi_frame_header header; @@ -563,7 +563,7 @@ struct mfi_init_qinfo { uint32_t pi_addr_hi; uint32_t ci_addr_lo; uint32_t ci_addr_hi; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Controller properties */ struct mfi_ctrl_props { @@ -626,7 +626,7 @@ struct mfi_ctrl_props { * is spun down (0=use FW defaults) */ uint8_t reserved[24]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* PCI information about the card. */ struct mfi_info_pci { @@ -635,7 +635,7 @@ struct mfi_info_pci { uint16_t subvendor; uint16_t subdevice; uint8_t reserved[24]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Host (front end) interface information */ struct mfi_info_host { @@ -647,7 +647,7 @@ struct mfi_info_host { uint8_t reserved[6]; uint8_t port_count; uint64_t port_addr[8]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Device (back end) interface information */ struct mfi_info_device { @@ -659,7 +659,7 @@ struct mfi_info_device { uint8_t reserved[6]; uint8_t port_count; uint64_t port_addr[8]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Firmware component information */ struct mfi_info_component { @@ -667,7 +667,7 @@ struct mfi_info_component { char version[32]; char build_date[16]; char build_time[16]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Controller default settings */ struct mfi_defaults { @@ -710,7 +710,7 @@ struct mfi_defaults { uint8_t fde_only; uint8_t delay_during_post; uint8_t resv[19]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* Controller default settings */ struct mfi_bios_data { @@ -722,7 +722,7 @@ struct mfi_bios_data { uint8_t expose_all_drives; uint8_t reserved[56]; uint8_t check_sum; -} __attribute__ ((packed)); +} QEMU_PACKED; /* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */ struct mfi_ctrl_info { @@ -807,7 +807,7 @@ struct mfi_ctrl_info { uint8_t min; uint8_t max; uint8_t reserved[2]; - } __attribute__ ((packed)) stripe_sz_ops; + } QEMU_PACKED stripe_sz_ops; uint32_t pd_ops; #define MFI_INFO_PDOPS_FORCE_ONLINE 0x01 @@ -826,7 +826,7 @@ struct mfi_ctrl_info { struct mfi_ctrl_props properties; char package_version[0x60]; uint8_t pad[0x800 - 0x6a0]; -} __attribute__ ((packed)); +} QEMU_PACKED; /* keep track of an event. */ union mfi_evt { @@ -836,7 +836,7 @@ union mfi_evt { int8_t class; } members; uint32_t word; -} __attribute__ ((packed)); +} QEMU_PACKED; /* event log state. */ struct mfi_evt_log_state { @@ -845,24 +845,24 @@ struct mfi_evt_log_state { uint32_t clear_seq_num; uint32_t shutdown_seq_num; uint32_t boot_seq_num; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_progress { uint16_t progress; uint16_t elapsed_seconds; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_evt_ld { uint16_t target_id; uint8_t ld_index; uint8_t reserved; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_evt_pd { uint16_t device_id; uint8_t enclosure_index; uint8_t slot_number; -} __attribute__ ((packed)); +} QEMU_PACKED; /* event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */ struct mfi_evt_detail { @@ -982,13 +982,13 @@ struct mfi_evt_detail { } args; char description[128]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_evt_list { uint32_t count; uint32_t reserved; struct mfi_evt_detail event[1]; -} __attribute__ ((packed)); +} QEMU_PACKED; union mfi_pd_ref { struct { @@ -996,7 +996,7 @@ union mfi_pd_ref { uint16_t seq_num; } v; uint32_t ref; -} __attribute__ ((packed)); +} QEMU_PACKED; union mfi_pd_ddf_type { struct { @@ -1016,7 +1016,7 @@ union mfi_pd_ddf_type { uint32_t reserved; } non_disk; uint32_t type; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_pd_progress { uint32_t active; @@ -1027,7 +1027,7 @@ struct mfi_pd_progress { struct mfi_progress patrol; struct mfi_progress clear; struct mfi_progress reserved[4]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_pd_info { union mfi_pd_ref ref; @@ -1062,7 +1062,7 @@ struct mfi_pd_info { uint8_t unusable_in_current_config; uint8_t vpd_page83_ext[64]; uint8_t reserved[512-358]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_pd_address { uint16_t device_id; @@ -1072,14 +1072,14 @@ struct mfi_pd_address { uint8_t scsi_dev_type; uint8_t connect_port_bitmap; uint64_t sas_addr[2]; -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_MAX_SYS_PDS 240 struct mfi_pd_list { uint32_t size; uint32_t count; struct mfi_pd_address addr[MFI_MAX_SYS_PDS]; -} __attribute__ ((packed)); +} QEMU_PACKED; union mfi_ld_ref { struct { @@ -1088,7 +1088,7 @@ union mfi_ld_ref { uint16_t seq; } v; uint32_t ref; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_ld_list { uint32_t ld_count; @@ -1099,7 +1099,7 @@ struct mfi_ld_list { uint8_t reserved2[3]; uint64_t size; } ld_list[MFI_MAX_LD]; -} __attribute__ ((packed)); +} QEMU_PACKED; enum mfi_ld_access { MFI_LD_ACCESS_RW = 0, @@ -1136,7 +1136,7 @@ struct mfi_ld_props { uint8_t current_cache_policy; uint8_t no_bgi; uint8_t reserved[7]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_ld_params { uint8_t primary_raid_level; @@ -1149,7 +1149,7 @@ struct mfi_ld_params { uint8_t init_state; uint8_t is_consistent; uint8_t reserved[23]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_ld_progress { uint32_t active; @@ -1162,21 +1162,21 @@ struct mfi_ld_progress { struct mfi_progress fgi; struct mfi_progress recon; struct mfi_progress reserved[4]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_span { uint64_t start_block; uint64_t num_blocks; uint16_t array_ref; uint8_t reserved[6]; -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_MAX_SPAN_DEPTH 8 struct mfi_ld_config { struct mfi_ld_props properties; struct mfi_ld_params params; struct mfi_span span[MFI_MAX_SPAN_DEPTH]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_ld_info { struct mfi_ld_config ld_config; @@ -1187,7 +1187,7 @@ struct mfi_ld_info { uint8_t reserved1[1]; uint8_t vpd_page83[64]; uint8_t reserved2[16]; -} __attribute__ ((packed)); +} QEMU_PACKED; union mfi_spare_type { uint8_t flags; @@ -1195,7 +1195,7 @@ union mfi_spare_type { #define MFI_SPARE_IS_REVERTABLE (1 << 1) #define MFI_SPARE_IS_ENCL_AFFINITY (1 << 2) uint8_t type; -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_MAX_ARRAYS 16 struct mfi_spare { @@ -1204,7 +1204,7 @@ struct mfi_spare { uint8_t reserved[2]; uint8_t array_count; uint16_t array_refd[MFI_MAX_ARRAYS]; -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_MAX_ROW_SIZE 32 struct mfi_array { @@ -1221,7 +1221,7 @@ struct mfi_array { uint8_t slot; } encl; } pd[MFI_MAX_ROW_SIZE]; -} __attribute__ ((packed)); +} QEMU_PACKED; struct mfi_config_data { uint32_t size; @@ -1237,7 +1237,7 @@ struct mfi_config_data { struct mfi_ld_config ld[]; struct mfi_spare spare[]; */ -} __attribute__ ((packed)); +} QEMU_PACKED; #define MFI_SCSI_MAX_TARGETS 128 #define MFI_SCSI_MAX_LUNS 8 diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 70bf336add..3924b8343d 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -448,7 +448,7 @@ static void milkymist_minimac2_reset(DeviceState *d) } static NetClientInfo net_milkymist_minimac2_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = minimac2_can_rx, .receive = minimac2_rx, diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 31072463f4..3385be7683 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -217,7 +217,7 @@ static void mipsnet_cleanup(VLANClientState *nc) } static NetClientInfo net_mipsnet_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = mipsnet_can_receive, .receive = mipsnet_receive, diff --git a/hw/musicpal.c b/hw/musicpal.c index f14f20d689..448897f82c 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -374,7 +374,7 @@ static void eth_cleanup(VLANClientState *nc) } static NetClientInfo net_mv88w8618_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = eth_can_receive, .receive = eth_receive, diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index a4a783ab89..99ed965eac 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -44,7 +44,7 @@ static void isa_ne2000_cleanup(VLANClientState *nc) } static NetClientInfo net_ne2000_isa_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = ne2000_can_receive, .receive = ne2000_receive, diff --git a/hw/ne2000.c b/hw/ne2000.c index d02e60c4a6..ae561e6567 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -677,15 +677,15 @@ static void ne2000_write(void *opaque, target_phys_addr_t addr, NE2000State *s = opaque; if (addr < 0x10 && size == 1) { - return ne2000_ioport_write(s, addr, data); + ne2000_ioport_write(s, addr, data); } else if (addr == 0x10) { if (size <= 2) { - return ne2000_asic_ioport_write(s, addr, data); + ne2000_asic_ioport_write(s, addr, data); } else { - return ne2000_asic_ioport_writel(s, addr, data); + ne2000_asic_ioport_writel(s, addr, data); } } else if (addr == 0x1f && size == 1) { - return ne2000_reset_ioport_write(s, addr, data); + ne2000_reset_ioport_write(s, addr, data); } } @@ -711,7 +711,7 @@ static void ne2000_cleanup(VLANClientState *nc) } static NetClientInfo net_ne2000_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = ne2000_can_receive, .receive = ne2000_receive, diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index 350f73173a..f4498d413d 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -467,7 +467,7 @@ static void open_eth_cleanup(VLANClientState *nc) } static NetClientInfo net_open_eth_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = open_eth_can_receive, .receive = open_eth_receive, diff --git a/hw/openrisc/Makefile.objs b/hw/openrisc/Makefile.objs new file mode 100644 index 0000000000..38ff8f5d6d --- /dev/null +++ b/hw/openrisc/Makefile.objs @@ -0,0 +1,3 @@ +obj-y = openrisc_pic.o openrisc_sim.o openrisc_timer.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/openrisc_pic.c b/hw/openrisc_pic.c new file mode 100644 index 0000000000..aaeb9a9171 --- /dev/null +++ b/hw/openrisc_pic.c @@ -0,0 +1,60 @@ +/* + * OpenRISC Programmable Interrupt Controller support. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Feng Gao <gf91597@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "cpu.h" + +/* OpenRISC pic handler */ +static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) +{ + OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; + int i; + uint32_t irq_bit = 1 << irq; + + if (irq > 31 || irq < 0) { + return; + } + + if (level) { + cpu->env.picsr |= irq_bit; + } else { + cpu->env.picsr &= ~irq_bit; + } + + for (i = 0; i < 32; i++) { + if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) { + cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD); + cpu->env.picsr &= ~(1 << i); + } + } +} + +void cpu_openrisc_pic_init(OpenRISCCPU *cpu) +{ + int i; + qemu_irq *qi; + qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS); + + for (i = 0; i < NR_IRQS; i++) { + cpu->env.irq[i] = qi[i]; + } +} diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c new file mode 100644 index 0000000000..f07f7fc517 --- /dev/null +++ b/hw/openrisc_sim.c @@ -0,0 +1,150 @@ +/* + * OpenRISC simulator for use as an IIS. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Feng Gao <gf91597@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "boards.h" +#include "elf.h" +#include "pc.h" +#include "loader.h" +#include "exec-memory.h" +#include "sysemu.h" +#include "sysbus.h" +#include "qtest.h" + +#define KERNEL_LOAD_ADDR 0x100 + +static void main_cpu_reset(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void openrisc_sim_net_init(MemoryRegion *address_space, + target_phys_addr_t base, + target_phys_addr_t descriptors, + qemu_irq irq, NICInfo *nd) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "open_eth"); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + + s = sysbus_from_qdev(dev); + sysbus_connect_irq(s, 0, irq); + memory_region_add_subregion(address_space, base, + sysbus_mmio_get_region(s, 0)); + memory_region_add_subregion(address_space, descriptors, + sysbus_mmio_get_region(s, 1)); +} + +static void cpu_openrisc_load_kernel(ram_addr_t ram_size, + const char *kernel_filename, + OpenRISCCPU *cpu) +{ + long kernel_size; + uint64_t elf_entry; + target_phys_addr_t entry; + + if (kernel_filename && !qtest_enabled()) { + kernel_size = load_elf(kernel_filename, NULL, NULL, + &elf_entry, NULL, NULL, 1, ELF_MACHINE, 1); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, + &entry, NULL, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + } + + if (kernel_size < 0) { + qemu_log("QEMU: couldn't load the kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + cpu->env.pc = entry; +} + +static void openrisc_sim_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + OpenRISCCPU *cpu = NULL; + MemoryRegion *ram; + int n; + + if (!cpu_model) { + cpu_model = "or1200"; + } + + for (n = 0; n < smp_cpus; n++) { + cpu = cpu_openrisc_init(cpu_model); + if (cpu == NULL) { + qemu_log("Unable to find CPU defineition!\n"); + exit(1); + } + qemu_register_reset(main_cpu_reset, cpu); + main_cpu_reset(cpu); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "openrisc.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(get_system_memory(), 0, ram); + + cpu_openrisc_pic_init(cpu); + cpu_openrisc_clock_init(cpu); + + serial_mm_init(get_system_memory(), 0x90000000, 0, cpu->env.irq[2], + 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); + + if (nd_table[0].vlan) { + openrisc_sim_net_init(get_system_memory(), 0x92000000, + 0x92000400, cpu->env.irq[4], nd_table); + } + + cpu_openrisc_load_kernel(ram_size, kernel_filename, cpu); +} + +static QEMUMachine openrisc_sim_machine = { + .name = "or32-sim", + .desc = "or32 simulation", + .init = openrisc_sim_init, + .max_cpus = 1, + .is_default = 1, +}; + +static void openrisc_sim_machine_init(void) +{ + qemu_register_machine(&openrisc_sim_machine); +} + +machine_init(openrisc_sim_machine_init); diff --git a/hw/openrisc_timer.c b/hw/openrisc_timer.c new file mode 100644 index 0000000000..7916e61d24 --- /dev/null +++ b/hw/openrisc_timer.c @@ -0,0 +1,101 @@ +/* + * QEMU OpenRISC timer support + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Zhizhou Zhang <etouzh@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "hw.h" +#include "qemu-timer.h" + +#define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */ + +/* The time when TTCR changes */ +static uint64_t last_clk; +static int is_counting; + +void cpu_openrisc_count_update(OpenRISCCPU *cpu) +{ + uint64_t now, next; + uint32_t wait; + + now = qemu_get_clock_ns(vm_clock); + if (!is_counting) { + qemu_del_timer(cpu->env.timer); + last_clk = now; + return; + } + + cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ, + get_ticks_per_sec()); + last_clk = now; + + if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) { + wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1; + wait += cpu->env.ttmr & TTMR_TP; + } else { + wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP); + } + + next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); + qemu_mod_timer(cpu->env.timer, next); +} + +void cpu_openrisc_count_start(OpenRISCCPU *cpu) +{ + is_counting = 1; + cpu_openrisc_count_update(cpu); +} + +void cpu_openrisc_count_stop(OpenRISCCPU *cpu) +{ + is_counting = 0; + cpu_openrisc_count_update(cpu); +} + +static void openrisc_timer_cb(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + + if ((cpu->env.ttmr & TTMR_IE) && + qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) { + cpu->env.ttmr |= TTMR_IP; + cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER; + } + + switch (cpu->env.ttmr & TTMR_M) { + case TIMER_NONE: + break; + case TIMER_INTR: + cpu->env.ttcr = 0; + cpu_openrisc_count_start(cpu); + break; + case TIMER_SHOT: + cpu_openrisc_count_stop(cpu); + break; + case TIMER_CONT: + cpu_openrisc_count_start(cpu); + break; + } +} + +void cpu_openrisc_clock_init(OpenRISCCPU *cpu) +{ + cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu); + cpu->env.ttmr = 0x00000000; + cpu->env.ttcr = 0x00000000; +} diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 34d73aaea1..931fedd913 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -284,7 +284,7 @@ static int pci_pcnet_uninit(PCIDevice *dev) } static NetClientInfo net_pci_pcnet_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = pcnet_can_receive, .receive = pcnet_receive, diff --git a/hw/pl011.c b/hw/pl011.c index 8a5a8f554a..3245702df0 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -78,7 +78,9 @@ static uint64_t pl011_read(void *opaque, target_phys_addr_t offset, if (s->read_count == s->read_trigger - 1) s->int_level &= ~ PL011_INT_RX; pl011_update(s); - qemu_chr_accept_input(s->chr); + if (s->chr) { + qemu_chr_accept_input(s->chr); + } return c; case 1: /* UARTCR */ return 0; diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index fddf2197a9..c5b8e051ec 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -40,7 +40,7 @@ typedef struct spin_info { uint32_t resv; uint32_t pir; uint64_t reserved; -} __attribute__ ((packed)) SpinInfo; +} QEMU_PACKED SpinInfo; typedef struct spin_state { SysBusDevice busdev; @@ -78,12 +78,6 @@ struct DeviceState { int alias_required_for_version; }; -/* - * This callback is used to create Open Firmware device path in accordance with - * OF spec http://forthworks.com/standards/of1275.pdf. Indicidual bus bindings - * can be found here http://playground.sun.com/1275/bindings/. - */ - #define TYPE_BUS "bus" #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS) #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS) @@ -95,6 +89,11 @@ struct BusClass { /* FIXME first arg should be BusState */ void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); char *(*get_dev_path)(DeviceState *dev); + /* + * This callback is used to create Open Firmware device path in accordance + * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus + * bindings can be found at http://playground.sun.com/1275/bindings/. + */ char *(*get_fw_dev_path)(DeviceState *dev); int (*reset)(BusState *bus); }; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 436b015c64..82fe235417 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3455,7 +3455,7 @@ static int pci_rtl8139_uninit(PCIDevice *dev) } static NetClientInfo net_rtl8139_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = rtl8139_can_receive, .receive = rtl8139_receive, diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 1a5213fa56..451ede0588 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -736,7 +736,7 @@ static void smc91c111_cleanup(VLANClientState *nc) } static NetClientInfo net_smc91c111_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = smc91c111_can_receive, .receive = smc91c111_receive, diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index d26fe9fea3..d54f933d3a 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -176,7 +176,7 @@ static ssize_t spapr_vlan_receive(VLANClientState *nc, const uint8_t *buf, } static NetClientInfo net_spapr_vlan_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = spapr_vlan_can_receive, .receive = spapr_vlan_receive, diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 47ba5ff770..b2e4f785ea 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -418,7 +418,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, uint64_t child; uint64_t parent; uint64_t size; - } __attribute__((packed)) ranges[] = { + } QEMU_PACKED ranges[] = { { cpu_to_be32(b_ss(1)), cpu_to_be64(0), cpu_to_be64(phb->io_win_addr), diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index fbe99cb4a9..b593cd0ed9 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -393,7 +393,7 @@ static void stellaris_enet_cleanup(VLANClientState *nc) } static NetClientInfo net_stellaris_enet_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = stellaris_enet_can_receive, .receive = stellaris_enet_receive, diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 5d2f0982c9..f40c349fc3 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1313,7 +1313,7 @@ static void usb_net_handle_destroy(USBDevice *dev) } static NetClientInfo net_usbnet_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = usbnet_can_receive, .receive = usbnet_receive, diff --git a/hw/vexpress.c b/hw/vexpress.c index 8072c5ada9..b2dc8a5ab3 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -284,9 +284,16 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } - if (ram_size > 0x80000000) { - fprintf(stderr, "vexpress-a15: cannot model more than 2GB RAM\n"); - exit(1); + { + /* We have to use a separate 64 bit variable here to avoid the gcc + * "comparison is always false due to limited range of data type" + * warning if we are on a host where ram_addr_t is 32 bits. + */ + uint64_t rsz = ram_size; + if (rsz > (30ULL * 1024 * 1024 * 1024)) { + fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n"); + exit(1); + } } memory_region_init_ram(ram, "vexpress.highmem", ram_size); diff --git a/hw/vhost_net.c b/hw/vhost_net.c index f672e9dafd..75f8211046 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -83,7 +83,7 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features) static int vhost_net_get_fd(VLANClientState *backend) { switch (backend->info->type) { - case NET_CLIENT_TYPE_TAP: + case NET_CLIENT_OPTIONS_KIND_TAP: return tap_get_fd(backend); default: fprintf(stderr, "vhost-net requires tap backend\n"); diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 533aa3d0f3..df204999bc 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -108,7 +108,7 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) if (!n->nic->nc.peer) { return; } - if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) { + if (n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return; } @@ -205,7 +205,7 @@ static int peer_has_vnet_hdr(VirtIONet *n) if (!n->nic->nc.peer) return 0; - if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) + if (n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) return 0; n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer); @@ -249,7 +249,7 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features) } if (!n->nic->nc.peer || - n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) { + n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return features; } if (!tap_get_vhost_net(n->nic->nc.peer)) { @@ -288,7 +288,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) (features >> VIRTIO_NET_F_GUEST_UFO) & 1); } if (!n->nic->nc.peer || - n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) { + n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return; } if (!tap_get_vhost_net(n->nic->nc.peer)) { @@ -988,7 +988,7 @@ static void virtio_net_cleanup(VLANClientState *nc) } static NetClientInfo net_virtio_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = virtio_net_can_receive, .receive = virtio_net_receive, diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 476dc89a0c..f5e4f440d5 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1150,11 +1150,14 @@ static void vmsvga_io_write(void *opaque, target_phys_addr_t addr, switch (addr) { case SVGA_IO_MUL * SVGA_INDEX_PORT: - return vmsvga_index_write(s, addr, data); + vmsvga_index_write(s, addr, data); + break; case SVGA_IO_MUL * SVGA_VALUE_PORT: - return vmsvga_value_write(s, addr, data); + vmsvga_value_write(s, addr, data); + break; case SVGA_IO_MUL * SVGA_BIOS_PORT: - return vmsvga_bios_write(s, addr, data); + vmsvga_bios_write(s, addr, data); + break; } } diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 98db9bb8f6..593a572119 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -301,7 +301,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz /* ------------------------------------------------------------- */ static NetClientInfo net_xen_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = net_rx_ok, .receive = net_rx_packet, diff --git a/hw/xgmac.c b/hw/xgmac.c index dd4bdc46f5..e539681d83 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -371,7 +371,7 @@ static void eth_cleanup(VLANClientState *nc) } static NetClientInfo net_xgmac_enet_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = eth_can_rx, .receive = eth_rx, diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 2e8d8a59ba..e948505849 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -832,7 +832,7 @@ axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr) } static NetClientInfo net_xilinx_enet_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = eth_can_rx, .receive = eth_rx, diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index affbb8bfff..9006322855 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -202,7 +202,7 @@ static void eth_cleanup(VLANClientState *nc) } static NetClientInfo net_xilinx_ethlite_info = { - .type = NET_CLIENT_TYPE_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = eth_can_rx, .receive = eth_rx, diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f3b1552e9e..6b622d4ff9 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -787,6 +787,47 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env #endif /* TARGET_MICROBLAZE */ +#ifdef TARGET_OPENRISC + +#define ELF_START_MMAP 0x08000000 + +#define elf_check_arch(x) ((x) == EM_OPENRISC) + +#define ELF_ARCH EM_OPENRISC +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + regs->pc = infop->entry; + regs->gpr[1] = infop->start_stack; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +/* See linux kernel arch/openrisc/include/asm/elf.h. */ +#define ELF_NREG 34 /* gprs and pc, sr */ +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPUOpenRISCState *env) +{ + int i; + + for (i = 0; i < 32; i++) { + (*regs)[i] = tswapl(env->gpr[i]); + } + + (*regs)[32] = tswapl(env->pc); + (*regs)[33] = tswapl(env->sr); +} +#define ELF_HWCAP 0 +#define ELF_PLATFORM NULL + +#endif /* TARGET_OPENRISC */ + #ifdef TARGET_SH4 #define ELF_START_MMAP 0x80000000 diff --git a/linux-user/main.c b/linux-user/main.c index d0e0e4fc6a..a0ab8e839c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2306,6 +2306,93 @@ done_syscall: } #endif +#ifdef TARGET_OPENRISC + +void cpu_loop(CPUOpenRISCState *env) +{ + int trapnr, gdbsig; + + for (;;) { + trapnr = cpu_exec(env); + gdbsig = 0; + + switch (trapnr) { + case EXCP_RESET: + qemu_log("\nReset request, exit, pc is %#x\n", env->pc); + exit(1); + break; + case EXCP_BUSERR: + qemu_log("\nBus error, exit, pc is %#x\n", env->pc); + gdbsig = SIGBUS; + break; + case EXCP_DPF: + case EXCP_IPF: + cpu_dump_state(env, stderr, fprintf, 0); + gdbsig = TARGET_SIGSEGV; + break; + case EXCP_TICK: + qemu_log("\nTick time interrupt pc is %#x\n", env->pc); + break; + case EXCP_ALIGN: + qemu_log("\nAlignment pc is %#x\n", env->pc); + gdbsig = SIGBUS; + break; + case EXCP_ILLEGAL: + qemu_log("\nIllegal instructionpc is %#x\n", env->pc); + gdbsig = SIGILL; + break; + case EXCP_INT: + qemu_log("\nExternal interruptpc is %#x\n", env->pc); + break; + case EXCP_DTLBMISS: + case EXCP_ITLBMISS: + qemu_log("\nTLB miss\n"); + break; + case EXCP_RANGE: + qemu_log("\nRange\n"); + gdbsig = SIGSEGV; + break; + case EXCP_SYSCALL: + env->pc += 4; /* 0xc00; */ + env->gpr[11] = do_syscall(env, + env->gpr[11], /* return value */ + env->gpr[3], /* r3 - r7 are params */ + env->gpr[4], + env->gpr[5], + env->gpr[6], + env->gpr[7], + env->gpr[8], 0, 0); + break; + case EXCP_FPE: + qemu_log("\nFloating point error\n"); + break; + case EXCP_TRAP: + qemu_log("\nTrap\n"); + gdbsig = SIGTRAP; + break; + case EXCP_NR: + qemu_log("\nNR\n"); + break; + default: + qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n", + trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + gdbsig = TARGET_SIGILL; + break; + } + if (gdbsig) { + gdb_handlesig(env, gdbsig); + if (gdbsig != TARGET_SIGTRAP) { + exit(1); + } + } + + process_pending_signals(env); + } +} + +#endif /* TARGET_OPENRISC */ + #ifdef TARGET_SH4 void cpu_loop(CPUSH4State *env) { @@ -3386,6 +3473,8 @@ int main(int argc, char **argv, char **envp) #else cpu_model = "24Kf"; #endif +#elif defined TARGET_OPENRISC + cpu_model = "or1200"; #elif defined(TARGET_PPC) #ifdef TARGET_PPC64 cpu_model = "970fx"; @@ -3788,6 +3877,17 @@ int main(int argc, char **argv, char **envp) env->hflags |= MIPS_HFLAG_M16; } } +#elif defined(TARGET_OPENRISC) + { + int i; + + for (i = 0; i < 32; i++) { + env->gpr[i] = regs->gpr[i]; + } + + env->sr = regs->sr; + env->pc = regs->pc; + } #elif defined(TARGET_SH4) { int i; diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h new file mode 100644 index 0000000000..bdbb577fc3 --- /dev/null +++ b/linux-user/openrisc/syscall.h @@ -0,0 +1,24 @@ +struct target_pt_regs { + union { + struct { + /* Named registers */ + uint32_t sr; /* Stored in place of r0 */ + target_ulong sp; /* r1 */ + }; + struct { + /* Old style */ + target_ulong offset[2]; + target_ulong gprs[30]; + }; + struct { + /* New style */ + target_ulong gpr[32]; + }; + }; + target_ulong pc; + target_ulong orig_gpr11; /* For restarting system calls */ + uint32_t syscallno; /* Syscall number (used by strace) */ + target_ulong dummy; /* Cheap alignment fix */ +}; + +#define UNAME_MACHINE "openrisc" diff --git a/linux-user/openrisc/syscall_nr.h b/linux-user/openrisc/syscall_nr.h new file mode 100644 index 0000000000..f4ac91ef71 --- /dev/null +++ b/linux-user/openrisc/syscall_nr.h @@ -0,0 +1,506 @@ +#define TARGET_NR_io_setup 0 +#define TARGET_NR_io_destroy 1 +#define TARGET_NR_io_submit 2 +#define TARGET_NR_io_cancel 3 +#define TARGET_NR_io_getevents 4 + +/* fs/xattr.c */ +#define TARGET_NR_setxattr 5 +#define TARGET_NR_lsetxattr 6 +#define TARGET_NR_fsetxattr 7 +#define TARGET_NR_getxattr 8 +#define TARGET_NR_lgetxattr 9 +#define TARGET_NR_fgetxattr 10 +#define TARGET_NR_listxattr 11 +#define TARGET_NR_llistxattr 12 +#define TARGET_NR_flistxattr 13 +#define TARGET_NR_removexattr 14 +#define TARGET_NR_lremovexattr 15 +#define TARGET_NR_fremovexattr 16 + +/* fs/dcache.c */ +#define TARGET_NR_getcwd 17 + +/* fs/cookies.c */ +#define TARGET_NR_lookup_dcookie 18 + +/* fs/eventfd.c */ +#define TARGET_NR_eventfd2 19 + +/* fs/eventpoll.c */ +#define TARGET_NR_epoll_create1 20 +#define TARGET_NR_epoll_ctl 21 +#define TARGET_NR_epoll_pwait 22 + +/* fs/fcntl.c */ +#define TARGET_NR_dup 23 +#define TARGET_NR_dup3 24 +#define TARGET_NR_3264_fcntl 25 + +/* fs/inotify_user.c */ +#define TARGET_NR_inotify_init1 26 +#define TARGET_NR_inotify_add_watch 27 +#define TARGET_NR_inotify_rm_watch 28 + +/* fs/ioctl.c */ +#define TARGET_NR_ioctl 29 + +/* fs/ioprio.c */ +#define TARGET_NR_ioprio_set 30 +#define TARGET_NR_ioprio_get 31 + +/* fs/locks.c */ +#define TARGET_NR_flock 32 + +/* fs/namei.c */ +#define TARGET_NR_mknodat 33 +#define TARGET_NR_mkdirat 34 +#define TARGET_NR_unlinkat 35 +#define TARGET_NR_symlinkat 36 +#define TARGET_NR_linkat 37 +#define TARGET_NR_renameat 38 + +/* fs/namespace.c */ +#define TARGET_NR_umount2 39 +#define TARGET_NR_mount 40 +#define TARGET_NR_pivot_root 41 + +/* fs/nfsctl.c */ +#define TARGET_NR_nfsservctl 42 + +/* fs/open.c */ +#define TARGET_NR_3264_statfs 43 +#define TARGET_NR_3264_fstatfs 44 +#define TARGET_NR_3264_truncate 45 +#define TARGET_NR_3264_ftruncate 46 + +#define TARGET_NR_fallocate 47 +#define TARGET_NR_faccessat 48 +#define TARGET_NR_chdir 49 +#define TARGET_NR_fchdir 50 +#define TARGET_NR_chroot 51 +#define TARGET_NR_fchmod 52 +#define TARGET_NR_fchmodat 53 +#define TARGET_NR_fchownat 54 +#define TARGET_NR_fchown 55 +#define TARGET_NR_openat 56 +#define TARGET_NR_close 57 +#define TARGET_NR_vhangup 58 + +/* fs/pipe.c */ +#define TARGET_NR_pipe2 59 + +/* fs/quota.c */ +#define TARGET_NR_quotactl 60 + +/* fs/readdir.c */ +#define TARGET_NR_getdents64 61 + +/* fs/read_write.c */ +#define TARGET_NR_3264_lseek 62 +#define TARGET_NR_read 63 +#define TARGET_NR_write 64 +#define TARGET_NR_readv 65 +#define TARGET_NR_writev 66 +#define TARGET_NR_pread64 67 +#define TARGET_NR_pwrite64 68 +#define TARGET_NR_preadv 69 +#define TARGET_NR_pwritev 70 + +/* fs/sendfile.c */ +#define TARGET_NR_3264_sendfile 71 + +/* fs/select.c */ +#define TARGET_NR_pselect6 72 +#define TARGET_NR_ppoll 73 + +/* fs/signalfd.c */ +#define TARGET_NR_signalfd4 74 + +/* fs/splice.c */ +#define TARGET_NR_vmsplice 75 +#define TARGET_NR_splice 76 +#define TARGET_NR_tee 77 + +/* fs/stat.c */ +#define TARGET_NR_readlinkat 78 +#define TARGET_NR_3264_fstatat 79 +#define TARGET_NR_3264_fstat 80 + +/* fs/sync.c */ +#define TARGET_NR_sync 81 +#define TARGET_NR_fsync 82 +#define TARGET_NR_fdatasync 83 + +#ifdef __ARCH_WANT_SYNC_FILE_RANGE2 +#define TARGET_NR_sync_file_range2 84 +#else +#define TARGET_NR_sync_file_range 84 +#endif + +/* fs/timerfd.c */ +#define TARGET_NR_timerfd_create 85 +#define TARGET_NR_timerfd_settime 86 +#define TARGET_NR_timerfd_gettime 87 + +/* fs/utimes.c */ +#define TARGET_NR_utimensat 88 + +/* kernel/acct.c */ +#define TARGET_NR_acct 89 + +/* kernel/capability.c */ +#define TARGET_NR_capget 90 +#define TARGET_NR_capset 91 + +/* kernel/exec_domain.c */ +#define TARGET_NR_personality 92 + +/* kernel/exit.c */ +#define TARGET_NR_exit 93 +#define TARGET_NR_exit_group 94 +#define TARGET_NR_waitid 95 + +/* kernel/fork.c */ +#define TARGET_NR_set_tid_address 96 +#define TARGET_NR_unshare 97 + +/* kernel/futex.c */ +#define TARGET_NR_futex 98 +#define TARGET_NR_set_robust_list 99 +#define TARGET_NR_get_robust_list 100 + +/* kernel/hrtimer.c */ +#define TARGET_NR_nanosleep 101 + +/* kernel/itimer.c */ +#define TARGET_NR_getitimer 102 +#define TARGET_NR_setitimer 103 + +/* kernel/kexec.c */ +#define TARGET_NR_kexec_load 104 + +/* kernel/module.c */ +#define TARGET_NR_init_module 105 +#define TARGET_NR_delete_module 106 + +/* kernel/posix-timers.c */ +#define TARGET_NR_timer_create 107 +#define TARGET_NR_timer_gettime 108 +#define TARGET_NR_timer_getoverrun 109 +#define TARGET_NR_timer_settime 110 +#define TARGET_NR_timer_delete 111 +#define TARGET_NR_clock_settime 112 +#define TARGET_NR_clock_gettime 113 +#define TARGET_NR_clock_getres 114 +#define TARGET_NR_clock_nanosleep 115 + +/* kernel/printk.c */ +#define TARGET_NR_syslog 116 + +/* kernel/ptrace.c */ +#define TARGET_NR_ptrace 117 + +/* kernel/sched.c */ +#define TARGET_NR_sched_setparam 118 +#define TARGET_NR_sched_setscheduler 119 +#define TARGET_NR_sched_getscheduler 120 +#define TARGET_NR_sched_getparam 121 +#define TARGET_NR_sched_setaffinity 122 +#define TARGET_NR_sched_getaffinity 123 +#define TARGET_NR_sched_yield 124 +#define TARGET_NR_sched_get_priority_max 125 +#define TARGET_NR_sched_get_priority_min 126 +#define TARGET_NR_sched_rr_get_interval 127 + +/* kernel/signal.c */ +#define TARGET_NR_restart_syscall 128 +#define TARGET_NR_kill 129 +#define TARGET_NR_tkill 130 +#define TARGET_NR_tgkill 131 +#define TARGET_NR_sigaltstack 132 +#define TARGET_NR_rt_sigsuspend 133 +#define TARGET_NR_rt_sigaction 134 +#define TARGET_NR_rt_sigprocmask 135 +#define TARGET_NR_rt_sigpending 136 +#define TARGET_NR_rt_sigtimedwait 137 +#define TARGET_NR_rt_sigqueueinfo 138 +#define TARGET_NR_rt_sigreturn 139 + +/* kernel/sys.c */ +#define TARGET_NR_setpriority 140 +#define TARGET_NR_getpriority 141 +#define TARGET_NR_reboot 142 +#define TARGET_NR_setregid 143 +#define TARGET_NR_setgid 144 +#define TARGET_NR_setreuid 145 +#define TARGET_NR_setuid 146 +#define TARGET_NR_setresuid 147 +#define TARGET_NR_getresuid 148 +#define TARGET_NR_setresgid 149 +#define TARGET_NR_getresgid 150 +#define TARGET_NR_setfsuid 151 +#define TARGET_NR_setfsgid 152 +#define TARGET_NR_times 153 +#define TARGET_NR_setpgid 154 +#define TARGET_NR_getpgid 155 +#define TARGET_NR_getsid 156 +#define TARGET_NR_setsid 157 +#define TARGET_NR_getgroups 158 +#define TARGET_NR_setgroups 159 +#define TARGET_NR_uname 160 +#define TARGET_NR_sethostname 161 +#define TARGET_NR_setdomainname 162 +#define TARGET_NR_getrlimit 163 +#define TARGET_NR_setrlimit 164 +#define TARGET_NR_getrusage 165 +#define TARGET_NR_umask 166 +#define TARGET_NR_prctl 167 +#define TARGET_NR_getcpu 168 + +/* kernel/time.c */ +#define TARGET_NR_gettimeofday 169 +#define TARGET_NR_settimeofday 170 +#define TARGET_NR_adjtimex 171 + +/* kernel/timer.c */ +#define TARGET_NR_getpid 172 +#define TARGET_NR_getppid 173 +#define TARGET_NR_getuid 174 +#define TARGET_NR_geteuid 175 +#define TARGET_NR_getgid 176 +#define TARGET_NR_getegid 177 +#define TARGET_NR_gettid 178 +#define TARGET_NR_sysinfo 179 + +/* ipc/mqueue.c */ +#define TARGET_NR_mq_open 180 +#define TARGET_NR_mq_unlink 181 +#define TARGET_NR_mq_timedsend 182 +#define TARGET_NR_mq_timedreceive 183 +#define TARGET_NR_mq_notify 184 +#define TARGET_NR_mq_getsetattr 185 + +/* ipc/msg.c */ +#define TARGET_NR_msgget 186 +#define TARGET_NR_msgctl 187 +#define TARGET_NR_msgrcv 188 +#define TARGET_NR_msgsnd 189 + +/* ipc/sem.c */ +#define TARGET_NR_semget 190 +#define TARGET_NR_semctl 191 +#define TARGET_NR_semtimedop 192 +#define TARGET_NR_semop 193 + +/* ipc/shm.c */ +#define TARGET_NR_shmget 194 +#define TARGET_NR_shmctl 195 +#define TARGET_NR_shmat 196 +#define TARGET_NR_shmdt 197 + +/* net/socket.c */ +#define TARGET_NR_socket 198 +#define TARGET_NR_socketpair 199 +#define TARGET_NR_bind 200 +#define TARGET_NR_listen 201 +#define TARGET_NR_accept 202 +#define TARGET_NR_connect 203 +#define TARGET_NR_getsockname 204 +#define TARGET_NR_getpeername 205 +#define TARGET_NR_sendto 206 +#define TARGET_NR_recvfrom 207 +#define TARGET_NR_setsockopt 208 +#define TARGET_NR_getsockopt 209 +#define TARGET_NR_shutdown 210 +#define TARGET_NR_sendmsg 211 +#define TARGET_NR_recvmsg 212 + +/* mm/filemap.c */ +#define TARGET_NR_readahead 213 + +/* mm/nommu.c, also with MMU */ +#define TARGET_NR_brk 214 +#define TARGET_NR_munmap 215 +#define TARGET_NR_mremap 216 + +/* security/keys/keyctl.c */ +#define TARGET_NR_add_key 217 +#define TARGET_NR_request_key 218 +#define TARGET_NR_keyctl 219 + +/* arch/example/kernel/sys_example.c */ +#define TARGET_NR_clone 220 +#define TARGET_NR_execve 221 + +#define TARGET_NR_3264_mmap 222 +/* mm/fadvise.c */ +#define TARGET_NR_3264_fadvise64 223 + +/* mm/, CONFIG_MMU only */ +#ifndef __ARCH_NOMMU +#define TARGET_NR_swapon 224 +#define TARGET_NR_swapoff 225 +#define TARGET_NR_mprotect 226 +#define TARGET_NR_msync 227 +#define TARGET_NR_mlock 228 +#define TARGET_NR_munlock 229 +#define TARGET_NR_mlockall 230 +#define TARGET_NR_munlockall 231 +#define TARGET_NR_mincore 232 +#define TARGET_NR_madvise 233 +#define TARGET_NR_remap_file_pages 234 +#define TARGET_NR_mbind 235 +#define TARGET_NR_get_mempolicy 236 +#define TARGET_NR_set_mempolicy 237 +#define TARGET_NR_migrate_pages 238 +#define TARGET_NR_move_pages 239 +#endif + +#define TARGET_NR_rt_tgsigqueueinfo 240 +#define TARGET_NR_perf_event_open 241 +#define TARGET_NR_accept4 242 +#define TARGET_NR_recvmmsg 243 + +/* + * Architectures may provide up to 16 syscalls of their own + * starting with this value. + */ +#define TARGET_NR_arch_specific_syscall 244 + +#define TARGET_NR_wait4 260 +#define TARGET_NR_prlimit64 261 +#define TARGET_NR_fanotify_init 262 +#define TARGET_NR_fanotify_mark 263 +#define TARGET_NR_name_to_handle_at 264 +#define TARGET_NR_open_by_handle_at 265 +#define TARGET_NR_clock_adjtime 266 +#define TARGET_NR_syncfs 267 +#define TARGET_NR_setns 268 +#define TARGET_NR_sendmmsg 269 + +#undef TARGET_NR_syscalls +#define TARGET_NR_syscalls 270 + +/* + * All syscalls below here should go away really, + * these are provided for both review and as a porting + * help for the C library version. +* + * Last chance: are any of these important enough to + * enable by default? + */ +#define TARGET_NR_open 1024 +#define TARGET_NR_link 1025 +#define TARGET_NR_unlink 1026 +#define TARGET_NR_mknod 1027 +#define TARGET_NR_chmod 1028 +#define TARGET_NR_chown 1029 +#define TARGET_NR_mkdir 1030 +#define TARGET_NR_rmdir 1031 +#define TARGET_NR_lchown 1032 +#define TARGET_NR_access 1033 +#define TARGET_NR_rename 1034 +#define TARGET_NR_readlink 1035 +#define TARGET_NR_symlink 1036 +#define TARGET_NR_utimes 1037 +#define TARGET_NR_3264_stat 1038 +#define TARGET_NR_3264_lstat 1039 + +#undef TARGET_NR_syscalls +#define TARGET_NR_syscalls (TARGET_NR_3264_lstat+1) + +#define TARGET_NR_pipe 1040 +#define TARGET_NR_dup2 1041 +#define TARGET_NR_epoll_create 1042 +#define TARGET_NR_inotify_init 1043 +#define TARGET_NR_eventfd 1044 +#define TARGET_NR_signalfd 1045 + +#undef TARGET_NR_syscalls +#define TARGET_NR_syscalls (TARGET_NR_signalfd+1) + + +#define TARGET_NR_sendfile 1046 +#define TARGET_NR_ftruncate 1047 +#define TARGET_NR_truncate 1048 +#define TARGET_NR_stat 1049 +#define TARGET_NR_lstat 1050 +#define TARGET_NR_fstat 1051 +#define TARGET_NR_fcntl 1052 +#define TARGET_NR_fadvise64 1053 +#define __ARCH_WANT_SYS_FADVISE64 +#define TARGET_NR_newfstatat 1054 +#define __ARCH_WANT_SYS_NEWFSTATAT +#define TARGET_NR_fstatfs 1055 +#define TARGET_NR_statfs 1056 +#define TARGET_NR_lseek 1057 +#define TARGET_NR_mmap 1058 + +#undef TARGET_NR_syscalls +#define TARGET_NR_syscalls (TARGET_NR_mmap+1) + +#define TARGET_NR_alarm 1059 +#define __ARCH_WANT_SYS_ALARM +#define TARGET_NR_getpgrp 1060 +#define __ARCH_WANT_SYS_GETPGRP +#define TARGET_NR_pause 1061 +#define __ARCH_WANT_SYS_PAUSE +#define TARGET_NR_time 1062 +#define __ARCH_WANT_SYS_TIME +#define __ARCH_WANT_COMPAT_SYS_TIME +#define TARGET_NR_utime 1063 +#define __ARCH_WANT_SYS_UTIME + +#define TARGET_NR_creat 1064 +#define TARGET_NR_getdents 1065 +#define __ARCH_WANT_SYS_GETDENTS +#define TARGET_NR_futimesat 1066 +#define TARGET_NR_select 1067 +#define __ARCH_WANT_SYS_SELECT +#define TARGET_NR_poll 1068 +#define TARGET_NR_epoll_wait 1069 +#define TARGET_NR_ustat 1070 +#define TARGET_NR_vfork 1071 +#define TARGET_NR_oldwait4 1072 +#define TARGET_NR_recv 1073 +#define TARGET_NR_send 1074 +#define TARGET_NR_bdflush 1075 +#define TARGET_NR_umount 1076 +#define __ARCH_WANT_SYS_OLDUMOUNT +#define TARGET_NR_uselib 1077 +#define TARGET_NR__sysctl 1078 + +#define TARGET_NR_fork 1079 + +#undef TARGET_NR_syscalls +#define TARGET_NR_syscalls (TARGET_NR_fork+1) + + +/* + * 32 bit systems traditionally used different + * syscalls for off_t and loff_t arguments, while + * 64 bit systems only need the off_t version. + * For new 32 bit platforms, there is no need to + * implement the old 32 bit off_t syscalls, so + * they take different names. + * Here we map the numbers so that both versions + * use the same syscall table layout. + */ + +#define TARGET_NR_fcntl64 TARGET_NR_3264_fcntl +#define TARGET_NR_statfs64 TARGET_NR_3264_statfs +#define TARGET_NR_fstatfs64 TARGET_NR_3264_fstatfs +#define TARGET_NR_truncate64 TARGET_NR_3264_truncate +#define TARGET_NR_ftruncate64 TARGET_NR_3264_ftruncate +#define TARGET_NR_llseek TARGET_NR_3264_lseek +#define TARGET_NR_sendfile64 TARGET_NR_3264_sendfile +#define TARGET_NR_fstatat64 TARGET_NR_3264_fstatat +#define TARGET_NR_fstat64 TARGET_NR_3264_fstat +#define TARGET_NR_mmap2 TARGET_NR_3264_mmap +#define TARGET_NR_fadvise64_64 TARGET_NR_3264_fadvise64 + +#ifdef TARGET_NR_3264_stat +#define TARGET_NR_stat64 TARGET_NR_3264_stat +#define TARGET_NR_lstat64 TARGET_NR_3264_lstat +#endif diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h new file mode 100644 index 0000000000..964aed69f1 --- /dev/null +++ b/linux-user/openrisc/target_signal.h @@ -0,0 +1,26 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + abi_long ss_sp; + abi_ulong ss_size; + abi_long ss_flags; +} target_stack_t; + +/* sigaltstack controls */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state) +{ + return state->gpr[1]; +} + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/openrisc/termbits.h b/linux-user/openrisc/termbits.h new file mode 100644 index 0000000000..373af77215 --- /dev/null +++ b/linux-user/openrisc/termbits.h @@ -0,0 +1,294 @@ +typedef unsigned char target_openrisc_cc; /*cc_t*/ +typedef unsigned int target_openrisc_speed; /*speed_t*/ +typedef unsigned int target_openrisc_tcflag; /*tcflag_t*/ + +#define TARGET_NCCS 19 +struct target_termios { + target_openrisc_tcflag c_iflag; /* input mode flags */ + target_openrisc_tcflag c_oflag; /* output mode flags */ + target_openrisc_tcflag c_cflag; /* control mode flags */ + target_openrisc_tcflag c_lflag; /* local mode flags */ + target_openrisc_cc c_line; /* line discipline */ + target_openrisc_cc c_cc[TARGET_NCCS]; /* control characters */ +}; + +struct target_termios2 { + target_openrisc_tcflag c_iflag; /* input mode flags */ + target_openrisc_tcflag c_oflag; /* output mode flags */ + target_openrisc_tcflag c_cflag; /* control mode flags */ + target_openrisc_tcflag c_lflag; /* local mode flags */ + target_openrisc_cc c_line; /* line discipline */ + target_openrisc_cc c_cc[TARGET_NCCS]; /* control characters */ + target_openrisc_speed c_ispeed; /* input speed */ + target_openrisc_speed c_ospeed; /* output speed */ +}; + +struct target_termios3 { + target_openrisc_tcflag c_iflag; /* input mode flags */ + target_openrisc_tcflag c_oflag; /* output mode flags */ + target_openrisc_tcflag c_cflag; /* control mode flags */ + target_openrisc_tcflag c_lflag; /* local mode flags */ + target_openrisc_cc c_line; /* line discipline */ + target_openrisc_cc c_cc[TARGET_NCCS]; /* control characters */ + target_openrisc_speed c_ispeed; /* input speed */ + target_openrisc_speed c_ospeed; /* output speed */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_BOTHER 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +#define TARGET_IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 +#define TARGET_EXTPROC 0200000 + +/* tcflow() and TCXONC use these */ +#define TARGET_TCOOFF 0 +#define TARGET_TCOON 1 +#define TARGET_TCIOFF 2 +#define TARGET_TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TARGET_TCIFLUSH 0 +#define TARGET_TCOFLUSH 1 +#define TARGET_TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TARGET_TCSANOW 0 +#define TARGET_TCSADRAIN 1 +#define TARGET_TCSAFLUSH 2 + +/* ioctls */ +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TCGETS2 TARGET_IOR('T', 0x2A, struct termios2) +#define TARGET_TCSETS2 TARGET_IOW('T', 0x2B, struct termios2) +#define TARGET_TCSETSW2 TARGET_IOW('T', 0x2C, struct termios2) +#define TARGET_TCSETSF2 TARGET_IOW('T', 0x2D, struct termios2) +#define TARGET_TIOCGRS485 0x542E +#ifndef TARGET_TIOCSRS485 +#define TARGET_TIOCSRS485 0x542F +#endif +/* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) +/* Lock/unlock Pty */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) +/* Get primary device node of /dev/console */ +#define TARGET_TIOCGDEV TARGET_IOR('T', 0x32, unsigned int) +#define TARGET_TCGETX 0x5432 /* SYS5 TCGETX compatibility */ +#define TARGET_TCSETX 0x5433 +#define TARGET_TCSETXF 0x5434 +#define TARGET_TCSETXW 0x5435 +/* pty: generate signal */ +#define TARGET_TIOCSIG TARGET_IOW('T', 0x36, int) +#define TARGET_TIOCVHANGUP 0x5437 + +#define TARGET_FIONCLEX 0x5450 +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +/* wait for a change on serial input line(s) */ +#define TARGET_TIOCMIWAIT 0x545C +/* read serial port inline interrupt counts */ +#define TARGET_TIOCGICOUNT 0x545D + +/* + * Some arches already define TARGET_FIOQSIZE due to a historical + * conflict with a Hayes modem-specific ioctl value. + */ +#ifndef TARGET_FIOQSIZE +#define TARGET_FIOQSIZE 0x5460 +#endif + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 +#define TARGET_TIOCPKT_IOCTL 64 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 43346dcbcc..97f30d9547 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -3629,6 +3629,235 @@ long do_rt_sigreturn(CPUCRISState *env) return -TARGET_ENOSYS; } +#elif defined(TARGET_OPENRISC) + +struct target_sigcontext { + struct target_pt_regs regs; + abi_ulong oldmask; + abi_ulong usp; +}; + +struct target_ucontext { + abi_ulong tuc_flags; + abi_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ +}; + +struct target_rt_sigframe { + abi_ulong pinfo; + uint64_t puc; + struct target_siginfo info; + struct target_sigcontext sc; + struct target_ucontext uc; + unsigned char retcode[16]; /* trampoline code */ +}; + +/* This is the asm-generic/ucontext.h version */ +#if 0 +static int restore_sigcontext(CPUOpenRISCState *regs, + struct target_sigcontext *sc) +{ + unsigned int err = 0; + unsigned long old_usp; + + /* Alwys make any pending restarted system call return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + /* restore the regs from &sc->regs (same as sc, since regs is first) + * (sc is already checked for VERIFY_READ since the sigframe was + * checked in sys_sigreturn previously) + */ + + if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) { + goto badframe; + } + + /* make sure the U-flag is set so user-mode cannot fool us */ + + regs->sr &= ~SR_SM; + + /* restore the old USP as it was before we stacked the sc etc. + * (we cannot just pop the sigcontext since we aligned the sp and + * stuff after pushing it) + */ + + err |= __get_user(old_usp, &sc->usp); + phx_signal("old_usp 0x%lx", old_usp); + + __PHX__ REALLY /* ??? */ + wrusp(old_usp); + regs->gpr[1] = old_usp; + + /* TODO: the other ports use regs->orig_XX to disable syscall checks + * after this completes, but we don't use that mechanism. maybe we can + * use it now ? + */ + + return err; + +badframe: + return 1; +} +#endif + +/* Set up a signal frame. */ + +static int setup_sigcontext(struct target_sigcontext *sc, + CPUOpenRISCState *regs, + unsigned long mask) +{ + int err = 0; + unsigned long usp = regs->gpr[1]; + + /* copy the regs. they are first in sc so we can use sc directly */ + + /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/ + + /* Set the frametype to CRIS_FRAME_NORMAL for the execution of + the signal handler. The frametype will be restored to its previous + value in restore_sigcontext. */ + /*regs->frametype = CRIS_FRAME_NORMAL;*/ + + /* then some other stuff */ + err |= __put_user(mask, &sc->oldmask); + err |= __put_user(usp, &sc->usp); return err; +} + +static inline unsigned long align_sigframe(unsigned long sp) +{ + unsigned long i; + i = sp & ~3UL; + return i; +} + +static inline abi_ulong get_sigframe(struct target_sigaction *ka, + CPUOpenRISCState *regs, + size_t frame_size) +{ + unsigned long sp = regs->gpr[1]; + int onsigstack = on_sig_stack(sp); + + /* redzone */ + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + + sp = align_sigframe(sp - frame_size); + + /* + * If we are on the alternate signal stack and would overflow it, don't. + * Return an always-bogus address instead so we will die with SIGSEGV. + */ + + if (onsigstack && !likely(on_sig_stack(sp))) { + return -1L; + } + + return sp; +} + +static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUOpenRISCState *env) +{ + qemu_log("Not implement.\n"); +} + +static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUOpenRISCState *env) +{ + int err = 0; + abi_ulong frame_addr; + unsigned long return_ip; + struct target_rt_sigframe *frame; + abi_ulong info_addr, uc_addr; + + frame_addr = get_sigframe(ka, env, sizeof *frame); + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + info_addr = frame_addr + offsetof(struct target_rt_sigframe, info); + err |= __put_user(info_addr, &frame->pinfo); + uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc); + err |= __put_user(uc_addr, &frame->puc); + + if (ka->sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + } + if (err) { + goto give_sigsegv; + } + + /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/ + err |= __put_user(0, &frame->uc.tuc_flags); + err |= __put_user(0, &frame->uc.tuc_link); + err |= __put_user(target_sigaltstack_used.ss_sp, + &frame->uc.tuc_stack.ss_sp); + err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags); + err |= __put_user(target_sigaltstack_used.ss_size, + &frame->uc.tuc_stack.ss_size); + err |= setup_sigcontext(&frame->sc, env, set->sig[0]); + + /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/ + + if (err) { + goto give_sigsegv; + } + + /* trampoline - the desired return ip is the retcode itself */ + return_ip = (unsigned long)&frame->retcode; + /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ + err |= __put_user(0xa960, (short *)(frame->retcode + 0)); + err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2)); + err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); + err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); + + if (err) { + goto give_sigsegv; + } + + /* TODO what is the current->exec_domain stuff and invmap ? */ + + /* Set up registers for signal handler */ + env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */ + env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */ + env->gpr[3] = (unsigned long)sig; /* arg 1: signo */ + env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */ + env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */ + + /* actually move the usp to reflect the stacked frame */ + env->gpr[1] = (unsigned long)frame; + + return; + +give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); + if (sig == TARGET_SIGSEGV) { + ka->_sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV); +} + +long do_sigreturn(CPUOpenRISCState *env) +{ + + qemu_log("do_sigreturn: not implemented\n"); + return -TARGET_ENOSYS; +} + +long do_rt_sigreturn(CPUOpenRISCState *env) +{ + qemu_log("do_rt_sigreturn: not implemented\n"); + return -TARGET_ENOSYS; +} +/* TARGET_OPENRISC */ + #elif defined(TARGET_S390X) #define __NUM_GPRS 16 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 539af3f94b..630a455276 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7377,7 +7377,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigaltstack: #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ - defined(TARGET_M68K) || defined(TARGET_S390X) + defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC) ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env)); break; #else diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index a79b67df49..cfece21b6d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -59,7 +59,7 @@ #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) \ - || defined(TARGET_S390X) + || defined(TARGET_S390X) || defined(TARGET_OPENRISC) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -323,7 +323,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \ || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \ || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) \ - || defined(TARGET_S390X) + || defined(TARGET_S390X) || defined(TARGET_OPENRISC) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -344,6 +344,14 @@ int do_sigaction(int sig, const struct target_sigaction *act, #if !defined(TARGET_ABI_MIPSN32) && !defined(TARGET_ABI_MIPSN64) #define TARGET_SA_RESTORER 0x04000000 /* Only for O32 */ #endif +#elif defined(TARGET_OPENRISC) +#define TARGET_SA_NOCLDSTOP 0x00000001 +#define TARGET_SA_NOCLDWAIT 0x00000002 +#define TARGET_SA_SIGINFO 0x00000004 +#define TARGET_SA_ONSTACK 0x08000000 +#define TARGET_SA_RESTART 0x10000000 +#define TARGET_SA_NODEFER 0x40000000 +#define TARGET_SA_RESETHAND 0x80000000 #elif defined(TARGET_ALPHA) #define TARGET_SA_ONSTACK 0x00000001 #define TARGET_SA_RESTART 0x00000002 @@ -448,6 +456,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, #else +/* OpenRISC Using the general signals */ #define TARGET_SIGHUP 1 #define TARGET_SIGINT 2 #define TARGET_SIGQUIT 3 @@ -1086,7 +1095,8 @@ struct target_winsize { #endif #if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \ - || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) + || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) \ + || defined(TARGET_OPENRISC) struct target_stat { unsigned short st_dev; unsigned short __pad1; @@ -1783,6 +1793,30 @@ struct target_stat { abi_long st_blocks; abi_ulong __unused[3]; }; +#elif defined(TARGET_OPENRISC) +struct target_stat { + abi_ulong st_dev; + abi_ulong st_ino; + abi_ulong st_nlink; + + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + abi_ulong st_rdev; + abi_long st_size; + abi_long st_blksize; + abi_long st_blocks; /* Number 512-byte blocks allocated. */ + + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + + abi_long __unused[3]; +}; #else #error unsupported CPU #endif @@ -941,13 +941,6 @@ static void do_info_cpu_stats(Monitor *mon) } #endif -#if defined(CONFIG_TRACE_SIMPLE) -static void do_info_trace(Monitor *mon) -{ - st_print_trace((FILE *)mon, &monitor_fprintf); -} -#endif - static void do_trace_print_events(Monitor *mon) { trace_print_events((FILE *)mon, &monitor_fprintf); @@ -2689,15 +2682,6 @@ static mon_cmd_t info_cmds[] = { .help = "show roms", .mhandler.info = do_info_roms, }, -#if defined(CONFIG_TRACE_SIMPLE) - { - .name = "trace", - .args_type = "", - .params = "", - .help = "show current contents of trace buffer", - .mhandler.info = do_info_trace, - }, -#endif { .name = "trace-events", .args_type = "", @@ -37,6 +37,9 @@ #include "qmp-commands.h" #include "hw/qdev.h" #include "iov.h" +#include "qapi-visit.h" +#include "qapi/opts-visitor.h" +#include "qapi/qapi-dealloc-visitor.h" /* Net bridge is currently not supported for W32. */ #if !defined(_WIN32) @@ -239,7 +242,7 @@ NICState *qemu_new_nic(NetClientInfo *info, VLANClientState *nc; NICState *nic; - assert(info->type == NET_CLIENT_TYPE_NIC); + assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC); assert(info->size >= sizeof(NICState)); nc = qemu_new_net_client(info, conf->vlan, conf->peer, model, name); @@ -282,7 +285,7 @@ static void qemu_free_vlan_client(VLANClientState *vc) void qemu_del_vlan_client(VLANClientState *vc) { /* If there is a peer NIC, delete and cleanup client, but do not free. */ - if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_TYPE_NIC) { + if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { NICState *nic = DO_UPCAST(NICState, nc, vc->peer); if (nic->peer_deleted) { return; @@ -298,7 +301,7 @@ void qemu_del_vlan_client(VLANClientState *vc) } /* If this is a peer NIC and peer has already been deleted, free it now. */ - if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_TYPE_NIC) { + if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { NICState *nic = DO_UPCAST(NICState, nc, vc); if (nic->peer_deleted) { qemu_free_vlan_client(vc->peer); @@ -341,14 +344,14 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) VLANState *vlan; QTAILQ_FOREACH(nc, &non_vlan_clients, next) { - if (nc->info->type == NET_CLIENT_TYPE_NIC) { + if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { func(DO_UPCAST(NICState, nc, nc), opaque); } } QTAILQ_FOREACH(vlan, &vlans, next) { QTAILQ_FOREACH(nc, &vlan->clients, next) { - if (nc->info->type == NET_CLIENT_TYPE_NIC) { + if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { func(DO_UPCAST(NICState, nc, nc), opaque); } } @@ -664,7 +667,7 @@ VLANClientState *qemu_find_netdev(const char *id) VLANClientState *vc; QTAILQ_FOREACH(vc, &non_vlan_clients, next) { - if (vc->info->type == NET_CLIENT_TYPE_NIC) + if (vc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) continue; if (!strcmp(vc->name, id)) { return vc; @@ -745,11 +748,15 @@ int net_handle_fd_param(Monitor *mon, const char *param) return fd; } -static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan) +static int net_init_nic(const NetClientOptions *opts, const char *name, + VLANState *vlan) { int idx; NICInfo *nd; - const char *netdev; + const NetLegacyNicOptions *nic; + + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_NIC); + nic = opts->nic; idx = nic_get_free_idx(); if (idx == -1 || nb_nics >= MAX_NICS) { @@ -761,10 +768,10 @@ static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan) memset(nd, 0, sizeof(*nd)); - if ((netdev = qemu_opt_get(opts, "netdev"))) { - nd->netdev = qemu_find_netdev(netdev); + if (nic->has_netdev) { + nd->netdev = qemu_find_netdev(nic->netdev); if (!nd->netdev) { - error_report("netdev '%s' not found", netdev); + error_report("netdev '%s' not found", nic->netdev); return -1; } } else { @@ -774,26 +781,28 @@ static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan) if (name) { nd->name = g_strdup(name); } - if (qemu_opt_get(opts, "model")) { - nd->model = g_strdup(qemu_opt_get(opts, "model")); + if (nic->has_model) { + nd->model = g_strdup(nic->model); } - if (qemu_opt_get(opts, "addr")) { - nd->devaddr = g_strdup(qemu_opt_get(opts, "addr")); + if (nic->has_addr) { + nd->devaddr = g_strdup(nic->addr); } - if (qemu_opt_get(opts, "macaddr") && - net_parse_macaddr(nd->macaddr.a, qemu_opt_get(opts, "macaddr")) < 0) { + if (nic->has_macaddr && + net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { error_report("invalid syntax for ethernet address"); return -1; } qemu_macaddr_default_if_unset(&nd->macaddr); - nd->nvectors = qemu_opt_get_number(opts, "vectors", - DEV_NVECTORS_UNSPECIFIED); - if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && - (nd->nvectors < 0 || nd->nvectors > 0x7ffffff)) { - error_report("invalid # of vectors: %d", nd->nvectors); - return -1; + if (nic->has_vectors) { + if (nic->vectors > 0x7ffffff) { + error_report("invalid # of vectors: %"PRIu32, nic->vectors); + return -1; + } + nd->nvectors = nic->vectors; + } else { + nd->nvectors = DEV_NVECTORS_UNSPECIFIED; } nd->used = 1; @@ -802,371 +811,128 @@ static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan) return idx; } -#define NET_COMMON_PARAMS_DESC \ - { \ - .name = "type", \ - .type = QEMU_OPT_STRING, \ - .help = "net client type (nic, tap etc.)", \ - }, { \ - .name = "vlan", \ - .type = QEMU_OPT_NUMBER, \ - .help = "vlan number", \ - }, { \ - .name = "name", \ - .type = QEMU_OPT_STRING, \ - .help = "identifier for monitor commands", \ - } - -typedef int (*net_client_init_func)(QemuOpts *opts, - const char *name, - VLANState *vlan); - -/* magic number, but compiler will warn if too small */ -#define NET_MAX_DESC 20 - -static const struct { - const char *type; - net_client_init_func init; - QemuOptDesc desc[NET_MAX_DESC]; -} net_client_types[NET_CLIENT_TYPE_MAX] = { - [NET_CLIENT_TYPE_NONE] = { - .type = "none", - .desc = { - NET_COMMON_PARAMS_DESC, - { /* end of list */ } - }, - }, - [NET_CLIENT_TYPE_NIC] = { - .type = "nic", - .init = net_init_nic, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "netdev", - .type = QEMU_OPT_STRING, - .help = "id of -netdev to connect to", - }, - { - .name = "macaddr", - .type = QEMU_OPT_STRING, - .help = "MAC address", - }, { - .name = "model", - .type = QEMU_OPT_STRING, - .help = "device model (e1000, rtl8139, virtio etc.)", - }, { - .name = "addr", - .type = QEMU_OPT_STRING, - .help = "PCI device address", - }, { - .name = "vectors", - .type = QEMU_OPT_NUMBER, - .help = "number of MSI-x vectors, 0 to disable MSI-X", - }, - { /* end of list */ } - }, - }, + +static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])( + const NetClientOptions *opts, + const char *name, + VLANState *vlan) = { + [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic, #ifdef CONFIG_SLIRP - [NET_CLIENT_TYPE_USER] = { - .type = "user", - .init = net_init_slirp, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "hostname", - .type = QEMU_OPT_STRING, - .help = "client hostname reported by the builtin DHCP server", - }, { - .name = "restrict", - .type = QEMU_OPT_STRING, - .help = "isolate the guest from the host (y|yes|n|no)", - }, { - .name = "ip", - .type = QEMU_OPT_STRING, - .help = "legacy parameter, use net= instead", - }, { - .name = "net", - .type = QEMU_OPT_STRING, - .help = "IP address and optional netmask", - }, { - .name = "host", - .type = QEMU_OPT_STRING, - .help = "guest-visible address of the host", - }, { - .name = "tftp", - .type = QEMU_OPT_STRING, - .help = "root directory of the built-in TFTP server", - }, { - .name = "bootfile", - .type = QEMU_OPT_STRING, - .help = "BOOTP filename, for use with tftp=", - }, { - .name = "dhcpstart", - .type = QEMU_OPT_STRING, - .help = "the first of the 16 IPs the built-in DHCP server can assign", - }, { - .name = "dns", - .type = QEMU_OPT_STRING, - .help = "guest-visible address of the virtual nameserver", - }, { - .name = "smb", - .type = QEMU_OPT_STRING, - .help = "root directory of the built-in SMB server", - }, { - .name = "smbserver", - .type = QEMU_OPT_STRING, - .help = "IP address of the built-in SMB server", - }, { - .name = "hostfwd", - .type = QEMU_OPT_STRING, - .help = "guest port number to forward incoming TCP or UDP connections", - }, { - .name = "guestfwd", - .type = QEMU_OPT_STRING, - .help = "IP address and port to forward guest TCP connections", - }, - { /* end of list */ } - }, - }, + [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp, #endif - [NET_CLIENT_TYPE_TAP] = { - .type = "tap", - .init = net_init_tap, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "ifname", - .type = QEMU_OPT_STRING, - .help = "interface name", - }, -#ifndef _WIN32 - { - .name = "fd", - .type = QEMU_OPT_STRING, - .help = "file descriptor of an already opened tap", - }, { - .name = "script", - .type = QEMU_OPT_STRING, - .help = "script to initialize the interface", - }, { - .name = "downscript", - .type = QEMU_OPT_STRING, - .help = "script to shut down the interface", - }, { -#ifdef CONFIG_NET_BRIDGE - .name = "helper", - .type = QEMU_OPT_STRING, - .help = "command to execute to configure bridge", - }, { -#endif - .name = "sndbuf", - .type = QEMU_OPT_SIZE, - .help = "send buffer limit" - }, { - .name = "vnet_hdr", - .type = QEMU_OPT_BOOL, - .help = "enable the IFF_VNET_HDR flag on the tap interface" - }, { - .name = "vhost", - .type = QEMU_OPT_BOOL, - .help = "enable vhost-net network accelerator", - }, { - .name = "vhostfd", - .type = QEMU_OPT_STRING, - .help = "file descriptor of an already opened vhost net device", - }, { - .name = "vhostforce", - .type = QEMU_OPT_BOOL, - .help = "force vhost on for non-MSIX virtio guests", - }, -#endif /* _WIN32 */ - { /* end of list */ } - }, - }, - [NET_CLIENT_TYPE_SOCKET] = { - .type = "socket", - .init = net_init_socket, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "fd", - .type = QEMU_OPT_STRING, - .help = "file descriptor of an already opened socket", - }, { - .name = "listen", - .type = QEMU_OPT_STRING, - .help = "port number, and optional hostname, to listen on", - }, { - .name = "connect", - .type = QEMU_OPT_STRING, - .help = "port number, and optional hostname, to connect to", - }, { - .name = "mcast", - .type = QEMU_OPT_STRING, - .help = "UDP multicast address and port number", - }, { - .name = "localaddr", - .type = QEMU_OPT_STRING, - .help = "source address and port for multicast and udp packets", - }, { - .name = "udp", - .type = QEMU_OPT_STRING, - .help = "UDP unicast address and port number", - }, - { /* end of list */ } - }, - }, + [NET_CLIENT_OPTIONS_KIND_TAP] = net_init_tap, + [NET_CLIENT_OPTIONS_KIND_SOCKET] = net_init_socket, #ifdef CONFIG_VDE - [NET_CLIENT_TYPE_VDE] = { - .type = "vde", - .init = net_init_vde, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "sock", - .type = QEMU_OPT_STRING, - .help = "socket path", - }, { - .name = "port", - .type = QEMU_OPT_NUMBER, - .help = "port number", - }, { - .name = "group", - .type = QEMU_OPT_STRING, - .help = "group owner of socket", - }, { - .name = "mode", - .type = QEMU_OPT_NUMBER, - .help = "permissions for socket", - }, - { /* end of list */ } - }, - }, + [NET_CLIENT_OPTIONS_KIND_VDE] = net_init_vde, #endif - [NET_CLIENT_TYPE_DUMP] = { - .type = "dump", - .init = net_init_dump, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "len", - .type = QEMU_OPT_SIZE, - .help = "per-packet size limit (64k default)", - }, { - .name = "file", - .type = QEMU_OPT_STRING, - .help = "dump file path (default is qemu-vlan0.pcap)", - }, - { /* end of list */ } - }, - }, + [NET_CLIENT_OPTIONS_KIND_DUMP] = net_init_dump, #ifdef CONFIG_NET_BRIDGE - [NET_CLIENT_TYPE_BRIDGE] = { - .type = "bridge", - .init = net_init_bridge, - .desc = { - NET_COMMON_PARAMS_DESC, - { - .name = "br", - .type = QEMU_OPT_STRING, - .help = "bridge name", - }, { - .name = "helper", - .type = QEMU_OPT_STRING, - .help = "command to execute to configure bridge", - }, - { /* end of list */ } - }, - }, -#endif /* CONFIG_NET_BRIDGE */ + [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge, +#endif }; -int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) + +static int net_client_init1(const void *object, int is_netdev, Error **errp) { + union { + const Netdev *netdev; + const NetLegacy *net; + } u; + const NetClientOptions *opts; const char *name; - const char *type; - int i; - - type = qemu_opt_get(opts, "type"); - if (!type) { - error_set(errp, QERR_MISSING_PARAMETER, "type"); - return -1; - } if (is_netdev) { - if (strcmp(type, "tap") != 0 && -#ifdef CONFIG_NET_BRIDGE - strcmp(type, "bridge") != 0 && -#endif + u.netdev = object; + opts = u.netdev->opts; + name = u.netdev->id; + + switch (opts->kind) { #ifdef CONFIG_SLIRP - strcmp(type, "user") != 0 && + case NET_CLIENT_OPTIONS_KIND_USER: #endif + case NET_CLIENT_OPTIONS_KIND_TAP: + case NET_CLIENT_OPTIONS_KIND_SOCKET: #ifdef CONFIG_VDE - strcmp(type, "vde") != 0 && + case NET_CLIENT_OPTIONS_KIND_VDE: +#endif +#ifdef CONFIG_NET_BRIDGE + case NET_CLIENT_OPTIONS_KIND_BRIDGE: #endif - strcmp(type, "socket") != 0) { + break; + + default: error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type", "a netdev backend type"); return -1; } + } else { + u.net = object; + opts = u.net->opts; + /* missing optional values have been initialized to "all bits zero" */ + name = u.net->has_id ? u.net->id : u.net->name; + } - if (qemu_opt_get(opts, "vlan")) { - error_set(errp, QERR_INVALID_PARAMETER, "vlan"); - return -1; - } - if (qemu_opt_get(opts, "name")) { - error_set(errp, QERR_INVALID_PARAMETER, "name"); - return -1; + if (net_client_init_fun[opts->kind]) { + VLANState *vlan = NULL; + + /* Do not add to a vlan if it's a -netdev or a nic with a netdev= + * parameter. */ + if (!is_netdev && + (opts->kind != NET_CLIENT_OPTIONS_KIND_NIC || + !opts->nic->has_netdev)) { + vlan = qemu_find_vlan(u.net->has_vlan ? u.net->vlan : 0, true); } - if (!qemu_opts_id(opts)) { - error_set(errp, QERR_MISSING_PARAMETER, "id"); + + if (net_client_init_fun[opts->kind](opts, name, vlan) < 0) { + /* TODO push error reporting into init() methods */ + error_set(errp, QERR_DEVICE_INIT_FAILED, + NetClientOptionsKind_lookup[opts->kind]); return -1; } } + return 0; +} + - name = qemu_opts_id(opts); - if (!name) { - name = qemu_opt_get(opts, "name"); +static void net_visit(Visitor *v, int is_netdev, void **object, Error **errp) +{ + if (is_netdev) { + visit_type_Netdev(v, (Netdev **)object, NULL, errp); + } else { + visit_type_NetLegacy(v, (NetLegacy **)object, NULL, errp); } +} - for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) { - if (net_client_types[i].type != NULL && - !strcmp(net_client_types[i].type, type)) { - Error *local_err = NULL; - VLANState *vlan = NULL; - int ret; - qemu_opts_validate(opts, &net_client_types[i].desc[0], &local_err); - if (error_is_set(&local_err)) { - error_propagate(errp, local_err); - return -1; - } +int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) +{ + void *object = NULL; + Error *err = NULL; + int ret = -1; - /* Do not add to a vlan if it's a -netdev or a nic with a - * netdev= parameter. */ - if (!(is_netdev || - (strcmp(type, "nic") == 0 && qemu_opt_get(opts, "netdev")))) { - vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1); - } + { + OptsVisitor *ov = opts_visitor_new(opts); - ret = 0; - if (net_client_types[i].init) { - ret = net_client_types[i].init(opts, name, vlan); - if (ret < 0) { - /* TODO push error reporting into init() methods */ - error_set(errp, QERR_DEVICE_INIT_FAILED, type); - return -1; - } - } - return ret; - } + net_visit(opts_get_visitor(ov), is_netdev, &object, &err); + opts_visitor_cleanup(ov); } - error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a network client type"); - return -1; + if (!err) { + ret = net_client_init1(object, is_netdev, &err); + } + + if (object) { + QapiDeallocVisitor *dv = qapi_dealloc_visitor_new(); + + net_visit(qapi_dealloc_get_visitor(dv), is_netdev, &object, NULL); + qapi_dealloc_visitor_cleanup(dv); + } + + error_propagate(errp, err); + return ret; } + static int net_host_check_device(const char *device) { int i; @@ -1286,14 +1052,14 @@ void qmp_netdev_del(const char *id, Error **errp) static void print_net_client(Monitor *mon, VLANClientState *vc) { monitor_printf(mon, "%s: type=%s,%s\n", vc->name, - net_client_types[vc->info->type].type, vc->info_str); + NetClientOptionsKind_lookup[vc->info->type], vc->info_str); } void do_info_network(Monitor *mon) { VLANState *vlan; VLANClientState *vc, *peer; - net_client_type type; + NetClientOptionsKind type; QTAILQ_FOREACH(vlan, &vlans, next) { monitor_printf(mon, "VLAN %d devices:\n", vlan->id); @@ -1307,11 +1073,11 @@ void do_info_network(Monitor *mon) QTAILQ_FOREACH(vc, &non_vlan_clients, next) { peer = vc->peer; type = vc->info->type; - if (!peer || type == NET_CLIENT_TYPE_NIC) { + if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) { monitor_printf(mon, " "); print_net_client(mon, vc); } /* else it's a netdev connected to a NIC, printed with the NIC */ - if (peer && type == NET_CLIENT_TYPE_NIC) { + if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) { monitor_printf(mon, " \\ "); print_net_client(mon, peer); } @@ -1399,13 +1165,13 @@ void net_check_clients(void) QTAILQ_FOREACH(vc, &vlan->clients, next) { switch (vc->info->type) { - case NET_CLIENT_TYPE_NIC: + case NET_CLIENT_OPTIONS_KIND_NIC: has_nic = 1; break; - case NET_CLIENT_TYPE_USER: - case NET_CLIENT_TYPE_TAP: - case NET_CLIENT_TYPE_SOCKET: - case NET_CLIENT_TYPE_VDE: + case NET_CLIENT_OPTIONS_KIND_USER: + case NET_CLIENT_OPTIONS_KIND_TAP: + case NET_CLIENT_OPTIONS_KIND_SOCKET: + case NET_CLIENT_OPTIONS_KIND_VDE: has_host_dev = 1; break; default: ; @@ -1421,7 +1187,7 @@ void net_check_clients(void) QTAILQ_FOREACH(vc, &non_vlan_clients, next) { if (!vc->peer) { fprintf(stderr, "Warning: %s %s has no peer\n", - vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev", + vc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ? "nic" : "netdev", vc->name); } } @@ -7,6 +7,7 @@ #include "qemu-option.h" #include "net/queue.h" #include "vmstate.h" +#include "qapi-types.h" struct MACAddr { uint8_t a[6]; @@ -29,19 +30,6 @@ typedef struct NICConf { /* VLANs support */ -typedef enum { - NET_CLIENT_TYPE_NONE, - NET_CLIENT_TYPE_NIC, - NET_CLIENT_TYPE_USER, - NET_CLIENT_TYPE_TAP, - NET_CLIENT_TYPE_SOCKET, - NET_CLIENT_TYPE_VDE, - NET_CLIENT_TYPE_DUMP, - NET_CLIENT_TYPE_BRIDGE, - - NET_CLIENT_TYPE_MAX -} net_client_type; - typedef void (NetPoll)(VLANClientState *, bool enable); typedef int (NetCanReceive)(VLANClientState *); typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t); @@ -50,7 +38,7 @@ typedef void (NetCleanup) (VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *); typedef struct NetClientInfo { - net_client_type type; + NetClientOptionsKind type; size_t size; NetReceive *receive; NetReceive *receive_raw; diff --git a/net/dump.c b/net/dump.c index f835c51187..b575430787 100644 --- a/net/dump.c +++ b/net/dump.c @@ -93,7 +93,7 @@ static void dump_cleanup(VLANClientState *nc) } static NetClientInfo net_dump_info = { - .type = NET_CLIENT_TYPE_DUMP, + .type = NET_CLIENT_OPTIONS_KIND_DUMP, .size = sizeof(DumpState), .receive = dump_receive, .cleanup = dump_cleanup, @@ -144,21 +144,35 @@ static int net_dump_init(VLANState *vlan, const char *device, return 0; } -int net_init_dump(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_dump(const NetClientOptions *opts, const char *name, + VLANState *vlan) { int len; const char *file; char def_file[128]; + const NetdevDumpOptions *dump; + + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP); + dump = opts->dump; assert(vlan); - file = qemu_opt_get(opts, "file"); - if (!file) { + if (dump->has_file) { + file = dump->file; + } else { snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", vlan->id); file = def_file; } - len = qemu_opt_get_size(opts, "len", 65536); + if (dump->has_len) { + if (dump->len > INT_MAX) { + error_report("invalid length: %"PRIu64, dump->len); + return -1; + } + len = dump->len; + } else { + len = 65536; + } return net_dump_init(vlan, "dump", name, file, len); } diff --git a/net/dump.h b/net/dump.h index 2b5d9ba644..0fa2dd72ca 100644 --- a/net/dump.h +++ b/net/dump.h @@ -25,8 +25,9 @@ #define QEMU_NET_DUMP_H #include "net.h" -#include "qemu-common.h" +#include "qapi-types.h" -int net_init_dump(QemuOpts *opts, const char *name, VLANState *vlan); +int net_init_dump(const NetClientOptions *opts, const char *name, + VLANState *vlan); #endif /* QEMU_NET_DUMP_H */ diff --git a/net/slirp.c b/net/slirp.c index b82eab0a07..5c2e6b2cec 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -129,7 +129,7 @@ static void net_slirp_cleanup(VLANClientState *nc) } static NetClientInfo net_slirp_info = { - .type = NET_CLIENT_TYPE_USER, + .type = NET_CLIENT_OPTIONS_KIND_USER, .size = sizeof(SlirpState), .receive = net_slirp_receive, .cleanup = net_slirp_cleanup, @@ -686,88 +686,46 @@ void do_info_usernet(Monitor *mon) } } -static int net_init_slirp_configs(const char *name, const char *value, void *opaque) +static void +net_init_slirp_configs(const StringList *fwd, int flags) { - struct slirp_config_str *config; - - if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { - return 0; - } - - config = g_malloc0(sizeof(*config)); + while (fwd) { + struct slirp_config_str *config; - pstrcpy(config->str, sizeof(config->str), value); + config = g_malloc0(sizeof(*config)); + pstrcpy(config->str, sizeof(config->str), fwd->value->str); + config->flags = flags; + config->next = slirp_configs; + slirp_configs = config; - if (!strcmp(name, "hostfwd")) { - config->flags = SLIRP_CFG_HOSTFWD; + fwd = fwd->next; } - - config->next = slirp_configs; - slirp_configs = config; - - return 0; } -int net_init_slirp(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_slirp(const NetClientOptions *opts, const char *name, + VLANState *vlan) { struct slirp_config_str *config; - const char *vhost; - const char *vhostname; - const char *vdhcp_start; - const char *vnamesrv; - const char *tftp_export; - const char *bootfile; - const char *smb_export; - const char *vsmbsrv; - const char *restrict_opt; - char *vnet = NULL; - int restricted = 0; + char *vnet; int ret; + const NetdevUserOptions *user; - vhost = qemu_opt_get(opts, "host"); - vhostname = qemu_opt_get(opts, "hostname"); - vdhcp_start = qemu_opt_get(opts, "dhcpstart"); - vnamesrv = qemu_opt_get(opts, "dns"); - tftp_export = qemu_opt_get(opts, "tftp"); - bootfile = qemu_opt_get(opts, "bootfile"); - smb_export = qemu_opt_get(opts, "smb"); - vsmbsrv = qemu_opt_get(opts, "smbserver"); - - restrict_opt = qemu_opt_get(opts, "restrict"); - if (restrict_opt) { - if (!strcmp(restrict_opt, "on") || - !strcmp(restrict_opt, "yes") || !strcmp(restrict_opt, "y")) { - restricted = 1; - } else if (strcmp(restrict_opt, "off") && - strcmp(restrict_opt, "no") && strcmp(restrict_opt, "n")) { - error_report("invalid option: 'restrict=%s'", restrict_opt); - return -1; - } - } - - if (qemu_opt_get(opts, "ip")) { - const char *ip = qemu_opt_get(opts, "ip"); - int l = strlen(ip) + strlen("/24") + 1; + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_USER); + user = opts->user; - vnet = g_malloc(l); + vnet = user->has_net ? g_strdup(user->net) : + user->has_ip ? g_strdup_printf("%s/24", user->ip) : + NULL; - /* emulate legacy ip= parameter */ - pstrcpy(vnet, l, ip); - pstrcat(vnet, l, "/24"); - } - - if (qemu_opt_get(opts, "net")) { - if (vnet) { - g_free(vnet); - } - vnet = g_strdup(qemu_opt_get(opts, "net")); - } + /* all optional fields are initialized to "all bits zero" */ - qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); + net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD); + net_init_slirp_configs(user->guestfwd, 0); - ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, - vhostname, tftp_export, bootfile, vdhcp_start, - vnamesrv, smb_export, vsmbsrv); + ret = net_slirp_init(vlan, "user", name, user->restrict, vnet, user->host, + user->hostname, user->tftp, user->bootfile, + user->dhcpstart, user->dns, user->smb, + user->smbserver); while (slirp_configs) { config = slirp_configs; diff --git a/net/slirp.h b/net/slirp.h index 53fe95dc12..e2c71eeca0 100644 --- a/net/slirp.h +++ b/net/slirp.h @@ -27,10 +27,12 @@ #include "qemu-common.h" #include "qdict.h" #include "qemu-option.h" +#include "qapi-types.h" #ifdef CONFIG_SLIRP -int net_init_slirp(QemuOpts *opts, const char *name, VLANState *vlan); +int net_init_slirp(const NetClientOptions *opts, const char *name, + VLANState *vlan); void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); diff --git a/net/socket.c b/net/socket.c index fcd0a3c162..600c287d79 100644 --- a/net/socket.c +++ b/net/socket.c @@ -239,7 +239,7 @@ static void net_socket_cleanup(VLANClientState *nc) } static NetClientInfo net_dgram_socket_info = { - .type = NET_CLIENT_TYPE_SOCKET, + .type = NET_CLIENT_OPTIONS_KIND_SOCKET, .size = sizeof(NetSocketState), .receive = net_socket_receive_dgram, .cleanup = net_socket_cleanup, @@ -317,7 +317,7 @@ static void net_socket_connect(void *opaque) } static NetClientInfo net_socket_info = { - .type = NET_CLIENT_TYPE_SOCKET, + .type = NET_CLIENT_OPTIONS_KIND_SOCKET, .size = sizeof(NetSocketState), .receive = net_socket_receive, .cleanup = net_socket_cleanup, @@ -586,100 +586,68 @@ static int net_socket_udp_init(VLANState *vlan, return 0; } -int net_init_socket(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_socket(const NetClientOptions *opts, const char *name, + VLANState *vlan) { - if (qemu_opt_get(opts, "fd")) { - int fd; + const NetdevSocketOptions *sock; - if (qemu_opt_get(opts, "listen") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "mcast") || - qemu_opt_get(opts, "localaddr")) { - error_report("listen=, connect=, mcast= and localaddr= is invalid with fd="); - return -1; - } + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_SOCKET); + sock = opts->socket; - fd = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "fd")); - if (fd == -1) { - return -1; - } + if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + + sock->has_udp != 1) { + error_report("exactly one of fd=, listen=, connect=, mcast= or udp=" + " is required"); + return -1; + } - if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) { - return -1; - } - } else if (qemu_opt_get(opts, "listen")) { - const char *listen; - - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "mcast") || - qemu_opt_get(opts, "localaddr")) { - error_report("fd=, connect=, mcast= and localaddr= is invalid with listen="); - return -1; - } + if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) { + error_report("localaddr= is only valid with mcast= or udp="); + return -1; + } - listen = qemu_opt_get(opts, "listen"); + if (sock->has_fd) { + int fd; - if (net_socket_listen_init(vlan, "socket", name, listen) == -1) { - return -1; - } - } else if (qemu_opt_get(opts, "connect")) { - const char *connect; - - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "listen") || - qemu_opt_get(opts, "mcast") || - qemu_opt_get(opts, "localaddr")) { - error_report("fd=, listen=, mcast= and localaddr= is invalid with connect="); + fd = net_handle_fd_param(cur_mon, sock->fd); + if (fd == -1 || !net_socket_fd_init(vlan, "socket", name, fd, 1)) { return -1; } + return 0; + } - connect = qemu_opt_get(opts, "connect"); - - if (net_socket_connect_init(vlan, "socket", name, connect) == -1) { + if (sock->has_listen) { + if (net_socket_listen_init(vlan, "socket", name, sock->listen) == -1) { return -1; } - } else if (qemu_opt_get(opts, "mcast")) { - const char *mcast, *localaddr; + return 0; + } - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "listen")) { - error_report("fd=, connect= and listen= is invalid with mcast="); + if (sock->has_connect) { + if (net_socket_connect_init(vlan, "socket", name, sock->connect) == + -1) { return -1; } + return 0; + } - mcast = qemu_opt_get(opts, "mcast"); - localaddr = qemu_opt_get(opts, "localaddr"); - - if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) { - return -1; - } - } else if (qemu_opt_get(opts, "udp")) { - const char *udp, *localaddr; - - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "listen") || - qemu_opt_get(opts, "mcast")) { - error_report("fd=, connect=, listen=" - " and mcast= is invalid with udp="); + if (sock->has_mcast) { + /* if sock->localaddr is missing, it has been initialized to "all bits + * zero" */ + if (net_socket_mcast_init(vlan, "socket", name, sock->mcast, + sock->localaddr) == -1) { return -1; } + return 0; + } - udp = qemu_opt_get(opts, "udp"); - localaddr = qemu_opt_get(opts, "localaddr"); - if (localaddr == NULL) { - error_report("localaddr= is mandatory with udp="); - return -1; - } - - if (net_socket_udp_init(vlan, "udp", name, udp, localaddr) == -1) { - return -1; - } - } else { - error_report("-socket requires fd=, listen=," - " connect=, mcast= or udp="); + assert(sock->has_udp); + if (!sock->has_localaddr) { + error_report("localaddr= is mandatory with udp="); + return -1; + } + if (net_socket_udp_init(vlan, "udp", name, sock->udp, sock->localaddr) == + -1) { return -1; } return 0; diff --git a/net/socket.h b/net/socket.h index e1fe959412..c4809ad0d9 100644 --- a/net/socket.h +++ b/net/socket.h @@ -25,8 +25,9 @@ #define QEMU_NET_SOCKET_H #include "net.h" -#include "qemu-common.h" +#include "qapi-types.h" -int net_init_socket(QemuOpts *opts, const char *name, VLANState *vlan); +int net_init_socket(const NetClientOptions *opts, const char *name, + VLANState *vlan); #endif /* QEMU_NET_SOCKET_H */ diff --git a/net/tap-aix.c b/net/tap-aix.c index e19aaba110..f27c17729e 100644 --- a/net/tap-aix.c +++ b/net/tap-aix.c @@ -31,7 +31,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required return -1; } -int tap_set_sndbuf(int fd, QemuOpts *opts) +int tap_set_sndbuf(int fd, const NetdevTapOptions *tap) { return 0; } diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 937a94b11f..a3b717dd1c 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -117,7 +117,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required return fd; } -int tap_set_sndbuf(int fd, QemuOpts *opts) +int tap_set_sndbuf(int fd, const NetdevTapOptions *tap) { return 0; } diff --git a/net/tap-haiku.c b/net/tap-haiku.c index 91dda8ebc0..34739d1562 100644 --- a/net/tap-haiku.c +++ b/net/tap-haiku.c @@ -31,7 +31,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required return -1; } -int tap_set_sndbuf(int fd, QemuOpts *opts) +int tap_set_sndbuf(int fd, const NetdevTapOptions *tap) { return 0; } diff --git a/net/tap-linux.c b/net/tap-linux.c index 41d581b734..c6521bec34 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -98,16 +98,19 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required */ #define TAP_DEFAULT_SNDBUF 0 -int tap_set_sndbuf(int fd, QemuOpts *opts) +int tap_set_sndbuf(int fd, const NetdevTapOptions *tap) { int sndbuf; - sndbuf = qemu_opt_get_size(opts, "sndbuf", TAP_DEFAULT_SNDBUF); + sndbuf = !tap->has_sndbuf ? TAP_DEFAULT_SNDBUF : + tap->sndbuf > INT_MAX ? INT_MAX : + tap->sndbuf; + if (!sndbuf) { sndbuf = INT_MAX; } - if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && qemu_opt_get(opts, "sndbuf")) { + if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && tap->has_sndbuf) { error_report("TUNSETSNDBUF ioctl failed: %s", strerror(errno)); return -1; } diff --git a/net/tap-solaris.c b/net/tap-solaris.c index cf764634ef..5d6ac42f24 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -197,7 +197,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required return fd; } -int tap_set_sndbuf(int fd, QemuOpts *opts) +int tap_set_sndbuf(int fd, const NetdevTapOptions *tap) { return 0; } diff --git a/net/tap-win32.c b/net/tap-win32.c index a801a553c4..232807236a 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -667,7 +667,7 @@ static void tap_win32_send(void *opaque) } static NetClientInfo net_tap_win32_info = { - .type = NET_CLIENT_TYPE_TAP, + .type = NET_CLIENT_OPTIONS_KIND_TAP, .size = sizeof(TAPState), .receive = tap_receive, .cleanup = tap_cleanup, @@ -699,18 +699,20 @@ static int tap_win32_init(VLANState *vlan, const char *model, return 0; } -int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_tap(const NetClientOptions *opts, const char *name, + VLANState *vlan) { - const char *ifname; + const NetdevTapOptions *tap; - ifname = qemu_opt_get(opts, "ifname"); + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP); + tap = opts->tap; - if (!ifname) { + if (!tap->has_ifname) { error_report("tap: no interface name"); return -1; } - if (tap_win32_init(vlan, "tap", name, ifname) == -1) { + if (tap_win32_init(vlan, "tap", name, tap->ifname) == -1) { return -1; } @@ -218,7 +218,7 @@ int tap_has_ufo(VLANClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); return s->has_ufo; } @@ -227,7 +227,7 @@ int tap_has_vnet_hdr(VLANClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); return !!s->host_vnet_hdr_len; } @@ -236,7 +236,7 @@ int tap_has_vnet_hdr_len(VLANClientState *nc, int len) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); return tap_probe_vnet_hdr_len(s->fd, len); } @@ -245,7 +245,7 @@ void tap_set_vnet_hdr_len(VLANClientState *nc, int len) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) || len == sizeof(struct virtio_net_hdr)); @@ -259,7 +259,7 @@ void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr) using_vnet_hdr = using_vnet_hdr != 0; - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); assert(!!s->host_vnet_hdr_len == using_vnet_hdr); s->using_vnet_hdr = using_vnet_hdr; @@ -306,14 +306,14 @@ static void tap_poll(VLANClientState *nc, bool enable) int tap_get_fd(VLANClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); return s->fd; } /* fd support */ static NetClientInfo net_tap_info = { - .type = NET_CLIENT_TYPE_TAP, + .type = NET_CLIENT_OPTIONS_KIND_TAP, .size = sizeof(TAPState), .receive = tap_receive, .receive_raw = tap_receive_raw, @@ -513,20 +513,22 @@ static int net_bridge_run_helper(const char *helper, const char *bridge) return -1; } -int net_init_bridge(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_bridge(const NetClientOptions *opts, const char *name, + VLANState *vlan) { + const NetdevBridgeOptions *bridge; + const char *helper, *br; + TAPState *s; int fd, vnet_hdr; - if (!qemu_opt_get(opts, "br")) { - qemu_opt_set(opts, "br", DEFAULT_BRIDGE_INTERFACE); - } - if (!qemu_opt_get(opts, "helper")) { - qemu_opt_set(opts, "helper", DEFAULT_BRIDGE_HELPER); - } + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_BRIDGE); + bridge = opts->bridge; - fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"), - qemu_opt_get(opts, "br")); + helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER; + br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE; + + fd = net_bridge_run_helper(helper, br); if (fd == -1) { return -1; } @@ -541,35 +543,38 @@ int net_init_bridge(QemuOpts *opts, const char *name, VLANState *vlan) return -1; } - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", - qemu_opt_get(opts, "helper"), qemu_opt_get(opts, "br")); + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, + br); return 0; } -static int net_tap_init(QemuOpts *opts, int *vnet_hdr) +static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, + const char *setup_script, char *ifname, + size_t ifname_sz) { int fd, vnet_hdr_required; - char ifname[128] = {0,}; - const char *setup_script; - if (qemu_opt_get(opts, "ifname")) { - pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname")); + if (tap->has_ifname) { + pstrcpy(ifname, ifname_sz, tap->ifname); + } else { + assert(ifname_sz > 0); + ifname[0] = '\0'; } - *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1); - if (qemu_opt_get(opts, "vnet_hdr")) { + if (tap->has_vnet_hdr) { + *vnet_hdr = tap->vnet_hdr; vnet_hdr_required = *vnet_hdr; } else { + *vnet_hdr = 1; vnet_hdr_required = 0; } - TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required)); + TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required)); if (fd < 0) { return -1; } - setup_script = qemu_opt_get(opts, "script"); if (setup_script && setup_script[0] != '\0' && strcmp(setup_script, "no") != 0 && @@ -578,29 +583,34 @@ static int net_tap_init(QemuOpts *opts, int *vnet_hdr) return -1; } - qemu_opt_set(opts, "ifname", ifname); - return fd; } -int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_tap(const NetClientOptions *opts, const char *name, + VLANState *vlan) { - TAPState *s; + const NetdevTapOptions *tap; + int fd, vnet_hdr = 0; const char *model; + TAPState *s; - if (qemu_opt_get(opts, "fd")) { - if (qemu_opt_get(opts, "ifname") || - qemu_opt_get(opts, "script") || - qemu_opt_get(opts, "downscript") || - qemu_opt_get(opts, "vnet_hdr") || - qemu_opt_get(opts, "helper")) { + /* for the no-fd, no-helper case */ + const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */ + char ifname[128]; + + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP); + tap = opts->tap; + + if (tap->has_fd) { + if (tap->has_ifname || tap->has_script || tap->has_downscript || + tap->has_vnet_hdr || tap->has_helper) { error_report("ifname=, script=, downscript=, vnet_hdr=, " "and helper= are invalid with fd="); return -1; } - fd = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "fd")); + fd = net_handle_fd_param(cur_mon, tap->fd); if (fd == -1) { return -1; } @@ -611,18 +621,15 @@ int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) model = "tap"; - } else if (qemu_opt_get(opts, "helper")) { - if (qemu_opt_get(opts, "ifname") || - qemu_opt_get(opts, "script") || - qemu_opt_get(opts, "downscript") || - qemu_opt_get(opts, "vnet_hdr")) { + } else if (tap->has_helper) { + if (tap->has_ifname || tap->has_script || tap->has_downscript || + tap->has_vnet_hdr) { error_report("ifname=, script=, downscript=, and vnet_hdr= " "are invalid with helper="); return -1; } - fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"), - DEFAULT_BRIDGE_INTERFACE); + fd = net_bridge_run_helper(tap->helper, DEFAULT_BRIDGE_INTERFACE); if (fd == -1) { return -1; } @@ -634,15 +641,8 @@ int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) model = "bridge"; } else { - if (!qemu_opt_get(opts, "script")) { - qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT); - } - - if (!qemu_opt_get(opts, "downscript")) { - qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT); - } - - fd = net_tap_init(opts, &vnet_hdr); + script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT; + fd = net_tap_init(tap, &vnet_hdr, script, ifname, sizeof ifname); if (fd == -1) { return -1; } @@ -656,25 +656,24 @@ int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) return -1; } - if (tap_set_sndbuf(s->fd, opts) < 0) { + if (tap_set_sndbuf(s->fd, tap) < 0) { return -1; } - if (qemu_opt_get(opts, "fd")) { + if (tap->has_fd) { snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); - } else if (qemu_opt_get(opts, "helper")) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "helper=%s", qemu_opt_get(opts, "helper")); + } else if (tap->has_helper) { + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", + tap->helper); } else { - const char *ifname, *script, *downscript; + const char *downscript; - ifname = qemu_opt_get(opts, "ifname"); - script = qemu_opt_get(opts, "script"); - downscript = qemu_opt_get(opts, "downscript"); + downscript = tap->has_downscript ? tap->downscript : + DEFAULT_NETWORK_DOWN_SCRIPT; snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "ifname=%s,script=%s,downscript=%s", - ifname, script, downscript); + "ifname=%s,script=%s,downscript=%s", ifname, script, + downscript); if (strcmp(downscript, "no") != 0) { snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); @@ -682,25 +681,26 @@ int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) } } - if (qemu_opt_get_bool(opts, "vhost", !!qemu_opt_get(opts, "vhostfd") || - qemu_opt_get_bool(opts, "vhostforce", false))) { - int vhostfd, r; - bool force = qemu_opt_get_bool(opts, "vhostforce", false); - if (qemu_opt_get(opts, "vhostfd")) { - r = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "vhostfd")); - if (r == -1) { + if (tap->has_vhost ? tap->vhost : + tap->has_vhostfd || (tap->has_vhostforce && tap->vhostforce)) { + int vhostfd; + + if (tap->has_vhostfd) { + vhostfd = net_handle_fd_param(cur_mon, tap->vhostfd); + if (vhostfd == -1) { return -1; } - vhostfd = r; } else { vhostfd = -1; } - s->vhost_net = vhost_net_init(&s->nc, vhostfd, force); + + s->vhost_net = vhost_net_init(&s->nc, vhostfd, + tap->has_vhostforce && tap->vhostforce); if (!s->vhost_net) { error_report("vhost-net requested but could not be initialized"); return -1; } - } else if (qemu_opt_get(opts, "vhostfd")) { + } else if (tap->has_vhostfd) { error_report("vhostfd= is not valid without vhost"); return -1; } @@ -711,6 +711,6 @@ int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) VHostNetState *tap_get_vhost_net(VLANClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); return s->vhost_net; } @@ -27,12 +27,13 @@ #define QEMU_NET_TAP_H #include "qemu-common.h" -#include "qemu-option.h" +#include "qapi-types.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" -int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan); +int net_init_tap(const NetClientOptions *opts, const char *name, + VLANState *vlan); int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required); @@ -45,7 +46,7 @@ void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr); void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn, int ufo); void tap_set_vnet_hdr_len(VLANClientState *vc, int len); -int tap_set_sndbuf(int fd, QemuOpts *opts); +int tap_set_sndbuf(int fd, const NetdevTapOptions *tap); int tap_probe_vnet_hdr(int fd); int tap_probe_vnet_hdr_len(int fd, int len); int tap_probe_has_ufo(int fd); @@ -57,6 +58,7 @@ int tap_get_fd(VLANClientState *vc); struct vhost_net; struct vhost_net *tap_get_vhost_net(VLANClientState *vc); -int net_init_bridge(QemuOpts *opts, const char *name, VLANState *vlan); +int net_init_bridge(const NetClientOptions *opts, const char *name, + VLANState *vlan); #endif /* QEMU_NET_TAP_H */ @@ -69,7 +69,7 @@ static void vde_cleanup(VLANClientState *nc) } static NetClientInfo net_vde_info = { - .type = NET_CLIENT_TYPE_VDE, + .type = NET_CLIENT_OPTIONS_KIND_VDE, .size = sizeof(VDEState), .receive = vde_receive, .cleanup = vde_cleanup, @@ -110,19 +110,17 @@ static int net_vde_init(VLANState *vlan, const char *model, return 0; } -int net_init_vde(QemuOpts *opts, const char *name, VLANState *vlan) +int net_init_vde(const NetClientOptions *opts, const char *name, + VLANState *vlan) { - const char *sock; - const char *group; - int port, mode; + const NetdevVdeOptions *vde; - sock = qemu_opt_get(opts, "sock"); - group = qemu_opt_get(opts, "group"); + assert(opts->kind == NET_CLIENT_OPTIONS_KIND_VDE); + vde = opts->vde; - port = qemu_opt_get_number(opts, "port", 0); - mode = qemu_opt_get_number(opts, "mode", 0700); - - if (net_vde_init(vlan, "vde", name, sock, port, group, mode) == -1) { + /* missing optional values have been initialized to "all bits zero" */ + if (net_vde_init(vlan, "vde", name, vde->sock, vde->port, vde->group, + vde->has_mode ? vde->mode : 0700) == -1) { return -1; } @@ -25,11 +25,12 @@ #define QEMU_NET_VDE_H #include "qemu-common.h" -#include "qemu-option.h" +#include "qapi-types.h" #ifdef CONFIG_VDE -int net_init_vde(QemuOpts *opts, const char *name, VLANState *vlan); +int net_init_vde(const NetClientOptions *opts, const char *name, + VLANState *vlan); #endif /* CONFIG_VDE */ @@ -70,10 +70,12 @@ typedef signed int int_fast16_t; #ifndef always_inline #if !((__GNUC__ < 3) || defined(__APPLE__)) #ifdef __OPTIMIZE__ +#undef inline #define inline __attribute__ (( always_inline )) __inline__ #endif #endif #else +#undef inline #define inline always_inline #endif @@ -14,6 +14,7 @@ #pragma GCC poison TARGET_M68K #pragma GCC poison TARGET_MIPS #pragma GCC poison TARGET_MIPS64 +#pragma GCC poison TARGET_OPENRISC #pragma GCC poison TARGET_PPC #pragma GCC poison TARGET_PPCEMB #pragma GCC poison TARGET_PPC64 diff --git a/qapi-schema.json b/qapi-schema.json index a92adb1d5b..bc55ed2b6d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -343,7 +343,7 @@ # @CPU: the index of the virtual CPU # # @current: this only exists for backwards compatible and should be ignored -# +# # @halted: true if the virtual CPU is in the halt state. Halt usually refers # to a processor specific low power mode. # @@ -686,7 +686,7 @@ # @SpiceInfo # # Information about the SPICE session. -# +# # @enabled: true if the SPICE server is enabled, false otherwise # # @host: #optional The hostname the SPICE server is bound to. This depends on @@ -1297,7 +1297,7 @@ ## { 'command': 'human-monitor-command', 'data': {'command-line': 'str', '*cpu-index': 'int'}, - 'returns': 'str' } + 'returns': 'str' } ## # @migrate_cancel @@ -1458,7 +1458,7 @@ # @password: the new password # # @connected: #optional how to handle existing clients when changing the -# password. If nothing is specified, defaults to `keep' +# password. If nothing is specified, defaults to `keep' # `fail' to fail the command if clients are connected # `disconnect' to disconnect existing clients # `keep' to maintain existing clients @@ -1598,7 +1598,7 @@ # If the argument combination is invalid, InvalidParameterCombination # # Since: 1.1 -## +## { 'command': 'block_set_io_throttle', 'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } } @@ -1872,6 +1872,284 @@ { 'command': 'netdev_del', 'data': {'id': 'str'} } ## +# @NetdevNoneOptions +# +# Use it alone to have zero network devices. +# +# Since 1.2 +## +{ 'type': 'NetdevNoneOptions', + 'data': { } } + +## +# @NetLegacyNicOptions +# +# Create a new Network Interface Card. +# +# @netdev: #optional id of -netdev to connect to +# +# @macaddr: #optional MAC address +# +# @model: #optional device model (e1000, rtl8139, virtio etc.) +# +# @addr: #optional PCI device address +# +# @vectors: #optional number of MSI-x vectors, 0 to disable MSI-X +# +# Since 1.2 +## +{ 'type': 'NetLegacyNicOptions', + 'data': { + '*netdev': 'str', + '*macaddr': 'str', + '*model': 'str', + '*addr': 'str', + '*vectors': 'uint32' } } + +## +# @String +# +# A fat type wrapping 'str', to be embedded in lists. +# +# Since 1.2 +## +{ 'type': 'String', + 'data': { + 'str': 'str' } } + +## +# @NetdevUserOptions +# +# Use the user mode network stack which requires no administrator privilege to +# run. +# +# @hostname: #optional client hostname reported by the builtin DHCP server +# +# @restrict: #optional isolate the guest from the host +# +# @ip: #optional legacy parameter, use net= instead +# +# @net: #optional IP address and optional netmask +# +# @host: #optional guest-visible address of the host +# +# @tftp: #optional root directory of the built-in TFTP server +# +# @bootfile: #optional BOOTP filename, for use with tftp= +# +# @dhcpstart: #optional the first of the 16 IPs the built-in DHCP server can +# assign +# +# @dns: #optional guest-visible address of the virtual nameserver +# +# @smb: #optional root directory of the built-in SMB server +# +# @smbserver: #optional IP address of the built-in SMB server +# +# @hostfwd: #optional redirect incoming TCP or UDP host connections to guest +# endpoints +# +# @guestfwd: #optional forward guest TCP connections +# +# Since 1.2 +## +{ 'type': 'NetdevUserOptions', + 'data': { + '*hostname': 'str', + '*restrict': 'bool', + '*ip': 'str', + '*net': 'str', + '*host': 'str', + '*tftp': 'str', + '*bootfile': 'str', + '*dhcpstart': 'str', + '*dns': 'str', + '*smb': 'str', + '*smbserver': 'str', + '*hostfwd': ['String'], + '*guestfwd': ['String'] } } + +## +# @NetdevTapOptions +# +# Connect the host TAP network interface name to the VLAN. +# +# @ifname: #optional interface name +# +# @fd: #optional file descriptor of an already opened tap +# +# @script: #optional script to initialize the interface +# +# @downscript: #optional script to shut down the interface +# +# @helper: #optional command to execute to configure bridge +# +# @sndbuf: #optional send buffer limit. Understands [TGMKkb] suffixes. +# +# @vnet_hdr: #optional enable the IFF_VNET_HDR flag on the tap interface +# +# @vhost: #optional enable vhost-net network accelerator +# +# @vhostfd: #optional file descriptor of an already opened vhost net device +# +# @vhostforce: #optional vhost on for non-MSIX virtio guests +# +# Since 1.2 +## +{ 'type': 'NetdevTapOptions', + 'data': { + '*ifname': 'str', + '*fd': 'str', + '*script': 'str', + '*downscript': 'str', + '*helper': 'str', + '*sndbuf': 'size', + '*vnet_hdr': 'bool', + '*vhost': 'bool', + '*vhostfd': 'str', + '*vhostforce': 'bool' } } + +## +# @NetdevSocketOptions +# +# Connect the VLAN to a remote VLAN in another QEMU virtual machine using a TCP +# socket connection. +# +# @fd: #optional file descriptor of an already opened socket +# +# @listen: #optional port number, and optional hostname, to listen on +# +# @connect: #optional port number, and optional hostname, to connect to +# +# @mcast: #optional UDP multicast address and port number +# +# @localaddr: #optional source address and port for multicast and udp packets +# +# @udp: #optional UDP unicast address and port number +# +# Since 1.2 +## +{ 'type': 'NetdevSocketOptions', + 'data': { + '*fd': 'str', + '*listen': 'str', + '*connect': 'str', + '*mcast': 'str', + '*localaddr': 'str', + '*udp': 'str' } } + +## +# @NetdevVdeOptions +# +# Connect the VLAN to a vde switch running on the host. +# +# @sock: #optional socket path +# +# @port: #optional port number +# +# @group: #optional group owner of socket +# +# @mode: #optional permissions for socket +# +# Since 1.2 +## +{ 'type': 'NetdevVdeOptions', + 'data': { + '*sock': 'str', + '*port': 'uint16', + '*group': 'str', + '*mode': 'uint16' } } + +## +# @NetdevDumpOptions +# +# Dump VLAN network traffic to a file. +# +# @len: #optional per-packet size limit (64k default). Understands [TGMKkb] +# suffixes. +# +# @file: #optional dump file path (default is qemu-vlan0.pcap) +# +# Since 1.2 +## +{ 'type': 'NetdevDumpOptions', + 'data': { + '*len': 'size', + '*file': 'str' } } + +## +# @NetdevBridgeOptions +# +# Connect a host TAP network interface to a host bridge device. +# +# @br: #optional bridge name +# +# @helper: #optional command to execute to configure bridge +# +# Since 1.2 +## +{ 'type': 'NetdevBridgeOptions', + 'data': { + '*br': 'str', + '*helper': 'str' } } + +## +# @NetClientOptions +# +# A discriminated record of network device traits. +# +# Since 1.2 +## +{ 'union': 'NetClientOptions', + 'data': { + 'none': 'NetdevNoneOptions', + 'nic': 'NetLegacyNicOptions', + 'user': 'NetdevUserOptions', + 'tap': 'NetdevTapOptions', + 'socket': 'NetdevSocketOptions', + 'vde': 'NetdevVdeOptions', + 'dump': 'NetdevDumpOptions', + 'bridge': 'NetdevBridgeOptions' } } + +## +# @NetLegacy +# +# Captures the configuration of a network device; legacy. +# +# @vlan: #optional vlan number +# +# @id: #optional identifier for monitor commands +# +# @name: #optional identifier for monitor commands, ignored if @id is present +# +# @opts: device type specific properties (legacy) +# +# Since 1.2 +## +{ 'type': 'NetLegacy', + 'data': { + '*vlan': 'int32', + '*id': 'str', + '*name': 'str', + 'opts': 'NetClientOptions' } } + +## +# @Netdev +# +# Captures the configuration of a network device. +# +# @id: identifier for monitor commands. +# +# @opts: device type specific properties +# +# Since 1.2 +## +{ 'type': 'Netdev', + 'data': { + 'id': 'str', + 'opts': 'NetClientOptions' } } + +## # @getfd: # # Receive a file descriptor via SCM rights and assign it a name diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index d0b0c16b90..5f5846e767 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -1,3 +1,3 @@ qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o -qapi-obj-y += string-input-visitor.o string-output-visitor.o +qapi-obj-y += string-input-visitor.o string-output-visitor.o opts-visitor.o diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c new file mode 100644 index 0000000000..a59d306e46 --- /dev/null +++ b/qapi/opts-visitor.c @@ -0,0 +1,427 @@ +/* + * Options Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Laszlo Ersek <lersek@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "opts-visitor.h" +#include "qemu-queue.h" +#include "qemu-option-internal.h" +#include "qapi-visit-impl.h" + + +struct OptsVisitor +{ + Visitor visitor; + + /* Ownership remains with opts_visitor_new()'s caller. */ + const QemuOpts *opts_root; + + unsigned depth; + + /* Non-null iff depth is positive. Each key is a QemuOpt name. Each value + * is a non-empty GQueue, enumerating all QemuOpt occurrences with that + * name. */ + GHashTable *unprocessed_opts; + + /* The list currently being traversed with opts_start_list() / + * opts_next_list(). The list must have a struct element type in the + * schema, with a single mandatory scalar member. */ + GQueue *repeated_opts; + bool repeated_opts_first; + + /* If "opts_root->id" is set, reinstantiate it as a fake QemuOpt for + * uniformity. Only its "name" and "str" fields are set. "fake_id_opt" does + * not survive or escape the OptsVisitor object. + */ + QemuOpt *fake_id_opt; +}; + + +static void +destroy_list(gpointer list) +{ + g_queue_free(list); +} + + +static void +opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt) +{ + GQueue *list; + + list = g_hash_table_lookup(unprocessed_opts, opt->name); + if (list == NULL) { + list = g_queue_new(); + + /* GHashTable will never try to free the keys -- we supply NULL as + * "key_destroy_func" in opts_start_struct(). Thus cast away key + * const-ness in order to suppress gcc's warning. + */ + g_hash_table_insert(unprocessed_opts, (gpointer)opt->name, list); + } + + /* Similarly, destroy_list() doesn't call g_queue_free_full(). */ + g_queue_push_tail(list, (gpointer)opt); +} + + +static void +opts_start_struct(Visitor *v, void **obj, const char *kind, + const char *name, size_t size, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + const QemuOpt *opt; + + *obj = g_malloc0(size > 0 ? size : 1); + if (ov->depth++ > 0) { + return; + } + + ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal, + NULL, &destroy_list); + QTAILQ_FOREACH(opt, &ov->opts_root->head, next) { + /* ensured by qemu-option.c::opts_do_parse() */ + assert(strcmp(opt->name, "id") != 0); + + opts_visitor_insert(ov->unprocessed_opts, opt); + } + + if (ov->opts_root->id != NULL) { + ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt); + + ov->fake_id_opt->name = "id"; + ov->fake_id_opt->str = ov->opts_root->id; + opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt); + } +} + + +static gboolean +ghr_true(gpointer ign_key, gpointer ign_value, gpointer ign_user_data) +{ + return TRUE; +} + + +static void +opts_end_struct(Visitor *v, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + GQueue *any; + + if (--ov->depth > 0) { + return; + } + + /* we should have processed all (distinct) QemuOpt instances */ + any = g_hash_table_find(ov->unprocessed_opts, &ghr_true, NULL); + if (any) { + const QemuOpt *first; + + first = g_queue_peek_head(any); + error_set(errp, QERR_INVALID_PARAMETER, first->name); + } + g_hash_table_destroy(ov->unprocessed_opts); + ov->unprocessed_opts = NULL; + g_free(ov->fake_id_opt); + ov->fake_id_opt = NULL; +} + + +static GQueue * +lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) +{ + GQueue *list; + + list = g_hash_table_lookup(ov->unprocessed_opts, name); + if (!list) { + error_set(errp, QERR_MISSING_PARAMETER, name); + } + return list; +} + + +static void +opts_start_list(Visitor *v, const char *name, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + + /* we can't traverse a list in a list */ + assert(ov->repeated_opts == NULL); + ov->repeated_opts = lookup_distinct(ov, name, errp); + ov->repeated_opts_first = (ov->repeated_opts != NULL); +} + + +static GenericList * +opts_next_list(Visitor *v, GenericList **list, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + GenericList **link; + + if (ov->repeated_opts_first) { + ov->repeated_opts_first = false; + link = list; + } else { + const QemuOpt *opt; + + opt = g_queue_pop_head(ov->repeated_opts); + if (g_queue_is_empty(ov->repeated_opts)) { + g_hash_table_remove(ov->unprocessed_opts, opt->name); + return NULL; + } + link = &(*list)->next; + } + + *link = g_malloc0(sizeof **link); + return *link; +} + + +static void +opts_end_list(Visitor *v, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + + ov->repeated_opts = NULL; +} + + +static const QemuOpt * +lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) +{ + if (ov->repeated_opts == NULL) { + GQueue *list; + + /* the last occurrence of any QemuOpt takes effect when queried by name + */ + list = lookup_distinct(ov, name, errp); + return list ? g_queue_peek_tail(list) : NULL; + } + return g_queue_peek_head(ov->repeated_opts); +} + + +static void +processed(OptsVisitor *ov, const char *name) +{ + if (ov->repeated_opts == NULL) { + g_hash_table_remove(ov->unprocessed_opts, name); + } +} + + +static void +opts_type_str(Visitor *v, char **obj, const char *name, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + const QemuOpt *opt; + + opt = lookup_scalar(ov, name, errp); + if (!opt) { + return; + } + *obj = g_strdup(opt->str ? opt->str : ""); + processed(ov, name); +} + + +/* mimics qemu-option.c::parse_option_bool() */ +static void +opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + const QemuOpt *opt; + + opt = lookup_scalar(ov, name, errp); + if (!opt) { + return; + } + + if (opt->str) { + if (strcmp(opt->str, "on") == 0 || + strcmp(opt->str, "yes") == 0 || + strcmp(opt->str, "y") == 0) { + *obj = true; + } else if (strcmp(opt->str, "off") == 0 || + strcmp(opt->str, "no") == 0 || + strcmp(opt->str, "n") == 0) { + *obj = false; + } else { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, + "on|yes|y|off|no|n"); + return; + } + } else { + *obj = true; + } + + processed(ov, name); +} + + +static void +opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + const QemuOpt *opt; + const char *str; + long long val; + char *endptr; + + opt = lookup_scalar(ov, name, errp); + if (!opt) { + return; + } + str = opt->str ? opt->str : ""; + + errno = 0; + val = strtoll(str, &endptr, 0); + if (*str != '\0' && *endptr == '\0' && errno == 0 && INT64_MIN <= val && + val <= INT64_MAX) { + *obj = val; + processed(ov, name); + return; + } + error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "an int64 value"); +} + + +static void +opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + const QemuOpt *opt; + const char *str; + + opt = lookup_scalar(ov, name, errp); + if (!opt) { + return; + } + + str = opt->str; + if (str != NULL) { + while (isspace((unsigned char)*str)) { + ++str; + } + + if (*str != '-' && *str != '\0') { + unsigned long long val; + char *endptr; + + /* non-empty, non-negative subject sequence */ + errno = 0; + val = strtoull(str, &endptr, 0); + if (*endptr == '\0' && errno == 0 && val <= UINT64_MAX) { + *obj = val; + processed(ov, name); + return; + } + } + } + error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, + "an uint64 value"); +} + + +static void +opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + const QemuOpt *opt; + int64_t val; + char *endptr; + + opt = lookup_scalar(ov, name, errp); + if (!opt) { + return; + } + + val = strtosz_suffix(opt->str ? opt->str : "", &endptr, + STRTOSZ_DEFSUFFIX_B); + if (val != -1 && *endptr == '\0') { + *obj = val; + processed(ov, name); + return; + } + error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, + "a size value representible as a non-negative int64"); +} + + +static void +opts_start_optional(Visitor *v, bool *present, const char *name, + Error **errp) +{ + OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); + + /* we only support a single mandatory scalar field in a list node */ + assert(ov->repeated_opts == NULL); + *present = (lookup_distinct(ov, name, NULL) != NULL); +} + + +OptsVisitor * +opts_visitor_new(const QemuOpts *opts) +{ + OptsVisitor *ov; + + ov = g_malloc0(sizeof *ov); + + ov->visitor.start_struct = &opts_start_struct; + ov->visitor.end_struct = &opts_end_struct; + + ov->visitor.start_list = &opts_start_list; + ov->visitor.next_list = &opts_next_list; + ov->visitor.end_list = &opts_end_list; + + /* input_type_enum() covers both "normal" enums and union discriminators. + * The union discriminator field is always generated as "type"; it should + * match the "type" QemuOpt child of any QemuOpts. + * + * input_type_enum() will remove the looked-up key from the + * "unprocessed_opts" hash even if the lookup fails, because the removal is + * done earlier in opts_type_str(). This should be harmless. + */ + ov->visitor.type_enum = &input_type_enum; + + ov->visitor.type_int = &opts_type_int; + ov->visitor.type_uint64 = &opts_type_uint64; + ov->visitor.type_size = &opts_type_size; + ov->visitor.type_bool = &opts_type_bool; + ov->visitor.type_str = &opts_type_str; + + /* type_number() is not filled in, but this is not the first visitor to + * skip some mandatory methods... */ + + ov->visitor.start_optional = &opts_start_optional; + + ov->opts_root = opts; + + return ov; +} + + +void +opts_visitor_cleanup(OptsVisitor *ov) +{ + if (ov->unprocessed_opts != NULL) { + g_hash_table_destroy(ov->unprocessed_opts); + } + g_free(ov->fake_id_opt); + memset(ov, '\0', sizeof *ov); +} + + +Visitor * +opts_get_visitor(OptsVisitor *ov) +{ + return &ov->visitor; +} diff --git a/qapi/opts-visitor.h b/qapi/opts-visitor.h new file mode 100644 index 0000000000..ea1a395573 --- /dev/null +++ b/qapi/opts-visitor.h @@ -0,0 +1,31 @@ +/* + * Options Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Laszlo Ersek <lersek@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef OPTS_VISITOR_H +#define OPTS_VISITOR_H + +#include "qapi-visit-core.h" +#include "qemu-option.h" + +typedef struct OptsVisitor OptsVisitor; + +/* Contrarily to qemu-option.c::parse_option_number(), OptsVisitor's "int" + * parser relies on strtoll() instead of strtoull(). Consequences: + * - string representations of negative numbers yield negative values, + * - values below INT64_MIN or LLONG_MIN are rejected, + * - values above INT64_MAX or LLONG_MAX are rejected. + */ +OptsVisitor *opts_visitor_new(const QemuOpts *opts); +void opts_visitor_cleanup(OptsVisitor *nv); +Visitor *opts_get_visitor(OptsVisitor *nv); + +#endif diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 705eca90aa..7a82b63766 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -39,9 +39,8 @@ void visit_start_struct(Visitor *v, void **obj, const char *kind, void visit_end_struct(Visitor *v, Error **errp) { - if (!error_is_set(errp)) { - v->end_struct(v, errp); - } + assert(!error_is_set(errp)); + v->end_struct(v, errp); } void visit_start_list(Visitor *v, const char *name, Error **errp) @@ -62,9 +61,8 @@ GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp) void visit_end_list(Visitor *v, Error **errp) { - if (!error_is_set(errp)) { - v->end_list(v, errp); - } + assert(!error_is_set(errp)); + v->end_list(v, errp); } void visit_start_optional(Visitor *v, bool *present, const char *name, @@ -236,6 +234,13 @@ void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) } } +void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) +{ + if (!error_is_set(errp)) { + (v->type_size ? v->type_size : v->type_uint64)(v, obj, name, errp); + } +} + void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) { if (!error_is_set(errp)) { diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h index a19d70c104..60acedac77 100644 --- a/qapi/qapi-visit-core.h +++ b/qapi/qapi-visit-core.h @@ -60,6 +60,8 @@ struct Visitor void (*type_int16)(Visitor *v, int16_t *obj, const char *name, Error **errp); void (*type_int32)(Visitor *v, int32_t *obj, const char *name, Error **errp); void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp); + /* visit_type_size() falls back to (*type_uint64)() if type_size is unset */ + void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp); }; void visit_start_handle(Visitor *v, void **obj, const char *kind, @@ -85,6 +87,7 @@ void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp); void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp); void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp); void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp); +void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp); void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp); void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp); void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp); diff --git a/qemu-common.h b/qemu-common.h index 09676f529f..7c8dac80a2 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -293,7 +293,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id); void qemu_cpu_kick(void *env); void qemu_cpu_kick_self(void); int qemu_cpu_is_self(void *env); -bool all_cpu_threads_idle(void); /* work queue */ struct qemu_work_item { diff --git a/qemu-option-internal.h b/qemu-option-internal.h new file mode 100644 index 0000000000..19fdc1ca85 --- /dev/null +++ b/qemu-option-internal.h @@ -0,0 +1,53 @@ +/* + * Commandline option parsing functions + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com> + * + * 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. + */ + +#ifndef QEMU_OPTIONS_INTERNAL_H +#define QEMU_OPTIONS_INTERNAL_H + +#include "qemu-option.h" + +struct QemuOpt { + const char *name; + const char *str; + + const QemuOptDesc *desc; + union { + bool boolean; + uint64_t uint; + } value; + + QemuOpts *opts; + QTAILQ_ENTRY(QemuOpt) next; +}; + +struct QemuOpts { + char *id; + QemuOptsList *list; + Location loc; + QTAILQ_HEAD(QemuOptHead, QemuOpt) head; + QTAILQ_ENTRY(QemuOpts) next; +}; + +#endif diff --git a/qemu-option.c b/qemu-option.c index bb3886c6b9..8334190c53 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -29,9 +29,9 @@ #include "qemu-common.h" #include "qemu-error.h" #include "qemu-objects.h" -#include "qemu-option.h" #include "error.h" #include "qerror.h" +#include "qemu-option-internal.h" /* * Extracts the name of an option from the parameter string (p points at the @@ -511,28 +511,6 @@ void print_option_help(QEMUOptionParameter *list) /* ------------------------------------------------------------------ */ -struct QemuOpt { - const char *name; - const char *str; - - const QemuOptDesc *desc; - union { - bool boolean; - uint64_t uint; - } value; - - QemuOpts *opts; - QTAILQ_ENTRY(QemuOpt) next; -}; - -struct QemuOpts { - char *id; - QemuOptsList *list; - Location loc; - QTAILQ_HEAD(QemuOptHead, QemuOpt) head; - QTAILQ_ENTRY(QemuOpts) next; -}; - static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) { QemuOpt *opt; diff --git a/qemu-options.hx b/qemu-options.hx index 97245a335c..dc68e15033 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1439,7 +1439,7 @@ Forward guest TCP connections to the IP address @var{server} on port @var{port} to the character device @var{dev} or to a program executed by @var{cmd:command} which gets spawned for each connection. This option can be given multiple times. -You can either use a chardev directly and have that one used throughout Qemu's +You can either use a chardev directly and have that one used throughout QEMU's lifetime, like in the following example: @example @@ -1449,7 +1449,7 @@ qemu -net user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 [...] @end example Or you can execute a command on every TCP connection established by the guest, -so that Qemu behaves similar to an inetd process for that virtual server: +so that QEMU behaves similar to an inetd process for that virtual server: @example # call "netcat 10.10.1.1 4321" on every TCP connection to 10.0.2.100:1234 diff --git a/qemu-sockets.c b/qemu-sockets.c index 2ae715db76..668fa93294 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -11,6 +11,9 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. */ #include <stdio.h> #include <stdlib.h> diff --git a/qga/Makefile.objs b/qga/Makefile.objs index 6a4d843436..cd3e13516c 100644 --- a/qga/Makefile.objs +++ b/qga/Makefile.objs @@ -1,3 +1,5 @@ qga-obj-y = commands.o guest-agent-command-state.o qga-obj-$(CONFIG_POSIX) += commands-posix.o channel-posix.o qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o +qga-obj-y += qapi-generated/qga-qapi-types.o qapi-generated/qga-qapi-visit.o +qga-obj-y += qapi-generated/qga-qmp-marshal.o @@ -94,7 +94,6 @@ define unnest-dir $(foreach var,$(nested-vars),$(call push-var,$(var),$1/)) $(eval obj := $(obj)/$1) $(eval include $(SRC_PATH)/$1/Makefile.objs) -$(eval -include $(wildcard $1/*.d)) $(eval obj := $(patsubst %/$1,%,$(obj))) $(foreach var,$(nested-vars),$(call pop-var,$(var),$1/)) endef @@ -113,4 +112,6 @@ define unnest-vars $(call unnest-vars-1) $(foreach var,$(nested-vars),$(eval $(var) := $(filter-out %/, $($(var))))) $(shell mkdir -p $(sort $(foreach var,$(nested-vars),$(dir $($(var)))))) +$(foreach var,$(nested-vars), $(eval \ + -include $(addsuffix *.d, $(sort $(dir $($(var))))))) endef diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 8d4e94a45f..04ef7c41ab 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -17,32 +17,49 @@ import os import getopt import errno -def generate_visit_struct_body(field_prefix, members): - ret = "" +def generate_visit_struct_body(field_prefix, name, members): + ret = mcgen(''' +if (!error_is_set(errp)) { +''') + push_indent() + if len(field_prefix): field_prefix = field_prefix + "." + ret += mcgen(''' +Error **errp = &err; /* from outer scope */ +Error *err = NULL; +visit_start_struct(m, NULL, "", "%(name)s", 0, &err); +''', + name=name) + else: + ret += mcgen(''' +Error *err = NULL; +visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); +''', + name=name) + + ret += mcgen(''' +if (!err) { + if (!obj || *obj) { +''') + + push_indent() + push_indent() for argname, argentry, optional, structured in parse_args(members): if optional: ret += mcgen(''' -visit_start_optional(m, (obj && *obj) ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp); -if ((*obj)->%(prefix)shas_%(c_name)s) { +visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err); +if (obj && (*obj)->%(prefix)shas_%(c_name)s) { ''', c_prefix=c_var(field_prefix), prefix=field_prefix, c_name=c_var(argname), name=argname) push_indent() if structured: - ret += mcgen(''' -visit_start_struct(m, NULL, "", "%(name)s", 0, errp); -''', - name=argname) - ret += generate_visit_struct_body(field_prefix + argname, argentry) - ret += mcgen(''' -visit_end_struct(m, errp); -''') + ret += generate_visit_struct_body(field_prefix + argname, argname, argentry) else: ret += mcgen(''' -visit_type_%(type)s(m, (obj && *obj) ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp); +visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err); ''', c_prefix=c_var(field_prefix), prefix=field_prefix, type=type_name(argentry), c_name=c_var(argname), @@ -52,7 +69,25 @@ visit_type_%(type)s(m, (obj && *obj) ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, " pop_indent() ret += mcgen(''' } -visit_end_optional(m, errp); +visit_end_optional(m, &err); +''') + + pop_indent() + ret += mcgen(''' + + error_propagate(errp, err); + err = NULL; +} +''') + + pop_indent() + pop_indent() + ret += mcgen(''' + /* Always call end_struct if start_struct succeeded. */ + visit_end_struct(m, &err); + } + error_propagate(errp, err); +} ''') return ret @@ -61,22 +96,14 @@ def generate_visit_struct(name, members): void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) { - if (error_is_set(errp)) { - return; - } - visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp); - if (obj && !*obj) { - goto end; - } ''', name=name) + push_indent() - ret += generate_visit_struct_body("", members) + ret += generate_visit_struct_body("", name, members) pop_indent() ret += mcgen(''' -end: - visit_end_struct(m, errp); } ''') return ret @@ -87,18 +114,23 @@ def generate_visit_list(name, members): void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) { GenericList *i, **prev = (GenericList **)obj; + Error *err = NULL; - if (error_is_set(errp)) { - return; - } - visit_start_list(m, name, errp); - - for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) { - %(name)sList *native_i = (%(name)sList *)i; - visit_type_%(name)s(m, &native_i->value, NULL, errp); + if (!error_is_set(errp)) { + visit_start_list(m, name, &err); + if (!err) { + for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) { + %(name)sList *native_i = (%(name)sList *)i; + visit_type_%(name)s(m, &native_i->value, NULL, &err); + } + error_propagate(errp, err); + err = NULL; + + /* Always call end_list if start_list succeeded. */ + visit_end_list(m, &err); + } + error_propagate(errp, err); } - - visit_end_list(m, errp); } ''', name=name) @@ -122,27 +154,23 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** { Error *err = NULL; - if (error_is_set(errp)) { - return; - } - visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); - if (obj && !*obj) { - goto end; - } - visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err); - if (err) { - error_propagate(errp, err); - goto end; - } - switch ((*obj)->kind) { + if (!error_is_set(errp)) { + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + if (!err) { + if (!obj || *obj) { + visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err); + if (!err) { + switch ((*obj)->kind) { ''', name=name) + push_indent() + push_indent() for key in members: ret += mcgen(''' - case %(abbrev)s_KIND_%(enum)s: - visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", errp); - break; + case %(abbrev)s_KIND_%(enum)s: + visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err); + break; ''', abbrev = de_camel_case(name).upper(), enum = c_fun(de_camel_case(key)).upper(), @@ -150,11 +178,25 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** c_name=c_fun(key)) ret += mcgen(''' - default: - abort(); + default: + abort(); + } + } + error_propagate(errp, err); + err = NULL; + } +''') + pop_indent() + ret += mcgen(''' + /* Always call end_struct if start_struct succeeded. */ + visit_end_struct(m, &err); } -end: - visit_end_struct(m, errp); + error_propagate(errp, err); +} +''') + + pop_indent(); + ret += mcgen(''' } ''') diff --git a/scripts/qapi.py b/scripts/qapi.py index e06233666b..8082af3fcd 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -159,6 +159,12 @@ def c_type(name): return 'char *' elif name == 'int': return 'int64_t' + elif (name == 'int8' or name == 'int16' or name == 'int32' or + name == 'int64' or name == 'uint8' or name == 'uint16' or + name == 'uint32' or name == 'uint64'): + return name + '_t' + elif name == 'size': + return 'uint64_t' elif name == 'bool': return 'bool' elif name == 'number': diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index f55e5e63f9..9b4419f7c3 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -12,53 +12,69 @@ import struct import re import inspect +from tracetool import _read_events, Event +from tracetool.backend.simple import is_string header_event_id = 0xffffffffffffffff header_magic = 0xf2b177cb0aa429b4 -header_version = 0 dropped_event_id = 0xfffffffffffffffe -trace_fmt = '=QQQQQQQQ' -trace_len = struct.calcsize(trace_fmt) -event_re = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*') +log_header_fmt = '=QQQ' +rec_header_fmt = '=QQII' -def parse_events(fobj): - """Parse a trace-events file into {event_num: (name, arg1, ...)}.""" - - def get_argnames(args): - """Extract argument names from a parameter list.""" - return tuple(arg.split()[-1].lstrip('*') for arg in args.split(',')) - - events = {dropped_event_id: ('dropped', 'count')} - event_num = 0 - for line in fobj: - m = event_re.match(line.strip()) - if m is None: - continue - - disable, name, args = m.groups() - events[event_num] = (name,) + get_argnames(args) - event_num += 1 - return events +def read_header(fobj, hfmt): + '''Read a trace record header''' + hlen = struct.calcsize(hfmt) + hdr = fobj.read(hlen) + if len(hdr) != hlen: + return None + return struct.unpack(hfmt, hdr) -def read_record(fobj): +def get_record(edict, rechdr, fobj): """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" - s = fobj.read(trace_len) - if len(s) != trace_len: + if rechdr is None: return None - return struct.unpack(trace_fmt, s) + rec = (rechdr[0], rechdr[1]) + if rechdr[0] != dropped_event_id: + event_id = rechdr[0] + event = edict[event_id] + for type, name in event.args: + if is_string(type): + l = fobj.read(4) + (len,) = struct.unpack('=L', l) + s = fobj.read(len) + rec = rec + (s,) + else: + (value,) = struct.unpack('=Q', fobj.read(8)) + rec = rec + (value,) + else: + (value,) = struct.unpack('=Q', fobj.read(8)) + rec = rec + (value,) + return rec + + +def read_record(edict, fobj): + """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" + rechdr = read_header(fobj, rec_header_fmt) + return get_record(edict, rechdr, fobj) # return tuple of record elements -def read_trace_file(fobj): +def read_trace_file(edict, fobj): """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6).""" - header = read_record(fobj) + header = read_header(fobj, log_header_fmt) if header is None or \ header[0] != header_event_id or \ - header[1] != header_magic or \ - header[2] != header_version: - raise ValueError('not a trace file or incompatible version') + header[1] != header_magic: + raise ValueError('Not a valid trace file!') + if header[2] != 0 and \ + header[2] != 2: + raise ValueError('Unknown version of tracelog format!') + + log_version = header[2] + if log_version == 0: + raise ValueError('Older log format, not supported with this Qemu release!') while True: - rec = read_record(fobj) + rec = read_record(edict, fobj) if rec is None: break @@ -89,16 +105,29 @@ class Analyzer(object): def process(events, log, analyzer): """Invoke an analyzer on each event in a log.""" if isinstance(events, str): - events = parse_events(open(events, 'r')) + events = _read_events(open(events, 'r')) if isinstance(log, str): log = open(log, 'rb') + enabled_events = [] + dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)") + edict = {dropped_event_id: dropped_event} + + for e in events: + if 'disable' not in e.properties: + enabled_events.append(e) + for num, event in enumerate(enabled_events): + edict[num] = event + def build_fn(analyzer, event): - fn = getattr(analyzer, event[0], None) + if isinstance(event, str): + return analyzer.catchall + + fn = getattr(analyzer, event.name, None) if fn is None: return analyzer.catchall - event_argcount = len(event) - 1 + event_argcount = len(event.args) fn_argcount = len(inspect.getargspec(fn)[0]) - 1 if fn_argcount == event_argcount + 1: # Include timestamp as first argument @@ -109,9 +138,9 @@ def process(events, log, analyzer): analyzer.begin() fn_cache = {} - for rec in read_trace_file(log): + for rec in read_trace_file(edict, log): event_num = rec[0] - event = events[event_num] + event = edict[event_num] if event_num not in fn_cache: fn_cache[event_num] = build_fn(analyzer, event) fn_cache[event_num](event, rec) @@ -128,7 +157,7 @@ def run(analyzer): sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0]) sys.exit(1) - events = parse_events(open(sys.argv[1], 'r')) + events = _read_events(open(sys.argv[1], 'r')) process(events, sys.argv[2], analyzer) if __name__ == '__main__': @@ -137,15 +166,20 @@ if __name__ == '__main__': self.last_timestamp = None def catchall(self, event, rec): + i = 1 timestamp = rec[1] if self.last_timestamp is None: self.last_timestamp = timestamp delta_ns = timestamp - self.last_timestamp self.last_timestamp = timestamp - fields = [event[0], '%0.3f' % (delta_ns / 1000.0)] - for i in xrange(1, len(event)): - fields.append('%s=0x%x' % (event[i], rec[i + 1])) + fields = [event.name, '%0.3f' % (delta_ns / 1000.0)] + for type, name in event.args: + if is_string(type): + fields.append('%s=%s' % (name, rec[i + 1])) + else: + fields.append('%s=0x%x' % (name, rec[i + 1])) + i += 1 print ' '.join(fields) run(Formatter()) diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index fbb5717c66..c7e47d6d72 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -15,9 +15,16 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out +def is_string(arg): + strtype = ('const char*', 'char*', 'const char *', 'char *') + if arg.lstrip().startswith(strtype): + return True + else: + return False def c(events): out('#include "trace.h"', + '#include "trace/simple.h"', '', 'TraceEvent trace_list[] = {') @@ -26,30 +33,75 @@ def c(events): name = e.name, ) - out('};') + out('};', + '') + + for num, event in enumerate(events): + out('void trace_%(name)s(%(args)s)', + '{', + ' TraceBufferRecord rec;', + name = event.name, + args = event.args, + ) + sizes = [] + for type_, name in event.args: + if is_string(type_): + out(' size_t arg%(name)s_len = %(name)s ? MIN(strlen(%(name)s), MAX_TRACE_STRLEN) : 0;', + name = name, + ) + strsizeinfo = "4 + arg%s_len" % name + sizes.append(strsizeinfo) + else: + sizes.append("8") + sizestr = " + ".join(sizes) + if len(event.args) == 0: + sizestr = '0' + + + out('', + ' if (!trace_list[%(event_id)s].state) {', + ' return;', + ' }', + '', + ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', + ' return; /* Trace Buffer Full, Event Dropped ! */', + ' }', + event_id = num, + size_str = sizestr, + ) + + if len(event.args) > 0: + for type_, name in event.args: + # string + if is_string(type_): + out(' trace_record_write_str(&rec, %(name)s, arg%(name)s_len);', + name = name, + ) + # pointer var (not string) + elif type_.endswith('*'): + out(' trace_record_write_u64(&rec, (uint64_t)(uint64_t *)%(name)s);', + name = name, + ) + # primitive data type + else: + out(' trace_record_write_u64(&rec, (uint64_t)%(name)s);', + name = name, + ) + + out(' trace_record_finish(&rec);', + '}', + '') + def h(events): out('#include "trace/simple.h"', '') - for num, e in enumerate(events): - if len(e.args): - argstr = e.args.names() - arg_prefix = ', (uint64_t)(uintptr_t)' - cast_args = arg_prefix + arg_prefix.join(argstr) - simple_args = (str(num) + cast_args) - else: - simple_args = str(num) - - out('static inline void trace_%(name)s(%(args)s)', - '{', - ' trace%(argc)d(%(trace_args)s);', - '}', - name = e.name, - args = e.args, - argc = len(e.args), - trace_args = simple_args, + for event in events: + out('void trace_%(name)s(%(args)s);', + name = event.name, + args = event.args, ) - + out('') out('#define NR_TRACE_EVENTS %d' % len(events)) out('extern TraceEvent trace_list[NR_TRACE_EVENTS];') diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b3bcbacd76..6b9659f9e7 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -50,7 +50,7 @@ static const char *ext_feature_name[] = { "ds_cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, "fma", "cx16", "xtpr", "pdcm", - NULL, NULL, "dca", "sse4.1|sse4_1", + NULL, "pcid", "dca", "sse4.1|sse4_1", "sse4.2|sse4_2", "x2apic", "movbe", "popcnt", "tsc-deadline", "aes", "xsave", "osxsave", "avx", NULL, NULL, "hypervisor", diff --git a/target-i386/translate.c b/target-i386/translate.c index 1988dae290..2b113333ac 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -459,12 +459,19 @@ static inline void gen_op_movl_A0_seg(int reg) tcg_gen_ld32u_tl(cpu_A0, cpu_env, offsetof(CPUX86State, segs[reg].base) + REG_L_OFFSET); } -static inline void gen_op_addl_A0_seg(int reg) +static inline void gen_op_addl_A0_seg(DisasContext *s, int reg) { tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUX86State, segs[reg].base)); - tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); #ifdef TARGET_X86_64 - tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); + if (CODE64(s)) { + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); + } else { + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); + } +#else + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); #endif } @@ -620,7 +627,7 @@ static inline void gen_string_movl_A0_ESI(DisasContext *s) override = R_DS; gen_op_movl_A0_reg(R_ESI); gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(override); + gen_op_addl_A0_seg(s, override); } } @@ -641,7 +648,7 @@ static inline void gen_string_movl_A0_EDI(DisasContext *s) } else { gen_op_movl_A0_reg(R_EDI); gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(R_ES); + gen_op_addl_A0_seg(s, R_ES); } } @@ -2066,7 +2073,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } else #endif { - gen_op_addl_A0_seg(override); + gen_op_addl_A0_seg(s, override); } } } else { @@ -2133,7 +2140,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ else override = R_DS; } - gen_op_addl_A0_seg(override); + gen_op_addl_A0_seg(s, override); } } @@ -2210,7 +2217,7 @@ static void gen_add_A0_ds_seg(DisasContext *s) } else #endif { - gen_op_addl_A0_seg(override); + gen_op_addl_A0_seg(s, override); } } } @@ -2463,12 +2470,12 @@ static void gen_push_T0(DisasContext *s) if (s->ss32) { if (s->addseg) { tcg_gen_mov_tl(cpu_T[1], cpu_A0); - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } } else { gen_op_andl_A0_ffff(); tcg_gen_mov_tl(cpu_T[1], cpu_A0); - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } gen_op_st_T0_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) @@ -2503,11 +2510,11 @@ static void gen_push_T1(DisasContext *s) gen_op_addl_A0_im(-4); if (s->ss32) { if (s->addseg) { - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } } else { gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } gen_op_st_T1_A0(s->dflag + 1 + s->mem_index); @@ -2531,10 +2538,10 @@ static void gen_pop_T0(DisasContext *s) gen_op_movl_A0_reg(R_ESP); if (s->ss32) { if (s->addseg) - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } else { gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } gen_op_ld_T0_A0(s->dflag + 1 + s->mem_index); } @@ -2559,7 +2566,7 @@ static void gen_stack_A0(DisasContext *s) gen_op_andl_A0_ffff(); tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); } /* NOTE: wrap around in 16 bit not fully handled */ @@ -2572,7 +2579,7 @@ static void gen_pusha(DisasContext *s) gen_op_andl_A0_ffff(); tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); for(i = 0;i < 8; i++) { gen_op_mov_TN_reg(OT_LONG, 0, 7 - i); gen_op_st_T0_A0(OT_WORD + s->dflag + s->mem_index); @@ -2591,7 +2598,7 @@ static void gen_popa(DisasContext *s) tcg_gen_mov_tl(cpu_T[1], cpu_A0); tcg_gen_addi_tl(cpu_T[1], cpu_T[1], 16 << s->dflag); if (s->addseg) - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); for(i = 0;i < 8; i++) { /* ESP is not reloaded */ if (i != 3) { @@ -2641,7 +2648,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_andl_A0_ffff(); tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) - gen_op_addl_A0_seg(R_SS); + gen_op_addl_A0_seg(s, R_SS); /* push bp */ gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); gen_op_st_T0_A0(ot + s->mem_index); diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs new file mode 100644 index 0000000000..44dc5399df --- /dev/null +++ b/target-openrisc/Makefile.objs @@ -0,0 +1,4 @@ +obj-$(CONFIG_SOFTMMU) += machine.o +obj-y += cpu.o exception.o interrupt.o mmu.o translate.o +obj-y += exception_helper.o fpu_helper.o int_helper.o \ + interrupt_helper.o mmu_helper.o sys_helper.o diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c new file mode 100644 index 0000000000..ba35b17581 --- /dev/null +++ b/target-openrisc/cpu.c @@ -0,0 +1,220 @@ +/* + * QEMU OpenRISC CPU + * + * Copyright (c) 2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "qemu-common.h" + +/* CPUClass::reset() */ +static void openrisc_cpu_reset(CPUState *s) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(s); + OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu); + + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", cpu->env.cpu_index); + log_cpu_state(&cpu->env, 0); + } + + occ->parent_reset(s); + + memset(&cpu->env, 0, offsetof(CPUOpenRISCState, breakpoints)); + + tlb_flush(&cpu->env, 1); + /*tb_flush(&cpu->env); FIXME: Do we need it? */ + + cpu->env.pc = 0x100; + cpu->env.sr = SR_FO | SR_SM; + cpu->env.exception_index = -1; + + cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP; + cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S; + cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2)); + cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2)); + +#ifndef CONFIG_USER_ONLY + cpu->env.picmr = 0x00000000; + cpu->env.picsr = 0x00000000; + + cpu->env.ttmr = 0x00000000; + cpu->env.ttcr = 0x00000000; +#endif +} + +static inline void set_feature(OpenRISCCPU *cpu, int feature) +{ + cpu->feature |= feature; + cpu->env.cpucfgr = cpu->feature; +} + +void openrisc_cpu_realize(Object *obj, Error **errp) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(obj); + + qemu_init_vcpu(&cpu->env); + cpu_reset(CPU(cpu)); +} + +static void openrisc_cpu_initfn(Object *obj) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(obj); + static int inited; + + cpu_exec_init(&cpu->env); + +#ifndef CONFIG_USER_ONLY + cpu_openrisc_mmu_init(cpu); +#endif + + if (tcg_enabled() && !inited) { + inited = 1; + openrisc_translate_init(); + } +} + +/* CPU models */ +static void or1200_initfn(Object *obj) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(obj); + + set_feature(cpu, OPENRISC_FEATURE_OB32S); + set_feature(cpu, OPENRISC_FEATURE_OF32S); +} + +static void openrisc_any_initfn(Object *obj) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(obj); + + set_feature(cpu, OPENRISC_FEATURE_OB32S); +} + +typedef struct OpenRISCCPUInfo { + const char *name; + void (*initfn)(Object *obj); +} OpenRISCCPUInfo; + +static const OpenRISCCPUInfo openrisc_cpus[] = { + { .name = "or1200", .initfn = or1200_initfn }, + { .name = "any", .initfn = openrisc_any_initfn }, +}; + +static void openrisc_cpu_class_init(ObjectClass *oc, void *data) +{ + OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(occ); + + occ->parent_reset = cc->reset; + cc->reset = openrisc_cpu_reset; +} + +static void cpu_register(const OpenRISCCPUInfo *info) +{ + TypeInfo type_info = { + .name = info->name, + .parent = TYPE_OPENRISC_CPU, + .instance_size = sizeof(OpenRISCCPU), + .instance_init = info->initfn, + .class_size = sizeof(OpenRISCCPUClass), + }; + + type_register_static(&type_info); +} + +static const TypeInfo openrisc_cpu_type_info = { + .name = TYPE_OPENRISC_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(OpenRISCCPU), + .instance_init = openrisc_cpu_initfn, + .abstract = false, + .class_size = sizeof(OpenRISCCPUClass), + .class_init = openrisc_cpu_class_init, +}; + +static void openrisc_cpu_register_types(void) +{ + int i; + + type_register_static(&openrisc_cpu_type_info); + for (i = 0; i < ARRAY_SIZE(openrisc_cpus); i++) { + cpu_register(&openrisc_cpus[i]); + } +} + +OpenRISCCPU *cpu_openrisc_init(const char *cpu_model) +{ + OpenRISCCPU *cpu; + + if (!object_class_by_name(cpu_model)) { + return NULL; + } + cpu = OPENRISC_CPU(object_new(cpu_model)); + cpu->env.cpu_model_str = cpu_model; + + openrisc_cpu_realize(OBJECT(cpu), NULL); + + return cpu; +} + +typedef struct OpenRISCCPUList { + fprintf_function cpu_fprintf; + FILE *file; +} OpenRISCCPUList; + +/* Sort alphabetically by type name, except for "any". */ +static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + const char *name_a, *name_b; + + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + if (strcmp(name_a, "any") == 0) { + return 1; + } else if (strcmp(name_b, "any") == 0) { + return -1; + } else { + return strcmp(name_a, name_b); + } +} + +static void openrisc_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + OpenRISCCPUList *s = user_data; + + (*s->cpu_fprintf)(s->file, " %s\n", + object_class_get_name(oc)); +} + +void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf) +{ + OpenRISCCPUList s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_OPENRISC_CPU, false); + list = g_slist_sort(list, openrisc_cpu_list_compare); + (*cpu_fprintf)(f, "Available CPUs:\n"); + g_slist_foreach(list, openrisc_cpu_list_entry, &s); + g_slist_free(list); +} + +type_init(openrisc_cpu_register_types) diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h new file mode 100644 index 0000000000..de21a877d3 --- /dev/null +++ b/target-openrisc/cpu.h @@ -0,0 +1,458 @@ +/* + * OpenRISC virtual CPU header. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef CPU_OPENRISC_H +#define CPU_OPENRISC_H + +#define TARGET_LONG_BITS 32 +#define ELF_MACHINE EM_OPENRISC + +#define CPUArchState struct CPUOpenRISCState + +/* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */ +struct OpenRISCCPU; + +#include "config.h" +#include "qemu-common.h" +#include "cpu-defs.h" +#include "softfloat.h" +#include "qemu/cpu.h" +#include "error.h" + +#define TYPE_OPENRISC_CPU "or32-cpu" + +#define OPENRISC_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(OpenRISCCPUClass, (klass), TYPE_OPENRISC_CPU) +#define OPENRISC_CPU(obj) \ + OBJECT_CHECK(OpenRISCCPU, (obj), TYPE_OPENRISC_CPU) +#define OPENRISC_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(OpenRISCCPUClass, (obj), TYPE_OPENRISC_CPU) + +/** + * OpenRISCCPUClass: + * @parent_reset: The parent class' reset handler. + * + * A OpenRISC CPU model. + */ +typedef struct OpenRISCCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + + void (*parent_reset)(CPUState *cpu); +} OpenRISCCPUClass; + +#define NB_MMU_MODES 3 + +enum { + MMU_NOMMU_IDX = 0, + MMU_SUPERVISOR_IDX = 1, + MMU_USER_IDX = 2, +}; + +#define TARGET_PAGE_BITS 13 + +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 + +#define SET_FP_CAUSE(reg, v) do {\ + (reg) = ((reg) & ~(0x3f << 12)) | \ + ((v & 0x3f) << 12);\ + } while (0) +#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) +#define UPDATE_FP_FLAGS(reg, v) do {\ + (reg) |= ((v & 0x1f) << 2);\ + } while (0) + +/* Version Register */ +#define SPR_VR 0xFFFF003F + +/* Internal flags, delay slot flag */ +#define D_FLAG 1 + +/* Interrupt */ +#define NR_IRQS 32 + +/* Registers */ +enum { + R0 = 0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, + R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, + R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, + R31 +}; + +/* Register aliases */ +enum { + R_ZERO = R0, + R_SP = R1, + R_FP = R2, + R_LR = R9, + R_RV = R11, + R_RVH = R12 +}; + +/* Unit presece register */ +enum { + UPR_UP = (1 << 0), + UPR_DCP = (1 << 1), + UPR_ICP = (1 << 2), + UPR_DMP = (1 << 3), + UPR_IMP = (1 << 4), + UPR_MP = (1 << 5), + UPR_DUP = (1 << 6), + UPR_PCUR = (1 << 7), + UPR_PMP = (1 << 8), + UPR_PICP = (1 << 9), + UPR_TTP = (1 << 10), + UPR_CUP = (255 << 24), +}; + +/* CPU configure register */ +enum { + CPUCFGR_NSGF = (15 << 0), + CPUCFGR_CGF = (1 << 4), + CPUCFGR_OB32S = (1 << 5), + CPUCFGR_OB64S = (1 << 6), + CPUCFGR_OF32S = (1 << 7), + CPUCFGR_OF64S = (1 << 8), + CPUCFGR_OV64S = (1 << 9), +}; + +/* DMMU configure register */ +enum { + DMMUCFGR_NTW = (3 << 0), + DMMUCFGR_NTS = (7 << 2), + DMMUCFGR_NAE = (7 << 5), + DMMUCFGR_CRI = (1 << 8), + DMMUCFGR_PRI = (1 << 9), + DMMUCFGR_TEIRI = (1 << 10), + DMMUCFGR_HTR = (1 << 11), +}; + +/* IMMU configure register */ +enum { + IMMUCFGR_NTW = (3 << 0), + IMMUCFGR_NTS = (7 << 2), + IMMUCFGR_NAE = (7 << 5), + IMMUCFGR_CRI = (1 << 8), + IMMUCFGR_PRI = (1 << 9), + IMMUCFGR_TEIRI = (1 << 10), + IMMUCFGR_HTR = (1 << 11), +}; + +/* Float point control status register */ +enum { + FPCSR_FPEE = 1, + FPCSR_RM = (3 << 1), + FPCSR_OVF = (1 << 3), + FPCSR_UNF = (1 << 4), + FPCSR_SNF = (1 << 5), + FPCSR_QNF = (1 << 6), + FPCSR_ZF = (1 << 7), + FPCSR_IXF = (1 << 8), + FPCSR_IVF = (1 << 9), + FPCSR_INF = (1 << 10), + FPCSR_DZF = (1 << 11), +}; + +/* Exceptions indices */ +enum { + EXCP_RESET = 0x1, + EXCP_BUSERR = 0x2, + EXCP_DPF = 0x3, + EXCP_IPF = 0x4, + EXCP_TICK = 0x5, + EXCP_ALIGN = 0x6, + EXCP_ILLEGAL = 0x7, + EXCP_INT = 0x8, + EXCP_DTLBMISS = 0x9, + EXCP_ITLBMISS = 0xa, + EXCP_RANGE = 0xb, + EXCP_SYSCALL = 0xc, + EXCP_FPE = 0xd, + EXCP_TRAP = 0xe, + EXCP_NR, +}; + +/* Supervisor register */ +enum { + SR_SM = (1 << 0), + SR_TEE = (1 << 1), + SR_IEE = (1 << 2), + SR_DCE = (1 << 3), + SR_ICE = (1 << 4), + SR_DME = (1 << 5), + SR_IME = (1 << 6), + SR_LEE = (1 << 7), + SR_CE = (1 << 8), + SR_F = (1 << 9), + SR_CY = (1 << 10), + SR_OV = (1 << 11), + SR_OVE = (1 << 12), + SR_DSX = (1 << 13), + SR_EPH = (1 << 14), + SR_FO = (1 << 15), + SR_SUMRA = (1 << 16), + SR_SCE = (1 << 17), +}; + +/* OpenRISC Hardware Capabilities */ +enum { + OPENRISC_FEATURE_NSGF = (15 << 0), + OPENRISC_FEATURE_CGF = (1 << 4), + OPENRISC_FEATURE_OB32S = (1 << 5), + OPENRISC_FEATURE_OB64S = (1 << 6), + OPENRISC_FEATURE_OF32S = (1 << 7), + OPENRISC_FEATURE_OF64S = (1 << 8), + OPENRISC_FEATURE_OV64S = (1 << 9), +}; + +/* Tick Timer Mode Register */ +enum { + TTMR_TP = (0xfffffff), + TTMR_IP = (1 << 28), + TTMR_IE = (1 << 29), + TTMR_M = (3 << 30), +}; + +/* Timer Mode */ +enum { + TIMER_NONE = (0 << 30), + TIMER_INTR = (1 << 30), + TIMER_SHOT = (2 << 30), + TIMER_CONT = (3 << 30), +}; + +/* TLB size */ +enum { + DTLB_WAYS = 1, + DTLB_SIZE = 64, + DTLB_MASK = (DTLB_SIZE-1), + ITLB_WAYS = 1, + ITLB_SIZE = 64, + ITLB_MASK = (ITLB_SIZE-1), +}; + +/* TLB prot */ +enum { + URE = (1 << 6), + UWE = (1 << 7), + SRE = (1 << 8), + SWE = (1 << 9), + + SXE = (1 << 6), + UXE = (1 << 7), +}; + +/* check if tlb available */ +enum { + TLBRET_INVALID = -3, + TLBRET_NOMATCH = -2, + TLBRET_BADADDR = -1, + TLBRET_MATCH = 0 +}; + +typedef struct OpenRISCTLBEntry { + uint32_t mr; + uint32_t tr; +} OpenRISCTLBEntry; + +#ifndef CONFIG_USER_ONLY +typedef struct CPUOpenRISCTLBContext { + OpenRISCTLBEntry itlb[ITLB_WAYS][ITLB_SIZE]; + OpenRISCTLBEntry dtlb[DTLB_WAYS][DTLB_SIZE]; + + int (*cpu_openrisc_map_address_code)(struct OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, + target_ulong address, int rw); + int (*cpu_openrisc_map_address_data)(struct OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, + target_ulong address, int rw); +} CPUOpenRISCTLBContext; +#endif + +typedef struct CPUOpenRISCState { + target_ulong gpr[32]; /* General registers */ + target_ulong pc; /* Program counter */ + target_ulong npc; /* Next PC */ + target_ulong ppc; /* Prev PC */ + target_ulong jmp_pc; /* Jump PC */ + + target_ulong machi; /* Multiply register MACHI */ + target_ulong maclo; /* Multiply register MACLO */ + + target_ulong fpmaddhi; /* Multiply and add float register FPMADDHI */ + target_ulong fpmaddlo; /* Multiply and add float register FPMADDLO */ + + target_ulong epcr; /* Exception PC register */ + target_ulong eear; /* Exception EA register */ + + uint32_t sr; /* Supervisor register */ + uint32_t vr; /* Version register */ + uint32_t upr; /* Unit presence register */ + uint32_t cpucfgr; /* CPU configure register */ + uint32_t dmmucfgr; /* DMMU configure register */ + uint32_t immucfgr; /* IMMU configure register */ + uint32_t esr; /* Exception supervisor register */ + uint32_t fpcsr; /* Float register */ + float_status fp_status; + + uint32_t flags; /* cpu_flags, we only use it for exception + in solt so far. */ + uint32_t btaken; /* the SR_F bit */ + + CPU_COMMON + +#ifndef CONFIG_USER_ONLY + CPUOpenRISCTLBContext * tlb; + + struct QEMUTimer *timer; + uint32_t ttmr; /* Timer tick mode register */ + uint32_t ttcr; /* Timer tick count register */ + + uint32_t picmr; /* Interrupt mask register */ + uint32_t picsr; /* Interrupt contrl register*/ +#endif + void *irq[32]; /* Interrupt irq input */ +} CPUOpenRISCState; + +/** + * OpenRISCCPU: + * @env: #CPUOpenRISCState + * + * A OpenRISC CPU. + */ +typedef struct OpenRISCCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUOpenRISCState env; + + uint32_t feature; /* CPU Capabilities */ +} OpenRISCCPU; + +static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env) +{ + return OPENRISC_CPU(container_of(env, OpenRISCCPU, env)); +} + +#define ENV_GET_CPU(e) CPU(openrisc_env_get_cpu(e)) + +OpenRISCCPU *cpu_openrisc_init(const char *cpu_model); +void openrisc_cpu_realize(Object *obj, Error **errp); + +void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf); +int cpu_openrisc_exec(CPUOpenRISCState *s); +void do_interrupt(CPUOpenRISCState *env); +void openrisc_translate_init(void); +int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, + target_ulong address, + int rw, int mmu_idx); +int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc); + +#define cpu_list cpu_openrisc_list +#define cpu_exec cpu_openrisc_exec +#define cpu_gen_code cpu_openrisc_gen_code +#define cpu_handle_mmu_fault cpu_openrisc_handle_mmu_fault +#define cpu_signal_handler cpu_openrisc_signal_handler + +#ifndef CONFIG_USER_ONLY +/* hw/openrisc_pic.c */ +void cpu_openrisc_pic_init(OpenRISCCPU *cpu); + +/* hw/openrisc_timer.c */ +void cpu_openrisc_clock_init(OpenRISCCPU *cpu); +void cpu_openrisc_count_update(OpenRISCCPU *cpu); +void cpu_openrisc_count_start(OpenRISCCPU *cpu); +void cpu_openrisc_count_stop(OpenRISCCPU *cpu); + +void cpu_openrisc_mmu_init(OpenRISCCPU *cpu); +int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, int rw); +int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, int rw); +int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, int rw); +#endif + +static inline CPUOpenRISCState *cpu_init(const char *cpu_model) +{ + OpenRISCCPU *cpu = cpu_openrisc_init(cpu_model); + if (cpu) { + return &cpu->env; + } + return NULL; +} + +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp) +{ + if (newsp) { + env->gpr[1] = newsp; + } + env->gpr[2] = 0; +} +#endif + +#include "cpu-all.h" + +static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, + target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->pc; + *cs_base = 0; + /* D_FLAG -- branch instruction exception */ + *flags = (env->flags & D_FLAG); +} + +static inline int cpu_mmu_index(CPUOpenRISCState *env) +{ + if (!(env->sr & SR_IME)) { + return MMU_NOMMU_IDX; + } + return (env->sr & SR_SM) == 0 ? MMU_USER_IDX : MMU_SUPERVISOR_IDX; +} + +#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 +static inline bool cpu_has_work(CPUOpenRISCState *env) +{ + return env->interrupt_request & (CPU_INTERRUPT_HARD | + CPU_INTERRUPT_TIMER); +} + +#include "exec-all.h" + +static inline target_ulong cpu_get_pc(CPUOpenRISCState *env) +{ + return env->pc; +} + +static inline void cpu_pc_from_tb(CPUOpenRISCState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; +} + +#endif /* CPU_OPENRISC_H */ diff --git a/target-openrisc/exception.c b/target-openrisc/exception.c new file mode 100644 index 0000000000..58e53c6c98 --- /dev/null +++ b/target-openrisc/exception.c @@ -0,0 +1,27 @@ +/* + * OpenRISC exception. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "exception.h" + +void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp) +{ + cpu->env.exception_index = excp; + cpu_loop_exit(&cpu->env); +} diff --git a/target-openrisc/exception.h b/target-openrisc/exception.h new file mode 100644 index 0000000000..4b64430df1 --- /dev/null +++ b/target-openrisc/exception.h @@ -0,0 +1,28 @@ +/* + * OpenRISC exception header. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_OPENRISC_EXCP_H +#define QEMU_OPENRISC_EXCP_H + +#include "cpu.h" +#include "qemu-common.h" + +void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp); + +#endif /* QEMU_OPENRISC_EXCP_H */ diff --git a/target-openrisc/exception_helper.c b/target-openrisc/exception_helper.c new file mode 100644 index 0000000000..dab4148151 --- /dev/null +++ b/target-openrisc/exception_helper.c @@ -0,0 +1,29 @@ +/* + * OpenRISC exception helper routines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "helper.h" +#include "exception.h" + +void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + raise_exception(cpu, excp); +} diff --git a/target-openrisc/fpu_helper.c b/target-openrisc/fpu_helper.c new file mode 100644 index 0000000000..b184d5ef73 --- /dev/null +++ b/target-openrisc/fpu_helper.c @@ -0,0 +1,300 @@ +/* + * OpenRISC float helper routines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Feng Gao <gf91597@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "helper.h" +#include "exception.h" + +static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp) +{ + int ret = 0; + if (fexcp) { + if (fexcp & float_flag_invalid) { + cpu->env.fpcsr |= FPCSR_IVF; + ret = 1; + } + if (fexcp & float_flag_overflow) { + cpu->env.fpcsr |= FPCSR_OVF; + ret = 1; + } + if (fexcp & float_flag_underflow) { + cpu->env.fpcsr |= FPCSR_UNF; + ret = 1; + } + if (fexcp & float_flag_divbyzero) { + cpu->env.fpcsr |= FPCSR_DZF; + ret = 1; + } + if (fexcp & float_flag_inexact) { + cpu->env.fpcsr |= FPCSR_IXF; + ret = 1; + } + } + + return ret; +} + +static inline void update_fpcsr(OpenRISCCPU *cpu) +{ + int tmp = ieee_ex_to_openrisc(cpu, + get_float_exception_flags(&cpu->env.fp_status)); + + SET_FP_CAUSE(cpu->env.fpcsr, tmp); + if ((GET_FP_ENABLE(cpu->env.fpcsr) & tmp) && + (cpu->env.fpcsr & FPCSR_FPEE)) { + helper_exception(&cpu->env, EXCP_FPE); + } else { + UPDATE_FP_FLAGS(cpu->env.fpcsr, tmp); + } +} + +uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val) +{ + uint64_t itofd; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + set_float_exception_flags(0, &cpu->env.fp_status); + itofd = int32_to_float64(val, &cpu->env.fp_status); + update_fpcsr(cpu); + + return itofd; +} + +uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val) +{ + uint32_t itofs; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + set_float_exception_flags(0, &cpu->env.fp_status); + itofs = int32_to_float32(val, &cpu->env.fp_status); + update_fpcsr(cpu); + + return itofs; +} + +uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val) +{ + uint64_t ftoid; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + set_float_exception_flags(0, &cpu->env.fp_status); + ftoid = float32_to_int64(val, &cpu->env.fp_status); + update_fpcsr(cpu); + + return ftoid; +} + +uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val) +{ + uint32_t ftois; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + set_float_exception_flags(0, &cpu->env.fp_status); + ftois = float32_to_int32(val, &cpu->env.fp_status); + update_fpcsr(cpu); + + return ftois; +} + +#define FLOAT_OP(name, p) void helper_float_##_##p(void) + +#define FLOAT_CALC(name) \ +uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, uint64_t fdt1) \ +{ \ + uint64_t result; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return result; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1) \ +{ \ + uint32_t result; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return result; \ +} \ + +FLOAT_CALC(add) +FLOAT_CALC(sub) +FLOAT_CALC(mul) +FLOAT_CALC(div) +FLOAT_CALC(rem) +#undef FLOAT_CALC + +#define FLOAT_TERNOP(name1, name2) \ +uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, \ + uint64_t fdt1) \ +{ \ + uint64_t result, temp, hi, lo; \ + uint32_t val1, val2; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + hi = env->fpmaddhi; \ + lo = env->fpmaddlo; \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \ + lo &= 0xffffffff; \ + hi &= 0xffffffff; \ + temp = (hi << 32) | lo; \ + result = float64_ ## name2(result, temp, &cpu->env.fp_status); \ + val1 = result >> 32; \ + val2 = (uint32_t) (result & 0xffffffff); \ + update_fpcsr(cpu); \ + cpu->env.fpmaddlo = val2; \ + cpu->env.fpmaddhi = val1; \ + return 0; \ +} \ + \ +uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1) \ +{ \ + uint64_t result, temp, hi, lo; \ + uint32_t val1, val2; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + hi = cpu->env.fpmaddhi; \ + lo = cpu->env.fpmaddlo; \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \ + temp = (hi << 32) | lo; \ + result = float64_ ## name2(result, temp, &cpu->env.fp_status); \ + val1 = result >> 32; \ + val2 = (uint32_t) (result & 0xffffffff); \ + update_fpcsr(cpu); \ + cpu->env.fpmaddlo = val2; \ + cpu->env.fpmaddhi = val1; \ + return 0; \ +} + +FLOAT_TERNOP(mul, add) +#undef FLOAT_TERNOP + + +#define FLOAT_CMP(name) \ +uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, uint64_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1)\ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} + +FLOAT_CMP(le) +FLOAT_CMP(eq) +FLOAT_CMP(lt) +#undef FLOAT_CMP + + +#define FLOAT_CMPNE(name) \ +uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, uint64_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} + +FLOAT_CMPNE(ne) +#undef FLOAT_CMPNE + +#define FLOAT_CMPGT(name) \ +uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, uint64_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = !float64_le(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = !float32_le(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} +FLOAT_CMPGT(gt) +#undef FLOAT_CMPGT + +#define FLOAT_CMPGE(name) \ +uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, uint64_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1) \ +{ \ + int res; \ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + set_float_exception_flags(0, &cpu->env.fp_status); \ + res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status); \ + update_fpcsr(cpu); \ + return res; \ +} + +FLOAT_CMPGE(ge) +#undef FLOAT_CMPGE diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h new file mode 100644 index 0000000000..404d46447f --- /dev/null +++ b/target-openrisc/helper.h @@ -0,0 +1,70 @@ +/* + * OpenRISC helper defines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "def-helper.h" + +/* exception */ +DEF_HELPER_FLAGS_2(exception, 0, void, env, i32) + +/* float */ +DEF_HELPER_FLAGS_2(itofd, 0, i64, env, i64) +DEF_HELPER_FLAGS_2(itofs, 0, i32, env, i32) +DEF_HELPER_FLAGS_2(ftoid, 0, i64, env, i64) +DEF_HELPER_FLAGS_2(ftois, 0, i32, env, i32) + +#define FOP_MADD(op) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64) +FOP_MADD(muladd) +#undef FOP_MADD + +#define FOP_CALC(op) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64) +FOP_CALC(add) +FOP_CALC(sub) +FOP_CALC(mul) +FOP_CALC(div) +FOP_CALC(rem) +#undef FOP_CALC + +#define FOP_CMP(op) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64) +FOP_CMP(eq) +FOP_CMP(lt) +FOP_CMP(le) +FOP_CMP(ne) +FOP_CMP(gt) +FOP_CMP(ge) +#undef FOP_CMP + +/* int */ +DEF_HELPER_FLAGS_1(ff1, 0, tl, tl) +DEF_HELPER_FLAGS_1(fl1, 0, tl, tl) +DEF_HELPER_FLAGS_3(mul32, 0, i32, env, i32, i32) + +/* interrupt */ +DEF_HELPER_FLAGS_1(rfe, 0, void, env) + +/* sys */ +DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl) +DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl) + +#include "def-helper.h" diff --git a/target-openrisc/int_helper.c b/target-openrisc/int_helper.c new file mode 100644 index 0000000000..2fdfd27712 --- /dev/null +++ b/target-openrisc/int_helper.c @@ -0,0 +1,79 @@ +/* + * OpenRISC int helper routines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Feng Gao <gf91597@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "helper.h" +#include "exception.h" +#include "host-utils.h" + +target_ulong HELPER(ff1)(target_ulong x) +{ +/*#ifdef TARGET_OPENRISC64 + return x ? ctz64(x) + 1 : 0; +#else*/ + return x ? ctz32(x) + 1 : 0; +/*#endif*/ +} + +target_ulong HELPER(fl1)(target_ulong x) +{ +/* not used yet, open it when we need or64. */ +/*#ifdef TARGET_OPENRISC64 + return 64 - clz64(x); +#else*/ + return 32 - clz32(x); +/*#endif*/ +} + +uint32_t HELPER(mul32)(CPUOpenRISCState *env, + uint32_t ra, uint32_t rb) +{ + uint64_t result; + uint32_t high, cy; + + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + result = (uint64_t)ra * rb; + /* regisiers in or32 is 32bit, so 32 is NOT a magic number. + or64 is not handled in this function, and not implement yet, + TARGET_LONG_BITS for or64 is 64, it will break this function, + so, we didn't use TARGET_LONG_BITS here. */ + high = result >> 32; + cy = result >> (32 - 1); + + if ((cy & 0x1) == 0x0) { + if (high == 0x0) { + return result; + } + } + + if ((cy & 0x1) == 0x1) { + if (high == 0xffffffff) { + return result; + } + } + + cpu->env.sr |= (SR_OV | SR_CY); + if (cpu->env.sr & SR_OVE) { + raise_exception(cpu, EXCP_RANGE); + } + + return result; +} diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c new file mode 100644 index 0000000000..642da7de49 --- /dev/null +++ b/target-openrisc/interrupt.c @@ -0,0 +1,74 @@ +/* + * OpenRISC interrupt. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "qemu-common.h" +#include "gdbstub.h" +#include "host-utils.h" +#ifndef CONFIG_USER_ONLY +#include "hw/loader.h" +#endif + +void do_interrupt(CPUOpenRISCState *env) +{ +#ifndef CONFIG_USER_ONLY + if (env->flags & D_FLAG) { /* Delay Slot insn */ + env->flags &= ~D_FLAG; + env->sr |= SR_DSX; + if (env->exception_index == EXCP_TICK || + env->exception_index == EXCP_INT || + env->exception_index == EXCP_SYSCALL || + env->exception_index == EXCP_FPE) { + env->epcr = env->jmp_pc; + } else { + env->epcr = env->pc - 4; + } + } else { + if (env->exception_index == EXCP_TICK || + env->exception_index == EXCP_INT || + env->exception_index == EXCP_SYSCALL || + env->exception_index == EXCP_FPE) { + env->epcr = env->npc; + } else { + env->epcr = env->pc; + } + } + + /* For machine-state changed between user-mode and supervisor mode, + we need flush TLB when we enter&exit EXCP. */ + tlb_flush(env, 1); + + env->esr = env->sr; + env->sr &= ~SR_DME; + env->sr &= ~SR_IME; + env->sr |= SR_SM; + env->sr &= ~SR_IEE; + env->sr &= ~SR_TEE; + env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; + env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; + + if (env->exception_index > 0 && env->exception_index < EXCP_NR) { + env->pc = (env->exception_index << 8); + } else { + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + } +#endif + + env->exception_index = -1; +} diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c new file mode 100644 index 0000000000..79f5afed44 --- /dev/null +++ b/target-openrisc/interrupt_helper.c @@ -0,0 +1,57 @@ +/* + * OpenRISC interrupt helper routines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Feng Gao <gf91597@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "helper.h" + +void HELPER(rfe)(CPUOpenRISCState *env) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); +#ifndef CONFIG_USER_ONLY + int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^ + (cpu->env.esr & (SR_SM | SR_IME | SR_DME)); +#endif + cpu->env.pc = cpu->env.epcr; + cpu->env.npc = cpu->env.epcr; + cpu->env.sr = cpu->env.esr; + +#ifndef CONFIG_USER_ONLY + if (cpu->env.sr & SR_DME) { + cpu->env.tlb->cpu_openrisc_map_address_data = + &cpu_openrisc_get_phys_data; + } else { + cpu->env.tlb->cpu_openrisc_map_address_data = + &cpu_openrisc_get_phys_nommu; + } + + if (cpu->env.sr & SR_IME) { + cpu->env.tlb->cpu_openrisc_map_address_code = + &cpu_openrisc_get_phys_code; + } else { + cpu->env.tlb->cpu_openrisc_map_address_code = + &cpu_openrisc_get_phys_nommu; + } + + if (need_flush_tlb) { + tlb_flush(&cpu->env, 1); + } +#endif + cpu->env.interrupt_request |= CPU_INTERRUPT_EXITTB; +} diff --git a/target-openrisc/machine.c b/target-openrisc/machine.c new file mode 100644 index 0000000000..cba9811ea5 --- /dev/null +++ b/target-openrisc/machine.c @@ -0,0 +1,47 @@ +/* + * OpenRISC Machine + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/hw.h" +#include "hw/boards.h" + +static const VMStateDescription vmstate_cpu = { + .name = "cpu", + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(gpr, CPUOpenRISCState, 32), + VMSTATE_UINT32(sr, CPUOpenRISCState), + VMSTATE_UINT32(epcr, CPUOpenRISCState), + VMSTATE_UINT32(eear, CPUOpenRISCState), + VMSTATE_UINT32(esr, CPUOpenRISCState), + VMSTATE_UINT32(fpcsr, CPUOpenRISCState), + VMSTATE_UINT32(pc, CPUOpenRISCState), + VMSTATE_UINT32(npc, CPUOpenRISCState), + VMSTATE_UINT32(ppc, CPUOpenRISCState), + VMSTATE_END_OF_LIST() + } +}; + +void cpu_save(QEMUFile *f, void *opaque) +{ + vmstate_save_state(f, &vmstate_cpu, opaque); +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return vmstate_load_state(f, &vmstate_cpu, opaque, version_id); +} diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c new file mode 100644 index 0000000000..0be1d413c9 --- /dev/null +++ b/target-openrisc/mmu.c @@ -0,0 +1,243 @@ +/* + * OpenRISC MMU. + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Zhizhou Zhang <etouzh@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "qemu-common.h" +#include "gdbstub.h" +#include "host-utils.h" +#ifndef CONFIG_USER_ONLY +#include "hw/loader.h" +#endif + +#ifndef CONFIG_USER_ONLY +int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, int rw) +{ + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; + return TLBRET_MATCH; +} + +int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, int rw) +{ + int vpn = address >> TARGET_PAGE_BITS; + int idx = vpn & ITLB_MASK; + int right = 0; + + if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) { + return TLBRET_NOMATCH; + } + if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) { + return TLBRET_INVALID; + } + + if (cpu->env.sr & SR_SM) { /* supervisor mode */ + if (cpu->env.tlb->itlb[0][idx].tr & SXE) { + right |= PAGE_EXEC; + } + } else { + if (cpu->env.tlb->itlb[0][idx].tr & UXE) { + right |= PAGE_EXEC; + } + } + + if ((rw & 2) && ((right & PAGE_EXEC) == 0)) { + return TLBRET_BADADDR; + } + + *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) | + (address & (TARGET_PAGE_SIZE-1)); + *prot = right; + return TLBRET_MATCH; +} + +int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, int rw) +{ + int vpn = address >> TARGET_PAGE_BITS; + int idx = vpn & DTLB_MASK; + int right = 0; + + if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) { + return TLBRET_NOMATCH; + } + if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) { + return TLBRET_INVALID; + } + + if (cpu->env.sr & SR_SM) { /* supervisor mode */ + if (cpu->env.tlb->dtlb[0][idx].tr & SRE) { + right |= PAGE_READ; + } + if (cpu->env.tlb->dtlb[0][idx].tr & SWE) { + right |= PAGE_WRITE; + } + } else { + if (cpu->env.tlb->dtlb[0][idx].tr & URE) { + right |= PAGE_READ; + } + if (cpu->env.tlb->dtlb[0][idx].tr & UWE) { + right |= PAGE_WRITE; + } + } + + if ((rw & 0) && ((right & PAGE_READ) == 0)) { + return TLBRET_BADADDR; + } + if ((rw & 1) && ((right & PAGE_WRITE) == 0)) { + return TLBRET_BADADDR; + } + + *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) | + (address & (TARGET_PAGE_SIZE-1)); + *prot = right; + return TLBRET_MATCH; +} + +static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu, + target_phys_addr_t *physical, + int *prot, target_ulong address, + int rw) +{ + int ret = TLBRET_MATCH; + + /* [0x0000--0x2000]: unmapped */ + if (address < 0x2000 && (cpu->env.sr & SR_SM)) { + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; + return ret; + } + + if (rw == 2) { /* ITLB */ + *physical = 0; + ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical, + prot, address, rw); + } else { /* DTLB */ + ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical, + prot, address, rw); + } + + return ret; +} +#endif + +static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu, + target_ulong address, + int rw, int tlb_error) +{ + int exception = 0; + + switch (tlb_error) { + default: + if (rw == 2) { + exception = EXCP_IPF; + } else { + exception = EXCP_DPF; + } + break; +#ifndef CONFIG_USER_ONLY + case TLBRET_BADADDR: + if (rw == 2) { + exception = EXCP_IPF; + } else { + exception = EXCP_DPF; + } + break; + case TLBRET_INVALID: + case TLBRET_NOMATCH: + /* No TLB match for a mapped address */ + if (rw == 2) { + exception = EXCP_ITLBMISS; + } else { + exception = EXCP_DTLBMISS; + } + break; +#endif + } + + cpu->env.exception_index = exception; + cpu->env.eear = address; +} + +#ifndef CONFIG_USER_ONLY +int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, + target_ulong address, int rw, int mmu_idx) +{ + int ret = 0; + target_phys_addr_t physical = 0; + int prot = 0; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot, + address, rw); + + if (ret == TLBRET_MATCH) { + tlb_set_page(env, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + mmu_idx, TARGET_PAGE_SIZE); + ret = 0; + } else if (ret < 0) { + cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret); + ret = 1; + } + + return ret; +} +#else +int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, + target_ulong address, int rw, int mmu_idx) +{ + int ret = 0; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret); + ret = 1; + + return ret; +} +#endif + +#ifndef CONFIG_USER_ONLY +target_phys_addr_t cpu_get_phys_page_debug(CPUOpenRISCState *env, + target_ulong addr) +{ + target_phys_addr_t phys_addr; + int prot; + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) { + return -1; + } + + return phys_addr; +} + +void cpu_openrisc_mmu_init(OpenRISCCPU *cpu) +{ + cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext)); + + cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; + cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; +} +#endif diff --git a/target-openrisc/mmu_helper.c b/target-openrisc/mmu_helper.c new file mode 100644 index 0000000000..59ed371ae0 --- /dev/null +++ b/target-openrisc/mmu_helper.c @@ -0,0 +1,63 @@ +/* + * OpenRISC MMU helper routines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Zhizhou Zhang <etouzh@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" + +#ifndef CONFIG_USER_ONLY +#include "softmmu_exec.h" +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +void tlb_fill(CPUOpenRISCState *env, target_ulong addr, int is_write, + int mmu_idx, uintptr_t retaddr) +{ + TranslationBlock *tb; + unsigned long pc; + int ret; + + ret = cpu_openrisc_handle_mmu_fault(env, addr, is_write, mmu_idx); + + if (ret) { + if (retaddr) { + /* now we have a real cpu fault. */ + pc = (unsigned long)retaddr; + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we + have a virtual CPU fault. */ + cpu_restore_state(tb, env, pc); + } + } + /* Raise Exception. */ + cpu_loop_exit(env); + } +} +#endif diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c new file mode 100644 index 0000000000..f160dc397c --- /dev/null +++ b/target-openrisc/sys_helper.c @@ -0,0 +1,287 @@ +/* + * OpenRISC system instructions helper routines + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Zhizhou Zhang <etouzh@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "helper.h" + +#define TO_SPR(group, number) (((group) << 11) + (number)) + +void HELPER(mtspr)(CPUOpenRISCState *env, + target_ulong ra, target_ulong rb, target_ulong offset) +{ +#ifndef CONFIG_USER_ONLY + int spr = (ra | offset); + int idx; + + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + switch (spr) { + case TO_SPR(0, 0): /* VR */ + env->vr = rb; + break; + + case TO_SPR(0, 16): /* NPC */ + env->npc = rb; + break; + + case TO_SPR(0, 17): /* SR */ + if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^ + (rb & (SR_IME | SR_DME | SR_SM))) { + tlb_flush(env, 1); + } + env->sr = rb; + env->sr |= SR_FO; /* FO is const equal to 1 */ + if (env->sr & SR_DME) { + env->tlb->cpu_openrisc_map_address_data = + &cpu_openrisc_get_phys_data; + } else { + env->tlb->cpu_openrisc_map_address_data = + &cpu_openrisc_get_phys_nommu; + } + + if (env->sr & SR_IME) { + env->tlb->cpu_openrisc_map_address_code = + &cpu_openrisc_get_phys_code; + } else { + env->tlb->cpu_openrisc_map_address_code = + &cpu_openrisc_get_phys_nommu; + } + break; + + case TO_SPR(0, 18): /* PPC */ + env->ppc = rb; + break; + + case TO_SPR(0, 32): /* EPCR */ + env->epcr = rb; + break; + + case TO_SPR(0, 48): /* EEAR */ + env->eear = rb; + break; + + case TO_SPR(0, 64): /* ESR */ + env->esr = rb; + break; + case TO_SPR(1, 512) ... TO_SPR(1, 639): /* DTLBW0MR 0-127 */ + idx = spr - TO_SPR(1, 512); + if (!(rb & 1)) { + tlb_flush_page(env, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK); + } + env->tlb->dtlb[0][idx].mr = rb; + break; + + case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */ + idx = spr - TO_SPR(1, 640); + env->tlb->dtlb[0][idx].tr = rb; + break; + case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */ + case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */ + case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */ + case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */ + case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */ + case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ + break; + case TO_SPR(2, 512) ... TO_SPR(2, 639): /* ITLBW0MR 0-127 */ + idx = spr - TO_SPR(2, 512); + if (!(rb & 1)) { + tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK); + } + env->tlb->itlb[0][idx].mr = rb; + break; + + case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */ + idx = spr - TO_SPR(2, 640); + env->tlb->itlb[0][idx].tr = rb; + break; + case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */ + case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */ + case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */ + case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */ + case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */ + case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */ + break; + case TO_SPR(9, 0): /* PICMR */ + env->picmr |= rb; + break; + case TO_SPR(9, 2): /* PICSR */ + env->picsr &= ~rb; + break; + case TO_SPR(10, 0): /* TTMR */ + { + int ip = env->ttmr & TTMR_IP; + + if (rb & TTMR_IP) { /* Keep IP bit. */ + env->ttmr = (rb & ~TTMR_IP) + ip; + } else { /* Clear IP bit. */ + env->ttmr = rb & ~TTMR_IP; + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; + } + + cpu_openrisc_count_update(cpu); + + switch (env->ttmr & TTMR_M) { + case TIMER_NONE: + cpu_openrisc_count_stop(cpu); + break; + case TIMER_INTR: + cpu_openrisc_count_start(cpu); + break; + case TIMER_SHOT: + cpu_openrisc_count_start(cpu); + break; + case TIMER_CONT: + cpu_openrisc_count_start(cpu); + break; + default: + break; + } + } + break; + + case TO_SPR(10, 1): /* TTCR */ + env->ttcr = rb; + if (env->ttmr & TIMER_NONE) { + return; + } + cpu_openrisc_count_start(cpu); + break; + default: + + break; + } +#endif +} + +target_ulong HELPER(mfspr)(CPUOpenRISCState *env, + target_ulong rd, target_ulong ra, uint32_t offset) +{ +#ifndef CONFIG_USER_ONLY + int spr = (ra | offset); + int idx; + + OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + + switch (spr) { + case TO_SPR(0, 0): /* VR */ + return env->vr & SPR_VR; + + case TO_SPR(0, 1): /* UPR */ + return env->upr; /* TT, DM, IM, UP present */ + + case TO_SPR(0, 2): /* CPUCFGR */ + return env->cpucfgr; + + case TO_SPR(0, 3): /* DMMUCFGR */ + return env->dmmucfgr; /* 1Way, 64 entries */ + + case TO_SPR(0, 4): /* IMMUCFGR */ + return env->immucfgr; + + case TO_SPR(0, 16): /* NPC */ + return env->npc; + + case TO_SPR(0, 17): /* SR */ + return env->sr; + + case TO_SPR(0, 18): /* PPC */ + return env->ppc; + + case TO_SPR(0, 32): /* EPCR */ + return env->epcr; + + case TO_SPR(0, 48): /* EEAR */ + return env->eear; + + case TO_SPR(0, 64): /* ESR */ + return env->esr; + + case TO_SPR(1, 512) ... TO_SPR(1, 639): /* DTLBW0MR 0-127 */ + idx = spr - TO_SPR(1, 512); + return env->tlb->dtlb[0][idx].mr; + + case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */ + idx = spr - TO_SPR(1, 640); + return env->tlb->dtlb[0][idx].tr; + + case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */ + case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */ + case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */ + case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */ + case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */ + case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ + break; + + case TO_SPR(2, 512) ... TO_SPR(2, 639): /* ITLBW0MR 0-127 */ + idx = spr - TO_SPR(2, 512); + return env->tlb->itlb[0][idx].mr; + + case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */ + idx = spr - TO_SPR(2, 640); + return env->tlb->itlb[0][idx].tr; + + case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */ + case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */ + case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */ + case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */ + case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */ + case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */ + break; + + case TO_SPR(9, 0): /* PICMR */ + return env->picmr; + + case TO_SPR(9, 2): /* PICSR */ + return env->picsr; + + case TO_SPR(10, 0): /* TTMR */ + return env->ttmr; + + case TO_SPR(10, 1): /* TTCR */ + cpu_openrisc_count_update(cpu); + return env->ttcr; + + default: + break; + } +#endif + +/*If we later need to add tracepoints (or debug printfs) for the return +value, it may be useful to structure the code like this: + +target_ulong ret = 0; + +switch() { +case x: + ret = y; + break; +case z: + ret = 42; + break; +... +} + +later something like trace_spr_read(ret); + +return ret;*/ + + /* for rd is passed in, if rd unchanged, just keep it back. */ + return rd; +} diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c new file mode 100644 index 0000000000..325ba09cb5 --- /dev/null +++ b/target-openrisc/translate.c @@ -0,0 +1,1835 @@ +/* + * OpenRISC translation + * + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> + * Feng Gao <gf91597@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-common.h" +#include "qemu-log.h" +#include "config.h" +#include "bitops.h" + +#include "helper.h" +#define GEN_HELPER 1 +#include "helper.h" + +#define OPENRISC_DISAS + +#ifdef OPENRISC_DISAS +# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) +#else +# define LOG_DIS(...) do { } while (0) +#endif + +typedef struct DisasContext { + TranslationBlock *tb; + target_ulong pc, ppc, npc; + uint32_t tb_flags, synced_flags, flags; + uint32_t is_jmp; + uint32_t mem_idx; + int singlestep_enabled; + uint32_t delayed_branch; +} DisasContext; + +static TCGv_ptr cpu_env; +static TCGv cpu_sr; +static TCGv cpu_R[32]; +static TCGv cpu_pc; +static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ +static TCGv cpu_npc; +static TCGv cpu_ppc; +static TCGv_i32 env_btaken; /* bf/bnf , F flag taken */ +static TCGv_i32 fpcsr; +static TCGv machi, maclo; +static TCGv fpmaddhi, fpmaddlo; +static TCGv_i32 env_flags; +#include "gen-icount.h" + +void openrisc_translate_init(void) +{ + static const char * const regnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + }; + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + cpu_sr = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, sr), "sr"); + env_flags = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUOpenRISCState, flags), + "flags"); + cpu_pc = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, pc), "pc"); + cpu_npc = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, npc), "npc"); + cpu_ppc = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, ppc), "ppc"); + jmp_pc = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc"); + env_btaken = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUOpenRISCState, btaken), + "btaken"); + fpcsr = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUOpenRISCState, fpcsr), + "fpcsr"); + machi = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, machi), + "machi"); + maclo = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, maclo), + "maclo"); + fpmaddhi = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, fpmaddhi), + "fpmaddhi"); + fpmaddlo = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, fpmaddlo), + "fpmaddlo"); + for (i = 0; i < 32; i++) { + cpu_R[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUOpenRISCState, gpr[i]), + regnames[i]); + } +#define GEN_HELPER 2 +#include "helper.h" +} + +/* Writeback SR_F transaltion-space to execution-space. */ +static inline void wb_SR_F(void) +{ + int label; + + label = gen_new_label(); + tcg_gen_andi_tl(cpu_sr, cpu_sr, ~SR_F); + tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, label); + tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_F); + gen_set_label(label); +} + +static inline int zero_extend(unsigned int val, int width) +{ + return val & ((1 << width) - 1); +} + +static inline int sign_extend(unsigned int val, int width) +{ + int sval; + + /* LSL */ + val <<= TARGET_LONG_BITS - width; + sval = val; + /* ASR. */ + sval >>= TARGET_LONG_BITS - width; + return sval; +} + +static inline void gen_sync_flags(DisasContext *dc) +{ + /* Sync the tb dependent flag between translate and runtime. */ + if (dc->tb_flags != dc->synced_flags) { + tcg_gen_movi_tl(env_flags, dc->tb_flags); + dc->synced_flags = dc->tb_flags; + } +} + +static void gen_exception(DisasContext *dc, unsigned int excp) +{ + TCGv_i32 tmp = tcg_const_i32(excp); + gen_helper_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); +} + +static void gen_illegal_exception(DisasContext *dc) +{ + tcg_gen_movi_tl(cpu_pc, dc->pc); + gen_exception(dc, EXCP_ILLEGAL); + dc->is_jmp = DISAS_UPDATE; +} + +/* not used yet, open it when we need or64. */ +/*#ifdef TARGET_OPENRISC64 +static void check_ob64s(DisasContext *dc) +{ + if (!(dc->flags & CPUCFGR_OB64S)) { + gen_illegal_exception(dc); + } +} + +static void check_of64s(DisasContext *dc) +{ + if (!(dc->flags & CPUCFGR_OF64S)) { + gen_illegal_exception(dc); + } +} + +static void check_ov64s(DisasContext *dc) +{ + if (!(dc->flags & CPUCFGR_OV64S)) { + gen_illegal_exception(dc); + } +} +#endif*/ + +static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = dc->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + likely(!dc->singlestep_enabled)) { + tcg_gen_movi_tl(cpu_pc, dest); + tcg_gen_goto_tb(n); + tcg_gen_exit_tb((tcg_target_long)tb + n); + } else { + tcg_gen_movi_tl(cpu_pc, dest); + if (dc->singlestep_enabled) { + gen_exception(dc, EXCP_DEBUG); + } + tcg_gen_exit_tb(0); + } +} + +static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0) +{ + target_ulong tmp_pc; + int lab = gen_new_label(); + TCGv sr_f = tcg_temp_new(); + /* N26, 26bits imm */ + tmp_pc = sign_extend((imm<<2), 26) + dc->pc; + tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); + + if (op0 == 0x00) { /* l.j */ + tcg_gen_movi_tl(jmp_pc, tmp_pc); + } else if (op0 == 0x01) { /* l.jal */ + tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); + tcg_gen_movi_tl(jmp_pc, tmp_pc); + } else if (op0 == 0x03) { /* l.bnf */ + tcg_gen_movi_tl(jmp_pc, dc->pc+8); + tcg_gen_brcondi_i32(TCG_COND_EQ, sr_f, SR_F, lab); + tcg_gen_movi_tl(jmp_pc, tmp_pc); + gen_set_label(lab); + } else if (op0 == 0x04) { /* l.bf */ + tcg_gen_movi_tl(jmp_pc, dc->pc+8); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_f, SR_F, lab); + tcg_gen_movi_tl(jmp_pc, tmp_pc); + gen_set_label(lab); + } else if (op0 == 0x11) { /* l.jr */ + tcg_gen_mov_tl(jmp_pc, cpu_R[reg]); + } else if (op0 == 0x12) { /* l.jalr */ + tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); + tcg_gen_mov_tl(jmp_pc, cpu_R[reg]); + } else { + gen_illegal_exception(dc); + } + + tcg_temp_free(sr_f); + dc->delayed_branch = 2; + dc->tb_flags |= D_FLAG; + gen_sync_flags(dc); +} + +static void dec_calc(DisasContext *dc, uint32_t insn) +{ + uint32_t op0, op1, op2; + uint32_t ra, rb, rd; + op0 = extract32(insn, 0, 4); + op1 = extract32(insn, 8, 2); + op2 = extract32(insn, 6, 2); + ra = extract32(insn, 16, 5); + rb = extract32(insn, 11, 5); + rd = extract32(insn, 21, 5); + + switch (op0) { + case 0x0000: + switch (op1) { + case 0x00: /* l.add */ + LOG_DIS("l.add r%d, r%d, r%d\n", rd, ra, rb); + { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 tb = tcg_temp_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_extu_i32_i64(tb, cpu_R[rb]); + tcg_gen_add_i64(td, ta, tb); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 31); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(tb); + tcg_temp_free_i64(td); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_ove); + } + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0001: /* l.addc */ + switch (op1) { + case 0x00: + LOG_DIS("l.addc r%d, r%d, r%d\n", rd, ra, rb); + { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 tb = tcg_temp_new_i64(); + TCGv_i64 tcy = tcg_temp_local_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_cy = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_extu_i32_i64(tb, cpu_R[rb]); + tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY); + tcg_gen_extu_i32_i64(tcy, sr_cy); + tcg_gen_shri_i64(tcy, tcy, 10); + tcg_gen_add_i64(td, ta, tb); + tcg_gen_add_i64(td, td, tcy); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 32); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(tb); + tcg_temp_free_i64(tcy); + tcg_temp_free_i64(td); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_cy); + tcg_temp_free_i32(sr_ove); + } + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0002: /* l.sub */ + switch (op1) { + case 0x00: + LOG_DIS("l.sub r%d, r%d, r%d\n", rd, ra, rb); + { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 tb = tcg_temp_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_extu_i32_i64(tb, cpu_R[rb]); + tcg_gen_sub_i64(td, ta, tb); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 31); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(tb); + tcg_temp_free_i64(td); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_ove); + } + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0003: /* l.and */ + switch (op1) { + case 0x00: + LOG_DIS("l.and r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_and_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0004: /* l.or */ + switch (op1) { + case 0x00: + LOG_DIS("l.or r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_or_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0005: + switch (op1) { + case 0x00: /* l.xor */ + LOG_DIS("l.xor r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_xor_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0006: + switch (op1) { + case 0x03: /* l.mul */ + LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb); + if (ra != 0 && rb != 0) { + gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + } else { + tcg_gen_movi_tl(cpu_R[rd], 0x0); + } + break; + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0009: + switch (op1) { + case 0x03: /* l.div */ + LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); + { + int lab0 = gen_new_label(); + int lab1 = gen_new_label(); + int lab2 = gen_new_label(); + int lab3 = gen_new_label(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + if (rb == 0) { + tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab0); + } else { + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb], + 0x00000000, lab1); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra], + 0x80000000, lab2); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb], + 0xffffffff, lab2); + gen_set_label(lab1); + tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab3); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab2); + tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + gen_set_label(lab3); + } + tcg_temp_free_i32(sr_ove); + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x000a: + switch (op1) { + case 0x03: /* l.divu */ + LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb); + { + int lab0 = gen_new_label(); + int lab1 = gen_new_label(); + int lab2 = gen_new_label(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + if (rb == 0) { + tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab0); + } else { + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb], + 0x00000000, lab1); + tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab1); + tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + gen_set_label(lab2); + } + tcg_temp_free_i32(sr_ove); + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x000b: + switch (op1) { + case 0x03: /* l.mulu */ + LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); + if (rb != 0 && ra != 0) { + TCGv_i64 result = tcg_temp_local_new_i64(); + TCGv_i64 tra = tcg_temp_local_new_i64(); + TCGv_i64 trb = tcg_temp_local_new_i64(); + TCGv_i64 high = tcg_temp_new_i64(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + int lab = gen_new_label(); + /* Calculate the each result. */ + tcg_gen_extu_i32_i64(tra, cpu_R[ra]); + tcg_gen_extu_i32_i64(trb, cpu_R[rb]); + tcg_gen_mul_i64(result, tra, trb); + tcg_temp_free_i64(tra); + tcg_temp_free_i64(trb); + tcg_gen_shri_i64(high, result, TARGET_LONG_BITS); + /* Overflow or not. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, high, 0x00000000, lab); + tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_temp_free_i64(high); + tcg_gen_trunc_i64_tl(cpu_R[rd], result); + tcg_temp_free_i64(result); + tcg_temp_free_i32(sr_ove); + } else { + tcg_gen_movi_tl(cpu_R[rd], 0); + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x000e: + switch (op1) { + case 0x00: /* l.cmov */ + LOG_DIS("l.cmov r%d, r%d, r%d\n", rd, ra, rb); + { + int lab = gen_new_label(); + TCGv res = tcg_temp_local_new(); + TCGv sr_f = tcg_temp_new(); + tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); + tcg_gen_mov_tl(res, cpu_R[rb]); + tcg_gen_brcondi_tl(TCG_COND_NE, sr_f, SR_F, lab); + tcg_gen_mov_tl(res, cpu_R[ra]); + gen_set_label(lab); + tcg_gen_mov_tl(cpu_R[rd], res); + tcg_temp_free(sr_f); + tcg_temp_free(res); + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x000f: + switch (op1) { + case 0x00: /* l.ff1 */ + LOG_DIS("l.ff1 r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_ff1(cpu_R[rd], cpu_R[ra]); + break; + case 0x01: /* l.fl1 */ + LOG_DIS("l.fl1 r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_fl1(cpu_R[rd], cpu_R[ra]); + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x0008: + switch (op1) { + case 0x00: + switch (op2) { + case 0x00: /* l.sll */ + LOG_DIS("l.sll r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_shl_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + case 0x01: /* l.srl */ + LOG_DIS("l.srl r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_shr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + case 0x02: /* l.sra */ + LOG_DIS("l.sra r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_sar_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + case 0x03: /* l.ror */ + LOG_DIS("l.ror r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_rotr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x000c: + switch (op1) { + case 0x00: + switch (op2) { + case 0x00: /* l.exths */ + LOG_DIS("l.exths r%d, r%d\n", rd, ra); + tcg_gen_ext16s_tl(cpu_R[rd], cpu_R[ra]); + break; + case 0x01: /* l.extbs */ + LOG_DIS("l.extbs r%d, r%d\n", rd, ra); + tcg_gen_ext8s_tl(cpu_R[rd], cpu_R[ra]); + break; + case 0x02: /* l.exthz */ + LOG_DIS("l.exthz r%d, r%d\n", rd, ra); + tcg_gen_ext16u_tl(cpu_R[rd], cpu_R[ra]); + break; + case 0x03: /* l.extbz */ + LOG_DIS("l.extbz r%d, r%d\n", rd, ra); + tcg_gen_ext8u_tl(cpu_R[rd], cpu_R[ra]); + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x000d: + switch (op1) { + case 0x00: + switch (op2) { + case 0x00: /* l.extws */ + LOG_DIS("l.extws r%d, r%d\n", rd, ra); + tcg_gen_ext32s_tl(cpu_R[rd], cpu_R[ra]); + break; + case 0x01: /* l.extwz */ + LOG_DIS("l.extwz r%d, r%d\n", rd, ra); + tcg_gen_ext32u_tl(cpu_R[rd], cpu_R[ra]); + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + default: + gen_illegal_exception(dc); + break; + } +} + +static void dec_misc(DisasContext *dc, uint32_t insn) +{ + uint32_t op0, op1; + uint32_t ra, rb, rd; +#ifdef OPENRISC_DISAS + uint32_t L6, K5; +#endif + uint32_t I16, I5, I11, N26, tmp; + op0 = extract32(insn, 26, 6); + op1 = extract32(insn, 24, 2); + ra = extract32(insn, 16, 5); + rb = extract32(insn, 11, 5); + rd = extract32(insn, 21, 5); +#ifdef OPENRISC_DISAS + L6 = extract32(insn, 5, 6); + K5 = extract32(insn, 0, 5); +#endif + I16 = extract32(insn, 0, 16); + I5 = extract32(insn, 21, 5); + I11 = extract32(insn, 0, 11); + N26 = extract32(insn, 0, 26); + tmp = (I5<<11) + I11; + + switch (op0) { + case 0x00: /* l.j */ + LOG_DIS("l.j %d\n", N26); + gen_jump(dc, N26, 0, op0); + break; + + case 0x01: /* l.jal */ + LOG_DIS("l.jal %d\n", N26); + gen_jump(dc, N26, 0, op0); + break; + + case 0x03: /* l.bnf */ + LOG_DIS("l.bnf %d\n", N26); + gen_jump(dc, N26, 0, op0); + break; + + case 0x04: /* l.bf */ + LOG_DIS("l.bf %d\n", N26); + gen_jump(dc, N26, 0, op0); + break; + + case 0x05: + switch (op1) { + case 0x01: /* l.nop */ + LOG_DIS("l.nop %d\n", I16); + break; + + default: + gen_illegal_exception(dc); + break; + } + break; + + case 0x11: /* l.jr */ + LOG_DIS("l.jr r%d\n", rb); + gen_jump(dc, 0, rb, op0); + break; + + case 0x12: /* l.jalr */ + LOG_DIS("l.jalr r%d\n", rb); + gen_jump(dc, 0, rb, op0); + break; + + case 0x13: /* l.maci */ + LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11); + { + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i32 dst = tcg_temp_new_i32(); + TCGv ttmp = tcg_const_tl(tmp); + tcg_gen_mul_tl(dst, cpu_R[ra], ttmp); + tcg_gen_ext_i32_i64(t1, dst); + tcg_gen_concat_i32_i64(t2, maclo, machi); + tcg_gen_add_i64(t2, t2, t1); + tcg_gen_trunc_i64_i32(maclo, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_i32(machi, t2); + tcg_temp_free_i32(dst); + tcg_temp_free(ttmp); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + } + break; + + case 0x09: /* l.rfe */ + LOG_DIS("l.rfe\n"); + { +#if defined(CONFIG_USER_ONLY) + return; +#else + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } + gen_helper_rfe(cpu_env); + dc->is_jmp = DISAS_UPDATE; +#endif + } + break; + + case 0x1c: /* l.cust1 */ + LOG_DIS("l.cust1\n"); + break; + + case 0x1d: /* l.cust2 */ + LOG_DIS("l.cust2\n"); + break; + + case 0x1e: /* l.cust3 */ + LOG_DIS("l.cust3\n"); + break; + + case 0x1f: /* l.cust4 */ + LOG_DIS("l.cust4\n"); + break; + + case 0x3c: /* l.cust5 */ + LOG_DIS("l.cust5 r%d, r%d, r%d, %d, %d\n", rd, ra, rb, L6, K5); + break; + + case 0x3d: /* l.cust6 */ + LOG_DIS("l.cust6\n"); + break; + + case 0x3e: /* l.cust7 */ + LOG_DIS("l.cust7\n"); + break; + + case 0x3f: /* l.cust8 */ + LOG_DIS("l.cust8\n"); + break; + +/* not used yet, open it when we need or64. */ +/*#ifdef TARGET_OPENRISC64 + case 0x20: l.ld + LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16); + { + check_ob64s(dc); + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_addi_i64(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free_i64(t0); + } + break; +#endif*/ + + case 0x21: /* l.lwz */ + LOG_DIS("l.lwz r%d, r%d, %d\n", rd, ra, I16); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld32u(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x22: /* l.lws */ + LOG_DIS("l.lws r%d, r%d, %d\n", rd, ra, I16); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld32s(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x23: /* l.lbz */ + LOG_DIS("l.lbz r%d, r%d, %d\n", rd, ra, I16); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld8u(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x24: /* l.lbs */ + LOG_DIS("l.lbs r%d, r%d, %d\n", rd, ra, I16); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld8s(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x25: /* l.lhz */ + LOG_DIS("l.lhz r%d, r%d, %d\n", rd, ra, I16); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld16u(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x26: /* l.lhs */ + LOG_DIS("l.lhs r%d, r%d, %d\n", rd, ra, I16); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_qemu_ld16s(cpu_R[rd], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x27: /* l.addi */ + LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16); + { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 32); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(td); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_ove); + } + break; + + case 0x28: /* l.addic */ + LOG_DIS("l.addic r%d, r%d, %d\n", rd, ra, I16); + { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i64 tcy = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_cy = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY); + tcg_gen_shri_i32(sr_cy, sr_cy, 10); + tcg_gen_extu_i32_i64(tcy, sr_cy); + tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); + tcg_gen_add_i64(td, td, tcy); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 32); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(td); + tcg_temp_free_i64(tcy); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_cy); + tcg_temp_free_i32(sr_ove); + } + break; + + case 0x29: /* l.andi */ + LOG_DIS("l.andi r%d, r%d, %d\n", rd, ra, I16); + tcg_gen_andi_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16)); + break; + + case 0x2a: /* l.ori */ + LOG_DIS("l.ori r%d, r%d, %d\n", rd, ra, I16); + tcg_gen_ori_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16)); + break; + + case 0x2b: /* l.xori */ + LOG_DIS("l.xori r%d, r%d, %d\n", rd, ra, I16); + tcg_gen_xori_tl(cpu_R[rd], cpu_R[ra], sign_extend(I16, 16)); + break; + + case 0x2c: /* l.muli */ + LOG_DIS("l.muli r%d, r%d, %d\n", rd, ra, I16); + if (ra != 0 && I16 != 0) { + TCGv_i32 im = tcg_const_i32(I16); + gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], im); + tcg_temp_free_i32(im); + } else { + tcg_gen_movi_tl(cpu_R[rd], 0x0); + } + break; + + case 0x2d: /* l.mfspr */ + LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16); + { +#if defined(CONFIG_USER_ONLY) + return; +#else + TCGv_i32 ti = tcg_const_i32(I16); + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } + gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti); + tcg_temp_free_i32(ti); +#endif + } + break; + + case 0x30: /* l.mtspr */ + LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11); + { +#if defined(CONFIG_USER_ONLY) + return; +#else + TCGv_i32 im = tcg_const_i32(tmp); + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } + gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im); + tcg_temp_free_i32(im); +#endif + } + break; + +/* not used yet, open it when we need or64. */ +/*#ifdef TARGET_OPENRISC64 + case 0x34: l.sd + LOG_DIS("l.sd %d, r%d, r%d, %d\n", I5, ra, rb, I11); + { + check_ob64s(dc); + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16)); + tcg_gen_qemu_st64(cpu_R[rb], t0, dc->mem_idx); + tcg_temp_free_i64(t0); + } + break; +#endif*/ + + case 0x35: /* l.sw */ + LOG_DIS("l.sw %d, r%d, r%d, %d\n", I5, ra, rb, I11); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16)); + tcg_gen_qemu_st32(cpu_R[rb], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x36: /* l.sb */ + LOG_DIS("l.sb %d, r%d, r%d, %d\n", I5, ra, rb, I11); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16)); + tcg_gen_qemu_st8(cpu_R[rb], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + case 0x37: /* l.sh */ + LOG_DIS("l.sh %d, r%d, r%d, %d\n", I5, ra, rb, I11); + { + TCGv t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16)); + tcg_gen_qemu_st16(cpu_R[rb], t0, dc->mem_idx); + tcg_temp_free(t0); + } + break; + + default: + gen_illegal_exception(dc); + break; + } +} + +static void dec_mac(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; + uint32_t ra, rb; + op0 = extract32(insn, 0, 4); + ra = extract32(insn, 16, 5); + rb = extract32(insn, 11, 5); + + switch (op0) { + case 0x0001: /* l.mac */ + LOG_DIS("l.mac r%d, r%d\n", ra, rb); + { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]); + tcg_gen_ext_i32_i64(t1, t0); + tcg_gen_concat_i32_i64(t2, maclo, machi); + tcg_gen_add_i64(t2, t2, t1); + tcg_gen_trunc_i64_i32(maclo, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_i32(machi, t2); + tcg_temp_free_i32(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + } + break; + + case 0x0002: /* l.msb */ + LOG_DIS("l.msb r%d, r%d\n", ra, rb); + { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]); + tcg_gen_ext_i32_i64(t1, t0); + tcg_gen_concat_i32_i64(t2, maclo, machi); + tcg_gen_sub_i64(t2, t2, t1); + tcg_gen_trunc_i64_i32(maclo, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_i32(machi, t2); + tcg_temp_free_i32(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + } + break; + + default: + gen_illegal_exception(dc); + break; + } +} + +static void dec_logic(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; + uint32_t rd, ra, L6; + op0 = extract32(insn, 6, 2); + rd = extract32(insn, 21, 5); + ra = extract32(insn, 16, 5); + L6 = extract32(insn, 0, 6); + + switch (op0) { + case 0x00: /* l.slli */ + LOG_DIS("l.slli r%d, r%d, %d\n", rd, ra, L6); + tcg_gen_shli_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); + break; + + case 0x01: /* l.srli */ + LOG_DIS("l.srli r%d, r%d, %d\n", rd, ra, L6); + tcg_gen_shri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); + break; + + case 0x02: /* l.srai */ + LOG_DIS("l.srai r%d, r%d, %d\n", rd, ra, L6); + tcg_gen_sari_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); break; + + case 0x03: /* l.rori */ + LOG_DIS("l.rori r%d, r%d, %d\n", rd, ra, L6); + tcg_gen_rotri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); + break; + + default: + gen_illegal_exception(dc); + break; + } +} + +static void dec_M(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; + uint32_t rd; + uint32_t K16; + op0 = extract32(insn, 16, 1); + rd = extract32(insn, 21, 5); + K16 = extract32(insn, 0, 16); + + switch (op0) { + case 0x0: /* l.movhi */ + LOG_DIS("l.movhi r%d, %d\n", rd, K16); + tcg_gen_movi_tl(cpu_R[rd], (K16 << 16)); + break; + + case 0x1: /* l.macrc */ + LOG_DIS("l.macrc r%d\n", rd); + tcg_gen_mov_tl(cpu_R[rd], maclo); + tcg_gen_movi_tl(maclo, 0x0); + tcg_gen_movi_tl(machi, 0x0); + break; + + default: + gen_illegal_exception(dc); + break; + } +} + +static void dec_comp(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; + uint32_t ra, rb; + + op0 = extract32(insn, 21, 5); + ra = extract32(insn, 16, 5); + rb = extract32(insn, 11, 5); + + tcg_gen_movi_i32(env_btaken, 0x0); + /* unsigned integers */ + tcg_gen_ext32u_tl(cpu_R[ra], cpu_R[ra]); + tcg_gen_ext32u_tl(cpu_R[rb], cpu_R[rb]); + + switch (op0) { + case 0x0: /* l.sfeq */ + LOG_DIS("l.sfeq r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0x1: /* l.sfne */ + LOG_DIS("l.sfne r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_NE, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0x2: /* l.sfgtu */ + LOG_DIS("l.sfgtu r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0x3: /* l.sfgeu */ + LOG_DIS("l.sfgeu r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0x4: /* l.sfltu */ + LOG_DIS("l.sfltu r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0x5: /* l.sfleu */ + LOG_DIS("l.sfleu r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0xa: /* l.sfgts */ + LOG_DIS("l.sfgts r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_GT, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0xb: /* l.sfges */ + LOG_DIS("l.sfges r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_GE, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0xc: /* l.sflts */ + LOG_DIS("l.sflts r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_LT, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + case 0xd: /* l.sfles */ + LOG_DIS("l.sfles r%d, r%d\n", ra, rb); + tcg_gen_setcond_tl(TCG_COND_LE, env_btaken, cpu_R[ra], cpu_R[rb]); + break; + + default: + gen_illegal_exception(dc); + break; + } + wb_SR_F(); +} + +static void dec_compi(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; + uint32_t ra, I16; + + op0 = extract32(insn, 21, 5); + ra = extract32(insn, 16, 5); + I16 = extract32(insn, 0, 16); + + tcg_gen_movi_i32(env_btaken, 0x0); + I16 = sign_extend(I16, 16); + + switch (op0) { + case 0x0: /* l.sfeqi */ + LOG_DIS("l.sfeqi r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], I16); + break; + + case 0x1: /* l.sfnei */ + LOG_DIS("l.sfnei r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_NE, env_btaken, cpu_R[ra], I16); + break; + + case 0x2: /* l.sfgtui */ + LOG_DIS("l.sfgtui r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], I16); + break; + + case 0x3: /* l.sfgeui */ + LOG_DIS("l.sfgeui r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], I16); + break; + + case 0x4: /* l.sfltui */ + LOG_DIS("l.sfltui r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], I16); + break; + + case 0x5: /* l.sfleui */ + LOG_DIS("l.sfleui r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], I16); + break; + + case 0xa: /* l.sfgtsi */ + LOG_DIS("l.sfgtsi r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_GT, env_btaken, cpu_R[ra], I16); + break; + + case 0xb: /* l.sfgesi */ + LOG_DIS("l.sfgesi r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_GE, env_btaken, cpu_R[ra], I16); + break; + + case 0xc: /* l.sfltsi */ + LOG_DIS("l.sfltsi r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_LT, env_btaken, cpu_R[ra], I16); + break; + + case 0xd: /* l.sflesi */ + LOG_DIS("l.sflesi r%d, %d\n", ra, I16); + tcg_gen_setcondi_tl(TCG_COND_LE, env_btaken, cpu_R[ra], I16); + break; + + default: + gen_illegal_exception(dc); + break; + } + wb_SR_F(); +} + +static void dec_sys(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; +#ifdef OPENRISC_DISAS + uint32_t K16; +#endif + op0 = extract32(insn, 16, 8); +#ifdef OPENRISC_DISAS + K16 = extract32(insn, 0, 16); +#endif + + switch (op0) { + case 0x000: /* l.sys */ + LOG_DIS("l.sys %d\n", K16); + tcg_gen_movi_tl(cpu_pc, dc->pc); + gen_exception(dc, EXCP_SYSCALL); + dc->is_jmp = DISAS_UPDATE; + break; + + case 0x100: /* l.trap */ + LOG_DIS("l.trap %d\n", K16); +#if defined(CONFIG_USER_ONLY) + return; +#else + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } + tcg_gen_movi_tl(cpu_pc, dc->pc); + gen_exception(dc, EXCP_TRAP); +#endif + break; + + case 0x300: /* l.csync */ + LOG_DIS("l.csync\n"); +#if defined(CONFIG_USER_ONLY) + return; +#else + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } +#endif + break; + + case 0x200: /* l.msync */ + LOG_DIS("l.msync\n"); +#if defined(CONFIG_USER_ONLY) + return; +#else + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } +#endif + break; + + case 0x270: /* l.psync */ + LOG_DIS("l.psync\n"); +#if defined(CONFIG_USER_ONLY) + return; +#else + if (dc->mem_idx == MMU_USER_IDX) { + gen_illegal_exception(dc); + return; + } +#endif + break; + + default: + gen_illegal_exception(dc); + break; + } +} + +static void dec_float(DisasContext *dc, uint32_t insn) +{ + uint32_t op0; + uint32_t ra, rb, rd; + op0 = extract32(insn, 0, 8); + ra = extract32(insn, 16, 5); + rb = extract32(insn, 11, 5); + rd = extract32(insn, 21, 5); + + switch (op0) { + case 0x00: /* lf.add.s */ + LOG_DIS("lf.add.s r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_float_add_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x01: /* lf.sub.s */ + LOG_DIS("lf.sub.s r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_float_sub_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + + case 0x02: /* lf.mul.s */ + LOG_DIS("lf.mul.s r%d, r%d, r%d\n", rd, ra, rb); + if (ra != 0 && rb != 0) { + gen_helper_float_mul_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + } else { + tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF); + tcg_gen_movi_i32(cpu_R[rd], 0x0); + } + break; + + case 0x03: /* lf.div.s */ + LOG_DIS("lf.div.s r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_float_div_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x04: /* lf.itof.s */ + LOG_DIS("lf.itof r%d, r%d\n", rd, ra); + gen_helper_itofs(cpu_R[rd], cpu_env, cpu_R[ra]); + break; + + case 0x05: /* lf.ftoi.s */ + LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra); + gen_helper_ftois(cpu_R[rd], cpu_env, cpu_R[ra]); + break; + + case 0x06: /* lf.rem.s */ + LOG_DIS("lf.rem.s r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_float_rem_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x07: /* lf.madd.s */ + LOG_DIS("lf.madd.s r%d, r%d, r%d\n", rd, ra, rb); + gen_helper_float_muladd_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x08: /* lf.sfeq.s */ + LOG_DIS("lf.sfeq.s r%d, r%d\n", ra, rb); + gen_helper_float_eq_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x09: /* lf.sfne.s */ + LOG_DIS("lf.sfne.s r%d, r%d\n", ra, rb); + gen_helper_float_ne_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x0a: /* lf.sfgt.s */ + LOG_DIS("lf.sfgt.s r%d, r%d\n", ra, rb); + gen_helper_float_gt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x0b: /* lf.sfge.s */ + LOG_DIS("lf.sfge.s r%d, r%d\n", ra, rb); + gen_helper_float_ge_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x0c: /* lf.sflt.s */ + LOG_DIS("lf.sflt.s r%d, r%d\n", ra, rb); + gen_helper_float_lt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x0d: /* lf.sfle.s */ + LOG_DIS("lf.sfle.s r%d, r%d\n", ra, rb); + gen_helper_float_le_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + +/* not used yet, open it when we need or64. */ +/*#ifdef TARGET_OPENRISC64 + case 0x10: lf.add.d + LOG_DIS("lf.add.d r%d, r%d, r%d\n", rd, ra, rb); + check_of64s(dc); + gen_helper_float_add_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x11: lf.sub.d + LOG_DIS("lf.sub.d r%d, r%d, r%d\n", rd, ra, rb); + check_of64s(dc); + gen_helper_float_sub_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x12: lf.mul.d + LOG_DIS("lf.mul.d r%d, r%d, r%d\n", rd, ra, rb); + check_of64s(dc); + if (ra != 0 && rb != 0) { + gen_helper_float_mul_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + } else { + tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF); + tcg_gen_movi_i64(cpu_R[rd], 0x0); + } + break; + + case 0x13: lf.div.d + LOG_DIS("lf.div.d r%d, r%d, r%d\n", rd, ra, rb); + check_of64s(dc); + gen_helper_float_div_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x14: lf.itof.d + LOG_DIS("lf.itof r%d, r%d\n", rd, ra); + check_of64s(dc); + gen_helper_itofd(cpu_R[rd], cpu_env, cpu_R[ra]); + break; + + case 0x15: lf.ftoi.d + LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra); + check_of64s(dc); + gen_helper_ftoid(cpu_R[rd], cpu_env, cpu_R[ra]); + break; + + case 0x16: lf.rem.d + LOG_DIS("lf.rem.d r%d, r%d, r%d\n", rd, ra, rb); + check_of64s(dc); + gen_helper_float_rem_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x17: lf.madd.d + LOG_DIS("lf.madd.d r%d, r%d, r%d\n", rd, ra, rb); + check_of64s(dc); + gen_helper_float_muladd_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x18: lf.sfeq.d + LOG_DIS("lf.sfeq.d r%d, r%d\n", ra, rb); + check_of64s(dc); + gen_helper_float_eq_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x1a: lf.sfgt.d + LOG_DIS("lf.sfgt.d r%d, r%d\n", ra, rb); + check_of64s(dc); + gen_helper_float_gt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x1b: lf.sfge.d + LOG_DIS("lf.sfge.d r%d, r%d\n", ra, rb); + check_of64s(dc); + gen_helper_float_ge_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x19: lf.sfne.d + LOG_DIS("lf.sfne.d r%d, r%d\n", ra, rb); + check_of64s(dc); + gen_helper_float_ne_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x1c: lf.sflt.d + LOG_DIS("lf.sflt.d r%d, r%d\n", ra, rb); + check_of64s(dc); + gen_helper_float_lt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; + + case 0x1d: lf.sfle.d + LOG_DIS("lf.sfle.d r%d, r%d\n", ra, rb); + check_of64s(dc); + gen_helper_float_le_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + break; +#endif*/ + + default: + gen_illegal_exception(dc); + break; + } + wb_SR_F(); +} + +static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu) +{ + uint32_t op0; + uint32_t insn; + insn = cpu_ldl_code(&cpu->env, dc->pc); + op0 = extract32(insn, 26, 6); + + switch (op0) { + case 0x06: + dec_M(dc, insn); + break; + + case 0x08: + dec_sys(dc, insn); + break; + + case 0x2e: + dec_logic(dc, insn); + break; + + case 0x2f: + dec_compi(dc, insn); + break; + + case 0x31: + dec_mac(dc, insn); + break; + + case 0x32: + dec_float(dc, insn); + break; + + case 0x38: + dec_calc(dc, insn); + break; + + case 0x39: + dec_comp(dc, insn); + break; + + default: + dec_misc(dc, insn); + break; + } +} + +static void check_breakpoint(OpenRISCCPU *cpu, DisasContext *dc) +{ + CPUBreakpoint *bp; + + if (unlikely(!QTAILQ_EMPTY(&cpu->env.breakpoints))) { + QTAILQ_FOREACH(bp, &cpu->env.breakpoints, entry) { + if (bp->pc == dc->pc) { + tcg_gen_movi_tl(cpu_pc, dc->pc); + gen_exception(dc, EXCP_DEBUG); + dc->is_jmp = DISAS_UPDATE; + } + } + } +} + +static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, + TranslationBlock *tb, + int search_pc) +{ + struct DisasContext ctx, *dc = &ctx; + uint16_t *gen_opc_end; + uint32_t pc_start; + int j, k; + uint32_t next_page_start; + int num_insns; + int max_insns; + + qemu_log_try_set_file(stderr); + + pc_start = tb->pc; + dc->tb = tb; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + dc->is_jmp = DISAS_NEXT; + dc->ppc = pc_start; + dc->pc = pc_start; + dc->flags = cpu->env.cpucfgr; + dc->mem_idx = cpu_mmu_index(&cpu->env); + dc->synced_flags = dc->tb_flags = tb->flags; + dc->delayed_branch = !!(dc->tb_flags & D_FLAG); + dc->singlestep_enabled = cpu->env.singlestep_enabled; + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("-----------------------------------------\n"); + log_cpu_state(&cpu->env, 0); + } + + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + k = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + + gen_icount_start(); + + do { + check_breakpoint(cpu, dc); + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (k < j) { + k++; + while (k < j) { + gen_opc_instr_start[k++] = 0; + } + } + gen_opc_pc[k] = dc->pc; + gen_opc_instr_start[k] = 1; + gen_opc_icount[k] = num_insns; + } + + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + tcg_gen_debug_insn_start(dc->pc); + } + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); + } + dc->ppc = dc->pc - 4; + dc->npc = dc->pc + 4; + tcg_gen_movi_tl(cpu_ppc, dc->ppc); + tcg_gen_movi_tl(cpu_npc, dc->npc); + disas_openrisc_insn(dc, cpu); + dc->pc = dc->npc; + num_insns++; + /* delay slot */ + if (dc->delayed_branch) { + dc->delayed_branch--; + if (!dc->delayed_branch) { + dc->tb_flags &= ~D_FLAG; + gen_sync_flags(dc); + tcg_gen_mov_tl(cpu_pc, jmp_pc); + tcg_gen_mov_tl(cpu_npc, jmp_pc); + tcg_gen_movi_tl(jmp_pc, 0); + tcg_gen_exit_tb(0); + dc->is_jmp = DISAS_JUMP; + break; + } + } + } while (!dc->is_jmp + && gen_opc_ptr < gen_opc_end + && !cpu->env.singlestep_enabled + && !singlestep + && (dc->pc < next_page_start) + && num_insns < max_insns); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + if (dc->is_jmp == DISAS_NEXT) { + dc->is_jmp = DISAS_UPDATE; + tcg_gen_movi_tl(cpu_pc, dc->pc); + } + if (unlikely(cpu->env.singlestep_enabled)) { + if (dc->is_jmp == DISAS_NEXT) { + tcg_gen_movi_tl(cpu_pc, dc->pc); + } + gen_exception(dc, EXCP_DEBUG); + } else { + switch (dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 0, dc->pc); + break; + default: + case DISAS_JUMP: + break; + case DISAS_UPDATE: + /* indicate that the hash table must be used + to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } + } + + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + k++; + while (k <= j) { + gen_opc_instr_start[k++] = 0; + } + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("\n"); + log_target_disas(pc_start, dc->pc - pc_start, 0); + qemu_log("\nisize=%d osize=%td\n", + dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); + } +#endif +} + +void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(openrisc_env_get_cpu(env), tb, 0); +} + +void gen_intermediate_code_pc(CPUOpenRISCState *env, + struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(openrisc_env_get_cpu(env), tb, 1); +} + +void cpu_dump_state(CPUOpenRISCState *env, FILE *f, + fprintf_function cpu_fprintf, + int flags) +{ + int i; + uint32_t *regs = env->gpr; + cpu_fprintf(f, "PC=%08x\n", env->pc); + for (i = 0; i < 32; ++i) { + cpu_fprintf(f, "R%02d=%08x%c", i, regs[i], + (i % 4) == 3 ? '\n' : ' '); + } +} + +void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb, + int pc_pos) +{ + env->pc = gen_opc_pc[pc_pos]; +} diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index b883e6bb72..1900bd5d44 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -2366,10 +2366,18 @@ static void disas_xtensa_insn(DisasContext *dc) case 5: /*BBC*/ /*BBS*/ gen_window_check2(dc, RRI8_S, RRI8_T); { - TCGv_i32 bit = tcg_const_i32(1); +#ifdef TARGET_WORDS_BIGENDIAN + TCGv_i32 bit = tcg_const_i32(0x80000000); +#else + TCGv_i32 bit = tcg_const_i32(0x00000001); +#endif TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f); +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_shr_i32(bit, bit, tmp); +#else tcg_gen_shl_i32(bit, bit, tmp); +#endif tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit); gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); tcg_temp_free(tmp); @@ -2383,7 +2391,11 @@ static void disas_xtensa_insn(DisasContext *dc) { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, cpu_R[RRI8_S], - 1 << (((RRI8_R & 1) << 4) | RRI8_T)); +#ifdef TARGET_WORDS_BIGENDIAN + 0x80000000 >> (((RRI8_R & 1) << 4) | RRI8_T)); +#else + 0x00000001 << (((RRI8_R & 1) << 4) | RRI8_T)); +#endif gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); tcg_temp_free(tmp); } diff --git a/tests/Makefile b/tests/Makefile index 9675ba7c13..f3f4159c25 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -147,3 +147,5 @@ check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS)) check-unit: $(patsubst %,check-%, $(check-unit-y)) check-block: $(patsubst %,check-%, $(check-block-y)) check: check-unit check-qtest + +-include $(wildcard tests/*.d) diff --git a/tests/tcg/openrisc/Makefile b/tests/tcg/openrisc/Makefile new file mode 100644 index 0000000000..7e65888761 --- /dev/null +++ b/tests/tcg/openrisc/Makefile @@ -0,0 +1,71 @@ +-include ../../config-host.mak + +CROSS = or32-linux- + +SIM = qemu-or32 + +CC = $(CROSS)gcc + +TESTCASES = test_add.tst +TESTCASES += test_sub.tst +TESTCASES += test_addc.tst +TESTCASES += test_addi.tst +TESTCASES += test_addic.tst +TESTCASES += test_and_or.tst +TESTCASES += test_bf.tst +TESTCASES += test_bnf.tst +TESTCASES += test_div.tst +TESTCASES += test_divu.tst +TESTCASES += test_extx.tst +TESTCASES += test_fx.tst +TESTCASES += test_jal.tst +TESTCASES += test_j.tst +TESTCASES += test_lf_div.tst +TESTCASES += test_lf_eqs.tst +TESTCASES += test_lf_ges.tst +TESTCASES += test_lf_gts.tst +TESTCASES += test_lf_les.tst +TESTCASES += test_lf_lts.tst +TESTCASES += test_lf_mul.tst +TESTCASES += test_lf_nes.tst +TESTCASES += test_lf_rem.tst +TESTCASES += test_lf_sub.tst +TESTCASES += test_lf_add.tst +TESTCASES += test_logic.tst +TESTCASES += test_lx.tst +TESTCASES += test_movhi.tst +TESTCASES += test_mul.tst +TESTCASES += test_mulu.tst +TESTCASES += test_muli.tst +TESTCASES += test_sfeq.tst +TESTCASES += test_sfeqi.tst +TESTCASES += test_sfges.tst +TESTCASES += test_sfgesi.tst +TESTCASES += test_sfgeu.tst +TESTCASES += test_sfgeui.tst +TESTCASES += test_sfgts.tst +TESTCASES += test_sfgtsi.tst +TESTCASES += test_sfgtu.tst +TESTCASES += test_sfgtui.tst +TESTCASES += test_sfles.tst +TESTCASES += test_sflesi.tst +TESTCASES += test_sfleu.tst +TESTCASES += test_sfleui.tst +TESTCASES += test_sflts.tst +TESTCASES += test_sfltsi.tst +TESTCASES += test_sfltu.tst +TESTCASES += test_sfltui.tst +TESTCASES += test_sfne.tst +TESTCASES += test_sfnei.tst + +all: $(TESTCASES) + +%.tst: %.c + $(CC) -static $< -o $@ + + +check: $(TESTCASES) + @for case in $(TESTCASES); do $(SIM) $$case; echo $$case pass!; sleep 0.2; done + +clean: + $(RM) -rf $(TESTCASES) diff --git a/tests/tcg/openrisc/test_add.c b/tests/tcg/openrisc/test_add.c new file mode 100644 index 0000000000..3d23592e76 --- /dev/null +++ b/tests/tcg/openrisc/test_add.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, d; + int result; + + a = 0x100; + b = 0x100; + result = 0x200; + __asm + ("l.add %0, %0, %1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("add error\n"); + return -1; + } + + a = 0xffff; + b = 0x1; + result = 0x10000; + __asm + ("l.add %0, %0, %1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("add error\n"); + return -1; + } + + a = 0x7fffffff; + b = 0x1; + __asm + ("l.add %0, %1, %2\n\t" + : "=r"(d) + : "r"(b), "r"(a) + ); + + return 0; +} diff --git a/tests/tcg/openrisc/test_addc.c b/tests/tcg/openrisc/test_addc.c new file mode 100644 index 0000000000..05d18f8ce5 --- /dev/null +++ b/tests/tcg/openrisc/test_addc.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x01; + c = 0xffffffff; + result = 1; + __asm + ("l.addc %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("first addc error\n"); + return -1; + } + + b = 0x01; + c = 0xffffffff; + result = 0x80000001; + __asm + ("l.addc %0, %1, %2\n\t" + "l.movhi %2, 0x7fff\n\t" + "l.ori %2, %2, 0xffff\n\t" + "l.addc %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("addc error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_addi.c b/tests/tcg/openrisc/test_addi.c new file mode 100644 index 0000000000..bbf5a5ffab --- /dev/null +++ b/tests/tcg/openrisc/test_addi.c @@ -0,0 +1,33 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + b = 0x01; + result = 0x00; + __asm + ("l.addi %0, %1, 0xffff\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("addi error\n\t"); + return -1; + } + + b = 0x010000; + result = 0xffff; + __asm + ("l.addi %0, %1, 0xffff\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("addi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_addic.c b/tests/tcg/openrisc/test_addic.c new file mode 100644 index 0000000000..4ba7432521 --- /dev/null +++ b/tests/tcg/openrisc/test_addic.c @@ -0,0 +1,33 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + a = 1; + result = 0x1; + __asm + ("l.addic %0, %0, 0xffff\n\t" + : "+r"(a) + ); + if (a != result) { + printf("first addic error\n"); + return -1; + } + + a = 0x1; + result = 0x201; + __asm + ("l.addic %0, %0, 0xffff\n\t" + "l.ori %0, r0, 0x100\n\t" + "l.addic %0, %0, 0x100\n\t" + : "+r"(a) + ); + if (a != result) { + printf("second addic error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_and_or.c b/tests/tcg/openrisc/test_and_or.c new file mode 100644 index 0000000000..810d868c7b --- /dev/null +++ b/tests/tcg/openrisc/test_and_or.c @@ -0,0 +1,65 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x2; + c = 0x1; + result = 0; + __asm + ("l.and %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("and error\n"); + return -1; + } + + result = 0x2; + __asm + ("l.andi %0, %1, 0x3\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("andi error %x\n", a); + return -1; + } + + result = 0x3; + __asm + ("l.or %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("or error\n"); + return -1; + } + + result = 0x3; + __asm + ("l.xor %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("xor error\n"); + return -1; + } + + __asm + ("l.xori %0, %1, 0x1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("xori error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_bf.c b/tests/tcg/openrisc/test_bf.c new file mode 100644 index 0000000000..79f3fb99aa --- /dev/null +++ b/tests/tcg/openrisc/test_bf.c @@ -0,0 +1,47 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + a = 0; + b = 10; + c = 11; + result = 0x2; + __asm + ("1:\n\t" + "l.addi %1, %1, 0x01\n\t" + "l.addi %0, %0, 0x01\n\t" + "l.sfeq %1, %2\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sfeq error\n"); + return -1; + } + + a = 0x00; + b = 0x11; + c = 0x11; + result = 0x01; + __asm + ("1:\n\t" + "l.addi %1, %1, 0x01\n\t" + "l.addi %0, %0, 0x01\n\t" + "l.sfeq %1, %2\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sfeq error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_bnf.c b/tests/tcg/openrisc/test_bnf.c new file mode 100644 index 0000000000..f716215f10 --- /dev/null +++ b/tests/tcg/openrisc/test_bnf.c @@ -0,0 +1,51 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + b = 0; + result = 0x3; + __asm + ("l.sfeqi %1, 0x0\n\t" + "l.bnf 1f\n\t" + "l.nop\n\t" + "\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "\n\t" + "1:\n\t" + "l.addi %0, %0, 0x1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("l.bnf error\n"); + return -1; + } + + a = 0; + b = 0; + result = 1; + __asm + ("l.sfeqi %1, 0x1\n\t" + "l.bnf 1f\n\t" + "l.nop\n\t" + "\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "\n\t" + "1:\n\t" + "l.addi %0, %0, 0x1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("l.bnf error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_div.c b/tests/tcg/openrisc/test_div.c new file mode 100644 index 0000000000..9b65f6e673 --- /dev/null +++ b/tests/tcg/openrisc/test_div.c @@ -0,0 +1,54 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x120; + c = 0x4; + result = 0x48; + __asm + ("l.div %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("div error\n"); + return -1; + } + + result = 0x4; + __asm + ("l.div %0, %1, %0\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("div error\n"); + return -1; + } + + b = 0xffffffff; + c = 0x80000000; + result = 0; + __asm + ("l.div %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("div error\n"); + return -1; + } + + b = 0x80000000; + c = 0xffffffff; + __asm + ("l.div %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + + return 0; +} diff --git a/tests/tcg/openrisc/test_divu.c b/tests/tcg/openrisc/test_divu.c new file mode 100644 index 0000000000..bff9e3ea59 --- /dev/null +++ b/tests/tcg/openrisc/test_divu.c @@ -0,0 +1,34 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x120; + c = 0x4; + result = 0x48; + + __asm + ("l.divu %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("divu error\n"); + return -1; + } + + result = 0x4; + __asm + ("l.divu %0, %1, %0\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("divu error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_extx.c b/tests/tcg/openrisc/test_extx.c new file mode 100644 index 0000000000..09221484a6 --- /dev/null +++ b/tests/tcg/openrisc/test_extx.c @@ -0,0 +1,78 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + b = 0x83; + result = 0xffffff83; + __asm + ("l.extbs %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("extbs error\n"); + return -1; + } + + result = 0x83; + __asm + ("l.extbz %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("extbz error\n"); + return -1; + } + + b = 0x8083; + result = 0xffff8083; + __asm + ("l.exths %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("exths error\n"); + return -1; + } + + result = 0x8083; + __asm + ("l.exthz %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("exthz error\n"); + return -1; + } + + b = 0x11; + result = 0x11; + __asm + ("l.extws %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + + if (a != result) { + printf("extws error\n"); + return -1; + } + + __asm + ("l.extwz %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("extwz error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_fx.c b/tests/tcg/openrisc/test_fx.c new file mode 100644 index 0000000000..df86000d90 --- /dev/null +++ b/tests/tcg/openrisc/test_fx.c @@ -0,0 +1,57 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + b = 0x123; + result = 1; + __asm + ("l.ff1 %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("ff1 error\n"); + return -1; + } + + b = 0x0; + result = 0; + __asm + ("l.ff1 %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("ff1 error\n"); + return -1; + } + + b = 0x123; + result = 9; + __asm + ("l.fl1 %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("fl1 error\n"); + return -1; + } + + b = 0x0; + result = 0; + __asm + ("l.fl1 %0, %1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("fl1 error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_j.c b/tests/tcg/openrisc/test_j.c new file mode 100644 index 0000000000..9ddf8bfbb5 --- /dev/null +++ b/tests/tcg/openrisc/test_j.c @@ -0,0 +1,26 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 2; + __asm + ("l.addi %0, %0, 1\n\t" + "l.j j\n\t" + "l.nop\n\t" + "l.addi %0, %0, 1\n\t" + "l.nop\n\t" + "j:\n\t" + "l.addi %0, %0, 1\n\t" + : "+r"(a) + ); + if (a != result) { + printf("j error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_jal.c b/tests/tcg/openrisc/test_jal.c new file mode 100644 index 0000000000..7e2da40163 --- /dev/null +++ b/tests/tcg/openrisc/test_jal.c @@ -0,0 +1,26 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 2; + __asm + ("l.addi %0, %0, 1\n\t" + "l.jal jal\n\t" + "l.nop\n\t" + "l.addi %0, %0, 1\n\t" + "l.nop\n\t" + "jal:\n\t" + "l.addi %0, %0, 1\n\t" + : "+r"(a) + ); + if (a != result) { + printf("jal error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_add.c b/tests/tcg/openrisc/test_lf_add.c new file mode 100644 index 0000000000..e00212dad6 --- /dev/null +++ b/tests/tcg/openrisc/test_lf_add.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + float a, b; + float res2; + + a = 1.5; + b = 2.5; + res2 = 4.0; + __asm + ("lf.add.s %0, %0, %1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != res2) { + printf("lf.add.s error, %f\n", a); + return -1; + } + +/* double c, d; + double res1; + + c = 1.5; + d = 1.5; + res1 = 3.00; + __asm + ("lf.add.d %0, %1, %2\n\t" + : "+r"(c) + : "r"(d) + ); + + if ((e - res1) > 0.002) { + printf("lf.add.d error, %f\n", e - res1); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_div.c b/tests/tcg/openrisc/test_lf_div.c new file mode 100644 index 0000000000..70b5d1c17b --- /dev/null +++ b/tests/tcg/openrisc/test_lf_div.c @@ -0,0 +1,37 @@ +#include <stdio.h> + +int main(void) +{ + float a, b, c; + float result; + + b = 1.5; + c = 0.5; + result = 3.0; + __asm + ("lf.div.s %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.div.s error\n"); + return -1; + } + +/* double a, b, c, res; + + b = 0x80000000; + c = 0x40; + result = 0x2000000; + __asm + ("lf.div.d %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.div.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_eqs.c b/tests/tcg/openrisc/test_lf_eqs.c new file mode 100644 index 0000000000..a176bd6fe0 --- /dev/null +++ b/tests/tcg/openrisc/test_lf_eqs.c @@ -0,0 +1,88 @@ +#include <stdio.h> + +int main(void) +{ + int a, result; + float b, c; + + a = 0x1; + b = 122.5; + c = 123.5; + result = 0x3; + __asm + ("lfeqd:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfeq.s %1, %2\n\t" + "l.bf lfeqd\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfeq.s error\n"); + return -1; + } + + b = 13.5; + c = 13.5; + result = 0x3; + __asm + ("lf.sfeq.s %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi r4, r4, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfeq.s error\n"); + return -1; + } + +/* double b, c; + double result; + int a; + + a = 0x1; + b = 122.5; + c = 133.5; + result = 0x3; + + __asm + ("lfeqd:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfeq.d %1, %2\n\t" + "l.bf lfeqd\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfeq.d error\n"); + return -1; + } + + double c, d, res; + int e = 0; + c = 11.5; + d = 11.5; + res = 1; + __asm + ("lf.sfeq.d %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(e) + : "r"(c), "r"(d) + ); + if (e != res) { + printf("lf.sfeq.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_ges.c b/tests/tcg/openrisc/test_lf_ges.c new file mode 100644 index 0000000000..98e7f50b6e --- /dev/null +++ b/tests/tcg/openrisc/test_lf_ges.c @@ -0,0 +1,88 @@ +#include <stdio.h> + +int main(void) +{ + int a, result; + float b, c; + + a = 0; + b = 122.5; + c = 123.5; + result = 0x1; + __asm + ("lfges:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfge.s %1, %2\n\t" + "l.bf lfges\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfge.s error\n"); + return -1; + } + + b = 133.5; + c = 13.5; + result = 0x3; + __asm + ("l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfge.s %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfge.s error\n"); + return -1; + } + +/* int a, result; + double b, c; + + a = 0x1; + b = 122.5; + c = 123.5; + result = 0x2; + __asm + ("lfged:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfge.d %1, %2\n\t" + "l.bf lfged\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfge.d error\n"); + return -1; + } + + b = 133.5; + c = 13.5; + result = 0x4; + __asm + ("lf.sfge.d %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfge.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_gts.c b/tests/tcg/openrisc/test_lf_gts.c new file mode 100644 index 0000000000..f3df27958e --- /dev/null +++ b/tests/tcg/openrisc/test_lf_gts.c @@ -0,0 +1,86 @@ +#include <stdio.h> + +int main(void) +{ + int a, result; + float b, c; + + a = 0; + b = 122.5; + c = 123.5; + result = 0x1; + __asm + ("lfgts:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfgt.s %1, %2\n\t" + "l.bf lfgts\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfgt.s error\n"); + return -1; + } + + b = 133.5; + c = 13.5; + result = 0x1; + __asm + ("lf.sfgt.s %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfgt.s error\n"); + return -1; + } + +/* int a, result; + double b, c; + + a = 0; + b = 122.5; + c = 123.5; + result = 0x1; + __asm + ("lfgtd:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfgt.d %1, %2\n\t" + "l.bf lfgtd\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfgt.d error\n"); + return -1; + } + + b = 133.5; + c = 13.5; + result = 0x3; + __asm + ("l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfgt.d %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfgt.d error, %x\n", a); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_les.c b/tests/tcg/openrisc/test_lf_les.c new file mode 100644 index 0000000000..046c511d93 --- /dev/null +++ b/tests/tcg/openrisc/test_lf_les.c @@ -0,0 +1,88 @@ +#include <stdio.h> + +int main(void) +{ + int a; + float b, c; + int result; + + a = 0; + b = 1234.2; + c = 12.4; + result = 0x1; + __asm + ("lfles:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfle.s %1, %2\n\t" + "l.bf lfles\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfle.s error\n"); + return -1; + } + + b = 1.1; + c = 19.4; + result = 0x3; + __asm + ("l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfle.s %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfle.s error\n"); + return -1; + } + +/* int a; + double b, c; + int result; + + a = 0; + b = 1212.5; + c = 123.5; + result = 0x1; + __asm + ("lfled:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfle.d %1, %2\n\t" + "l.bf lfled\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfle.d error\n"); + return -1; + } + + b = 13.5; + c = 113.5; + result = 0x2; + __asm + ("l.addi %0, %0, 0x1\n\t" + "lf.sfle.d %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfle.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_lts.c b/tests/tcg/openrisc/test_lf_lts.c new file mode 100644 index 0000000000..fa56721dfa --- /dev/null +++ b/tests/tcg/openrisc/test_lf_lts.c @@ -0,0 +1,92 @@ +#include <stdio.h> + +int main(void) +{ + int a; + float b, c, d; + int result; + + a = 0; + b = 124.5; + c = 1.4; + result = 1; + __asm + ("lfltd:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sflt.s %1, %2\n\t" + "l.bf lfltd\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sflt.s error\n"); + return -1; + } + + a = 0; + b = 11.1; + c = 13.1; + d = 1.0; + result = 2; + __asm + ("1:\n\t" + "lf.add.s %1, %1, %3\n\t" + "l.addi %0, %0, 1\n\t" + "lf.sflt.s %1, %2\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c), "r"(d) + ); + if (a != result) { + printf("lf.sflt.s error\n"); + return -1; + } + +/* int a; + double b, c; + int result; + + a = 0; + b = 1432.1; + c = 2.4; + result = 0x1; + __asm + ("lfltd:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sflt.d %1, %2\n\t" + "l.bf lfltd\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sflt.d error\n"); + return -1; + } + + a = 0; + b = 1.1; + c = 19.7; + result = 2; + __asm + ("lf.sflt.d %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 1\n\t" + "l.addi %0, %0, 1\n\t" + "l.addi %0, %0, 1\n\t" + "1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.addi %0, %0, 1\n\t" + : "+r"(a), "+r"(b) + : "r"(c) + ); + if (a != result) { + printf("lf.sflt.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_mul.c b/tests/tcg/openrisc/test_lf_mul.c new file mode 100644 index 0000000000..bc8ad800c7 --- /dev/null +++ b/tests/tcg/openrisc/test_lf_mul.c @@ -0,0 +1,22 @@ +#include <stdio.h> + +int main(void) +{ + float a, b, c; + float result; + + b = 1.5; + c = 4.0; + result = 6.0; + __asm + ("lf.mul.s %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.mul.s error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_nes.c b/tests/tcg/openrisc/test_lf_nes.c new file mode 100644 index 0000000000..613631005b --- /dev/null +++ b/tests/tcg/openrisc/test_lf_nes.c @@ -0,0 +1,89 @@ +#include <stdio.h> + +int main(void) +{ + int a; + float b, c; + int result; + + a = 0; + b = 23.1; + c = 23.1; + result = 0x1; + __asm + ("lfnes:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfne.s %1, %2\n\t" + "l.bf lfnes\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfne.s error"); + return -1; + } + + b = 12.4; + c = 7.8; + result = 0x3; + __asm + ("l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfne.s %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfne.s error\n"); + return -1; + } +/* int a; + double b, c; + int result; + + a = 0; + b = 124.3; + c = 124.3; + result = 0x1; + __asm + ("lfned:\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfne.d %1, %2\n\t" + "l.bf lfned\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfne.d error\n"); + return -1; + } + + b = 11.5; + c = 16.7; + result = 0x3; + __asm + ("l.addi %0, %0, 0x1\n\t" + "l.addi %0, %0, 0x1\n\t" + "lf.sfne.d %1, %2\n\t" + "l.bf 1f\n\t" + "l.nop\n\t" + "l.addi r4, r4, 0x1\n\t" + "l.addi r4, r4, 0x1\n\t" + "1:\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sfne.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_rem.c b/tests/tcg/openrisc/test_lf_rem.c new file mode 100644 index 0000000000..bd6090d694 --- /dev/null +++ b/tests/tcg/openrisc/test_lf_rem.c @@ -0,0 +1,32 @@ +#include <stdio.h> + +int main(void) +{ + float a, b, c; + float result; + + b = 101.5; + c = 10; + result = 1.5; +/* __asm + ("lf.rem.d %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.rem.d error\n"); + return -1; + }*/ + + __asm + ("lf.rem.s %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.rem.s error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_lf_sub.c b/tests/tcg/openrisc/test_lf_sub.c new file mode 100644 index 0000000000..5ee9b03910 --- /dev/null +++ b/tests/tcg/openrisc/test_lf_sub.c @@ -0,0 +1,35 @@ +#include <stdio.h> + +int main(void) +{ + float a, b, c; + float result; + + b = 10.5; + c = 1.5; + result = 9.0; + __asm + ("lf.sub.s %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sub.s error\n"); + return -1; + } + +/* b = 0x999; + c = 0x654; + result = 0x345; + __asm + ("lf.sub.d %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("lf.sub.d error\n"); + return -1; + }*/ + + return 0; +} diff --git a/tests/tcg/openrisc/test_logic.c b/tests/tcg/openrisc/test_logic.c new file mode 100644 index 0000000000..46d173f481 --- /dev/null +++ b/tests/tcg/openrisc/test_logic.c @@ -0,0 +1,105 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x9743; + c = 0x2; + result = 0x25d0c; + __asm + ("l.sll %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sll error\n"); + return -1; + } + + b = 0x9743; + result = 0x25d0c; + __asm + ("l.slli %0, %1, 0x2\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("slli error\n"); + return -1; + } + + b = 0x7654; + c = 0x03; + result = 0xeca; + __asm + ("l.srl %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + + b = 0x7654; + result = 0xeca; + __asm + ("l.srli %0, %1, 0x3\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("srli error\n"); + return -1; + } + + b = 0x80000001; + c = 0x4; + result = 0x18000000; + __asm + ("l.ror %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("ror error\n"); + return -1; + } + + b = 0x80000001; + result = 0x18000000; + __asm + ("l.rori %0, %1, 0x4\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("rori error\n"); + return -1; + } + + b = 0x80000001; + c = 0x03; + result = 0xf0000000; + __asm + ("l.sra %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sra error\n"); + return -1; + } + + b = 0x80000001; + result = 0xf0000000; + __asm + ("l.srai %0, %1, 0x3\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("srai error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_lx.c b/tests/tcg/openrisc/test_lx.c new file mode 100644 index 0000000000..792e3d5c7f --- /dev/null +++ b/tests/tcg/openrisc/test_lx.c @@ -0,0 +1,84 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int p[50]; + int result; + + result = 0x23; + __asm + ("l.ori r8, r0, 0x123\n\t" + "l.sb 0x4 + %1, r8\n\t" + "\n\t" + "l.lbz %0, 0x4 + %1\n\t" + : "=r"(a), "+m"(*p) + ); + if (a != result) { + printf("lbz error, %x\n", a); + return -1; + } + + result = 0x23; + __asm + ("l.lbs %0, 0x4 + %1\n\t" + : "=r"(a) + : "m"(*p) + ); + if (a != result) { + printf("lbs error\n"); + return -1; + } + + result = 0x1111; + __asm + ("l.ori r8, r0, 0x1111\n\t" + "l.sh 0x20 + %1, r8\n\t" + "\n\t" + "l.lhs %0, 0x20 + %1\n\t" + : "=r"(a), "=m"(*p) + ); + if (a != result) { + printf("lhs error, %x\n", a); + return -1; + } + + result = 0x1111; + __asm + ("l.lhz %0, 0x20 + %1\n\t" + : "=r"(a) + : "m"(*p) + ); + if (a != result) { + printf("lhz error\n"); + return -1; + } + + result = 0x1111233; + __asm + ("l.ori r8, r0, 0x1233\n\t" + "l.movhi r1, 0x111\n\t" + "l.or r8, r8, r1\n\t" + "l.sw 0x123 + %1, r8\n\t" + "\n\t" + "l.lws %0, 0x123 + %1\n\t" + : "=r"(a), "+m"(*p) + ); + if (a != result) { + printf("lws error, %x\n", a); + return -1; + } + + result = 0x1111233; + __asm + ("l.lwz %0, 0x123 + %1\n\t" + : "=r"(a) + : "m"(*p) + ); + if (a != result) { + printf("lwz error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_movhi.c b/tests/tcg/openrisc/test_movhi.c new file mode 100644 index 0000000000..737f75b9fd --- /dev/null +++ b/tests/tcg/openrisc/test_movhi.c @@ -0,0 +1,31 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + result = 0x1222; + __asm + ("l.movhi r3, 0x1222\n\t" + "l.srli %0, r3, 16\n\t" + : "=r"(a) + ); + if (a != result) { + printf("movhi error\n"); + return -1; + } + + result = 0x1111; + __asm + ("l.movhi r8, 0x1111\n\t" + "l.srli %0, r8, 16\n\t" + : "=r"(a) + ); + if (a != result) { + printf("movhi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_mul.c b/tests/tcg/openrisc/test_mul.c new file mode 100644 index 0000000000..130101fdee --- /dev/null +++ b/tests/tcg/openrisc/test_mul.c @@ -0,0 +1,61 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x4; + c = 0x1; + result = 0x4; + __asm + ("l.mul %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mul error\n"); + return -1; + } + + b = 0x1; + c = 0x0; + result = 0x0; + __asm + ("l.mul %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mul error\n"); + return -1; + } + + b = 0x1; + c = 0xff; + result = 0xff; + __asm + ("l.mul %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mul error\n"); + return -1; + } + + b = 0x7fffffff; + c = 0x2; + result = 0xfffffffe; + __asm + ("l.mul %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mul error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_muli.c b/tests/tcg/openrisc/test_muli.c new file mode 100644 index 0000000000..f1042e98de --- /dev/null +++ b/tests/tcg/openrisc/test_muli.c @@ -0,0 +1,48 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x4; + c = 0x1; + result = 0x4; + __asm + ("l.muli %0, %1, 0x1\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("muli error\n"); + return -1; + } + + b = 0x1; + c = 0x0; + result = 0x0; + __asm + ("l.muli %0, %1, 0x0\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("muli error\n"); + return -1; + } + + b = 0x1; + c = 0xff; + result = 0xff; + __asm + ("l.muli %0, %1, 0xff\n\t" + : "=r"(a) + : "r"(b) + ); + if (a != result) { + printf("muli error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_mulu.c b/tests/tcg/openrisc/test_mulu.c new file mode 100644 index 0000000000..2d1e97d16e --- /dev/null +++ b/tests/tcg/openrisc/test_mulu.c @@ -0,0 +1,48 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + b = 0x4; + c = 0x1; + result = 0x4; + __asm + ("l.mulu %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mulu error\n"); + return -1; + } + + b = 0x1; + c = 0x0; + result = 0x0; + __asm + ("l.mulu %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mulu error\n"); + return -1; + } + + b = 0x1; + c = 0xff; + result = 0xff; + __asm + ("l.mulu %0, %1, %2\n\t" + : "=r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("mulu error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfeq.c b/tests/tcg/openrisc/test_sfeq.c new file mode 100644 index 0000000000..bd7f875b71 --- /dev/null +++ b/tests/tcg/openrisc/test_sfeq.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0x1; + b = 0x80; + result = 0x2; + __asm + ("1:\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.sfeq %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfeq error\n"); + return -1; + } + + a = 0x7f; + b = 0x80; + result = 0x81; + __asm + ("2:\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.sfeq %0, %1\n\t" + "l.bf 2b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfeq error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfeqi.c b/tests/tcg/openrisc/test_sfeqi.c new file mode 100644 index 0000000000..574261321b --- /dev/null +++ b/tests/tcg/openrisc/test_sfeqi.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 1; + result = 2; + __asm + ("1:\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.sfeqi %0, 0x80\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfeqi error\n"); + return -1; + } + + a = 0x7f; + result = 0x81; + __asm + ("2:\n\t" + "l.addi %0, %0, 0x1\n\t" + "l.sfeqi %0, 0x80\n\t" + "l.bf 2b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfeqi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfges.c b/tests/tcg/openrisc/test_sfges.c new file mode 100644 index 0000000000..23761d7f5a --- /dev/null +++ b/tests/tcg/openrisc/test_sfges.c @@ -0,0 +1,44 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + a = 0; + b = 3; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfges %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfges error\n"); + return -1; + } + + a = 0xff; + b = 3; + c = 0x1; + result = 2; + __asm + ("1:\n\t" + "l.sub %0, %0, %2\n\t" + "l.sfges %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sfges error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgesi.c b/tests/tcg/openrisc/test_sfgesi.c new file mode 100644 index 0000000000..54a2d51cd5 --- /dev/null +++ b/tests/tcg/openrisc/test_sfgesi.c @@ -0,0 +1,40 @@ +#include <stdio.h> +int main(void) +{ + int a, b; + int result; + + a = 0; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgesi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfgesi error\n"); + return -1; + } + + a = 0xff; + b = 1; + result = 2; + __asm + ("1:\n\t" + "l.sub %0, %0, %1\n\t" + "l.sfgesi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgesi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgeu.c b/tests/tcg/openrisc/test_sfgeu.c new file mode 100644 index 0000000000..2a491d91ea --- /dev/null +++ b/tests/tcg/openrisc/test_sfgeu.c @@ -0,0 +1,44 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + a = 0; + b = 3; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgeu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgeu error\n"); + return -1; + } + + a = 0xff; + b = 3; + c = 1; + result = 2; + __asm + ("1:\n\t" + "l.sub %0, %0, %2\n\t" + "l.sfgeu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sfgeu error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgeui.c b/tests/tcg/openrisc/test_sfgeui.c new file mode 100644 index 0000000000..40af35c68f --- /dev/null +++ b/tests/tcg/openrisc/test_sfgeui.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgeui %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfgeui error\n"); + return -1; + } + + a = 0xff; + b = 1; + result = 2; + __asm + ("1:\n\t" + "l.sub %0, %0, %1\n\t" + "l.sfgeui %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgeui error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgts.c b/tests/tcg/openrisc/test_sfgts.c new file mode 100644 index 0000000000..4481a9cc3d --- /dev/null +++ b/tests/tcg/openrisc/test_sfgts.c @@ -0,0 +1,45 @@ +#include <stdio.h> + +int main(void) +{ + int a, b, c; + int result; + + a = 0; + b = 3; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgts %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgts error\n"); + return -1; + } + + + a = 0xff; + b = 3; + c = 1; + result = 3; + __asm + ("1:\n\t" + "l.sub %0, %0, %2\n\t" + "l.sfgts %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sfgts error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgtsi.c b/tests/tcg/openrisc/test_sfgtsi.c new file mode 100644 index 0000000000..7366e1292c --- /dev/null +++ b/tests/tcg/openrisc/test_sfgtsi.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgtsi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfgtsi error\n"); + return -1; + } + + a = 0xff; + b = 1; + result = 3; + __asm + ("1:\n\t" + "l.sub %0, %0, %1\n\t" + "l.sfgtsi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgtsi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgtu.c b/tests/tcg/openrisc/test_sfgtu.c new file mode 100644 index 0000000000..da2868916d --- /dev/null +++ b/tests/tcg/openrisc/test_sfgtu.c @@ -0,0 +1,43 @@ +#include <stdio.h> +int main(void) +{ + int a, b, c; + int result; + + a = 0; + b = 3; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgtu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgtu error\n"); + return -1; + } + + a = 0xff; + b = 3; + c = 1; + result = 3; + __asm + ("1:\n\t" + "l.sub %0, %0, %2\n\t" + "l.sfgtu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b), "r"(c) + ); + if (a != result) { + printf("sfgtu error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfgtui.c b/tests/tcg/openrisc/test_sfgtui.c new file mode 100644 index 0000000000..565d44f112 --- /dev/null +++ b/tests/tcg/openrisc/test_sfgtui.c @@ -0,0 +1,42 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + result = 1; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfgtui %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfgtui error\n"); + return -1; + } + + + a = 0xff; + b = 1; + result = 3; + __asm + ("1:\n\t" + "l.sub %0, %0, %1\n\t" + "l.sfgtui %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfgtui error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfles.c b/tests/tcg/openrisc/test_sfles.c new file mode 100644 index 0000000000..f5735228fe --- /dev/null +++ b/tests/tcg/openrisc/test_sfles.c @@ -0,0 +1,26 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + b = 3; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sfles %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfles error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sflesi.c b/tests/tcg/openrisc/test_sflesi.c new file mode 100644 index 0000000000..16fe6053e5 --- /dev/null +++ b/tests/tcg/openrisc/test_sflesi.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sflesi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sflesi error\n"); + return -1; + } + + a = 0; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sflesi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sflesi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfleu.c b/tests/tcg/openrisc/test_sfleu.c new file mode 100644 index 0000000000..be0a3c3f48 --- /dev/null +++ b/tests/tcg/openrisc/test_sfleu.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + b = 3; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sfleu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfleu error\n"); + return -1; + } + + a = 0; + b = 3; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfleu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfleu error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfleui.c b/tests/tcg/openrisc/test_sfleui.c new file mode 100644 index 0000000000..38d3c89709 --- /dev/null +++ b/tests/tcg/openrisc/test_sfleui.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sfleui %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfleui error\n"); + return -1; + } + + a = 0; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfleui %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfleui error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sflts.c b/tests/tcg/openrisc/test_sflts.c new file mode 100644 index 0000000000..7deeb48d09 --- /dev/null +++ b/tests/tcg/openrisc/test_sflts.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + b = 3; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sflts %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sflts error\n"); + return -1; + } + + a = 0; + b = 3; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sflts %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sflts error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfltsi.c b/tests/tcg/openrisc/test_sfltsi.c new file mode 100644 index 0000000000..3cb1f02857 --- /dev/null +++ b/tests/tcg/openrisc/test_sfltsi.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sfltsi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfltsi error\n"); + return -1; + } + + a = 0; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfltsi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfltsi error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfltu.c b/tests/tcg/openrisc/test_sfltu.c new file mode 100644 index 0000000000..7ed3b26858 --- /dev/null +++ b/tests/tcg/openrisc/test_sfltu.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + b = 3; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sfltu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfltu error\n"); + return -1; + } + + a = 0; + b = 3; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfltu %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfltu error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfltui.c b/tests/tcg/openrisc/test_sfltui.c new file mode 100644 index 0000000000..a5cb9f6a97 --- /dev/null +++ b/tests/tcg/openrisc/test_sfltui.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 4; + __asm + ("1:\n\t" + "l.addi %0, %0, 4\n\t" + "l.sfltsi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfltui error\n"); + return -1; + } + + a = 0; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfltsi %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfltui error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfne.c b/tests/tcg/openrisc/test_sfne.c new file mode 100644 index 0000000000..b33a35cf96 --- /dev/null +++ b/tests/tcg/openrisc/test_sfne.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0; + b = 3; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 3\n\t" + "l.sfne %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfne error\n"); + return -1; + } + + a = 0; + b = 3; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfne %0, %1\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sfne error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sfnei.c b/tests/tcg/openrisc/test_sfnei.c new file mode 100644 index 0000000000..d311c9e660 --- /dev/null +++ b/tests/tcg/openrisc/test_sfnei.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +int main(void) +{ + int a; + int result; + + a = 0; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 3\n\t" + "l.sfnei %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfnei error\n"); + return -1; + } + + a = 0; + result = 3; + __asm + ("1:\n\t" + "l.addi %0, %0, 1\n\t" + "l.sfnei %0, 0x3\n\t" + "l.bf 1b\n\t" + "l.nop\n\t" + : "+r"(a) + ); + if (a != result) { + printf("sfnei error\n"); + return -1; + } + + return 0; +} diff --git a/tests/tcg/openrisc/test_sub.c b/tests/tcg/openrisc/test_sub.c new file mode 100644 index 0000000000..474ec6055b --- /dev/null +++ b/tests/tcg/openrisc/test_sub.c @@ -0,0 +1,35 @@ +#include <stdio.h> + +int main(void) +{ + int a, b; + int result; + + a = 0x100; + b = 0x100; + result = 0x0; + __asm + ("l.sub %0, %0, %1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sub error\n"); + return -1; + } + + a = 0xffff; + b = 0x1; + result = 0xfffe; + __asm + ("l.sub %0, %0, %1\n\t" + : "+r"(a) + : "r"(b) + ); + if (a != result) { + printf("sub error\n"); + return -1; + } + + return 0; +} diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 60cbf019bb..dc3c507f2b 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -3,6 +3,9 @@ #include "test-qmp-commands.h" #include "qapi/qmp-core.h" #include "module.h" +#include "qapi/qmp-input-visitor.h" +#include "tests/test-qapi-types.h" +#include "tests/test-qapi-visit.h" void qmp_user_def_cmd(Error **errp) { @@ -123,6 +126,44 @@ static void test_dealloc_types(void) qapi_free_UserDefOneList(ud1list); } +/* test generated deallocation on an object whose construction was prematurely + * terminated due to an error */ +static void test_dealloc_partial(void) +{ + static const char text[] = "don't leak me"; + + UserDefTwo *ud2 = NULL; + Error *err = NULL; + + /* create partial object */ + { + QDict *ud2_dict; + QmpInputVisitor *qiv; + + ud2_dict = qdict_new(); + qdict_put_obj(ud2_dict, "string", QOBJECT(qstring_from_str(text))); + + qiv = qmp_input_visitor_new(QOBJECT(ud2_dict)); + visit_type_UserDefTwo(qmp_input_get_visitor(qiv), &ud2, NULL, &err); + qmp_input_visitor_cleanup(qiv); + QDECREF(ud2_dict); + } + + /* verify partial success */ + assert(ud2 != NULL); + assert(ud2->string != NULL); + assert(strcmp(ud2->string, text) == 0); + assert(ud2->dict.dict.userdef == NULL); + + /* confirm & release construction error */ + assert(err != NULL); + error_free(err); + + /* tear down partial object */ + qapi_free_UserDefTwo(ud2); +} + + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -131,6 +172,7 @@ int main(int argc, char **argv) g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error); g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io); g_test_add_func("/0.15/dealloc_types", test_dealloc_types); + g_test_add_func("/0.15/dealloc_partial", test_dealloc_partial); module_call_init(MODULE_INIT_QAPI); g_test_run(); diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index c30fdc4e59..8f5a509582 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -151,14 +151,22 @@ typedef struct TestStruct static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - errp); - - visit_type_int(v, &(*obj)->integer, "integer", errp); - visit_type_bool(v, &(*obj)->boolean, "boolean", errp); - visit_type_str(v, &(*obj)->string, "string", errp); - - visit_end_struct(v, errp); + Error *err = NULL; + if (!error_is_set(errp)) { + visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), + &err); + if (!err) { + visit_type_int(v, &(*obj)->integer, "integer", &err); + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + visit_type_str(v, &(*obj)->string, "string", &err); + + /* Always call end_struct if start_struct succeeded. */ + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); + } + error_propagate(errp, err); + } } static void test_visitor_in_struct(TestInputVisitorData *data, diff --git a/trace/control.c b/trace/control.c index 4c5527d20a..22d5863eeb 100644 --- a/trace/control.c +++ b/trace/control.c @@ -27,6 +27,9 @@ void trace_backend_init_events(const char *fname) size_t len = strlen(line_buf); if (len > 1) { /* skip empty lines */ line_buf[len - 1] = '\0'; + if ('#' == line_buf[0]) { /* skip commented lines */ + continue; + } if (!trace_event_set_state(line_buf, true)) { fprintf(stderr, "error: trace event '%s' does not exist\n", line_buf); diff --git a/trace/simple.c b/trace/simple.c index b4a3c6e950..b700ea317c 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -27,7 +27,7 @@ #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL /** Trace file version number, bump if format changes */ -#define HEADER_VERSION 0 +#define HEADER_VERSION 2 /** Records were dropped event ID */ #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) @@ -35,23 +35,6 @@ /** Trace record is valid */ #define TRACE_RECORD_VALID ((uint64_t)1 << 63) -/** Trace buffer entry */ -typedef struct { - uint64_t event; - uint64_t timestamp_ns; - uint64_t x1; - uint64_t x2; - uint64_t x3; - uint64_t x4; - uint64_t x5; - uint64_t x6; -} TraceRecord; - -enum { - TRACE_BUF_LEN = 4096, - TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4, -}; - /* * Trace records are written out by a dedicated thread. The thread waits for * records to become available, writes them out, and then waits again. @@ -62,11 +45,48 @@ static GCond *trace_empty_cond; static bool trace_available; static bool trace_writeout_enabled; -static TraceRecord trace_buf[TRACE_BUF_LEN]; +enum { + TRACE_BUF_LEN = 4096 * 64, + TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4, +}; + +uint8_t trace_buf[TRACE_BUF_LEN]; static unsigned int trace_idx; +static unsigned int writeout_idx; +static uint64_t dropped_events; static FILE *trace_fp; static char *trace_file_name = NULL; +/* * Trace buffer entry */ +typedef struct { + uint64_t event; /* TraceEventID */ + uint64_t timestamp_ns; + uint32_t length; /* in bytes */ + uint32_t reserved; /* unused */ + uint8_t arguments[]; +} TraceRecord; + +typedef struct { + uint64_t header_event_id; /* HEADER_EVENT_ID */ + uint64_t header_magic; /* HEADER_MAGIC */ + uint64_t header_version; /* HEADER_VERSION */ +} TraceRecordHeader; + + +static void read_from_buffer(unsigned int idx, void *dataptr, size_t size); +static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size); + +static void clear_buffer_range(unsigned int idx, size_t len) +{ + uint32_t num = 0; + while (num < len) { + if (idx >= TRACE_BUF_LEN) { + idx = idx % TRACE_BUF_LEN; + } + trace_buf[idx++] = 0; + num++; + } +} /** * Read a trace record from the trace buffer * @@ -75,16 +95,30 @@ static char *trace_file_name = NULL; * * Returns false if the record is not valid. */ -static bool get_trace_record(unsigned int idx, TraceRecord *record) +static bool get_trace_record(unsigned int idx, TraceRecord **recordptr) { - if (!(trace_buf[idx].event & TRACE_RECORD_VALID)) { + uint64_t event_flag = 0; + TraceRecord record; + /* read the event flag to see if its a valid record */ + read_from_buffer(idx, &record, sizeof(event_flag)); + + if (!(record.event & TRACE_RECORD_VALID)) { return false; } - __sync_synchronize(); /* read memory barrier before accessing record */ - - *record = trace_buf[idx]; - record->event &= ~TRACE_RECORD_VALID; + smp_rmb(); /* read memory barrier before accessing record */ + /* read the record header to know record length */ + read_from_buffer(idx, &record, sizeof(TraceRecord)); + *recordptr = malloc(record.length); /* dont use g_malloc, can deadlock when traced */ + /* make a copy of record to avoid being overwritten */ + read_from_buffer(idx, *recordptr, record.length); + smp_rmb(); /* memory barrier before clearing valid flag */ + (*recordptr)->event &= ~TRACE_RECORD_VALID; + /* clear the trace buffer range for consumed record otherwise any byte + * with its MSB set may be considered as a valid event id when the writer + * thread crosses this range of buffer again. + */ + clear_buffer_range(idx, record.length); return true; } @@ -120,29 +154,39 @@ static void wait_for_trace_records_available(void) static gpointer writeout_thread(gpointer opaque) { - TraceRecord record; - unsigned int writeout_idx = 0; - unsigned int num_available, idx; + TraceRecord *recordptr; + union { + TraceRecord rec; + uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; + } dropped; + unsigned int idx = 0; + uint64_t dropped_count; size_t unused __attribute__ ((unused)); for (;;) { wait_for_trace_records_available(); - num_available = trace_idx - writeout_idx; - if (num_available > TRACE_BUF_LEN) { - record = (TraceRecord){ - .event = DROPPED_EVENT_ID, - .x1 = num_available, - }; - unused = fwrite(&record, sizeof(record), 1, trace_fp); - writeout_idx += num_available; + if (dropped_events) { + dropped.rec.event = DROPPED_EVENT_ID, + dropped.rec.timestamp_ns = get_clock(); + dropped.rec.length = sizeof(TraceRecord) + sizeof(dropped_events), + dropped.rec.reserved = 0; + while (1) { + dropped_count = dropped_events; + if (g_atomic_int_compare_and_exchange((gint *)&dropped_events, + dropped_count, 0)) { + break; + } + } + memcpy(dropped.rec.arguments, &dropped_count, sizeof(uint64_t)); + unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); } - idx = writeout_idx % TRACE_BUF_LEN; - while (get_trace_record(idx, &record)) { - trace_buf[idx].event = 0; /* clear valid bit */ - unused = fwrite(&record, sizeof(record), 1, trace_fp); - idx = ++writeout_idx % TRACE_BUF_LEN; + while (get_trace_record(idx, &recordptr)) { + unused = fwrite(recordptr, recordptr->length, 1, trace_fp); + writeout_idx += recordptr->length; + free(recordptr); /* dont use g_free, can deadlock when traced */ + idx = writeout_idx % TRACE_BUF_LEN; } fflush(trace_fp); @@ -150,73 +194,93 @@ static gpointer writeout_thread(gpointer opaque) return NULL; } -static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, - uint64_t x4, uint64_t x5, uint64_t x6) +void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val) { - unsigned int idx; - uint64_t timestamp; - - if (!trace_list[event].state) { - return; - } - - timestamp = get_clock(); -#if GLIB_CHECK_VERSION(2, 30, 0) - idx = g_atomic_int_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; -#else - idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; -#endif - trace_buf[idx] = (TraceRecord){ - .event = event, - .timestamp_ns = timestamp, - .x1 = x1, - .x2 = x2, - .x3 = x3, - .x4 = x4, - .x5 = x5, - .x6 = x6, - }; - __sync_synchronize(); /* write barrier before marking as valid */ - trace_buf[idx].event |= TRACE_RECORD_VALID; - - if ((idx + 1) % TRACE_BUF_FLUSH_THRESHOLD == 0) { - flush_trace_file(false); - } + rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t)); } -void trace0(TraceEventID event) +void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen) { - trace(event, 0, 0, 0, 0, 0, 0); + /* Write string length first */ + rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen)); + /* Write actual string now */ + rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen); } -void trace1(TraceEventID event, uint64_t x1) +int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasize) { - trace(event, x1, 0, 0, 0, 0, 0); -} + unsigned int idx, rec_off, old_idx, new_idx; + uint32_t rec_len = sizeof(TraceRecord) + datasize; + uint64_t timestamp_ns = get_clock(); + + while (1) { + old_idx = trace_idx; + smp_rmb(); + new_idx = old_idx + rec_len; + + if (new_idx - writeout_idx > TRACE_BUF_LEN) { + /* Trace Buffer Full, Event dropped ! */ + g_atomic_int_inc((gint *)&dropped_events); + return -ENOSPC; + } -void trace2(TraceEventID event, uint64_t x1, uint64_t x2) -{ - trace(event, x1, x2, 0, 0, 0, 0); -} + if (g_atomic_int_compare_and_exchange((gint *)&trace_idx, + old_idx, new_idx)) { + break; + } + } -void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3) -{ - trace(event, x1, x2, x3, 0, 0, 0); + idx = old_idx % TRACE_BUF_LEN; + /* To check later if threshold crossed */ + rec->next_tbuf_idx = new_idx % TRACE_BUF_LEN; + + rec_off = idx; + rec_off = write_to_buffer(rec_off, (uint8_t*)&event, sizeof(event)); + rec_off = write_to_buffer(rec_off, (uint8_t*)×tamp_ns, sizeof(timestamp_ns)); + rec_off = write_to_buffer(rec_off, (uint8_t*)&rec_len, sizeof(rec_len)); + + rec->tbuf_idx = idx; + rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN; + return 0; } -void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4) +static void read_from_buffer(unsigned int idx, void *dataptr, size_t size) { - trace(event, x1, x2, x3, x4, 0, 0); + uint8_t *data_ptr = dataptr; + uint32_t x = 0; + while (x < size) { + if (idx >= TRACE_BUF_LEN) { + idx = idx % TRACE_BUF_LEN; + } + data_ptr[x++] = trace_buf[idx++]; + } } -void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5) +static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size) { - trace(event, x1, x2, x3, x4, x5, 0); + uint8_t *data_ptr = dataptr; + uint32_t x = 0; + while (x < size) { + if (idx >= TRACE_BUF_LEN) { + idx = idx % TRACE_BUF_LEN; + } + trace_buf[idx++] = data_ptr[x++]; + } + return idx; /* most callers wants to know where to write next */ } -void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) +void trace_record_finish(TraceBufferRecord *rec) { - trace(event, x1, x2, x3, x4, x5, x6); + uint8_t temp_rec[sizeof(TraceRecord)]; + TraceRecord *record = (TraceRecord *) temp_rec; + read_from_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord)); + smp_wmb(); /* write barrier before marking as valid */ + record->event |= TRACE_RECORD_VALID; + write_to_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord)); + + if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) { + flush_trace_file(false); + } } void st_set_trace_file_enabled(bool enable) @@ -231,10 +295,11 @@ void st_set_trace_file_enabled(bool enable) flush_trace_file(true); if (enable) { - static const TraceRecord header = { - .event = HEADER_EVENT_ID, - .timestamp_ns = HEADER_MAGIC, - .x1 = HEADER_VERSION, + static const TraceRecordHeader header = { + .header_event_id = HEADER_EVENT_ID, + .header_magic = HEADER_MAGIC, + /* Older log readers will check for version at next location */ + .header_version = HEADER_VERSION, }; trace_fp = fopen(trace_file_name, "wb"); @@ -291,24 +356,6 @@ void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, trace_file_name, trace_fp ? "on" : "off"); } -void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)) -{ - unsigned int i; - - for (i = 0; i < TRACE_BUF_LEN; i++) { - TraceRecord record; - - if (!get_trace_record(i, &record)) { - continue; - } - stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64 - " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n", - record.event, record.x1, record.x2, - record.x3, record.x4, record.x5, - record.x6); - } -} - void st_flush_trace_buffer(void) { flush_trace_file(true); diff --git a/trace/simple.h b/trace/simple.h index 466e75b4ff..7e521c1e1f 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -22,17 +22,41 @@ typedef struct { bool state; } TraceEvent; -void trace0(TraceEventID event); -void trace1(TraceEventID event, uint64_t x1); -void trace2(TraceEventID event, uint64_t x1, uint64_t x2); -void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3); -void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4); -void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5); -void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6); -void st_print_trace(FILE *stream, fprintf_function stream_printf); void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf); void st_set_trace_file_enabled(bool enable); bool st_set_trace_file(const char *file); void st_flush_trace_buffer(void); +typedef struct { + unsigned int tbuf_idx; + unsigned int next_tbuf_idx; + unsigned int rec_off; +} TraceBufferRecord; + +/* Note for hackers: Make sure MAX_TRACE_LEN < sizeof(uint32_t) */ +#define MAX_TRACE_STRLEN 512 +/** + * Initialize a trace record and claim space for it in the buffer + * + * @arglen number of bytes required for arguments + */ +int trace_record_start(TraceBufferRecord *rec, TraceEventID id, size_t arglen); + +/** + * Append a 64-bit argument to a trace record + */ +void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val); + +/** + * Append a string argument to a trace record + */ +void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen); + +/** + * Mark a trace record completed + * + * Don't append any more arguments to the trace record after calling this. + */ +void trace_record_finish(TraceBufferRecord *rec); + #endif /* TRACE_SIMPLE_H */ diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index 674ba97dc7..c59b188602 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -47,7 +47,8 @@ static void start_auth_vencrypt_subauth(VncState *vs) case VNC_AUTH_VENCRYPT_TLSSASL: case VNC_AUTH_VENCRYPT_X509SASL: VNC_DEBUG("Start TLS auth SASL\n"); - return start_auth_sasl(vs); + start_auth_sasl(vs); + break; #endif /* CONFIG_VNC_SASL */ default: /* Should not be possible, but just in case */ @@ -3089,5 +3089,5 @@ void vnc_display_add_client(DisplayState *ds, int csock, int skipauth) { VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; - return vnc_connect(vs, csock, skipauth); + vnc_connect(vs, csock, skipauth); } @@ -1984,8 +1984,8 @@ static int serial_parse(const char *devname) snprintf(label, sizeof(label), "serial%d", index); serial_hds[index] = qemu_chr_new(label, devname, NULL); if (!serial_hds[index]) { - fprintf(stderr, "qemu: could not open serial device '%s': %s\n", - devname, strerror(errno)); + fprintf(stderr, "qemu: could not connect serial device" + " to character backend '%s'\n", devname); return -1; } index++; @@ -2006,8 +2006,8 @@ static int parallel_parse(const char *devname) snprintf(label, sizeof(label), "parallel%d", index); parallel_hds[index] = qemu_chr_new(label, devname, NULL); if (!parallel_hds[index]) { - fprintf(stderr, "qemu: could not open parallel device '%s': %s\n", - devname, strerror(errno)); + fprintf(stderr, "qemu: could not connect parallel device" + " to character backend '%s'\n", devname); return -1; } index++; @@ -2041,8 +2041,8 @@ static int virtcon_parse(const char *devname) snprintf(label, sizeof(label), "virtcon%d", index); virtcon_hds[index] = qemu_chr_new(label, devname, NULL); if (!virtcon_hds[index]) { - fprintf(stderr, "qemu: could not open virtio console '%s': %s\n", - devname, strerror(errno)); + fprintf(stderr, "qemu: could not connect virtio console" + " to character backend '%s'\n", devname); return -1; } qemu_opt_set(dev_opts, "chardev", label); |