From d4674ed3b7cd98fab499d0d94d364bdb060df3ff Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Mon, 2 Apr 2012 15:20:02 +0200 Subject: arm: implement safe reads by intercepting the data abort handler. Implement functions to read from a memory location and indicate failure in case this is not possible. Since we do not have a MMU, intercept the data abort handler and simply return when the abort comes from the safe read routines. Change-Id: I08f2e59898dcac893319a8150d4cf626f3adabbd Reviewed-on: http://gerrit.rockbox.org/207 Reviewed-by: Marcin Bukat --- lib/unwarminder/SOURCES | 1 + lib/unwarminder/backtrace.c | 10 ++-- lib/unwarminder/safe_read.S | 143 ++++++++++++++++++++++++++++++++++++++++++++ lib/unwarminder/safe_read.h | 33 ++++++++++ 4 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 lib/unwarminder/safe_read.S create mode 100644 lib/unwarminder/safe_read.h diff --git a/lib/unwarminder/SOURCES b/lib/unwarminder/SOURCES index 055e6d0ab3..b060e2908d 100644 --- a/lib/unwarminder/SOURCES +++ b/lib/unwarminder/SOURCES @@ -5,3 +5,4 @@ unwarm.c unwarminder.c unwarmmem.c unwarm_thumb.c +safe_read.S \ No newline at end of file diff --git a/lib/unwarminder/backtrace.c b/lib/unwarminder/backtrace.c index 4e1609137c..294b7f66f4 100644 --- a/lib/unwarminder/backtrace.c +++ b/lib/unwarminder/backtrace.c @@ -23,6 +23,7 @@ ***************************************************************************/ #include "backtrace.h" +#include "safe_read.h" /*************************************************************************** * Prototypes @@ -86,20 +87,17 @@ static Boolean CliReport(void *data, Int32 address) static Boolean CliReadW(const Int32 a, Int32 *v) { - *v = *(Int32 *)a; - return TRUE; + return safe_read32((uint32_t *)a, (uint32_t *)v); } static Boolean CliReadH(const Int32 a, Int16 *v) { - *v = *(Int16 *)a; - return TRUE; + return safe_read16((void *)a, (uint16_t *)v); } static Boolean CliReadB(const Int32 a, Int8 *v) { - *v = *(Int8 *)a; - return TRUE; + return safe_read8((void *)a, (uint8_t *)v); } Boolean CliInvalidateW(const Int32 a) diff --git a/lib/unwarminder/safe_read.S b/lib/unwarminder/safe_read.S new file mode 100644 index 0000000000..2e3fc78955 --- /dev/null +++ b/lib/unwarminder/safe_read.S @@ -0,0 +1,143 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 by Amaury Pouly + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" + +.data +was_aborted: + .word 0 + +.section .text.safe_read8 +.type safe_read8, %function +.global safe_read8 +@ bool safe_read8(uint8_t *addr, uint8_t *value) +safe_read8: + @ was_aborted = 0 + ldr r2, =was_aborted + mov r3, #0 + str r3, [r2] + @ r0=*addr +safe_read8_faulty_addr: + ldrb r0, [r0] + @ if(was_aborted) + ldr r2, [r2] + cmp r2, #1 + @ return false; + moveq r0, #0 + bxeq lr + @ if(value != NULL) + cmp r1, #0 + @ *value = r0 + strneb r0, [r1] + @ return true; + mov r0, #1 + bx lr +.size safe_read8, . - safe_read8 + +.section .text.safe_read16 +.type safe_read16, %function +.global safe_read16 +@ bool safe_read16(uint16_t *addr, uint16_t *value) +safe_read16: + @ was_aborted = 0 + ldr r2, =was_aborted + mov r3, #0 + str r3, [r2] + @ r0=*addr +safe_read16_faulty_addr: + ldrh r0, [r0] + @ if(was_aborted) + ldr r2, [r2] + cmp r2, #1 + @ return false; + moveq r0, #0 + bxeq lr + @ if(value != NULL) + cmp r1, #0 + @ *value = r0 + strneh r0, [r1] + @ return true; + mov r0, #1 + bx lr +.size safe_read16, . - safe_read16 + +.section .text.safe_read32 +.type safe_read32, %function +.global safe_read32 +@ bool safe_read32(uint32_t *addr, uint32_t *value) +safe_read32: + @ was_aborted = 0 + ldr r2, =was_aborted + mov r3, #0 + str r3, [r2] + @ r0=*addr +safe_read32_faulty_addr: + ldr r0, [r0] + @ if(was_aborted) + ldr r2, [r2] + cmp r2, #1 + @ return false; + moveq r0, #0 + bxeq lr + @ if(value != NULL) + cmp r1, #0 + @ *value = r0 + strne r0, [r1] + @ return true; + mov r0, #1 + bx lr +.size safe_read32, . - safe_read32 + +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +.section .text.data_abort_handler +.type data_abort_handler, %function +.global data_abort_handler +data_abort_handler: + @ store minimal amount of registers + stmfd sp!, {r0-r1} + @ compute faulty address + sub r0, lr, #8 + @ compare to safe_read8 + ldr r1, =safe_read8_faulty_addr + cmp r0, r1 + beq 1f + @ compare to safe_read16 + ldr r1, =safe_read16_faulty_addr + cmp r0, r1 + beq 1f + @ compare to safe_read32 + ldr r1, =safe_read32_faulty_addr + cmp r0, r1 + beq 1f + @ otherwise just normally to UIE + mov r0, r1 + mov r1, #2 + b UIE +1: + @ set was_aborted + ldr r1, =was_aborted + mov r0, #1 + str r0, [r1] + @ restore registers + ldmfd sp!, {r0-r1} + @ restore mode and jump back to the *next* instruction + subs pc, lr, #-4 +.size data_abort_handler, . - data_abort_handler +#endif diff --git a/lib/unwarminder/safe_read.h b/lib/unwarminder/safe_read.h new file mode 100644 index 0000000000..0ad23e648d --- /dev/null +++ b/lib/unwarminder/safe_read.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 by Amaury Pouly + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __SAFE_READ__ +#define __SAFE_READ__ + +#include "system.h" + +/* Try to read an X-bit unsigned integer. If the address is not readable, + * returns false. Otherwise returns true and store the result in *value + * if value is not NULL */ +bool safe_read8(uint8_t *addr, uint8_t *value); +bool safe_read16(uint16_t *addr, uint16_t *value); +bool safe_read32(uint32_t *addr, uint32_t *value); + +#endif /* __SAFE_READ__ */ \ No newline at end of file -- cgit v1.2.3