source: mainline/kernel/arch/arm32/src/mm/page_fault.c@ 3451129

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3451129 was 3451129, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

Mainline changes.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * Copyright (c) 2007 Pavel Jancik, Michal Kebrt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup arm32mm
30 * @{
31 */
32/** @file
33 * @brief Page fault related functions.
34 */
35#include <panic.h>
36#include <arch/exception.h>
37#include <arch/mm/page_fault.h>
38#include <mm/as.h>
39#include <genarch/mm/page_pt.h>
40#include <arch.h>
41#include <interrupt.h>
42#include <print.h>
43
44/** Returns value stored in comnbined/data fault status register.
45 *
46 * @return Value stored in CP15 fault status register (FSR).
47 *
48 * "VMSAv6 added a fifth fault status bit (bit[10]) to both the IFSR and DFSR.
49 * It is IMPLEMENTATION DEFINED how this bit is encoded in earlier versions of
50 * the architecture. A write flag (bit[11] of the DFSR) has also been
51 * introduced."
52 * ARM Architecture Reference Manual version i ch. B4.6 (PDF p. 719)
53 *
54 * See ch. B4.9.6 for location of data/instruction FSR.
55 *
56 */
57static inline fault_status_t read_data_fault_status_register(void)
58{
59 fault_status_t fsu;
60
61 /* Combined/Data fault status is stored in CP15 register 5, c0. */
62 asm volatile (
63 "mrc p15, 0, %[dummy], c5, c0, 0"
64 : [dummy] "=r" (fsu.raw)
65 );
66
67 return fsu;
68}
69
70/** Returns DFAR (fault address register) content.
71 *
72 * This register is equivalent to FAR on pre armv6 machines.
73 *
74 * @return DFAR (fault address register) content (address that caused a page
75 * fault)
76 */
77static inline uintptr_t read_data_fault_address_register(void)
78{
79 uintptr_t ret;
80
81 /* fault adress is stored in CP15 register 6 */
82 asm volatile (
83 "mrc p15, 0, %[ret], c6, c0, 0"
84 : [ret] "=r" (ret)
85 );
86
87 return ret;
88}
89
90#if defined(PROCESSOR_armv4) | defined(PROCESSOR_armv5)
91/** Decides whether read or write into memory is requested.
92 *
93 * @param instr_addr Address of instruction which tries to access memory.
94 * @param badvaddr Virtual address the instruction tries to access.
95 *
96 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
97 * requested.
98 */
99static pf_access_t get_memory_access_type(uint32_t instr_addr,
100 uintptr_t badvaddr)
101{
102 instruction_union_t instr_union;
103 instr_union.pc = instr_addr;
104
105 instruction_t instr = *(instr_union.instr);
106
107 /* undefined instructions */
108 if (instr.condition == 0xf) {
109 panic("page_fault - instruction does not access memory "
110 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
111 *(uint32_t*)instr_union.instr, (void *) badvaddr);
112 return PF_ACCESS_EXEC;
113 }
114
115 /* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition
116 * A5.3 (PDF p. 206) */
117 static const struct {
118 uint32_t mask;
119 uint32_t value;
120 pf_access_t access;
121 } ls_inst[] = {
122 /* Store word/byte */
123 { 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/
124 { 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/
125 /* Load word/byte */
126 { 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR(B) imm*/
127 { 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR(B) reg*/
128 /* Store half-word/dual A5.2.8 */
129 { 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/
130 /* Load half-word/dual A5.2.8 */
131 { 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/
132 { 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/
133 /* Block data transfer, Store */
134 { 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */
135 { 0x0e100000, 0x08100000, PF_ACCESS_READ }, /* LDM variants */
136 /* Swap */
137 { 0x0fb00000, 0x01000000, PF_ACCESS_WRITE },
138 };
139 const uint32_t inst = *(uint32_t*)instr_addr;
140 for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) {
141 if ((inst & ls_inst[i].mask) == ls_inst[i].value) {
142 return ls_inst[i].access;
143 }
144 }
145
146 panic("page_fault - instruction doesn't access memory "
147 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
148 inst, (void *) badvaddr);
149}
150#endif
151
152/** Handles "data abort" exception (load or store at invalid address).
153 *
154 * @param exc_no Exception number.
155 * @param istate CPU state when exception occured.
156 *
157 */
158void data_abort(unsigned int exc_no, istate_t *istate)
159{
160 uintptr_t badvaddr = read_data_fault_address_register();
161
162#if defined(PROCESSOR_armv6) | defined(PROCESSOR_armv7_a)
163 fault_status_t fsr = read_data_fault_status_register();
164 const pf_access_t access =
165 fsr.data.wr ? PF_ACCESS_WRITE : PF_ACCESS_READ;
166#elif defined(PROCESSOR_armv4) | defined(PROCESSOR_armv5)
167 const pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
168#else
169#error "Unsupported architecture"
170#endif
171 int ret = as_page_fault(badvaddr, access, istate);
172
173 if (ret == AS_PF_FAULT) {
174 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
175 panic_memtrap(istate, access, badvaddr, NULL);
176 }
177}
178
179/** Handles "prefetch abort" exception (instruction couldn't be executed).
180 *
181 * @param exc_no Exception number.
182 * @param istate CPU state when exception occured.
183 *
184 */
185void prefetch_abort(unsigned int exc_no, istate_t *istate)
186{
187 /* NOTE: We should use IFAR and IFSR here. */
188 int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
189
190 if (ret == AS_PF_FAULT) {
191 fault_if_from_uspace(istate,
192 "Page fault - prefetch_abort: %#x.", istate->pc);
193 panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc, NULL);
194 }
195}
196
197/** @}
198 */
Note: See TracBrowser for help on using the repository browser.