root / prex-0.9.0 / sys / mem / vm_nommu.c @ 03e9c04a
History | View | Annotate | Download (13.9 KB)
1 |
/*-
|
---|---|
2 |
* Copyright (c) 2005-2009, Kohsuke Ohtani
|
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 |
* 1. Redistributions of source code must retain the above copyright
|
9 |
* notice, this list of conditions and the following disclaimer.
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright
|
11 |
* notice, this list of conditions and the following disclaimer in the
|
12 |
* documentation and/or other materials provided with the distribution.
|
13 |
* 3. Neither the name of the author nor the names of any co-contributors
|
14 |
* may be used to endorse or promote products derived from this software
|
15 |
* without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
27 |
* SUCH DAMAGE.
|
28 |
*/
|
29 |
|
30 |
/*
|
31 |
* vm_nommu.c - virtual memory alloctor for no MMU systems
|
32 |
*/
|
33 |
|
34 |
/*
|
35 |
* When the platform does not support memory management unit (MMU)
|
36 |
* all virtual memories are mapped to the physical memory. So, the
|
37 |
* memory space is shared among all tasks and kernel.
|
38 |
*
|
39 |
* Important: The lists of segments are not sorted by address.
|
40 |
*/
|
41 |
|
42 |
#include <kernel.h> |
43 |
#include <kmem.h> |
44 |
#include <thread.h> |
45 |
#include <page.h> |
46 |
#include <task.h> |
47 |
#include <sched.h> |
48 |
#include <vm.h> |
49 |
|
50 |
/* forward declarations */
|
51 |
static void seg_init(struct seg *); |
52 |
static struct seg *seg_create(struct seg *, vaddr_t, size_t); |
53 |
static void seg_delete(struct seg *, struct seg *); |
54 |
static struct seg *seg_lookup(struct seg *, vaddr_t, size_t); |
55 |
static struct seg *seg_alloc(struct seg *, size_t); |
56 |
static void seg_free(struct seg *, struct seg *); |
57 |
static struct seg *seg_reserve(struct seg *, vaddr_t, size_t); |
58 |
static int do_allocate(vm_map_t, void **, size_t, int); |
59 |
static int do_free(vm_map_t, void *); |
60 |
static int do_attribute(vm_map_t, void *, int); |
61 |
static int do_map(vm_map_t, void *, size_t, void **); |
62 |
|
63 |
|
64 |
static struct vm_map kernel_map; /* vm mapping for kernel */ |
65 |
|
66 |
/**
|
67 |
* vm_allocate - allocate zero-filled memory for specified address
|
68 |
*
|
69 |
* If "anywhere" argument is true, the "addr" argument will be
|
70 |
* ignored. In this case, the address of free space will be
|
71 |
* found automatically.
|
72 |
*
|
73 |
* The allocated area has writable, user-access attribute by
|
74 |
* default. The "addr" and "size" argument will be adjusted
|
75 |
* to page boundary.
|
76 |
*/
|
77 |
int
|
78 |
vm_allocate(task_t task, void **addr, size_t size, int anywhere) |
79 |
{ |
80 |
int error;
|
81 |
void *uaddr;
|
82 |
|
83 |
sched_lock(); |
84 |
|
85 |
if (!task_valid(task)) {
|
86 |
sched_unlock(); |
87 |
return ESRCH;
|
88 |
} |
89 |
if (task != curtask && !task_capable(CAP_EXTMEM)) {
|
90 |
sched_unlock(); |
91 |
return EPERM;
|
92 |
} |
93 |
if (copyin(addr, &uaddr, sizeof(*addr))) { |
94 |
sched_unlock(); |
95 |
return EFAULT;
|
96 |
} |
97 |
if (anywhere == 0 && !user_area(*addr)) { |
98 |
sched_unlock(); |
99 |
return EACCES;
|
100 |
} |
101 |
|
102 |
error = do_allocate(task->map, &uaddr, size, anywhere); |
103 |
if (!error) {
|
104 |
if (copyout(&uaddr, addr, sizeof(uaddr))) |
105 |
error = EFAULT; |
106 |
} |
107 |
sched_unlock(); |
108 |
return error;
|
109 |
} |
110 |
|
111 |
static int |
112 |
do_allocate(vm_map_t map, void **addr, size_t size, int anywhere) |
113 |
{ |
114 |
struct seg *seg;
|
115 |
vaddr_t start, end; |
116 |
|
117 |
if (size == 0) |
118 |
return EINVAL;
|
119 |
if (map->total + size >= MAXMEM)
|
120 |
return ENOMEM;
|
121 |
|
122 |
/*
|
123 |
* Allocate segment, and reserve pages for it.
|
124 |
*/
|
125 |
if (anywhere) {
|
126 |
size = round_page(size); |
127 |
if ((seg = seg_alloc(&map->head, size)) == NULL) |
128 |
return ENOMEM;
|
129 |
start = seg->addr; |
130 |
} else {
|
131 |
start = trunc_page((vaddr_t)*addr); |
132 |
end = round_page(start + size); |
133 |
size = (size_t)(end - start); |
134 |
|
135 |
if ((seg = seg_reserve(&map->head, start, size)) == NULL) |
136 |
return ENOMEM;
|
137 |
} |
138 |
seg->flags = SEG_READ | SEG_WRITE; |
139 |
|
140 |
/* Zero fill */
|
141 |
memset((void *)start, 0, size); |
142 |
*addr = (void *)seg->addr;
|
143 |
map->total += size; |
144 |
return 0; |
145 |
} |
146 |
|
147 |
/*
|
148 |
* Deallocate memory segment for specified address.
|
149 |
*
|
150 |
* The "addr" argument points to a memory segment previously
|
151 |
* allocated through a call to vm_allocate() or vm_map(). The
|
152 |
* number of bytes freed is the number of bytes of the
|
153 |
* allocated segment. If one of the segment of previous and
|
154 |
* next are free, it combines with them, and larger free
|
155 |
* segment is created.
|
156 |
*/
|
157 |
int
|
158 |
vm_free(task_t task, void *addr)
|
159 |
{ |
160 |
int error;
|
161 |
|
162 |
sched_lock(); |
163 |
if (!task_valid(task)) {
|
164 |
sched_unlock(); |
165 |
return ESRCH;
|
166 |
} |
167 |
if (task != curtask && !task_capable(CAP_EXTMEM)) {
|
168 |
sched_unlock(); |
169 |
return EPERM;
|
170 |
} |
171 |
if (!user_area(addr)) {
|
172 |
sched_unlock(); |
173 |
return EFAULT;
|
174 |
} |
175 |
|
176 |
error = do_free(task->map, addr); |
177 |
|
178 |
sched_unlock(); |
179 |
return error;
|
180 |
} |
181 |
|
182 |
static int |
183 |
do_free(vm_map_t map, void *addr)
|
184 |
{ |
185 |
struct seg *seg;
|
186 |
vaddr_t va; |
187 |
|
188 |
va = trunc_page((vaddr_t)addr); |
189 |
|
190 |
/*
|
191 |
* Find the target segment.
|
192 |
*/
|
193 |
seg = seg_lookup(&map->head, va, 1);
|
194 |
if (seg == NULL || seg->addr != va || (seg->flags & SEG_FREE)) |
195 |
return EINVAL; /* not allocated */ |
196 |
|
197 |
/*
|
198 |
* Relinquish use of the page if it is not shared and mapped.
|
199 |
*/
|
200 |
if (!(seg->flags & SEG_SHARED) && !(seg->flags & SEG_MAPPED))
|
201 |
page_free(seg->phys, seg->size); |
202 |
|
203 |
map->total -= seg->size; |
204 |
seg_free(&map->head, seg); |
205 |
|
206 |
return 0; |
207 |
} |
208 |
|
209 |
/*
|
210 |
* Change attribute of specified virtual address.
|
211 |
*
|
212 |
* The "addr" argument points to a memory segment previously
|
213 |
* allocated through a call to vm_allocate(). The attribute
|
214 |
* type can be chosen a combination of PROT_READ, PROT_WRITE.
|
215 |
* Note: PROT_EXEC is not supported, yet.
|
216 |
*/
|
217 |
int
|
218 |
vm_attribute(task_t task, void *addr, int attr) |
219 |
{ |
220 |
int error;
|
221 |
|
222 |
sched_lock(); |
223 |
if (attr == 0 || attr & ~(PROT_READ | PROT_WRITE)) { |
224 |
sched_unlock(); |
225 |
return EINVAL;
|
226 |
} |
227 |
if (!task_valid(task)) {
|
228 |
sched_unlock(); |
229 |
return ESRCH;
|
230 |
} |
231 |
if (task != curtask && !task_capable(CAP_EXTMEM)) {
|
232 |
sched_unlock(); |
233 |
return EPERM;
|
234 |
} |
235 |
if (!user_area(addr)) {
|
236 |
sched_unlock(); |
237 |
return EFAULT;
|
238 |
} |
239 |
|
240 |
error = do_attribute(task->map, addr, attr); |
241 |
|
242 |
sched_unlock(); |
243 |
return error;
|
244 |
} |
245 |
|
246 |
static int |
247 |
do_attribute(vm_map_t map, void *addr, int attr) |
248 |
{ |
249 |
struct seg *seg;
|
250 |
int new_flags = 0; |
251 |
vaddr_t va; |
252 |
|
253 |
va = trunc_page((vaddr_t)addr); |
254 |
|
255 |
/*
|
256 |
* Find the target segment.
|
257 |
*/
|
258 |
seg = seg_lookup(&map->head, va, 1);
|
259 |
if (seg == NULL || seg->addr != va || (seg->flags & SEG_FREE)) { |
260 |
return EINVAL; /* not allocated */ |
261 |
} |
262 |
/*
|
263 |
* The attribute of the mapped or shared segment can not be changed.
|
264 |
*/
|
265 |
if ((seg->flags & SEG_MAPPED) || (seg->flags & SEG_SHARED))
|
266 |
return EINVAL;
|
267 |
|
268 |
/*
|
269 |
* Check new and old flag.
|
270 |
*/
|
271 |
if (seg->flags & SEG_WRITE) {
|
272 |
if (!(attr & PROT_WRITE))
|
273 |
new_flags = SEG_READ; |
274 |
} else {
|
275 |
if (attr & PROT_WRITE)
|
276 |
new_flags = SEG_READ | SEG_WRITE; |
277 |
} |
278 |
if (new_flags == 0) |
279 |
return 0; /* same attribute */ |
280 |
seg->flags = new_flags; |
281 |
return 0; |
282 |
} |
283 |
|
284 |
/**
|
285 |
* vm_map - map another task's memory to current task.
|
286 |
*
|
287 |
* Note: This routine does not support mapping to the specific
|
288 |
* address.
|
289 |
*/
|
290 |
int
|
291 |
vm_map(task_t target, void *addr, size_t size, void **alloc) |
292 |
{ |
293 |
int error;
|
294 |
|
295 |
sched_lock(); |
296 |
if (!task_valid(target)) {
|
297 |
sched_unlock(); |
298 |
return ESRCH;
|
299 |
} |
300 |
if (target == curtask) {
|
301 |
sched_unlock(); |
302 |
return EINVAL;
|
303 |
} |
304 |
if (!task_capable(CAP_EXTMEM)) {
|
305 |
sched_unlock(); |
306 |
return EPERM;
|
307 |
} |
308 |
if (!user_area(addr)) {
|
309 |
sched_unlock(); |
310 |
return EFAULT;
|
311 |
} |
312 |
|
313 |
error = do_map(target->map, addr, size, alloc); |
314 |
|
315 |
sched_unlock(); |
316 |
return error;
|
317 |
} |
318 |
|
319 |
static int |
320 |
do_map(vm_map_t map, void *addr, size_t size, void **alloc) |
321 |
{ |
322 |
struct seg *seg, *tgt;
|
323 |
vm_map_t curmap; |
324 |
vaddr_t start, end; |
325 |
void *tmp;
|
326 |
|
327 |
if (size == 0) |
328 |
return EINVAL;
|
329 |
if (map->total + size >= MAXMEM)
|
330 |
return ENOMEM;
|
331 |
|
332 |
/* check fault */
|
333 |
tmp = NULL;
|
334 |
if (copyout(&tmp, alloc, sizeof(tmp))) |
335 |
return EFAULT;
|
336 |
|
337 |
start = trunc_page((vaddr_t)addr); |
338 |
end = round_page((vaddr_t)addr + size); |
339 |
size = (size_t)(end - start); |
340 |
|
341 |
/*
|
342 |
* Find the segment that includes target address
|
343 |
*/
|
344 |
seg = seg_lookup(&map->head, start, size); |
345 |
if (seg == NULL || (seg->flags & SEG_FREE)) |
346 |
return EINVAL; /* not allocated */ |
347 |
tgt = seg; |
348 |
|
349 |
/*
|
350 |
* Create new segment to map
|
351 |
*/
|
352 |
curmap = curtask->map; |
353 |
if ((seg = seg_create(&curmap->head, start, size)) == NULL) |
354 |
return ENOMEM;
|
355 |
seg->flags = tgt->flags | SEG_MAPPED; |
356 |
|
357 |
copyout(&addr, alloc, sizeof(addr));
|
358 |
|
359 |
curmap->total += size; |
360 |
return 0; |
361 |
} |
362 |
|
363 |
/*
|
364 |
* Create new virtual memory space.
|
365 |
* No memory is inherited.
|
366 |
* Must be called with scheduler locked.
|
367 |
*/
|
368 |
vm_map_t |
369 |
vm_create(void)
|
370 |
{ |
371 |
struct vm_map *map;
|
372 |
|
373 |
/* Allocate new map structure */
|
374 |
if ((map = kmem_alloc(sizeof(*map))) == NULL) |
375 |
return NULL; |
376 |
|
377 |
map->refcnt = 1;
|
378 |
map->total = 0;
|
379 |
|
380 |
seg_init(&map->head); |
381 |
return map;
|
382 |
} |
383 |
|
384 |
/*
|
385 |
* Terminate specified virtual memory space.
|
386 |
* This is called when task is terminated.
|
387 |
*/
|
388 |
void
|
389 |
vm_terminate(vm_map_t map) |
390 |
{ |
391 |
struct seg *seg, *tmp;
|
392 |
|
393 |
if (--map->refcnt > 0) |
394 |
return;
|
395 |
|
396 |
sched_lock(); |
397 |
seg = &map->head; |
398 |
do {
|
399 |
if (seg->flags != SEG_FREE) {
|
400 |
/* Free segment if it is not shared and mapped */
|
401 |
if (!(seg->flags & SEG_SHARED) &&
|
402 |
!(seg->flags & SEG_MAPPED)) { |
403 |
page_free(seg->phys, seg->size); |
404 |
} |
405 |
} |
406 |
tmp = seg; |
407 |
seg = seg->next; |
408 |
seg_delete(&map->head, tmp); |
409 |
} while (seg != &map->head);
|
410 |
|
411 |
kmem_free(map); |
412 |
sched_unlock(); |
413 |
} |
414 |
|
415 |
/*
|
416 |
* Duplicate specified virtual memory space.
|
417 |
*/
|
418 |
vm_map_t |
419 |
vm_dup(vm_map_t org_map) |
420 |
{ |
421 |
/*
|
422 |
* This function is not supported with no MMU system.
|
423 |
*/
|
424 |
return NULL; |
425 |
} |
426 |
|
427 |
/*
|
428 |
* Switch VM mapping.
|
429 |
*/
|
430 |
void
|
431 |
vm_switch(vm_map_t map) |
432 |
{ |
433 |
} |
434 |
|
435 |
/*
|
436 |
* Increment reference count of VM mapping.
|
437 |
*/
|
438 |
int
|
439 |
vm_reference(vm_map_t map) |
440 |
{ |
441 |
|
442 |
map->refcnt++; |
443 |
return 0; |
444 |
} |
445 |
|
446 |
/*
|
447 |
* Setup task image for boot task. (NOMMU version)
|
448 |
* Return 0 on success, errno on failure.
|
449 |
*
|
450 |
* Note: We assume that the task images are already copied to
|
451 |
* the proper address by a boot loader.
|
452 |
*/
|
453 |
int
|
454 |
vm_load(vm_map_t map, struct module *mod, void **stack) |
455 |
{ |
456 |
struct seg *seg;
|
457 |
vaddr_t base, start, end; |
458 |
size_t size; |
459 |
|
460 |
DPRINTF(("Loading task:\'%s\'\n", mod->name));
|
461 |
|
462 |
/*
|
463 |
* Reserve text & data area
|
464 |
*/
|
465 |
base = mod->text; |
466 |
size = mod->textsz + mod->datasz + mod->bsssz; |
467 |
if (size == 0) |
468 |
return EINVAL;
|
469 |
|
470 |
start = trunc_page(base); |
471 |
end = round_page(start + size); |
472 |
size = (size_t)(end - start); |
473 |
|
474 |
if ((seg = seg_create(&map->head, start, size)) == NULL) |
475 |
return ENOMEM;
|
476 |
|
477 |
seg->flags = SEG_READ | SEG_WRITE; |
478 |
|
479 |
if (mod->bsssz != 0) |
480 |
memset((void *)(mod->data + mod->datasz), 0, mod->bsssz); |
481 |
|
482 |
/*
|
483 |
* Create stack
|
484 |
*/
|
485 |
return do_allocate(map, stack, DFLSTKSZ, 1); |
486 |
} |
487 |
|
488 |
/*
|
489 |
* Translate virtual address of current task to physical address.
|
490 |
* Returns physical address on success, or NULL if no mapped memory.
|
491 |
*/
|
492 |
paddr_t |
493 |
vm_translate(vaddr_t addr, size_t size) |
494 |
{ |
495 |
|
496 |
return (paddr_t)addr;
|
497 |
} |
498 |
|
499 |
int
|
500 |
vm_info(struct vminfo *info)
|
501 |
{ |
502 |
u_long target = info->cookie; |
503 |
task_t task = info->task; |
504 |
u_long i; |
505 |
vm_map_t map; |
506 |
struct seg *seg;
|
507 |
|
508 |
sched_lock(); |
509 |
if (!task_valid(task)) {
|
510 |
sched_unlock(); |
511 |
return ESRCH;
|
512 |
} |
513 |
map = task->map; |
514 |
seg = &map->head; |
515 |
i = 0;
|
516 |
do {
|
517 |
if (i++ == target) {
|
518 |
info->cookie = i; |
519 |
info->virt = seg->addr; |
520 |
info->size = seg->size; |
521 |
info->flags = seg->flags; |
522 |
info->phys = seg->phys; |
523 |
sched_unlock(); |
524 |
return 0; |
525 |
} |
526 |
seg = seg->next; |
527 |
} while (seg != &map->head);
|
528 |
sched_unlock(); |
529 |
return ESRCH;
|
530 |
} |
531 |
|
532 |
void
|
533 |
vm_init(void)
|
534 |
{ |
535 |
|
536 |
seg_init(&kernel_map.head); |
537 |
kernel_task.map = &kernel_map; |
538 |
} |
539 |
|
540 |
/*
|
541 |
* Initialize segment.
|
542 |
*/
|
543 |
static void |
544 |
seg_init(struct seg *seg)
|
545 |
{ |
546 |
|
547 |
seg->next = seg->prev = seg; |
548 |
seg->sh_next = seg->sh_prev = seg; |
549 |
seg->addr = 0;
|
550 |
seg->phys = 0;
|
551 |
seg->size = 0;
|
552 |
seg->flags = SEG_FREE; |
553 |
} |
554 |
|
555 |
/*
|
556 |
* Create new free segment after the specified segment.
|
557 |
* Returns segment on success, or NULL on failure.
|
558 |
*/
|
559 |
static struct seg * |
560 |
seg_create(struct seg *prev, vaddr_t addr, size_t size)
|
561 |
{ |
562 |
struct seg *seg;
|
563 |
|
564 |
if ((seg = kmem_alloc(sizeof(*seg))) == NULL) |
565 |
return NULL; |
566 |
|
567 |
seg->addr = addr; |
568 |
seg->size = size; |
569 |
seg->phys = (paddr_t)addr; |
570 |
seg->flags = SEG_FREE; |
571 |
seg->sh_next = seg->sh_prev = seg; |
572 |
|
573 |
seg->next = prev->next; |
574 |
seg->prev = prev; |
575 |
prev->next->prev = seg; |
576 |
prev->next = seg; |
577 |
|
578 |
return seg;
|
579 |
} |
580 |
|
581 |
/*
|
582 |
* Delete specified segment.
|
583 |
*/
|
584 |
static void |
585 |
seg_delete(struct seg *head, struct seg *seg) |
586 |
{ |
587 |
|
588 |
/*
|
589 |
* If it is shared segment, unlink from shared list.
|
590 |
*/
|
591 |
if (seg->flags & SEG_SHARED) {
|
592 |
seg->sh_prev->sh_next = seg->sh_next; |
593 |
seg->sh_next->sh_prev = seg->sh_prev; |
594 |
if (seg->sh_prev == seg->sh_next)
|
595 |
seg->sh_prev->flags &= ~SEG_SHARED; |
596 |
} |
597 |
if (head != seg)
|
598 |
kmem_free(seg); |
599 |
} |
600 |
|
601 |
/*
|
602 |
* Find the segment at the specified address.
|
603 |
*/
|
604 |
static struct seg * |
605 |
seg_lookup(struct seg *head, vaddr_t addr, size_t size)
|
606 |
{ |
607 |
struct seg *seg;
|
608 |
|
609 |
seg = head; |
610 |
do {
|
611 |
if (seg->addr <= addr &&
|
612 |
seg->addr + seg->size >= addr + size) { |
613 |
return seg;
|
614 |
} |
615 |
seg = seg->next; |
616 |
} while (seg != head);
|
617 |
return NULL; |
618 |
} |
619 |
|
620 |
/*
|
621 |
* Allocate free segment for specified size.
|
622 |
*/
|
623 |
static struct seg * |
624 |
seg_alloc(struct seg *head, size_t size)
|
625 |
{ |
626 |
struct seg *seg;
|
627 |
paddr_t pa; |
628 |
|
629 |
if ((pa = page_alloc(size)) == 0) |
630 |
return NULL; |
631 |
|
632 |
if ((seg = seg_create(head, (vaddr_t)pa, size)) == NULL) { |
633 |
page_free(pa, size); |
634 |
return NULL; |
635 |
} |
636 |
return seg;
|
637 |
} |
638 |
|
639 |
/*
|
640 |
* Delete specified free segment.
|
641 |
*/
|
642 |
static void |
643 |
seg_free(struct seg *head, struct seg *seg) |
644 |
{ |
645 |
ASSERT(seg->flags != SEG_FREE); |
646 |
|
647 |
/*
|
648 |
* If it is shared segment, unlink from shared list.
|
649 |
*/
|
650 |
if (seg->flags & SEG_SHARED) {
|
651 |
seg->sh_prev->sh_next = seg->sh_next; |
652 |
seg->sh_next->sh_prev = seg->sh_prev; |
653 |
if (seg->sh_prev == seg->sh_next)
|
654 |
seg->sh_prev->flags &= ~SEG_SHARED; |
655 |
} |
656 |
seg->prev->next = seg->next; |
657 |
seg->next->prev = seg->prev; |
658 |
|
659 |
kmem_free(seg); |
660 |
} |
661 |
|
662 |
/*
|
663 |
* Reserve the segment at the specified address/size.
|
664 |
*/
|
665 |
static struct seg * |
666 |
seg_reserve(struct seg *head, vaddr_t addr, size_t size)
|
667 |
{ |
668 |
struct seg *seg;
|
669 |
paddr_t pa; |
670 |
|
671 |
pa = (paddr_t)addr; |
672 |
|
673 |
if (page_reserve(pa, size) != 0) |
674 |
return NULL; |
675 |
|
676 |
if ((seg = seg_create(head, (vaddr_t)pa, size)) == NULL) { |
677 |
page_free(pa, size); |
678 |
return NULL; |
679 |
} |
680 |
return seg;
|
681 |
} |