===================================================================
@@ -1092,6 +1092,36 @@ static int gdb_handle_packet(GDBState *s
put_packet(s, buf);
}
break;
+ } else if (strncmp(p, "Symbol:", 7) == 0) {
+#if defined(TARGET_MIPS) && !defined(CONFIG_USER_ONLY)
+#define MDI_SYSCALL_SYMBOL "_mdi_syscall"
+ if (strcmp(p+7, ":") == 0) {
+ /* GDB is telling us we can ask for symbols. Look for
+ _mdi_syscall. */
+ memtohex((char *)mem_buf, (const uint8_t *)MDI_SYSCALL_SYMBOL,
+ strlen(MDI_SYSCALL_SYMBOL));
+ mem_buf[strlen(MDI_SYSCALL_SYMBOL)*2] = 0;
+ snprintf(buf, sizeof(buf), "qSymbol:%s", mem_buf);
+ put_packet(s, buf);
+ break;
+ } else {
+ /* A response from a previous query. We only send one
+ query so it must be _mdi_syscall. */
+ if (*(p+7) != ':') {
+ addr = strtoull(p+7, (char **)&p, 16);
+ hextomem(mem_buf, p+1, strlen(MDI_SYSCALL_SYMBOL)*2);
+
+ if (memcmp(mem_buf, MDI_SYSCALL_SYMBOL,
+ strlen(MDI_SYSCALL_SYMBOL)) == 0) {
+ install_semihosting_breakpoint(s->c_cpu, addr);
+ }
+ }
+ }
+ /* All done, regardless of whether we got the right symbol. */
+ put_packet(s, "OK");
+ break;
+#undef MDI_SYSCALL_SYMBOL
+#endif
}
#ifdef CONFIG_USER_ONLY
else if (strncmp(p, "Offsets", 7) == 0) {
===================================================================
@@ -325,9 +325,12 @@ const char *load_elf_strerror(int error)
}
/* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
- void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
- uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
+int load_elf_introspect(const char *filename,
+ uint64_t (*translate_fn)(void *, uint64_t),
+ void *translate_opaque,
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+ int big_endian, int elf_machine, int clear_lsb,
+ section_callback_t section_callback)
{
int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
uint8_t e_ident[EI_NIDENT];
@@ -366,10 +369,12 @@ int load_elf(const char *filename, uint6
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab,
- pentry, lowaddr, highaddr, elf_machine, clear_lsb);
+ pentry, lowaddr, highaddr, elf_machine, clear_lsb,
+ section_callback);
} else {
ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
- pentry, lowaddr, highaddr, elf_machine, clear_lsb);
+ pentry, lowaddr, highaddr, elf_machine, clear_lsb,
+ section_callback);
}
fail:
@@ -377,6 +382,17 @@ int load_elf(const char *filename, uint6
return ret;
}
+/* return < 0 if error, otherwise the number of bytes loaded in memory */
+int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
+ void *translate_opaque,
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+ int big_endian, int elf_machine, int clear_lsb)
+{
+ return load_elf_introspect(filename, translate_fn, translate_opaque,
+ pentry, lowaddr, highaddr,
+ big_endian, elf_machine, clear_lsb, NULL);
+}
+
static void bswap_uboot_header(uboot_image_header_t *hdr)
{
#ifndef HOST_WORDS_BIGENDIAN
===================================================================
@@ -56,6 +56,8 @@
//#define DEBUG_BOARD_INIT
+#define KERNEL_LOAD_ADDR 0x00100000
+
#define ENVP_ADDR 0x80002000l
#define ENVP_NB_ENTRIES 16
#define ENVP_ENTRY_SIZE 256
@@ -772,6 +774,7 @@ static void GCC_FMT_ATTR(3, 4) prom_set(
static int64_t load_kernel (void)
{
int64_t kernel_entry, kernel_high;
+ int kernel_size;
long initrd_size;
ram_addr_t initrd_offset;
int big_endian;
@@ -786,9 +789,19 @@ static int64_t load_kernel (void)
big_endian = 0;
#endif
- if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
- (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
- big_endian, ELF_MACHINE, 1) < 0) {
+ kernel_size = load_elf(loaderparams.kernel_filename,
+ cpu_mips_kseg0_to_phys, NULL,
+ (uint64_t *)&kernel_entry, NULL,
+ (uint64_t *)&kernel_high,
+ big_endian, ELF_MACHINE, 1);
+ if (kernel_size < 0) {
+ kernel_size = load_image_targphys(loaderparams.kernel_filename,
+ KERNEL_LOAD_ADDR,
+ ram_size - KERNEL_LOAD_ADDR);
+ kernel_high = KERNEL_LOAD_ADDR + kernel_size;
+ kernel_entry = KERNEL_LOAD_ADDR;
+ }
+ if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loaderparams.kernel_filename);
exit(1);
===================================================================
@@ -40,6 +40,8 @@
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
+#define KERNEL_LOAD_ADDR 0x00100000
+
static struct _loaderparams {
int ram_size;
const char *kernel_filename;
@@ -47,12 +49,75 @@ static struct _loaderparams {
const char *initrd_filename;
} loaderparams;
+static target_ulong mdi_semihost_bkpt;
+
+#define ENTWORDS 2
+
+static void find_sdeosabi_section(int fd, int elf_class, int must_swab,
+ uint64_t size, uint64_t offset,
+ char *name)
+{
+ const int entsize = ENTWORDS * (elf_class / 8);
+
+ if (semihosting_enabled &&
+ size >= entsize &&
+ strcmp(name, ".sdeosabi") == 0) {
+ uint64_t section_offset = 0;
+
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ return;
+ }
+
+ while (section_offset < size) {
+ /* .sdeosabi is organized into pairs of pointer-size words. The
+ first word in each pair is a numeric tag; the second word
+ is interpreted according to the tag. For our purposes,
+ we're looking for tag 2. The second word will be the
+ address of the _mdi_syscall function. */
+ union {
+ uint64_t u64[ENTWORDS];
+ int64_t i64[ENTWORDS];
+ uint32_t u32[ENTWORDS];
+ int32_t i32[ENTWORDS];
+ } bkpt_info;
+
+ if (read(fd, &bkpt_info, entsize) == entsize) {
+ if (elf_class == 32) {
+ if (must_swab) {
+ bswap32s(&bkpt_info.u32[0]);
+ bswap32s(&bkpt_info.u32[1]);
+ }
+
+ if (bkpt_info.i32[0] == 2 && bkpt_info.i32[1]) {
+ mdi_semihost_bkpt = bkpt_info.i32[1];
+ break;
+ }
+ } else {
+ if (must_swab) {
+ bswap64s(&bkpt_info.u64[0]);
+ bswap64s(&bkpt_info.u64[1]);
+ }
+
+ if (bkpt_info.i64[0] == 2 && bkpt_info.i64[1]) {
+ mdi_semihost_bkpt = bkpt_info.i64[1];
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+
+ section_offset += entsize;
+ }
+ }
+}
+
typedef struct ResetData {
MIPSCPU *cpu;
uint64_t vector;
} ResetData;
-static int64_t load_kernel(void)
+static int64_t load_kernel(CPUMIPSState *env)
{
int64_t entry, kernel_high;
long kernel_size;
@@ -66,10 +131,20 @@ static int64_t load_kernel(void)
big_endian = 0;
#endif
- kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
- NULL, (uint64_t *)&entry, NULL,
- (uint64_t *)&kernel_high, big_endian,
- ELF_MACHINE, 1);
+ kernel_size = load_elf_introspect(loaderparams.kernel_filename,
+ cpu_mips_kseg0_to_phys, NULL,
+ (uint64_t *)&entry,
+ NULL,
+ (uint64_t *)&kernel_high,
+ big_endian, ELF_MACHINE, 1,
+ find_sdeosabi_section);
+ if (kernel_size < 0) {
+ kernel_size = load_image_targphys(loaderparams.kernel_filename,
+ KERNEL_LOAD_ADDR,
+ ram_size - KERNEL_LOAD_ADDR);
+ kernel_high = KERNEL_LOAD_ADDR + kernel_size;
+ entry = KERNEL_LOAD_ADDR;
+ }
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
@@ -79,6 +154,11 @@ static int64_t load_kernel(void)
exit(1);
}
+ /* set up semihosting */
+ if (semihosting_enabled && mdi_semihost_bkpt) {
+ install_semihosting_breakpoint(ENV_GET_CPU(env), mdi_semihost_bkpt);
+ }
+
/* load initrd */
initrd_size = 0;
initrd_offset = 0;
@@ -209,7 +289,7 @@ mips_mipssim_init(MachineState *machine)
loaderparams.kernel_filename = kernel_filename;
loaderparams.kernel_cmdline = kernel_cmdline;
loaderparams.initrd_filename = initrd_filename;
- reset_info->vector = load_kernel();
+ reset_info->vector = load_kernel(env);
}
/* Init CPU internal devices. */
===================================================================
@@ -9,6 +9,12 @@
#ifndef SOFTMMU_SEMI_H
#define SOFTMMU_SEMI_H 1
+#ifdef __GNUC__
+#define SOFTMMU_UNUSED __attribute__ ((unused))
+#else
+#define SOFTMMU_UNUSED
+#endif
+
static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr)
{
uint32_t val;
@@ -67,6 +73,21 @@ static char *softmmu_lock_user_string(CP
return s;
}
#define lock_user_string(p) softmmu_lock_user_string(env, p)
+SOFTMMU_UNUSED
+static int softmmu_target_strlen(CPUArchState *env, target_ulong addr)
+{
+ uint8_t c;
+ int len;
+
+ len = 0;
+ do {
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr + len, &c, 1, 0);
+ len++;
+ } while (c);
+
+ return len - 1;
+}
+#define target_strlen(p) softmmu_target_strlen(env, p)
static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
target_ulong len)
{
@@ -77,4 +98,6 @@ static void softmmu_unlock_user(CPUArchS
}
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
+#undef SOFTMMU_UNUSED
+
#endif
===================================================================
@@ -97,8 +97,14 @@ static int glue(symcmp, SZ)(const void *
: ((sym0->st_value > sym1->st_value) ? 1 : 0);
}
+/* Load function symbols for later groveling. If SECTION_CALLBACK is
+ non-NULL, it will be called with information about each section in
+ the binary. This interface enables to the caller to mine the binary
+ for useful information about the ABI, such as whether the CPU chosen is
+ compatible with the binary. */
static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
- int clear_lsb)
+ int clear_lsb,
+ section_callback_t section_callback)
{
struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
struct elf_sym *syms = NULL;
@@ -117,6 +123,28 @@ static int glue(load_symbols, SZ)(struct
}
}
+ /* Permit machines to grovel through the ELF file looking for
+ interesting bits of information. */
+ if (section_callback && ehdr->e_shstrndx != SHN_UNDEF) {
+ char *shstr = NULL;
+ struct elf_shdr *shstrtab = &shdr_table[ehdr->e_shstrndx];
+
+ shstr = load_at(fd, shstrtab->sh_offset, shstrtab->sh_size);
+ if (!shstr) {
+ goto fail_callback;
+ }
+
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ struct elf_shdr *sh = shdr_table + i;
+
+ section_callback(fd, SZ, must_swab, sh->sh_size, sh->sh_offset,
+ &shstr[sh->sh_name]);
+ }
+
+ fail_callback:
+ free(shstr);
+ }
+
symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
if (!symtab)
goto fail;
@@ -187,7 +215,8 @@ static int glue(load_elf, SZ)(const char
void *translate_opaque,
int must_swab, uint64_t *pentry,
uint64_t *lowaddr, uint64_t *highaddr,
- int elf_machine, int clear_lsb)
+ int elf_machine, int clear_lsb,
+ section_callback_t section_callback)
{
struct elfhdr ehdr;
struct elf_phdr *phdr = NULL, *ph;
@@ -236,7 +265,7 @@ static int glue(load_elf, SZ)(const char
if (pentry)
*pentry = (uint64_t)(elf_sword)ehdr.e_entry;
- glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
+ glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, section_callback);
size = ehdr.e_phnum * sizeof(phdr[0]);
lseek(fd, ehdr.e_phoff, SEEK_SET);
===================================================================
@@ -27,6 +27,14 @@ int load_elf(const char *filename, uint6
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
uint64_t *highaddr, int big_endian, int elf_machine,
int clear_lsb);
+typedef void (*section_callback_t)(int fd, int elf_class, int must_swab,
+ uint64_t size, uint64_t offset, char *name);
+int load_elf_introspect(const char *filename,
+ uint64_t (*translate_fn)(void *, uint64_t),
+ void *translate_opaque,
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+ int big_endian, int elf_machine, int clear_lsb,
+ section_callback_t callback);
int load_aout(const char *filename, hwaddr addr, int max_sz,
int bswap_needed, hwaddr target_page_size);
int load_uimage(const char *filename, hwaddr *ep,
===================================================================
@@ -3212,11 +3212,11 @@ Set OpenBIOS nvram @var{variable} to giv
ETEXI
DEF("semihosting", 0, QEMU_OPTION_semihosting,
"-semihosting semihosting mode\n",
- QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
+ QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_MIPS | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
STEXI
@item -semihosting
@findex -semihosting
-Semihosting mode (ARM, M68K, Xtensa only).
+Semihosting mode (ARM, M68K, MIPS, Xtensa only).
ETEXI
DEF("old-param", 0, QEMU_OPTION_old_param,
"-old-param old param mode\n", QEMU_ARCH_ARM)
===================================================================
@@ -1,5 +1,5 @@
obj-y += translate.o dsp_helper.o lmi_helper.o msa_helper.o op_helper.o
obj-y += helper.o cpu.o
-obj-y += gdbstub.o
+obj-y += gdbstub.o mips-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o
===================================================================
@@ -789,6 +789,10 @@ static inline void restore_flush_mode(CP
&env->active_fpu.fp_status);
}
+extern target_ulong mdi_semihost_breakpoint;
+void do_mips_semihosting(CPUMIPSState *env);
+void install_semihosting_breakpoint(CPUState *cs, target_ulong bkpt_address);
+
static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
===================================================================
@@ -18,14 +18,13 @@
*/
#include <stdarg.h>
#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
-#include <inttypes.h>
#include <signal.h>
#include "cpu.h"
-#include "sysemu/kvm.h"
#include "exec/cpu_ldst.h"
+#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
enum {
TLBRET_XI = -6,
@@ -390,6 +389,17 @@ hwaddr cpu_mips_translate_address(CPUMIP
}
#endif
+#if !defined(CONFIG_USER_ONLY)
+target_ulong mdi_semihost_breakpoint;
+
+void install_semihosting_breakpoint(CPUState *cs, target_ulong bkpt_address)
+{
+ if (semihosting_enabled) {
+ mdi_semihost_breakpoint = bkpt_address & ~(target_ulong)1;
+ }
+}
+#endif
+
static const char * const excp_names[EXCP_LAST + 1] = {
[EXCP_RESET] = "reset",
[EXCP_SRESET] = "soft reset",
===================================================================
@@ -173,6 +173,7 @@ DEF_HELPER_0(dmt, tl)
DEF_HELPER_0(emt, tl)
DEF_HELPER_1(dvpe, tl, env)
DEF_HELPER_1(evpe, tl, env)
+DEF_HELPER_1(semihosting_call, void, env)
#endif /* !CONFIG_USER_ONLY */
/* microMIPS functions */
===================================================================
@@ -0,0 +1,242 @@
+/*
+ * MIPS MDI semihosting syscalls
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Nathan Froyd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "cpu.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "exec/gdbstub.h"
+#include "exec/softmmu-semi.h"
+
+#define HOSTED_OPEN 0
+#define HOSTED_CLOSE 1
+#define HOSTED_READ 2
+#define HOSTED_WRITE 3
+#define HOSTED_GETCHAR 4
+#define HOSTED_PUTCHAR 5
+#define HOSTED_LSEEK32 6
+#define HOSTED_GETTIME 7
+#define HOSTED_EXIT 8
+#define HOSTED_MOVED 9
+#define HOSTED_GETARGS 10
+#define HOSTED_ISATTY 11
+#define HOSTED_PROFIL 12
+#define HOSTED_SIGHOOK 13
+
+#define ARG(n) (env->active_tc.gpr[4 + (n)])
+
+static void mips_store_result(CPUMIPSState *env,
+ target_ulong ret, target_ulong err)
+{
+ env->active_tc.PC = env->active_tc.gpr[31] & ~(target_ulong)1;
+ if (env->active_tc.gpr[31] & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ } else {
+ env->hflags &= ~MIPS_HFLAG_M16;
+ }
+ env->active_tc.gpr[2] = ret;
+ env->active_tc.gpr[3] = err;
+}
+
+static void mips_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ mips_store_result(env, ret, err);
+}
+
+#define GDB_O_RDONLY 0x0
+#define GDB_O_WRONLY 0x1
+#define GDB_O_RDWR 0x2
+#define GDB_O_APPEND 0x8
+#define GDB_O_CREAT 0x200
+#define GDB_O_TRUNC 0x400
+#define GDB_O_EXCL 0x800
+
+static int translate_openflags(int flags)
+{
+ int hf;
+
+ if (flags & GDB_O_WRONLY) {
+ hf = O_WRONLY;
+ } else if (flags & GDB_O_RDWR) {
+ hf = O_RDWR;
+ } else {
+ hf = O_RDONLY;
+ }
+
+ if (flags & GDB_O_APPEND) {
+ hf |= O_APPEND;
+ }
+ if (flags & GDB_O_CREAT) {
+ hf |= O_CREAT;
+ }
+ if (flags & GDB_O_TRUNC) {
+ hf |= O_TRUNC;
+ }
+ if (flags & GDB_O_EXCL) {
+ hf |= O_EXCL;
+ }
+
+ return hf;
+}
+
+void do_mips_semihosting(CPUMIPSState *env)
+{
+ target_ulong result;
+ void *p;
+ uint32_t len;
+ target_ulong err = 0;
+ char *s;
+
+ switch (env->active_tc.gpr[2]) {
+ case HOSTED_OPEN:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(mips_semi_cb, "open,%s,%x,%x", ARG(0),
+ target_strlen(ARG(0))+1, ARG(1), ARG(2));
+ return;
+ } else {
+ s = lock_user_string(ARG(0));
+ if (s) {
+ result = open(s, translate_openflags(ARG(1)), ARG(2));
+ unlock_user(s, ARG(0), 0);
+ } else {
+ result = -1;
+ }
+ }
+ break;
+ case HOSTED_CLOSE:
+ /* Ignore attempts to close stdin/out/err */
+ if (ARG(0) > 2) {
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(mips_semi_cb, "close,%x", ARG(0));
+ return;
+ } else {
+ result = close(ARG(0));
+ }
+ } else {
+ result = 0;
+ }
+ break;
+ case HOSTED_READ:
+ len = ARG(2);
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(mips_semi_cb, "read,%x,%x,%x",
+ ARG(0), ARG(1), len);
+ return;
+ } else {
+ p = lock_user(VERIFY_WRITE, ARG(1), len, 0);
+ if (p) {
+ result = read(ARG(0), p, len);
+ unlock_user(p, ARG(1), len);
+ } else {
+ result = -1;
+ }
+ }
+ break;
+ case HOSTED_WRITE:
+ len = ARG(2);
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(mips_semi_cb, "write,%x,%x,%x",
+ ARG(0), ARG(1), len);
+ return;
+ } else {
+ p = lock_user(VERIFY_READ, ARG(1), len, 1);
+ if (p) {
+ result = write(ARG(0), p, len);
+ unlock_user(p, ARG(1), len);
+ } else {
+ result = -1;
+ }
+ }
+ break;
+ case HOSTED_LSEEK32:
+ {
+ off_t off = (target_long)ARG(1);
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(mips_semi_cb, "lseek,%x,%lx,%x",
+ ARG(0), off, ARG(2));
+ return;
+ } else {
+ off = lseek(ARG(0), off, ARG(2));
+ result = (uint32_t)off;
+ }
+ }
+ break;
+ case HOSTED_GETTIME:
+ {
+ qemu_timeval tv;
+ result = qemu_gettimeofday(&tv);
+ if (!result) {
+ result = tv.tv_sec;
+ err = tv.tv_usec;
+ } else {
+ result = -1;
+ err = errno;
+ }
+ }
+ break;
+ case HOSTED_EXIT:
+ /* FIXME: ideally we want to inform gdb about program
+ exit whenever gdb is connected, even if syscalls
+ are not handled by gdb. */
+ if (use_gdb_syscalls()) {
+ gdb_exit(env, ARG(0));
+ }
+ exit(ARG(0));
+ break;
+ case HOSTED_ISATTY:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(mips_semi_cb, "isatty,%x", ARG(0));
+ return;
+ } else {
+ result = isatty(ARG(0));
+ }
+ break;
+ case HOSTED_GETARGS:
+ /* argc gets placed in A0, argv gets copied onto the stack and
+ the address of the copy placed in A1. We have nothing to
+ provide in terms of argc/argv, so just stuff NULL in
+ each. */
+ ARG(1) = ARG(0) = 0;
+ result = 0;
+ break;
+ case HOSTED_GETCHAR:
+ case HOSTED_PUTCHAR:
+ case HOSTED_MOVED:
+ case HOSTED_PROFIL:
+ case HOSTED_SIGHOOK:
+ default:
+ result = -1;
+ err = 88; /* ENOSYS */
+ break;
+ }
+
+ mips_store_result(env, result, err);
+}
===================================================================
@@ -1764,6 +1764,11 @@ target_ulong helper_evpe(CPUMIPSState *e
}
return prev;
}
+
+void helper_semihosting_call(CPUMIPSState *env)
+{
+ do_mips_semihosting(env);
+}
#endif /* !CONFIG_USER_ONLY */
void helper_fork(target_ulong arg1, target_ulong arg2)
===================================================================
@@ -29,6 +29,7 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
#include "trace-tcg.h"
@@ -19142,6 +19143,17 @@ gen_intermediate_code_internal(MIPSCPU *
}
}
}
+#ifndef CONFIG_USER_ONLY
+ if (unlikely(semihosting_enabled) &&
+ mdi_semihost_breakpoint &&
+ ctx.pc == mdi_semihost_breakpoint) {
+ ctx.bstate = BS_EXCP;
+ gen_helper_semihosting_call(cpu_env);
+ tcg_gen_exit_tb(0);
+ ctx.pc += 4;
+ goto done_generating;
+ }
+#endif
if (search_pc) {
j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;