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-07-25 01:54:12 +03:00
// Memory model used for kernel structure storage
// Each Memory object has several pointers, one for each type of objects it contains. These pointers are the start of double-linked lists.
// Each object also has a NEXT and PREV pointer, which point to the next and previous object in the same page. These pointers are 0 for the first (or last) object in a page. There is no pointer to the first object, it always starts at page_base + SIZE.
2009-08-18 00:11:15 +03:00
// The PREV/NEXT-list contains all objects in the page, including kFree objects, in the order they appear in the page.
2009-07-25 01:54:12 +03:00
// The prev/next-lists contain only objects of one type, unsorted.
// All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV.
2009-08-18 00:11:15 +03:00
#define PREV(x) (((kObject **)(x))[-2])
#define NEXT(x) (((kObject **)(x))[-1])
2010-01-24 22:34:24 +02:00
// ATTENTION! When changing SIZE, be sure to also change the hard-coded 8 in kernel.hhp which defines MAX_NUM_CAPS.
2009-08-18 00:11:15 +03:00
#define SIZE (2 * sizeof (kObject *))
2009-05-25 01:31:35 +03:00
2009-08-18 00:11:15 +03:00
bool kMemory::use (unsigned num):
2009-05-24 13:22:22 +03:00
// Go up to parents, incrementing used.
2009-08-18 00:11:15 +03:00
for kMemory *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-08-18 00:11:15 +03:00
for kMemory *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-08-18 00:11:15 +03:00
void kMemory::unuse (unsigned num):
for kMemory *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
2009-07-25 01:54:12 +03:00
// This allocates a new block of memory for use by the kernel.
2010-01-24 22:34:24 +02:00
// size is the required size of the block (excluding SIZE)
2009-07-25 01:54:12 +03:00
// first is a pointer to the first object pointer of this type.
// The result is a block of size at least size, which is linked as an object in the list of first.
2009-08-18 00:11:15 +03:00
void *kMemory::search_free (unsigned size, void **first):
kFree *f
2010-01-24 22:34:24 +02:00
if size >= PAGE_SIZE - SIZE:
panic (size, "requested size is too large")
int s = 0
2009-08-18 00:11:15 +03:00
// Let's see if there already is a kFree chunk which is large enough.
for f = frees; f; f = (kFree *)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
2009-07-25 01:54:12 +03:00
// s is now the size of the current free block, including SIZE.
// The requirement is to fit a block of size, plus its SIZE header.
2009-05-25 01:31:35 +03:00
if s >= size + SIZE:
2009-05-18 10:30:27 +03:00
break
if !f:
2009-07-25 01:54:12 +03:00
// No chunk was found; allocate a new page and add a chunk in it. It is always large enough.
2009-05-25 01:31:35 +03:00
unsigned p = palloc ()
if !p:
2010-01-24 22:34:24 +02:00
kdebug ("no free space: kernel allocation failed")
2009-05-18 10:30:27 +03:00
return NULL
2009-08-18 00:11:15 +03:00
f = (kFree *)(p + SIZE)
// Mark it as a kFree object.
2009-05-18 10:30:27 +03:00
f->marker = ~0
2009-08-18 00:11:15 +03:00
// Link it in the kFree list.
2009-05-18 10:30:27 +03:00
f->next = frees
f->prev = NULL
frees = f
if f->next:
2009-08-18 00:11:15 +03:00
((kFree *)f->next)->prev = f
2009-07-25 01:54:12 +03:00
// There are no other objects in this page.
2009-05-25 01:31:35 +03:00
NEXT (f) = NULL
PREV (f) = NULL
2009-07-25 01:54:12 +03:00
// The size of this block is the entire page.
2009-05-18 10:30:27 +03:00
s = PAGE_SIZE
2009-07-25 01:54:12 +03:00
// We have a free block, possibly too large. The block is linked in frees, and in the page.
2009-08-18 00:11:15 +03:00
if s >= size + sizeof (kFree) + 2 * SIZE:
2009-05-18 10:30:27 +03:00
// Create the new object at the end and keep the Free.
2009-07-25 01:54:12 +03:00
// f is the start of the free block
// f + (s - SIZE) is the end of the free block, compensated for the header of the next block.
// f + (s - SIZE) - size is the address where the new block should start.
2009-08-18 00:11:15 +03:00
kFree *obj = (kFree *)((unsigned)f + (s - SIZE) - size)
2009-07-25 01:54:12 +03:00
// Link the new object in the page.
2009-05-25 01:31:35 +03:00
NEXT (obj) = NEXT (f)
if NEXT (obj):
PREV (NEXT (obj)) = obj
PREV (obj) = f
NEXT (f) = obj
2009-07-25 01:54:12 +03:00
// Set f to the new object, because it is used by that name later.
2009-05-18 10:30:27 +03:00
f = obj
else:
2009-07-25 01:54:12 +03:00
// The block was only just large enough: turn it into a new type. It is already linked into the page.
// Unlink it from the free list.
2009-05-18 10:30:27 +03:00
if f->prev:
2009-08-18 00:11:15 +03:00
((kFree *)f->prev)->next = f->next
2009-05-18 10:30:27 +03:00
else:
2009-08-18 00:11:15 +03:00
frees = (kFree *)f->next
2009-05-18 10:30:27 +03:00
if f->next:
2009-08-18 00:11:15 +03:00
((kFree *)f->next)->prev = f->prev
2009-07-25 01:54:12 +03:00
// f is now a block which is linked in the page, but not in any list. Link it into first.
2009-08-18 00:11:15 +03:00
f->next = (kFree *)*first
2009-05-18 10:30:27 +03:00
f->prev = NULL
if f->next:
2009-08-18 00:11:15 +03:00
((kFree *)f->next)->prev = f
2009-05-19 00:18:23 +03:00
*first = f
2009-07-25 01:54:12 +03:00
// Set common initial values.
f->address_space = this
2009-08-05 11:16:24 +03:00
f->refs.reset ()
2009-05-18 10:30:27 +03:00
return f
2009-07-25 01:54:12 +03:00
// Free an object; it is still in its list, and it is still in the page list.
2009-08-18 00:11:15 +03:00
void kMemory::free_obj (kObject *obj, kPointer *first):
kFree *self = (kFree *)obj
2009-08-05 11:16:24 +03:00
// Invalidate references.
2009-08-24 22:02:35 +03:00
while self->refs.valid ():
2009-08-05 11:16:24 +03:00
self->refs->invalidate ()
2009-07-25 01:54:12 +03:00
// Free it from its list.
if self->prev:
2009-08-18 00:11:15 +03:00
((kFree *)self->prev)->next = self->next
2009-07-25 01:54:12 +03:00
else:
2009-08-18 00:11:15 +03:00
*(kPointer *)first = (kPointer)self->next
2009-07-25 01:54:12 +03:00
if self->next:
2009-08-18 00:11:15 +03:00
((kFree *)self->next)->prev = self->prev
// Merge with previous, if it exists and is a kFree.
2009-07-25 01:54:12 +03:00
if PREV (self) && PREV (self)->is_free ():
2009-08-18 00:11:15 +03:00
self = (kFree *)PREV (self)
2009-07-25 01:54:12 +03:00
// Remove the object from the page list.
2009-05-25 01:31:35 +03:00
NEXT (self) = NEXT (obj)
2009-07-25 01:54:12 +03:00
if NEXT (self):
PREV (NEXT (self)) = self
2009-05-18 10:30:27 +03:00
else:
2009-08-18 00:11:15 +03:00
// The previous object is not a kFree, so create a new one.
2009-07-25 01:54:12 +03:00
// It is already linked in the page, but needs to be linked into the free list.
2009-05-25 01:31:35 +03:00
self->next = frees
2009-05-18 10:30:27 +03:00
self->prev = NULL
if self->next:
2009-08-18 00:11:15 +03:00
((kFree *)self->next)->prev = self
2009-05-25 01:31:35 +03:00
frees = self
2009-08-18 00:11:15 +03:00
// Mark it as a kFree.
2009-05-18 10:30:27 +03:00
self->marker = ~0
2009-08-18 00:11:15 +03:00
// Merge with next, if it exists and is a kFree.
2009-05-25 01:31:35 +03:00
if NEXT (self) && NEXT (self)->is_free ():
2009-07-25 01:54:12 +03:00
// Unlink the next from the frees list.
2009-08-18 00:11:15 +03:00
kFree *n = (kFree *)NEXT (self)
2009-07-25 01:54:12 +03:00
if n->prev:
2009-08-18 00:11:15 +03:00
((kFree *)n->prev)->next = n->next
2009-07-25 01:54:12 +03:00
else:
2009-08-18 00:11:15 +03:00
frees = (kFree *)n->next
2009-07-25 01:54:12 +03:00
if n->next:
2009-08-18 00:11:15 +03:00
((kFree *)n->next)->prev = n->prev
2009-07-25 01:54:12 +03:00
// Unlink the next from the page list.
2009-05-25 01:31:35 +03:00
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:
2009-08-18 00:11:15 +03:00
((kFree *)self->next)->prev = self->prev
2009-05-18 10:30:27 +03:00
if self->prev:
2009-08-18 00:11:15 +03:00
((kFree *)self->prev)->next = self->next
2009-05-18 10:30:27 +03:00
else:
2009-08-18 00:11:15 +03:00
frees = (kFree *)self->next
2010-05-01 00:13:49 +03:00
//kdebug ("freeing page: ")
//kdebug_num ((unsigned)self - SIZE)
//kdebug ("\n")
2009-06-11 00:20:33 +03:00
pfree ((unsigned)self - SIZE)
2009-05-18 10:30:27 +03:00
2009-08-18 00:11:15 +03:00
kPage *kMemory::alloc_page ():
kPage *ret = (kPage *)search_free (sizeof (kPage), (void **)&pages)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-08-05 11:16:24 +03:00
ret->frame = 0
ret->flags = 0
2010-01-17 11:01:42 +02:00
ret->mapping = ~0
2010-01-18 06:01:59 +02:00
ret->share_prev = NULL
ret->share_next = NULL
kPage_arch_init (ret)
2009-05-18 10:30:27 +03:00
return ret
2009-08-18 00:11:15 +03:00
kThread *kMemory::alloc_thread (unsigned size):
2009-09-08 22:20:30 +03:00
kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kThread::caps_store), (void **)&threads)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-08-05 11:16:24 +03:00
ret->receivers = NULL
2009-05-18 10:30:27 +03:00
ret->pc = 0
ret->sp = 0
2009-08-18 00:11:15 +03:00
kThread_arch_init (ret)
2009-05-25 01:31:35 +03:00
ret->flags = 0
2009-12-26 15:17:06 +02:00
ret->id = ~0
2009-05-18 10:30:27 +03:00
ret->schedule_prev = NULL
ret->schedule_next = NULL
2009-08-13 18:28:36 +03:00
ret->slots = size
2009-08-05 11:16:24 +03:00
for unsigned i = 0; i < size; ++i:
2009-09-08 22:20:30 +03:00
ret->slot[i].prev.thread = NULL
ret->slot[i].next.thread = NULL
ret->slot[i].caps = NULL
2010-01-24 22:34:24 +02:00
//kdebug ("new thread: ")
//kdebug_num ((unsigned)ret)
//kdebug ("\n")
2009-05-18 10:30:27 +03:00
return ret
2009-12-30 23:41:45 +02:00
void kCaps::init (unsigned s):
2009-12-30 15:00:37 +02:00
first_slot.thread = NULL
2009-12-30 23:41:45 +02:00
size = s
for unsigned i = 0; i < s; ++i:
2009-12-30 15:00:37 +02:00
set (i, NULL, 0, kCapRef (), NULL)
kCaps *kMemory::alloc_caps (unsigned size):
2010-01-24 22:34:24 +02:00
if size == 0:
dpanic (0, "zero-size caps")
return NULL
kCaps *ret
if size > MAX_NUM_CAPS:
dpanic (size, "requested caps is too large")
return NULL
ret = (kCaps *)search_free (sizeof (kCaps) + (size - 1) * sizeof (kCapability), (void **)&capses)
2009-12-30 15:00:37 +02:00
if !ret:
return NULL
ret->init (size)
2010-01-24 22:34:24 +02:00
//kdebug ("allocate caps ")
//kdebug_num ((unsigned)ret)
//kdebug ('+')
//kdebug_num (size)
//kdebug ('\n')
2009-12-30 15:00:37 +02:00
return ret
2009-08-18 00:11:15 +03:00
kMessage *kMemory::alloc_message (kReceiver *target):
2009-09-06 12:04:09 +03:00
kMessage *ret = (kMessage *)search_free (sizeof (kMessage) + sizeof (kCapability), (void **)&target->messages)
2009-05-24 13:22:22 +03:00
if !ret:
return NULL
2009-12-30 15:00:37 +02:00
ret->caps.init (2)
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
2009-12-30 15:00:37 +02:00
kList *kMemory::alloc_list ():
kList *ret = (kList *)search_free (sizeof (kList), (void **)&lists)
if !ret:
return NULL
ret->owner.init (1)
ret->first_listitem = NULL
return ret
kListitem *kMemory::alloc_listitem ():
kListitem *ret = (kListitem *)search_free (sizeof (kListitem), (void **)&listitems)
if !ret:
return NULL
ret->target.init (1)
ret->list = NULL
ret->prev_item = NULL
ret->next_item = NULL
ret->info = 0
return ret
2009-08-18 00:11:15 +03:00
kReceiver *kMemory::alloc_receiver ():
kReceiver *ret = (kReceiver *)search_free (sizeof (kReceiver), (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-08-05 11:16:24 +03:00
ret->caps = NULL
ret->capabilities.reset ()
2009-05-20 23:07:56 +03:00
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-08-24 22:02:35 +03:00
ret->queue_limit = ~0
2009-05-20 23:07:56 +03:00
return ret
2009-08-18 00:11:15 +03:00
kMemory *kMemory::alloc_memory ():
kMemory *ret = (kMemory *)search_free (sizeof (kMemory), (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
2009-08-05 11:16:24 +03:00
ret->capses = NULL
ret->receivers = NULL
2009-05-18 10:30:27 +03:00
ret->memories = NULL
ret->limit = ~0
ret->used = 0
2009-08-18 00:11:15 +03:00
kMemory_arch_init (ret)
2009-05-18 10:30:27 +03:00
return ret
2009-05-19 00:18:23 +03:00
2010-05-01 00:13:49 +03:00
void kCaps::set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
2010-01-24 22:34:24 +02:00
if index >= size:
kdebug ("size: ")
kdebug_num (size)
kdebug ("\n")
dpanic (index, "index too large for kCaps")
return
kCapability *c = &caps[index]
c->target = target
c->protected_data = pdata
c->parent = parent
c->children.reset ()
c->sibling_prev.reset ()
2009-08-24 22:02:35 +03:00
if parent.valid ():
2010-01-24 22:34:24 +02:00
c->sibling_next = parent->children
2009-08-18 00:11:15 +03:00
parent->children = kCapRef (this, index)
2009-08-05 11:16:24 +03:00
else:
if parent_ptr:
2010-01-24 22:34:24 +02:00
c->sibling_next = *parent_ptr
2009-08-18 00:11:15 +03:00
*parent_ptr = kCapRef (this, index)
2009-08-05 11:16:24 +03:00
else:
2010-01-24 22:34:24 +02:00
c->sibling_next.reset ()
if c->sibling_next.valid ():
c->sibling_next->sibling_prev = kCapRef (this, index)
2009-08-05 11:16:24 +03:00
2009-08-18 00:11:15 +03:00
void kCaps::clone (unsigned index, kCapRef source, bool copy):
2009-09-06 12:04:09 +03:00
cap (index)->invalidate ()
if !source.valid ():
return
2009-08-05 11:16:24 +03:00
if copy:
2009-08-24 22:02:35 +03:00
if source->parent.valid ():
2009-09-06 12:04:09 +03:00
set (index, source->target, source->protected_data, source->parent)
2009-08-05 11:16:24 +03:00
else if (unsigned)source->target & ~KERNEL_MASK:
2009-09-06 12:04:09 +03:00
set (index, source->target, source->protected_data, kCapRef (), &source->target->capabilities)
2009-08-05 11:16:24 +03:00
else:
2009-09-06 12:04:09 +03:00
set (index, source->target, source->protected_data, kCapRef (), &((kObject *)source->protected_data.l)->refs)
2009-08-05 11:16:24 +03:00
else:
2009-09-06 12:04:09 +03:00
set (index, source->target, source->protected_data, source)
2009-08-05 11:16:24 +03:00
2009-08-18 00:11:15 +03:00
void kMemory::free_page (kPage *page):
2010-01-17 11:01:42 +02:00
if page->mapping != ~0:
page->address_space->unmap (page)
2010-05-01 00:13:49 +03:00
page->forget ()
if page->flags & Iris::Page::PAYING:
2009-07-25 01:54:12 +03:00
unuse ()
2009-08-18 00:11:15 +03:00
free_obj (page, (kPointer *)&pages)
2009-05-19 00:18:23 +03:00
2009-09-08 22:20:30 +03:00
void kThread::unset_slot (unsigned s):
if !slot[s].caps:
return
if slot[s].prev.thread:
slot[s].prev.thread->slot[slot[s].prev.index].next = slot[s].next
else:
slot[s].caps->first_slot = slot[s].next
if slot[s].next.thread:
slot[s].next.thread->slot[slot[s].next.index].prev = slot[s].prev
slot[s].prev.thread = NULL
slot[s].next.thread = NULL
slot[s].caps = NULL
2009-08-18 00:11:15 +03:00
void kMemory::free_thread (kThread *thread):
2009-07-25 01:54:12 +03:00
thread->unrun ()
2009-05-24 13:22:22 +03:00
while thread->receivers:
thread->receivers->orphan ()
2009-09-08 22:20:30 +03:00
for unsigned i = 0; i < thread->slots; ++i:
thread->unset_slot (i)
2009-07-25 01:54:12 +03:00
free_obj (thread, (void **)&threads)
2010-05-01 00:13:49 +03:00
if old_current == thread:
old_current = NULL
2009-05-20 23:07:56 +03:00
2009-08-18 00:11:15 +03:00
void kMemory::free_message (kReceiver *owner, kMessage *message):
2009-10-10 02:31:10 +03:00
for unsigned i = 0; i < 2; ++i:
message->caps.cap (i)->invalidate ()
2009-07-25 01:54:12 +03:00
if !message->next:
2009-08-18 00:11:15 +03:00
owner->last_message = (kMessageP)message->prev
2009-07-25 01:54:12 +03:00
free_obj (message, (void **)&owner->messages)
2009-05-20 23:07:56 +03:00
2009-08-18 00:11:15 +03:00
void kMemory::free_receiver (kReceiver *receiver):
2009-05-24 13:22:22 +03:00
receiver->orphan ()
2009-08-24 22:02:35 +03:00
while receiver->capabilities.valid ():
2009-05-20 23:07:56 +03:00
receiver->capabilities->invalidate ()
while receiver->messages:
2009-07-20 01:23:45 +03:00
free_message (receiver, receiver->messages)
2009-07-25 01:54:12 +03:00
free_obj (receiver, (void **)&receivers)
2009-05-20 23:07:56 +03:00
2009-08-18 00:11:15 +03:00
void kReceiver::orphan ():
2009-05-24 13:22:22 +03:00
if prev_owned:
prev_owned->next_owned = next_owned
2010-05-01 00:13:49 +03:00
else if owner:
2009-05-24 13:22:22 +03:00
owner->receivers = next_owned
if next_owned:
next_owned->prev_owned = prev_owned
owner = NULL
2009-08-18 00:11:15 +03:00
void kReceiver::own (kThread *o):
2009-05-24 13:22:22 +03:00
if owner:
orphan ()
owner = o
next_owned = o->receivers
if next_owned:
next_owned->prev_owned = this
o->receivers = this
2009-08-18 00:11:15 +03:00
void kCapability::invalidate ():
2009-06-01 02:12:54 +03:00
if !target:
return
2010-05-01 00:13:49 +03:00
//kdebug_num ((unsigned)this)
//kdebug ("\n")
2010-01-24 22:34:24 +02:00
//kdebug_num ((unsigned)target)
//kdebug (":")
//kdebug_num ((unsigned)protected_data.l)
//kdebug ("\n")
2010-05-01 00:13:49 +03:00
if (unsigned)this == dbg_code.h:
dpanic (0, "invalidating watched capability")
2009-08-24 22:02:35 +03:00
if sibling_prev.valid ():
2009-05-20 23:07:56 +03:00
sibling_prev->sibling_next = sibling_next
2010-01-18 07:45:52 +02:00
else if parent.valid ():
parent->children = 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:
2009-09-06 12:04:09 +03:00
((kObject *)protected_data.l)->refs = sibling_next
2009-08-24 22:02:35 +03:00
if sibling_next.valid ():
2009-05-20 23:07:56 +03:00
sibling_next->sibling_prev = sibling_prev
2009-08-05 11:16:24 +03:00
parent.reset ()
sibling_prev.reset ()
sibling_next.reset ()
2009-08-18 00:11:15 +03:00
kCapability *c = this
2009-05-20 23:07:56 +03:00
while c:
2009-08-24 22:02:35 +03:00
while c->children.valid ():
2009-08-05 11:16:24 +03:00
c = c->children.deref ()
2009-08-18 00:11:15 +03:00
kCapability *next = c->sibling_next.deref ()
2009-05-20 23:07:56 +03:00
if !next:
2009-08-05 11:16:24 +03:00
next = c->parent.deref ()
2009-05-20 23:07:56 +03:00
c->target = NULL
2010-05-01 00:13:49 +03:00
if c->parent.valid ():
c->parent->children = c->sibling_next
2009-08-05 11:16:24 +03:00
c->parent.reset ()
c->children.reset ()
c->sibling_prev.reset ()
c->sibling_next.reset ()
2009-09-06 12:04:09 +03:00
c->protected_data = 0
2009-05-20 23:07:56 +03:00
c = next
2009-05-19 00:18:23 +03:00
2009-08-18 00:11:15 +03:00
void kMemory::free_caps (kCaps *c):
2010-01-24 22:34:24 +02:00
//kdebug ("free caps ")
//kdebug_num ((unsigned)c)
//kdebug ('\n')
2009-08-05 11:16:24 +03:00
for unsigned i = 0; i < c->size; ++i:
2010-01-24 22:34:24 +02:00
c->cap (i)->invalidate ()
2009-09-08 22:20:30 +03:00
while c->first_slot.thread:
c->first_slot.thread->unset_slot (c->first_slot.index)
2009-08-05 11:16:24 +03:00
free_obj (c, (void **)&capses)
2009-05-24 13:22:22 +03:00
2009-12-30 15:00:37 +02:00
void kListitem::add (kList *l):
// Remove item from list.
if list:
if prev_item:
prev_item->next_item = next_item
else:
list->first_listitem = next_item
if next_item:
next_item->prev_item = prev_item
// Notify list owner.
if list->owner.cap (0):
kCapability::Context context
context.data[0] = list->first_listitem != NULL
context.data[1] = info
list->owner.cap (0)->invoke (&context)
// Don't leak info to new owner.
info = 0
list = l
prev_item = NULL
if !l:
next_item = NULL
return
next_item = l->first_listitem
l->first_listitem = this
if next_item:
next_item->prev_item = this
void kMemory::free_listitem (kListitem *i):
// Unset target.
i->target.cap (0)->invalidate ()
// Remove item from its list.
i->add (NULL)
// Remove item from its address space.
free_obj (i, (void **)&listitems)
void kMemory::free_list (kList *l):
// Unset callback.
l->owner.cap (0)->invalidate ()
// Clear list.
while l->first_listitem:
l->first_listitem->add (NULL)
// Remove list from address space.
free_obj (l, (void **)&lists)
2009-08-18 00:11:15 +03:00
void kMemory::free_memory (kMemory *mem):
2009-05-19 00:18:23 +03:00
while mem->pages:
2010-05-01 00:13:49 +03:00
//kdebug ("freeing page ")
//kdebug_num ((unsigned)mem->pages)
//kdebug (", next = ")
//kdebug_num ((unsigned)mem->pages->next)
//kdebug ("\n")
mem->free_page (mem->pages)
2009-08-05 11:16:24 +03:00
while mem->capses:
2010-05-01 00:13:49 +03:00
mem->free_caps (mem->capses)
2009-05-19 00:18:23 +03:00
while mem->threads:
2010-05-01 00:13:49 +03:00
mem->free_thread (mem->threads)
2009-05-19 00:18:23 +03:00
while mem->memories:
2010-05-01 00:13:49 +03:00
mem->free_memory (mem->memories)
2009-07-25 01:54:12 +03:00
while mem->receivers:
2010-05-01 00:13:49 +03:00
mem->free_receiver (mem->receivers)
2009-12-30 15:00:37 +02:00
while mem->lists:
2010-05-01 00:13:49 +03:00
mem->free_list (mem->lists)
2009-12-30 15:00:37 +02:00
while mem->listitems:
2010-05-01 00:13:49 +03:00
mem->free_listitem (mem->listitems)
2009-07-25 01:54:12 +03:00
if mem->frees:
panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories)
2009-06-01 02:12:54 +03:00
2010-10-07 10:52:04 +03:00
void kPage::check_payment ():
kPage *p
for p = this; p; p = p->share_prev:
if p->flags & Iris::Page::PAYING:
return
for p = share_next; p; p = p->share_next:
if p->flags & Iris::Page::PAYING:
return
// No kPage is paying for this frame anymore.
raw_pfree (frame)
kPage *next
2013-05-12 16:46:11 +03:00
for p = share_prev, next = (p ? p->share_prev : NULL); p; p = next, next = p ? p->share_prev : NULL:
2010-10-07 10:52:04 +03:00
p->frame = NULL
p->share_prev = NULL
p->share_next = NULL
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
kPage_arch_update_mapping (p)
for p = this, next = p->share_next; p; p = next, next = p->share_next:
p->frame = NULL
p->share_prev = NULL
p->share_next = NULL
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
kPage_arch_update_mapping (p)
2009-08-18 00:11:15 +03:00
void kPage::forget ():
2009-08-05 11:16:24 +03:00
if share_prev || share_next:
if share_prev:
share_prev->share_next = share_next
if share_next:
share_next->share_prev = share_prev
2010-10-07 10:52:04 +03:00
share_next->check_payment ()
else:
share_prev->check_payment ()
2009-08-05 11:16:24 +03:00
share_prev = NULL
share_next = NULL
2009-06-01 02:12:54 +03:00
else:
2009-07-20 01:23:45 +03:00
// If the page has a frame and should be freed, free it.
2010-05-01 00:13:49 +03:00
if !((flags ^ Iris::Page::FRAME) & (Iris::Page::PHYSICAL | Iris::Page::FRAME)):
2009-08-05 11:16:24 +03:00
raw_pfree (frame)
frame = 0
2010-05-01 00:13:49 +03:00
flags &= ~(Iris::Page::FRAME | Iris::Page::SHARED | Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
2009-08-18 00:11:15 +03:00
kPage_arch_update_mapping (this)
2009-10-10 02:31:10 +03:00
static void check_receiver (kReceiver *r, kCapRef cap, unsigned line):
if (unsigned)cap->target & ~KERNEL_MASK:
if cap->target != r:
dpanic (line, "consistency bug in capabilities")
else:
if cap->protected_data.l != (unsigned)r:
2010-01-24 22:34:24 +02:00
kdebug ("Buggy: receiver=")
kdebug_num ((unsigned)r)
kdebug ("; caps=")
kdebug_num ((unsigned)cap.caps)
kdebug ("; caps mem=")
kdebug_num ((unsigned)cap.caps->address_space)
kdebug ("; cap=")
kdebug_num ((unsigned)cap.deref ())
kdebug ("; cap target=")
kdebug_num ((unsigned)cap->target)
kdebug ("; protected=")
kdebug_num (cap->protected_data.l)
kdebug ("!= receiver\n")
2009-10-10 02:31:10 +03:00
dpanic (line, "consistency bug in kernel capabilities")
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
2010-05-01 00:13:49 +03:00
if c->protected_data.value () != cap->protected_data.value () || c->target != cap->target:
dpanic (line, "capability db bug")
2009-10-10 02:31:10 +03:00
check_receiver (r, c, line)
void kReceiver::check (unsigned line):
for kCapRef cap = capabilities; cap.valid (); cap = cap->sibling_next:
check_receiver (this, cap, line)
void kMemory::check (unsigned line):
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
r->check (line)
2010-01-24 22:34:24 +02:00
for kThread *t = threads; t; t = (kThread *)t->next:
2010-05-01 00:13:49 +03:00
if t->flags & Iris::Thread::RUNNING && t->pc == 0:
2010-01-24 22:34:24 +02:00
kdebug_num ((unsigned)t)
kdebug ("\n")
panic (line, "pc is 0")
2009-10-10 02:31:10 +03:00
for kMemory *m = memories; m; m = (kMemory *)m->next:
m->check (line)
static void print_obj (kObject *o):
for kObject *obj = o; o; o = (kObject *)o->next:
2010-01-24 22:34:24 +02:00
kdebug_num ((unsigned)o)
kdebug ("->")
kdebug ("NULL\n")
2009-10-10 02:31:10 +03:00
void kMemory::print (unsigned line, unsigned indent):
if indent == 0:
print_free ()
for unsigned i = 0; i < indent; ++i:
2010-01-24 22:34:24 +02:00
kdebug ('\t')
2009-10-10 02:31:10 +03:00
++indent
2010-01-24 22:34:24 +02:00
kdebug ("Memory ")
kdebug_num ((unsigned)this)
kdebug ("\n")
2009-10-10 02:31:10 +03:00
for unsigned i = 0; i < indent; ++i:
2010-01-24 22:34:24 +02:00
kdebug ('\t')
kdebug ("frees: ")
2009-10-10 02:31:10 +03:00
for kFree *f = frees; f; f = (kFree *)f->next:
2010-01-24 22:34:24 +02:00
kdebug_num ((unsigned)f)
kdebug (":")
2009-10-10 02:31:10 +03:00
unsigned n = (unsigned)NEXT (f)
if n:
n -= (unsigned)f
if n >= PAGE_SIZE:
dpanic (0, "invalid kFree")
2010-01-24 22:34:24 +02:00
kdebug_num (n, 3)
kdebug ("->")
kdebug ("NULL\n")
2009-10-10 02:31:10 +03:00
for unsigned i = 0; i < indent; ++i:
2010-01-24 22:34:24 +02:00
kdebug ('\t')
kdebug ("pages: ")
2009-10-10 02:31:10 +03:00
print_obj (pages)
for unsigned i = 0; i < indent; ++i:
2010-01-24 22:34:24 +02:00
kdebug ('\t')
kdebug ("threads: ")
2009-10-10 02:31:10 +03:00
print_obj (threads)
for unsigned i = 0; i < indent; ++i:
2010-01-24 22:34:24 +02:00
kdebug ('\t')
kdebug ("receivers: ")
2009-10-10 02:31:10 +03:00
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
2010-01-24 22:34:24 +02:00
kdebug_num ((unsigned)r)
kdebug ("(")
2009-10-10 02:31:10 +03:00
for kMessage *m = r->messages; m; m = (kMessage *)m->next:
2010-01-24 22:34:24 +02:00
kdebug_num ((unsigned)m)
kdebug ("->")
kdebug ("NULL)->")
kdebug ("NULL\n")
2009-10-10 02:31:10 +03:00
for unsigned i = 0; i < indent; ++i:
2010-01-24 22:34:24 +02:00
kdebug ('\t')
kdebug ("capses: ")
2009-10-10 02:31:10 +03:00
print_obj (capses)
for kMemory *m = memories; m; m = (kMemory *)m->next:
m->print (line, indent)
void check_impl (kObject *o, unsigned num, char const *msg):
for ; o; o = (kObject *)o->next:
unsigned n = (unsigned)NEXT (o)
unsigned size = n ? n - (unsigned)o : PAGE_SIZE - ((unsigned)o & PAGE_MASK)
if !check_free (o, size):
panic (num, msg)