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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 214ec25c was 214ec25c, checked in by Martin Decky <martin@…>, 15 years ago

use unsigned integers for exception and interrupt numbers

  • Property mode set to 100644
File size: 5.7 KB
RevLine 
[6b781c0]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>
[009474f]42#include <print.h>
[6b781c0]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;
[e762b43]51
[6b781c0]52 /* fault status is stored in CP15 register 5 */
53 asm volatile (
[e762b43]54 "mrc p15, 0, %[dummy], c5, c0, 0"
55 : [dummy] "=r" (fsu.dummy)
[6b781c0]56 );
[e762b43]57
[6b781c0]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
[e762b43]64 * fault)
[6b781c0]65 */
66static inline uintptr_t read_fault_address_register(void)
67{
68 uintptr_t ret;
[e762b43]69
[6b781c0]70 /* fault adress is stored in CP15 register 6 */
71 asm volatile (
[e762b43]72 "mrc p15, 0, %[ret], c6, c0, 0"
73 : [ret] "=r" (ret)
[6b781c0]74 );
[e762b43]75
[6b781c0]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
[e762b43]84 *
[6b781c0]85 */
86static inline bool is_load_store_instruction(instruction_t instr)
87{
88 /* load store immediate offset */
[e762b43]89 if (instr.type == 0x2)
[6b781c0]90 return true;
[e762b43]91
[6b781c0]92 /* load store register offset */
[e762b43]93 if ((instr.type == 0x3) && (instr.bit4 == 0))
[6b781c0]94 return true;
[e762b43]95
[6b781c0]96 /* load store multiple */
[e762b43]97 if (instr.type == 0x4)
[6b781c0]98 return true;
[e762b43]99
[6b781c0]100 /* oprocessor load/store */
[e762b43]101 if (instr.type == 0x6)
[6b781c0]102 return true;
[e762b43]103
[6b781c0]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 */
[e762b43]116 if ((instr.type == 0x0) &&
117 ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
118 (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
[6b781c0]119 return true;
[e762b43]120
[6b781c0]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) {
[f651e80]142 panic("page_fault - instruction does not access memory "
143 "(instr_code: %x, badvaddr:%x).", instr, badvaddr);
[6b781c0]144 return PF_ACCESS_EXEC;
145 }
146
147 /* load store instructions */
148 if (is_load_store_instruction(instr)) {
149 if (instr.access == 1) {
150 return PF_ACCESS_READ;
151 } else {
152 return PF_ACCESS_WRITE;
153 }
154 }
155
156 /* swap, swpb instruction */
157 if (is_swap_instruction(instr)) {
158 return PF_ACCESS_WRITE;
159 }
160
161 panic("page_fault - instruction doesn't access memory "
[f651e80]162 "(instr_code: %x, badvaddr:%x).", instr, badvaddr);
[6b781c0]163
164 return PF_ACCESS_EXEC;
165}
166
167/** Handles "data abort" exception (load or store at invalid address).
168 *
[214ec25c]169 * @param exc_no Exception number.
170 * @param istate CPU state when exception occured.
171 *
[6b781c0]172 */
[214ec25c]173void data_abort(unsigned int exc_no, istate_t *istate)
[6b781c0]174{
[cbd6545f]175 fault_status_t fsr __attribute__ ((unused)) =
176 read_fault_status_register();
[6b781c0]177 uintptr_t badvaddr = read_fault_address_register();
178
179 pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
180
181 int ret = as_page_fault(badvaddr, access, istate);
182
183 if (ret == AS_PF_FAULT) {
[c94841e]184 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
[6b781c0]185 print_istate(istate);
[00287cc]186 printf("page fault - pc: %x, va: %x, status: %x(%x), "
[6b781c0]187 "access:%d\n", istate->pc, badvaddr, fsr.status, fsr,
188 access);
[00287cc]189
[f651e80]190 panic("Page fault.");
[6b781c0]191 }
192}
193
194/** Handles "prefetch abort" exception (instruction couldn't be executed).
195 *
[214ec25c]196 * @param exc_no Exception number.
197 * @param istate CPU state when exception occured.
198 *
[6b781c0]199 */
[214ec25c]200void prefetch_abort(unsigned int exc_no, istate_t *istate)
[6b781c0]201{
202 int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
203
204 if (ret == AS_PF_FAULT) {
[00287cc]205 printf("prefetch_abort\n");
[6b781c0]206 print_istate(istate);
[f651e80]207 panic("page fault - prefetch_abort at address: %x.",
[6b781c0]208 istate->pc);
209 }
210}
211
212/** @}
213 */
Note: See TracBrowser for help on using the repository browser.