mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
new directory organization
This commit is contained in:
663
kernel/alloc.ccp
Normal file
663
kernel/alloc.ccp
Normal file
@@ -0,0 +1,663 @@
|
||||
#pypp 0
|
||||
// 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/>.
|
||||
|
||||
#include "kernel.hh"
|
||||
|
||||
// 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.
|
||||
// The PREV/NEXT-list contains all objects in the page, including kFree objects, in the order they appear in the page.
|
||||
// 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.
|
||||
|
||||
#define PREV(x) (((kObject **)(x))[-2])
|
||||
#define NEXT(x) (((kObject **)(x))[-1])
|
||||
// ATTENTION! When changing SIZE, be sure to also change the hard-coded 8 in kernel.hhp which defines MAX_NUM_CAPS.
|
||||
#define SIZE (2 * sizeof (kObject *))
|
||||
|
||||
bool kMemory::use (unsigned num):
|
||||
// Go up to parents, incrementing used.
|
||||
for kMemory *m = this; m; m = m->address_space:
|
||||
if used + num > limit:
|
||||
// Not allowed. Restore used for all children.
|
||||
for kMemory *r = this; r != m; r = r->address_space:
|
||||
r->used -= num
|
||||
return false
|
||||
m->used += num
|
||||
return true
|
||||
|
||||
void kMemory::unuse (unsigned num):
|
||||
for kMemory *m = this; m; m = m->address_space:
|
||||
m->used -= num
|
||||
|
||||
// This allocates a new block of memory for use by the kernel.
|
||||
// size is the required size of the block (excluding SIZE)
|
||||
// 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.
|
||||
void *kMemory::search_free (unsigned size, void **first):
|
||||
kFree *f
|
||||
if size >= PAGE_SIZE - SIZE:
|
||||
panic (size, "requested size is too large")
|
||||
int s = 0
|
||||
// Let's see if there already is a kFree chunk which is large enough.
|
||||
for f = frees; f; f = (kFree *)f->next:
|
||||
if NEXT (f):
|
||||
s = (unsigned)NEXT (f) - (unsigned)f
|
||||
else:
|
||||
s = PAGE_SIZE - ((unsigned)f & ~PAGE_MASK) + SIZE
|
||||
// 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.
|
||||
if s >= size + SIZE:
|
||||
break
|
||||
if !f:
|
||||
// No chunk was found; allocate a new page and add a chunk in it. It is always large enough.
|
||||
unsigned p = palloc ()
|
||||
if !p:
|
||||
kdebug ("no free space: kernel allocation failed")
|
||||
return NULL
|
||||
f = (kFree *)(p + SIZE)
|
||||
// Mark it as a kFree object.
|
||||
f->marker = ~0
|
||||
// Link it in the kFree list.
|
||||
f->next = frees
|
||||
f->prev = NULL
|
||||
frees = f
|
||||
if f->next:
|
||||
((kFree *)f->next)->prev = f
|
||||
// There are no other objects in this page.
|
||||
NEXT (f) = NULL
|
||||
PREV (f) = NULL
|
||||
// The size of this block is the entire page.
|
||||
s = PAGE_SIZE
|
||||
// We have a free block, possibly too large. The block is linked in frees, and in the page.
|
||||
if s >= size + sizeof (kFree) + 2 * SIZE:
|
||||
// Create the new object at the end and keep the Free.
|
||||
// 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.
|
||||
kFree *obj = (kFree *)((unsigned)f + (s - SIZE) - size)
|
||||
// Link the new object in the page.
|
||||
NEXT (obj) = NEXT (f)
|
||||
if NEXT (obj):
|
||||
PREV (NEXT (obj)) = obj
|
||||
PREV (obj) = f
|
||||
NEXT (f) = obj
|
||||
// Set f to the new object, because it is used by that name later.
|
||||
f = obj
|
||||
else:
|
||||
// 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.
|
||||
if f->prev:
|
||||
((kFree *)f->prev)->next = f->next
|
||||
else:
|
||||
frees = (kFree *)f->next
|
||||
if f->next:
|
||||
((kFree *)f->next)->prev = f->prev
|
||||
// f is now a block which is linked in the page, but not in any list. Link it into first.
|
||||
f->next = (kFree *)*first
|
||||
f->prev = NULL
|
||||
if f->next:
|
||||
((kFree *)f->next)->prev = f
|
||||
*first = f
|
||||
// Set common initial values.
|
||||
f->address_space = this
|
||||
f->refs.reset ()
|
||||
return f
|
||||
|
||||
// Free an object; it is still in its list, and it is still in the page list.
|
||||
void kMemory::free_obj (kObject *obj, kPointer *first):
|
||||
kFree *self = (kFree *)obj
|
||||
// Invalidate references.
|
||||
while self->refs.valid ():
|
||||
self->refs->invalidate ()
|
||||
// Free it from its list.
|
||||
if self->prev:
|
||||
((kFree *)self->prev)->next = self->next
|
||||
else:
|
||||
*(kPointer *)first = (kPointer)self->next
|
||||
if self->next:
|
||||
((kFree *)self->next)->prev = self->prev
|
||||
// Merge with previous, if it exists and is a kFree.
|
||||
if PREV (self) && PREV (self)->is_free ():
|
||||
self = (kFree *)PREV (self)
|
||||
// Remove the object from the page list.
|
||||
NEXT (self) = NEXT (obj)
|
||||
if NEXT (self):
|
||||
PREV (NEXT (self)) = self
|
||||
else:
|
||||
// The previous object is not a kFree, so create a new one.
|
||||
// It is already linked in the page, but needs to be linked into the free list.
|
||||
self->next = frees
|
||||
self->prev = NULL
|
||||
if self->next:
|
||||
((kFree *)self->next)->prev = self
|
||||
frees = self
|
||||
// Mark it as a kFree.
|
||||
self->marker = ~0
|
||||
// Merge with next, if it exists and is a kFree.
|
||||
if NEXT (self) && NEXT (self)->is_free ():
|
||||
// Unlink the next from the frees list.
|
||||
kFree *n = (kFree *)NEXT (self)
|
||||
if n->prev:
|
||||
((kFree *)n->prev)->next = n->next
|
||||
else:
|
||||
frees = (kFree *)n->next
|
||||
if n->next:
|
||||
((kFree *)n->next)->prev = n->prev
|
||||
// Unlink the next from the page list.
|
||||
NEXT (self) = NEXT (NEXT (self))
|
||||
if NEXT (self):
|
||||
PREV (NEXT (self)) = self
|
||||
// Free page if the resulting object is the only thing in it.
|
||||
if !PREV (self) && !NEXT (self):
|
||||
if self->next:
|
||||
((kFree *)self->next)->prev = self->prev
|
||||
if self->prev:
|
||||
((kFree *)self->prev)->next = self->next
|
||||
else:
|
||||
frees = (kFree *)self->next
|
||||
//kdebug ("freeing page: ")
|
||||
//kdebug_num ((unsigned)self - SIZE)
|
||||
//kdebug ("\n")
|
||||
pfree ((unsigned)self - SIZE)
|
||||
|
||||
kPage *kMemory::alloc_page ():
|
||||
kPage *ret = (kPage *)search_free (sizeof (kPage), (void **)&pages)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->frame = 0
|
||||
ret->flags = 0
|
||||
ret->mapping = ~0
|
||||
ret->share_prev = NULL
|
||||
ret->share_next = NULL
|
||||
kPage_arch_init (ret)
|
||||
return ret
|
||||
|
||||
kThread *kMemory::alloc_thread (unsigned size):
|
||||
kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kThread::caps_store), (void **)&threads)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->receivers = NULL
|
||||
ret->pc = 0
|
||||
ret->sp = 0
|
||||
kThread_arch_init (ret)
|
||||
ret->flags = 0
|
||||
ret->id = ~0
|
||||
ret->schedule_prev = NULL
|
||||
ret->schedule_next = NULL
|
||||
ret->slots = size
|
||||
for unsigned i = 0; i < size; ++i:
|
||||
ret->slot[i].prev.thread = NULL
|
||||
ret->slot[i].next.thread = NULL
|
||||
ret->slot[i].caps = NULL
|
||||
//kdebug ("new thread: ")
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void kCaps::init (unsigned s):
|
||||
first_slot.thread = NULL
|
||||
size = s
|
||||
for unsigned i = 0; i < s; ++i:
|
||||
set (i, NULL, 0, kCapRef (), NULL)
|
||||
|
||||
kCaps *kMemory::alloc_caps (unsigned size):
|
||||
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)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->init (size)
|
||||
//kdebug ("allocate caps ")
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ('+')
|
||||
//kdebug_num (size)
|
||||
//kdebug ('\n')
|
||||
return ret
|
||||
|
||||
kMessage *kMemory::alloc_message (kReceiver *target):
|
||||
kMessage *ret = (kMessage *)search_free (sizeof (kMessage) + sizeof (kCapability), (void **)&target->messages)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->caps.init (2)
|
||||
if !ret->next:
|
||||
target->last_message = ret
|
||||
return ret
|
||||
|
||||
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
|
||||
|
||||
kReceiver *kMemory::alloc_receiver ():
|
||||
kReceiver *ret = (kReceiver *)search_free (sizeof (kReceiver), (void **)&receivers)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->owner = NULL
|
||||
ret->prev_owned = NULL
|
||||
ret->next_owned = NULL
|
||||
ret->alarm_count = ~0
|
||||
ret->caps = NULL
|
||||
ret->capabilities.reset ()
|
||||
ret->messages = NULL
|
||||
ret->last_message = NULL
|
||||
ret->reply_protected_data = ~0
|
||||
ret->protected_only = false
|
||||
ret->queue_limit = ~0
|
||||
return ret
|
||||
|
||||
kMemory *kMemory::alloc_memory ():
|
||||
kMemory *ret = (kMemory *)search_free (sizeof (kMemory), (void **)&memories)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->frees = NULL
|
||||
ret->pages = NULL
|
||||
ret->threads = NULL
|
||||
ret->capses = NULL
|
||||
ret->receivers = NULL
|
||||
ret->memories = NULL
|
||||
ret->limit = ~0
|
||||
ret->used = 0
|
||||
kMemory_arch_init (ret)
|
||||
return ret
|
||||
|
||||
void kCaps::set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
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 ()
|
||||
if parent.valid ():
|
||||
c->sibling_next = parent->children
|
||||
parent->children = kCapRef (this, index)
|
||||
else:
|
||||
if parent_ptr:
|
||||
c->sibling_next = *parent_ptr
|
||||
*parent_ptr = kCapRef (this, index)
|
||||
else:
|
||||
c->sibling_next.reset ()
|
||||
if c->sibling_next.valid ():
|
||||
c->sibling_next->sibling_prev = kCapRef (this, index)
|
||||
|
||||
void kCaps::clone (unsigned index, kCapRef source, bool copy):
|
||||
cap (index)->invalidate ()
|
||||
if !source.valid ():
|
||||
return
|
||||
if copy:
|
||||
if source->parent.valid ():
|
||||
set (index, source->target, source->protected_data, source->parent)
|
||||
else if (unsigned)source->target & ~KERNEL_MASK:
|
||||
set (index, source->target, source->protected_data, kCapRef (), &source->target->capabilities)
|
||||
else:
|
||||
set (index, source->target, source->protected_data, kCapRef (), &((kObject *)source->protected_data.l)->refs)
|
||||
else:
|
||||
set (index, source->target, source->protected_data, source)
|
||||
|
||||
void kMemory::free_page (kPage *page):
|
||||
if page->mapping != ~0:
|
||||
page->address_space->unmap (page)
|
||||
page->forget ()
|
||||
if page->flags & Iris::Page::PAYING:
|
||||
unuse ()
|
||||
free_obj (page, (kPointer *)&pages)
|
||||
|
||||
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
|
||||
|
||||
void kMemory::free_thread (kThread *thread):
|
||||
thread->unrun ()
|
||||
while thread->receivers:
|
||||
thread->receivers->orphan ()
|
||||
for unsigned i = 0; i < thread->slots; ++i:
|
||||
thread->unset_slot (i)
|
||||
free_obj (thread, (void **)&threads)
|
||||
if old_current == thread:
|
||||
old_current = NULL
|
||||
|
||||
void kMemory::free_message (kReceiver *owner, kMessage *message):
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
message->caps.cap (i)->invalidate ()
|
||||
if !message->next:
|
||||
owner->last_message = (kMessageP)message->prev
|
||||
free_obj (message, (void **)&owner->messages)
|
||||
|
||||
void kMemory::free_receiver (kReceiver *receiver):
|
||||
receiver->orphan ()
|
||||
while receiver->capabilities.valid ():
|
||||
receiver->capabilities->invalidate ()
|
||||
while receiver->messages:
|
||||
free_message (receiver, receiver->messages)
|
||||
free_obj (receiver, (void **)&receivers)
|
||||
|
||||
void kReceiver::orphan ():
|
||||
if prev_owned:
|
||||
prev_owned->next_owned = next_owned
|
||||
else if owner:
|
||||
owner->receivers = next_owned
|
||||
if next_owned:
|
||||
next_owned->prev_owned = prev_owned
|
||||
owner = NULL
|
||||
|
||||
void kReceiver::own (kThread *o):
|
||||
if owner:
|
||||
orphan ()
|
||||
owner = o
|
||||
next_owned = o->receivers
|
||||
if next_owned:
|
||||
next_owned->prev_owned = this
|
||||
o->receivers = this
|
||||
|
||||
void kCapability::invalidate ():
|
||||
if !target:
|
||||
return
|
||||
//kdebug_num ((unsigned)this)
|
||||
//kdebug ("\n")
|
||||
//kdebug_num ((unsigned)target)
|
||||
//kdebug (":")
|
||||
//kdebug_num ((unsigned)protected_data.l)
|
||||
//kdebug ("\n")
|
||||
if (unsigned)this == dbg_code.h:
|
||||
dpanic (0, "invalidating watched capability")
|
||||
if sibling_prev.valid ():
|
||||
sibling_prev->sibling_next = sibling_next
|
||||
else if parent.valid ():
|
||||
parent->children = sibling_next
|
||||
else if (unsigned)target & ~KERNEL_MASK:
|
||||
target->capabilities = sibling_next
|
||||
else:
|
||||
((kObject *)protected_data.l)->refs = sibling_next
|
||||
if sibling_next.valid ():
|
||||
sibling_next->sibling_prev = sibling_prev
|
||||
parent.reset ()
|
||||
sibling_prev.reset ()
|
||||
sibling_next.reset ()
|
||||
kCapability *c = this
|
||||
while c:
|
||||
while c->children.valid ():
|
||||
c = c->children.deref ()
|
||||
kCapability *next = c->sibling_next.deref ()
|
||||
if !next:
|
||||
next = c->parent.deref ()
|
||||
c->target = NULL
|
||||
if c->parent.valid ():
|
||||
c->parent->children = c->sibling_next
|
||||
c->parent.reset ()
|
||||
c->children.reset ()
|
||||
c->sibling_prev.reset ()
|
||||
c->sibling_next.reset ()
|
||||
c->protected_data = 0
|
||||
c = next
|
||||
|
||||
void kMemory::free_caps (kCaps *c):
|
||||
//kdebug ("free caps ")
|
||||
//kdebug_num ((unsigned)c)
|
||||
//kdebug ('\n')
|
||||
for unsigned i = 0; i < c->size; ++i:
|
||||
c->cap (i)->invalidate ()
|
||||
while c->first_slot.thread:
|
||||
c->first_slot.thread->unset_slot (c->first_slot.index)
|
||||
free_obj (c, (void **)&capses)
|
||||
|
||||
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)
|
||||
|
||||
void kMemory::free_memory (kMemory *mem):
|
||||
while mem->pages:
|
||||
//kdebug ("freeing page ")
|
||||
//kdebug_num ((unsigned)mem->pages)
|
||||
//kdebug (", next = ")
|
||||
//kdebug_num ((unsigned)mem->pages->next)
|
||||
//kdebug ("\n")
|
||||
mem->free_page (mem->pages)
|
||||
while mem->capses:
|
||||
mem->free_caps (mem->capses)
|
||||
while mem->threads:
|
||||
mem->free_thread (mem->threads)
|
||||
while mem->memories:
|
||||
mem->free_memory (mem->memories)
|
||||
while mem->receivers:
|
||||
mem->free_receiver (mem->receivers)
|
||||
while mem->lists:
|
||||
mem->free_list (mem->lists)
|
||||
while mem->listitems:
|
||||
mem->free_listitem (mem->listitems)
|
||||
if mem->frees:
|
||||
panic (0, "kernel memory leak: memory still in use")
|
||||
free_obj (mem, (void **)&memories)
|
||||
|
||||
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
|
||||
for p = share_prev, next = (p ? p->share_prev : NULL); p; p = next, next = p ? p->share_prev : NULL:
|
||||
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)
|
||||
|
||||
void kPage::forget ():
|
||||
if share_prev || share_next:
|
||||
if share_prev:
|
||||
share_prev->share_next = share_next
|
||||
if share_next:
|
||||
share_next->share_prev = share_prev
|
||||
share_next->check_payment ()
|
||||
else:
|
||||
share_prev->check_payment ()
|
||||
share_prev = NULL
|
||||
share_next = NULL
|
||||
else:
|
||||
// If the page has a frame and should be freed, free it.
|
||||
if !((flags ^ Iris::Page::FRAME) & (Iris::Page::PHYSICAL | Iris::Page::FRAME)):
|
||||
raw_pfree (frame)
|
||||
frame = 0
|
||||
flags &= ~(Iris::Page::FRAME | Iris::Page::SHARED | Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
|
||||
kPage_arch_update_mapping (this)
|
||||
|
||||
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:
|
||||
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")
|
||||
dpanic (line, "consistency bug in kernel capabilities")
|
||||
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
||||
if c->protected_data.value () != cap->protected_data.value () || c->target != cap->target:
|
||||
dpanic (line, "capability db bug")
|
||||
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)
|
||||
for kThread *t = threads; t; t = (kThread *)t->next:
|
||||
if t->flags & Iris::Thread::RUNNING && t->pc == 0:
|
||||
kdebug_num ((unsigned)t)
|
||||
kdebug ("\n")
|
||||
panic (line, "pc is 0")
|
||||
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:
|
||||
kdebug_num ((unsigned)o)
|
||||
kdebug ("->")
|
||||
kdebug ("NULL\n")
|
||||
|
||||
void kMemory::print (unsigned line, unsigned indent):
|
||||
if indent == 0:
|
||||
print_free ()
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug ('\t')
|
||||
++indent
|
||||
kdebug ("Memory ")
|
||||
kdebug_num ((unsigned)this)
|
||||
kdebug ("\n")
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug ('\t')
|
||||
kdebug ("frees: ")
|
||||
for kFree *f = frees; f; f = (kFree *)f->next:
|
||||
kdebug_num ((unsigned)f)
|
||||
kdebug (":")
|
||||
unsigned n = (unsigned)NEXT (f)
|
||||
if n:
|
||||
n -= (unsigned)f
|
||||
if n >= PAGE_SIZE:
|
||||
dpanic (0, "invalid kFree")
|
||||
kdebug_num (n, 3)
|
||||
kdebug ("->")
|
||||
kdebug ("NULL\n")
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug ('\t')
|
||||
kdebug ("pages: ")
|
||||
print_obj (pages)
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug ('\t')
|
||||
kdebug ("threads: ")
|
||||
print_obj (threads)
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug ('\t')
|
||||
kdebug ("receivers: ")
|
||||
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
|
||||
kdebug_num ((unsigned)r)
|
||||
kdebug ("(")
|
||||
for kMessage *m = r->messages; m; m = (kMessage *)m->next:
|
||||
kdebug_num ((unsigned)m)
|
||||
kdebug ("->")
|
||||
kdebug ("NULL)->")
|
||||
kdebug ("NULL\n")
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug ('\t')
|
||||
kdebug ("capses: ")
|
||||
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)
|
||||
27
kernel/data.ccp
Normal file
27
kernel/data.ccp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// data.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/>.
|
||||
|
||||
// All variables are defined in kernel.hhp as "EXTERN", which is normally
|
||||
// defined as "extern". By defining it empty, space is allocated for them.
|
||||
// This must happen exactly once in all files linked into the kernel.
|
||||
#define EXTERN
|
||||
#include "kernel.hh"
|
||||
|
||||
// This is needed to make gcc compile c++ code without its standard library.
|
||||
char __gxx_personality_v0[] = "hack"
|
||||
|
||||
1071
kernel/invoke.ccp
Normal file
1071
kernel/invoke.ccp
Normal file
File diff suppressed because it is too large
Load Diff
271
kernel/memory.ccp
Normal file
271
kernel/memory.ccp
Normal file
@@ -0,0 +1,271 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// memory.ccp: Page allocation system.
|
||||
// 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/>.
|
||||
|
||||
#include "kernel.hh"
|
||||
//#define DEBUG_ALLOC
|
||||
|
||||
extern unsigned _end
|
||||
|
||||
static void clear_page (unsigned page, unsigned num = 1):
|
||||
#ifdef DEBUG_ALLOC
|
||||
kdebug ("clearing page ")
|
||||
kdebug_num (page)
|
||||
kdebug ("+")
|
||||
kdebug_num (num << PAGE_BITS)
|
||||
kdebug ('\n')
|
||||
#endif
|
||||
page = (page & ~0xc0000000) | 0xa0000000
|
||||
for unsigned p = 0; p < num; ++p:
|
||||
arch_uncache_page (page - 0x20000000 + (p << PAGE_BITS))
|
||||
for unsigned i = 0; i < (1 << (PAGE_BITS - 2)); ++i:
|
||||
// Clear page.
|
||||
((unsigned *)page)[(p << PAGE_BITS - 2) + i] = 0
|
||||
if *(unsigned *)page != 0 || ((unsigned *)page)[(num << (PAGE_BITS - 2)) - 1] != 0:
|
||||
kdebug_num ((num << (PAGE_BITS - 2)) - 1)
|
||||
kdebug ("/")
|
||||
kdebug_num (((unsigned *)page)[(num << (PAGE_BITS - 2)) - 1])
|
||||
kdebug (",")
|
||||
kdebug_num (*(unsigned *)page)
|
||||
kdebug ("\n")
|
||||
dpanic (0, "clear_page didn't work")
|
||||
|
||||
#if 0
|
||||
|
||||
static unsigned free_begin
|
||||
static unsigned free_end
|
||||
|
||||
unsigned init_memory (unsigned mem):
|
||||
free_begin = ((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK
|
||||
free_end = (0x80000000 + mem) & PAGE_MASK
|
||||
return (free_end - free_begin) >> PAGE_BITS
|
||||
|
||||
unsigned phys_alloc (unsigned num):
|
||||
if free_begin + num * PAGE_SIZE > free_end:
|
||||
kdebug ("memory allocation failed\n")
|
||||
return 0
|
||||
unsigned ret = free_begin
|
||||
free_begin += num * PAGE_SIZE
|
||||
clear_page (ret, num)
|
||||
return ret
|
||||
|
||||
void phys_free (unsigned page, unsigned num):
|
||||
// Not supported.
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*void check_impl (kObject *o, unsigned num, char const *msg):
|
||||
// for ; o; o = (kObject *)o->next:
|
||||
// if (unsigned)o >= (unsigned)free_begin && (unsigned)o < (unsigned)free_end:
|
||||
*/ // panic (num, msg)
|
||||
bool check_free (kObject *o, unsigned size):
|
||||
return true
|
||||
void print_free ():
|
||||
#endif
|
||||
#else
|
||||
|
||||
struct kFreePages:
|
||||
kFreePages *prev, *next
|
||||
unsigned num
|
||||
|
||||
static kFreePages *first_free
|
||||
|
||||
unsigned init_memory (unsigned mem):
|
||||
first_free = (kFreePages *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
|
||||
first_free->prev = NULL
|
||||
first_free->next = NULL
|
||||
first_free->num = ((mem & PAGE_MASK) - ((unsigned)first_free & ~0xc0000000)) >> PAGE_BITS
|
||||
#ifdef DEBUG_ALLOC
|
||||
kdebug ("initial memory: ")
|
||||
kdebug_num ((unsigned)first_free & ~0xc0000000)
|
||||
kdebug ("+")
|
||||
kdebug_num (first_free->num)
|
||||
kdebug ("\n")
|
||||
#endif
|
||||
return first_free->num
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
static bool is_free (unsigned page):
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
if page >= (unsigned)p && page < (unsigned)p + (p->num << PAGE_BITS):
|
||||
return true
|
||||
return false
|
||||
#endif
|
||||
|
||||
unsigned phys_alloc (unsigned num):
|
||||
kFreePages *choice = NULL
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
if p->num < num:
|
||||
continue
|
||||
if choice && choice->num < p->num:
|
||||
continue
|
||||
if p->num == num:
|
||||
if p->prev:
|
||||
p->prev->next = p->next
|
||||
else:
|
||||
first_free = p->next
|
||||
if p->next:
|
||||
p->next->prev = p->prev
|
||||
clear_page ((unsigned)p, num)
|
||||
#ifdef DEBUG_ALLOC
|
||||
kdebug ("allocating ")
|
||||
kdebug_num ((unsigned)p & ~0xc0000000)
|
||||
kdebug ("+")
|
||||
kdebug_num (num << PAGE_BITS)
|
||||
kdebug ("\n")
|
||||
if is_free ((unsigned)p):
|
||||
panic ((unsigned)p, "page still free after allocation")
|
||||
#endif
|
||||
return (unsigned)p
|
||||
choice = p
|
||||
if !choice:
|
||||
// TODO: reorganizing may work to allow allocation.
|
||||
dpanic (0x03948859, "range memory allocation failed")
|
||||
return 0
|
||||
choice->num -= num
|
||||
unsigned ret = (unsigned)choice + (choice->num << PAGE_BITS)
|
||||
clear_page (ret, num)
|
||||
#ifdef DEBUG_ALLOC
|
||||
kdebug ("allocating ")
|
||||
kdebug_num (ret & ~0xc0000000)
|
||||
kdebug ("+")
|
||||
kdebug_num (num << PAGE_BITS)
|
||||
kdebug ("\n")
|
||||
if is_free (ret):
|
||||
panic (ret, "page still free after allocation")
|
||||
#endif
|
||||
return ret
|
||||
|
||||
void phys_free (unsigned page, unsigned num):
|
||||
#ifdef DEBUG_ALLOC
|
||||
kdebug ("free ")
|
||||
kdebug_num (page & ~0xc0000000)
|
||||
kdebug ("+")
|
||||
kdebug_num (num << PAGE_BITS)
|
||||
kdebug ("\n")
|
||||
if is_free (page):
|
||||
panic (page, "page already free")
|
||||
#endif
|
||||
unsigned size = num << PAGE_BITS
|
||||
if !first_free || (unsigned)first_free > page:
|
||||
// This is the first free block.
|
||||
kFreePages *n = (kFreePages *)page
|
||||
n->prev = NULL
|
||||
if (unsigned)first_free == page + size:
|
||||
// It fits exactly before the previous first free block.
|
||||
n->next = first_free->next
|
||||
n->num = num + first_free->num
|
||||
else:
|
||||
// It is a new block.
|
||||
n->next = first_free
|
||||
n->num = num
|
||||
first_free = n
|
||||
if n->next:
|
||||
n->next->prev = n
|
||||
return
|
||||
kFreePages *p
|
||||
for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
|
||||
// Do nothing.
|
||||
if p == p->next:
|
||||
dpanic (0, "page is its own next")
|
||||
// The new block should be inserted directly after p.
|
||||
if (unsigned)p->next == page + size:
|
||||
// It can be merged with the block after it: do that.
|
||||
kFreePages *n = (kFreePages *)page
|
||||
n->prev = p
|
||||
n->next = p->next->next
|
||||
if n->next:
|
||||
n->next->prev = n
|
||||
n->num = num + p->next->num
|
||||
p->next = n
|
||||
if (unsigned)p + (p->num << PAGE_BITS) == (unsigned)n:
|
||||
// It can also be merged with the page before it: do that as well.
|
||||
p->num += n->num
|
||||
p->next = n->next
|
||||
if p->next:
|
||||
p->next->prev = p
|
||||
return
|
||||
// The new block cannot be merged with the block after it.
|
||||
if (unsigned)p + (p->num << PAGE_BITS) == page:
|
||||
// But it can be merged with the one before it: do that.
|
||||
p->num += num
|
||||
return
|
||||
// The new block cannot be merged at all.
|
||||
kFreePages *n = (kFreePages *)page
|
||||
n->next = p->next
|
||||
n->prev = p
|
||||
if n->next:
|
||||
n->next->prev = n
|
||||
p->next = n
|
||||
n->num = num
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool check_free (kObject *o, unsigned size):
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
if (unsigned)o + size > (unsigned)p && (unsigned)o < (unsigned)p + p->num * PAGE_SIZE:
|
||||
return false
|
||||
return true
|
||||
|
||||
void print_free ():
|
||||
kdebug ("Free pages: ")
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
kdebug_num ((unsigned)p)
|
||||
kdebug (":")
|
||||
kdebug_num (p->num, 4)
|
||||
kdebug ("->")
|
||||
kdebug ("NULL\n")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check_memory (kMemory *mem, unsigned num, char const *msg):
|
||||
check_impl (mem->pages, num, msg)
|
||||
check_impl (mem->threads, num, msg)
|
||||
check_impl (mem->receivers, num, msg)
|
||||
for kReceiver *r = mem->receivers; r; r = (kReceiver *)r->next:
|
||||
check_impl (r->messages, num, msg)
|
||||
check_impl (mem->capses, num, msg)
|
||||
check_impl (mem->memories, num, msg)
|
||||
for kMemory *m = mem->memories; m; m = (kMemory *)m->next:
|
||||
check_memory (m, num, msg)
|
||||
|
||||
void check (unsigned num, char const *msg):
|
||||
check_memory (&top_memory, num, msg)
|
||||
top_memory.check (num)
|
||||
#endif
|
||||
|
||||
unsigned raw_zalloc ():
|
||||
return phys_alloc (1)
|
||||
|
||||
void raw_pfree (unsigned page):
|
||||
return phys_free (page, 1)
|
||||
|
||||
unsigned kMemory::zalloc ():
|
||||
if !use ():
|
||||
dpanic (0x34638920, "limit reached: allocation not allowed")
|
||||
kdebug ("limit reached: allocation not allowed\n")
|
||||
return NULL
|
||||
return raw_zalloc ()
|
||||
|
||||
void kMemory::pfree (unsigned page):
|
||||
unuse ()
|
||||
return raw_pfree (page)
|
||||
|
||||
unsigned kMemory::palloc ():
|
||||
return zalloc ()
|
||||
|
||||
void kMemory::zfree (unsigned page):
|
||||
pfree (page)
|
||||
247
kernel/panic.ccp
Normal file
247
kernel/panic.ccp
Normal file
@@ -0,0 +1,247 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// panic.ccp: Stop running and try to notify the user of the problem.
|
||||
// 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/>.
|
||||
|
||||
#define ARCH
|
||||
#include "kernel.hh"
|
||||
|
||||
#ifdef USE_SERIAL
|
||||
void kdebug (unsigned ch):
|
||||
while !(UART0_LSR & UARTLSR_TDRQ):
|
||||
UART0_TDR = ch
|
||||
#else
|
||||
void kdebug (unsigned ch):
|
||||
if !dbg_cap.valid () || dbg_code.l:
|
||||
return
|
||||
kCapability::Context c
|
||||
c.data[0] = ch
|
||||
++dbg_code.l
|
||||
dbg_cap->invoke (&c)
|
||||
--dbg_code.l
|
||||
#endif
|
||||
|
||||
void kdebug (char const *str):
|
||||
while *str:
|
||||
kdebug (*str++)
|
||||
|
||||
void kdebug_num (unsigned num, unsigned digits):
|
||||
char const *encode = "0123456789abcdef"
|
||||
for unsigned i = 0; i < digits; ++i:
|
||||
kdebug (encode[(num >> (4 * ((digits - 1) - i))) & 0xf])
|
||||
return
|
||||
|
||||
#if 1 || defined (NDEBUG)
|
||||
static void print_addr (char const *t, unsigned addr, bool last = false):
|
||||
kdebug (t)
|
||||
kdebug_num (addr)
|
||||
#if 0
|
||||
unsigned de = addr >> 21
|
||||
unsigned te = (addr >> 12) & ((1 << 9) - 1)
|
||||
if de < 0x400 && old_current && old_current->address_space->arch.directory && old_current->address_space->arch.directory[de]:
|
||||
kdebug ("; EntryLo = ")
|
||||
kdebug_num (old_current->address_space->arch.directory[de]->entrylo[te])
|
||||
else:
|
||||
kdebug ("; no directory or page table")
|
||||
if old_current && de < 0x400:
|
||||
cp0_set (CP0_ENTRY_HI, (addr & (PAGE_MASK << 1)) | old_current->address_space->arch.asid)
|
||||
__asm__ volatile ("tlbp")
|
||||
unsigned idx, hi
|
||||
cp0_get (CP0_INDEX, idx)
|
||||
kdebug ("; tlb index: ")
|
||||
if idx & (1 << 31):
|
||||
kdebug ("none\n")
|
||||
else:
|
||||
__asm__ volatile ("tlbr")
|
||||
kdebug_num (idx, 2)
|
||||
kdebug ("; EntryLo = ")
|
||||
unsigned lo
|
||||
cp0_get (CP0_ENTRY_LO0, lo)
|
||||
kdebug_num (lo)
|
||||
kdebug (":")
|
||||
cp0_get (CP0_ENTRY_LO1, lo)
|
||||
kdebug_num (lo)
|
||||
kdebug ("\n")
|
||||
else:
|
||||
kdebug ('\n')
|
||||
if addr >= 0x80000000 && addr < 0xc0000000:
|
||||
for int i = -4; i < 4; ++i:
|
||||
kdebug (" ")
|
||||
kdebug_num (((unsigned *)addr)[i])
|
||||
kdebug ("\n")
|
||||
#else
|
||||
kdebug (last ? "\n" : "; ")
|
||||
#endif
|
||||
|
||||
static void panic_message (unsigned n, const char *line, char const *name, char const *message):
|
||||
kdebug ("**********************************************************************\n")
|
||||
unsigned vaddr, epc
|
||||
cp0_get (CP0_BAD_V_ADDR, vaddr)
|
||||
cp0_get (CP0_EPC, epc)
|
||||
#if 1
|
||||
unsigned addr
|
||||
print_addr ("BadVAddr: ", vaddr)
|
||||
if old_current:
|
||||
print_addr ("PC: ", old_current->pc)
|
||||
print_addr ("epc: ", epc, true)
|
||||
#endif
|
||||
kdebug ("Panic: caller = ")
|
||||
if old_current:
|
||||
kdebug_num (old_current->id, 2)
|
||||
kdebug (":")
|
||||
kdebug_num ((unsigned)old_current)
|
||||
if old_current:
|
||||
kdebug ('@')
|
||||
kdebug_num (old_current->pc)
|
||||
kdebug ("\nregisters: sp=")
|
||||
kdebug_num (old_current->sp)
|
||||
kdebug (" at=")
|
||||
kdebug_num (old_current->arch.at)
|
||||
kdebug ("\nv=")
|
||||
kdebug_num (old_current->arch.v[0])
|
||||
kdebug (" ")
|
||||
kdebug_num (old_current->arch.v[1])
|
||||
kdebug ("\na=")
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
kdebug_num (old_current->arch.a[i])
|
||||
kdebug (" ")
|
||||
kdebug ("\nt=")
|
||||
for unsigned i = 0; i < 10; ++i:
|
||||
kdebug_num (old_current->arch.t[i])
|
||||
kdebug (" ")
|
||||
kdebug ("\ns=")
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
kdebug_num (old_current->arch.s[i])
|
||||
kdebug (" ")
|
||||
kdebug ("\ngp=")
|
||||
kdebug_num (old_current->arch.gp)
|
||||
kdebug (" fp=")
|
||||
kdebug_num (old_current->arch.fp)
|
||||
kdebug (" ra=")
|
||||
kdebug_num (old_current->arch.ra)
|
||||
kdebug ("\nhi=")
|
||||
kdebug_num (old_current->arch.hi)
|
||||
kdebug (" lo=")
|
||||
kdebug_num (old_current->arch.lo)
|
||||
kdebug ('\n')
|
||||
kdebug ("Directory: ")
|
||||
kdebug_num ((unsigned)directory)
|
||||
kdebug ("; ")
|
||||
kdebug (name)
|
||||
kdebug (':')
|
||||
kdebug (line)
|
||||
kdebug (": ")
|
||||
kdebug (message)
|
||||
kdebug ('/')
|
||||
kdebug_num (n)
|
||||
kdebug ("; debug: ")
|
||||
kdebug_num (dbg_code.h)
|
||||
kdebug (':')
|
||||
kdebug_num (dbg_code.l)
|
||||
kdebug ('\n')
|
||||
kdebug ("debug buffer (most recently pushed at end):")
|
||||
unsigned b = dbg_buffer_head
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
kdebug ('\n')
|
||||
for unsigned j = 0; j < 4; ++j:
|
||||
kdebug (' ')
|
||||
kdebug_num (dbg_buffer[b])
|
||||
++b
|
||||
if b == 32:
|
||||
b = 0
|
||||
kdebug ('\n')
|
||||
if old_current:
|
||||
kdebug ("Attempt to print *pc:\n")
|
||||
unsigned page = old_current->pc & PAGE_MASK
|
||||
unsigned start = old_current->pc & ~(4 * 4 - 1)
|
||||
for int i = -4; i < 8; ++i:
|
||||
kdebug_num (start + i * 4 * 4)
|
||||
kdebug (" ==>")
|
||||
for unsigned j = 0; j < 4; ++j:
|
||||
kdebug (' ')
|
||||
unsigned addr = start + (i * 4 + j) * 4
|
||||
if (addr & PAGE_MASK) == page:
|
||||
kdebug_num (*(unsigned *)addr)
|
||||
else:
|
||||
kdebug ("--------")
|
||||
kdebug ('\n')
|
||||
|
||||
void panic_impl (unsigned n, const char *line, char const *name, char const *message):
|
||||
// Stop all threads.
|
||||
while first_scheduled:
|
||||
first_scheduled->unrun ()
|
||||
for kReceiver *r = first_alarm; r; r = r->next_alarm:
|
||||
if r->owner:
|
||||
r->owner->unrun ()
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
if arch_interrupt_receiver[i] && arch_interrupt_receiver[i]->owner:
|
||||
arch_interrupt_receiver[i]->owner->unrun ()
|
||||
#ifndef NDEBUG
|
||||
panic_message (n, line, name, message)
|
||||
// If a log capability is registered, run its owner.
|
||||
#ifndef USE_SERIAL
|
||||
if dbg_cap.valid () && dbg_cap->target->owner:
|
||||
dbg_cap->target->owner->run ()
|
||||
// Use the (now running) log thread to display the message.
|
||||
// If no log capability is registered, the machine just hangs.
|
||||
#else
|
||||
arch_reboot ()
|
||||
#endif
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
void dbg_send (unsigned num, unsigned bits):
|
||||
kdebug ("Warning: ")
|
||||
kdebug_num (num)
|
||||
kdebug ('/')
|
||||
kdebug_num (bits)
|
||||
kdebug ('\n')
|
||||
#endif
|
||||
#else
|
||||
void delay (unsigned ms):
|
||||
for unsigned t = 0; t < 8000 * ms; ++t:
|
||||
GPIO_GPDIR (0) = GPIO_GPDIR (0)
|
||||
|
||||
void set_leds (bool a, bool b):
|
||||
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
|
||||
gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
|
||||
if a:
|
||||
GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
|
||||
if b:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
|
||||
|
||||
void dbg_send (unsigned n, unsigned bits):
|
||||
for unsigned i = 0; i < bits; ++i:
|
||||
bool v = n & (1 << (bits - 1))
|
||||
set_leds (v, !v)
|
||||
delay (350)
|
||||
set_leds (false, false)
|
||||
delay (150)
|
||||
n <<= 1
|
||||
set_leds (true, true)
|
||||
delay (50)
|
||||
set_leds (false, false)
|
||||
delay (50)
|
||||
void panic_impl (unsigned n, const char *line, char const *name, char const *message):
|
||||
unsigned epc
|
||||
cp0_get (CP0_EPC, epc)
|
||||
dbg_send (epc, 32)
|
||||
while true:
|
||||
dbg_send (n, 32)
|
||||
#endif
|
||||
96
kernel/schedule.ccp
Normal file
96
kernel/schedule.ccp
Normal file
@@ -0,0 +1,96 @@
|
||||
#pypp 0
|
||||
// vim: set filetype=cpp : //
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// schedule.ccp: Thread scheduling.
|
||||
// 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/>.
|
||||
|
||||
#include "kernel.hh"
|
||||
|
||||
static void run_thread (kThread *thread):
|
||||
thread->schedule_next = first_scheduled
|
||||
if thread->schedule_next:
|
||||
thread->schedule_next->schedule_prev = thread
|
||||
thread->schedule_prev = NULL
|
||||
first_scheduled = thread
|
||||
|
||||
static void unrun_thread (kThread *thread):
|
||||
if current == thread:
|
||||
current = thread->schedule_next
|
||||
if thread->schedule_prev:
|
||||
thread->schedule_prev->schedule_next = thread->schedule_next
|
||||
else:
|
||||
first_scheduled = thread->schedule_next
|
||||
if thread->schedule_next:
|
||||
thread->schedule_next->schedule_prev = thread->schedule_prev
|
||||
|
||||
void kThread::run ():
|
||||
if flags & Iris::Thread::RUNNING:
|
||||
return
|
||||
flags |= Iris::Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
run_thread (this)
|
||||
|
||||
void kThread::unrun ():
|
||||
if !(flags & Iris::Thread::RUNNING):
|
||||
return
|
||||
flags &= ~Iris::Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
unrun_thread (this)
|
||||
|
||||
void kThread::unwait ():
|
||||
flags &= ~Iris::Thread::WAITING
|
||||
if flags & Iris::Thread::RUNNING:
|
||||
run_thread (this)
|
||||
|
||||
static void alarm_tick (kReceiver *recv):
|
||||
if !recv->alarm_count:
|
||||
// Send message and stop counting.
|
||||
kCapability::Context c
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
c.data[i] = 0
|
||||
recv->send_message (~0, &c)
|
||||
if recv->prev_alarm:
|
||||
recv->prev_alarm->next_alarm = recv->next_alarm
|
||||
else:
|
||||
first_alarm = recv->next_alarm
|
||||
if recv->next_alarm:
|
||||
recv->next_alarm->prev_alarm = recv->prev_alarm
|
||||
// Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm.
|
||||
--recv->alarm_count
|
||||
|
||||
void kThread::wait ():
|
||||
if flags & Iris::Thread::RUNNING:
|
||||
unrun_thread (this)
|
||||
flags |= Iris::Thread::WAITING
|
||||
// Try to receive a message from a kReceiver immediately.
|
||||
for kReceiver *r = receivers; r; r = r->next_owned:
|
||||
if r->try_deliver ():
|
||||
return
|
||||
|
||||
void schedule ():
|
||||
if current:
|
||||
current = current->schedule_next
|
||||
if !current:
|
||||
current = first_scheduled
|
||||
|
||||
void timer_interrupt ():
|
||||
kReceiver *recv, *next
|
||||
for recv = first_alarm; recv; recv = next:
|
||||
next = (kReceiver *)recv->next_alarm
|
||||
alarm_tick (recv)
|
||||
//schedule ()
|
||||
Reference in New Issue
Block a user