diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-09-05 20:35:53 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-09-05 20:35:53 +0900 |
commit | 16b1353a36171ae06d63fd309f4772dbfb1da113 (patch) | |
tree | cf6c297ee81aba0d9b47f23d78a889667e7bce48 /target-lm32 | |
parent | a15119db2ff5c2fdfdeb913b297bf8aa3399132e (diff) | |
download | qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.gz qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.bz2 qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.zip |
Imported Upstream version 2.1.0upstream/2.1.0
Diffstat (limited to 'target-lm32')
-rw-r--r-- | target-lm32/Makefile.objs | 1 | ||||
-rw-r--r-- | target-lm32/README | 15 | ||||
-rw-r--r-- | target-lm32/cpu.h | 1 | ||||
-rw-r--r-- | target-lm32/helper.c | 14 | ||||
-rw-r--r-- | target-lm32/helper.h | 4 | ||||
-rw-r--r-- | target-lm32/lm32-semi.c | 215 | ||||
-rw-r--r-- | target-lm32/machine.c | 6 | ||||
-rw-r--r-- | target-lm32/op_helper.c | 16 | ||||
-rw-r--r-- | target-lm32/translate.c | 6 |
9 files changed, 244 insertions, 34 deletions
diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs index 40236876c..c3e1bd6bd 100644 --- a/target-lm32/Makefile.objs +++ b/target-lm32/Makefile.objs @@ -1,3 +1,4 @@ obj-y += translate.o op_helper.o helper.o cpu.o obj-y += gdbstub.o +obj-y += lm32-semi.o obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-lm32/README b/target-lm32/README index a1c2c7eb1..ba3508a71 100644 --- a/target-lm32/README +++ b/target-lm32/README @@ -16,14 +16,13 @@ This will make serial0 (the lm32_uart) and serial1 (the JTAG UART) available as virtual consoles. -Programmatically terminate the emulator ----------------------------------------- -Originally neither the LatticeMico32 nor its peripherals support a -mechanism to shut down the machine. Emulation aware programs can write to a -to a special register within the system control block to shut down the -virtual machine. For more details see hw/lm32_sys.c. The lm32-evr is the -first BSP which instantiate this model. A (32 bit) write to 0xfff0000 -causes a vm shutdown. +Semihosting +----------- +Semihosting on this target is supported. Some system calls like read, write +and exit are executed on the host if semihosting is enabled. See +target/lm32-semi.c for all supported system calls. Emulation aware programs +can use this mechanism to shut down the virtual machine and print to the +host console. See the tcg tests for an example. Special instructions diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 24bde7850..70600aa47 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -217,6 +217,7 @@ void lm32_breakpoint_remove(CPULM32State *env, int index); void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address, lm32_wp_t wp_type); void lm32_watchpoint_remove(CPULM32State *env, int index); +bool lm32_cpu_do_semihosting(CPUState *cs); static inline CPULM32State *cpu_init(const char *cpu_model) { diff --git a/target-lm32/helper.c b/target-lm32/helper.c index 783aa16a4..1bca1961a 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -1,7 +1,7 @@ /* * LatticeMico32 helper routines. * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * Copyright (c) 2010-2014 Michael Walle <michael@walle.cc> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,7 @@ #include "cpu.h" #include "qemu/host-utils.h" +#include "sysemu/sysemu.h" int lm32_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx) @@ -159,11 +160,20 @@ void lm32_cpu_do_interrupt(CPUState *cs) "exception at pc=%x type=%x\n", env->pc, cs->exception_index); switch (cs->exception_index) { + case EXCP_SYSTEMCALL: + if (unlikely(semihosting_enabled)) { + /* do_semicall() returns true if call was handled. Otherwise + * do the normal exception handling. */ + if (lm32_cpu_do_semihosting(cs)) { + env->pc += 4; + break; + } + } + /* fall through */ case EXCP_INSN_BUS_ERROR: case EXCP_DATA_BUS_ERROR: case EXCP_DIVIDE_BY_ZERO: case EXCP_IRQ: - case EXCP_SYSTEMCALL: /* non-debug exceptions */ env->regs[R_EA] = env->pc; env->ie |= (env->ie & IE_IE) ? IE_EIE : 0; diff --git a/target-lm32/helper.h b/target-lm32/helper.h index f4442e0a9..445578c43 100644 --- a/target-lm32/helper.h +++ b/target-lm32/helper.h @@ -1,5 +1,3 @@ -#include "exec/def-helper.h" - DEF_HELPER_2(raise_exception, void, env, i32) DEF_HELPER_1(hlt, void, env) DEF_HELPER_3(wcsr_bp, void, env, i32, i32) @@ -14,5 +12,3 @@ DEF_HELPER_1(rcsr_ip, i32, env) DEF_HELPER_1(rcsr_jtx, i32, env) DEF_HELPER_1(rcsr_jrx, i32, env) DEF_HELPER_1(ill, void, env) - -#include "exec/def-helper.h" diff --git a/target-lm32/lm32-semi.c b/target-lm32/lm32-semi.c new file mode 100644 index 000000000..ec6524f37 --- /dev/null +++ b/target-lm32/lm32-semi.c @@ -0,0 +1,215 @@ +/* + * Lattice Mico32 semihosting syscall interface + * + * Copyright (c) 2014 Michael Walle <michael@walle.cc> + * + * Based on target-m68k/m68k-semi.c, which is + * Copyright (c) 2005-2007 CodeSourcery. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stddef.h> +#include "cpu.h" +#include "exec/helper-proto.h" +#include "qemu/log.h" +#include "exec/softmmu-semi.h" + +enum { + TARGET_SYS_exit = 1, + TARGET_SYS_open = 2, + TARGET_SYS_close = 3, + TARGET_SYS_read = 4, + TARGET_SYS_write = 5, + TARGET_SYS_lseek = 6, + TARGET_SYS_fstat = 10, + TARGET_SYS_stat = 15, +}; + +enum { + NEWLIB_O_RDONLY = 0x0, + NEWLIB_O_WRONLY = 0x1, + NEWLIB_O_RDWR = 0x2, + NEWLIB_O_APPEND = 0x8, + NEWLIB_O_CREAT = 0x200, + NEWLIB_O_TRUNC = 0x400, + NEWLIB_O_EXCL = 0x800, +}; + +static int translate_openflags(int flags) +{ + int hf; + + if (flags & NEWLIB_O_WRONLY) { + hf = O_WRONLY; + } else if (flags & NEWLIB_O_RDWR) { + hf = O_RDWR; + } else { + hf = O_RDONLY; + } + + if (flags & NEWLIB_O_APPEND) { + hf |= O_APPEND; + } + + if (flags & NEWLIB_O_CREAT) { + hf |= O_CREAT; + } + + if (flags & NEWLIB_O_TRUNC) { + hf |= O_TRUNC; + } + + if (flags & NEWLIB_O_EXCL) { + hf |= O_EXCL; + } + + return hf; +} + +struct newlib_stat { + int16_t newlib_st_dev; /* device */ + uint16_t newlib_st_ino; /* inode */ + uint16_t newlib_st_mode; /* protection */ + uint16_t newlib_st_nlink; /* number of hard links */ + uint16_t newlib_st_uid; /* user ID of owner */ + uint16_t newlib_st_gid; /* group ID of owner */ + int16_t newlib_st_rdev; /* device type (if inode device) */ + int32_t newlib_st_size; /* total size, in bytes */ + int32_t newlib_st_atime; /* time of last access */ + uint32_t newlib_st_spare1; + int32_t newlib_st_mtime; /* time of last modification */ + uint32_t newlib_st_spare2; + int32_t newlib_st_ctime; /* time of last change */ + uint32_t newlib_st_spare3; +} QEMU_PACKED; + +static int translate_stat(CPULM32State *env, target_ulong addr, + struct stat *s) +{ + struct newlib_stat *p; + + p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0); + if (!p) { + return 0; + } + p->newlib_st_dev = cpu_to_be16(s->st_dev); + p->newlib_st_ino = cpu_to_be16(s->st_ino); + p->newlib_st_mode = cpu_to_be16(s->st_mode); + p->newlib_st_nlink = cpu_to_be16(s->st_nlink); + p->newlib_st_uid = cpu_to_be16(s->st_uid); + p->newlib_st_gid = cpu_to_be16(s->st_gid); + p->newlib_st_rdev = cpu_to_be16(s->st_rdev); + p->newlib_st_size = cpu_to_be32(s->st_size); + p->newlib_st_atime = cpu_to_be32(s->st_atime); + p->newlib_st_mtime = cpu_to_be32(s->st_mtime); + p->newlib_st_ctime = cpu_to_be32(s->st_ctime); + unlock_user(p, addr, sizeof(struct newlib_stat)); + + return 1; +} + +bool lm32_cpu_do_semihosting(CPUState *cs) +{ + LM32CPU *cpu = LM32_CPU(cs); + CPULM32State *env = &cpu->env; + + int ret = -1; + target_ulong nr, arg0, arg1, arg2; + void *p; + struct stat s; + + nr = env->regs[R_R8]; + arg0 = env->regs[R_R1]; + arg1 = env->regs[R_R2]; + arg2 = env->regs[R_R3]; + + switch (nr) { + case TARGET_SYS_exit: + /* void _exit(int rc) */ + exit(arg0); + + case TARGET_SYS_open: + /* int open(const char *pathname, int flags) */ + p = lock_user_string(arg0); + if (!p) { + ret = -1; + } else { + ret = open(p, translate_openflags(arg2)); + unlock_user(p, arg0, 0); + } + break; + + case TARGET_SYS_read: + /* ssize_t read(int fd, const void *buf, size_t count) */ + p = lock_user(VERIFY_WRITE, arg1, arg2, 0); + if (!p) { + ret = -1; + } else { + ret = read(arg0, p, arg2); + unlock_user(p, arg1, arg2); + } + break; + + case TARGET_SYS_write: + /* ssize_t write(int fd, const void *buf, size_t count) */ + p = lock_user(VERIFY_READ, arg1, arg2, 1); + if (!p) { + ret = -1; + } else { + ret = write(arg0, p, arg2); + unlock_user(p, arg1, 0); + } + break; + + case TARGET_SYS_close: + /* int close(int fd) */ + /* don't close stdin/stdout/stderr */ + if (arg0 > 2) { + ret = close(arg0); + } else { + ret = 0; + } + break; + + case TARGET_SYS_lseek: + /* off_t lseek(int fd, off_t offset, int whence */ + ret = lseek(arg0, arg1, arg2); + break; + + case TARGET_SYS_stat: + /* int stat(const char *path, struct stat *buf) */ + p = lock_user_string(arg0); + if (!p) { + ret = -1; + } else { + ret = stat(p, &s); + unlock_user(p, arg0, 0); + if (translate_stat(env, arg1, &s) == 0) { + ret = -1; + } + } + break; + + case TARGET_SYS_fstat: + /* int stat(int fd, struct stat *buf) */ + ret = fstat(arg0, &s); + if (ret == 0) { + if (translate_stat(env, arg1, &s) == 0) { + ret = -1; + } + } + break; + + default: + /* unhandled */ + return false; + } + + env->regs[R_R1] = ret; + return true; +} diff --git a/target-lm32/machine.c b/target-lm32/machine.c index 9e0919c25..8327c6d97 100644 --- a/target-lm32/machine.c +++ b/target-lm32/machine.c @@ -5,8 +5,7 @@ static const VMStateDescription vmstate_env = { .name = "env", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, CPULM32State, 32), VMSTATE_UINT32(pc, CPULM32State), VMSTATE_UINT32(ie, CPULM32State), @@ -26,8 +25,7 @@ const VMStateDescription vmstate_lm32_cpu = { .name = "cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State), VMSTATE_END_OF_LIST() } diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index 2f36b7b05..61209c19b 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -1,28 +1,18 @@ #include <assert.h> #include "cpu.h" -#include "helper.h" +#include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "hw/lm32/lm32_pic.h" #include "hw/char/lm32_juart.h" -#include "exec/softmmu_exec.h" +#include "exec/cpu_ldst.h" #ifndef CONFIG_USER_ONLY #include "sysemu/sysemu.h" #endif #if !defined(CONFIG_USER_ONLY) -#define MMUSUFFIX _mmu -#define SHIFT 0 -#include "exec/softmmu_template.h" -#define SHIFT 1 -#include "exec/softmmu_template.h" -#define SHIFT 2 -#include "exec/softmmu_template.h" -#define SHIFT 3 -#include "exec/softmmu_template.h" - void raise_exception(CPULM32State *env, int index) { CPUState *cs = CPU(lm32_env_get_cpu(env)); @@ -52,7 +42,7 @@ void HELPER(ill)(CPULM32State *env) fprintf(stderr, "VM paused due to illegal instruction. " "Connect a debugger or switch to the monitor console " "to find out more.\n"); - qemu_system_vmstop_request(RUN_STATE_PAUSED); + vm_stop(RUN_STATE_PAUSED); cs->halted = 1; raise_exception(env, EXCP_HALTED); #endif diff --git a/target-lm32/translate.c b/target-lm32/translate.c index c8abd1f27..a51ade9a1 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -19,13 +19,13 @@ #include "cpu.h" #include "disas/disas.h" -#include "helper.h" +#include "exec/helper-proto.h" #include "tcg-op.h" +#include "exec/cpu_ldst.h" #include "hw/lm32/lm32_pic.h" -#define GEN_HELPER 1 -#include "helper.h" +#include "exec/helper-gen.h" #define DISAS_LM32 1 #if DISAS_LM32 |