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

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

arm32: Use FSR for data aborts on armv6+.

  • Property mode set to 100644
File size: 6.5 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/** Decides whether the instruction is load/store or not.
91 *
92 * @param instr Instruction
93 *
94 * @return true when instruction is load/store, false otherwise
95 *
96 */
97static inline bool is_load_store_instruction(instruction_t instr)
98{
99 /* load store immediate offset */
100 if (instr.type == 0x2)
101 return true;
102
103 /* load store register offset */
104 if ((instr.type == 0x3) && (instr.bit4 == 0))
105 return true;
106
107 /* load store multiple */
108 if (instr.type == 0x4)
109 return true;
110
111 /* oprocessor load/store */
112 if (instr.type == 0x6)
113 return true;
114
115 return false;
116}
117
118/** Decides whether the instruction is swap or not.
119 *
120 * @param instr Instruction
121 *
122 * @return true when instruction is swap, false otherwise
123 */
124static inline bool is_swap_instruction(instruction_t instr)
125{
126 /* swap, swapb instruction */
127 if ((instr.type == 0x0) &&
128 ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
129 (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
130 return true;
131
132 return false;
133}
134
135#if defined(PROCESSOR_armv4) | defined(PROCESSOR_armv5)
136/** Decides whether read or write into memory is requested.
137 *
138 * @param instr_addr Address of instruction which tries to access memory.
139 * @param badvaddr Virtual address the instruction tries to access.
140 *
141 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
142 * requested.
143 */
144static pf_access_t get_memory_access_type(uint32_t instr_addr,
145 uintptr_t badvaddr)
146{
147 instruction_union_t instr_union;
148 instr_union.pc = instr_addr;
149
150 instruction_t instr = *(instr_union.instr);
151
152 /* undefined instructions */
153 if (instr.condition == 0xf) {
154 panic("page_fault - instruction does not access memory "
155 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
156 *(uint32_t*)instr_union.instr, (void *) badvaddr);
157 return PF_ACCESS_EXEC;
158 }
159
160 /* load store instructions */
161 if (is_load_store_instruction(instr)) {
162 if (instr.access == 1) {
163 return PF_ACCESS_READ;
164 } else {
165 return PF_ACCESS_WRITE;
166 }
167 }
168
169 /* swap, swpb instruction */
170 if (is_swap_instruction(instr)) {
171 return PF_ACCESS_WRITE;
172 }
173
174 panic("page_fault - instruction doesn't access memory "
175 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
176 *(uint32_t*)instr_union.instr, (void *) badvaddr);
177
178 return PF_ACCESS_EXEC;
179}
180#endif
181
182/** Handles "data abort" exception (load or store at invalid address).
183 *
184 * @param exc_no Exception number.
185 * @param istate CPU state when exception occured.
186 *
187 */
188void data_abort(unsigned int exc_no, istate_t *istate)
189{
190 uintptr_t badvaddr = read_data_fault_address_register();
191
192#if defined(PROCESSOR_armv6) | defined(PROCESSOR_armv7_a)
193 fault_status_t fsr = read_data_fault_status_register();
194 const pf_access_t access =
195 fsr.data.wr ? PF_ACCESS_WRITE : PF_ACCESS_READ;
196#elif defined(PROCESSOR_armv4) | defined(PROCESSOR_armv5)
197 const pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
198#else
199#error "Unsupported architecture"
200#endif
201 int ret = as_page_fault(badvaddr, access, istate);
202
203 if (ret == AS_PF_FAULT) {
204 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
205 panic_memtrap(istate, access, badvaddr, NULL);
206 }
207}
208
209/** Handles "prefetch abort" exception (instruction couldn't be executed).
210 *
211 * @param exc_no Exception number.
212 * @param istate CPU state when exception occured.
213 *
214 */
215void prefetch_abort(unsigned int exc_no, istate_t *istate)
216{
217 /* NOTE: We should use IFAR and IFSR here. */
218 int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
219
220 if (ret == AS_PF_FAULT) {
221 fault_if_from_uspace(istate,
222 "Page fault - prefetch_abort: %#x.", istate->pc);
223 panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc, NULL);
224 }
225}
226
227/** @}
228 */
Note: See TracBrowser for help on using the repository browser.