source: mainline/generic/src/mm/as.c@ 085d973

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

Cleanup o frame allocator.
Removed early_malloc & initial heap.
Will break ia64, ppc & sparc.
Added e820 table print.

  • 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/slab.h>
40#include <mm/tlb.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);
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 *) 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 = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
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 SET_PTL0_ADDRESS(as->page_table);
285 spinlock_unlock(&as->lock);
286 interrupts_restore(ipl);
287
288 /*
289 * Perform architecture-specific steps.
290 * (e.g. write ASID to hardware register etc.)
291 */
292 as_install_arch(as);
293
294 AS = as;
295}
296
297/** Compute flags for virtual address translation subsytem.
298 *
299 * The address space area must be locked.
300 * Interrupts must be disabled.
301 *
302 * @param a Address space area.
303 *
304 * @return Flags to be used in page_mapping_insert().
305 */
306int get_area_flags(as_area_t *a)
307{
308 int flags;
309
310 switch (a->type) {
311 case AS_AREA_TEXT:
312 flags = PAGE_EXEC | PAGE_READ | PAGE_USER | PAGE_PRESENT | PAGE_CACHEABLE;
313 break;
314 case AS_AREA_DATA:
315 case AS_AREA_STACK:
316 flags = PAGE_READ | PAGE_WRITE | PAGE_USER | PAGE_PRESENT | PAGE_CACHEABLE;
317 break;
318 default:
319 panic("unexpected as_area_type_t %d", a->type);
320 }
321
322 return flags;
323}
324
325/** Create page table.
326 *
327 * Depending on architecture, create either address space
328 * private or global page table.
329 *
330 * @param flags Flags saying whether the page table is for kernel address space.
331 *
332 * @return First entry of the page table.
333 */
334pte_t *page_table_create(int flags)
335{
336 ASSERT(as_operations);
337 ASSERT(as_operations->page_table_create);
338
339 return as_operations->page_table_create(flags);
340}
Note: See TracBrowser for help on using the repository browser.