From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MRuXM-0008W8-HL for qemu-devel@nongnu.org; Fri, 17 Jul 2009 17:00:12 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MRuXH-0008Op-GJ for qemu-devel@nongnu.org; Fri, 17 Jul 2009 17:00:12 -0400 Received: from [199.232.76.173] (port=50907 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MRuXH-0008OJ-88 for qemu-devel@nongnu.org; Fri, 17 Jul 2009 17:00:07 -0400 Received: from mx20.gnu.org ([199.232.41.8]:31975) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MRuXG-0006Pg-Or for qemu-devel@nongnu.org; Fri, 17 Jul 2009 17:00:06 -0400 Received: from mail.codesourcery.com ([65.74.133.4]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MRuXF-0007ek-DU for qemu-devel@nongnu.org; Fri, 17 Jul 2009 17:00:05 -0400 From: Nathan Froyd Date: Fri, 17 Jul 2009 13:33:20 -0700 Message-Id: <1247862802-13033-5-git-send-email-froydnj@codesourcery.com> In-Reply-To: <1247862802-13033-1-git-send-email-froydnj@codesourcery.com> References: <1247862802-13033-1-git-send-email-froydnj@codesourcery.com> Subject: [Qemu-devel] [PATCH 4/6] target-mips: add MDI semihosting support to mipssim machine List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 --- 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 #include -#include #include -#include #include -#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