aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS3
-rw-r--r--Makefile25
-rw-r--r--Makefile.dis3
-rw-r--r--Makefile.hw3
-rw-r--r--Makefile.target3
-rw-r--r--Makefile.user3
-rw-r--r--arch_init.c2
-rw-r--r--arch_init.h1
-rw-r--r--block.c2
-rwxr-xr-xconfigure15
-rw-r--r--cpu-exec.c19
-rw-r--r--cpus.c52
-rw-r--r--default-configs/or32-linux-user.mak1
-rw-r--r--default-configs/or32-softmmu.mak4
-rw-r--r--device_tree.c30
-rw-r--r--device_tree.h4
-rw-r--r--dma.h6
-rw-r--r--docs/qapi-code-gen.txt2
-rw-r--r--docs/usb-storage.txt2
-rw-r--r--elf.h2
-rw-r--r--error.c3
-rw-r--r--error.h2
-rw-r--r--gdbstub.c64
-rw-r--r--hw/arm-misc.h2
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm_boot.c46
-rw-r--r--hw/bt-l2cap.c11
-rw-r--r--hw/cadence_gem.c2
-rw-r--r--hw/dp8393x.c2
-rw-r--r--hw/e1000.c2
-rw-r--r--hw/eepro100.c17
-rw-r--r--hw/escc.c1
-rw-r--r--hw/etraxfs_eth.c2
-rw-r--r--hw/exynos4210.c27
-rw-r--r--hw/exynos4210.h3
-rw-r--r--hw/exynos4210_i2c.c334
-rw-r--r--hw/exynos4210_rtc.c7
-rw-r--r--hw/ide/cmd646.c6
-rw-r--r--hw/ide/piix.c3
-rw-r--r--hw/ide/via.c3
-rw-r--r--hw/lan9118.c8
-rw-r--r--hw/lance.c2
-rw-r--r--hw/mcf_fec.c2
-rw-r--r--hw/mfi.h92
-rw-r--r--hw/milkymist-minimac2.c2
-rw-r--r--hw/mipsnet.c2
-rw-r--r--hw/musicpal.c2
-rw-r--r--hw/ne2000-isa.c2
-rw-r--r--hw/ne2000.c10
-rw-r--r--hw/opencores_eth.c2
-rw-r--r--hw/openrisc/Makefile.objs3
-rw-r--r--hw/openrisc_pic.c60
-rw-r--r--hw/openrisc_sim.c150
-rw-r--r--hw/openrisc_timer.c101
-rw-r--r--hw/pcnet-pci.c2
-rw-r--r--hw/pl011.c4
-rw-r--r--hw/ppce500_spin.c2
-rw-r--r--hw/qdev.h11
-rw-r--r--hw/rtl8139.c2
-rw-r--r--hw/smc91c111.c2
-rw-r--r--hw/spapr_llan.c2
-rw-r--r--hw/spapr_pci.c2
-rw-r--r--hw/stellaris_enet.c2
-rw-r--r--hw/usb/dev-network.c2
-rw-r--r--hw/vexpress.c13
-rw-r--r--hw/vhost_net.c2
-rw-r--r--hw/virtio-net.c10
-rw-r--r--hw/vmware_vga.c9
-rw-r--r--hw/xen_nic.c2
-rw-r--r--hw/xgmac.c2
-rw-r--r--hw/xilinx_axienet.c2
-rw-r--r--hw/xilinx_ethlite.c2
-rw-r--r--linux-user/elfload.c41
-rw-r--r--linux-user/main.c100
-rw-r--r--linux-user/openrisc/syscall.h24
-rw-r--r--linux-user/openrisc/syscall_nr.h506
-rw-r--r--linux-user/openrisc/target_signal.h26
-rw-r--r--linux-user/openrisc/termbits.h294
-rw-r--r--linux-user/signal.c229
-rw-r--r--linux-user/syscall.c2
-rw-r--r--linux-user/syscall_defs.h40
-rw-r--r--monitor.c16
-rw-r--r--net.c494
-rw-r--r--net.h16
-rw-r--r--net/dump.c24
-rw-r--r--net/dump.h5
-rw-r--r--net/slirp.c96
-rw-r--r--net/slirp.h4
-rw-r--r--net/socket.c124
-rw-r--r--net/socket.h5
-rw-r--r--net/tap-aix.c2
-rw-r--r--net/tap-bsd.c2
-rw-r--r--net/tap-haiku.c2
-rw-r--r--net/tap-linux.c9
-rw-r--r--net/tap-solaris.c2
-rw-r--r--net/tap-win32.c14
-rw-r--r--net/tap.c152
-rw-r--r--net/tap.h10
-rw-r--r--net/vde.c20
-rw-r--r--net/vde.h5
-rw-r--r--osdep.h2
-rw-r--r--poison.h1
-rw-r--r--qapi-schema.json288
-rw-r--r--qapi/Makefile.objs2
-rw-r--r--qapi/opts-visitor.c427
-rw-r--r--qapi/opts-visitor.h31
-rw-r--r--qapi/qapi-visit-core.c17
-rw-r--r--qapi/qapi-visit-core.h3
-rw-r--r--qemu-common.h1
-rw-r--r--qemu-option-internal.h53
-rw-r--r--qemu-option.c24
-rw-r--r--qemu-options.hx4
-rw-r--r--qemu-sockets.c3
-rw-r--r--qga/Makefile.objs2
-rw-r--r--rules.mak3
-rw-r--r--scripts/qapi-visit.py150
-rw-r--r--scripts/qapi.py6
-rwxr-xr-xscripts/simpletrace.py116
-rw-r--r--scripts/tracetool/backend/simple.py90
-rw-r--r--target-i386/cpu.c2
-rw-r--r--target-i386/translate.c43
-rw-r--r--target-openrisc/Makefile.objs4
-rw-r--r--target-openrisc/cpu.c220
-rw-r--r--target-openrisc/cpu.h458
-rw-r--r--target-openrisc/exception.c27
-rw-r--r--target-openrisc/exception.h28
-rw-r--r--target-openrisc/exception_helper.c29
-rw-r--r--target-openrisc/fpu_helper.c300
-rw-r--r--target-openrisc/helper.h70
-rw-r--r--target-openrisc/int_helper.c79
-rw-r--r--target-openrisc/interrupt.c74
-rw-r--r--target-openrisc/interrupt_helper.c57
-rw-r--r--target-openrisc/machine.c47
-rw-r--r--target-openrisc/mmu.c243
-rw-r--r--target-openrisc/mmu_helper.c63
-rw-r--r--target-openrisc/sys_helper.c287
-rw-r--r--target-openrisc/translate.c1835
-rw-r--r--target-xtensa/translate.c16
-rw-r--r--tests/Makefile2
-rw-r--r--tests/tcg/openrisc/Makefile71
-rw-r--r--tests/tcg/openrisc/test_add.c43
-rw-r--r--tests/tcg/openrisc/test_addc.c38
-rw-r--r--tests/tcg/openrisc/test_addi.c33
-rw-r--r--tests/tcg/openrisc/test_addic.c33
-rw-r--r--tests/tcg/openrisc/test_and_or.c65
-rw-r--r--tests/tcg/openrisc/test_bf.c47
-rw-r--r--tests/tcg/openrisc/test_bnf.c51
-rw-r--r--tests/tcg/openrisc/test_div.c54
-rw-r--r--tests/tcg/openrisc/test_divu.c34
-rw-r--r--tests/tcg/openrisc/test_extx.c78
-rw-r--r--tests/tcg/openrisc/test_fx.c57
-rw-r--r--tests/tcg/openrisc/test_j.c26
-rw-r--r--tests/tcg/openrisc/test_jal.c26
-rw-r--r--tests/tcg/openrisc/test_lf_add.c39
-rw-r--r--tests/tcg/openrisc/test_lf_div.c37
-rw-r--r--tests/tcg/openrisc/test_lf_eqs.c88
-rw-r--r--tests/tcg/openrisc/test_lf_ges.c88
-rw-r--r--tests/tcg/openrisc/test_lf_gts.c86
-rw-r--r--tests/tcg/openrisc/test_lf_les.c88
-rw-r--r--tests/tcg/openrisc/test_lf_lts.c92
-rw-r--r--tests/tcg/openrisc/test_lf_mul.c22
-rw-r--r--tests/tcg/openrisc/test_lf_nes.c89
-rw-r--r--tests/tcg/openrisc/test_lf_rem.c32
-rw-r--r--tests/tcg/openrisc/test_lf_sub.c35
-rw-r--r--tests/tcg/openrisc/test_logic.c105
-rw-r--r--tests/tcg/openrisc/test_lx.c84
-rw-r--r--tests/tcg/openrisc/test_movhi.c31
-rw-r--r--tests/tcg/openrisc/test_mul.c61
-rw-r--r--tests/tcg/openrisc/test_muli.c48
-rw-r--r--tests/tcg/openrisc/test_mulu.c48
-rw-r--r--tests/tcg/openrisc/test_sfeq.c43
-rw-r--r--tests/tcg/openrisc/test_sfeqi.c39
-rw-r--r--tests/tcg/openrisc/test_sfges.c44
-rw-r--r--tests/tcg/openrisc/test_sfgesi.c40
-rw-r--r--tests/tcg/openrisc/test_sfgeu.c44
-rw-r--r--tests/tcg/openrisc/test_sfgeui.c41
-rw-r--r--tests/tcg/openrisc/test_sfgts.c45
-rw-r--r--tests/tcg/openrisc/test_sfgtsi.c41
-rw-r--r--tests/tcg/openrisc/test_sfgtu.c43
-rw-r--r--tests/tcg/openrisc/test_sfgtui.c42
-rw-r--r--tests/tcg/openrisc/test_sfles.c26
-rw-r--r--tests/tcg/openrisc/test_sflesi.c39
-rw-r--r--tests/tcg/openrisc/test_sfleu.c43
-rw-r--r--tests/tcg/openrisc/test_sfleui.c39
-rw-r--r--tests/tcg/openrisc/test_sflts.c43
-rw-r--r--tests/tcg/openrisc/test_sfltsi.c39
-rw-r--r--tests/tcg/openrisc/test_sfltu.c43
-rw-r--r--tests/tcg/openrisc/test_sfltui.c39
-rw-r--r--tests/tcg/openrisc/test_sfne.c43
-rw-r--r--tests/tcg/openrisc/test_sfnei.c39
-rw-r--r--tests/tcg/openrisc/test_sub.c35
-rw-r--r--tests/test-qmp-commands.c42
-rw-r--r--tests/test-qmp-input-visitor.c24
-rw-r--r--trace/control.c3
-rw-r--r--trace/simple.c271
-rw-r--r--trace/simple.h40
-rw-r--r--ui/vnc-auth-vencrypt.c3
-rw-r--r--ui/vnc.c2
-rw-r--r--vl.c12
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>
diff --git a/Makefile b/Makefile
index ab82ef3dcb..621cb8617c 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
diff --git a/block.c b/block.c
index ce7eb8f79b..b38940bf85 100644
--- a/block.c
+++ b/block.c
@@ -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);
}
diff --git a/configure b/configure
index cef0a71a27..c65b5f6a55 100755
--- a/configure
+++ b/configure
@@ -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)
diff --git a/cpus.c b/cpus.c
index b182b3d7d9..756e6245fd 100644
--- a/cpus.c
+++ b/cpus.c
@@ -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);
diff --git a/dma.h b/dma.h
index acacf1bf27..f35c4b6632 100644
--- a/dma.h
+++ b/dma.h
@@ -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
diff --git a/elf.h b/elf.h
index 9c9acfaf75..a21ea535bd 100644
--- a/elf.h
+++ b/elf.h
@@ -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 */
/*
diff --git a/error.c b/error.c
index a52b7710d2..58f55a012e 100644
--- a/error.c
+++ b/error.c
@@ -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);
diff --git a/error.h b/error.h
index 45ff6c1ffe..3d9d96def0 100644
--- a/error.h
+++ b/error.h
@@ -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);
diff --git a/gdbstub.c b/gdbstub.c
index 08cf8645d7..5d37dd98f4 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -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,
diff --git a/hw/escc.c b/hw/escc.c
index 4d8a8e8886..e1f5e73ba2 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -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,
diff --git a/hw/mfi.h b/hw/mfi.h
index 8a821623e0..3045d4eb6e 100644
--- a/hw/mfi.h
+++ b/hw/mfi.h
@@ -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;
diff --git a/hw/qdev.h b/hw/qdev.h
index 247dd1eb39..a2cbd9dba0 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -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
diff --git a/monitor.c b/monitor.c
index 09aa3cdf52..49dccfe854 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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 = "",
diff --git a/net.c b/net.c
index abf0fd0a0d..dbca77bad1 100644
--- a/net.c
+++ b/net.c
@@ -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);
}
}
diff --git a/net.h b/net.h
index bdc2a0602d..b0b8c7ab6b 100644
--- a/net.h
+++ b/net.h
@@ -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;
}
diff --git a/net/tap.c b/net/tap.c
index 17e91355ce..72062275fe 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -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;
}
diff --git a/net/tap.h b/net/tap.h
index b2a9450aab..19dea58dc5 100644
--- a/net/tap.h
+++ b/net/tap.h
@@ -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 */
diff --git a/net/vde.c b/net/vde.c
index 6b9d45294a..ee19f5c42c 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -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;
}
diff --git a/net/vde.h b/net/vde.h
index 732e5756f6..ad502ef4de 100644
--- a/net/vde.h
+++ b/net/vde.h
@@ -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 */
diff --git a/osdep.h b/osdep.h
index 3ea4af099b..1e15a4b91c 100644
--- a/osdep.h
+++ b/osdep.h
@@ -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
diff --git a/poison.h b/poison.h
index d396f20ca4..7d7b23b1fc 100644
--- a/poison.h
+++ b/poison.h
@@ -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
diff --git a/rules.mak b/rules.mak
index 60f3e96541..a28494679a 100644
--- a/rules.mak
+++ b/rules.mak
@@ -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*)&timestamp_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 */
diff --git a/ui/vnc.c b/ui/vnc.c
index cf1cae2de4..cfc61a7756 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -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);
}
diff --git a/vl.c b/vl.c
index 54e36ed10f..9fea320bb2 100644
--- a/vl.c
+++ b/vl.c
@@ -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);