From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MSuj7-0007zq-Aj for qemu-devel@nongnu.org; Mon, 20 Jul 2009 11:24:29 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MSuj2-0007xh-BK for qemu-devel@nongnu.org; Mon, 20 Jul 2009 11:24:28 -0400 Received: from [199.232.76.173] (port=54112 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MSuj2-0007xZ-06 for qemu-devel@nongnu.org; Mon, 20 Jul 2009 11:24:24 -0400 Received: from mx20.gnu.org ([199.232.41.8]:7966) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MSuj1-0001VX-OK for qemu-devel@nongnu.org; Mon, 20 Jul 2009 11:24:23 -0400 Received: from mail.codesourcery.com ([65.74.133.4]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MSuj0-000171-B9 for qemu-devel@nongnu.org; Mon, 20 Jul 2009 11:24:22 -0400 Date: Mon, 20 Jul 2009 08:24:20 -0700 From: Nathan Froyd Subject: Re: [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting Message-ID: <20090720152420.GF26319@codesourcery.com> References: <1247862802-13033-1-git-send-email-froydnj@codesourcery.com> <1247862802-13033-4-git-send-email-froydnj@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Later patches will call into this file via do_mips_semihosting. Signed-off-by: Nathan Froyd --- 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 . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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