diff options
130 files changed, 9234 insertions, 551 deletions
@@ -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 5b0f5626a9..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) @@ -184,11 +186,19 @@ static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset, static RAMBlock *last_block; static ram_addr_t last_offset; +/* + * ram_save_block: Writes a page of memory to the stream f + * + * Returns: 0: if the page hasn't changed + * -1: if there are no more dirty pages + * n: the amount of bytes written in other case + */ + static int ram_save_block(QEMUFile *f) { RAMBlock *block = last_block; ram_addr_t offset = last_offset; - int bytes_sent = 0; + int bytes_sent = -1; MemoryRegion *mr; if (!block) @@ -296,51 +306,56 @@ static void migration_end(void) memory_global_dirty_log_stop(); } +static void ram_migration_cancel(void *opaque) +{ + migration_end(); +} + #define MAX_WAIT 50 /* ms, half buffered_file limit */ -int ram_save_live(QEMUFile *f, int stage, void *opaque) +static int ram_save_setup(QEMUFile *f, void *opaque) { ram_addr_t addr; - uint64_t bytes_transferred_last; - double bwidth = 0; - int ret; - int i; - - if (stage < 0) { - migration_end(); - return 0; - } + RAMBlock *block; - memory_global_sync_dirty_bitmap(get_system_memory()); + bytes_transferred = 0; + last_block = NULL; + last_offset = 0; + sort_ram_list(); - if (stage == 1) { - RAMBlock *block; - bytes_transferred = 0; - last_block = NULL; - last_offset = 0; - sort_ram_list(); - - /* Make sure all dirty bits are set */ - QLIST_FOREACH(block, &ram_list.blocks, next) { - for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { - if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { - memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE); - } + /* Make sure all dirty bits are set */ + QLIST_FOREACH(block, &ram_list.blocks, next) { + for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { + if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { + memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE); } } + } - memory_global_dirty_log_start(); + memory_global_dirty_log_start(); - qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); + qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); - QLIST_FOREACH(block, &ram_list.blocks, next) { - qemu_put_byte(f, strlen(block->idstr)); - qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr)); - qemu_put_be64(f, block->length); - } + QLIST_FOREACH(block, &ram_list.blocks, next) { + qemu_put_byte(f, strlen(block->idstr)); + qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr)); + qemu_put_be64(f, block->length); } + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + + return 0; +} + +static int ram_save_iterate(QEMUFile *f, void *opaque) +{ + uint64_t bytes_transferred_last; + double bwidth = 0; + int ret; + int i; + uint64_t expected_time; + bytes_transferred_last = bytes_transferred; bwidth = qemu_get_clock_ns(rt_clock); @@ -349,10 +364,11 @@ int ram_save_live(QEMUFile *f, int stage, void *opaque) int bytes_sent; bytes_sent = ram_save_block(f); - bytes_transferred += bytes_sent; - if (bytes_sent == 0) { /* no more blocks */ + /* no more blocks to sent */ + if (bytes_sent < 0) { break; } + bytes_transferred += bytes_sent; /* we want to check in the 1st loop, just in case it was the 1st time and we had to sync the dirty bitmap. qemu_get_clock_ns() is a bit expensive, so we only check each some @@ -382,28 +398,43 @@ int ram_save_live(QEMUFile *f, int stage, void *opaque) bwidth = 0.000001; } + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + + DPRINTF("ram_save_live: expected(" PRIu64 ") <= max(" PRIu64 ")?\n", + expected_time, migrate_max_downtime()); + + if (expected_time <= migrate_max_downtime()) { + memory_global_sync_dirty_bitmap(get_system_memory()); + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + + return expected_time <= migrate_max_downtime(); + } + return 0; +} + +static int ram_save_complete(QEMUFile *f, void *opaque) +{ + memory_global_sync_dirty_bitmap(get_system_memory()); + /* try transferring iterative blocks of memory */ - if (stage == 3) { + + /* flush all remaining blocks regardless of rate limiting */ + while (true) { int bytes_sent; - /* flush all remaining blocks regardless of rate limiting */ - while ((bytes_sent = ram_save_block(f)) != 0) { - bytes_transferred += bytes_sent; + bytes_sent = ram_save_block(f); + /* no more blocks to sent */ + if (bytes_sent < 0) { + break; } - memory_global_dirty_log_stop(); + bytes_transferred += bytes_sent; } + memory_global_dirty_log_stop(); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - if (stage == 2) { - uint64_t expected_time; - expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; - - DPRINTF("ram_save_live: expected(" PRIu64 ") <= max(" PRIu64 ")?\n", - expected_time, migrate_max_downtime()); - - return expected_time <= migrate_max_downtime(); - } return 0; } @@ -437,7 +468,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, return NULL; } -int ram_load(QEMUFile *f, void *opaque, int version_id) +static int ram_load(QEMUFile *f, void *opaque, int version_id) { ram_addr_t addr; int flags, ret = 0; @@ -534,6 +565,14 @@ done: return ret; } +SaveVMHandlers savevm_ram_handlers = { + .save_live_setup = ram_save_setup, + .save_live_iterate = ram_save_iterate, + .save_live_complete = ram_save_complete, + .load_state = ram_load, + .cancel = ram_migration_cancel, +}; + #ifdef HAS_AUDIO struct soundhw { const char *name; 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-migration.c b/block-migration.c index b95b4e1389..7def8ab197 100644 --- a/block-migration.c +++ b/block-migration.c @@ -536,30 +536,44 @@ static void blk_mig_cleanup(void) } } -static int block_save_live(QEMUFile *f, int stage, void *opaque) +static void block_migration_cancel(void *opaque) +{ + blk_mig_cleanup(); +} + +static int block_save_setup(QEMUFile *f, void *opaque) { int ret; - DPRINTF("Enter save live stage %d submitted %d transferred %d\n", - stage, block_mig_state.submitted, block_mig_state.transferred); + DPRINTF("Enter save live setup submitted %d transferred %d\n", + block_mig_state.submitted, block_mig_state.transferred); + + init_blk_migration(f); + + /* start track dirty blocks */ + set_dirty_tracking(1); - if (stage < 0) { + flush_blks(f); + + ret = qemu_file_get_error(f); + if (ret) { blk_mig_cleanup(); - return 0; + return ret; } - if (block_mig_state.blk_enable != 1) { - /* no need to migrate storage */ - qemu_put_be64(f, BLK_MIG_FLAG_EOS); - return 1; - } + blk_mig_reset_dirty_cursor(); - if (stage == 1) { - init_blk_migration(f); + qemu_put_be64(f, BLK_MIG_FLAG_EOS); - /* start track dirty blocks */ - set_dirty_tracking(1); - } + return 0; +} + +static int block_save_iterate(QEMUFile *f, void *opaque) +{ + int ret; + + DPRINTF("Enter save live iterate submitted %d transferred %d\n", + block_mig_state.submitted, block_mig_state.transferred); flush_blks(f); @@ -571,56 +585,76 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) blk_mig_reset_dirty_cursor(); - if (stage == 2) { - /* control the rate of transfer */ - while ((block_mig_state.submitted + - block_mig_state.read_done) * BLOCK_SIZE < - qemu_file_get_rate_limit(f)) { - if (block_mig_state.bulk_completed == 0) { - /* first finish the bulk phase */ - if (blk_mig_save_bulked_block(f) == 0) { - /* finished saving bulk on all devices */ - block_mig_state.bulk_completed = 1; - } - } else { - if (blk_mig_save_dirty_block(f, 1) == 0) { - /* no more dirty blocks */ - break; - } + /* control the rate of transfer */ + while ((block_mig_state.submitted + + block_mig_state.read_done) * BLOCK_SIZE < + qemu_file_get_rate_limit(f)) { + if (block_mig_state.bulk_completed == 0) { + /* first finish the bulk phase */ + if (blk_mig_save_bulked_block(f) == 0) { + /* finished saving bulk on all devices */ + block_mig_state.bulk_completed = 1; + } + } else { + if (blk_mig_save_dirty_block(f, 1) == 0) { + /* no more dirty blocks */ + break; } } + } - flush_blks(f); + flush_blks(f); - ret = qemu_file_get_error(f); - if (ret) { - blk_mig_cleanup(); - return ret; - } + ret = qemu_file_get_error(f); + if (ret) { + blk_mig_cleanup(); + return ret; } - if (stage == 3) { - /* we know for sure that save bulk is completed and - all async read completed */ - assert(block_mig_state.submitted == 0); + qemu_put_be64(f, BLK_MIG_FLAG_EOS); + + return is_stage2_completed(); +} + +static int block_save_complete(QEMUFile *f, void *opaque) +{ + int ret; + + DPRINTF("Enter save live complete submitted %d transferred %d\n", + block_mig_state.submitted, block_mig_state.transferred); + + flush_blks(f); - while (blk_mig_save_dirty_block(f, 0) != 0); + ret = qemu_file_get_error(f); + if (ret) { blk_mig_cleanup(); + return ret; + } - /* report completion */ - qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); + blk_mig_reset_dirty_cursor(); - ret = qemu_file_get_error(f); - if (ret) { - return ret; - } + /* we know for sure that save bulk is completed and + all async read completed */ + assert(block_mig_state.submitted == 0); - DPRINTF("Block migration completed\n"); + while (blk_mig_save_dirty_block(f, 0) != 0) { + /* Do nothing */ + } + blk_mig_cleanup(); + + /* report completion */ + qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); + + ret = qemu_file_get_error(f); + if (ret) { + return ret; } + DPRINTF("Block migration completed\n"); + qemu_put_be64(f, BLK_MIG_FLAG_EOS); - return ((stage == 2) && is_stage2_completed()); + return 0; } static int block_load(QEMUFile *f, void *opaque, int version_id) @@ -709,11 +743,26 @@ static void block_set_params(const MigrationParams *params, void *opaque) block_mig_state.blk_enable |= params->shared; } +static bool block_is_active(void *opaque) +{ + return block_mig_state.blk_enable == 1; +} + +SaveVMHandlers savevm_block_handlers = { + .set_params = block_set_params, + .save_live_setup = block_save_setup, + .save_live_iterate = block_save_iterate, + .save_live_complete = block_save_complete, + .load_state = block_load, + .cancel = block_migration_cancel, + .is_active = block_is_active, +}; + void blk_mig_init(void) { QSIMPLEQ_INIT(&block_mig_state.bmds_list); QSIMPLEQ_INIT(&block_mig_state.blk_list); - register_savevm_live(NULL, "block", 0, 1, block_set_params, - block_save_live, NULL, block_load, &block_mig_state); + register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers, + &block_mig_state); } @@ -2609,7 +2609,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) return; } - return drv->bdrv_debug_event(bs, event); + drv->bdrv_debug_event(bs, event); } @@ -924,6 +924,7 @@ mips-softmmu \ mipsel-softmmu \ mips64-softmmu \ mips64el-softmmu \ +or32-softmmu \ ppc-softmmu \ ppcemb-softmmu \ ppc64-softmmu \ @@ -950,6 +951,7 @@ microblaze-linux-user \ microblazeel-linux-user \ mips-linux-user \ mipsel-linux-user \ +or32-linux-user \ ppc-linux-user \ ppc64-linux-user \ ppc64abi32-linux-user \ @@ -3520,7 +3522,7 @@ target_arch2=`echo $target | cut -d '-' -f 1` target_bigendian="no" case "$target_arch2" in - armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -3636,6 +3638,11 @@ case "$target_arch2" in target_phys_bits=64 target_long_alignment=8 ;; + or32) + TARGET_ARCH=openrisc + TARGET_BASE_ARCH=openrisc + target_phys_bits=32 + ;; ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_phys_bits=64 @@ -3714,7 +3721,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" case "$target_arch2" in - alpha | sparc* | xtensa* | ppc*) + alpha | or32 | sparc* | xtensa* | ppc*) echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak ;; esac @@ -3888,6 +3895,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do echo "CONFIG_MIPS_DIS=y" >> $config_target_mak echo "CONFIG_MIPS_DIS=y" >> $libdis_config_mak ;; + or32) + echo "CONFIG_OPENRISC_DIS=y" >> $config_target_mak + echo "CONFIG_OPENRISC_DIS=y" >> $libdis_config_mak + ;; ppc*) echo "CONFIG_PPC_DIS=y" >> $config_target_mak echo "CONFIG_PPC_DIS=y" >> $libdis_config_mak diff --git a/cpu-exec.c b/cpu-exec.c index fc185a4f04..543460c34c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -225,6 +225,7 @@ int cpu_exec(CPUArchState *env) #elif defined(TARGET_LM32) #elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) +#elif defined(TARGET_OPENRISC) #elif defined(TARGET_SH4) #elif defined(TARGET_CRIS) #elif defined(TARGET_S390X) @@ -387,6 +388,23 @@ int cpu_exec(CPUArchState *env) do_interrupt(env); next_tb = 0; } +#elif defined(TARGET_OPENRISC) + { + int idx = -1; + if ((interrupt_request & CPU_INTERRUPT_HARD) + && (env->sr & SR_IEE)) { + idx = EXCP_INT; + } + if ((interrupt_request & CPU_INTERRUPT_TIMER) + && (env->sr & SR_TEE)) { + idx = EXCP_TICK; + } + if (idx >= 0) { + env->exception_index = idx; + do_interrupt(env); + next_tb = 0; + } + } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && @@ -640,6 +658,7 @@ int cpu_exec(CPUArchState *env) | env->cc_dest | (env->cc_x << 4); #elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) +#elif defined(TARGET_OPENRISC) #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) #elif defined(TARGET_CRIS) @@ -28,6 +28,13 @@ #include "qemu_socket.h" #include "iov.h" +void strpadcpy(char *buf, int buf_size, const char *str, char pad) +{ + int len = qemu_strnlen(str, buf_size); + memcpy(buf, str, len); + memset(buf + len, pad, buf_size - len); +} + void pstrcpy(char *buf, int buf_size, const char *str) { int c; 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 @@ -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); } @@ -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 */ /* @@ -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/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/eepro100.c b/hw/eepro100.c index f343685dbd..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(); } } @@ -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/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 40fb7654f4..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); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 2fe141d24e..5f6cb17bda 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -282,8 +282,6 @@ static inline int lsi_irq_on_rsl(LSIState *s) static void lsi_soft_reset(LSIState *s) { - lsi_request *p; - DPRINTF("Reset\n"); s->carry = 0; @@ -350,15 +348,8 @@ static void lsi_soft_reset(LSIState *s) s->sbc = 0; s->csbc = 0; s->sbr = 0; - while (!QTAILQ_EMPTY(&s->queue)) { - p = QTAILQ_FIRST(&s->queue); - QTAILQ_REMOVE(&s->queue, p, next); - g_free(p); - } - if (s->current) { - g_free(s->current); - s->current = NULL; - } + assert(QTAILQ_EMPTY(&s->queue)); + assert(!s->current); } static int lsi_dma_40bit(LSIState *s) @@ -650,23 +641,24 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag) return NULL; } +static void lsi_request_free(LSIState *s, lsi_request *p) +{ + if (p == s->current) { + s->current = NULL; + } else { + QTAILQ_REMOVE(&s->queue, p, next); + } + g_free(p); +} + static void lsi_request_cancelled(SCSIRequest *req) { LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); lsi_request *p = req->hba_private; - if (s->current && req == s->current->req) { - scsi_req_unref(req); - g_free(s->current); - s->current = NULL; - return; - } - - if (p) { - QTAILQ_REMOVE(&s->queue, p, next); - scsi_req_unref(req); - g_free(p); - } + req->hba_private = NULL; + lsi_request_free(s, p); + scsi_req_unref(req); } /* Record that data is available for a queued command. Returns zero if @@ -714,10 +706,10 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid lsi_set_phase(s, PHASE_ST); } - if (s->current && req == s->current->req) { - scsi_req_unref(s->current->req); - g_free(s->current); - s->current = NULL; + if (req->hba_private == s->current) { + req->hba_private = NULL; + lsi_request_free(s, s->current); + scsi_req_unref(req); } lsi_resume_script(s); } @@ -728,7 +720,8 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len) LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; - if (s->waiting == 1 || !s->current || req->hba_private != s->current || + assert(req->hba_private); + if (s->waiting == 1 || req->hba_private != s->current || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { if (lsi_queue_req(s, req, len)) { return; @@ -1738,7 +1731,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) lsi_execute_script(s); } if (val & LSI_ISTAT0_SRST) { - lsi_soft_reset(s); + qdev_reset_all(&s->dev.qdev); } break; case 0x16: /* MBOX0 */ diff --git a/hw/megasas.c b/hw/megasas.c index b99fa9792e..9a0eab1c98 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -544,7 +544,7 @@ static void megasas_reset_frames(MegasasState *s) static void megasas_abort_command(MegasasCmd *cmd) { if (cmd->req) { - scsi_req_abort(cmd->req, ABORTED_COMMAND); + scsi_req_cancel(cmd->req); cmd->req = NULL; } } @@ -1290,35 +1290,16 @@ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd) static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) { - uint8_t *dummy = g_malloc(cmd->iov_size); - - dma_buf_write(dummy, cmd->iov_size, &cmd->qsg); - - trace_megasas_dcmd_dump_frame(0, - dummy[0x00], dummy[0x01], dummy[0x02], dummy[0x03], - dummy[0x04], dummy[0x05], dummy[0x06], dummy[0x07]); - trace_megasas_dcmd_dump_frame(1, - dummy[0x08], dummy[0x09], dummy[0x0a], dummy[0x0b], - dummy[0x0c], dummy[0x0d], dummy[0x0e], dummy[0x0f]); - trace_megasas_dcmd_dump_frame(2, - dummy[0x10], dummy[0x11], dummy[0x12], dummy[0x13], - dummy[0x14], dummy[0x15], dummy[0x16], dummy[0x17]); - trace_megasas_dcmd_dump_frame(3, - dummy[0x18], dummy[0x19], dummy[0x1a], dummy[0x1b], - dummy[0x1c], dummy[0x1d], dummy[0x1e], dummy[0x1f]); - trace_megasas_dcmd_dump_frame(4, - dummy[0x20], dummy[0x21], dummy[0x22], dummy[0x23], - dummy[0x24], dummy[0x25], dummy[0x26], dummy[0x27]); - trace_megasas_dcmd_dump_frame(5, - dummy[0x28], dummy[0x29], dummy[0x2a], dummy[0x2b], - dummy[0x2c], dummy[0x2d], dummy[0x2e], dummy[0x2f]); - trace_megasas_dcmd_dump_frame(6, - dummy[0x30], dummy[0x31], dummy[0x32], dummy[0x33], - dummy[0x34], dummy[0x35], dummy[0x36], dummy[0x37]); - trace_megasas_dcmd_dump_frame(7, - dummy[0x38], dummy[0x39], dummy[0x3a], dummy[0x3b], - dummy[0x3c], dummy[0x3d], dummy[0x3e], dummy[0x3f]); - g_free(dummy); + struct mfi_ctrl_props info; + size_t dcmd_size = sizeof(info); + + if (cmd->iov_size < dcmd_size) { + trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, + dcmd_size); + return MFI_STAT_INVALID_PARAMETER; + } + dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg); + trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size); return MFI_STAT_OK; } diff --git a/hw/ne2000.c b/hw/ne2000.c index 760ed2972a..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); } } 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/scsi-bus.c b/hw/scsi-bus.c index dc7406389d..e4ec19e051 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -186,6 +186,10 @@ static int scsi_qdev_init(DeviceState *qdev) dev); } + if (bus->info->hotplug) { + bus->info->hotplug(bus, dev); + } + err: return rc; } @@ -1068,6 +1072,16 @@ int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) return 0; } +void scsi_device_report_change(SCSIDevice *dev, SCSISense sense) +{ + SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); + + scsi_device_set_ua(dev, sense); + if (bus->info->change) { + bus->info->change(bus, dev, sense); + } +} + /* * Predefined sense codes */ @@ -1112,6 +1126,16 @@ const struct SCSISense sense_code_INVALID_FIELD = { .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 }; +/* Illegal request, Invalid field in parameter list */ +const struct SCSISense sense_code_INVALID_PARAM = { + .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00 +}; + +/* Illegal request, Parameter list length error */ +const struct SCSISense sense_code_INVALID_PARAM_LEN = { + .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00 +}; + /* Illegal request, LUN not supported */ const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 @@ -1147,6 +1171,11 @@ const struct SCSISense sense_code_LUN_FAILURE = { .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 }; +/* Unit attention, Capacity data has changed */ +const struct SCSISense sense_code_CAPACITY_CHANGED = { + .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 +}; + /* Unit attention, Power on, reset or bus device reset occurred */ const struct SCSISense sense_code_RESET = { .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 @@ -1172,6 +1201,11 @@ const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 }; +/* Data Protection, Write Protected */ +const struct SCSISense sense_code_WRITE_PROTECTED = { + .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00 +}; + /* * scsi_build_sense * @@ -1481,6 +1515,7 @@ void scsi_req_complete(SCSIRequest *req, int status) void scsi_req_cancel(SCSIRequest *req) { + trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); if (!req->enqueued) { return; } @@ -1511,6 +1546,55 @@ void scsi_req_abort(SCSIRequest *req, int status) scsi_req_unref(req); } +static int scsi_ua_precedence(SCSISense sense) +{ + if (sense.key != UNIT_ATTENTION) { + return INT_MAX; + } + if (sense.asc == 0x29 && sense.ascq == 0x04) { + /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */ + return 1; + } else if (sense.asc == 0x3F && sense.ascq == 0x01) { + /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */ + return 2; + } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) { + /* These two go with "all others". */ + ; + } else if (sense.asc == 0x29 && sense.ascq <= 0x07) { + /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0 + * POWER ON OCCURRED = 1 + * SCSI BUS RESET OCCURRED = 2 + * BUS DEVICE RESET FUNCTION OCCURRED = 3 + * I_T NEXUS LOSS OCCURRED = 7 + */ + return sense.ascq; + } else if (sense.asc == 0x2F && sense.ascq == 0x01) { + /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION */ + return 8; + } + return (sense.asc << 8) | sense.ascq; +} + +void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense) +{ + int prec1, prec2; + if (sense.key != UNIT_ATTENTION) { + return; + } + trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key, + sense.asc, sense.ascq); + + /* + * Override a pre-existing unit attention condition, except for a more + * important reset condition. + */ + prec1 = scsi_ua_precedence(sdev->unit_attention); + prec2 = scsi_ua_precedence(sense); + if (prec2 < prec1) { + sdev->unit_attention = sense; + } +} + void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) { SCSIRequest *req; @@ -1519,7 +1603,8 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) req = QTAILQ_FIRST(&sdev->requests); scsi_req_cancel(req); } - sdev->unit_attention = sense; + + scsi_device_set_ua(sdev, sense); } static char *scsibus_get_dev_path(DeviceState *dev) @@ -1634,6 +1719,17 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) return 0; } +static int scsi_qdev_unplug(DeviceState *qdev) +{ + SCSIDevice *dev = SCSI_DEVICE(qdev); + SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); + + if (bus->info->hot_unplug) { + bus->info->hot_unplug(bus, dev); + } + return qdev_simple_unplug_cb(qdev); +} + static const VMStateInfo vmstate_info_scsi_requests = { .name = "scsi-requests", .get = get_scsi_requests, @@ -1670,7 +1766,7 @@ static void scsi_device_class_init(ObjectClass *klass, void *data) DeviceClass *k = DEVICE_CLASS(klass); k->bus_type = TYPE_SCSI_BUS; k->init = scsi_qdev_init; - k->unplug = qdev_simple_unplug_cb; + k->unplug = scsi_qdev_unplug; k->exit = scsi_qdev_exit; k->props = scsi_props; } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 525816cb76..84b63ffafb 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -43,6 +43,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 +#define SCSI_MAX_MODE_LEN 256 typedef struct SCSIDiskState SCSIDiskState; @@ -72,6 +73,8 @@ struct SCSIDiskState QEMUBH *bh; char *version; char *serial; + char *vendor; + char *product; bool tray_open; bool tray_locked; }; @@ -167,7 +170,7 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) qemu_iovec_init_external(&r->qiov, &r->iov, 1); } -static void scsi_flush_complete(void * opaque, int ret) +static void scsi_aio_complete(void *opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); @@ -220,7 +223,7 @@ static void scsi_write_do_fua(SCSIDiskReq *r) if (scsi_is_cmd_fua(&r->req.cmd)) { bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH); - r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r); + r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); return; } @@ -341,13 +344,6 @@ static void scsi_read_data(SCSIRequest *req) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); bool first; - if (r->sector_count == (uint32_t)-1) { - DPRINTF("Read buf_len=%zd\n", r->iov.iov_len); - r->sector_count = 0; - r->started = true; - scsi_req_data(&r->req, r->iov.iov_len); - return; - } DPRINTF("Read sector_count=%d\n", r->sector_count); if (r->sector_count == 0) { /* This also clears the sense buffer for REQUEST SENSE. */ @@ -669,12 +665,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) outbuf[0] = s->qdev.type & 0x1f; outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; - if (s->qdev.type == TYPE_ROM) { - memcpy(&outbuf[16], "QEMU CD-ROM ", 16); - } else { - memcpy(&outbuf[16], "QEMU HARDDISK ", 16); - } - memcpy(&outbuf[8], "QEMU ", 8); + + strpadcpy((char *) &outbuf[16], 16, s->product, ' '); + strpadcpy((char *) &outbuf[8], 8, s->vendor, ' '); + memset(&outbuf[32], 0, 4); memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version))); /* @@ -966,148 +960,157 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM), [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM), }; - uint8_t *p = *p_outbuf; + + uint8_t *p = *p_outbuf + 2; + int length; if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) { return -1; } - p[0] = page; - /* * If Changeable Values are requested, a mask denoting those mode parameters * that are changeable shall be returned. As we currently don't support * parameter changes via MODE_SELECT all bits are returned set to zero. * The buffer was already menset to zero by the caller of this function. + * + * The offsets here are off by two compared to the descriptions in the + * SCSI specs, because those include a 2-byte header. This is unfortunate, + * but it is done so that offsets are consistent within our implementation + * of MODE SENSE and MODE SELECT. MODE SELECT has to deal with both + * 2-byte and 4-byte headers. */ switch (page) { case MODE_PAGE_HD_GEOMETRY: - p[1] = 0x16; + length = 0x16; if (page_control == 1) { /* Changeable Values */ break; } /* if a geometry hint is available, use it */ - p[2] = (s->qdev.conf.cyls >> 16) & 0xff; - p[3] = (s->qdev.conf.cyls >> 8) & 0xff; - p[4] = s->qdev.conf.cyls & 0xff; - p[5] = s->qdev.conf.heads & 0xff; + p[0] = (s->qdev.conf.cyls >> 16) & 0xff; + p[1] = (s->qdev.conf.cyls >> 8) & 0xff; + p[2] = s->qdev.conf.cyls & 0xff; + p[3] = s->qdev.conf.heads & 0xff; /* Write precomp start cylinder, disabled */ - p[6] = (s->qdev.conf.cyls >> 16) & 0xff; - p[7] = (s->qdev.conf.cyls >> 8) & 0xff; - p[8] = s->qdev.conf.cyls & 0xff; + p[4] = (s->qdev.conf.cyls >> 16) & 0xff; + p[5] = (s->qdev.conf.cyls >> 8) & 0xff; + p[6] = s->qdev.conf.cyls & 0xff; /* Reduced current start cylinder, disabled */ - p[9] = (s->qdev.conf.cyls >> 16) & 0xff; - p[10] = (s->qdev.conf.cyls >> 8) & 0xff; - p[11] = s->qdev.conf.cyls & 0xff; + p[7] = (s->qdev.conf.cyls >> 16) & 0xff; + p[8] = (s->qdev.conf.cyls >> 8) & 0xff; + p[9] = s->qdev.conf.cyls & 0xff; /* Device step rate [ns], 200ns */ - p[12] = 0; - p[13] = 200; + p[10] = 0; + p[11] = 200; /* Landing zone cylinder */ + p[12] = 0xff; + p[13] = 0xff; p[14] = 0xff; - p[15] = 0xff; - p[16] = 0xff; /* Medium rotation rate [rpm], 5400 rpm */ - p[20] = (5400 >> 8) & 0xff; - p[21] = 5400 & 0xff; + p[18] = (5400 >> 8) & 0xff; + p[19] = 5400 & 0xff; break; case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY: - p[1] = 0x1e; + length = 0x1e; if (page_control == 1) { /* Changeable Values */ break; } /* Transfer rate [kbit/s], 5Mbit/s */ - p[2] = 5000 >> 8; - p[3] = 5000 & 0xff; + p[0] = 5000 >> 8; + p[1] = 5000 & 0xff; /* if a geometry hint is available, use it */ - p[4] = s->qdev.conf.heads & 0xff; - p[5] = s->qdev.conf.secs & 0xff; - p[6] = s->qdev.blocksize >> 8; + p[2] = s->qdev.conf.heads & 0xff; + p[3] = s->qdev.conf.secs & 0xff; + p[4] = s->qdev.blocksize >> 8; + p[6] = (s->qdev.conf.cyls >> 8) & 0xff; + p[7] = s->qdev.conf.cyls & 0xff; + /* Write precomp start cylinder, disabled */ p[8] = (s->qdev.conf.cyls >> 8) & 0xff; p[9] = s->qdev.conf.cyls & 0xff; - /* Write precomp start cylinder, disabled */ + /* Reduced current start cylinder, disabled */ p[10] = (s->qdev.conf.cyls >> 8) & 0xff; p[11] = s->qdev.conf.cyls & 0xff; - /* Reduced current start cylinder, disabled */ - p[12] = (s->qdev.conf.cyls >> 8) & 0xff; - p[13] = s->qdev.conf.cyls & 0xff; /* Device step rate [100us], 100us */ - p[14] = 0; - p[15] = 1; + p[12] = 0; + p[13] = 1; /* Device step pulse width [us], 1us */ - p[16] = 1; + p[14] = 1; /* Device head settle delay [100us], 100us */ - p[17] = 0; - p[18] = 1; + p[15] = 0; + p[16] = 1; /* Motor on delay [0.1s], 0.1s */ - p[19] = 1; + p[17] = 1; /* Motor off delay [0.1s], 0.1s */ - p[20] = 1; + p[18] = 1; /* Medium rotation rate [rpm], 5400 rpm */ - p[28] = (5400 >> 8) & 0xff; - p[29] = 5400 & 0xff; + p[26] = (5400 >> 8) & 0xff; + p[27] = 5400 & 0xff; break; case MODE_PAGE_CACHING: - p[0] = 8; - p[1] = 0x12; - if (page_control == 1) { /* Changeable Values */ - break; - } - if (bdrv_enable_write_cache(s->qdev.conf.bs)) { - p[2] = 4; /* WCE */ + length = 0x12; + if (page_control == 1 || /* Changeable Values */ + bdrv_enable_write_cache(s->qdev.conf.bs)) { + p[0] = 4; /* WCE */ } break; case MODE_PAGE_R_W_ERROR: - p[1] = 10; - p[2] = 0x80; /* Automatic Write Reallocation Enabled */ + length = 10; + if (page_control == 1) { /* Changeable Values */ + break; + } + p[0] = 0x80; /* Automatic Write Reallocation Enabled */ if (s->qdev.type == TYPE_ROM) { - p[3] = 0x20; /* Read Retry Count */ + p[1] = 0x20; /* Read Retry Count */ } break; case MODE_PAGE_AUDIO_CTL: - p[1] = 14; + length = 14; break; case MODE_PAGE_CAPABILITIES: - p[1] = 0x14; + length = 0x14; if (page_control == 1) { /* Changeable Values */ break; } - p[2] = 0x3b; /* CD-R & CD-RW read */ - p[3] = 0; /* Writing not supported */ - p[4] = 0x7f; /* Audio, composite, digital out, + p[0] = 0x3b; /* CD-R & CD-RW read */ + p[1] = 0; /* Writing not supported */ + p[2] = 0x7f; /* Audio, composite, digital out, mode 2 form 1&2, multi session */ - p[5] = 0xff; /* CD DA, DA accurate, RW supported, + p[3] = 0xff; /* CD DA, DA accurate, RW supported, RW corrected, C2 errors, ISRC, UPC, Bar code */ - p[6] = 0x2d | (s->tray_locked ? 2 : 0); + p[4] = 0x2d | (s->tray_locked ? 2 : 0); /* Locking supported, jumper present, eject, tray */ - p[7] = 0; /* no volume & mute control, no + p[5] = 0; /* no volume & mute control, no changer */ - p[8] = (50 * 176) >> 8; /* 50x read speed */ - p[9] = (50 * 176) & 0xff; - p[10] = 2 >> 8; /* Two volume levels */ - p[11] = 2 & 0xff; - p[12] = 2048 >> 8; /* 2M buffer */ - p[13] = 2048 & 0xff; - p[14] = (16 * 176) >> 8; /* 16x read speed current */ - p[15] = (16 * 176) & 0xff; - p[18] = (16 * 176) >> 8; /* 16x write speed */ + p[6] = (50 * 176) >> 8; /* 50x read speed */ + p[7] = (50 * 176) & 0xff; + p[8] = 2 >> 8; /* Two volume levels */ + p[9] = 2 & 0xff; + p[10] = 2048 >> 8; /* 2M buffer */ + p[11] = 2048 & 0xff; + p[12] = (16 * 176) >> 8; /* 16x read speed current */ + p[13] = (16 * 176) & 0xff; + p[16] = (16 * 176) >> 8; /* 16x write speed */ + p[17] = (16 * 176) & 0xff; + p[18] = (16 * 176) >> 8; /* 16x write speed current */ p[19] = (16 * 176) & 0xff; - p[20] = (16 * 176) >> 8; /* 16x write speed current */ - p[21] = (16 * 176) & 0xff; break; default: return -1; } - *p_outbuf += p[1] + 2; - return p[1] + 2; + assert(length < 256); + (*p_outbuf)[0] = page; + (*p_outbuf)[1] = length; + *p_outbuf += length + 2; + return length + 2; } static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) @@ -1245,7 +1248,7 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r) bool start = req->cmd.buf[4] & 1; bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */ - if (s->qdev.type == TYPE_ROM && loej) { + if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) { if (!start && !s->tray_open && s->tray_locked) { scsi_check_condition(r, bdrv_is_inserted(s->qdev.conf.bs) @@ -1262,13 +1265,239 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r) return 0; } -static int scsi_disk_emulate_command(SCSIDiskReq *r) +static void scsi_disk_emulate_read_data(SCSIRequest *req) { - SCSIRequest *req = &r->req; + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + int buflen = r->iov.iov_len; + + if (buflen) { + DPRINTF("Read buf_len=%zd\n", buflen); + r->iov.iov_len = 0; + r->started = true; + scsi_req_data(&r->req, buflen); + return; + } + + /* This also clears the sense buffer for REQUEST SENSE. */ + scsi_req_complete(&r->req, GOOD); +} + +static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, + uint8_t *inbuf, int inlen) +{ + uint8_t mode_current[SCSI_MAX_MODE_LEN]; + uint8_t mode_changeable[SCSI_MAX_MODE_LEN]; + uint8_t *p; + int len, expected_len, changeable_len, i; + + /* The input buffer does not include the page header, so it is + * off by 2 bytes. + */ + expected_len = inlen + 2; + if (expected_len > SCSI_MAX_MODE_LEN) { + return -1; + } + + p = mode_current; + memset(mode_current, 0, inlen + 2); + len = mode_sense_page(s, page, &p, 0); + if (len < 0 || len != expected_len) { + return -1; + } + + p = mode_changeable; + memset(mode_changeable, 0, inlen + 2); + changeable_len = mode_sense_page(s, page, &p, 1); + assert(changeable_len == len); + + /* Check that unchangeable bits are the same as what MODE SENSE + * would return. + */ + for (i = 2; i < len; i++) { + if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) { + return -1; + } + } + return 0; +} + +static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p) +{ + switch (page) { + case MODE_PAGE_CACHING: + bdrv_set_enable_write_cache(s->qdev.conf.bs, (p[0] & 4) != 0); + break; + + default: + break; + } +} + +static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + while (len > 0) { + int page, subpage, page_len; + + /* Parse both possible formats for the mode page headers. */ + page = p[0] & 0x3f; + if (p[0] & 0x40) { + if (len < 4) { + goto invalid_param_len; + } + subpage = p[1]; + page_len = lduw_be_p(&p[2]); + p += 4; + len -= 4; + } else { + if (len < 2) { + goto invalid_param_len; + } + subpage = 0; + page_len = p[1]; + p += 2; + len -= 2; + } + + if (subpage) { + goto invalid_param; + } + if (page_len > len) { + goto invalid_param_len; + } + + if (!change) { + if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) { + goto invalid_param; + } + } else { + scsi_disk_apply_mode_select(s, page, p); + } + + p += page_len; + len -= page_len; + } + return 0; + +invalid_param: + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM)); + return -1; + +invalid_param_len: + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return -1; +} + +static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) +{ + uint8_t *p = inbuf; + int cmd = r->req.cmd.buf[0]; + int len = r->req.cmd.xfer; + int hdr_len = (cmd == MODE_SELECT ? 4 : 8); + int bd_len; + int pass; + + /* We only support PF=1, SP=0. */ + if ((r->req.cmd.buf[1] & 0x11) != 0x10) { + goto invalid_field; + } + + if (len < hdr_len) { + goto invalid_param_len; + } + + bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6])); + len -= hdr_len; + p += hdr_len; + if (len < bd_len) { + goto invalid_param_len; + } + if (bd_len != 0 && bd_len != 8) { + goto invalid_param; + } + + len -= bd_len; + p += bd_len; + + /* Ensure no change is made if there is an error! */ + for (pass = 0; pass < 2; pass++) { + if (mode_select_pages(r, p, len, pass == 1) < 0) { + assert(pass == 0); + return; + } + } + scsi_req_complete(&r->req, GOOD); + return; + +invalid_param: + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM)); + return; + +invalid_param_len: + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return; + +invalid_field: + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); + return; +} + +static void scsi_disk_emulate_write_data(SCSIRequest *req) +{ + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + + if (r->iov.iov_len) { + int buflen = r->iov.iov_len; + DPRINTF("Write buf_len=%zd\n", buflen); + r->iov.iov_len = 0; + scsi_req_data(&r->req, buflen); + return; + } + + switch (req->cmd.buf[0]) { + case MODE_SELECT: + case MODE_SELECT_10: + /* This also clears the sense buffer for REQUEST SENSE. */ + scsi_disk_emulate_mode_select(r, r->iov.iov_base); + break; + + default: + abort(); + } +} + +static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) +{ + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); uint64_t nb_sectors; uint8_t *outbuf; - int buflen = 0; + int buflen; + + switch (req->cmd.buf[0]) { + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + case RESERVE: + case RESERVE_10: + case RELEASE: + case RELEASE_10: + case START_STOP: + case ALLOW_MEDIUM_REMOVAL: + case GET_CONFIGURATION: + case GET_EVENT_STATUS_NOTIFICATION: + case MECHANISM_STATUS: + case REQUEST_SENSE: + break; + + default: + if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); + return 0; + } + break; + } if (!r->iov.iov_base) { /* @@ -1286,6 +1515,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r) r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); } + buflen = req->cmd.xfer; outbuf = r->iov.iov_base; switch (req->cmd.buf[0]) { case TEST_UNIT_READY: @@ -1332,7 +1562,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r) break; case START_STOP: if (scsi_disk_emulate_start_stop(r) < 0) { - return -1; + return 0; } break; case ALLOW_MEDIUM_REMOVAL: @@ -1448,18 +1678,78 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r) } DPRINTF("Unsupported Service Action In\n"); goto illegal_request; + case SYNCHRONIZE_CACHE: + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH); + r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); + return 0; + case SEEK_10: + DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba); + if (r->req.cmd.lba > s->qdev.max_lba) { + goto illegal_lba; + } + break; + case MODE_SELECT: + DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer); + break; + case MODE_SELECT_10: + DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer); + break; + case WRITE_SAME_10: + nb_sectors = lduw_be_p(&req->cmd.buf[7]); + goto write_same; + case WRITE_SAME_16: + nb_sectors = ldl_be_p(&req->cmd.buf[10]) & 0xffffffffULL; + write_same: + if (bdrv_is_read_only(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return 0; + } + if (r->req.cmd.lba > s->qdev.max_lba) { + goto illegal_lba; + } + + /* + * We only support WRITE SAME with the unmap bit set for now. + */ + if (!(req->cmd.buf[1] & 0x8)) { + goto illegal_request; + } + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs, + r->req.cmd.lba * (s->qdev.blocksize / 512), + nb_sectors * (s->qdev.blocksize / 512), + scsi_aio_complete, r); + return 0; default: + DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); - return -1; + return 0; + } + assert(!r->req.aiocb); + r->iov.iov_len = MIN(buflen, req->cmd.xfer); + if (r->iov.iov_len == 0) { + scsi_req_complete(&r->req, GOOD); + } + if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { + assert(r->iov.iov_len == req->cmd.xfer); + return -r->iov.iov_len; + } else { + return r->iov.iov_len; } - buflen = MIN(buflen, req->cmd.xfer); - return buflen; illegal_request: if (r->req.status == -1) { scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); } - return -1; + return 0; + +illegal_lba: + scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); + return 0; } /* Execute a scsi command. Returns the length of the data expected by the @@ -1467,99 +1757,37 @@ illegal_request: (eg. disk reads), negative for transfers to the device (eg. disk writes), and zero if the command does not transfer any data. */ -static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) +static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int32_t len; uint8_t command; - int rc; command = buf[0]; - DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]); - -#ifdef DEBUG_SCSI - { - int i; - for (i = 1; i < r->req.cmd.len; i++) { - printf(" 0x%02x", buf[i]); - } - printf("\n"); - } -#endif - switch (command) { - case INQUIRY: - case MODE_SENSE: - case MODE_SENSE_10: - case RESERVE: - case RESERVE_10: - case RELEASE: - case RELEASE_10: - case START_STOP: - case ALLOW_MEDIUM_REMOVAL: - case GET_CONFIGURATION: - case GET_EVENT_STATUS_NOTIFICATION: - case MECHANISM_STATUS: - case REQUEST_SENSE: - break; - - default: - if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) { - scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); - return 0; - } - break; + if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); + return 0; } switch (command) { - case TEST_UNIT_READY: - case INQUIRY: - case MODE_SENSE: - case MODE_SENSE_10: - case RESERVE: - case RESERVE_10: - case RELEASE: - case RELEASE_10: - case START_STOP: - case ALLOW_MEDIUM_REMOVAL: - case READ_CAPACITY_10: - case READ_TOC: - case READ_DISC_INFORMATION: - case READ_DVD_STRUCTURE: - case GET_CONFIGURATION: - case GET_EVENT_STATUS_NOTIFICATION: - case MECHANISM_STATUS: - case SERVICE_ACTION_IN_16: - case REQUEST_SENSE: - rc = scsi_disk_emulate_command(r); - if (rc < 0) { - return 0; - } - - r->iov.iov_len = rc; - break; - case SYNCHRONIZE_CACHE: - /* The request is used as the AIO opaque value, so add a ref. */ - scsi_req_ref(&r->req); - bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH); - r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r); - return 0; case READ_6: case READ_10: case READ_12: case READ_16: len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); - if (r->req.cmd.lba > s->qdev.max_lba) { + if (r->req.cmd.buf[1] & 0xe0) { + goto illegal_request; + } + if (r->req.cmd.lba > r->req.cmd.lba + len || + r->req.cmd.lba + len - 1 > s->qdev.max_lba) { goto illegal_lba; } r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); r->sector_count = len * (s->qdev.blocksize / 512); break; - case VERIFY_10: - case VERIFY_12: - case VERIFY_16: case WRITE_6: case WRITE_10: case WRITE_12: @@ -1567,90 +1795,45 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) case WRITE_VERIFY_10: case WRITE_VERIFY_12: case WRITE_VERIFY_16: + if (bdrv_is_read_only(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return 0; + } + /* fallthrough */ + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); - if (r->req.cmd.lba > s->qdev.max_lba) { + if (r->req.cmd.buf[1] & 0xe0) { + goto illegal_request; + } + if (r->req.cmd.lba > r->req.cmd.lba + len || + r->req.cmd.lba + len - 1 > s->qdev.max_lba) { goto illegal_lba; } r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); r->sector_count = len * (s->qdev.blocksize / 512); break; - case MODE_SELECT: - DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer); - /* We don't support mode parameter changes. - Allow the mode parameter header + block descriptors only. */ - if (r->req.cmd.xfer > 12) { - goto fail; - } - break; - case MODE_SELECT_10: - DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer); - /* We don't support mode parameter changes. - Allow the mode parameter header + block descriptors only. */ - if (r->req.cmd.xfer > 16) { - goto fail; - } - break; - case SEEK_10: - DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba); - if (r->req.cmd.lba > s->qdev.max_lba) { - goto illegal_lba; - } - break; - case WRITE_SAME_10: - len = lduw_be_p(&buf[7]); - goto write_same; - case WRITE_SAME_16: - len = ldl_be_p(&buf[10]) & 0xffffffffULL; - write_same: - - DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n", - r->req.cmd.lba, len); - - if (r->req.cmd.lba > s->qdev.max_lba) { - goto illegal_lba; - } - - /* - * We only support WRITE SAME with the unmap bit set for now. - */ - if (!(buf[1] & 0x8)) { - goto fail; - } - - rc = bdrv_discard(s->qdev.conf.bs, - r->req.cmd.lba * (s->qdev.blocksize / 512), - len * (s->qdev.blocksize / 512)); - if (rc < 0) { - /* XXX: better error code ?*/ - goto fail; - } - - break; default: - DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); - scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); - return 0; - fail: + abort(); + illegal_request: scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); return 0; illegal_lba: scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); return 0; } - if (r->sector_count == 0 && r->iov.iov_len == 0) { + if (r->sector_count == 0) { scsi_req_complete(&r->req, GOOD); } - len = r->sector_count * 512 + r->iov.iov_len; + assert(r->iov.iov_len == 0); if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { - return -len; + return -r->sector_count * 512; } else { - if (!r->sector_count) { - r->sector_count = -1; - } - return len; + return r->sector_count * 512; } } @@ -1677,6 +1860,19 @@ static void scsi_destroy(SCSIDevice *dev) blockdev_mark_auto_del(s->qdev.conf.bs); } +static void scsi_disk_resize_cb(void *opaque) +{ + SCSIDiskState *s = opaque; + + /* SPC lists this sense code as available only for + * direct-access devices. + */ + if (s->qdev.type == TYPE_DISK) { + scsi_device_set_ua(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); + scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); + } +} + static void scsi_cd_change_media_cb(void *opaque, bool load) { SCSIDiskState *s = opaque; @@ -1693,7 +1889,7 @@ static void scsi_cd_change_media_cb(void *opaque, bool load) */ s->media_changed = load; s->tray_open = !load; - s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM); + scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM)); s->media_event = true; s->eject_request = false; } @@ -1718,11 +1914,17 @@ static bool scsi_cd_is_medium_locked(void *opaque) return ((SCSIDiskState *)opaque)->tray_locked; } -static const BlockDevOps scsi_cd_block_ops = { +static const BlockDevOps scsi_disk_removable_block_ops = { .change_media_cb = scsi_cd_change_media_cb, .eject_request_cb = scsi_cd_eject_request_cb, .is_tray_open = scsi_cd_is_tray_open, .is_medium_locked = scsi_cd_is_medium_locked, + + .resize_cb = scsi_disk_resize_cb, +}; + +static const BlockDevOps scsi_disk_block_ops = { + .resize_cb = scsi_disk_resize_cb, }; static void scsi_disk_unit_attention_reported(SCSIDevice *dev) @@ -1730,7 +1932,7 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); if (s->media_changed) { s->media_changed = false; - s->qdev.unit_attention = SENSE_CODE(MEDIUM_CHANGED); + scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED)); } } @@ -1757,6 +1959,9 @@ static int scsi_initfn(SCSIDevice *dev) if (!s->version) { s->version = g_strdup(qemu_get_version()); } + if (!s->vendor) { + s->vendor = g_strdup("QEMU"); + } if (bdrv_is_sg(s->qdev.conf.bs)) { error_report("unwanted /dev/sg*"); @@ -1764,7 +1969,9 @@ static int scsi_initfn(SCSIDevice *dev) } if (s->features & (1 << SCSI_DISK_F_REMOVABLE)) { - bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s); + bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_removable_block_ops, s); + } else { + bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_block_ops, s); } bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); @@ -1778,6 +1985,9 @@ static int scsi_hd_initfn(SCSIDevice *dev) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); s->qdev.blocksize = s->qdev.conf.logical_block_size; s->qdev.type = TYPE_DISK; + if (!s->product) { + s->product = g_strdup("QEMU HARDDISK"); + } return scsi_initfn(&s->qdev); } @@ -1787,6 +1997,9 @@ static int scsi_cd_initfn(SCSIDevice *dev) s->qdev.blocksize = 2048; s->qdev.type = TYPE_ROM; s->features |= 1 << SCSI_DISK_F_REMOVABLE; + if (!s->product) { + s->product = g_strdup("QEMU CD-ROM"); + } return scsi_initfn(&s->qdev); } @@ -1806,10 +2019,19 @@ static int scsi_disk_initfn(SCSIDevice *dev) } } -static const SCSIReqOps scsi_disk_reqops = { +static const SCSIReqOps scsi_disk_emulate_reqops = { .size = sizeof(SCSIDiskReq), .free_req = scsi_free_request, - .send_command = scsi_send_command, + .send_command = scsi_disk_emulate_command, + .read_data = scsi_disk_emulate_read_data, + .write_data = scsi_disk_emulate_write_data, + .get_buf = scsi_get_buf, +}; + +static const SCSIReqOps scsi_disk_dma_reqops = { + .size = sizeof(SCSIDiskReq), + .free_req = scsi_free_request, + .send_command = scsi_disk_dma_command, .read_data = scsi_read_data, .write_data = scsi_write_data, .cancel_io = scsi_cancel_io, @@ -1818,13 +2040,70 @@ static const SCSIReqOps scsi_disk_reqops = { .save_request = scsi_disk_save_request, }; +static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { + [TEST_UNIT_READY] = &scsi_disk_emulate_reqops, + [INQUIRY] = &scsi_disk_emulate_reqops, + [MODE_SENSE] = &scsi_disk_emulate_reqops, + [MODE_SENSE_10] = &scsi_disk_emulate_reqops, + [START_STOP] = &scsi_disk_emulate_reqops, + [ALLOW_MEDIUM_REMOVAL] = &scsi_disk_emulate_reqops, + [READ_CAPACITY_10] = &scsi_disk_emulate_reqops, + [READ_TOC] = &scsi_disk_emulate_reqops, + [READ_DVD_STRUCTURE] = &scsi_disk_emulate_reqops, + [READ_DISC_INFORMATION] = &scsi_disk_emulate_reqops, + [GET_CONFIGURATION] = &scsi_disk_emulate_reqops, + [GET_EVENT_STATUS_NOTIFICATION] = &scsi_disk_emulate_reqops, + [MECHANISM_STATUS] = &scsi_disk_emulate_reqops, + [SERVICE_ACTION_IN_16] = &scsi_disk_emulate_reqops, + [REQUEST_SENSE] = &scsi_disk_emulate_reqops, + [SYNCHRONIZE_CACHE] = &scsi_disk_emulate_reqops, + [SEEK_10] = &scsi_disk_emulate_reqops, + [MODE_SELECT] = &scsi_disk_emulate_reqops, + [MODE_SELECT_10] = &scsi_disk_emulate_reqops, + [WRITE_SAME_10] = &scsi_disk_emulate_reqops, + [WRITE_SAME_16] = &scsi_disk_emulate_reqops, + + [READ_6] = &scsi_disk_dma_reqops, + [READ_10] = &scsi_disk_dma_reqops, + [READ_12] = &scsi_disk_dma_reqops, + [READ_16] = &scsi_disk_dma_reqops, + [VERIFY_10] = &scsi_disk_dma_reqops, + [VERIFY_12] = &scsi_disk_dma_reqops, + [VERIFY_16] = &scsi_disk_dma_reqops, + [WRITE_6] = &scsi_disk_dma_reqops, + [WRITE_10] = &scsi_disk_dma_reqops, + [WRITE_12] = &scsi_disk_dma_reqops, + [WRITE_16] = &scsi_disk_dma_reqops, + [WRITE_VERIFY_10] = &scsi_disk_dma_reqops, + [WRITE_VERIFY_12] = &scsi_disk_dma_reqops, + [WRITE_VERIFY_16] = &scsi_disk_dma_reqops, +}; + static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIRequest *req; + const SCSIReqOps *ops; + uint8_t command; + +#ifdef DEBUG_SCSI + DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, buf[0]); + { + int i; + for (i = 1; i < r->req.cmd.len; i++) { + printf(" 0x%02x", buf[i]); + } + printf("\n"); + } +#endif - req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private); + command = buf[0]; + ops = scsi_disk_reqops_dispatch[command]; + if (!ops) { + ops = &scsi_disk_emulate_reqops; + } + req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private); return req; } @@ -1938,15 +2217,14 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, * unreliable, too. It is even possible that reads deliver random data * from the host page cache (this is probably a Linux bug). * - * We might use scsi_disk_reqops as long as no writing commands are + * We might use scsi_disk_dma_reqops as long as no writing commands are * seen, but performance usually isn't paramount on optical media. So, * just make scsi-block operate the same as scsi-generic for them. */ - if (s->qdev.type == TYPE_ROM) { - break; - } - return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, - hba_private); + if (s->qdev.type != TYPE_ROM) { + return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun, + hba_private); + } } return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun, @@ -1954,10 +2232,12 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, } #endif -#define DEFINE_SCSI_DISK_PROPERTIES() \ - DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \ - DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ - DEFINE_PROP_STRING("serial", SCSIDiskState, serial) +#define DEFINE_SCSI_DISK_PROPERTIES() \ + DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \ + DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ + DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \ + DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \ + DEFINE_PROP_STRING("product", SCSIDiskState, product) static Property scsi_hd_properties[] = { DEFINE_SCSI_DISK_PROPERTIES(), @@ -2040,7 +2320,7 @@ static TypeInfo scsi_cd_info = { #ifdef __linux__ static Property scsi_block_properties[] = { - DEFINE_SCSI_DISK_PROPERTIES(), + DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs), DEFINE_PROP_END_OF_LIST(), }; @@ -131,6 +131,9 @@ struct SCSIBusInfo { void (*transfer_data)(SCSIRequest *req, uint32_t arg); void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid); void (*cancel)(SCSIRequest *req); + void (*hotplug)(SCSIBus *bus, SCSIDevice *dev); + void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev); + void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense); QEMUSGList *(*get_sg_list)(SCSIRequest *req); void (*save_request)(QEMUFile *f, SCSIRequest *req); @@ -180,6 +183,10 @@ extern const struct SCSISense sense_code_INVALID_OPCODE; extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE; /* Illegal request, Invalid field in CDB */ extern const struct SCSISense sense_code_INVALID_FIELD; +/* Illegal request, Invalid field in parameter list */ +extern const struct SCSISense sense_code_INVALID_PARAM; +/* Illegal request, Parameter list length error */ +extern const struct SCSISense sense_code_INVALID_PARAM_LEN; /* Illegal request, LUN not supported */ extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; /* Illegal request, Saving parameters not supported */ @@ -194,6 +201,8 @@ extern const struct SCSISense sense_code_IO_ERROR; extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; /* Command aborted, Logical Unit failure */ extern const struct SCSISense sense_code_LUN_FAILURE; +/* LUN not ready, Capacity data has changed */ +extern const struct SCSISense sense_code_CAPACITY_CHANGED; /* LUN not ready, Medium not present */ extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; /* Unit attention, Power on, reset or bus device reset occurred */ @@ -204,6 +213,8 @@ extern const struct SCSISense sense_code_MEDIUM_CHANGED; extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED; /* Unit attention, Device internal reset */ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET; +/* Data Protection, Write Protected */ +extern const struct SCSISense sense_code_WRITE_PROTECTED; #define SENSE_CODE(x) sense_code_ ## x @@ -231,6 +242,8 @@ void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_cancel(SCSIRequest *req); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); +void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); +void scsi_device_report_change(SCSIDevice *dev, SCSISense sense); int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 4e03f0b42c..1109467d19 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -1023,7 +1023,9 @@ static int virtio_scsi_init_pci(PCIDevice *pci_dev) return -EINVAL; } - vdev->nvectors = proxy->nvectors; + vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED + ? proxy->scsi.num_queues + 3 + : proxy->nvectors; virtio_init_pci(proxy, vdev); /* make the actual value visible */ @@ -1040,7 +1042,8 @@ static int virtio_scsi_exit_pci(PCIDevice *pci_dev) } static Property virtio_scsi_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED), DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 0a5ac40e2f..c4a5b22f94 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -24,6 +24,11 @@ #define VIRTIO_SCSI_MAX_TARGET 255 #define VIRTIO_SCSI_MAX_LUN 16383 +/* Feature Bits */ +#define VIRTIO_SCSI_F_INOUT 0 +#define VIRTIO_SCSI_F_HOTPLUG 1 +#define VIRTIO_SCSI_F_CHANGE 2 + /* Response codes */ #define VIRTIO_SCSI_S_OK 0 #define VIRTIO_SCSI_S_OVERRUN 1 @@ -59,6 +64,12 @@ #define VIRTIO_SCSI_T_NO_EVENT 0 #define VIRTIO_SCSI_T_TRANSPORT_RESET 1 #define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 +#define VIRTIO_SCSI_T_PARAM_CHANGE 3 + +/* Reasons for transport reset event */ +#define VIRTIO_SCSI_EVT_RESET_HARD 0 +#define VIRTIO_SCSI_EVT_RESET_RESCAN 1 +#define VIRTIO_SCSI_EVT_RESET_REMOVED 2 /* SCSI command request, followed by data-out */ typedef struct { @@ -132,6 +143,7 @@ typedef struct { uint32_t sense_size; uint32_t cdb_size; int resetting; + bool events_dropped; VirtQueue *ctrl_vq; VirtQueue *event_vq; VirtQueue *cmd_vqs[0]; @@ -206,11 +218,13 @@ static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) { - assert(req->elem.out_num && req->elem.in_num); + assert(req->elem.in_num); req->vq = vq; req->dev = s; req->sreq = NULL; - req->req.buf = req->elem.out_sg[0].iov_base; + if (req->elem.out_num) { + req->req.buf = req->elem.out_sg[0].iov_base; + } req->resp.buf = req->elem.in_sg[0].iov_base; if (req->elem.out_num > 1) { @@ -405,10 +419,6 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } } -static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) -{ -} - static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, size_t resid) { @@ -545,6 +555,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, uint32_t requested_features) { + requested_features |= (1UL << VIRTIO_SCSI_F_HOTPLUG); + requested_features |= (1UL << VIRTIO_SCSI_F_CHANGE); return requested_features; } @@ -554,6 +566,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev) s->sense_size = VIRTIO_SCSI_SENSE_SIZE; s->cdb_size = VIRTIO_SCSI_CDB_SIZE; + s->events_dropped = false; } /* The device does not have anything to save beyond the virtio data. @@ -577,6 +590,93 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason) +{ + VirtIOSCSIReq *req = virtio_scsi_pop_req(s, s->event_vq); + VirtIOSCSIEvent *evt; + int in_size; + + if (!req) { + s->events_dropped = true; + return; + } + + if (req->elem.out_num || req->elem.in_num != 1) { + virtio_scsi_bad_req(); + } + + if (s->events_dropped) { + event |= VIRTIO_SCSI_T_EVENTS_MISSED; + s->events_dropped = false; + } + + in_size = req->elem.in_sg[0].iov_len; + if (in_size < sizeof(VirtIOSCSIEvent)) { + virtio_scsi_bad_req(); + } + + evt = req->resp.event; + memset(evt, 0, sizeof(VirtIOSCSIEvent)); + evt->event = event; + evt->reason = reason; + if (!dev) { + assert(event == VIRTIO_SCSI_T_NO_EVENT); + } else { + evt->lun[0] = 1; + evt->lun[1] = dev->id; + + /* Linux wants us to keep the same encoding we use for REPORT LUNS. */ + if (dev->lun >= 256) { + evt->lun[2] = (dev->lun >> 8) | 0x40; + } + evt->lun[3] = dev->lun & 0xFF; + } + virtio_scsi_complete_req(req); +} + +static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + + if (s->events_dropped) { + virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); + } +} + +static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) +{ + VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); + + if (((s->vdev.guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) && + (s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) && + dev->type != TYPE_ROM) { + virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE, + sense.asc | (sense.ascq << 8)); + } +} + +static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev) +{ + VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); + + if (((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) && + (s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET, + VIRTIO_SCSI_EVT_RESET_RESCAN); + } +} + +static void virtio_scsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev) +{ + VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); + + if ((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) { + virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET, + VIRTIO_SCSI_EVT_RESET_REMOVED); + } +} + static struct SCSIBusInfo virtio_scsi_scsi_info = { .tcq = true, .max_channel = VIRTIO_SCSI_MAX_CHANNEL, @@ -585,6 +685,9 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .complete = virtio_scsi_command_complete, .cancel = virtio_scsi_request_cancelled, + .change = virtio_scsi_change, + .hotplug = virtio_scsi_hotplug, + .hot_unplug = virtio_scsi_hot_unplug, .get_sg_list = virtio_scsi_get_sg_list, .save_request = virtio_scsi_save_request, .load_request = virtio_scsi_load_request, 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/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/migration.h b/migration.h index de13004573..57572a61e9 100644 --- a/migration.h +++ b/migration.h @@ -18,6 +18,7 @@ #include "qemu-common.h" #include "notify.h" #include "error.h" +#include "vmstate.h" struct MigrationParams { bool blk; @@ -81,8 +82,7 @@ uint64_t ram_bytes_remaining(void); uint64_t ram_bytes_transferred(void); uint64_t ram_bytes_total(void); -int ram_save_live(QEMUFile *f, int stage, void *opaque); -int ram_load(QEMUFile *f, void *opaque, int version_id); +extern SaveVMHandlers savevm_ram_handlers; /** * @migrate_add_blocker - prevent migration from proceeding @@ -70,10 +70,12 @@ typedef signed int int_fast16_t; #ifndef always_inline #if !((__GNUC__ < 3) || defined(__APPLE__)) #ifdef __OPTIMIZE__ +#undef inline #define inline __attribute__ (( always_inline )) __inline__ #endif #endif #else +#undef inline #define inline always_inline #endif @@ -14,6 +14,7 @@ #pragma GCC poison TARGET_M68K #pragma GCC poison TARGET_MIPS #pragma GCC poison TARGET_MIPS64 +#pragma GCC poison TARGET_OPENRISC #pragma GCC poison TARGET_PPC #pragma GCC poison TARGET_PPCEMB #pragma GCC poison TARGET_PPC64 diff --git a/qemu-common.h b/qemu-common.h index 7c8dac80a2..d26ff39e87 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -138,6 +138,7 @@ int qemu_timedate_diff(struct tm *tm); /* cutils.c */ void pstrcpy(char *buf, int buf_size, const char *str); +void strpadcpy(char *buf, int buf_size, const char *str, char pad); char *pstrcat(char *buf, int buf_size, const char *s); int strstart(const char *str, const char *val, const char **ptr); int stristart(const char *str, const char *val, const char **ptr); diff --git a/qemu-sockets.c b/qemu-sockets.c index 2ae715db76..668fa93294 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -11,6 +11,9 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. */ #include <stdio.h> #include <stdlib.h> diff --git a/qga/Makefile.objs b/qga/Makefile.objs index 6a4d843436..cd3e13516c 100644 --- a/qga/Makefile.objs +++ b/qga/Makefile.objs @@ -1,3 +1,5 @@ qga-obj-y = commands.o guest-agent-command-state.o qga-obj-$(CONFIG_POSIX) += commands-posix.o channel-posix.o qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o +qga-obj-y += qapi-generated/qga-qapi-types.o qapi-generated/qga-qapi-visit.o +qga-obj-y += qapi-generated/qga-qmp-marshal.o @@ -94,7 +94,6 @@ define unnest-dir $(foreach var,$(nested-vars),$(call push-var,$(var),$1/)) $(eval obj := $(obj)/$1) $(eval include $(SRC_PATH)/$1/Makefile.objs) -$(eval -include $(wildcard $1/*.d)) $(eval obj := $(patsubst %/$1,%,$(obj))) $(foreach var,$(nested-vars),$(call pop-var,$(var),$1/)) endef @@ -113,4 +112,6 @@ define unnest-vars $(call unnest-vars-1) $(foreach var,$(nested-vars),$(eval $(var) := $(filter-out %/, $($(var))))) $(shell mkdir -p $(sort $(foreach var,$(nested-vars),$(dir $($(var)))))) +$(foreach var,$(nested-vars), $(eval \ + -include $(addsuffix *.d, $(sort $(dir $($(var))))))) endef @@ -1171,10 +1171,7 @@ typedef struct SaveStateEntry { int alias_id; int version_id; int section_id; - SaveSetParamsHandler *set_params; - SaveLiveStateHandler *save_live_state; - SaveStateHandler *save_state; - LoadStateHandler *load_state; + SaveVMHandlers *ops; const VMStateDescription *vmsd; void *opaque; CompatEntry *compat; @@ -1226,10 +1223,7 @@ int register_savevm_live(DeviceState *dev, const char *idstr, int instance_id, int version_id, - SaveSetParamsHandler *set_params, - SaveLiveStateHandler *save_live_state, - SaveStateHandler *save_state, - LoadStateHandler *load_state, + SaveVMHandlers *ops, void *opaque) { SaveStateEntry *se; @@ -1237,15 +1231,12 @@ int register_savevm_live(DeviceState *dev, se = g_malloc0(sizeof(SaveStateEntry)); se->version_id = version_id; se->section_id = global_section_id++; - se->set_params = set_params; - se->save_live_state = save_live_state; - se->save_state = save_state; - se->load_state = load_state; + se->ops = ops; se->opaque = opaque; se->vmsd = NULL; se->no_migrate = 0; /* if this is a live_savem then set is_ram */ - if (save_live_state != NULL) { + if (ops->save_live_setup != NULL) { se->is_ram = 1; } @@ -1284,8 +1275,11 @@ int register_savevm(DeviceState *dev, LoadStateHandler *load_state, void *opaque) { + SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers)); + ops->save_state = save_state; + ops->load_state = load_state; return register_savevm_live(dev, idstr, instance_id, version_id, - NULL, NULL, save_state, load_state, opaque); + ops, opaque); } void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque) @@ -1309,6 +1303,7 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque) if (se->compat) { g_free(se->compat); } + g_free(se->ops); g_free(se); } } @@ -1327,9 +1322,6 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, se = g_malloc0(sizeof(SaveStateEntry)); se->version_id = vmsd->version_id; se->section_id = global_section_id++; - se->save_live_state = NULL; - se->save_state = NULL; - se->load_state = NULL; se->opaque = opaque; se->vmsd = vmsd; se->alias_id = alias_id; @@ -1524,7 +1516,7 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id) { if (!se->vmsd) { /* Old style */ - return se->load_state(f, se->opaque, version_id); + return se->ops->load_state(f, se->opaque, version_id); } return vmstate_load_state(f, se->vmsd, se->opaque, version_id); } @@ -1532,7 +1524,7 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id) static void vmstate_save(QEMUFile *f, SaveStateEntry *se) { if (!se->vmsd) { /* Old style */ - se->save_state(f, se->opaque); + se->ops->save_state(f, se->opaque); return; } vmstate_save_state(f,se->vmsd, se->opaque); @@ -1569,10 +1561,10 @@ int qemu_savevm_state_begin(QEMUFile *f, int ret; QTAILQ_FOREACH(se, &savevm_handlers, entry) { - if(se->set_params == NULL) { + if (!se->ops || !se->ops->set_params) { continue; } - se->set_params(params, se->opaque); + se->ops->set_params(params, se->opaque); } qemu_put_be32(f, QEMU_VM_FILE_MAGIC); @@ -1581,9 +1573,14 @@ int qemu_savevm_state_begin(QEMUFile *f, QTAILQ_FOREACH(se, &savevm_handlers, entry) { int len; - if (se->save_live_state == NULL) + if (!se->ops || !se->ops->save_live_setup) { continue; - + } + if (se->ops && se->ops->is_active) { + if (!se->ops->is_active(se->opaque)) { + continue; + } + } /* Section type */ qemu_put_byte(f, QEMU_VM_SECTION_START); qemu_put_be32(f, se->section_id); @@ -1596,7 +1593,7 @@ int qemu_savevm_state_begin(QEMUFile *f, qemu_put_be32(f, se->instance_id); qemu_put_be32(f, se->version_id); - ret = se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); + ret = se->ops->save_live_setup(f, se->opaque); if (ret < 0) { qemu_savevm_state_cancel(f); return ret; @@ -1623,9 +1620,14 @@ int qemu_savevm_state_iterate(QEMUFile *f) int ret = 1; QTAILQ_FOREACH(se, &savevm_handlers, entry) { - if (se->save_live_state == NULL) + if (!se->ops || !se->ops->save_live_iterate) { continue; - + } + if (se->ops && se->ops->is_active) { + if (!se->ops->is_active(se->opaque)) { + continue; + } + } if (qemu_file_rate_limit(f)) { return 0; } @@ -1634,7 +1636,7 @@ int qemu_savevm_state_iterate(QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_PART); qemu_put_be32(f, se->section_id); - ret = se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); + ret = se->ops->save_live_iterate(f, se->opaque); trace_savevm_section_end(se->section_id); if (ret <= 0) { @@ -1663,15 +1665,20 @@ int qemu_savevm_state_complete(QEMUFile *f) cpu_synchronize_all_states(); QTAILQ_FOREACH(se, &savevm_handlers, entry) { - if (se->save_live_state == NULL) + if (!se->ops || !se->ops->save_live_complete) { continue; - + } + if (se->ops && se->ops->is_active) { + if (!se->ops->is_active(se->opaque)) { + continue; + } + } trace_savevm_section_start(); /* Section type */ qemu_put_byte(f, QEMU_VM_SECTION_END); qemu_put_be32(f, se->section_id); - ret = se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); + ret = se->ops->save_live_complete(f, se->opaque); trace_savevm_section_end(se->section_id); if (ret < 0) { return ret; @@ -1681,9 +1688,9 @@ int qemu_savevm_state_complete(QEMUFile *f) QTAILQ_FOREACH(se, &savevm_handlers, entry) { int len; - if (se->save_state == NULL && se->vmsd == NULL) + if ((!se->ops || !se->ops->save_state) && !se->vmsd) { continue; - + } trace_savevm_section_start(); /* Section type */ qemu_put_byte(f, QEMU_VM_SECTION_FULL); @@ -1711,8 +1718,8 @@ void qemu_savevm_state_cancel(QEMUFile *f) SaveStateEntry *se; QTAILQ_FOREACH(se, &savevm_handlers, entry) { - if (se->save_live_state) { - se->save_live_state(f, -1, se->opaque); + if (se->ops && se->ops->cancel) { + se->ops->cancel(se->opaque); } } } @@ -1765,7 +1772,7 @@ static int qemu_save_device_state(QEMUFile *f) if (se->is_ram) { continue; } - if (se->save_state == NULL && se->vmsd == NULL) { + if ((!se->ops || !se->ops->save_state) && !se->vmsd) { continue; } 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/trace-events b/trace-events index 2a5f074137..6b12f83de0 100644 --- a/trace-events +++ b/trace-events @@ -403,6 +403,7 @@ usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s" # hw/scsi-bus.c scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d" +scsi_req_cancel(int target, int lun, int tag) "target %d lun %d tag %d" scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d" scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d" scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d" @@ -411,6 +412,7 @@ scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "targ scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64 scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x" +scsi_device_set_ua(int target, int lun, int key, int asc, int ascq) "target %d lun %d key %#02x asc %#02x ascq %#02x" scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d" scsi_inquiry(int target, int lun, int tag, int cdb1, int cdb2) "target %d lun %d tag %d page %#02x/%#02x" scsi_test_unit_ready(int target, int lun, int tag) "target %d lun %d tag %d" @@ -595,7 +597,7 @@ megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list: megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d" megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d" megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x" -megasas_dcmd_dump_frame(int offset, char f0, char f1, char f2, char f3, char f4, char f5, char f6, char f7) "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x" +megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld" megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x" megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 "" megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x" diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index 674ba97dc7..c59b188602 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -47,7 +47,8 @@ static void start_auth_vencrypt_subauth(VncState *vs) case VNC_AUTH_VENCRYPT_TLSSASL: case VNC_AUTH_VENCRYPT_X509SASL: VNC_DEBUG("Start TLS auth SASL\n"); - return start_auth_sasl(vs); + start_auth_sasl(vs); + break; #endif /* CONFIG_VNC_SASL */ default: /* Should not be possible, but just in case */ @@ -3089,5 +3089,5 @@ void vnc_display_add_client(DisplayState *ds, int csock, int skipauth) { VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; - return vnc_connect(vs, csock, skipauth); + vnc_connect(vs, csock, skipauth); } @@ -1984,8 +1984,8 @@ static int serial_parse(const char *devname) snprintf(label, sizeof(label), "serial%d", index); serial_hds[index] = qemu_chr_new(label, devname, NULL); if (!serial_hds[index]) { - fprintf(stderr, "qemu: could not open serial device '%s': %s\n", - devname, strerror(errno)); + fprintf(stderr, "qemu: could not connect serial device" + " to character backend '%s'\n", devname); return -1; } index++; @@ -2006,8 +2006,8 @@ static int parallel_parse(const char *devname) snprintf(label, sizeof(label), "parallel%d", index); parallel_hds[index] = qemu_chr_new(label, devname, NULL); if (!parallel_hds[index]) { - fprintf(stderr, "qemu: could not open parallel device '%s': %s\n", - devname, strerror(errno)); + fprintf(stderr, "qemu: could not connect parallel device" + " to character backend '%s'\n", devname); return -1; } index++; @@ -2041,8 +2041,8 @@ static int virtcon_parse(const char *devname) snprintf(label, sizeof(label), "virtcon%d", index); virtcon_hds[index] = qemu_chr_new(label, devname, NULL); if (!virtcon_hds[index]) { - fprintf(stderr, "qemu: could not open virtio console '%s': %s\n", - devname, strerror(errno)); + fprintf(stderr, "qemu: could not connect virtio console" + " to character backend '%s'\n", devname); return -1; } qemu_opt_set(dev_opts, "chardev", label); @@ -3437,8 +3437,7 @@ int main(int argc, char **argv, char **envp) default_drive(default_sdcard, snapshot, machine->use_scsi, IF_SD, 0, SD_OPTS); - register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL, - ram_load, NULL); + register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL); if (nb_numa_nodes > 0) { int i; @@ -26,11 +26,20 @@ #ifndef QEMU_VMSTATE_H #define QEMU_VMSTATE_H 1 -typedef void SaveSetParamsHandler(const MigrationParams *params, void * opaque); typedef void SaveStateHandler(QEMUFile *f, void *opaque); -typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); +typedef struct SaveVMHandlers { + void (*set_params)(const MigrationParams *params, void * opaque); + SaveStateHandler *save_state; + int (*save_live_setup)(QEMUFile *f, void *opaque); + int (*save_live_iterate)(QEMUFile *f, void *opaque); + int (*save_live_complete)(QEMUFile *f, void *opaque); + void (*cancel)(void *opaque); + LoadStateHandler *load_state; + bool (*is_active)(void *opaque); +} SaveVMHandlers; + int register_savevm(DeviceState *dev, const char *idstr, int instance_id, @@ -43,10 +52,7 @@ int register_savevm_live(DeviceState *dev, const char *idstr, int instance_id, int version_id, - SaveSetParamsHandler *set_params, - SaveLiveStateHandler *save_live_state, - SaveStateHandler *save_state, - LoadStateHandler *load_state, + SaveVMHandlers *ops, void *opaque); void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque); |