[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting
From: |
Nathan Froyd |
Subject: |
[Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting |
Date: |
Fri, 17 Jul 2009 13:33:19 -0700 |
Later patches will call into this file via do_mips_semihosting.
Signed-off-by: Nathan Froyd <address@hidden>
---
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
- [Qemu-devel] [PATCH 0/6] target-mips: add MDI semihosting, Nathan Froyd, 2009/07/17
- [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader, Nathan Froyd, 2009/07/17
- [Qemu-devel] [PATCH 5/6] enable --semihosting option for TARGET_MIPS, Nathan Froyd, 2009/07/17
- [Qemu-devel] [PATCH 4/6] target-mips: add MDI semihosting support to mipssim machine, Nathan Froyd, 2009/07/17
- [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting,
Nathan Froyd <=
- [Qemu-devel] [PATCH 2/6] add softmmu_target_strlen, Nathan Froyd, 2009/07/17
- [Qemu-devel] [PATCH 6/6] gdbstub: add qSymbol handling for TARGET_MIPS, Nathan Froyd, 2009/07/17