qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting
@ 2009-07-17 20:33 Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader Nathan Froyd
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel

This patch series adds semihosting for bare-metal 32-bit MIPS targets
that follows the MDI semihosting model used in MIPS's development
product.

The semihosting protocol works as follows:

- All semihosted calls go through _mdi_syscall, which in the absence of
  simulator support, returns ENOSYS;

- The address of _mdi_syscall is stored in a special section, .sdeosabi;

- When an MDI semihosting-aware simulator is used, a breakpoint is
  placed at _mdi_syscall;

- When this breakpoint is hit, the simulator performs the requested
  action and returns control to the program.

Discovering the address of _mdi_syscall is straightforward when the
program is passed in via -kernel.  We extended the ELF loader interface
slightly so that the caller could inspect the sections of the binary and
act on the contents of the sections if they so chose.  Things are
slightly trickier when using QEMU as a GDB remote target, as the program
will not be provided via -kernel, but via `load' from within GDB.  This
second method requires that we implement qSymbol support in the GDB
stub so we can directly ask GDB where _mdi_syscall is.

The patches have been built for {mips,mips64}-softmmu targets and tested
with the libstdc++ testsuite (which exercises things like read(),
write(), and lseek()).

-Nathan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader
  2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
@ 2009-07-17 20:33 ` Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 2/6] add softmmu_target_strlen Nathan Froyd
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel

Some targets indicate properties of the program with special sections in
the ELF file--MIPS in particular.  This infrastructure is useful for
grovelling through those sections.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 elf_ops.h |   34 +++++++++++++++++++++++++++++++---
 loader.c  |   19 ++++++++++++++-----
 sysemu.h  |    5 +++++
 3 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/elf_ops.h b/elf_ops.h
index 72cd83e..9bede1b 100644
--- a/elf_ops.h
+++ b/elf_ops.h
@@ -98,7 +98,13 @@ static int glue(symcmp, SZ)(const void *s0, const void *s1)
         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
 }
 
-static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
+/* 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,
+                                  section_callback_t section_callback)
 {
     struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
     struct elf_sym *syms = NULL;
@@ -117,6 +123,27 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
         }
     }
 
+    /* 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, 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;
@@ -179,7 +206,8 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
 
 static int glue(load_elf, SZ)(int fd, int64_t address_offset,
                               int must_swab, uint64_t *pentry,
-                              uint64_t *lowaddr, uint64_t *highaddr)
+                              uint64_t *lowaddr, uint64_t *highaddr,
+                              section_callback_t section_callback)
 {
     struct elfhdr ehdr;
     struct elf_phdr *phdr = NULL, *ph;
@@ -213,7 +241,7 @@ static int glue(load_elf, SZ)(int fd, int64_t address_offset,
     if (pentry)
    	*pentry = (uint64_t)(elf_sword)ehdr.e_entry;
 
-    glue(load_symbols, SZ)(&ehdr, fd, must_swab);
+    glue(load_symbols, SZ)(&ehdr, fd, must_swab, section_callback);
 
     size = ehdr.e_phnum * sizeof(phdr[0]);
     lseek(fd, ehdr.e_phoff, SEEK_SET);
diff --git a/loader.c b/loader.c
index 54580e4..7caf395 100644
--- a/loader.c
+++ b/loader.c
@@ -302,9 +302,10 @@ static void *load_at(int fd, int offset, int size)
 #define SZ		64
 #include "elf_ops.h"
 
-/* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, int64_t address_offset,
-             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr)
+int load_elf_introspect(const char *filename, int64_t address_offset,
+                        uint64_t *pentry, uint64_t *lowaddr,
+                        uint64_t *highaddr,
+                        section_callback_t section_callback)
 {
     int fd, data_order, host_data_order, must_swab, ret;
     uint8_t e_ident[EI_NIDENT];
@@ -339,10 +340,10 @@ int load_elf(const char *filename, int64_t address_offset,
     lseek(fd, 0, SEEK_SET);
     if (e_ident[EI_CLASS] == ELFCLASS64) {
         ret = load_elf64(fd, address_offset, must_swab, pentry,
-                         lowaddr, highaddr);
+                         lowaddr, highaddr, section_callback);
     } else {
         ret = load_elf32(fd, address_offset, must_swab, pentry,
-                         lowaddr, highaddr);
+                         lowaddr, highaddr, section_callback);
     }
 
     close(fd);
@@ -353,6 +354,14 @@ int load_elf(const char *filename, int64_t address_offset,
     return -1;
 }
 
+/* return < 0 if error, otherwise the number of bytes loaded in memory */
+int load_elf(const char *filename, int64_t address_offset,
+             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr)
+{
+    return load_elf_introspect (filename, address_offset, pentry, lowaddr,
+                                highaddr, NULL);
+}
+
 static void bswap_uboot_header(uboot_image_header_t *hdr)
 {
 #ifndef WORDS_BIGENDIAN
diff --git a/sysemu.h b/sysemu.h
index df19f02..5f685a7 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -245,6 +245,11 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */
 int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
 int load_elf(const char *filename, int64_t address_offset,
              uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr);
+typedef void (*section_callback_t)(int fd, int must_swab,
+                                   uint64_t size, uint64_t offset, char *name);
+int load_elf_introspect(const char *filename, int64_t address_offset,
+                        uint64_t *pentry, uint64_t *lowaddr,
+                        uint64_t *highaddr, section_callback_t callback);
 int load_aout(const char *filename, target_phys_addr_t addr, int max_sz);
 int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr,
                 int *is_linux);
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 2/6] add softmmu_target_strlen
  2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader Nathan Froyd
@ 2009-07-17 20:33 ` Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting Nathan Froyd
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 softmmu-semi.h |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/softmmu-semi.h b/softmmu-semi.h
index 79278cc..dc667bc 100644
--- a/softmmu-semi.h
+++ b/softmmu-semi.h
@@ -60,6 +60,22 @@ static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
     return s;
 }
 #define lock_user_string(p) softmmu_lock_user_string(env, p)
+
+static int softmmu_target_strlen(CPUState *env, target_ulong addr)
+{
+    uint8_t c;
+    int len;
+
+    len = 0;
+    do {
+        cpu_memory_rw_debug(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(CPUState *env, void *p, target_ulong addr,
                                 target_ulong len)
 {
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting
  2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 2/6] add softmmu_target_strlen Nathan Froyd
@ 2009-07-17 20:33 ` Nathan Froyd
  2009-07-18  7:22   ` Blue Swirl
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 4/6] target-mips: add MDI semihosting support to mipssim machine Nathan Froyd
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel

Later patches will call into this file via do_mips_semihosting.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 Makefile.target   |    1 +
 mips-semi.c       |  217 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-mips/cpu.h |    1 +
 3 files changed, 219 insertions(+), 0 deletions(-)
 create mode 100644 mips-semi.c

diff --git a/Makefile.target b/Makefile.target
index f9cd42a..7230c44 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -534,6 +534,7 @@ obj-mips-y += piix_pci.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
 obj-mips-y += mipsnet.o
 obj-mips-y += pflash_cfi01.o
 obj-mips-y += vmware_vga.o
+obj-mips-y += mips-semi.o
 
 ifeq ($(TARGET_BASE_ARCH), mips)
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
diff --git a/mips-semi.c b/mips-semi.c
new file mode 100644
index 0000000..c1557a7
--- /dev/null
+++ b/mips-semi.c
@@ -0,0 +1,217 @@
+/*
+ * 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+#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.h"
+#include "gdbstub.h"
+#include "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(CPUState *env, target_ulong ret, target_ulong err)
+{
+    env->active_tc.PC = env->active_tc.gpr[31];
+    env->active_tc.gpr[2] = ret;
+    env->active_tc.gpr[3] = err;
+}
+
+static void mips_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+    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(CPUState *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 {
+            if (!(s = lock_user_string(ARG(0)))) {
+                result = -1;
+            } else {
+                result = open(s, translate_openflags(ARG(1)), ARG(2));
+            }
+            unlock_user(s, ARG(0), 0);
+        }
+        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 {
+            if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) {
+                result = -1;
+            } else {
+                result = read(ARG(0), p, len);
+                unlock_user(p, ARG(1), len);
+            }
+        }
+        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 {
+            if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) {
+                result = -1;
+            } else {
+                result = write(ARG(0), p, len);
+                unlock_user(p, ARG(1), len);
+            }
+        }
+        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:
+        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);
+}
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index bb9a49b..44420a1 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -587,6 +587,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 void do_interrupt (CPUState *env);
 void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
 
+void do_mips_semihosting(CPUState *env);
 static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
 {
     env->active_tc.PC = tb->pc;
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 4/6] target-mips: add MDI semihosting support to mipssim machine
  2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
                   ` (2 preceding siblings ...)
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting Nathan Froyd
@ 2009-07-17 20:33 ` Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 6/6] gdbstub: add qSymbol handling " Nathan Froyd
  5 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel

We need to grovel through the .sdeosabi section to find out where
_mdi_syscall is located.  Once we find it, we can set a breakpoint
there.

We use BP_CPU breakpoints to implement the semihosting breakpoint.
Writing BREAK instructions means that users could unintentionally remove
breakpoints, either by means of buggy programs, or mistyped commands.
Using BP_CPU breakpoints means that the user cannot access them and
therefore that they will not be removed (although BP_CPU breakpoints can
be overridden by BP_GDB breakpoints; we assume that the user knows what
he or she is doing if a breakpoint is set at _mdi_syscall).

The shuffling of #includes in helper.c is to deal with peculiarities of
dyngen-exec.h.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 hw/mips_mipssim.c    |   58 +++++++++++++++++++++++++++++++++++++++++++++++--
 target-mips/cpu.h    |    2 +
 target-mips/helper.c |   50 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 103 insertions(+), 7 deletions(-)

diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 6080dc8..7da3269 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -48,6 +48,50 @@ static struct _loaderparams {
     const char *initrd_filename;
 } loaderparams;
 
+static uint32_t mdi_semihost_bkpt;
+
+static void find_sdeosabi_section (int fd, int must_swab,
+                                   uint64_t size, uint64_t offset,
+                                   char *name)
+{
+/* We don't support semihosting for 64-bit targets */
+#ifndef TARGET_MIPS64
+    if (semihosting_enabled &&
+        size >= 8 &&
+        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 4-byte 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.  */
+            uint32_t bkpt_info[2];
+
+            if (read(fd, bkpt_info, sizeof(bkpt_info)) == sizeof(bkpt_info)) {
+                if (must_swab) {
+                    bswap32s (&bkpt_info[0]);
+                    bswap32s (&bkpt_info[1]);
+                }
+
+                if (bkpt_info[0] == 2 && bkpt_info[1]) {
+                    mdi_semihost_bkpt = bkpt_info[1];
+                    break;
+                }
+            } else {
+                break;
+            }
+
+            section_offset += sizeof(bkpt_info);
+        }
+    }
+#endif
+}
+
 static void load_kernel (CPUState *env)
 {
     int64_t entry, kernel_low, kernel_high;
@@ -55,9 +99,12 @@ static void load_kernel (CPUState *env)
     long initrd_size;
     ram_addr_t initrd_offset;
 
-    kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
-                           (uint64_t *)&entry, (uint64_t *)&kernel_low,
-                           (uint64_t *)&kernel_high);
+    kernel_size = load_elf_introspect(loaderparams.kernel_filename,
+                                      VIRT_TO_PHYS_ADDEND,
+                                      (uint64_t *)&entry,
+                                      (uint64_t *)&kernel_low,
+                                      (uint64_t *)&kernel_high,
+                                      find_sdeosabi_section);
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
@@ -68,6 +115,11 @@ static void load_kernel (CPUState *env)
         exit(1);
     }
 
+    /* set up semihosting */
+    if (semihosting_enabled && mdi_semihost_bkpt) {
+        install_semihosting_breakpoint(env, mdi_semihost_bkpt);
+    }
+
     /* load initrd */
     initrd_size = 0;
     initrd_offset = 0;
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 44420a1..d1ab9dd 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -588,6 +588,8 @@ void do_interrupt (CPUState *env);
 void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
 
 void do_mips_semihosting(CPUState *env);
+void install_semihosting_breakpoint(CPUState *env, uint32_t bkpt_address);
+
 static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
 {
     env->active_tc.PC = tb->pc;
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 7369025..db9ee8d 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -18,13 +18,10 @@
  */
 #include <stdarg.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
-#include <inttypes.h>
 #include <signal.h>
 
-#include "cpu.h"
-#include "exec-all.h"
+#include "exec.h"
 
 enum {
     TLBRET_DIRTY = -4,
@@ -340,6 +337,51 @@ static const char * const excp_names[EXCP_LAST + 1] = {
     [EXCP_CACHE] = "cache error",
 };
 
+#if !defined(CONFIG_USER_ONLY)
+extern int semihosting_enabled;
+static uint32_t mdi_semihost_breakpoint;
+
+static CPUDebugExcpHandler *prev_debug_excp_handler;
+static CPUBreakpoint *semihosting_breakpoint;
+
+static void breakpoint_handler(CPUState *env)
+{
+    CPUBreakpoint *bp;
+    int semihosting_done = 0;
+
+    TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (bp->pc == env->active_tc.PC &&
+            semihosting_enabled &&
+            mdi_semihost_breakpoint &&
+            bp->pc == mdi_semihost_breakpoint &&
+            bp->flags & BP_CPU) {
+            do_mips_semihosting(env);
+            semihosting_done = 1;
+            break;
+        }
+    }
+    if (prev_debug_excp_handler) {
+        prev_debug_excp_handler(env);
+    }
+    if (semihosting_done) {
+        /* Reset exception state and return.  */
+        env->exception_index = -1;
+        cpu_loop_exit();
+    }
+}
+
+void install_semihosting_breakpoint(CPUState *env, uint32_t bkpt_address)
+{
+    if (!semihosting_breakpoint && semihosting_enabled) {
+        mdi_semihost_breakpoint = bkpt_address & ~(uint32_t)1;
+        cpu_breakpoint_insert(env, mdi_semihost_breakpoint, BP_CPU,
+                              &semihosting_breakpoint);
+        prev_debug_excp_handler =
+            cpu_set_debug_excp_handler(breakpoint_handler);
+    }
+}
+#endif
+
 void do_interrupt (CPUState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS
  2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
                   ` (3 preceding siblings ...)
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 4/6] target-mips: add MDI semihosting support to mipssim machine Nathan Froyd
@ 2009-07-17 20:33 ` Nathan Froyd
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 6/6] gdbstub: add qSymbol handling " Nathan Froyd
  5 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 qemu-options.hx |    2 +-
 vl.c            |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index a58287c..b45f382 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1653,7 +1653,7 @@ DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env,
     "-prom-env variable=value\n"
     "                set OpenBIOS nvram variables\n")
 #endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_MIPS)
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
     "-semihosting    semihosting mode\n")
 #endif
diff --git a/vl.c b/vl.c
index ce213c2..3542b72 100644
--- a/vl.c
+++ b/vl.c
@@ -5511,7 +5511,7 @@ int main(int argc, char **argv, char **envp)
 		option_rom[nb_option_roms] = optarg;
 		nb_option_roms++;
 		break;
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_MIPS)
             case QEMU_OPTION_semihosting:
                 semihosting_enabled = 1;
                 break;
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 6/6] gdbstub: add qSymbol handling for TARGET_MIPS
  2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
                   ` (4 preceding siblings ...)
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS Nathan Froyd
@ 2009-07-17 20:33 ` Nathan Froyd
  5 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-17 20:33 UTC (permalink / raw)
  To: qemu-devel

QEMU needs to know the address of _mdi_syscall so that breakpoints can
be set appropriately.  But if QEMU is started from within GDB as:

  (gdb) target remote | qemu -M mipssim -s -S ... -kernel /dev/null
  ...
  (gdb) load

then QEMU's ELF loader never gets a chance to grovel through the ELF
file to look for the .sdeosabi section.

Therefore, the GDB stub needs to know how to ask GDB for the address of
_mdi_syscall so that the necessary breakpoint can be set.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 gdbstub.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index bb38971..d881a66 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1937,6 +1937,35 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
                 put_packet(s, buf);
             }
             break;
+        } else if (strncmp(p, "Symbol:", 7) == 0) {
+#if defined(TARGET_MIPS) && !defined(TARGET_MIPS64) && !defined(CONFIG_USER_ONLY)
+#define MDI_SYSCALL_SYMBOL "_mdi_syscall"
+            if (strncmp(p+7, ":", 1) == 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.  */
+                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) {
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting
  2009-07-17 20:33 ` [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting Nathan Froyd
@ 2009-07-18  7:22   ` Blue Swirl
  2009-07-20 15:24     ` Nathan Froyd
  0 siblings, 1 reply; 10+ messages in thread
From: Blue Swirl @ 2009-07-18  7:22 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Fri, Jul 17, 2009 at 11:33 PM, Nathan Froyd<froydnj@codesourcery.com> wrote:
> Later patches will call into this file via do_mips_semihosting.

> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
> + *  MA 02110-1301, USA.

Please use the latest version: "if not, see <http://www.gnu.org/licenses/>."

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting
  2009-07-18  7:22   ` Blue Swirl
@ 2009-07-20 15:24     ` Nathan Froyd
  0 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-07-20 15:24 UTC (permalink / raw)
  To: qemu-devel

Later patches will call into this file via do_mips_semihosting.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 Makefile.target   |    1 +
 mips-semi.c       |  216 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-mips/cpu.h |    1 +
 3 files changed, 218 insertions(+), 0 deletions(-)
 create mode 100644 mips-semi.c

v2: point at FSF website for copies of GPL

diff --git a/Makefile.target b/Makefile.target
index f9cd42a..7230c44 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -534,6 +534,7 @@ obj-mips-y += piix_pci.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
 obj-mips-y += mipsnet.o
 obj-mips-y += pflash_cfi01.o
 obj-mips-y += vmware_vga.o
+obj-mips-y += mips-semi.o
 
 ifeq ($(TARGET_BASE_ARCH), mips)
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
diff --git a/mips-semi.c b/mips-semi.c
new file mode 100644
index 0000000..77ecff3
--- /dev/null
+++ b/mips-semi.c
@@ -0,0 +1,216 @@
+
+/*
+ * 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.h"
+#include "gdbstub.h"
+#include "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(CPUState *env, target_ulong ret, target_ulong err)
+{
+    env->active_tc.PC = env->active_tc.gpr[31];
+    env->active_tc.gpr[2] = ret;
+    env->active_tc.gpr[3] = err;
+}
+
+static void mips_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+    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(CPUState *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 {
+            if (!(s = lock_user_string(ARG(0)))) {
+                result = -1;
+            } else {
+                result = open(s, translate_openflags(ARG(1)), ARG(2));
+            }
+            unlock_user(s, ARG(0), 0);
+        }
+        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 {
+            if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) {
+                result = -1;
+            } else {
+                result = read(ARG(0), p, len);
+                unlock_user(p, ARG(1), len);
+            }
+        }
+        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 {
+            if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) {
+                result = -1;
+            } else {
+                result = write(ARG(0), p, len);
+                unlock_user(p, ARG(1), len);
+            }
+        }
+        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:
+        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);
+}
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index bb9a49b..44420a1 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -587,6 +587,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 void do_interrupt (CPUState *env);
 void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
 
+void do_mips_semihosting(CPUState *env);
 static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
 {
     env->active_tc.PC = tb->pc;
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS
  2009-08-03 14:45 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting, v2 Nathan Froyd
@ 2009-08-03 14:45 ` Nathan Froyd
  0 siblings, 0 replies; 10+ messages in thread
From: Nathan Froyd @ 2009-08-03 14:45 UTC (permalink / raw)
  To: qemu-devel


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 qemu-options.hx |    2 +-
 vl.c            |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index 1b420a3..8514491 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1658,7 +1658,7 @@ DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env,
     "-prom-env variable=value\n"
     "                set OpenBIOS nvram variables\n")
 #endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_MIPS)
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
     "-semihosting    semihosting mode\n")
 #endif
diff --git a/vl.c b/vl.c
index fdd4f03..c3525e2 100644
--- a/vl.c
+++ b/vl.c
@@ -5520,7 +5520,7 @@ int main(int argc, char **argv, char **envp)
 		option_rom[nb_option_roms] = optarg;
 		nb_option_roms++;
 		break;
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_MIPS)
             case QEMU_OPTION_semihosting:
                 semihosting_enabled = 1;
                 break;
-- 
1.6.3.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-08-03 14:45 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-17 20:33 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting Nathan Froyd
2009-07-17 20:33 ` [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader Nathan Froyd
2009-07-17 20:33 ` [Qemu-devel] [PATCH 2/6] add softmmu_target_strlen Nathan Froyd
2009-07-17 20:33 ` [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting Nathan Froyd
2009-07-18  7:22   ` Blue Swirl
2009-07-20 15:24     ` Nathan Froyd
2009-07-17 20:33 ` [Qemu-devel] [PATCH 4/6] target-mips: add MDI semihosting support to mipssim machine Nathan Froyd
2009-07-17 20:33 ` [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS Nathan Froyd
2009-07-17 20:33 ` [Qemu-devel] [PATCH 6/6] gdbstub: add qSymbol handling " Nathan Froyd
  -- strict thread matches above, loose matches on Subject: below --
2009-08-03 14:45 [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting, v2 Nathan Froyd
2009-08-03 14:45 ` [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS Nathan Froyd

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).