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

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

better inline assembler readability using the new symbolic syntax

  • 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/debug/print.h>
38#include <arch/mm/page_fault.h>
39#include <mm/as.h>
40#include <genarch/mm/page_pt.h>
41#include <arch.h>
42#include <interrupt.h>
[009474f]43#include <print.h>
[6b781c0]44
45/** Returns value stored in fault status register.
46 *
47 * @return Value stored in CP15 fault status register (FSR).
48 */
49static inline fault_status_t read_fault_status_register(void)
50{
51 fault_status_union_t fsu;
[e762b43]52
[6b781c0]53 /* fault status is stored in CP15 register 5 */
54 asm volatile (
[e762b43]55 "mrc p15, 0, %[dummy], c5, c0, 0"
56 : [dummy] "=r" (fsu.dummy)
[6b781c0]57 );
[e762b43]58
[6b781c0]59 return fsu.fs;
60}
61
62/** Returns FAR (fault address register) content.
63 *
64 * @return FAR (fault address register) content (address that caused a page
[e762b43]65 * fault)
[6b781c0]66 */
67static inline uintptr_t read_fault_address_register(void)
68{
69 uintptr_t ret;
[e762b43]70
[6b781c0]71 /* fault adress is stored in CP15 register 6 */
72 asm volatile (
[e762b43]73 "mrc p15, 0, %[ret], c6, c0, 0"
74 : [ret] "=r" (ret)
[6b781c0]75 );
[e762b43]76
[6b781c0]77 return ret;
78}
79
80/** Decides whether the instruction is load/store or not.
81 *
82 * @param instr Instruction
83 *
84 * @return true when instruction is load/store, false otherwise
[e762b43]85 *
[6b781c0]86 */
87static inline bool is_load_store_instruction(instruction_t instr)
88{
89 /* load store immediate offset */
[e762b43]90 if (instr.type == 0x2)
[6b781c0]91 return true;
[e762b43]92
[6b781c0]93 /* load store register offset */
[e762b43]94 if ((instr.type == 0x3) && (instr.bit4 == 0))
[6b781c0]95 return true;
[e762b43]96
[6b781c0]97 /* load store multiple */
[e762b43]98 if (instr.type == 0x4)
[6b781c0]99 return true;
[e762b43]100
[6b781c0]101 /* oprocessor load/store */
[e762b43]102 if (instr.type == 0x6)
[6b781c0]103 return true;
[e762b43]104
[6b781c0]105 return false;
106}
107
108/** Decides whether the instruction is swap or not.
109 *
110 * @param instr Instruction
111 *
112 * @return true when instruction is swap, false otherwise
113 */
114static inline bool is_swap_instruction(instruction_t instr)
115{
116 /* swap, swapb instruction */
[e762b43]117 if ((instr.type == 0x0) &&
118 ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
119 (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
[6b781c0]120 return true;
[e762b43]121
[6b781c0]122 return false;
123}
124
125/** Decides whether read or write into memory is requested.
126 *
127 * @param instr_addr Address of instruction which tries to access memory.
128 * @param badvaddr Virtual address the instruction tries to access.
129 *
130 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
131 * requested.
132 */
133static pf_access_t get_memory_access_type(uint32_t instr_addr,
134 uintptr_t badvaddr)
135{
136 instruction_union_t instr_union;
137 instr_union.pc = instr_addr;
138
139 instruction_t instr = *(instr_union.instr);
140
141 /* undefined instructions */
142 if (instr.condition == 0xf) {
[f651e80]143 panic("page_fault - instruction does not access memory "
144 "(instr_code: %x, badvaddr:%x).", instr, badvaddr);
[6b781c0]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 "
[f651e80]163 "(instr_code: %x, badvaddr:%x).", instr, badvaddr);
[6b781c0]164
165 return PF_ACCESS_EXEC;
166}
167
168/** Handles "data abort" exception (load or store at invalid address).
169 *
170 * @param exc_no Exception number.
171 * @param istate CPU state when exception occured.
172 */
173void data_abort(int exc_no, istate_t *istate)
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) {
184 print_istate(istate);
185 dprintf("page fault - pc: %x, va: %x, status: %x(%x), "
186 "access:%d\n", istate->pc, badvaddr, fsr.status, fsr,
187 access);
188
[f651e80]189 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
190 panic("Page fault.");
[6b781c0]191 }
192}
193
194/** Handles "prefetch abort" exception (instruction couldn't be executed).
195 *
196 * @param exc_no Exception number.
197 * @param istate CPU state when exception occured.
198 */
199void prefetch_abort(int exc_no, istate_t *istate)
200{
201 int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
202
203 if (ret == AS_PF_FAULT) {
204 dprintf("prefetch_abort\n");
205 print_istate(istate);
[f651e80]206 panic("page fault - prefetch_abort at address: %x.",
[6b781c0]207 istate->pc);
208 }
209}
210
211/** @}
212 */
Note: See TracBrowser for help on using the repository browser.