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

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

arm32: Print opcode when we say it's opcode.

  • Property mode set to 100644
File size: 5.7 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 *(uint32_t*)instr_union.instr, (void *) badvaddr);
145 return PF_ACCESS_EXEC;
146 }
147
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;
154 }
155 }
156
157 /* swap, swpb instruction */
158 if (is_swap_instruction(instr)) {
159 return PF_ACCESS_WRITE;
160 }
161
162 panic("page_fault - instruction doesn't access memory "
163 "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
164 *(uint32_t*)instr_union.instr, (void *) badvaddr);
165
166 return PF_ACCESS_EXEC;
167}
168
169/** Handles "data abort" exception (load or store at invalid address).
170 *
171 * @param exc_no Exception number.
172 * @param istate CPU state when exception occured.
173 *
174 */
175void data_abort(unsigned int exc_no, istate_t *istate)
176{
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 }
189}
190
191/** Handles "prefetch abort" exception (instruction couldn't be executed).
192 *
193 * @param exc_no Exception number.
194 * @param istate CPU state when exception occured.
195 *
196 */
197void prefetch_abort(unsigned int exc_no, istate_t *istate)
198{
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 }
206}
207
208/** @}
209 */
Note: See TracBrowser for help on using the repository browser.