From patchwork Mon Aug 3 14:45:08 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Froyd X-Patchwork-Id: 30601 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id F06E7B6F31 for ; Tue, 4 Aug 2009 03:20:54 +1000 (EST) Received: from localhost ([127.0.0.1]:49480 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MY1DP-0002sf-FC for incoming@patchwork.ozlabs.org; Mon, 03 Aug 2009 13:20:51 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MXzCo-0004md-5u for qemu-devel@nongnu.org; Mon, 03 Aug 2009 11:12:07 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MXzCh-0004kz-61 for qemu-devel@nongnu.org; Mon, 03 Aug 2009 11:12:03 -0400 Received: from [199.232.76.173] (port=35530 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MXzCe-0004kW-0l for qemu-devel@nongnu.org; Mon, 03 Aug 2009 11:11:56 -0400 Received: from mx20.gnu.org ([199.232.41.8]:48380) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MXzCd-0000yE-Nc for qemu-devel@nongnu.org; Mon, 03 Aug 2009 11:11:55 -0400 Received: from mail.codesourcery.com ([65.74.133.4]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MXzCc-0002as-I3 for qemu-devel@nongnu.org; Mon, 03 Aug 2009 11:11:54 -0400 Received: (qmail 16854 invoked from network); 3 Aug 2009 14:45:12 -0000 Received: from unknown (HELO localhost) (froydnj@127.0.0.2) by mail.codesourcery.com with ESMTPA; 3 Aug 2009 14:45:12 -0000 From: Nathan Froyd To: qemu-devel@nongnu.org Date: Mon, 3 Aug 2009 07:45:08 -0700 Message-Id: <1249310711-8873-4-git-send-email-froydnj@codesourcery.com> X-Mailer: git-send-email 1.6.3.2 In-Reply-To: <1249310711-8873-1-git-send-email-froydnj@codesourcery.com> References: <1249310711-8873-1-git-send-email-froydnj@codesourcery.com> X-Detected-Operating-System: by mx20.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Subject: [Qemu-devel] [PATCH 3/6] add implementation of MIPS semihosting X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@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 diff --git a/Makefile.target b/Makefile.target index 49ba08d..676a9f9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -370,6 +370,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 789176b..1510244 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;