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

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

arm32: Identify swap instructions.

  • Property mode set to 100644
File size: 7.2 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 fault status register.
45 *
46 * @return Value stored in CP15 fault status register (FSR).
47 */
48static 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 */
66static 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 */
86static 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 */
113static 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
124/** Decides whether read or write into memory is requested.
125 *
126 * @param instr_addr Address of instruction which tries to access memory.
127 * @param badvaddr Virtual address the instruction tries to access.
128 *
129 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
130 * requested.
131 */
132static pf_access_t get_memory_access_type(uint32_t instr_addr,
133 uintptr_t badvaddr)
134{
135 instruction_union_t instr_union;
136 instr_union.pc = instr_addr;
137
138 instruction_t instr = *(instr_union.instr);
139
140 /* undefined instructions */
141 if (instr.condition == 0xf) {
142 panic("page_fault - instruction does not access memory "
143 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
144 instr_union.pc, (void *) badvaddr);
145 return PF_ACCESS_EXEC;
146 }
147
148 /* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition
149 * A5.3 (PDF p. 206) */
150 static const struct {
151 uint32_t mask;
152 uint32_t value;
153 pf_access_t access;
154 } ls_inst[] = {
155 /* Store word/byte */
156 { 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/
157 { 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/
158 /* Load word/byte */
159 { 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR imm*/
160 { 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR reg*/
161 /* Store half-word/dual A5.2.8 */
162 { 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/
163 /* Load half-word/dual A5.2.8 */
164 { 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/
165 { 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/
166 /* Block data transfer, Store */
167 { 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */
168 { 0x0e100000, 0x08100000, PF_ACCESS_READ }, /* LDM variants */
169 /* Swap */
170 { 0x0fb00000, 0x01000000, PF_ACCESS_WRITE },
171 };
172 pf_access_t access = PF_ACCESS_UNKNOWN;
173 uint32_t inst = *(uint32_t*)instr_addr;
174 for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) {
175 if ((inst & ls_inst[i].mask) == ls_inst[i].value) {
176 if (access != PF_ACCESS_UNKNOWN)
177 printf("Double match: %x %u\n", inst, i);
178 access = ls_inst[i].access;
179 }
180 }
181
182 /* load store instructions */
183 if (is_load_store_instruction(instr)) {
184 if (instr.access == 1) {
185 if (access != PF_ACCESS_READ)
186 printf("MISMATCH READ(%u): %x\n", access, inst);
187 return PF_ACCESS_READ;
188 } else {
189 if (access != PF_ACCESS_WRITE)
190 printf("MISMATCH WRITE(%u): %x\n", access, inst);
191 return PF_ACCESS_WRITE;
192 }
193 }
194
195 /* swap, swpb instruction */
196 if (is_swap_instruction(instr)) {
197 if (access != PF_ACCESS_WRITE)
198 printf("MISMATCH WRITE(%u): %x\n", access, inst);
199 return PF_ACCESS_WRITE;
200 }
201
202 panic("page_fault - instruction doesn't access memory "
203 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
204 instr_union.pc, (void *) badvaddr);
205
206 return PF_ACCESS_EXEC;
207}
208
209/** Handles "data abort" exception (load or store at invalid address).
210 *
211 * @param exc_no Exception number.
212 * @param istate CPU state when exception occured.
213 *
214 */
215void data_abort(unsigned int exc_no, istate_t *istate)
216{
217 fault_status_t fsr __attribute__ ((unused)) =
218 read_fault_status_register();
219 uintptr_t badvaddr = read_fault_address_register();
220
221 pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
222
223 int ret = as_page_fault(badvaddr, access, istate);
224
225 if (ret == AS_PF_FAULT) {
226 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
227 panic_memtrap(istate, access, badvaddr, NULL);
228 }
229}
230
231/** Handles "prefetch abort" exception (instruction couldn't be executed).
232 *
233 * @param exc_no Exception number.
234 * @param istate CPU state when exception occured.
235 *
236 */
237void prefetch_abort(unsigned int exc_no, istate_t *istate)
238{
239 int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
240
241 if (ret == AS_PF_FAULT) {
242 fault_if_from_uspace(istate,
243 "Page fault - prefetch_abort: %#x.", istate->pc);
244 panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc, NULL);
245 }
246}
247
248/** @}
249 */
Note: See TracBrowser for help on using the repository browser.