source: mainline/generic/src/mm/as.c@ 5c9a08b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5c9a08b was 5c9a08b, checked in by Jakub Jermar <jakub@…>, 20 years ago

Move list and fifo data types to adt/.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * Copyright (C) 2001-2006 Jakub Jermar
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/*
30 * This file contains address space manipulation functions.
31 * Roughly speaking, this is a higher-level client of
32 * Virtual Address Translation (VAT) subsystem.
33 */
34
35#include <mm/as.h>
36#include <arch/mm/as.h>
37#include <mm/page.h>
38#include <mm/frame.h>
39#include <mm/tlb.h>
40#include <mm/heap.h>
41#include <arch/mm/page.h>
42#include <genarch/mm/page_pt.h>
43#include <mm/asid.h>
44#include <arch/mm/asid.h>
45#include <arch/types.h>
46#include <typedefs.h>
47#include <synch/spinlock.h>
48#include <config.h>
49#include <adt/list.h>
50#include <panic.h>
51#include <arch/asm.h>
52#include <debug.h>
53#include <memstr.h>
54#include <arch.h>
55#include <print.h>
56
57as_operations_t *as_operations = NULL;
58
59/** Kernel address space. */
60as_t *AS_KERNEL = NULL;
61
62static int get_area_flags(as_area_t *a);
63
64/** Initialize address space subsystem. */
65void as_init(void)
66{
67 as_arch_init();
68 AS_KERNEL = as_create(FLAG_AS_KERNEL | FLAG_AS_EARLYMALLOC);
69 if (!AS_KERNEL)
70 panic("can't create kernel address space\n");
71}
72
73/** Create address space.
74 *
75 * @param flags Flags that influence way in wich the address space is created.
76 */
77as_t *as_create(int flags)
78{
79 as_t *as;
80
81 if (flags & FLAG_AS_EARLYMALLOC)
82 as = (as_t *) early_malloc(sizeof(as_t));
83 else
84 as = (as_t *) malloc(sizeof(as_t));
85 if (as) {
86 list_initialize(&as->as_with_asid_link);
87 spinlock_initialize(&as->lock, "as_lock");
88 list_initialize(&as->as_area_head);
89
90 if (flags & FLAG_AS_KERNEL)
91 as->asid = ASID_KERNEL;
92 else
93 as->asid = ASID_INVALID;
94
95 as->page_table = page_table_create(flags);
96 }
97
98 return as;
99}
100
101/** Create address space area of common attributes.
102 *
103 * The created address space area is added to the target address space.
104 *
105 * @param as Target address space.
106 * @param type Type of area.
107 * @param size Size of area in multiples of PAGE_SIZE.
108 * @param base Base address of area.
109 *
110 * @return Address space area on success or NULL on failure.
111 */
112as_area_t *as_area_create(as_t *as, as_area_type_t type, size_t size, __address base)
113{
114 ipl_t ipl;
115 as_area_t *a;
116
117 if (base % PAGE_SIZE)
118 panic("addr not aligned to a page boundary");
119
120 ipl = interrupts_disable();
121 spinlock_lock(&as->lock);
122
123 /*
124 * TODO: test as_area which is to be created doesn't overlap with an existing one.
125 */
126
127 a = (as_area_t *) malloc(sizeof(as_area_t));
128 if (a) {
129 spinlock_initialize(&a->lock, "as_area_lock");
130
131 link_initialize(&a->link);
132 a->type = type;
133 a->size = size;
134 a->base = base;
135
136 list_append(&a->link, &as->as_area_head);
137 }
138
139 spinlock_unlock(&as->lock);
140 interrupts_restore(ipl);
141
142 return a;
143}
144
145/** Initialize mapping for one page of address space.
146 *
147 * This functions maps 'page' to 'frame' according
148 * to attributes of the address space area to
149 * wich 'page' belongs.
150 *
151 * @param a Target address space.
152 * @param page Virtual page within the area.
153 * @param frame Physical frame to which page will be mapped.
154 */
155void as_set_mapping(as_t *as, __address page, __address frame)
156{
157 as_area_t *a, *area = NULL;
158 link_t *cur;
159 ipl_t ipl;
160
161 ipl = interrupts_disable();
162 spinlock_lock(&as->lock);
163
164 /*
165 * First, try locate an area.
166 */
167 for (cur = as->as_area_head.next; cur != &as->as_area_head; cur = cur->next) {
168 a = list_get_instance(cur, as_area_t, link);
169 spinlock_lock(&a->lock);
170
171 if ((page >= a->base) && (page < a->base + a->size * PAGE_SIZE)) {
172 area = a;
173 break;
174 }
175
176 spinlock_unlock(&a->lock);
177 }
178
179 if (!area) {
180 panic("page not part of any as_area\n");
181 }
182
183 /*
184 * Note: area->lock is held.
185 */
186
187 page_mapping_insert(as, page, frame, get_area_flags(area));
188
189 spinlock_unlock(&area->lock);
190 spinlock_unlock(&as->lock);
191 interrupts_restore(ipl);
192}
193
194/** Handle page fault within the current address space.
195 *
196 * This is the high-level page fault handler.
197 * Interrupts are assumed disabled.
198 *
199 * @param page Faulting page.
200 *
201 * @return 0 on page fault, 1 on success.
202 */
203int as_page_fault(__address page)
204{
205 link_t *cur;
206 as_area_t *a, *area = NULL;
207 __address frame;
208
209 ASSERT(AS);
210 spinlock_lock(&AS->lock);
211
212 /*
213 * Search this areas of this address space for presence of 'page'.
214 */
215 for (cur = AS->as_area_head.next; cur != &AS->as_area_head; cur = cur->next) {
216 a = list_get_instance(cur, as_area_t, link);
217 spinlock_lock(&a->lock);
218
219 if ((page >= a->base) && (page < a->base + a->size * PAGE_SIZE)) {
220
221 /*
222 * We found the area containing 'page'.
223 * TODO: access checking
224 */
225 area = a;
226 break;
227 }
228
229 spinlock_unlock(&a->lock);
230 }
231
232 if (!area) {
233 /*
234 * No area contained mapping for 'page'.
235 * Signal page fault to low-level handler.
236 */
237 spinlock_unlock(&AS->lock);
238 return 0;
239 }
240
241 /*
242 * Note: area->lock is held.
243 */
244
245 /*
246 * In general, there can be several reasons that
247 * can have caused this fault.
248 *
249 * - non-existent mapping: the area is a scratch
250 * area (e.g. stack) and so far has not been
251 * allocated a frame for the faulting page
252 *
253 * - non-present mapping: another possibility,
254 * currently not implemented, would be frame
255 * reuse; when this becomes a possibility,
256 * do not forget to distinguish between
257 * the different causes
258 */
259 frame = frame_alloc(ONE_FRAME, 0);
260 memsetb(PA2KA(frame), FRAME_SIZE, 0);
261
262 /*
263 * Map 'page' to 'frame'.
264 * Note that TLB shootdown is not attempted as only new information is being
265 * inserted into page tables.
266 */
267 page_mapping_insert(AS, page, frame, get_area_flags(area));
268
269 spinlock_unlock(&area->lock);
270 spinlock_unlock(&AS->lock);
271
272 return 1;
273}
274
275/** Install address space on CPU.
276 *
277 * @param as Address space.
278 */
279void as_install(as_t *as)
280{
281 ipl_t ipl;
282
283 asid_install(as);
284
285 ipl = interrupts_disable();
286 spinlock_lock(&as->lock);
287 ASSERT(as->page_table);
288 SET_PTL0_ADDRESS(as->page_table);
289 spinlock_unlock(&as->lock);
290 interrupts_restore(ipl);
291
292 /*
293 * Perform architecture-specific steps.
294 * (e.g. write ASID to hardware register etc.)
295 */
296 as_install_arch(as);
297
298 AS = as;
299}
300
301/** Compute flags for virtual address translation subsytem.
302 *
303 * The address space area must be locked.
304 * Interrupts must be disabled.
305 *
306 * @param a Address space area.
307 *
308 * @return Flags to be used in page_mapping_insert().
309 */
310int get_area_flags(as_area_t *a)
311{
312 int flags;
313
314 switch (a->type) {
315 case AS_AREA_TEXT:
316 flags = PAGE_EXEC | PAGE_READ | PAGE_USER | PAGE_PRESENT | PAGE_CACHEABLE;
317 break;
318 case AS_AREA_DATA:
319 case AS_AREA_STACK:
320 flags = PAGE_READ | PAGE_WRITE | PAGE_USER | PAGE_PRESENT | PAGE_CACHEABLE;
321 break;
322 default:
323 panic("unexpected as_area_type_t %d", a->type);
324 }
325
326 return flags;
327}
328
329/** Create page table.
330 *
331 * Depending on architecture, create either address space
332 * private or global page table.
333 *
334 * @param flags Flags saying whether the page table is for kernel address space.
335 *
336 * @return First entry of the page table.
337 */
338pte_t *page_table_create(int flags)
339{
340 ASSERT(as_operations);
341 ASSERT(as_operations->page_table_create);
342
343 return as_operations->page_table_create(flags);
344}
Note: See TracBrowser for help on using the repository browser.