Ignore:
Timestamp:
2013-02-09T23:14:45Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/fix-logger-deadlock, topic/msim-upgrade, topic/simplify-dev-export
Children:
22dfd38
Parents:
b5d2e57 (diff), 005b765 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

Conflict resulting from bool.h → stdbool.h move and ddf structs turning opaque.
Fails to boot to shell console.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/arm32/src/mm/page_fault.c

    rb5d2e57 r03362fbd  
    3434 */
    3535#include <panic.h>
     36#include <arch/cp15.h>
    3637#include <arch/exception.h>
    3738#include <arch/mm/page_fault.h>
     
    4243#include <print.h>
    4344
    44 /** Returns value stored in fault status register.
    45  *
    46  *  @return Value stored in CP15 fault status register (FSR).
    47  */
    48 static inline fault_status_t read_fault_status_register(void)
    49 {
    50         fault_status_union_t fsu;
    51        
    52         /* fault status is stored in CP15 register 5 */
    53         asm volatile (
    54                 "mrc p15, 0, %[dummy], c5, c0, 0"
    55                 : [dummy] "=r" (fsu.dummy)
    56         );
    57        
    58         return fsu.fs;
    59 }
    60 
    61 /** Returns FAR (fault address register) content.
    62  *
    63  * @return FAR (fault address register) content (address that caused a page
    64  *         fault)
    65  */
    66 static inline uintptr_t read_fault_address_register(void)
    67 {
    68         uintptr_t ret;
    69        
    70         /* fault adress is stored in CP15 register 6 */
    71         asm volatile (
    72                 "mrc p15, 0, %[ret], c6, c0, 0"
    73                 : [ret] "=r" (ret)
    74         );
    75        
    76         return ret;
    77 }
    78 
    79 /** Decides whether the instruction is load/store or not.
    80  *
    81  * @param instr Instruction
    82  *
    83  * @return true when instruction is load/store, false otherwise
    84  *
    85  */
    86 static inline bool is_load_store_instruction(instruction_t instr)
    87 {
    88         /* load store immediate offset */
    89         if (instr.type == 0x2)
    90                 return true;
    91        
    92         /* load store register offset */
    93         if ((instr.type == 0x3) && (instr.bit4 == 0))
    94                 return true;
    95        
    96         /* load store multiple */
    97         if (instr.type == 0x4)
    98                 return true;
    99        
    100         /* oprocessor load/store */
    101         if (instr.type == 0x6)
    102                 return true;
    103        
    104         return false;
    105 }
    106 
    107 /** Decides whether the instruction is swap or not.
    108  *
    109  * @param instr Instruction
    110  *
    111  * @return true when instruction is swap, false otherwise
    112  */
    113 static inline bool is_swap_instruction(instruction_t instr)
    114 {
    115         /* swap, swapb instruction */
    116         if ((instr.type == 0x0) &&
    117             ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
    118             (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
    119                 return true;
    120        
    121         return false;
    122 }
    123 
     45
     46/**
     47 * FSR encoding ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition.
     48 *
     49 * B3.13.3 page B3-1406 (PDF page 1406)
     50 */
     51typedef enum {
     52        DFSR_SOURCE_ALIGN = 0x0001,
     53        DFSR_SOURCE_CACHE_MAINTENANCE = 0x0004,
     54        DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L1 = 0x000c,
     55        DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L2 = 0x000e,
     56        DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L1 = 0x040c,
     57        DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L2 = 0x040e,
     58        DFSR_SOURCE_TRANSLATION_L1 = 0x0005,
     59        DFSR_SOURCE_TRANSLATION_L2 = 0x0007,
     60        DFSR_SOURCE_ACCESS_FLAG_L1 = 0x0003,  /**< @note: This used to be alignment enc. */
     61        DFSR_SOURCE_ACCESS_FLAG_L2 = 0x0006,
     62        DFSR_SOURCE_DOMAIN_L1 = 0x0009,
     63        DFSR_SOURCE_DOMAIN_L2 = 0x000b,
     64        DFSR_SOURCE_PERMISSION_L1 = 0x000d,
     65        DFSR_SOURCE_PERMISSION_L2 = 0x000f,
     66        DFSR_SOURCE_DEBUG = 0x0002,
     67        DFSR_SOURCE_SYNC_EXTERNAL = 0x0008,
     68        DFSR_SOURCE_TLB_CONFLICT = 0x0400,
     69        DFSR_SOURCE_LOCKDOWN = 0x0404, /**< @note: Implementation defined */
     70        DFSR_SOURCE_COPROCESSOR = 0x040a, /**< @note Implementation defined */
     71        DFSR_SOURCE_SYNC_PARITY = 0x0409,
     72        DFSR_SOURCE_ASYNC_EXTERNAL = 0x0406,
     73        DFSR_SOURCE_ASYNC_PARITY = 0x0408,
     74        DFSR_SOURCE_MASK = 0x0000040f,
     75} dfsr_source_t;
     76
     77static inline const char * dfsr_source_to_str(dfsr_source_t source)
     78{
     79        switch (source) {
     80        case DFSR_SOURCE_TRANSLATION_L1:
     81                return "Translation fault L1";
     82        case DFSR_SOURCE_TRANSLATION_L2:
     83                return "Translation fault L2";
     84        case DFSR_SOURCE_PERMISSION_L1:
     85                return "Permission fault L1";
     86        case DFSR_SOURCE_PERMISSION_L2:
     87                return "Permission fault L2";
     88        case DFSR_SOURCE_ALIGN:
     89                return "Alignment fault";
     90        case DFSR_SOURCE_CACHE_MAINTENANCE:
     91                return "Instruction cache maintenance fault";
     92        case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L1:
     93                return "Synchronous external abort on translation table walk level 1";
     94        case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L2:
     95                return "Synchronous external abort on translation table walk level 2";
     96        case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L1:
     97                return "Synchronous parity error on translation table walk level 1";
     98        case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L2:
     99                return "Synchronous parity error on translation table walk level 2";
     100        case DFSR_SOURCE_ACCESS_FLAG_L1:
     101                return "Access flag fault L1";
     102        case DFSR_SOURCE_ACCESS_FLAG_L2:
     103                return "Access flag fault L2";
     104        case DFSR_SOURCE_DOMAIN_L1:
     105                return "Domain fault L1";
     106        case DFSR_SOURCE_DOMAIN_L2:
     107                return "Domain flault L2";
     108        case DFSR_SOURCE_DEBUG:
     109                return "Debug event";
     110        case DFSR_SOURCE_SYNC_EXTERNAL:
     111                return "Synchronous external abort";
     112        case DFSR_SOURCE_TLB_CONFLICT:
     113                return "TLB conflict abort";
     114        case DFSR_SOURCE_LOCKDOWN:
     115                return "Lockdown (Implementation defined)";
     116        case DFSR_SOURCE_COPROCESSOR:
     117                return "Coprocessor abort (Implementation defined)";
     118        case DFSR_SOURCE_SYNC_PARITY:
     119                return "Synchronous parity error on memory access";
     120        case DFSR_SOURCE_ASYNC_EXTERNAL:
     121                return "Asynchronous external abort";
     122        case DFSR_SOURCE_ASYNC_PARITY:
     123                return "Asynchronous parity error on memory access";
     124        case DFSR_SOURCE_MASK:
     125                break;
     126        }
     127        return "Unknown data abort";
     128}
     129
     130#if defined(PROCESSOR_ARCH_armv4) | defined(PROCESSOR_ARCH_armv5)
    124131/** Decides whether read or write into memory is requested.
    125132 *
     
    128135 *
    129136 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
    130  *         requested.
     137 *         requested.
    131138 */
    132139static pf_access_t get_memory_access_type(uint32_t instr_addr,
     
    142149                panic("page_fault - instruction does not access memory "
    143150                    "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
    144                     instr_union.pc, (void *) badvaddr);
     151                    *(uint32_t*)instr_union.instr, (void *) badvaddr);
    145152                return PF_ACCESS_EXEC;
    146153        }
    147154
    148         /* load store instructions */
    149         if (is_load_store_instruction(instr)) {
    150                 if (instr.access == 1) {
    151                         return PF_ACCESS_READ;
    152                 } else {
    153                         return PF_ACCESS_WRITE;
     155        /* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition
     156         * A5.3 (PDF p. 206) */
     157        static const struct {
     158                uint32_t mask;
     159                uint32_t value;
     160                pf_access_t access;
     161        } ls_inst[] = {
     162                /* Store word/byte */
     163                { 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/
     164                { 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/
     165                /* Load word/byte */
     166                { 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR(B) imm*/
     167                { 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR(B) reg*/
     168                /* Store half-word/dual  A5.2.8 */
     169                { 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/
     170                /* Load half-word/dual A5.2.8 */
     171                { 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/
     172                { 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/
     173                /* Block data transfer, Store */
     174                { 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */
     175                { 0x0e100000, 0x08100000, PF_ACCESS_READ },  /* LDM variants */
     176                /* Swap */
     177                { 0x0fb00000, 0x01000000, PF_ACCESS_WRITE },
     178        };
     179        const uint32_t inst = *(uint32_t*)instr_addr;
     180        for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) {
     181                if ((inst & ls_inst[i].mask) == ls_inst[i].value) {
     182                        return ls_inst[i].access;
    154183                }
    155         }
    156 
    157         /* swap, swpb instruction */
    158         if (is_swap_instruction(instr)) {
    159                 return PF_ACCESS_WRITE;
    160184        }
    161185
    162186        panic("page_fault - instruction doesn't access memory "
    163187            "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
    164             instr_union.pc, (void *) badvaddr);
    165 
    166         return PF_ACCESS_EXEC;
    167 }
     188            inst, (void *) badvaddr);
     189}
     190#endif
    168191
    169192/** Handles "data abort" exception (load or store at invalid address).
     
    175198void data_abort(unsigned int exc_no, istate_t *istate)
    176199{
    177         fault_status_t fsr __attribute__ ((unused)) =
    178             read_fault_status_register();
    179         uintptr_t badvaddr = read_fault_address_register();
    180 
    181         pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
    182 
    183         int ret = as_page_fault(badvaddr, access, istate);
    184 
    185         if (ret == AS_PF_FAULT) {
    186                 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
    187                 panic_memtrap(istate, access, badvaddr, NULL);
    188         }
     200        const uintptr_t badvaddr = DFAR_read();
     201        const fault_status_t fsr = { .raw = DFSR_read() };
     202        const dfsr_source_t source = fsr.raw & DFSR_SOURCE_MASK;
     203
     204        switch (source) {
     205        case DFSR_SOURCE_TRANSLATION_L1:
     206        case DFSR_SOURCE_TRANSLATION_L2:
     207        case DFSR_SOURCE_PERMISSION_L1:
     208        case DFSR_SOURCE_PERMISSION_L2:
     209                /* Page fault is handled further down */
     210                break;
     211        case DFSR_SOURCE_ALIGN:
     212        case DFSR_SOURCE_CACHE_MAINTENANCE:
     213        case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L1:
     214        case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L2:
     215        case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L1:
     216        case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L2:
     217        case DFSR_SOURCE_ACCESS_FLAG_L1:
     218        case DFSR_SOURCE_ACCESS_FLAG_L2:
     219        case DFSR_SOURCE_DOMAIN_L1:
     220        case DFSR_SOURCE_DOMAIN_L2:
     221        case DFSR_SOURCE_DEBUG:
     222        case DFSR_SOURCE_SYNC_EXTERNAL:
     223        case DFSR_SOURCE_TLB_CONFLICT:
     224        case DFSR_SOURCE_LOCKDOWN:
     225        case DFSR_SOURCE_COPROCESSOR:
     226        case DFSR_SOURCE_SYNC_PARITY:
     227        case DFSR_SOURCE_ASYNC_EXTERNAL:
     228        case DFSR_SOURCE_ASYNC_PARITY:
     229        case DFSR_SOURCE_MASK:
     230                /* Weird abort stuff */
     231                fault_if_from_uspace(istate, "Unhandled abort %s at address: "
     232                    "%#x.", dfsr_source_to_str(source), badvaddr);
     233                panic("Unhandled abort %s at address: %#x.",
     234                    dfsr_source_to_str(source), badvaddr);
     235        }
     236
     237#if defined(PROCESSOR_ARCH_armv6) | defined(PROCESSOR_ARCH_armv7_a)
     238        const pf_access_t access =
     239            fsr.data.wr ? PF_ACCESS_WRITE : PF_ACCESS_READ;
     240#elif defined(PROCESSOR_ARCH_armv4) | defined(PROCESSOR_ARCH_armv5)
     241        const pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
     242#else
     243#error "Unsupported architecture"
     244#endif
     245        as_page_fault(badvaddr, access, istate);
    189246}
    190247
     
    197254void prefetch_abort(unsigned int exc_no, istate_t *istate)
    198255{
    199         int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
    200 
    201         if (ret == AS_PF_FAULT) {
    202                 fault_if_from_uspace(istate,
    203                     "Page fault - prefetch_abort: %#x.", istate->pc);
    204                 panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc, NULL);
    205         }
     256        as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
    206257}
    207258
Note: See TracChangeset for help on using the changeset viewer.