| /*************************************************************************** |
| * __________ __ ___. |
| * 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 |