1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-01-31 01:11:07 +02:00

compiling again with new capability scheme

This commit is contained in:
Bas Wijnen 2009-08-17 23:11:15 +02:00
parent 7b99ba0bdf
commit a892e9cfc0
21 changed files with 1616 additions and 2053 deletions

View File

@ -22,7 +22,7 @@ CC = $(CROSS)gcc
LD = $(CROSS)ld LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy OBJCOPY = $(CROSS)objcopy
headers = kernel.hh iris.h $(arch_headers) headers = kernel.hh iris.hh $(arch_headers)
iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources) iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
BUILT_SOURCES = $(iris_sources) $(boot_sources) BUILT_SOURCES = $(iris_sources) $(boot_sources)

177
alloc.ccp
View File

@ -21,38 +21,38 @@
// Memory model used for kernel structure storage // 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 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. // 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 Free objects, in the order they appear in the page. // 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. // 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. // 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) (((Object **)(x))[-2]) #define PREV(x) (((kObject **)(x))[-2])
#define NEXT(x) (((Object **)(x))[-1]) #define NEXT(x) (((kObject **)(x))[-1])
#define SIZE (2 * sizeof (Object *)) #define SIZE (2 * sizeof (kObject *))
bool Memory::use (unsigned num): bool kMemory::use (unsigned num):
// Go up to parents, incrementing used. // Go up to parents, incrementing used.
for Memory *m = this; m; m = m->address_space: for kMemory *m = this; m; m = m->address_space:
if used + num > limit: if used + num > limit:
// Not allowed. Restore used for all children. // Not allowed. Restore used for all children.
for Memory *r = this; r != m; r = r->address_space: for kMemory *r = this; r != m; r = r->address_space:
r->used -= num r->used -= num
return false return false
m->used += num m->used += num
return true return true
void Memory::unuse (unsigned num): void kMemory::unuse (unsigned num):
for Memory *m = this; m; m = m->address_space: for kMemory *m = this; m; m = m->address_space:
m->used -= num m->used -= num
// This allocates a new block of memory for use by the kernel. // This allocates a new block of memory for use by the kernel.
// size is the requires size of the block (excluding SIZE) // size is the requires size of the block (excluding SIZE)
// first is a pointer to the first object pointer of this type. // 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. // The result is a block of size at least size, which is linked as an object in the list of first.
void *Memory::search_free (unsigned size, void **first): void *kMemory::search_free (unsigned size, void **first):
Free *f kFree *f
unsigned s = 0 unsigned s = 0
// Let's see if there already is a Free chunk which is large enough. // Let's see if there already is a kFree chunk which is large enough.
for f = frees; f; f = (Free *)f->next: for f = frees; f; f = (kFree *)f->next:
if NEXT (f): if NEXT (f):
s = (unsigned)NEXT (f) - (unsigned)f s = (unsigned)NEXT (f) - (unsigned)f
else: else:
@ -67,27 +67,27 @@ void *Memory::search_free (unsigned size, void **first):
if !p: if !p:
dbg_log ("no free space: kernel allocation failed") dbg_log ("no free space: kernel allocation failed")
return NULL return NULL
f = (Free *)(p + SIZE) f = (kFree *)(p + SIZE)
// Mark it as a Free object. // Mark it as a kFree object.
f->marker = ~0 f->marker = ~0
// Link it in the Free list. // Link it in the kFree list.
f->next = frees f->next = frees
f->prev = NULL f->prev = NULL
frees = f frees = f
if f->next: if f->next:
((Free *)f->next)->prev = f ((kFree *)f->next)->prev = f
// There are no other objects in this page. // There are no other objects in this page.
NEXT (f) = NULL NEXT (f) = NULL
PREV (f) = NULL PREV (f) = NULL
// The size of this block is the entire page. // The size of this block is the entire page.
s = PAGE_SIZE s = PAGE_SIZE
// We have a free block, possibly too large. The block is linked in frees, and in the page. // We have a free block, possibly too large. The block is linked in frees, and in the page.
if s >= size + sizeof (Free) + 2 * SIZE: if s >= size + sizeof (kFree) + 2 * SIZE:
// Create the new object at the end and keep the Free. // Create the new object at the end and keep the Free.
// f is the start of the free block // 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) 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. // f + (s - SIZE) - size is the address where the new block should start.
Free *obj = (Free *)((unsigned)f + (s - SIZE) - size) kFree *obj = (kFree *)((unsigned)f + (s - SIZE) - size)
// Link the new object in the page. // Link the new object in the page.
NEXT (obj) = NEXT (f) NEXT (obj) = NEXT (f)
if NEXT (obj): if NEXT (obj):
@ -100,16 +100,16 @@ void *Memory::search_free (unsigned size, void **first):
// The block was only just large enough: turn it into a new type. It is already linked into the page. // 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. // Unlink it from the free list.
if f->prev: if f->prev:
((Free *)f->prev)->next = f->next ((kFree *)f->prev)->next = f->next
else: else:
frees = (Free *)f->next frees = (kFree *)f->next
if f->next: if f->next:
((Free *)f->next)->prev = f->prev ((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 is now a block which is linked in the page, but not in any list. Link it into first.
f->next = (Free *)*first f->next = (kFree *)*first
f->prev = NULL f->prev = NULL
if f->next: if f->next:
((Free *)f->next)->prev = f ((kFree *)f->next)->prev = f
*first = f *first = f
// Set common initial values. // Set common initial values.
f->address_space = this f->address_space = this
@ -117,45 +117,45 @@ void *Memory::search_free (unsigned size, void **first):
return f return f
// Free an object; it is still in its list, and it is still in the page list. // Free an object; it is still in its list, and it is still in the page list.
void Memory::free_obj (Object *obj, Pointer *first): void kMemory::free_obj (kObject *obj, kPointer *first):
Free *self = (Free *)obj kFree *self = (kFree *)obj
// Invalidate references. // Invalidate references.
while self->refs: while self->refs:
self->refs->invalidate () self->refs->invalidate ()
// Free it from its list. // Free it from its list.
if self->prev: if self->prev:
((Free *)self->prev)->next = self->next ((kFree *)self->prev)->next = self->next
else: else:
*(Pointer *)first = (Pointer)self->next *(kPointer *)first = (kPointer)self->next
if self->next: if self->next:
((Free *)self->next)->prev = self->prev ((kFree *)self->next)->prev = self->prev
// Merge with previous, if it exists and is a Free. // Merge with previous, if it exists and is a kFree.
if PREV (self) && PREV (self)->is_free (): if PREV (self) && PREV (self)->is_free ():
self = (Free *)PREV (self) self = (kFree *)PREV (self)
// Remove the object from the page list. // Remove the object from the page list.
NEXT (self) = NEXT (obj) NEXT (self) = NEXT (obj)
if NEXT (self): if NEXT (self):
PREV (NEXT (self)) = self PREV (NEXT (self)) = self
else: else:
// The previous object is not a Free, so create a new one. // 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. // It is already linked in the page, but needs to be linked into the free list.
self->next = frees self->next = frees
self->prev = NULL self->prev = NULL
if self->next: if self->next:
((Free *)self->next)->prev = self ((kFree *)self->next)->prev = self
frees = self frees = self
// Mark it as a Free. // Mark it as a kFree.
self->marker = ~0 self->marker = ~0
// Merge with next, if it exists and is a Free. // Merge with next, if it exists and is a kFree.
if NEXT (self) && NEXT (self)->is_free (): if NEXT (self) && NEXT (self)->is_free ():
// Unlink the next from the frees list. // Unlink the next from the frees list.
Free *n = (Free *)NEXT (self) kFree *n = (kFree *)NEXT (self)
if n->prev: if n->prev:
((Free *)n->prev)->next = n->next ((kFree *)n->prev)->next = n->next
else: else:
frees = (Free *)n->next frees = (kFree *)n->next
if n->next: if n->next:
((Free *)n->next)->prev = n->prev ((kFree *)n->next)->prev = n->prev
// Unlink the next from the page list. // Unlink the next from the page list.
NEXT (self) = NEXT (NEXT (self)) NEXT (self) = NEXT (NEXT (self))
if NEXT (self): if NEXT (self):
@ -163,29 +163,29 @@ void Memory::free_obj (Object *obj, Pointer *first):
// Free page if the resulting object is the only thing in it. // Free page if the resulting object is the only thing in it.
if !PREV (self) && !NEXT (self): if !PREV (self) && !NEXT (self):
if self->next: if self->next:
((Free *)self->next)->prev = self->prev ((kFree *)self->next)->prev = self->prev
if self->prev: if self->prev:
((Free *)self->prev)->next = self->next ((kFree *)self->prev)->next = self->next
else: else:
frees = (Free *)self->next frees = (kFree *)self->next
pfree ((unsigned)self - SIZE) pfree ((unsigned)self - SIZE)
Page *Memory::alloc_page (): kPage *kMemory::alloc_page ():
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages) kPage *ret = (kPage *)search_free (sizeof (kPage), (void **)&pages)
if !ret: if !ret:
return NULL return NULL
ret->frame = 0 ret->frame = 0
ret->flags = 0 ret->flags = 0
return ret return ret
Thread *Memory::alloc_thread (unsigned size): kThread *kMemory::alloc_thread (unsigned size):
Thread *ret = (Thread *)search_free (sizeof (Thread) + (size - 1) * sizeof (CapsP), (void **)&threads) kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kCapsP), (void **)&threads)
if !ret: if !ret:
return NULL return NULL
ret->receivers = NULL ret->receivers = NULL
ret->pc = 0 ret->pc = 0
ret->sp = 0 ret->sp = 0
Thread_arch_init (ret) kThread_arch_init (ret)
ret->flags = 0 ret->flags = 0
ret->schedule_prev = NULL ret->schedule_prev = NULL
ret->schedule_next = NULL ret->schedule_next = NULL
@ -194,16 +194,16 @@ Thread *Memory::alloc_thread (unsigned size):
ret->caps[i] = NULL ret->caps[i] = NULL
return ret return ret
Message *Memory::alloc_message (Receiver *target): kMessage *kMemory::alloc_message (kReceiver *target):
Message *ret = (Message *)search_free (sizeof (Message), (void **)&target->messages) kMessage *ret = (kMessage *)search_free (sizeof (kMessage), (void **)&target->messages)
if !ret: if !ret:
return NULL return NULL
if !ret->next: if !ret->next:
target->last_message = ret target->last_message = ret
return ret return ret
Receiver *Memory::alloc_receiver (): kReceiver *kMemory::alloc_receiver ():
Receiver *ret = (Receiver *)search_free (sizeof (Receiver), (void **)&receivers) kReceiver *ret = (kReceiver *)search_free (sizeof (kReceiver), (void **)&receivers)
if !ret: if !ret:
return NULL return NULL
ret->owner = NULL ret->owner = NULL
@ -216,19 +216,20 @@ Receiver *Memory::alloc_receiver ():
ret->last_message = NULL ret->last_message = NULL
ret->reply_protected_data = ~0 ret->reply_protected_data = ~0
ret->protected_only = false ret->protected_only = false
ret->queue_limit = 0
return ret return ret
Caps *Memory::alloc_caps (unsigned size): kCaps *kMemory::alloc_caps (unsigned size):
Caps *ret = (Caps *)search_free (sizeof (Caps) + (size - 1) * sizeof (Capability), (void **)&capses) kCaps *ret = (kCaps *)search_free (sizeof (kCaps) + (size - 1) * sizeof (kCapability), (void **)&capses)
if !ret: if !ret:
return NULL return NULL
ret->size = size ret->size = size
for unsigned i = 0; i < size; ++i: for unsigned i = 0; i < size; ++i:
ret->set (i, NULL, 0, CapRef (), NULL) ret->set (i, NULL, 0, kCapRef (), NULL)
return ret return ret
Memory *Memory::alloc_memory (): kMemory *kMemory::alloc_memory ():
Memory *ret = (Memory *)search_free (sizeof (Memory), (void **)&memories) kMemory *ret = (kMemory *)search_free (sizeof (kMemory), (void **)&memories)
if !ret: if !ret:
return NULL return NULL
ret->frees = NULL ret->frees = NULL
@ -239,57 +240,57 @@ Memory *Memory::alloc_memory ():
ret->memories = NULL ret->memories = NULL
ret->limit = ~0 ret->limit = ~0
ret->used = 0 ret->used = 0
Memory_arch_init (ret) kMemory_arch_init (ret)
return ret return ret
void Caps::set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr): void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
caps[index].target = target caps[index].target = target
caps[index].protected_data = pdata caps[index].cap_protected = pdata
caps[index].parent = parent caps[index].parent = parent
caps[index].children.reset () caps[index].children.reset ()
caps[index].sibling_prev.reset () caps[index].sibling_prev.reset ()
if parent: if parent:
caps[index].sibling_next = parent->children caps[index].sibling_next = parent->children
parent->children = CapRef (this, index) parent->children = kCapRef (this, index)
else: else:
if parent_ptr: if parent_ptr:
caps[index].sibling_next = *parent_ptr caps[index].sibling_next = *parent_ptr
*parent_ptr = CapRef (this, index) *parent_ptr = kCapRef (this, index)
else: else:
caps[index].sibling_next.reset () caps[index].sibling_next.reset ()
if caps[index].sibling_next: if caps[index].sibling_next:
caps[index].sibling_next->sibling_prev = CapRef (this, index) caps[index].sibling_next->sibling_prev = kCapRef (this, index)
void Caps::clone (unsigned index, CapRef source, bool copy): void kCaps::clone (unsigned index, kCapRef source, bool copy):
if copy: if copy:
if source->parent: if source->parent:
set (index, source->target, source->protected_data, source->parent) set (index, source->target, source->cap_protected, source->parent)
else if (unsigned)source->target & ~KERNEL_MASK: else if (unsigned)source->target & ~KERNEL_MASK:
set (index, source->target, source->protected_data, CapRef (), &source->target->capabilities) set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities)
else: else:
set (index, source->target, source->protected_data, CapRef (), &((Object *)source->protected_data)->refs) set (index, source->target, source->cap_protected, kCapRef (), &((kObject *)source->cap_protected.l)->refs)
else: else:
set (index, source->target, source->protected_data, source) set (index, source->target, source->cap_protected, source)
void Memory::free_page (Page *page): void kMemory::free_page (kPage *page):
if page->flags & PAGE_FLAG_PAYING: if page->flags & Page::PAYING:
unuse () unuse ()
if page->frame: if page->frame:
pfree (page->frame) pfree (page->frame)
free_obj (page, (Pointer *)&pages) free_obj (page, (kPointer *)&pages)
void Memory::free_thread (Thread *thread): void kMemory::free_thread (kThread *thread):
thread->unrun () thread->unrun ()
while thread->receivers: while thread->receivers:
thread->receivers->orphan () thread->receivers->orphan ()
free_obj (thread, (void **)&threads) free_obj (thread, (void **)&threads)
void Memory::free_message (Receiver *owner, Message *message): void kMemory::free_message (kReceiver *owner, kMessage *message):
if !message->next: if !message->next:
owner->last_message = (MessageP)message->prev owner->last_message = (kMessageP)message->prev
free_obj (message, (void **)&owner->messages) free_obj (message, (void **)&owner->messages)
void Memory::free_receiver (Receiver *receiver): void kMemory::free_receiver (kReceiver *receiver):
receiver->orphan () receiver->orphan ()
while receiver->capabilities: while receiver->capabilities:
receiver->capabilities->invalidate () receiver->capabilities->invalidate ()
@ -297,7 +298,7 @@ void Memory::free_receiver (Receiver *receiver):
free_message (receiver, receiver->messages) free_message (receiver, receiver->messages)
free_obj (receiver, (void **)&receivers) free_obj (receiver, (void **)&receivers)
void Receiver::orphan (): void kReceiver::orphan ():
if prev_owned: if prev_owned:
prev_owned->next_owned = next_owned prev_owned->next_owned = next_owned
else: else:
@ -306,7 +307,7 @@ void Receiver::orphan ():
next_owned->prev_owned = prev_owned next_owned->prev_owned = prev_owned
owner = NULL owner = NULL
void Receiver::own (Thread *o): void kReceiver::own (kThread *o):
if owner: if owner:
orphan () orphan ()
owner = o owner = o
@ -315,7 +316,7 @@ void Receiver::own (Thread *o):
next_owned->prev_owned = this next_owned->prev_owned = this
o->receivers = this o->receivers = this
void Capability::invalidate (): void kCapability::invalidate ():
if !target: if !target:
return return
if sibling_prev: if sibling_prev:
@ -323,17 +324,17 @@ void Capability::invalidate ():
else if (unsigned)target & ~KERNEL_MASK: else if (unsigned)target & ~KERNEL_MASK:
target->capabilities = sibling_next target->capabilities = sibling_next
else: else:
((Object *)protected_data)->refs = sibling_next ((kObject *)cap_protected.l)->refs = sibling_next
if sibling_next: if sibling_next:
sibling_next->sibling_prev = sibling_prev sibling_next->sibling_prev = sibling_prev
parent.reset () parent.reset ()
sibling_prev.reset () sibling_prev.reset ()
sibling_next.reset () sibling_next.reset ()
Capability *c = this kCapability *c = this
while c: while c:
while c->children: while c->children:
c = c->children.deref () c = c->children.deref ()
Capability *next = c->sibling_next.deref () kCapability *next = c->sibling_next.deref ()
if !next: if !next:
next = c->parent.deref () next = c->parent.deref ()
c->target = NULL c->target = NULL
@ -341,15 +342,15 @@ void Capability::invalidate ():
c->children.reset () c->children.reset ()
c->sibling_prev.reset () c->sibling_prev.reset ()
c->sibling_next.reset () c->sibling_next.reset ()
c->protected_data = 0 c->cap_protected = 0
c = next c = next
void Memory::free_caps (Caps *c): void kMemory::free_caps (kCaps *c):
for unsigned i = 0; i < c->size; ++i: for unsigned i = 0; i < c->size; ++i:
c->caps[i].invalidate () c->caps[i].invalidate ()
free_obj (c, (void **)&capses) free_obj (c, (void **)&capses)
void Memory::free_memory (Memory *mem): void kMemory::free_memory (kMemory *mem):
while mem->pages: while mem->pages:
free_page (mem->pages) free_page (mem->pages)
while mem->capses: while mem->capses:
@ -360,12 +361,12 @@ void Memory::free_memory (Memory *mem):
free_memory (mem->memories) free_memory (mem->memories)
while mem->receivers: while mem->receivers:
free_receiver (mem->receivers) free_receiver (mem->receivers)
Memory_arch_free (mem) kMemory_arch_free (mem)
if mem->frees: if mem->frees:
panic (0, "kernel memory leak: memory still in use") panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories) free_obj (mem, (void **)&memories)
void Page::forget (): void kPage::forget ():
if share_prev || share_next: if share_prev || share_next:
if share_prev: if share_prev:
share_prev->share_next = share_next share_prev->share_next = share_next
@ -375,8 +376,8 @@ void Page::forget ():
share_next = NULL share_next = NULL
else: else:
// If the page has a frame and should be freed, free it. // If the page has a frame and should be freed, free it.
if !((flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)): if !((flags ^ Page::FRAME) & (Page::PHYSICAL | Page::FRAME)):
raw_pfree (frame) raw_pfree (frame)
frame = 0 frame = 0
flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) flags &= ~(Page::FRAME | Page::SHARED | Page::PHYSICAL | Page::UNCACHED)
Page_arch_update_mapping (this) kPage_arch_update_mapping (this)

View File

@ -1,41 +0,0 @@
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.S: Startup code for initial Threads.
// 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/>.
.globl __start
.globl __my_receiver
.globl __my_thread
.globl __my_memory
.globl __my_call
.globl __my_parent
.set noreorder
__start:
bal 1f
__hack_label:
nop
.word _gp
1:
lw $gp, 0($ra)
la $t9, main
la $ra, 1f
jr $t9
nop
1:
// This should not be reached: generate an address fault.
b 1b
lw $a0, -4($zero)

117
boot-programs/crt0.ccp Normal file
View File

@ -0,0 +1,117 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.S: Startup code for initial Threads.
// 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 "iris.hh"
// For some unknown reason, gcc needs this to be defined.
unsigned __gxx_personality_v0
struct list:
list *prev, *next
static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap
Receiver __my_receiver
Thread __my_thread
Memory __my_memory
Caps __my_caps
Cap __my_call
Cap __my_parent
Caps __tmp_caps
void free_slot (unsigned slot):
__slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next:
__slot_admin[slot].next->prev = &__slot_admin[slot]
__first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap):
list *l = &__cap_admin[cap.idx ()]
l->prev = NULL
l->next = __first_free_cap
if l->next:
l->next->prev = l
__first_free_cap = l
unsigned alloc_slot ():
if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
return ~0
list *ret = __first_free_slot
__first_free_slot = ret->next
if ret->next:
ret->next->prev = NULL
unsigned alloc_cap ():
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return NO_SLOT.
return ~0
list *ret = __first_free_cap
__first_free_cap = ret->next
if ret->next:
ret->next->prev = NULL
return ret - __slot_admin
extern "C":
void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
__slots = slots
__caps = caps
__slot_admin = slot_admin
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i:
free_slot (i)
__first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i:
free_cap (Cap (0, i))
__my_receiver = Cap (0, __receiver_num)
__my_thread = Cap (0, __thread_num)
__my_memory = Cap (0, __memory_num)
__my_caps = Cap (0, __caps_num)
__my_call = Cap (0, __call_num)
__my_parent = Cap (0, __parent_num)
__tmp_caps = Cap (0, __tmp_num)
Num ret = start ()
__my_parent.invoke (~0, ret)
__my_memory.destroy (__my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:
*(volatile unsigned *)~0
__asm__ volatile ("\t.globl __start\n"
"\t.set noreorder\n"
"__start:\n"
"\tbal 1f\n"
"__hack_label:\n"
"\tnop\n"
"\t.word _gp\n"
"1:\n"
"\tlw $gp, 0($ra)\n"
"\tsll $v0, $a0, 3\n"
"\tsll $v1, $a1, 3\n"
"\tsubu $sp, $sp, $v0\n"
"\tmove $a2, $sp\n"
"\tsubu $sp, $sp, $v1\n"
"\tmove $a3, $sp\n"
"\tla $t9, __main\n"
"\tjr $t9\n"
"\tnop\n"
"\t.set reorder")

View File

@ -19,7 +19,7 @@
#ifndef __IRIS_DEVICES_HH #ifndef __IRIS_DEVICES_HH
#define __IRIS_DEVICES_HH #define __IRIS_DEVICES_HH
#include "iris.h" #include "iris.hh"
// This shouldn't really be here. But where should it be? // This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves. // Requests made by initial threads to tell init about themselves.
@ -27,136 +27,150 @@ enum init_requests:
INIT_SET_GPIO INIT_SET_GPIO
INIT_SET_LCD INIT_SET_LCD
// List interface.
template <typename _T> //
struct List : public Cap:
List (Cap c = Cap ()) : Cap (c):
// TODO
struct String : public Cap:
String (Cap c = Cap ()) : Cap (c):
// TODO
// Keyboard interface. // Keyboard interface.
enum Keyboard_request: struct Keyboard : public Cap:
KEYBOARD_SET_CB Keyboard (Cap c = Cap ()) : Cap (c):
KEYBOARD_GET_KEYS enum request:
SET_CB
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events. GET_KEYS
static __inline__ void keyboard_set_cb (Capability kbd, Capability cb):
invoke_11 (kbd, cb, KEYBOARD_SET_CB)
// At event: the callback is called with a keycode. One bit defines if it's a press or release event. // At event: the callback is called with a keycode. One bit defines if it's a press or release event.
#define KEYBOARD_RELEASE (1 << 31) enum constant:
RELEASE = 1 << 31
// Get a list of keys on this keyboard. The key codes start at zero with no gaps. The returned capability is a read-only list of strings. // Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
static __inline__ void keyboard_get_keys (Capability target, Capability kbd): void set_cb (Cap cb):
call_c01 (kbd, target, KEYBOARD_GET_KEYS) invoke (cb, CAP_MASTER_DIRECT | SET_CB)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps.
void get_keys (List <String> ret):
call (ret, CAP_MASTER_DIRECT | GET_KEYS)
// Display interface. // Display interface.
// Startup: disp_set_eof_cb, disp_create_fb, disp_use_fb, disp_info struct Display : public Cap:
Display (Cap c = Cap ()) : Cap (c):
enum request:
EOF_CB
CREATE_FB
USE_FB
GET_INFO
// Register an end-of-frame callback. // Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events. // At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
static __inline__ void display_set_eof_cb (Capability disp_set_eof_cb, Capability cb): void set_eof_cb (Cap cb):
invoke_10 (disp_set_eof_cb, cb) invoke (cb, CAP_MASTER_DIRECT | EOF_CB)
// Create a framebuffer for the display. When not in use, it can be freed by the user. // Create a framebuffer for the display. When not in use, it can be freed by the user.
// The pages must be cappages holding Page capabilities. They are filled by the display. // The pages must be cappages holding Page capabilities. They are filled by the display.
// The passed numbers must be 0 or match a mode that the device can use. // The passed numbers must be 0 or match a mode that the device can use.
// The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer. // The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer.
static __inline__ unsigned display_create_framebuffer (Capability disp_create_fb, Capability page0, Capability page1 = 0, Capability page2 = 0, unsigned w = 0, unsigned h = 0, unsigned mode = 0): unsigned create_framebuffer (Caps pages, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return call_n33 (disp_create_fb, page0, page1, page2, w, h, mode) return call (pages, Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Num ((w << 16) | h, mode)).l
// Use a framebuffer. The address must have been returned from display_create_framebuffer. // Use a framebuffer. The address must have been returned from display_create_framebuffer.
// w, h and mode must match the values given at creation time. // w, h and mode must match the values given at creation time.
// unuse_cb is called the next time this operation is requested. // unuse_cb is called the next time this operation is requested for this display.
static __inline__ void display_use_framebuffer (Capability disp_use_fb, unsigned addr, Capability unuse_cb, unsigned w = 0, unsigned h = 0, unsigned mode = 0): void use_framebuffer (unsigned addr, Cap unuse_cb = Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0):
invoke_11 (disp_use_fb, unuse_cb, addr) invoke (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode))
// Get information about the display. // Get information about the display.
static __inline__ void display_get_info (Capability disp_info): void get_info ():
// TODO: Interface is to be designed. // TODO: Interface is to be designed.
// File system interface. // File system interface.
// This may not be a server, so there need not be a startup phase. Instead, capabilities can implement certain interfaces: directory, file, stream, seekable file, mappable file. Normal files implement at least stream or seekable file. Directories implement directory. // filesystem-related interfaces: file, directory, stream, seekable, mappable.
// Normal files implement at least stream or seekable file. Directories implement directory.
enum File_request: struct File : public Cap:
FILE_INFO File (Cap c = Cap ()) : Cap (c):
FILE_CLOSE enum request:
FILE_COPY_HANDLE INFO
DIRECTORY_GET_SIZE CLOSE
DIRECTORY_GET_NAME MAP_HANDLE
DIRECTORY_GET_FILE
DIRECTORY_GET_FILE_INFO
DIRECTORY_CREATE_FILE
DIRECTORY_DELETE_FILE
FILE_STREAM_READ
FILE_STREAM_WRITE
FILE_SEEKABLE_READ
FILE_SEEKABLE_WRITE
FILE_SEEKABLE_TRUNCATE
// File interface.
// Get information about the file. // Get information about the file.
static __inline__ unsigned long long file_get_info (Capability file, unsigned type): Num get_info (unsigned type, Caps ret = Cap ()):
return call_l02 (file, FILE_INFO, type) return call (ret, Num (CAP_MASTER_DIRECT | INFO, type))
// Close a file. If this is a directory, it implicitly closes all files opened from it. // Close a file. If this is a directory, it implicitly closes all files opened from it.
static __inline__ void file_close (Capability file): void close ():
invoke_01 (file, FILE_CLOSE) invoke (CAP_MASTER_DIRECT | CLOSE)
// Copy a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle. // Map a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
static __inline__ void file_copy_handle (Capability target, Capability file): File map_handle (File ret):
call_c01 (file, target, FILE_COPY_HANDLE) call (ret, CAP_MASTER_DIRECT | MAP_HANDLE)
// Directory interface. // Directory interface.
struct Directory : public File:
Directory (Cap c = Cap ()) : File (c):
enum request:
GET_SIZE
GET_NAME
GET_FILE
GET_FILE_INFO
CREATE_FILE
DELETE_FILE
// Get the number of entries in this directory. // Get the number of entries in this directory.
static __inline__ unsigned long long directory_get_size (Capability dir): Num get_size ():
return call_l01 (dir, DIRECTORY_GET_SIZE) return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename. The return value is the size of the string, the page is filled with the string itself. // Get the filename. The return value is the size of the string, the page is filled with the string itself.
static __inline__ unsigned directory_get_name (Capability dir, unsigned long long idx, Capability page): void get_name (Num idx, String target):
return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32) call (target, CAP_MASTER_DIRECT | GET_NAME, idx)
// Get the file. // Get the file.
static __inline__ void directory_get_file (Capability target, Capability dir, unsigned long long idx, Capability page): void get_file (Num idx, File ret):
call_c03 (dir, target, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32) call (ret, CAP_MASTER_DIRECT | GET_FILE, idx)
// Get file info. This returns the same information as file_get_info, without opening the file. // Get file info. This returns the same information as file_get_info, without opening the file.
static __inline__ unsigned long long directory_get_file_info (Capability dir, unsigned long long idx, unsigned type): Num get_file_info (Num idx, unsigned type, Caps ret = Cap ()):
return call_l04 (dir, DIRECTORY_GET_FILE_INFO, idx & 0xffffffff, idx >> 32, type) return call (ret, Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Create a new file. After this, any index may map to a different file. // Create a new file. After this, any index may map to a different file.
static __inline__ void directory_create_file (Capability target, Capability dir, unsigned long long idx, Capability page): void create_file (String name, File ret):
call_c03 (dir, target, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32) call (ret, CAP_MASTER_DIRECT | CREATE_FILE)
// Delete a file. After this, any index may map to a different file. // Delete a file. After this, any index may map to a different file.
static __inline__ void directory_delete_file (Capability target, Capability dir, unsigned long long idx, Capability page): void delete_file (Num idx):
call_c03 (dir, target, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32) invoke (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Stream interface. // Stream interface.
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE. struct Stream : public File:
static __inline__ unsigned file_stream_read (Capability file, Capability page, unsigned size): Stream (Cap c = Cap ()) : File (c):
return call_n12 (file, page, FILE_STREAM_READ, size) enum request:
// Try to write size bytes. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE. READ
static __inline__ unsigned file_stream_write (Capability file, Capability page, unsigned size): WRITE
return call_n12 (file, page, FILE_STREAM_WRITE, size) // Try to read size bytes. Returns the number of bytes successfully read.
Num read (Num size, String ret):
return call (ret, CAP_MASTER_DIRECT | READ, size)
// Try to write size bytes. Returns the number of bytes successfully written.
Num write (String s, Num size):
return call (s, CAP_MASTER_DIRECT | WRITE, size)
// Seekable file interface. // Seekable file interface.
// Try to read size bytes from position idx. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE. struct Seekable : public File:
static __inline__ unsigned file_seekable_read (Capability file, Capability page, unsigned long long idx, unsigned size): Seekable (Cap c = Cap ()) : File (c):
return call_n14 (file, page, FILE_SEEKABLE_READ, idx & 0xffffffff, idx >> 32, size) enum request:
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE. READ
static __inline__ unsigned file_seekable_write (Capability file, Capability page, unsigned long long idx, unsigned size): WRITE
return call_n14 (file, page, FILE_SEEKABLE_WRITE, idx & 0xffffffff, idx >> 32, size) TRUNCATE
// Try to read size bytes from position idx. Returns the number of bytes successfully read.
Num read (Num idx, unsigned size, String ret):
return call (ret, Num (CAP_MASTER_DIRECT | READ, size), idx)
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written.
Num write (Num idx, String s):
return call (s, CAP_MASTER_DIRECT | WRITE, idx)
// Truncate file to size idx. The file is extended with zeroes if it gets longer. // Truncate file to size idx. The file is extended with zeroes if it gets longer.
static __inline__ void file_seekable_truncate (Capability file, unsigned long long idx): void truncate (Num idx):
call_n03 (file, FILE_SEEKABLE_TRUNCATE, idx & 0xffffffff, idx >> 32) invoke (CAP_MASTER_DIRECT | TRUNCATE, idx)
// Mappable file interface. // Mappable file interface.
struct Mappable : public Seekable:
Mappable (Cap c = Cap ()) : Seekable (c):
// TODO: to be designed. // TODO: to be designed.
// Block device interface. // Block device interface.
// Startup: blk_get_size, blk_get_file. struct Block_device : public Mappable:
Block_device (Cap c = Cap ()) : Mappable (c):
// Get block size. // TODO: to be designed.
static __inline__ unsigned block_get_size (Capability blk_get_size):
return call_n00 (blk_get_size)
// Get file capability. Returns a seekable mappable non-stream file.
static __inline__ void block_get_file (Capability target, Capability blk_get_file):
call_c00 (blk_get_file, target)
// TODO. // TODO.

View File

@ -58,14 +58,17 @@ enum cap_type:
CAP_TOUCHPAD CAP_TOUCHPAD
CAP_LOCKLEDS CAP_LOCKLEDS
CAP_PWM CAP_PWM
NUM_EVENT_TYPES
static Caps events = Cap (0, 6)
static void event (event_type type, unsigned data): static void event (event_type type, unsigned data):
invoke_01 (11 + type, data) Cap (2, type - 32).invoke (data)
static void set_cb (event_type type): static void set_cb (Cap cap, event_type type):
capability_clone (11 + type, 6) cap.clone (events, type - 32)
class Keyboard: class DevKeyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
unsigned keys[GPIO_KBD_NUM_COLS] unsigned keys[GPIO_KBD_NUM_COLS]
bool scanning bool scanning
@ -74,7 +77,7 @@ class Keyboard:
if (data ^ keys[col]) & (1 << row): if (data ^ keys[col]) & (1 << row):
unsigned code = encode[col][row] unsigned code = encode[col][row]
if data & (1 << row): if data & (1 << row):
code |= KEYBOARD_RELEASE code |= Keyboard::RELEASE
event (KEYBOARD_EVENT, code) event (KEYBOARD_EVENT, code)
keys[col] = data keys[col] = data
// If any keys are pressed, scanning is required. // If any keys are pressed, scanning is required.
@ -127,7 +130,7 @@ class Keyboard:
gpio_irq_high (GPIO_KBD_ROW_PORT, i) gpio_irq_high (GPIO_KBD_ROW_PORT, i)
// Reenable interrupts. // Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
Keyboard (): DevKeyboard ():
// Set all columns to output without pull-ups when set as input. // Set all columns to output without pull-ups when set as input.
GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
@ -152,9 +155,9 @@ enum Keys:
ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
LSHIFT, RSHIFT, CTRL, ALT LSHIFT, RSHIFT, CTRL, ALT
CAPS, NUM CAPS, NUM
NONE = ~0 & ~KEYBOARD_RELEASE NONE = ~Keyboard::RELEASE
unsigned const Keyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = { unsigned const DevKeyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
{ PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 }, { PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 }, { Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 }, { W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
@ -251,61 +254,60 @@ class Pwm:
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE) GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything. // TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
int main (): Num start ():
__my_memory.create_caps (NUM_EVENT_TYPES - 32).clone (__my_caps, 6)
map_gpio () map_gpio ()
map_pwm0 () map_pwm0 ()
Keyboard kbd DevKeyboard kbd
Touchpad tp Touchpad tp
Lockleds leds Lockleds leds
Pwm pwm Pwm pwm
// Enable interrupts. All are in port 0. // Enable interrupts. All are in port 0.
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
register_interrupt (IRQ_GPIO0) Kernel::register_interrupt (IRQ_GPIO0)
Capability cap_kbd = 7 Caps c (0, 7)
Capability cap_tp = 8 __my_memory.create_caps (4).clone (__my_caps, 7)
Capability cap_lockleds = 9 __my_receiver.create_capability (CAP_KEYBOARD).clone (c, 0)
Capability cap_pwm = 10 __my_receiver.create_capability (CAP_TOUCHPAD).clone (c, 1)
receiver_create_capability (cap_kbd, __my_receiver, CAP_KEYBOARD) __my_receiver.create_capability (CAP_LOCKLEDS).clone (c, 2)
receiver_create_capability (cap_tp, __my_receiver, CAP_TOUCHPAD) __my_receiver.create_capability (CAP_PWM).clone (c, 3)
receiver_create_capability (cap_lockleds, __my_receiver, CAP_LOCKLEDS)
receiver_create_capability (cap_pwm, __my_receiver, CAP_PWM)
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO) __my_parent.invoke (c, INIT_SET_GPIO)
if kbd.is_scanning (): if kbd.is_scanning ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL) __my_receiver.set_alarm (ALARM_INTERVAL)
while true: while true:
schedule () Kernel::schedule ()
Message msg Cap::OMessage msg
wait (&msg, 6, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE) Kernel::wait (&msg)
switch msg.protected_data: switch (unsigned)msg.cap_protected.value ():
case ~0: case ~0:
// Alarm. // Alarm.
kbd.scan () kbd.scan ()
if kbd.is_scanning (): if kbd.is_scanning ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL) __my_receiver.set_alarm (ALARM_INTERVAL)
break break
case IRQ_GPIO0: case IRQ_GPIO0:
// Always scan keyboard and touchpad on any interrupt. // Always scan keyboard and touchpad on any interrupt.
kbd.scan () kbd.scan ()
tp.check_events () tp.check_events ()
// Reregister the interrupt. // Reregister the interrupt.
register_interrupt (IRQ_GPIO0) Kernel::register_interrupt (IRQ_GPIO0)
break break
case CAP_KEYBOARD: case CAP_KEYBOARD:
set_cb (KEYBOARD_EVENT) set_cb (Cap (__tmp_slot, 0), KEYBOARD_EVENT)
kbd.send_initial () kbd.send_initial ()
break break
case CAP_TOUCHPAD: case CAP_TOUCHPAD:
set_cb (TOUCHPAD_EVENT) set_cb (Cap (__tmp_slot, 0), TOUCHPAD_EVENT)
tp.send_initial () tp.send_initial ()
break break
case CAP_LOCKLEDS: case CAP_LOCKLEDS:
leds.set (msg.data[0]) leds.set (msg.data[0].l)
break break
case CAP_PWM: case CAP_PWM:
pwm.set_backlight (msg.data[0]) pwm.set_backlight (msg.data[0].l)
break break

View File

@ -17,71 +17,70 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "devices.hh" #include "devices.hh"
#include "iris.h" #include "iris.hh"
static Capability kbd, tp, lockleds, pwm, lcd static Keyboard kbd, tp
static Display lcd
static Cap lockleds, pwm
// Event types.
enum type: enum type:
KBD = 0x10000 KBD = 0x10000
TP TP
static void send (Capability c, unsigned d):
receiver_create_capability (6, __my_receiver, d)
invoke_10 (c, cap_copy (6))
static void setup (): static void setup ():
unsigned state = 0 unsigned state = 0
Capability base = 7 unsigned slot = 2
while true: while true:
Message msg Cap::OMessage msg
wait (&msg, base, base + 1, base + 2, base + 3) Kernel::wait (&msg, slot)
switch msg.data[0]: switch msg.data[0].value ():
case INIT_SET_GPIO: case INIT_SET_GPIO:
kdebug ("gpio\n") kdebug ("gpio\n")
kbd = base kbd = Cap (slot, 0)
tp = base + 1 tp = Cap (slot, 1)
lockleds = base + 2 lockleds = Cap (slot, 2)
pwm = base + 3 pwm = Cap (slot, 3)
base += 4 ++slot
++state ++state
break break
case INIT_SET_LCD: case INIT_SET_LCD:
kdebug ("lcd\n") kdebug ("lcd\n")
lcd = base lcd = Cap (slot, 0)
++base ++slot
++state ++state
break break
if state == 2: if state == 2:
break break
send (kbd, KBD) kbd.set_cb (__my_receiver.create_capability (KBD).copy ())
send (tp, TP) tp.set_cb (__my_receiver.create_capability (TP).copy ())
invoke_01 (pwm, 1) pwm.invoke (1)
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":" char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
int main (): Num start ():
// Set up lcd first // Set up lcd first
schedule () Kernel::schedule ()
kdebug ("start init\n") kdebug ("start init\n")
setup () setup ()
kdebug ("run init\n") kdebug ("run init\n")
while true: while true:
Message msg Cap::OMessage msg
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE) Kernel::wait (&msg)
switch msg.protected_data: switch msg.cap_protected.value ():
case KBD: case KBD:
unsigned code = msg.data[0] unsigned code = msg.data[0].l
if code & KEYBOARD_RELEASE: if code & Keyboard::RELEASE:
break break
kdebug_char (decode_kbd[code]) kdebug_char (decode_kbd[code])
break break
case TP: case TP:
unsigned leds = 0 unsigned leds = 0
if msg.data[0] & 1: if msg.data[0].l & 1:
leds |= 0x1 leds |= 0x1
else: else:
leds |= 0x4 leds |= 0x4
if !(msg.data[0] & 0x10000): if !(msg.data[0].l & Keyboard::RELEASE):
leds |= 0x2 leds |= 0x2
invoke_01 (lockleds, leds) lockleds.invoke (leds)
break break

View File

@ -102,36 +102,37 @@ static void log_str (char const *str):
while *str: while *str:
log_char (*str++) log_char (*str++)
static void log_num (unsigned n): static void log_num (Num n):
char const *encode = "0123456789abcdef" char const *encode = "0123456789abcdef"
log_char ('[') log_char ('[')
for unsigned i = 0; i < 8; ++i: for unsigned i = 0; i < 8; ++i:
log_char (encode[(n >> (4 * (7 - i))) & 0xf]) log_char (encode[(n.h >> (4 * (7 - i))) & 0xf])
log_char (' ')
for unsigned i = 0; i < 8; ++i:
log_char (encode[(n.l >> (4 * (7 - i))) & 0xf])
log_char (']') log_char (']')
static void log_msg (Message *msg): static void log_msg (Cap::OMessage *msg):
log_str ("prot:") log_str ("cap_prot:")
log_num (msg->protected_data) log_num (msg->cap_protected)
log_str ("data:") log_str ("data:")
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 2; ++i:
log_num (msg->data[i]) log_num (msg->data[i])
log_str ("cap:")
for unsigned i = 0; i < 4; ++i:
log_num (msg->cap[i])
log_char ('\n') log_char ('\n')
int main (): Num start ():
map_lcd () map_lcd ()
map_cpm () map_cpm ()
Descriptor descriptor __attribute__ ((aligned (16))) Descriptor descriptor __attribute__ ((aligned (16)))
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
unsigned physical = alloc_range (__my_memory, pages) unsigned physical = Kernel::alloc_range (__my_memory, pages)
assert (physical) assert (physical)
for unsigned i = 0; i < pages; ++i: for unsigned i = 0; i < pages; ++i:
memory_create_page (6, __my_memory) Page p = __my_memory.create_page ()
alloc_physical (6, physical + i * PAGE_SIZE, 0, 1) p.alloc_physical (physical + i * PAGE_SIZE, false, true)
memory_map (__my_memory, 6, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1) __my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, true)
free_cap (p)
for unsigned y = 0; y < 480; ++y: for unsigned y = 0; y < 480; ++y:
unsigned g = (y << 6) / 480 unsigned g = (y << 6) / 480
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480) unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
@ -148,8 +149,9 @@ int main ():
ob = b ob = b
b = 0x1f b = 0x1f
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b) LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
memory_mapping (6, __my_memory, &descriptor) Page p = __my_memory.mapping (&descriptor)
unsigned physical_descriptor = page_physical_address (cap_copy (6)) + ((unsigned)&descriptor & ~PAGE_MASK) unsigned physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
free_cap (p)
descriptor.next = physical_descriptor descriptor.next = physical_descriptor
descriptor.frame = physical descriptor.frame = physical
descriptor.id = 0xdeadbeef descriptor.id = 0xdeadbeef
@ -158,30 +160,26 @@ int main ():
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0") __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
reset (physical_descriptor) reset (physical_descriptor)
Capability eof_cb = 0 Cap set_eof_cb = __my_receiver.create_capability (LCD_EOF_CB)
__my_parent.invoke (set_eof_cb.copy (), INIT_SET_LCD)
receiver_create_capability (6, __my_receiver, LCD_EOF_CB) Cap logcap = __my_receiver.create_capability (LCD_LOG)
invoke_11 (__my_parent, cap_copy (6), INIT_SET_LCD) __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
receiver_create_capability (15, __my_receiver, LCD_LOG)
__asm__ volatile ("li $a0, 1\nli $a1, 15\nbreak" ::: "a0", "a1", "memory")
unsigned slot = alloc_slot ()
while true: while true:
Message msg Cap::OMessage msg
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE) Kernel::wait (&msg, slot)
//log_msg (&msg) //log_msg (&msg)
switch msg.protected_data: switch msg.cap_protected.value ():
case IRQ_LCD: case IRQ_LCD:
lcd_clr_eof () lcd_clr_eof ()
if eof_cb: Cap (slot, 0).invoke ()
register_interrupt (IRQ_LCD) Cap (slot, 0) = Cap ()
invoke_00 (eof_cb)
break break
case LCD_EOF_CB: case LCD_EOF_CB:
eof_cb = msg.cap[0] Kernel::register_interrupt (IRQ_LCD)
if eof_cb:
register_interrupt (IRQ_LCD)
break break
case LCD_LOG: case LCD_LOG:
log_char (msg.data[0]) log_char (msg.data[0].l)
break break

File diff suppressed because it is too large Load Diff

1023
iris.h

File diff suppressed because it is too large Load Diff

514
iris.hhp Normal file
View File

@ -0,0 +1,514 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// iris.hhp: header file for userspace programs.
// 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/>.
#ifndef __IRIS_HHP
#define __IRIS_HHP
// Without the standard library, we don't have this definition.
// I preferred ((void*)0), but C++ has too strict type-checking to
// make that work.
#ifndef NULL
#define NULL 0
#endif
// Number of clock interrupts per second.
#define HZ 100
#define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
enum Exception_code:
NO_ERROR
ERR_WRITE_DENIED
ERR_UNMAPPED_READ
ERR_UNMAPPED_WRITE
ERR_INVALID_ADDRESS_READ
ERR_INVALID_ADDRESS_WRITE
ERR_RESERVED_INSTRUCTION
ERR_COPROCESSOR_UNUSABLE
ERR_OVERFLOW
ERR_TRAP
ERR_WATCHPOINT
ERR_BREAKPOINT
ERR_NO_PAGE_DIRECTORY
ERR_NO_PAGE_TABLE
ERR_OUT_OF_MEMORY
// The following are not raised, but returned.
ERR_INVALID_OPERATION
NUM_EXCEPTION_CODES
#ifndef NDEBUG
static const char *exception_name[NUM_EXCEPTION_CODES] = {
"no error",
"write denied",
"unmapped read",
"unmapped write",
"invalid address read",
"invalid address write",
"reserved instruction",
"coprocessor unusable",
"overflow",
"trap",
"watchpoint",
"breakpoint",
"no page directory",
"no page table",
"out of memory",
"invalid operation"
}
#endif
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
#define CAPTYPE_INVALID 0x000
#define CAPTYPE_RECEIVER 0x200
#define CAPTYPE_MEMORY 0x400
#define CAPTYPE_THREAD 0x600
#define CAPTYPE_PAGE 0x800
#define CAPTYPE_CAPS 0xa00
//#define CAPTYPE_??? 0xc00
//#define CAPTYPE_??? 0xe00
// All kernel capabilities have a master capability, which can create others.
#define CAP_MASTER 0
// Create, invoke and forget, with masked data set to 0.
#define CAP_MASTER_DIRECT 0
// Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31)
struct Num:
unsigned l, h
Num (unsigned long long n = 0) : l (n), h (n >> 32):
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
unsigned long long value () const:
return ((unsigned long long)h << 32) | l
unsigned &low ():
return l
unsigned &high ():
return h
unsigned const &low () const:
return l
unsigned const &high () const:
return h
// The start function has this prototype (there is no main function).
Num start ()
struct Cap
struct Caps
struct Receiver
struct Thread
struct Page
struct Memory
#define __receiver_num 0
#define __thread_num 1
#define __memory_num 2
#define __caps_num 3
#define __call_num 4
#define __parent_num 5
#define __tmp_num 6
// If this flag is set in a capability, it is copied instead of mapped.
// If it is set in the target capability, the Thread waits after the request.
#define CAP_COPY ((unsigned)0x80000000)
// This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY)
extern Receiver __my_receiver
extern Thread __my_thread
extern Memory __my_memory
extern Cap __my_call
extern Cap __my_parent
extern Caps __my_caps
extern Caps __tmp_caps
unsigned alloc_slot ()
unsigned alloc_cap ()
void free_slot (unsigned slot)
void free_cap (Cap cap)
#define __tmp_slot 1
struct Cap:
unsigned code
inline Cap copy () const
inline Cap ()
explicit inline Cap (unsigned c)
inline Cap (unsigned slot, unsigned idx)
inline unsigned slot () const
inline unsigned idx () const
struct IMessage
struct OMessage
inline void invoke (IMessage const *i, OMessage *o)
inline void call (IMessage *i, OMessage *o)
inline void invoke (Cap c, Num d0 = 0, Num d1 = 0, Caps caps = __tmp_caps)
inline void invoke (Num d0 = 0, Num d1 = 0)
inline Num call (Cap c, Num d0 = 0, Num d1 = 0, Caps caps = __tmp_caps, unsigned slot = ~0)
inline Num call (Num d0 = 0, Num d1 = 0, Caps caps = __tmp_caps, unsigned slot = ~0)
inline void clone (Caps caps, unsigned idx)
struct Caps : public Cap:
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
Caps (Cap c = Cap ()) : Cap (c):
struct Cap::IMessage:
Num data[2]
Caps caps
unsigned slot
unsigned num, first
Cap *set
struct Cap::OMessage:
Num data[2]
Num cap_protected
Num recv_protected
Cap Cap::copy () const:
return Cap (code | CAP_COPY)
Cap::Cap () : code (CAP_NONE):
Cap::Cap (unsigned c) : code (c):
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
unsigned Cap::slot () const:
return code >> 16
unsigned Cap::idx () const:
return code & 0xffff
void Cap::invoke (IMessage const *i, OMessage *o):
switch i->num:
default:
__asm__ volatile ("lw $t9, %0" :: "m"(i->set[9].code) : "t9")
case 9:
__asm__ volatile ("lw $t8, %0" :: "m"(i->set[8].code) : "t8")
case 8:
__asm__ volatile ("lw $t7, %0" :: "m"(i->set[7].code) : "t7")
case 7:
__asm__ volatile ("lw $t6, %0" :: "m"(i->set[6].code) : "t6")
case 6:
__asm__ volatile ("lw $t5, %0" :: "m"(i->set[5].code) : "t5")
case 5:
__asm__ volatile ("lw $t4, %0" :: "m"(i->set[4].code) : "t4")
case 4:
__asm__ volatile ("lw $t3, %0" :: "m"(i->set[3].code) : "t3")
case 3:
__asm__ volatile ("lw $t2, %0" :: "m"(i->set[2].code) : "t2")
case 2:
__asm__ volatile ("lw $t1, %0" :: "m"(i->set[1].code) : "t1")
case 1:
__asm__ volatile ("lw $t0, %0" :: "m"(i->set[0].code) : "t0")
case 0:
break
__asm__ volatile ("lw $v0, %2\n"
"\tlw $a0, 0($v0)\n"
"\tlw $a1, 4($v0)\n"
"\tlw $a2, 8($v0)\n"
"\tlw $a3, 12($v0)\n"
"\tlw $s0, 16($v0)\n"
"\tlw $s1, 20($v0)\n"
"\tlw $s2, 24($v0)\n"
"\tlw $s3, 28($v0)\n"
"\tlw $v0, %1\n"
"\tsyscall\n"
"\tlw $v0, %0\n"
"\tsw $a0, 0($v0)\n"
"\tsw $a1, 4($v0)\n"
"\tsw $a2, 8($v0)\n"
"\tsw $a3, 12($v0)\n"
"\tsw $s0, 16($v0)\n"
"\tsw $s1, 20($v0)\n"
"\tsw $s2, 24($v0)\n"
"\tsw $s3, 28($v0)\n"
: "=m"(o)
: "m"(code), "m"(i)
: "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3")
void Cap::call (IMessage *i, OMessage *o):
i->set[0] = *this
__my_call.copy ().invoke (i, o)
void Cap::invoke (Cap c, Num d0, Num d1, Caps caps):
IMessage i
OMessage o
i.slot = ~0
i.caps = caps
Cap cs[2]
cs[0] = c
i.set = cs
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
void Cap::invoke (Num d0, Num d1):
IMessage i
OMessage o
i.caps = Cap ()
i.slot = ~0
i.num = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
Num Cap::call (Cap c, Num d0, Num d1, Caps caps, unsigned slot):
IMessage i
OMessage o
Cap cs[2]
cs[1] = c
i.set = cs
i.caps = caps
i.slot = slot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
return o.data[0]
Num Cap::call (Num d0, Num d1, Caps caps, unsigned slot):
IMessage i
OMessage o
Cap cs[2]
i.set = cs
i.caps = caps
i.slot = slot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
return o.data[0]
void Cap::clone (Caps caps, unsigned idx):
IMessage i
OMessage o
Cap c = this->copy ()
i.set = &c
i.caps = caps
i.first = idx
i.num = 1
i.slot = ~0
i.data[0] = 0
i.data[1] = 0
invoke (&i, &o)
struct Receiver : public Cap:
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
Receiver (Cap c = Cap ()) : Cap (c):
enum request:
// Operations
SET_OWNER = 1
CREATE_CAPABILITY
CREATE_CALL_CAPABILITY
CREATE_ASYNC_CALL_CAPABILITY
GET_REPLY_PROTECTED_DATA
SET_REPLY_PROTECTED_DATA
GET_ALARM
SET_ALARM
ADD_ALARM
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
REPLY
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
CALL
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
CALL_ASYNC
void set_owner (Cap owner):
invoke (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
return ret
Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
void set_reply_protected_data (Num data):
invoke (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
unsigned get_alarm ():
return call (CAP_MASTER_DIRECT | GET_ALARM).l
unsigned add_alarm (unsigned data):
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
void set_alarm (unsigned data):
invoke (CAP_MASTER_DIRECT | SET_ALARM, data)
static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot)
Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
return ret
Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
return ret
struct Thread : public Cap:
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
Thread (Cap c = Cap ()) : Cap (c):
enum request:
// Info details are arch-specific.
GET_INFO = 1
SET_INFO
SCHEDULE
PRIV_ALLOC_RANGE
PRIV_PHYSICAL_ADDRESS
PRIV_ALLOC_PHYSICAL
PRIV_MAKE_PRIV
PRIV_GET_TOP_MEMORY
PRIV_REGISTER_INTERRUPT
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
SET_OWNER
// These get/set_info are not arch-specific.
enum info_type:
PC = ~0
SP = ~1
FLAGS = ~2
enum flags:
PRIV = 1 << 31
WAITING = 1 << 30
RUNNING = 1 << 29
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
void make_priv ():
__my_thread.invoke (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
unsigned get_info (unsigned info):
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
invoke (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
void set_pc (unsigned pc):
set_info (PC, pc)
void set_sp (unsigned sp):
set_info (SP, sp)
void set_flags (unsigned value, unsigned mask):
set_info (FLAGS, value, mask)
unsigned get_pc ():
return get_info (PC)
unsigned get_sp ():
return get_info (SP)
unsigned get_flags ():
return get_info (FLAGS)
void run (bool run):
set_flags (run ? RUNNING : 0, RUNNING)
void wait (bool wait):
set_flags (wait ? WAITING : 0, WAITING)
struct Page : public Cap:
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
Page (Cap c = Cap ()) : Cap (c):
enum request:
SHARE = 1
GET_FLAGS
SET_FLAGS
// Not an operation; a capability with this bit cannot write to the page.
READONLY = 8
enum share_detail:
// Operation details for PAGE_SHARE
// Forget the source page during the operation. This makes it a move.
FORGET
// Make the target independent of the source (make a copy if needed).
COPY
// Make the target unwritable.
//READONLY: use the value from request.
enum flag_values:
// This is a read-only flag, which is set if the Page is shared.
SHARED = 1
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
PAYING = 2
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
FRAME = 4
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
//READONLY = 8
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
PHYSICAL = 0x10
// This is a read-only flag, saying if this is uncachable memory.
UNCACHED = 0x20
void share (Cap target, unsigned flags):
invoke (target, CAP_MASTER_DIRECT | SHARE, flags)
unsigned get_flags ():
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
void set_flags (unsigned new_flags, unsigned mask):
invoke (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
unsigned physical_address ():
return __my_thread.call (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
void alloc_physical (unsigned address, bool cachable, bool freeable):
__my_thread.invoke (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
struct Memory : public Cap:
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
Memory (Cap c = Cap ()) : Cap (c):
enum request:
CREATE = 1
DESTROY
LIST
MAP
MAPPING
GET_LIMIT
SET_LIMIT
Page create_page (Page ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
return ret
Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
return ret
Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
return ret
Memory create_memory (Memory ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
return ret
Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
return ret
void destroy (Cap target):
invoke (target, CAP_MASTER_DIRECT | DESTROY)
// TODO: LIST
void map (Cap page, unsigned address, bool readonly):
if readonly:
address |= Page::READONLY
invoke (page, CAP_MASTER_DIRECT | MAP, address)
Page mapping (void *address, Page ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
return ret
unsigned get_limit (unsigned limit):
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
void set_limit (unsigned limit):
invoke (CAP_MASTER_DIRECT | SET_LIMIT, limit)
struct Kernel:
static void wait (Cap::OMessage *o, unsigned slot = __tmp_slot):
Cap::IMessage i
i.slot = slot
i.num = 0
Cap ().copy ().invoke (&i, o)
static void schedule ():
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
static void register_interrupt (unsigned num):
__my_thread.invoke (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static void unregister_interrupt (unsigned num):
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static Cap get_top_memory ():
__my_thread.call (__tmp_slot, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
return Cap (__tmp_slot, 0)
static unsigned alloc_range (Cap memory, unsigned pages):
__my_thread.call (memory, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages)
void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot):
__my_receiver.set_alarm (value)
Kernel::wait (ret, slot)
#if 1
// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.
#define kdebug_char(c) do { unsigned d = (c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(d) : "a0", "a1", "memory"); } while (0)
#else
#define kdebug_char(c) do {} while (0)
#endif
#define kdebug(str) do { const char *s = (str); while (*s) { kdebug_char (*s); ++s; } } while (0)
static void kdebug_num (unsigned n):
unsigned i
const char *encode = "0123456789abcdef"
for i = 0; i < 8; ++i:
kdebug_char (encode[(n >> (4 * (7 - i))) & 0xf])
#endif

View File

@ -21,7 +21,7 @@
// Include definitions which are shared with user space. // Include definitions which are shared with user space.
#define __KERNEL #define __KERNEL
#include "iris.h" #include "iris.hh"
// Normally define all variables in this file as extern. // Normally define all variables in this file as extern.
// Exactly once (in data.ccp), EXTERN is predefined empty. // Exactly once (in data.ccp), EXTERN is predefined empty.
@ -30,145 +30,146 @@
#define EXTERN extern #define EXTERN extern
#endif #endif
struct Page struct kPage
struct Thread struct kThread
struct Message struct kMessage
struct Receiver struct kReceiver
struct Capability struct kCapability
struct Caps struct kCaps
struct Memory struct kMemory
typedef Page *PageP typedef kPage *kPageP
typedef Thread *ThreadP typedef kThread *kThreadP
typedef Message *MessageP typedef kMessage *kMessageP
typedef Receiver *ReceiverP typedef kReceiver *kReceiverP
typedef Capability *CapabilityP typedef kCapability *kCapabilityP
typedef Caps *CapsP typedef kCaps *kCapsP
typedef Memory *MemoryP typedef kMemory *kMemoryP
typedef void *Pointer typedef void *kPointer
typedef unsigned Protected struct kCapRef:
kCapsP caps
struct CapRef:
CapsP caps
unsigned index unsigned index
inline Capability *deref () inline kCapability *deref ()
operator bool (): operator bool ():
return deref () != NULL return deref () != NULL
Capability *operator-> (): kCapability *operator-> ():
return deref () return deref ()
void reset (): void reset ():
caps = NULL caps = NULL
CapRef (CapsP c, unsigned i) : caps (c), index (i): kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
CapRef () : caps (NULL), index (~0): kCapRef () : caps (NULL), index (~0):
inline void clone (CapRef source, bool copy) inline void clone (kCapRef source, bool copy)
inline void set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL) inline void set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
struct Object: struct kObject:
CapRef refs kCapRef refs
MemoryP address_space kMemoryP address_space
// Next and previous object of the same type in any page. // Next and previous object of the same type in any page.
Pointer prev, next kPointer prev, next
inline bool is_free () inline bool is_free ()
struct Free : public Object: struct kFree : public kObject:
// This marker is ~0. No other kernel structure may allow this value // This marker is ~0. No other kernel structure may allow this value
// at this point. It is used to recognize free chunks. // at this point. It is used to recognize free chunks.
unsigned marker unsigned marker
bool Object::is_free (): bool kObject::is_free ():
return ((Free *)this)->marker == ~0 return ((kFree *)this)->marker == ~0
// Include architecture-specific parts. // Include architecture-specific parts.
#include "arch.hh" #include "arch.hh"
struct Message : public Object: struct kMessage : public kObject:
Protected protected_data Num cap_protected
unsigned data[4] Num data[2]
unsigned char capabilities[4] kCapsP caps
struct Capability : public Object: struct kCapability : public kObject:
struct Context: struct Context:
unsigned data[4] Num data[2]
CapRef cap[4] kCaps *caps
bool copy[4] kReceiverP target
ReceiverP target kCapRef parent
CapRef parent kCapRef children
CapRef children kCapRef sibling_prev, sibling_next
CapRef sibling_prev, sibling_next Num cap_protected
Protected protected_data inline void invoke (kCapability::Context *c)
void invoke (Context *c)
void invalidate () void invalidate ()
struct Thread : public Object: struct kThread : public kObject:
ReceiverP receivers kReceiverP receivers
unsigned pc, sp unsigned pc, sp
Thread_arch arch kThread_arch arch
unsigned flags unsigned flags
ThreadP schedule_prev, schedule_next kThreadP schedule_prev, schedule_next
CapRef rcaps[4] unsigned recv_slot
// caps is an array of slots pointers to Capses. // caps is an array of slots pointers to kCapses.
unsigned slots unsigned slots
// TODO: handle freeing of capses which are in use. // TODO: handle freeing of capses which are in use.
CapsP caps[1] kCapsP caps[1]
void raise (unsigned code, unsigned data) void raise (unsigned code, unsigned data)
void run () void run ()
void unrun () void unrun ()
void wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3) void wait ()
void unwait () void unwait ()
bool is_waiting (): bool is_waiting ():
return flags & THREAD_FLAG_WAITING return flags & Thread::WAITING
CapRef find_capability (unsigned code, bool *copy) kCapRef find_capability (unsigned code, bool *copy)
void fill_slot (unsigned slot, kCaps *new_caps)
struct Receiver : public Object: struct kReceiver : public kObject:
ThreadP owner kThreadP owner
ReceiverP prev_owned, next_owned kReceiverP prev_owned, next_owned
ReceiverP prev_alarm, next_alarm kReceiverP prev_alarm, next_alarm
unsigned alarm_count unsigned alarm_count
// random is used like the tlb random register to find invalid caps to store the message to. // random is used like the tlb random register to find invalid caps to store the message to.
unsigned random unsigned random
CapsP caps kCapsP caps
// These are capabilities which call this receiver on invoke. // These are capabilities which call this receiver on invoke.
CapRef capabilities kCapRef capabilities
// The message queue. Messages are added at the tail, and removed at the front. // The message queue. kMessages are added at the tail, and removed at the front.
MessageP messages kMessageP messages
MessageP last_message kMessageP last_message
Protected reply_protected_data Num recv_protected
Num reply_protected_data
bool protected_only bool protected_only
void own (ThreadP o) // This limit is for messages stored in its address space. There is unlimited space if senders provide it.
unsigned queue_limit
void own (kThreadP o)
void orphan () void orphan ()
bool try_deliver () bool try_deliver ()
bool send_message (Protected protected_data, Capability::Context *c) bool send_message (Num cap_protected, kCapability::Context *c)
struct Page : public Object: struct kPage : public kObject:
unsigned frame unsigned frame
unsigned flags unsigned flags
PageP share_first kPageP share_first
PageP share_prev, share_next kPageP share_prev, share_next
Page_arch arch kPage_arch arch
void forget () void forget ()
struct Caps : public Object: struct kCaps : public kObject:
unsigned size unsigned size
Capability caps[1] kCapability caps[1]
Capability *cap (unsigned idx): kCapability *cap (unsigned idx):
return &caps[idx] return &caps[idx]
void set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL) void set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
void clone (unsigned index, CapRef source, bool copy) void clone (unsigned index, kCapRef source, bool copy)
struct Memory : public Object: struct kMemory : public kObject:
Free *frees kFree *frees
PageP pages kPageP pages
ThreadP threads kThreadP threads
ReceiverP receivers kReceiverP receivers
CapsP capses kCapsP capses
MemoryP memories kMemoryP memories
unsigned limit, used unsigned limit, used
Memory_arch arch kMemory_arch arch
inline bool map (Page *page, unsigned address, bool write) inline bool map (kPage *page, unsigned address, bool write)
inline void unmap (Page *page, unsigned address) inline void unmap (kPage *page, unsigned address)
inline Page *get_mapping (unsigned address, bool *writable) inline kPage *get_mapping (unsigned address, bool *readonly)
// Allocation of pages. // Allocation of pages.
bool use (unsigned num = 1) bool use (unsigned num = 1)
@ -180,28 +181,28 @@ struct Memory : public Object:
// Allocation routines for kernel structures // Allocation routines for kernel structures
void *search_free (unsigned size, void **first) void *search_free (unsigned size, void **first)
Page *alloc_page () kPage *alloc_page ()
Thread *alloc_thread (unsigned size) kThread *alloc_thread (unsigned size)
Message *alloc_message (Receiver *target) kMessage *alloc_message (kReceiver *target)
Receiver *alloc_receiver () kReceiver *alloc_receiver ()
Caps *alloc_caps (unsigned size) kCaps *alloc_caps (unsigned size)
Memory *alloc_memory () kMemory *alloc_memory ()
void free_page (Page *page) void free_page (kPage *page)
void free_thread (Thread *thread) void free_thread (kThread *thread)
void free_message (Receiver *owner, Message *message) void free_message (kReceiver *owner, kMessage *message)
void free_receiver (Receiver *receiver) void free_receiver (kReceiver *receiver)
void free_caps (Caps *page) void free_caps (kCaps *page)
void free_memory (Memory *mem) void free_memory (kMemory *mem)
void free_obj (Object *obj, void **first) void free_obj (kObject *obj, void **first)
// Functions which can be called from assembly must not be mangled. // Functions which can be called from assembly must not be mangled.
extern "C": extern "C":
// Panic. n is sent over caps led. message is currently ignored. // Panic. n is sent over caps led. message is currently ignored.
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "") void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
EXTERN unsigned dbg_code EXTERN unsigned dbg_code
EXTERN CapRef dbg_cap EXTERN kCapRef dbg_cap
void dbg_log_char (unsigned ch) void dbg_log_char (unsigned ch)
void dbg_log (char const *str) void dbg_log (char const *str)
void dbg_log_num (unsigned num) void dbg_log_num (unsigned num)
@ -212,46 +213,51 @@ extern "C":
void schedule () void schedule ()
void timer_interrupt () void timer_interrupt ()
EXTERN Memory top_memory EXTERN kMemory top_memory
EXTERN ReceiverP first_alarm EXTERN kReceiverP first_alarm
EXTERN Thread idle EXTERN kThread idle
EXTERN Memory idle_memory EXTERN kMemory idle_memory
EXTERN Page idle_page EXTERN kPage idle_page
EXTERN ThreadP first_scheduled EXTERN kThreadP first_scheduled
EXTERN ThreadP current, old_current EXTERN kThreadP current, old_current
EXTERN bool do_schedule EXTERN bool do_schedule
// Defined in memory.cc // Defined in memory.ccp
unsigned init_memory (unsigned mem) unsigned init_memory (unsigned mem)
unsigned raw_zalloc () unsigned raw_zalloc ()
void raw_pfree (unsigned page) void raw_pfree (unsigned page)
unsigned phys_alloc (unsigned num) unsigned phys_alloc (unsigned num)
void phys_free (unsigned page, unsigned num) void phys_free (unsigned page, unsigned num)
// Defined by architecture-specific files. // Defind in invoke.ccp
void Thread_arch_init (Thread *thread) void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self)
void Thread_arch_receive (Thread *thread, Protected protected_data, unsigned *data)
unsigned *Thread_arch_info (Thread *thread, unsigned num)
void Memory_arch_init (Memory *mem)
void Memory_arch_free (Memory *mem)
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write)
void Memory_arch_unmap (Memory *mem, Page *page, unsigned address)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable)
void Page_arch_update_mapping (Page *page)
void arch_register_interrupt (unsigned num, ReceiverP r)
bool Memory::map (Page *page, unsigned address, bool write): // Defined by architecture-specific files.
return Memory_arch_map (this, page, address, write) void kThread_arch_init (kThread *thread)
void Memory::unmap (Page *page, unsigned address): void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data)
Memory_arch_unmap (this, page, address) unsigned *kThread_arch_info (kThread *thread, unsigned num)
Page *Memory::get_mapping (unsigned address, bool *writable): void kMemory_arch_init (kMemory *mem)
return Memory_arch_get_mapping (this, address, writable) void kMemory_arch_free (kMemory *mem)
Capability *CapRef::deref (): bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool write)
void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address)
kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly)
void kPage_arch_update_mapping (kPage *page)
void arch_register_interrupt (unsigned num, kReceiverP r)
bool kMemory::map (kPage *page, unsigned address, bool write):
return kMemory_arch_map (this, page, address, write)
void kMemory::unmap (kPage *page, unsigned address):
kMemory_arch_unmap (this, page, address)
kPage *kMemory::get_mapping (unsigned address, bool *readonly):
return kMemory_arch_get_mapping (this, address, readonly)
kCapability *kCapRef::deref ():
return caps ? caps->cap (index) : NULL return caps ? caps->cap (index) : NULL
void CapRef::clone (CapRef source, bool copy): void kCapRef::clone (kCapRef source, bool copy):
caps->clone (index, source, copy) caps->clone (index, source, copy)
void CapRef::set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr): void kCapRef::set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
caps->set (index, target, pdata, parent, parent_ptr) caps->set (index, target, pdata, parent, parent_ptr)
void kCapability::invoke (kCapability::Context *c):
::invoke (target, cap_protected, c, this)
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0) #define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)

View File

@ -31,22 +31,22 @@ void phys_free (unsigned page, unsigned num):
#else #else
struct FreePages: struct kFreePages:
FreePages *prev, *next kFreePages *prev, *next
unsigned num unsigned num
static FreePages *first_free static kFreePages *first_free
unsigned init_memory (unsigned mem): unsigned init_memory (unsigned mem):
first_free = (FreePages *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK) first_free = (kFreePages *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
first_free->prev = NULL first_free->prev = NULL
first_free->next = NULL first_free->next = NULL
first_free->num = ((mem & PAGE_MASK) - ((unsigned)first_free - 0x80000000)) >> PAGE_BITS first_free->num = ((mem & PAGE_MASK) - ((unsigned)first_free - 0x80000000)) >> PAGE_BITS
return first_free->num return first_free->num
unsigned phys_alloc (unsigned num): unsigned phys_alloc (unsigned num):
FreePages *choice = NULL kFreePages *choice = NULL
for FreePages *p = first_free; p; p = p->next: for kFreePages *p = first_free; p; p = p->next:
if p->num < num: if p->num < num:
continue continue
if choice && choice->num < p->num: if choice && choice->num < p->num:
@ -75,7 +75,7 @@ void phys_free (unsigned page, unsigned num):
unsigned size = num << PAGE_BITS unsigned size = num << PAGE_BITS
if !first_free || (unsigned)first_free > page: if !first_free || (unsigned)first_free > page:
// This is the first free block. // This is the first free block.
FreePages *n = (FreePages *)page kFreePages *n = (kFreePages *)page
n->prev = NULL n->prev = NULL
if (unsigned)first_free == page + size: if (unsigned)first_free == page + size:
// It fits exactly before the previous first free block. // It fits exactly before the previous first free block.
@ -89,13 +89,13 @@ void phys_free (unsigned page, unsigned num):
if n->next: if n->next:
n->next->prev = n n->next->prev = n
return return
FreePages *p kFreePages *p
for p = first_free; p->next && (unsigned)p->next < page; p = p->next: for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
// Do nothing. // Do nothing.
// The new block should be inserted directly after p. // The new block should be inserted directly after p.
if (unsigned)p->next == page + size: if (unsigned)p->next == page + size:
// It can be merged with the block after it: do that. // It can be merged with the block after it: do that.
FreePages *n = (FreePages *)page kFreePages *n = (kFreePages *)page
n->prev = p n->prev = p
n->next = p->next->next n->next = p->next->next
if n->next: if n->next:
@ -115,7 +115,7 @@ void phys_free (unsigned page, unsigned num):
p->num += num p->num += num
return return
// The new block cannot be merged at all. // The new block cannot be merged at all.
FreePages *n = (FreePages *)page kFreePages *n = (kFreePages *)page
n->next = p->next n->next = p->next
n->prev = p n->prev = p
if n->next: if n->next:
@ -130,18 +130,18 @@ unsigned raw_zalloc ():
void raw_pfree (unsigned page): void raw_pfree (unsigned page):
return phys_free (page, 1) return phys_free (page, 1)
unsigned Memory::zalloc (): unsigned kMemory::zalloc ():
if !use (): if !use ():
dbg_log ("limit reached: allocation not allowed") dbg_log ("limit reached: allocation not allowed")
return NULL return NULL
return raw_zalloc () return raw_zalloc ()
void Memory::pfree (unsigned page): void kMemory::pfree (unsigned page):
unuse () unuse ()
return raw_pfree (page) return raw_pfree (page)
unsigned Memory::palloc (): unsigned kMemory::palloc ():
return zalloc () return zalloc ()
void Memory::zfree (unsigned page): void kMemory::zfree (unsigned page):
pfree (page) pfree (page)

View File

@ -19,7 +19,7 @@
#define ARCH #define ARCH
#include "../kernel.hh" #include "../kernel.hh"
void Thread_arch_init (Thread *thread): void kThread_arch_init (kThread *thread):
thread->arch.at = 0 thread->arch.at = 0
thread->arch.v0 = 0 thread->arch.v0 = 0
thread->arch.v1 = 0 thread->arch.v1 = 0
@ -45,14 +45,17 @@ void Thread_arch_init (Thread *thread):
thread->arch.k0 = 0 thread->arch.k0 = 0
thread->arch.k1 = 0 thread->arch.k1 = 0
void Thread_arch_receive (Thread *thread, unsigned protected_data, unsigned *data): void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data):
thread->arch.t0 = data[0] thread->arch.a0 = data[0].l
thread->arch.t1 = data[1] thread->arch.a1 = data[0].h
thread->arch.t2 = data[2] thread->arch.a2 = data[1].l
thread->arch.t3 = data[3] thread->arch.a3 = data[1].h
thread->arch.v0 = protected_data thread->arch.s0 = cap_protected.l
thread->arch.s1 = cap_protected.h
thread->arch.s2 = recv_protected.l
thread->arch.s3 = recv_protected.h
unsigned *Thread_arch_info (Thread *thread, unsigned num): unsigned *kThread_arch_info (kThread *thread, unsigned num):
switch num: switch num:
case 1: case 1:
return &thread->arch.at return &thread->arch.at
@ -119,29 +122,29 @@ unsigned *Thread_arch_info (Thread *thread, unsigned num):
default: default:
return NULL return NULL
void Memory_arch_init (Memory *mem): void kMemory_arch_init (kMemory *mem):
mem->arch.asid = 1 mem->arch.asid = 1
mem->arch.directory = NULL mem->arch.directory = NULL
mem->arch.shadow = NULL mem->arch.shadow = NULL
void Memory_arch_free (Memory *mem): void kMemory_arch_free (kMemory *mem):
while mem->arch.first_page_table: while mem->arch.first_page_table:
mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping) mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping)
if (Memory *)asids[mem->arch.asid] == mem: if (kMemory *)asids[mem->arch.asid] == mem:
flush_tlb (mem->arch.asid) flush_tlb (mem->arch.asid)
asids[mem->arch.asid] = asids[0] asids[mem->arch.asid] = asids[0]
asids[0] = mem->arch.asid asids[0] = mem->arch.asid
mem->unuse () mem->unuse ()
mem->zfree ((unsigned)mem->arch.directory) mem->zfree ((unsigned)mem->arch.directory)
static arch_page_table *alloc_page_table (Memory *mem): static arch_page_table *alloc_page_table (kMemory *mem):
arch_page_table *ret = (arch_page_table *)mem->search_free (sizeof (arch_page_table), (void **)&mem->arch.first_page_table) arch_page_table *ret = (arch_page_table *)mem->search_free (sizeof (arch_page_table), (void **)&mem->arch.first_page_table)
if !ret: if !ret:
return NULL return NULL
ret->first_page = NULL ret->first_page = NULL
return ret return ret
static arch_page *alloc_page (Memory *mem, arch_page_table *t): static arch_page *alloc_page (kMemory *mem, arch_page_table *t):
arch_page *ret = (arch_page *)mem->search_free (sizeof (arch_page), (void **)&t->first_page) arch_page *ret = (arch_page *)mem->search_free (sizeof (arch_page), (void **)&t->first_page)
if !ret: if !ret:
return NULL return NULL
@ -152,7 +155,7 @@ static arch_page *alloc_page (Memory *mem, arch_page_table *t):
return ret return ret
static void free_page_table (arch_page_table *t, unsigned idx): static void free_page_table (arch_page_table *t, unsigned idx):
Memory *mem = t->address_space kMemory *mem = t->address_space
mem->zfree ((unsigned)mem->arch.directory[idx]) mem->zfree ((unsigned)mem->arch.directory[idx])
mem->arch.directory[idx] = NULL mem->arch.directory[idx] = NULL
mem->arch.shadow[idx] = NULL mem->arch.shadow[idx] = NULL
@ -188,19 +191,19 @@ static void free_page (arch_page_table *t, arch_page *p):
if !t->first_page: if !t->first_page:
free_page_table (t, idx) free_page_table (t, idx)
static unsigned make_entry_lo (Page *page, bool write): static unsigned make_entry_lo (kPage *page, bool readonly):
if !page->frame: if !page->frame:
return 0 return 0
unsigned flags unsigned flags
if page->flags & PAGE_FLAG_UNCACHED: if page->flags & Page::UNCACHED:
flags = 0x10 | 0x2 flags = 0x10 | 0x2
else: else:
flags = 0x18 | 0x2 flags = 0x18 | 0x2
if write: if !readonly:
flags |= 0x4 flags |= 0x4
return ((page->frame & ~0x80000000) >> 6) | flags return ((page->frame & ~0x80000000) >> 6) | flags
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write): bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool readonly):
if address >= 0x80000000: if address >= 0x80000000:
return false return false
address &= PAGE_MASK address &= PAGE_MASK
@ -243,10 +246,10 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
return false return false
unsigned idx = (address >> 12) & ((1 << 9) - 1) unsigned idx = (address >> 12) & ((1 << 9) - 1)
if table[idx]: if table[idx]:
mem->unmap ((Page *)table[idx + 0x200], address) mem->unmap ((kPage *)table[idx + 0x200], address)
table[idx] = make_entry_lo (page, write) table[idx] = make_entry_lo (page, readonly)
table[idx + 0x200] = (unsigned)p table[idx + 0x200] = (unsigned)p
p->mapping = address + write p->mapping = address + readonly
p->page = page p->page = page
p->next_mapped = page->arch.first_mapped p->next_mapped = page->arch.first_mapped
if p->next_mapped: if p->next_mapped:
@ -254,7 +257,7 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
page->arch.first_mapped = p page->arch.first_mapped = p
return true return true
void Memory_arch_unmap (Memory *mem, Page *page, unsigned address): void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address):
unsigned didx = address >> 21 unsigned didx = address >> 21
unsigned tidx = (address >> 12) & ((1 << 9) - 1) unsigned tidx = (address >> 12) & ((1 << 9) - 1)
unsigned *table = mem->arch.directory[didx] unsigned *table = mem->arch.directory[didx]
@ -264,34 +267,34 @@ void Memory_arch_unmap (Memory *mem, Page *page, unsigned address):
table[tidx + 0x200] = 0 table[tidx + 0x200] = 0
free_page (t, p) free_page (t, p)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable): kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly):
if address >= 0x80000000: if address >= 0x80000000:
return NULL return NULL
unsigned *table = mem->arch.directory[address >> 21] unsigned *table = mem->arch.directory[address >> 21]
unsigned idx = (address >> 12) & ((1 << 9) - 1) unsigned idx = (address >> 12) & ((1 << 9) - 1)
arch_page *page = (arch_page *)table[idx + 0x200] arch_page *page = (arch_page *)table[idx + 0x200]
if writable: if readonly:
*writable = table[idx] & 4 *readonly = !(table[idx] & 4)
return page->page return page->page
void Page_arch_update_mapping (Page *page): void kPage_arch_update_mapping (kPage *page):
if !page->arch.first_mapped: if !page->arch.first_mapped:
return return
Memory *as = page->address_space kMemory *as = page->address_space
unsigned target = make_entry_lo (page, page->flags & PAGE_FLAG_WRITABLE) unsigned target = make_entry_lo (page, page->flags & Page::READONLY)
for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped: for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped:
unsigned de = p->mapping >> 21 unsigned de = p->mapping >> 21
unsigned te = (p->mapping >> 12) & ((1 << 9) - 1) unsigned te = (p->mapping >> 12) & ((1 << 9) - 1)
bool write = p->mapping & 1 bool readonly = p->mapping & 1
unsigned t unsigned t
if p->mapping & 1: if readonly:
t = target
else:
t = target & ~0x4 t = target & ~0x4
else:
t = target
as->arch.directory[de][te] = t as->arch.directory[de][te] = t
tlb_reset (p->mapping & ~1, as->arch.asid, t) tlb_reset (p->mapping & ~1, as->arch.asid, t)
void arch_register_interrupt (unsigned num, Receiver *r): void arch_register_interrupt (unsigned num, kReceiver *r):
arch_interrupt_receiver[num] = r arch_interrupt_receiver[num] = r
// And enable or disable the interrupt. // And enable or disable the interrupt.
if r: if r:

View File

@ -68,7 +68,7 @@
#endif #endif
#ifdef __KERNEL #ifdef __KERNEL
// register save positions in Thread // register save positions in kThread
#define SAVE_PC (6 * 4) #define SAVE_PC (6 * 4)
#define SAVE_SP (SAVE_PC + 4) #define SAVE_SP (SAVE_PC + 4)
#define SAVE_AT (SAVE_SP + 4) #define SAVE_AT (SAVE_SP + 4)
@ -108,7 +108,7 @@
void flush_tlb (unsigned asid) void flush_tlb (unsigned asid)
struct Thread_arch: struct kThread_arch:
unsigned at, v0, v1, a0, a1, a2, a3 unsigned at, v0, v1, a0, a1, a2, a3
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
unsigned s0, s1, s2, s3, s4, s5, s6, s7 unsigned s0, s1, s2, s3, s4, s5, s6, s7
@ -122,41 +122,41 @@ struct Thread_arch:
// bits 12-20 are an index in the page table, bits 21-30 // bits 12-20 are an index in the page table, bits 21-30
// are an index in the page directory and bit 31 is always 0. // are an index in the page directory and bit 31 is always 0.
struct arch_page : public Object : struct arch_page : public kObject :
Page *page kPage *page
unsigned mapping unsigned mapping
arch_page *prev_mapped, *next_mapped arch_page *prev_mapped, *next_mapped
struct arch_page_table : public Object : struct arch_page_table : public kObject :
arch_page *first_page arch_page *first_page
struct Page_arch: struct kPage_arch:
arch_page *first_mapped arch_page *first_mapped
struct Memory_arch: struct kMemory_arch:
unsigned asid unsigned asid
unsigned **directory unsigned **directory
arch_page_table **shadow arch_page_table **shadow
arch_page_table *first_page_table arch_page_table *first_page_table
// Pointers to Memory when asid is taken, index of next free, or 0, if free. // Pointers to kMemory when asid is taken, index of next free, or 0, if free.
// asid[0] is used as index to first free asid. // asid[0] is used as index to first free asid.
EXTERN unsigned asids[64] EXTERN unsigned asids[64]
EXTERN Receiver *arch_interrupt_receiver[32] EXTERN kReceiverP arch_interrupt_receiver[32]
// Functions which can be called from assembly must not be mangled. // Functions which can be called from assembly must not be mangled.
extern "C": extern "C":
// Kernel entry points, called from entry.S. // Kernel entry points, called from entry.S.
Thread *interrupt () kThread *interrupt ()
Thread *cache_error () kThread *cache_error ()
Thread *exception () kThread *exception ()
Thread *tlb_refill () kThread *tlb_refill ()
#ifdef INIT #ifdef INIT
// Initialize most things (the rest is done in boot.S) // Initialize most things (the rest is done in boot.S)
void init (unsigned mem) void init (unsigned mem)
// Start running the idle task for the first time. // Start running the idle task for the first time.
void run_idle (Thread *self) void run_idle (kThread *self)
#endif #endif
// These are "extern", not "EXTERN", because they really are defined elsewhere. // These are "extern", not "EXTERN", because they really are defined elsewhere.

View File

@ -30,7 +30,7 @@ static void init_idle ():
idle.schedule_next = NULL idle.schedule_next = NULL
idle.address_space = &idle_memory idle.address_space = &idle_memory
idle.refs.reset () idle.refs.reset ()
idle.flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV idle.flags = Thread::RUNNING | Thread::PRIV
// initialize idle_memory. // initialize idle_memory.
idle_memory.prev = NULL idle_memory.prev = NULL
idle_memory.next = NULL idle_memory.next = NULL
@ -49,7 +49,7 @@ static void init_idle ():
idle_page.prev = NULL idle_page.prev = NULL
idle_page.next = NULL idle_page.next = NULL
idle_page.frame = 0x80000000 idle_page.frame = 0x80000000
idle_page.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME idle_page.flags = Page::PAYING | Page::FRAME
idle_page.refs.reset () idle_page.refs.reset ()
idle_page.address_space = NULL idle_page.address_space = NULL
current = &idle current = &idle
@ -104,15 +104,15 @@ static void init_cp0 ():
// exceptions in the bootup code will fill EPC and friends. // exceptions in the bootup code will fill EPC and friends.
static void init_threads (): static void init_threads ():
Thread *previous = NULL kThread *previous = NULL
first_scheduled = NULL first_scheduled = NULL
first_alarm = NULL first_alarm = NULL
Receiver *init_receiver = NULL kReceiver *init_receiver = NULL
for unsigned i = 0; i < NUM_THREADS; ++i: for unsigned i = 0; i < NUM_THREADS; ++i:
Memory *mem = top_memory.alloc_memory () kMemory *mem = top_memory.alloc_memory ()
assert (mem) assert (mem)
Thread *thread = mem->alloc_thread (3) kThread *thread = mem->alloc_thread (3)
Page **pages = (Page **)mem->zalloc () kPage **pages = (kPage **)mem->zalloc ()
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i] Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
for unsigned j = 0; j < SELFMAG; ++j: for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]: if header->e_ident[j] != ELFMAG[j]:
@ -139,7 +139,7 @@ static void init_threads ():
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize) Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC: if ~shdr->sh_flags & SHF_ALLOC:
continue continue
bool writable = shdr->sh_flags & SHF_WRITE bool readonly = !(shdr->sh_flags & SHF_WRITE)
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR //bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS: if shdr->sh_type != SHT_NOBITS:
unsigned file_offset = shdr->sh_offset >> PAGE_BITS unsigned file_offset = shdr->sh_offset >> PAGE_BITS
@ -152,18 +152,18 @@ static void init_threads ():
if !pages[idx]: if !pages[idx]:
pages[idx] = mem->alloc_page () pages[idx] = mem->alloc_page ()
pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS) pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS)
pages[idx]->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME pages[idx]->flags = Page::PAYING | Page::FRAME
++top_memory.limit ++top_memory.limit
mem->use () mem->use ()
if !mem->map (pages[idx], p, writable): if !mem->map (pages[idx], p, readonly):
panic (0x22446688, "unable to map initial page") panic (0x22446688, "unable to map initial page")
return return
else: else:
if !writable: if readonly:
panic (0x33399993, "unwritable bss section") panic (0x33399993, "unwritable bss section")
return return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Page *page = mem->get_mapping (p, &writable) kPage *page = mem->get_mapping (p, &readonly)
if !page: if !page:
page = mem->alloc_page () page = mem->alloc_page ()
if !page: if !page:
@ -173,12 +173,12 @@ static void init_threads ():
if !page->frame: if !page->frame:
panic (0x02220022, "out of memory"); panic (0x02220022, "out of memory");
return return
page->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME page->flags = Page::PAYING | Page::FRAME
if !mem->map (page, p, true): if !mem->map (page, p, true):
panic (0x33557799, "unable to map initial bss page") panic (0x33557799, "unable to map initial bss page")
return return
else: else:
if !writable: if readonly:
panic (0x20203030, "bss section starts on read-only page") panic (0x20203030, "bss section starts on read-only page")
return return
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4: for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
@ -192,28 +192,26 @@ static void init_threads ():
continue continue
++top_memory.limit ++top_memory.limit
top_memory.pfree (thread_start[i] + (p << PAGE_BITS)) top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
Page *stackpage = mem->alloc_page () kPage *stackpage = mem->alloc_page ()
stackpage->frame = mem->zalloc () stackpage->frame = mem->zalloc ()
stackpage->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME stackpage->flags = Page::PAYING | Page::FRAME
if !stackpage || !mem->map (stackpage, 0x7ffff000, true): if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
panic (0x13151719, "unable to map initial stack page") panic (0x13151719, "unable to map initial stack page")
return return
thread->caps[0] = mem->alloc_caps (16) thread->caps[0] = mem->alloc_caps (16)
for unsigned r = 0; r < 4; ++r: kReceiver *recv = mem->alloc_receiver ()
thread->rcaps[r] = CapRef ()
Receiver *recv = mem->alloc_receiver ()
recv->owner = thread recv->owner = thread
thread->receivers = recv thread->receivers = recv
thread->caps[0]->set (__my_receiver, (ReceiverP)(CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS), (Protected)recv, CapRef ()) thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->caps[0]->set (__my_thread, (ReceiverP)(CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS), (Protected)thread, CapRef ()) thread->caps[0]->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Num ((unsigned)thread), kCapRef (), &thread->refs)
thread->caps[0]->set (__my_memory, (ReceiverP)(CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS), (Protected)mem, CapRef ()) thread->caps[0]->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Num ((unsigned)mem), kCapRef (), &mem->refs)
thread->caps[0]->set (__my_call, (ReceiverP)(CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)), (Protected)recv, CapRef ()) thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Receiver::CALL), Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV thread->flags = Thread::RUNNING | Thread::PRIV
if !i: if !i:
first_scheduled = thread first_scheduled = thread
init_receiver = recv init_receiver = recv
else: else:
thread->caps[0]->set (__my_parent, init_receiver, i, CapRef ()) thread->caps[0]->set (__parent_num, init_receiver, i, kCapRef (), &init_receiver->capabilities)
previous->schedule_next = thread previous->schedule_next = thread
thread->schedule_prev = previous thread->schedule_prev = previous
thread->schedule_next = NULL thread->schedule_next = NULL

View File

@ -29,7 +29,7 @@ static void handle_exit ():
schedule () schedule ()
if !current: if !current:
current = &idle current = &idle
if (current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) != THREAD_FLAG_RUNNING: if (current->flags & (Thread::RUNNING | Thread::WAITING)) != Thread::RUNNING:
panic (current->flags, "non-scheduled thread running") panic (current->flags, "non-scheduled thread running")
if !current: if !current:
current = &idle current = &idle
@ -37,7 +37,7 @@ static void handle_exit ():
return return
arch_flush_cache () arch_flush_cache ()
if current != &idle: if current != &idle:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space: if (kMemory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]: if asids[0]:
current->address_space->arch.asid = asids[0] current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]] asids[0] = asids[asids[0]]
@ -52,7 +52,7 @@ static void handle_exit ():
asids[current->address_space->arch.asid] = (unsigned)current->address_space asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid) cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory directory = current->address_space->arch.directory
if current->flags & THREAD_FLAG_PRIV: if current->flags & Thread::PRIV:
cp0_set (CP0_STATUS, 0x1000ff13) cp0_set (CP0_STATUS, 0x1000ff13)
else: else:
cp0_set (CP0_STATUS, 0x0000ff13) cp0_set (CP0_STATUS, 0x0000ff13)
@ -60,7 +60,7 @@ static void handle_exit ():
/// A TLB miss has occurred. This is the slow version. It is only used /// A TLB miss has occurred. This is the slow version. It is only used
/// when k0 or k1 is not 0, or when an error occurs. /// when k0 or k1 is not 0, or when an error occurs.
/// Otherwise, the ultra-fast code in entry.S is used. /// Otherwise, the ultra-fast code in entry.S is used.
Thread *tlb_refill (): kThread *tlb_refill ():
old_current = current old_current = current
if !directory: if !directory:
unsigned addr unsigned addr
@ -85,7 +85,7 @@ Thread *tlb_refill ():
return current return current
/// An interrupt which is not an exception has occurred. /// An interrupt which is not an exception has occurred.
Thread *interrupt (): kThread *interrupt ():
old_current = current old_current = current
unsigned ipr = INTC_IPR unsigned ipr = INTC_IPR
for unsigned i = 0; i < 32; ++i: for unsigned i = 0; i < 32; ++i:
@ -98,11 +98,10 @@ Thread *interrupt ():
intc_ack_irq (i) intc_ack_irq (i)
// Send message to interrupt handler. // Send message to interrupt handler.
if arch_interrupt_receiver[i]: if arch_interrupt_receiver[i]:
Capability::Context c kCapability::Context c
for unsigned j = 0; j < 4; ++j: for unsigned j = 0; j < 2; ++j:
c.data[j] = 0 c.data[j] = 0
c.cap[j].reset () c.caps = NULL
c.copy[j] = false
arch_interrupt_receiver[i]->send_message (i, &c) arch_interrupt_receiver[i]->send_message (i, &c)
arch_interrupt_receiver[i] = NULL arch_interrupt_receiver[i] = NULL
if ipr & (1 << IRQ_OST0): if ipr & (1 << IRQ_OST0):
@ -124,42 +123,49 @@ void flush_tlb (unsigned asid):
__asm__ volatile ("tlbwi") __asm__ volatile ("tlbwi")
static void arch_invoke (): static void arch_invoke ():
CapRef target kCapRef target
bool wait bool wait
target = old_current->find_capability (old_current->arch.v0, &wait) target = old_current->find_capability (old_current->arch.v0, &wait)
do_schedule = false do_schedule = false
kCapability::Context msg
unsigned num = old_current->arch.s2
unsigned first = old_current->arch.s3
if num:
if num > 10:
num = 10
bool copy
if old_current->arch.s0 < old_current->slots:
msg.caps = old_current->caps[old_current->arch.s0]
if msg.caps && first < msg.caps->size:
for unsigned i = first; i < num && i < msg.caps->size; ++i:
msg.caps->cap (i)->invalidate ()
kCapRef t = old_current->find_capability ((&old_current->arch.t0)[i], &copy)
if t:
msg.caps->clone (i, t, copy)
else:
msg.caps = NULL
else:
msg.caps = NULL
if wait: if wait:
bool dummy old_current->recv_slot = old_current->arch.s1
CapRef c0, c1, c2, c3 old_current->wait ()
c0 = old_current->find_capability (old_current->arch.t4, &dummy)
c1 = old_current->find_capability (old_current->arch.t5, &dummy)
c2 = old_current->find_capability (old_current->arch.t6, &dummy)
c3 = old_current->find_capability (old_current->arch.t7, &dummy)
old_current->wait (c0, c1, c2, c3)
if !target: if !target:
if (old_current->arch.v0 & ~CAPABILITY_COPY) != ~CAPABILITY_COPY: if (old_current->arch.v0 & ~CAP_COPY) != ~CAP_COPY:
panic (old_current->arch.v0, "debug") panic (old_current->arch.v0, "debug")
// There must be no action here. // There must be no action here.
return return
Capability::Context c msg.data[0] = Num (old_current->arch.a0, old_current->arch.a1)
c.cap[0] = old_current->find_capability (old_current->arch.a0, &c.copy[0]) msg.data[1] = Num (old_current->arch.a2, old_current->arch.a3)
c.cap[1] = old_current->find_capability (old_current->arch.a1, &c.copy[1]) target->invoke (&msg)
c.cap[2] = old_current->find_capability (old_current->arch.a2, &c.copy[2])
c.cap[3] = old_current->find_capability (old_current->arch.a3, &c.copy[3])
c.data[0] = old_current->arch.t0
c.data[1] = old_current->arch.t1
c.data[2] = old_current->arch.t2
c.data[3] = old_current->arch.t3
target->invoke (&c)
if do_schedule && !wait: if do_schedule && !wait:
// If the call was to schedule without wait, it isn't done yet. // If the call was to schedule without wait, it isn't done yet.
schedule () schedule ()
else if old_current != current && (old_current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING: else if old_current != current && (old_current->flags & (Thread::RUNNING | Thread::WAITING)) == Thread::RUNNING:
// If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice. // If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
current = old_current current = old_current
/// A general exception has occurred. /// A general exception has occurred.
Thread *exception (): kThread *exception ():
old_current = current old_current = current
unsigned cause unsigned cause
cp0_get (CP0_CAUSE, cause) cp0_get (CP0_CAUSE, cause)
@ -288,7 +294,7 @@ Thread *exception ():
return current return current
/// There's a cache error. Big trouble. Probably not worth trying to recover. /// There's a cache error. Big trouble. Probably not worth trying to recover.
Thread *cache_error (): kThread *cache_error ():
panic (0x33333333, "cache error") panic (0x33333333, "cache error")
old_current = current old_current = current
handle_exit () handle_exit ()

View File

@ -136,13 +136,13 @@
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000) #define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
// Map IO memory (requires a priviledged __my_thread capability). // Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h> #include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping): static void __map_io (unsigned physical, unsigned mapping):
memory_create_page (6, __my_memory) Page p = __my_memory.create_page ()
// 0 means not cachable; 0 means don't free when done. // false means not cachable; false means don't free when done.
alloc_physical (6, physical, 0, 0) p.alloc_physical (physical, 0, 0)
// 1 means writable. // true means writable.
memory_map (__my_memory, 6, mapping, 1) __my_memory.map (p, mapping, true)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0) #define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0) #define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
@ -2323,9 +2323,9 @@ static __inline__ void udelay (unsigned us):
GPIO_GPDR (0) = GPIO_GPDR (0) GPIO_GPDR (0) = GPIO_GPDR (0)
#ifndef __KERNEL #ifndef __KERNEL
static __inline__ void ddelay (unsigned ds): static __inline__ void cdelay (unsigned ds):
Message m __my_receiver.set_alarm (ds * (HZ / 100))
my_sleep (ds, &m) Cap ().call (~0)
#endif #endif
/*************************************************************************** /***************************************************************************
@ -3034,9 +3034,7 @@ static __inline__ void i2c_open ():
// Note that this kills messages from the queue. // Note that this kills messages from the queue.
static __inline__ void i2c_close (): static __inline__ void i2c_close ():
Message msg cdelay (30)
receiver_set_alarm (__my_receiver, 3 * HZ / 10)
call_00 (0)
i2c_disable () i2c_disable ()
static __inline__ bool i2c_send (unsigned data): static __inline__ bool i2c_send (unsigned data):

View File

@ -24,11 +24,10 @@ void dbg_log_char (unsigned ch):
if !dbg_cap: if !dbg_cap:
return return
Capability::Context c Capability::Context c
for unsigned i = 0; i < 4; ++i: c->recv_memory = NULL
c.cap[i].reset () c->caps = NULL
c.copy[i] = false
c.data[i] = 0
c.data[0] = ch c.data[0] = ch
c.data[1] = 0
dbg_cap->invoke (&c) dbg_cap->invoke (&c)
if dbg_cap->target->owner: if dbg_cap->target->owner:
current = dbg_cap->target->owner current = dbg_cap->target->owner

3
plan
View File

@ -1,6 +1,5 @@
kernel capabilities: 1 per aktie; bevat code in plaats van bitmask. CREATE ipv DEGRADE. kernel capabilities: 1 per aktie; bevat code in plaats van bitmask. CREATE ipv DEGRADE.
activation address in receiver protected data in receiver
message: a0-a3: data0; data1; protectedL; protectedH message: a0-a3: data0; data1; protectedL; protectedH
caps is stored in designated (by receiver) slot
caps zonder size limit? caps zonder size limit?
invoke ipc: try sync; try receiver memory; try caller memory; fail. invoke ipc: try sync; try receiver memory; try caller memory; fail.

View File

@ -18,14 +18,14 @@
#include "kernel.hh" #include "kernel.hh"
static void run_thread (Thread *thread): static void run_thread (kThread *thread):
thread->schedule_next = first_scheduled thread->schedule_next = first_scheduled
if thread->schedule_next: if thread->schedule_next:
thread->schedule_next->schedule_prev = thread thread->schedule_next->schedule_prev = thread
thread->schedule_prev = NULL thread->schedule_prev = NULL
first_scheduled = thread first_scheduled = thread
static void unrun_thread (Thread *thread): static void unrun_thread (kThread *thread):
if current == thread: if current == thread:
current = thread->schedule_next current = thread->schedule_next
if thread->schedule_prev: if thread->schedule_prev:
@ -35,35 +35,34 @@ static void unrun_thread (Thread *thread):
if thread->schedule_next: if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev thread->schedule_next->schedule_prev = thread->schedule_prev
void Thread::run (): void kThread::run ():
if flags & THREAD_FLAG_RUNNING: if flags & Thread::RUNNING:
return return
flags |= THREAD_FLAG_RUNNING flags |= Thread::RUNNING
if is_waiting (): if is_waiting ():
return return
run_thread (this) run_thread (this)
void Thread::unrun (): void kThread::unrun ():
if !(flags & THREAD_FLAG_RUNNING): if !(flags & Thread::RUNNING):
return return
flags &= ~THREAD_FLAG_RUNNING flags &= ~Thread::RUNNING
if is_waiting (): if is_waiting ():
return return
unrun_thread (this) unrun_thread (this)
void Thread::unwait (): void kThread::unwait ():
flags &= ~THREAD_FLAG_WAITING flags &= ~Thread::WAITING
if flags & THREAD_FLAG_RUNNING: if flags & Thread::RUNNING:
run_thread (this) run_thread (this)
static void alarm_tick (Receiver *recv): static void alarm_tick (kReceiver *recv):
if !recv->alarm_count: if !recv->alarm_count:
// Send message and stop counting. // Send message and stop counting.
Capability::Context c kCapability::Context c
for unsigned i = 0; i < 4; ++i: c.caps = NULL
for unsigned i = 0; i < 2; ++i:
c.data[i] = 0 c.data[i] = 0
c.cap[i].reset ()
c.copy[i] = false
recv->send_message (~0, &c) recv->send_message (~0, &c)
if recv->prev_alarm: if recv->prev_alarm:
recv->prev_alarm->next_alarm = recv->next_alarm recv->prev_alarm->next_alarm = recv->next_alarm
@ -74,16 +73,12 @@ static void alarm_tick (Receiver *recv):
// Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm. // Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm.
--recv->alarm_count --recv->alarm_count
void Thread::wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3): void kThread::wait ():
if flags & THREAD_FLAG_RUNNING: if flags & Thread::RUNNING:
unrun_thread (this) unrun_thread (this)
flags |= THREAD_FLAG_WAITING flags |= Thread::WAITING
rcaps[0] = c0 // Try to receive a message from a kReceiver immediately.
rcaps[1] = c1 for kReceiver *r = receivers; r; r = r->next_owned:
rcaps[2] = c2
rcaps[3] = c3
// Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned:
if r->try_deliver (): if r->try_deliver ():
return return
@ -94,8 +89,8 @@ void schedule ():
current = first_scheduled current = first_scheduled
void timer_interrupt (): void timer_interrupt ():
Receiver *recv, *next kReceiver *recv, *next
for recv = first_alarm; recv; recv = next: for recv = first_alarm; recv; recv = next:
next = (Receiver *)recv->next next = (kReceiver *)recv->next
alarm_tick (recv) alarm_tick (recv)
//schedule () //schedule ()