source: mainline/generic/src/mm/as.c@ c352c2e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c352c2e was c352c2e, checked in by Ondrej Palkovsky <ondrap@…>, 19 years ago

Implemented malloc/free as SLABs.

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