1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 02:45:27 +03:00
iris/alloc.ccp

379 lines
10 KiB
Plaintext
Raw Normal View History

2009-05-19 00:18:23 +03:00
#pypp 0
2009-06-01 15:26:42 +03:00
// Iris: micro-kernel for a capability-based operating system.
// alloc.ccp: Allocation of kernel structures.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2009-05-18 10:30:27 +03:00
#include "kernel.hh"
2009-05-25 01:31:35 +03:00
#define PREV(x) (((Object_base **)(x))[-2])
#define NEXT(x) (((Object_base **)(x))[-1])
2009-06-08 14:46:13 +03:00
#define SIZE (2 * sizeof (Object_base *))
2009-05-25 01:31:35 +03:00
2009-07-20 01:23:45 +03:00
bool Memory::use (unsigned num):
2009-05-24 13:22:22 +03:00
// Go up to parents, incrementing used.
2009-05-25 01:31:35 +03:00
for Memory *m = this; m; m = m->address_space:
2009-07-20 01:23:45 +03:00
if used + num > limit:
2009-05-24 13:22:22 +03:00
// Not allowed. Restore used for all children.
2009-05-25 01:31:35 +03:00
for Memory *r = this; r != m; r = r->address_space:
2009-07-20 01:23:45 +03:00
r->used -= num
2009-05-24 13:22:22 +03:00
return false
2009-07-20 01:23:45 +03:00
m->used += num
2009-05-24 13:22:22 +03:00
return true
2009-05-19 00:18:23 +03:00
2009-07-20 01:23:45 +03:00
void Memory::unuse (unsigned num):
2009-05-25 01:31:35 +03:00
for Memory *m = this; m; m = m->address_space:
2009-07-20 01:23:45 +03:00
m->used -= num
2009-05-19 00:18:23 +03:00
void *Memory::search_free (unsigned size, void **first):
2009-05-18 10:30:27 +03:00
Free *f
unsigned s = 0
for f = frees; f; f = f->next:
2009-05-25 01:31:35 +03:00
if NEXT (f):
s = (unsigned)NEXT (f) - (unsigned)f
2009-05-18 10:30:27 +03:00
else:
2009-05-25 01:31:35 +03:00
s = PAGE_SIZE - ((unsigned)f & ~PAGE_MASK) + SIZE
if s >= size + SIZE:
2009-05-18 10:30:27 +03:00
break
if !f:
2009-05-25 01:31:35 +03:00
unsigned p = palloc ()
if !p:
2009-07-20 01:23:45 +03:00
assert (false)
2009-05-18 10:30:27 +03:00
return NULL
2009-05-25 01:31:35 +03:00
f = (Free *)(p + SIZE)
2009-05-18 10:30:27 +03:00
f->marker = ~0
f->next = frees
f->prev = NULL
frees = f
if f->next:
f->next->prev = f
2009-05-25 01:31:35 +03:00
NEXT (f) = NULL
PREV (f) = NULL
2009-05-18 10:30:27 +03:00
s = PAGE_SIZE
// We have a free block, possibly too large.
2009-06-08 14:46:13 +03:00
if s >= size + sizeof (Free) + 2 * SIZE:
2009-05-18 10:30:27 +03:00
// Create the new object at the end and keep the Free.
2009-05-25 01:31:35 +03:00
Free *obj = (Free *)((unsigned)f + s - size - SIZE)
NEXT (obj) = NEXT (f)
if NEXT (obj):
PREV (NEXT (obj)) = obj
PREV (obj) = f
NEXT (f) = obj
2009-05-18 10:30:27 +03:00
f = obj
else:
if f->prev:
f->prev->next = f->next
else:
frees = f->next
if f->next:
f->next->prev = f->prev
2009-05-25 01:31:35 +03:00
f->address_space = this
f->refs = NULL
2009-05-19 00:18:23 +03:00
f->next = (Free *)*first
2009-05-18 10:30:27 +03:00
f->prev = NULL
if f->next:
f->next->prev = f
2009-05-19 00:18:23 +03:00
*first = f
2009-05-18 10:30:27 +03:00
return f
2009-05-25 01:31:35 +03:00
void Memory::free_obj (Object_base *obj):
2009-05-18 10:30:27 +03:00
Free *self
// Merge with previous, if it exists and is a Free.
2009-05-25 01:31:35 +03:00
if PREV (obj) && PREV (obj)->is_free ():
self = (Free *)PREV (obj)
NEXT (self) = NEXT (obj)
if NEXT (obj):
PREV (NEXT (obj)) = self
2009-05-18 10:30:27 +03:00
else:
2009-05-25 01:31:35 +03:00
self = (Free *)obj
self->next = frees
2009-05-18 10:30:27 +03:00
self->prev = NULL
if self->next:
self->next->prev = self
2009-05-25 01:31:35 +03:00
frees = self
2009-05-18 10:30:27 +03:00
self->marker = ~0
// Merge with next, if it exists and is a Free.
2009-05-25 01:31:35 +03:00
if NEXT (self) && NEXT (self)->is_free ():
NEXT (self) = NEXT (NEXT (self))
if NEXT (self):
PREV (NEXT (self)) = self
2009-05-18 10:30:27 +03:00
// Free page if the resulting object is the only thing in it.
2009-05-25 01:31:35 +03:00
if !PREV (self) && !NEXT (self):
2009-05-18 10:30:27 +03:00
if self->next:
self->next->prev = self->prev
if self->prev:
self->prev->next = self->next
else:
2009-05-25 01:31:35 +03:00
frees = self->next
2009-06-11 00:20:33 +03:00
pfree ((unsigned)self - SIZE)
2009-05-18 10:30:27 +03:00
Page *Memory::alloc_page ():
2009-05-19 00:18:23 +03:00
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-05-29 00:35:27 +03:00
ret->data.frame = 0
ret->data.flags = 0
2009-05-18 10:30:27 +03:00
return ret
Thread *Memory::alloc_thread ():
2009-05-19 00:18:23 +03:00
Thread *ret = (Thread *)search_free (sizeof (Thread), (void **)&threads)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-05-18 10:30:27 +03:00
ret->address_space = this
ret->pc = 0
ret->sp = 0
Thread_arch_init (ret)
2009-05-25 01:31:35 +03:00
ret->flags = 0
2009-05-18 10:30:27 +03:00
ret->schedule_prev = NULL
ret->schedule_next = NULL
2009-05-24 13:22:22 +03:00
ret->receivers = NULL
2009-05-18 10:30:27 +03:00
return ret
2009-07-20 01:23:45 +03:00
Message *Memory::alloc_message (Receiver *target):
2009-05-27 19:33:05 +03:00
Message *ret = (Message *)search_free (sizeof (Message), (void **)&target->messages)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-07-20 01:23:45 +03:00
if !ret->next:
target->last_message = ret
2009-05-20 23:07:56 +03:00
return ret
Receiver *Memory::alloc_receiver ():
Receiver *ret = (Receiver *)search_free (sizeof (Receiver), (void **)&receivers)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-05-20 23:07:56 +03:00
ret->owner = NULL
ret->prev_owned = NULL
ret->next_owned = NULL
2009-07-20 01:23:45 +03:00
ret->alarm_count = ~0
2009-05-20 23:07:56 +03:00
ret->capabilities = NULL
ret->messages = NULL
2009-07-20 01:23:45 +03:00
ret->last_message = NULL
2009-06-01 02:12:54 +03:00
ret->reply_protected_data = ~0
ret->protected_only = false
2009-05-20 23:07:56 +03:00
return ret
2009-05-25 01:31:35 +03:00
Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret):
2009-05-24 13:22:22 +03:00
if !ret:
2009-05-25 01:31:35 +03:00
ret = (Capability *)search_free (sizeof (Capability), (void **)&capabilities)
if !ret:
return NULL
2009-05-20 23:07:56 +03:00
ret->target = target
2009-06-08 14:46:13 +03:00
ret->protected_data = protected_data
2009-05-25 01:31:35 +03:00
ret->parent = parent
2009-05-20 23:07:56 +03:00
ret->children = NULL
ret->sibling_prev = NULL
2009-06-08 14:46:13 +03:00
if parent:
ret->sibling_next = parent->children
parent->children = ret
else:
if parent_ptr:
ret->sibling_next = *parent_ptr
else:
ret->sibling_next = NULL
2009-05-20 23:07:56 +03:00
if ret->sibling_next:
ret->sibling_next->sibling_prev = ret
return ret
2009-05-25 01:31:35 +03:00
Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret):
if copy:
2009-06-08 14:46:13 +03:00
if source->parent:
return alloc_capability (source->target, source->parent, &source->parent->children, source->protected_data, ret)
else if (unsigned)source->target & ~KERNEL_MASK:
return alloc_capability (source->target, source->parent, &source->target->capabilities, source->protected_data, ret)
else:
return alloc_capability (source->target, source->parent, &((Object_base *)source->protected_data)->refs, source->protected_data, ret)
2009-05-25 01:31:35 +03:00
else:
return alloc_capability (source->target, source, &source->children, source->protected_data, ret)
2009-05-24 13:22:22 +03:00
Cappage *Memory::alloc_cappage ():
Cappage *ret = (Cappage *)search_free (sizeof (Cappage), (void **)&cappages)
if !ret:
return NULL
2009-05-29 00:35:27 +03:00
ret->data.frame = zalloc ()
if !ret->data.frame:
2009-05-24 13:22:22 +03:00
free_cappage (ret)
return NULL
2009-05-29 00:35:27 +03:00
ret->data.flags = 0
2009-05-24 13:22:22 +03:00
return ret
2009-05-18 10:30:27 +03:00
Memory *Memory::alloc_memory ():
2009-05-19 00:18:23 +03:00
Memory *ret = (Memory *)search_free (sizeof (Memory), (void **)&memories)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-05-18 10:30:27 +03:00
ret->frees = NULL
ret->pages = NULL
ret->threads = NULL
ret->memories = NULL
ret->limit = ~0
ret->used = 0
Memory_arch_init (ret)
return ret
2009-05-19 00:18:23 +03:00
void Memory::free_page (Page *page):
if page->prev:
page->prev->next = page->next
else:
pages = page->next
if page->next:
page->next->prev = page->prev
unuse ()
2009-05-29 00:35:27 +03:00
if page->data.frame:
pfree (page->data.frame)
2009-05-25 01:31:35 +03:00
free_obj (page)
2009-05-19 00:18:23 +03:00
void Memory::free_thread (Thread *thread):
if thread->prev:
thread->prev->next = thread->next
else:
threads = thread->next
if thread->next:
thread->next->prev = thread->prev
2009-05-20 23:07:56 +03:00
// Unschedule.
if thread->schedule_prev:
thread->schedule_prev->schedule_next = thread->schedule_next
else if first_scheduled == thread:
first_scheduled = thread->schedule_next
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev
2009-05-24 13:22:22 +03:00
while thread->receivers:
thread->receivers->orphan ()
2009-05-25 01:31:35 +03:00
free_obj (thread)
2009-05-20 23:07:56 +03:00
2009-07-20 01:23:45 +03:00
void Memory::free_message (Receiver *owner, Message *message):
if message->prev:
message->prev->next = message->next
else:
owner->messages = message->next
if message->next:
message->next->prev = message->prev
else:
owner->last_message = message->prev
2009-05-20 23:07:56 +03:00
for unsigned i = 0; i < 4; ++i:
2009-07-20 01:23:45 +03:00
if message->capabilities[i]:
free_capability (message->capabilities[i])
2009-05-25 01:31:35 +03:00
free_obj (message)
2009-05-20 23:07:56 +03:00
void Memory::free_receiver (Receiver *receiver):
2009-05-24 13:22:22 +03:00
receiver->orphan ()
2009-05-20 23:07:56 +03:00
while receiver->capabilities:
receiver->capabilities->invalidate ()
while receiver->messages:
2009-07-20 01:23:45 +03:00
free_message (receiver, receiver->messages)
2009-05-25 01:31:35 +03:00
free_obj (receiver)
2009-05-20 23:07:56 +03:00
2009-05-24 13:22:22 +03:00
void Receiver::orphan ():
if prev_owned:
prev_owned->next_owned = next_owned
2009-05-20 23:07:56 +03:00
else:
2009-05-24 13:22:22 +03:00
owner->receivers = next_owned
if next_owned:
next_owned->prev_owned = prev_owned
owner = NULL
void Receiver::own (Thread *o):
if owner:
orphan ()
owner = o
next_owned = o->receivers
if next_owned:
next_owned->prev_owned = this
o->receivers = this
void Memory::free_capability (Capability *capability):
capability->invalidate ()
2009-05-25 01:31:35 +03:00
free_obj (capability)
2009-05-20 23:07:56 +03:00
void Capability::invalidate ():
2009-06-01 02:12:54 +03:00
if !target:
return
2009-05-20 23:07:56 +03:00
if sibling_prev:
sibling_prev->sibling_next = sibling_next
2009-06-08 14:46:13 +03:00
else if (unsigned)target & ~KERNEL_MASK:
2009-05-20 23:07:56 +03:00
target->capabilities = sibling_next
2009-06-08 14:46:13 +03:00
else:
((Object_base *)protected_data)->refs = sibling_next
2009-05-20 23:07:56 +03:00
if sibling_next:
sibling_next->sibling_prev = sibling_prev
2009-06-01 02:12:54 +03:00
parent = NULL
sibling_prev = NULL
sibling_next = NULL
2009-05-20 23:07:56 +03:00
Capability *c = this
while c->children:
c = c->children
while c:
Capability *next = c->sibling_next
if !next:
2009-05-25 01:31:35 +03:00
next = c->parent
2009-05-20 23:07:56 +03:00
c->target = NULL
2009-05-25 01:31:35 +03:00
c->parent = NULL
2009-05-20 23:07:56 +03:00
c->children = NULL
c->sibling_prev = NULL
c->sibling_next = NULL
c->protected_data = 0
c = next
2009-05-19 00:18:23 +03:00
2009-05-24 13:22:22 +03:00
void Memory::free_cappage (Cappage *p):
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
2009-05-29 00:35:27 +03:00
((Capability *)p->data.frame)[i].invalidate ()
zfree (p->data.frame)
2009-05-25 01:31:35 +03:00
free_obj (p)
2009-05-24 13:22:22 +03:00
2009-05-19 00:18:23 +03:00
void Memory::free_memory (Memory *mem):
if mem->prev:
mem->prev->next = mem->next
else:
memories = mem->next
if mem->next:
mem->next->prev = mem->prev
while mem->pages:
free_page (mem->pages)
while mem->threads:
free_thread (mem->threads)
while mem->memories:
free_memory (mem->memories)
Memory_arch_free (mem)
2009-05-25 01:31:35 +03:00
free_obj (mem)
2009-06-01 02:12:54 +03:00
void Page::forget ():
if data.share_prev || data.share_next:
if data.share_prev:
((Page *)data.share_prev)->data.share_next = data.share_next
if data.share_next:
((Page *)data.share_next)->data.share_prev = data.share_prev
data.share_prev = NULL
data.share_next = NULL
else:
2009-07-20 01:23:45 +03:00
// If the page has a frame and should be freed, free it.
if !((data.flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)):
2009-06-08 14:46:13 +03:00
raw_pfree (data.frame)
2009-06-01 02:12:54 +03:00
data.frame = 0
2009-06-08 14:46:13 +03:00
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
2009-06-01 02:12:54 +03:00
Page_arch_update_mapping (this)
void Cappage::forget ():
if data.share_prev || data.share_next:
if data.share_prev:
((Cappage *)data.share_prev)->data.share_next = data.share_next
if data.share_next:
((Cappage *)data.share_next)->data.share_prev = data.share_prev
data.share_prev = NULL
data.share_next = NULL
else:
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
((Capability *)data.frame)[i].invalidate ()
raw_pfree (data.frame)
data.frame = 0
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED)