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

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

Changed malloc to include second parameter and documented
recommended usage.
Added zone merging, made ia32 & amd64 to merge found zones.

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