mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-01-30 19:01:05 +02:00
compiling again with new capability scheme
This commit is contained in:
parent
7b99ba0bdf
commit
a892e9cfc0
2
Makefile
2
Makefile
@ -22,7 +22,7 @@ CC = $(CROSS)gcc
|
||||
LD = $(CROSS)ld
|
||||
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)
|
||||
BUILT_SOURCES = $(iris_sources) $(boot_sources)
|
||||
|
||||
|
177
alloc.ccp
177
alloc.ccp
@ -21,38 +21,38 @@
|
||||
// Memory model used for kernel structure storage
|
||||
// Each Memory object has several pointers, one for each type of objects it contains. These pointers are the start of double-linked lists.
|
||||
// Each object also has a NEXT and PREV pointer, which point to the next and previous object in the same page. These pointers are 0 for the first (or last) object in a page. There is no pointer to the first object, it always starts at page_base + SIZE.
|
||||
// The PREV/NEXT-list contains all objects in the page, including 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.
|
||||
// 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 NEXT(x) (((Object **)(x))[-1])
|
||||
#define SIZE (2 * sizeof (Object *))
|
||||
#define PREV(x) (((kObject **)(x))[-2])
|
||||
#define NEXT(x) (((kObject **)(x))[-1])
|
||||
#define SIZE (2 * sizeof (kObject *))
|
||||
|
||||
bool Memory::use (unsigned num):
|
||||
bool kMemory::use (unsigned num):
|
||||
// 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:
|
||||
// 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
|
||||
return false
|
||||
m->used += num
|
||||
return true
|
||||
|
||||
void Memory::unuse (unsigned num):
|
||||
for Memory *m = this; m; m = m->address_space:
|
||||
void kMemory::unuse (unsigned num):
|
||||
for kMemory *m = this; m; m = m->address_space:
|
||||
m->used -= num
|
||||
|
||||
// This allocates a new block of memory for use by the kernel.
|
||||
// size is the requires size of the block (excluding SIZE)
|
||||
// first is a pointer to the first object pointer of this type.
|
||||
// The result is a block of size at least size, which is linked as an object in the list of first.
|
||||
void *Memory::search_free (unsigned size, void **first):
|
||||
Free *f
|
||||
void *kMemory::search_free (unsigned size, void **first):
|
||||
kFree *f
|
||||
unsigned s = 0
|
||||
// Let's see if there already is a Free chunk which is large enough.
|
||||
for f = frees; f; f = (Free *)f->next:
|
||||
// Let's see if there already is a kFree chunk which is large enough.
|
||||
for f = frees; f; f = (kFree *)f->next:
|
||||
if NEXT (f):
|
||||
s = (unsigned)NEXT (f) - (unsigned)f
|
||||
else:
|
||||
@ -67,27 +67,27 @@ void *Memory::search_free (unsigned size, void **first):
|
||||
if !p:
|
||||
dbg_log ("no free space: kernel allocation failed")
|
||||
return NULL
|
||||
f = (Free *)(p + SIZE)
|
||||
// Mark it as a Free object.
|
||||
f = (kFree *)(p + SIZE)
|
||||
// Mark it as a kFree object.
|
||||
f->marker = ~0
|
||||
// Link it in the Free list.
|
||||
// Link it in the kFree list.
|
||||
f->next = frees
|
||||
f->prev = NULL
|
||||
frees = f
|
||||
if f->next:
|
||||
((Free *)f->next)->prev = f
|
||||
((kFree *)f->next)->prev = f
|
||||
// There are no other objects in this page.
|
||||
NEXT (f) = NULL
|
||||
PREV (f) = NULL
|
||||
// The size of this block is the entire page.
|
||||
s = PAGE_SIZE
|
||||
// We have a free block, possibly too large. The block is linked in frees, and in the page.
|
||||
if s >= size + sizeof (Free) + 2 * SIZE:
|
||||
if s >= size + sizeof (kFree) + 2 * SIZE:
|
||||
// Create the new object at the end and keep the Free.
|
||||
// f is the start of the free block
|
||||
// f + (s - SIZE) is the end of the free block, compensated for the header of the next block.
|
||||
// f + (s - SIZE) - size is the address where the new block should start.
|
||||
Free *obj = (Free *)((unsigned)f + (s - SIZE) - size)
|
||||
kFree *obj = (kFree *)((unsigned)f + (s - SIZE) - size)
|
||||
// Link the new object in the page.
|
||||
NEXT (obj) = NEXT (f)
|
||||
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.
|
||||
// Unlink it from the free list.
|
||||
if f->prev:
|
||||
((Free *)f->prev)->next = f->next
|
||||
((kFree *)f->prev)->next = f->next
|
||||
else:
|
||||
frees = (Free *)f->next
|
||||
frees = (kFree *)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->next = (Free *)*first
|
||||
f->next = (kFree *)*first
|
||||
f->prev = NULL
|
||||
if f->next:
|
||||
((Free *)f->next)->prev = f
|
||||
((kFree *)f->next)->prev = f
|
||||
*first = f
|
||||
// Set common initial values.
|
||||
f->address_space = this
|
||||
@ -117,45 +117,45 @@ void *Memory::search_free (unsigned size, void **first):
|
||||
return f
|
||||
|
||||
// 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):
|
||||
Free *self = (Free *)obj
|
||||
void kMemory::free_obj (kObject *obj, kPointer *first):
|
||||
kFree *self = (kFree *)obj
|
||||
// Invalidate references.
|
||||
while self->refs:
|
||||
self->refs->invalidate ()
|
||||
// Free it from its list.
|
||||
if self->prev:
|
||||
((Free *)self->prev)->next = self->next
|
||||
((kFree *)self->prev)->next = self->next
|
||||
else:
|
||||
*(Pointer *)first = (Pointer)self->next
|
||||
*(kPointer *)first = (kPointer)self->next
|
||||
if self->next:
|
||||
((Free *)self->next)->prev = self->prev
|
||||
// Merge with previous, if it exists and is a Free.
|
||||
((kFree *)self->next)->prev = self->prev
|
||||
// Merge with previous, if it exists and is a kFree.
|
||||
if PREV (self) && PREV (self)->is_free ():
|
||||
self = (Free *)PREV (self)
|
||||
self = (kFree *)PREV (self)
|
||||
// Remove the object from the page list.
|
||||
NEXT (self) = NEXT (obj)
|
||||
if NEXT (self):
|
||||
PREV (NEXT (self)) = self
|
||||
else:
|
||||
// The previous object is not a 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.
|
||||
self->next = frees
|
||||
self->prev = NULL
|
||||
if self->next:
|
||||
((Free *)self->next)->prev = self
|
||||
((kFree *)self->next)->prev = self
|
||||
frees = self
|
||||
// Mark it as a Free.
|
||||
// Mark it as a kFree.
|
||||
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 ():
|
||||
// Unlink the next from the frees list.
|
||||
Free *n = (Free *)NEXT (self)
|
||||
kFree *n = (kFree *)NEXT (self)
|
||||
if n->prev:
|
||||
((Free *)n->prev)->next = n->next
|
||||
((kFree *)n->prev)->next = n->next
|
||||
else:
|
||||
frees = (Free *)n->next
|
||||
frees = (kFree *)n->next
|
||||
if n->next:
|
||||
((Free *)n->next)->prev = n->prev
|
||||
((kFree *)n->next)->prev = n->prev
|
||||
// Unlink the next from the page list.
|
||||
NEXT (self) = NEXT (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.
|
||||
if !PREV (self) && !NEXT (self):
|
||||
if self->next:
|
||||
((Free *)self->next)->prev = self->prev
|
||||
((kFree *)self->next)->prev = self->prev
|
||||
if self->prev:
|
||||
((Free *)self->prev)->next = self->next
|
||||
((kFree *)self->prev)->next = self->next
|
||||
else:
|
||||
frees = (Free *)self->next
|
||||
frees = (kFree *)self->next
|
||||
pfree ((unsigned)self - SIZE)
|
||||
|
||||
Page *Memory::alloc_page ():
|
||||
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages)
|
||||
kPage *kMemory::alloc_page ():
|
||||
kPage *ret = (kPage *)search_free (sizeof (kPage), (void **)&pages)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->frame = 0
|
||||
ret->flags = 0
|
||||
return ret
|
||||
|
||||
Thread *Memory::alloc_thread (unsigned size):
|
||||
Thread *ret = (Thread *)search_free (sizeof (Thread) + (size - 1) * sizeof (CapsP), (void **)&threads)
|
||||
kThread *kMemory::alloc_thread (unsigned size):
|
||||
kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kCapsP), (void **)&threads)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->receivers = NULL
|
||||
ret->pc = 0
|
||||
ret->sp = 0
|
||||
Thread_arch_init (ret)
|
||||
kThread_arch_init (ret)
|
||||
ret->flags = 0
|
||||
ret->schedule_prev = NULL
|
||||
ret->schedule_next = NULL
|
||||
@ -194,16 +194,16 @@ Thread *Memory::alloc_thread (unsigned size):
|
||||
ret->caps[i] = NULL
|
||||
return ret
|
||||
|
||||
Message *Memory::alloc_message (Receiver *target):
|
||||
Message *ret = (Message *)search_free (sizeof (Message), (void **)&target->messages)
|
||||
kMessage *kMemory::alloc_message (kReceiver *target):
|
||||
kMessage *ret = (kMessage *)search_free (sizeof (kMessage), (void **)&target->messages)
|
||||
if !ret:
|
||||
return NULL
|
||||
if !ret->next:
|
||||
target->last_message = ret
|
||||
return ret
|
||||
|
||||
Receiver *Memory::alloc_receiver ():
|
||||
Receiver *ret = (Receiver *)search_free (sizeof (Receiver), (void **)&receivers)
|
||||
kReceiver *kMemory::alloc_receiver ():
|
||||
kReceiver *ret = (kReceiver *)search_free (sizeof (kReceiver), (void **)&receivers)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->owner = NULL
|
||||
@ -216,19 +216,20 @@ Receiver *Memory::alloc_receiver ():
|
||||
ret->last_message = NULL
|
||||
ret->reply_protected_data = ~0
|
||||
ret->protected_only = false
|
||||
ret->queue_limit = 0
|
||||
return ret
|
||||
|
||||
Caps *Memory::alloc_caps (unsigned size):
|
||||
Caps *ret = (Caps *)search_free (sizeof (Caps) + (size - 1) * sizeof (Capability), (void **)&capses)
|
||||
kCaps *kMemory::alloc_caps (unsigned size):
|
||||
kCaps *ret = (kCaps *)search_free (sizeof (kCaps) + (size - 1) * sizeof (kCapability), (void **)&capses)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->size = size
|
||||
for unsigned i = 0; i < size; ++i:
|
||||
ret->set (i, NULL, 0, CapRef (), NULL)
|
||||
ret->set (i, NULL, 0, kCapRef (), NULL)
|
||||
return ret
|
||||
|
||||
Memory *Memory::alloc_memory ():
|
||||
Memory *ret = (Memory *)search_free (sizeof (Memory), (void **)&memories)
|
||||
kMemory *kMemory::alloc_memory ():
|
||||
kMemory *ret = (kMemory *)search_free (sizeof (kMemory), (void **)&memories)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->frees = NULL
|
||||
@ -239,57 +240,57 @@ Memory *Memory::alloc_memory ():
|
||||
ret->memories = NULL
|
||||
ret->limit = ~0
|
||||
ret->used = 0
|
||||
Memory_arch_init (ret)
|
||||
kMemory_arch_init (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].protected_data = pdata
|
||||
caps[index].cap_protected = pdata
|
||||
caps[index].parent = parent
|
||||
caps[index].children.reset ()
|
||||
caps[index].sibling_prev.reset ()
|
||||
if parent:
|
||||
caps[index].sibling_next = parent->children
|
||||
parent->children = CapRef (this, index)
|
||||
parent->children = kCapRef (this, index)
|
||||
else:
|
||||
if parent_ptr:
|
||||
caps[index].sibling_next = *parent_ptr
|
||||
*parent_ptr = CapRef (this, index)
|
||||
*parent_ptr = kCapRef (this, index)
|
||||
else:
|
||||
caps[index].sibling_next.reset ()
|
||||
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 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:
|
||||
set (index, source->target, source->protected_data, CapRef (), &source->target->capabilities)
|
||||
set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities)
|
||||
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:
|
||||
set (index, source->target, source->protected_data, source)
|
||||
set (index, source->target, source->cap_protected, source)
|
||||
|
||||
void Memory::free_page (Page *page):
|
||||
if page->flags & PAGE_FLAG_PAYING:
|
||||
void kMemory::free_page (kPage *page):
|
||||
if page->flags & Page::PAYING:
|
||||
unuse ()
|
||||
if 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 ()
|
||||
while thread->receivers:
|
||||
thread->receivers->orphan ()
|
||||
free_obj (thread, (void **)&threads)
|
||||
|
||||
void Memory::free_message (Receiver *owner, Message *message):
|
||||
void kMemory::free_message (kReceiver *owner, kMessage *message):
|
||||
if !message->next:
|
||||
owner->last_message = (MessageP)message->prev
|
||||
owner->last_message = (kMessageP)message->prev
|
||||
free_obj (message, (void **)&owner->messages)
|
||||
|
||||
void Memory::free_receiver (Receiver *receiver):
|
||||
void kMemory::free_receiver (kReceiver *receiver):
|
||||
receiver->orphan ()
|
||||
while receiver->capabilities:
|
||||
receiver->capabilities->invalidate ()
|
||||
@ -297,7 +298,7 @@ void Memory::free_receiver (Receiver *receiver):
|
||||
free_message (receiver, receiver->messages)
|
||||
free_obj (receiver, (void **)&receivers)
|
||||
|
||||
void Receiver::orphan ():
|
||||
void kReceiver::orphan ():
|
||||
if prev_owned:
|
||||
prev_owned->next_owned = next_owned
|
||||
else:
|
||||
@ -306,7 +307,7 @@ void Receiver::orphan ():
|
||||
next_owned->prev_owned = prev_owned
|
||||
owner = NULL
|
||||
|
||||
void Receiver::own (Thread *o):
|
||||
void kReceiver::own (kThread *o):
|
||||
if owner:
|
||||
orphan ()
|
||||
owner = o
|
||||
@ -315,7 +316,7 @@ void Receiver::own (Thread *o):
|
||||
next_owned->prev_owned = this
|
||||
o->receivers = this
|
||||
|
||||
void Capability::invalidate ():
|
||||
void kCapability::invalidate ():
|
||||
if !target:
|
||||
return
|
||||
if sibling_prev:
|
||||
@ -323,17 +324,17 @@ void Capability::invalidate ():
|
||||
else if (unsigned)target & ~KERNEL_MASK:
|
||||
target->capabilities = sibling_next
|
||||
else:
|
||||
((Object *)protected_data)->refs = sibling_next
|
||||
((kObject *)cap_protected.l)->refs = sibling_next
|
||||
if sibling_next:
|
||||
sibling_next->sibling_prev = sibling_prev
|
||||
parent.reset ()
|
||||
sibling_prev.reset ()
|
||||
sibling_next.reset ()
|
||||
Capability *c = this
|
||||
kCapability *c = this
|
||||
while c:
|
||||
while c->children:
|
||||
c = c->children.deref ()
|
||||
Capability *next = c->sibling_next.deref ()
|
||||
kCapability *next = c->sibling_next.deref ()
|
||||
if !next:
|
||||
next = c->parent.deref ()
|
||||
c->target = NULL
|
||||
@ -341,15 +342,15 @@ void Capability::invalidate ():
|
||||
c->children.reset ()
|
||||
c->sibling_prev.reset ()
|
||||
c->sibling_next.reset ()
|
||||
c->protected_data = 0
|
||||
c->cap_protected = 0
|
||||
c = next
|
||||
|
||||
void Memory::free_caps (Caps *c):
|
||||
void kMemory::free_caps (kCaps *c):
|
||||
for unsigned i = 0; i < c->size; ++i:
|
||||
c->caps[i].invalidate ()
|
||||
free_obj (c, (void **)&capses)
|
||||
|
||||
void Memory::free_memory (Memory *mem):
|
||||
void kMemory::free_memory (kMemory *mem):
|
||||
while mem->pages:
|
||||
free_page (mem->pages)
|
||||
while mem->capses:
|
||||
@ -360,12 +361,12 @@ void Memory::free_memory (Memory *mem):
|
||||
free_memory (mem->memories)
|
||||
while mem->receivers:
|
||||
free_receiver (mem->receivers)
|
||||
Memory_arch_free (mem)
|
||||
kMemory_arch_free (mem)
|
||||
if mem->frees:
|
||||
panic (0, "kernel memory leak: memory still in use")
|
||||
free_obj (mem, (void **)&memories)
|
||||
|
||||
void Page::forget ():
|
||||
void kPage::forget ():
|
||||
if share_prev || share_next:
|
||||
if share_prev:
|
||||
share_prev->share_next = share_next
|
||||
@ -375,8 +376,8 @@ void Page::forget ():
|
||||
share_next = NULL
|
||||
else:
|
||||
// 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)
|
||||
frame = 0
|
||||
flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
|
||||
Page_arch_update_mapping (this)
|
||||
flags &= ~(Page::FRAME | Page::SHARED | Page::PHYSICAL | Page::UNCACHED)
|
||||
kPage_arch_update_mapping (this)
|
||||
|
@ -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
117
boot-programs/crt0.ccp
Normal 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")
|
@ -19,7 +19,7 @@
|
||||
#ifndef __IRIS_DEVICES_HH
|
||||
#define __IRIS_DEVICES_HH
|
||||
|
||||
#include "iris.h"
|
||||
#include "iris.hh"
|
||||
|
||||
// This shouldn't really be here. But where should it be?
|
||||
// Requests made by initial threads to tell init about themselves.
|
||||
@ -27,136 +27,150 @@ enum init_requests:
|
||||
INIT_SET_GPIO
|
||||
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.
|
||||
enum Keyboard_request:
|
||||
KEYBOARD_SET_CB
|
||||
KEYBOARD_GET_KEYS
|
||||
|
||||
// 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_set_cb (Capability kbd, Capability cb):
|
||||
invoke_11 (kbd, cb, KEYBOARD_SET_CB)
|
||||
struct Keyboard : public Cap:
|
||||
Keyboard (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
SET_CB
|
||||
GET_KEYS
|
||||
// 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)
|
||||
|
||||
// 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.
|
||||
static __inline__ void keyboard_get_keys (Capability target, Capability kbd):
|
||||
call_c01 (kbd, target, KEYBOARD_GET_KEYS)
|
||||
|
||||
|
||||
enum constant:
|
||||
RELEASE = 1 << 31
|
||||
// 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.
|
||||
void set_cb (Cap cb):
|
||||
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.
|
||||
// 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.
|
||||
// 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):
|
||||
invoke_10 (disp_set_eof_cb, cb)
|
||||
|
||||
void set_eof_cb (Cap 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.
|
||||
// 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 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):
|
||||
return call_n33 (disp_create_fb, page0, page1, page2, w, h, mode)
|
||||
|
||||
unsigned create_framebuffer (Caps pages, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
|
||||
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.
|
||||
// w, h and mode must match the values given at creation time.
|
||||
// unuse_cb is called the next time this operation is requested.
|
||||
static __inline__ void display_use_framebuffer (Capability disp_use_fb, unsigned addr, Capability unuse_cb, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
|
||||
invoke_11 (disp_use_fb, unuse_cb, addr)
|
||||
|
||||
// unuse_cb is called the next time this operation is requested for this display.
|
||||
void use_framebuffer (unsigned addr, Cap unuse_cb = Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0):
|
||||
invoke (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode))
|
||||
// Get information about the display.
|
||||
static __inline__ void display_get_info (Capability disp_info):
|
||||
void get_info ():
|
||||
// TODO: Interface is to be designed.
|
||||
|
||||
|
||||
|
||||
// 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.
|
||||
|
||||
enum File_request:
|
||||
FILE_INFO
|
||||
FILE_CLOSE
|
||||
FILE_COPY_HANDLE
|
||||
DIRECTORY_GET_SIZE
|
||||
DIRECTORY_GET_NAME
|
||||
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.
|
||||
// filesystem-related interfaces: file, directory, stream, seekable, mappable.
|
||||
// Normal files implement at least stream or seekable file. Directories implement directory.
|
||||
struct File : public Cap:
|
||||
File (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
INFO
|
||||
CLOSE
|
||||
MAP_HANDLE
|
||||
// Get information about the file.
|
||||
static __inline__ unsigned long long file_get_info (Capability file, unsigned type):
|
||||
return call_l02 (file, FILE_INFO, type)
|
||||
Num get_info (unsigned type, Caps ret = Cap ()):
|
||||
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.
|
||||
static __inline__ void file_close (Capability file):
|
||||
invoke_01 (file, FILE_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.
|
||||
static __inline__ void file_copy_handle (Capability target, Capability file):
|
||||
call_c01 (file, target, FILE_COPY_HANDLE)
|
||||
void close ():
|
||||
invoke (CAP_MASTER_DIRECT | CLOSE)
|
||||
// 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.
|
||||
File map_handle (File ret):
|
||||
call (ret, CAP_MASTER_DIRECT | MAP_HANDLE)
|
||||
|
||||
// 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.
|
||||
static __inline__ unsigned long long directory_get_size (Capability dir):
|
||||
return call_l01 (dir, DIRECTORY_GET_SIZE)
|
||||
Num 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.
|
||||
static __inline__ unsigned directory_get_name (Capability dir, unsigned long long idx, Capability page):
|
||||
return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32)
|
||||
void get_name (Num idx, String target):
|
||||
call (target, CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||
// Get the file.
|
||||
static __inline__ void directory_get_file (Capability target, Capability dir, unsigned long long idx, Capability page):
|
||||
call_c03 (dir, target, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
|
||||
void get_file (Num idx, File ret):
|
||||
call (ret, CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||
// 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):
|
||||
return call_l04 (dir, DIRECTORY_GET_FILE_INFO, idx & 0xffffffff, idx >> 32, type)
|
||||
Num get_file_info (Num idx, unsigned type, Caps ret = Cap ()):
|
||||
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.
|
||||
static __inline__ void directory_create_file (Capability target, Capability dir, unsigned long long idx, Capability page):
|
||||
call_c03 (dir, target, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
|
||||
void create_file (String name, File ret):
|
||||
call (ret, CAP_MASTER_DIRECT | CREATE_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):
|
||||
call_c03 (dir, target, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
|
||||
void delete_file (Num idx):
|
||||
invoke (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||
|
||||
// Stream interface.
|
||||
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
|
||||
static __inline__ unsigned file_stream_read (Capability file, Capability page, unsigned size):
|
||||
return call_n12 (file, page, FILE_STREAM_READ, size)
|
||||
// Try to write size bytes. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE.
|
||||
static __inline__ unsigned file_stream_write (Capability file, Capability page, unsigned size):
|
||||
return call_n12 (file, page, FILE_STREAM_WRITE, size)
|
||||
struct Stream : public File:
|
||||
Stream (Cap c = Cap ()) : File (c):
|
||||
enum request:
|
||||
READ
|
||||
WRITE
|
||||
// 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.
|
||||
// Try to read size bytes from position idx. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
|
||||
static __inline__ unsigned file_seekable_read (Capability file, Capability page, unsigned long long idx, unsigned size):
|
||||
return call_n14 (file, page, FILE_SEEKABLE_READ, idx & 0xffffffff, idx >> 32, size)
|
||||
// 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.
|
||||
static __inline__ unsigned file_seekable_write (Capability file, Capability page, unsigned long long idx, unsigned size):
|
||||
return call_n14 (file, page, FILE_SEEKABLE_WRITE, idx & 0xffffffff, idx >> 32, size)
|
||||
struct Seekable : public File:
|
||||
Seekable (Cap c = Cap ()) : File (c):
|
||||
enum request:
|
||||
READ
|
||||
WRITE
|
||||
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.
|
||||
static __inline__ void file_seekable_truncate (Capability file, unsigned long long idx):
|
||||
call_n03 (file, FILE_SEEKABLE_TRUNCATE, idx & 0xffffffff, idx >> 32)
|
||||
void truncate (Num idx):
|
||||
invoke (CAP_MASTER_DIRECT | TRUNCATE, idx)
|
||||
|
||||
// Mappable file interface.
|
||||
struct Mappable : public Seekable:
|
||||
Mappable (Cap c = Cap ()) : Seekable (c):
|
||||
// TODO: to be designed.
|
||||
|
||||
|
||||
|
||||
// Block device interface.
|
||||
// Startup: blk_get_size, blk_get_file.
|
||||
|
||||
// Get block size.
|
||||
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)
|
||||
|
||||
struct Block_device : public Mappable:
|
||||
Block_device (Cap c = Cap ()) : Mappable (c):
|
||||
// TODO: to be designed.
|
||||
|
||||
|
||||
// TODO.
|
||||
|
@ -58,14 +58,17 @@ enum cap_type:
|
||||
CAP_TOUCHPAD
|
||||
CAP_LOCKLEDS
|
||||
CAP_PWM
|
||||
NUM_EVENT_TYPES
|
||||
|
||||
static Caps events = Cap (0, 6)
|
||||
|
||||
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):
|
||||
capability_clone (11 + type, 6)
|
||||
static void set_cb (Cap cap, event_type type):
|
||||
cap.clone (events, type - 32)
|
||||
|
||||
class Keyboard:
|
||||
class DevKeyboard:
|
||||
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
|
||||
unsigned keys[GPIO_KBD_NUM_COLS]
|
||||
bool scanning
|
||||
@ -74,7 +77,7 @@ class Keyboard:
|
||||
if (data ^ keys[col]) & (1 << row):
|
||||
unsigned code = encode[col][row]
|
||||
if data & (1 << row):
|
||||
code |= KEYBOARD_RELEASE
|
||||
code |= Keyboard::RELEASE
|
||||
event (KEYBOARD_EVENT, code)
|
||||
keys[col] = data
|
||||
// If any keys are pressed, scanning is required.
|
||||
@ -127,7 +130,7 @@ class Keyboard:
|
||||
gpio_irq_high (GPIO_KBD_ROW_PORT, i)
|
||||
// Reenable interrupts.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
|
||||
Keyboard ():
|
||||
DevKeyboard ():
|
||||
// Set all columns to output without pull-ups when set as input.
|
||||
GPIO_GPPUR (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
|
||||
LSHIFT, RSHIFT, CTRL, ALT
|
||||
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 },
|
||||
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
|
||||
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
|
||||
@ -251,61 +254,60 @@ class Pwm:
|
||||
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.
|
||||
|
||||
int main ():
|
||||
Num start ():
|
||||
__my_memory.create_caps (NUM_EVENT_TYPES - 32).clone (__my_caps, 6)
|
||||
map_gpio ()
|
||||
map_pwm0 ()
|
||||
|
||||
Keyboard kbd
|
||||
DevKeyboard kbd
|
||||
Touchpad tp
|
||||
Lockleds leds
|
||||
Pwm pwm
|
||||
|
||||
// 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
|
||||
register_interrupt (IRQ_GPIO0)
|
||||
Kernel::register_interrupt (IRQ_GPIO0)
|
||||
|
||||
Capability cap_kbd = 7
|
||||
Capability cap_tp = 8
|
||||
Capability cap_lockleds = 9
|
||||
Capability cap_pwm = 10
|
||||
receiver_create_capability (cap_kbd, __my_receiver, CAP_KEYBOARD)
|
||||
receiver_create_capability (cap_tp, __my_receiver, CAP_TOUCHPAD)
|
||||
receiver_create_capability (cap_lockleds, __my_receiver, CAP_LOCKLEDS)
|
||||
receiver_create_capability (cap_pwm, __my_receiver, CAP_PWM)
|
||||
Caps c (0, 7)
|
||||
__my_memory.create_caps (4).clone (__my_caps, 7)
|
||||
__my_receiver.create_capability (CAP_KEYBOARD).clone (c, 0)
|
||||
__my_receiver.create_capability (CAP_TOUCHPAD).clone (c, 1)
|
||||
__my_receiver.create_capability (CAP_LOCKLEDS).clone (c, 2)
|
||||
__my_receiver.create_capability (CAP_PWM).clone (c, 3)
|
||||
|
||||
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 ():
|
||||
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
|
||||
__my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
while true:
|
||||
schedule ()
|
||||
Message msg
|
||||
wait (&msg, 6, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
|
||||
switch msg.protected_data:
|
||||
Kernel::schedule ()
|
||||
Cap::OMessage msg
|
||||
Kernel::wait (&msg)
|
||||
switch (unsigned)msg.cap_protected.value ():
|
||||
case ~0:
|
||||
// Alarm.
|
||||
kbd.scan ()
|
||||
if kbd.is_scanning ():
|
||||
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
|
||||
__my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
break
|
||||
case IRQ_GPIO0:
|
||||
// Always scan keyboard and touchpad on any interrupt.
|
||||
kbd.scan ()
|
||||
tp.check_events ()
|
||||
// Reregister the interrupt.
|
||||
register_interrupt (IRQ_GPIO0)
|
||||
Kernel::register_interrupt (IRQ_GPIO0)
|
||||
break
|
||||
case CAP_KEYBOARD:
|
||||
set_cb (KEYBOARD_EVENT)
|
||||
set_cb (Cap (__tmp_slot, 0), KEYBOARD_EVENT)
|
||||
kbd.send_initial ()
|
||||
break
|
||||
case CAP_TOUCHPAD:
|
||||
set_cb (TOUCHPAD_EVENT)
|
||||
set_cb (Cap (__tmp_slot, 0), TOUCHPAD_EVENT)
|
||||
tp.send_initial ()
|
||||
break
|
||||
case CAP_LOCKLEDS:
|
||||
leds.set (msg.data[0])
|
||||
leds.set (msg.data[0].l)
|
||||
break
|
||||
case CAP_PWM:
|
||||
pwm.set_backlight (msg.data[0])
|
||||
pwm.set_backlight (msg.data[0].l)
|
||||
break
|
||||
|
@ -17,71 +17,70 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#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:
|
||||
KBD = 0x10000
|
||||
TP
|
||||
|
||||
static void send (Capability c, unsigned d):
|
||||
receiver_create_capability (6, __my_receiver, d)
|
||||
invoke_10 (c, cap_copy (6))
|
||||
|
||||
static void setup ():
|
||||
unsigned state = 0
|
||||
Capability base = 7
|
||||
unsigned slot = 2
|
||||
while true:
|
||||
Message msg
|
||||
wait (&msg, base, base + 1, base + 2, base + 3)
|
||||
switch msg.data[0]:
|
||||
Cap::OMessage msg
|
||||
Kernel::wait (&msg, slot)
|
||||
switch msg.data[0].value ():
|
||||
case INIT_SET_GPIO:
|
||||
kdebug ("gpio\n")
|
||||
kbd = base
|
||||
tp = base + 1
|
||||
lockleds = base + 2
|
||||
pwm = base + 3
|
||||
base += 4
|
||||
kbd = Cap (slot, 0)
|
||||
tp = Cap (slot, 1)
|
||||
lockleds = Cap (slot, 2)
|
||||
pwm = Cap (slot, 3)
|
||||
++slot
|
||||
++state
|
||||
break
|
||||
case INIT_SET_LCD:
|
||||
kdebug ("lcd\n")
|
||||
lcd = base
|
||||
++base
|
||||
lcd = Cap (slot, 0)
|
||||
++slot
|
||||
++state
|
||||
break
|
||||
if state == 2:
|
||||
break
|
||||
send (kbd, KBD)
|
||||
send (tp, TP)
|
||||
invoke_01 (pwm, 1)
|
||||
kbd.set_cb (__my_receiver.create_capability (KBD).copy ())
|
||||
tp.set_cb (__my_receiver.create_capability (TP).copy ())
|
||||
pwm.invoke (1)
|
||||
|
||||
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
|
||||
|
||||
int main ():
|
||||
Num start ():
|
||||
// Set up lcd first
|
||||
schedule ()
|
||||
Kernel::schedule ()
|
||||
kdebug ("start init\n")
|
||||
setup ()
|
||||
kdebug ("run init\n")
|
||||
while true:
|
||||
Message msg
|
||||
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
|
||||
switch msg.protected_data:
|
||||
Cap::OMessage msg
|
||||
Kernel::wait (&msg)
|
||||
switch msg.cap_protected.value ():
|
||||
case KBD:
|
||||
unsigned code = msg.data[0]
|
||||
if code & KEYBOARD_RELEASE:
|
||||
unsigned code = msg.data[0].l
|
||||
if code & Keyboard::RELEASE:
|
||||
break
|
||||
kdebug_char (decode_kbd[code])
|
||||
break
|
||||
case TP:
|
||||
unsigned leds = 0
|
||||
if msg.data[0] & 1:
|
||||
if msg.data[0].l & 1:
|
||||
leds |= 0x1
|
||||
else:
|
||||
leds |= 0x4
|
||||
if !(msg.data[0] & 0x10000):
|
||||
if !(msg.data[0].l & Keyboard::RELEASE):
|
||||
leds |= 0x2
|
||||
invoke_01 (lockleds, leds)
|
||||
lockleds.invoke (leds)
|
||||
break
|
||||
|
@ -102,36 +102,37 @@ static void log_str (char const *str):
|
||||
while *str:
|
||||
log_char (*str++)
|
||||
|
||||
static void log_num (unsigned n):
|
||||
static void log_num (Num n):
|
||||
char const *encode = "0123456789abcdef"
|
||||
log_char ('[')
|
||||
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 (']')
|
||||
|
||||
static void log_msg (Message *msg):
|
||||
log_str ("prot:")
|
||||
log_num (msg->protected_data)
|
||||
static void log_msg (Cap::OMessage *msg):
|
||||
log_str ("cap_prot:")
|
||||
log_num (msg->cap_protected)
|
||||
log_str ("data:")
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
log_num (msg->data[i])
|
||||
log_str ("cap:")
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
log_num (msg->cap[i])
|
||||
log_char ('\n')
|
||||
|
||||
int main ():
|
||||
Num start ():
|
||||
map_lcd ()
|
||||
map_cpm ()
|
||||
|
||||
Descriptor descriptor __attribute__ ((aligned (16)))
|
||||
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)
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
memory_create_page (6, __my_memory)
|
||||
alloc_physical (6, physical + i * PAGE_SIZE, 0, 1)
|
||||
memory_map (__my_memory, 6, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1)
|
||||
Page p = __my_memory.create_page ()
|
||||
p.alloc_physical (physical + i * PAGE_SIZE, false, true)
|
||||
__my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, true)
|
||||
free_cap (p)
|
||||
for unsigned y = 0; y < 480; ++y:
|
||||
unsigned g = (y << 6) / 480
|
||||
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
||||
@ -148,8 +149,9 @@ int main ():
|
||||
ob = b
|
||||
b = 0x1f
|
||||
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
|
||||
memory_mapping (6, __my_memory, &descriptor)
|
||||
unsigned physical_descriptor = page_physical_address (cap_copy (6)) + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
Page p = __my_memory.mapping (&descriptor)
|
||||
unsigned physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
free_cap (p)
|
||||
descriptor.next = physical_descriptor
|
||||
descriptor.frame = physical
|
||||
descriptor.id = 0xdeadbeef
|
||||
@ -158,30 +160,26 @@ int main ():
|
||||
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
|
||||
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)
|
||||
invoke_11 (__my_parent, cap_copy (6), INIT_SET_LCD)
|
||||
|
||||
receiver_create_capability (15, __my_receiver, LCD_LOG)
|
||||
__asm__ volatile ("li $a0, 1\nli $a1, 15\nbreak" ::: "a0", "a1", "memory")
|
||||
Cap logcap = __my_receiver.create_capability (LCD_LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
|
||||
unsigned slot = alloc_slot ()
|
||||
while true:
|
||||
Message msg
|
||||
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
|
||||
Cap::OMessage msg
|
||||
Kernel::wait (&msg, slot)
|
||||
//log_msg (&msg)
|
||||
switch msg.protected_data:
|
||||
switch msg.cap_protected.value ():
|
||||
case IRQ_LCD:
|
||||
lcd_clr_eof ()
|
||||
if eof_cb:
|
||||
register_interrupt (IRQ_LCD)
|
||||
invoke_00 (eof_cb)
|
||||
Cap (slot, 0).invoke ()
|
||||
Cap (slot, 0) = Cap ()
|
||||
break
|
||||
case LCD_EOF_CB:
|
||||
eof_cb = msg.cap[0]
|
||||
if eof_cb:
|
||||
register_interrupt (IRQ_LCD)
|
||||
Kernel::register_interrupt (IRQ_LCD)
|
||||
break
|
||||
case LCD_LOG:
|
||||
log_char (msg.data[0])
|
||||
log_char (msg.data[0].l)
|
||||
break
|
||||
|
758
invoke.ccp
758
invoke.ccp
File diff suppressed because it is too large
Load Diff
514
iris.hhp
Normal file
514
iris.hhp
Normal 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
|
268
kernel.hhp
268
kernel.hhp
@ -21,7 +21,7 @@
|
||||
|
||||
// Include definitions which are shared with user space.
|
||||
#define __KERNEL
|
||||
#include "iris.h"
|
||||
#include "iris.hh"
|
||||
|
||||
// Normally define all variables in this file as extern.
|
||||
// Exactly once (in data.ccp), EXTERN is predefined empty.
|
||||
@ -30,145 +30,146 @@
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
struct Page
|
||||
struct Thread
|
||||
struct Message
|
||||
struct Receiver
|
||||
struct Capability
|
||||
struct Caps
|
||||
struct Memory
|
||||
struct kPage
|
||||
struct kThread
|
||||
struct kMessage
|
||||
struct kReceiver
|
||||
struct kCapability
|
||||
struct kCaps
|
||||
struct kMemory
|
||||
|
||||
typedef Page *PageP
|
||||
typedef Thread *ThreadP
|
||||
typedef Message *MessageP
|
||||
typedef Receiver *ReceiverP
|
||||
typedef Capability *CapabilityP
|
||||
typedef Caps *CapsP
|
||||
typedef Memory *MemoryP
|
||||
typedef void *Pointer
|
||||
typedef kPage *kPageP
|
||||
typedef kThread *kThreadP
|
||||
typedef kMessage *kMessageP
|
||||
typedef kReceiver *kReceiverP
|
||||
typedef kCapability *kCapabilityP
|
||||
typedef kCaps *kCapsP
|
||||
typedef kMemory *kMemoryP
|
||||
typedef void *kPointer
|
||||
|
||||
typedef unsigned Protected
|
||||
|
||||
struct CapRef:
|
||||
CapsP caps
|
||||
struct kCapRef:
|
||||
kCapsP caps
|
||||
unsigned index
|
||||
inline Capability *deref ()
|
||||
inline kCapability *deref ()
|
||||
operator bool ():
|
||||
return deref () != NULL
|
||||
Capability *operator-> ():
|
||||
kCapability *operator-> ():
|
||||
return deref ()
|
||||
void reset ():
|
||||
caps = NULL
|
||||
CapRef (CapsP c, unsigned i) : caps (c), index (i):
|
||||
CapRef () : caps (NULL), index (~0):
|
||||
inline void clone (CapRef source, bool copy)
|
||||
inline void set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL)
|
||||
kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
|
||||
kCapRef () : caps (NULL), index (~0):
|
||||
inline void clone (kCapRef source, bool copy)
|
||||
inline void set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
|
||||
struct Object:
|
||||
CapRef refs
|
||||
MemoryP address_space
|
||||
struct kObject:
|
||||
kCapRef refs
|
||||
kMemoryP address_space
|
||||
// Next and previous object of the same type in any page.
|
||||
Pointer prev, next
|
||||
kPointer prev, next
|
||||
inline bool is_free ()
|
||||
|
||||
struct Free : public Object:
|
||||
struct kFree : public kObject:
|
||||
// This marker is ~0. No other kernel structure may allow this value
|
||||
// at this point. It is used to recognize free chunks.
|
||||
unsigned marker
|
||||
|
||||
bool Object::is_free ():
|
||||
return ((Free *)this)->marker == ~0
|
||||
bool kObject::is_free ():
|
||||
return ((kFree *)this)->marker == ~0
|
||||
|
||||
// Include architecture-specific parts.
|
||||
#include "arch.hh"
|
||||
|
||||
struct Message : public Object:
|
||||
Protected protected_data
|
||||
unsigned data[4]
|
||||
unsigned char capabilities[4]
|
||||
struct kMessage : public kObject:
|
||||
Num cap_protected
|
||||
Num data[2]
|
||||
kCapsP caps
|
||||
|
||||
struct Capability : public Object:
|
||||
struct kCapability : public kObject:
|
||||
struct Context:
|
||||
unsigned data[4]
|
||||
CapRef cap[4]
|
||||
bool copy[4]
|
||||
ReceiverP target
|
||||
CapRef parent
|
||||
CapRef children
|
||||
CapRef sibling_prev, sibling_next
|
||||
Protected protected_data
|
||||
void invoke (Context *c)
|
||||
Num data[2]
|
||||
kCaps *caps
|
||||
kReceiverP target
|
||||
kCapRef parent
|
||||
kCapRef children
|
||||
kCapRef sibling_prev, sibling_next
|
||||
Num cap_protected
|
||||
inline void invoke (kCapability::Context *c)
|
||||
void invalidate ()
|
||||
|
||||
struct Thread : public Object:
|
||||
ReceiverP receivers
|
||||
struct kThread : public kObject:
|
||||
kReceiverP receivers
|
||||
unsigned pc, sp
|
||||
Thread_arch arch
|
||||
kThread_arch arch
|
||||
unsigned flags
|
||||
ThreadP schedule_prev, schedule_next
|
||||
CapRef rcaps[4]
|
||||
// caps is an array of slots pointers to Capses.
|
||||
kThreadP schedule_prev, schedule_next
|
||||
unsigned recv_slot
|
||||
// caps is an array of slots pointers to kCapses.
|
||||
unsigned slots
|
||||
// TODO: handle freeing of capses which are in use.
|
||||
CapsP caps[1]
|
||||
kCapsP caps[1]
|
||||
void raise (unsigned code, unsigned data)
|
||||
void run ()
|
||||
void unrun ()
|
||||
void wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3)
|
||||
void wait ()
|
||||
void unwait ()
|
||||
bool is_waiting ():
|
||||
return flags & THREAD_FLAG_WAITING
|
||||
CapRef find_capability (unsigned code, bool *copy)
|
||||
return flags & Thread::WAITING
|
||||
kCapRef find_capability (unsigned code, bool *copy)
|
||||
void fill_slot (unsigned slot, kCaps *new_caps)
|
||||
|
||||
struct Receiver : public Object:
|
||||
ThreadP owner
|
||||
ReceiverP prev_owned, next_owned
|
||||
ReceiverP prev_alarm, next_alarm
|
||||
struct kReceiver : public kObject:
|
||||
kThreadP owner
|
||||
kReceiverP prev_owned, next_owned
|
||||
kReceiverP prev_alarm, next_alarm
|
||||
unsigned alarm_count
|
||||
// random is used like the tlb random register to find invalid caps to store the message to.
|
||||
unsigned random
|
||||
CapsP caps
|
||||
kCapsP caps
|
||||
// These are capabilities which call this receiver on invoke.
|
||||
CapRef capabilities
|
||||
// The message queue. Messages are added at the tail, and removed at the front.
|
||||
MessageP messages
|
||||
MessageP last_message
|
||||
Protected reply_protected_data
|
||||
kCapRef capabilities
|
||||
// The message queue. kMessages are added at the tail, and removed at the front.
|
||||
kMessageP messages
|
||||
kMessageP last_message
|
||||
Num recv_protected
|
||||
Num reply_protected_data
|
||||
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 ()
|
||||
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 flags
|
||||
PageP share_first
|
||||
PageP share_prev, share_next
|
||||
Page_arch arch
|
||||
kPageP share_first
|
||||
kPageP share_prev, share_next
|
||||
kPage_arch arch
|
||||
void forget ()
|
||||
|
||||
struct Caps : public Object:
|
||||
struct kCaps : public kObject:
|
||||
unsigned size
|
||||
Capability caps[1]
|
||||
Capability *cap (unsigned idx):
|
||||
kCapability caps[1]
|
||||
kCapability *cap (unsigned idx):
|
||||
return &caps[idx]
|
||||
void set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL)
|
||||
void clone (unsigned index, CapRef source, bool copy)
|
||||
void set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
void clone (unsigned index, kCapRef source, bool copy)
|
||||
|
||||
struct Memory : public Object:
|
||||
Free *frees
|
||||
PageP pages
|
||||
ThreadP threads
|
||||
ReceiverP receivers
|
||||
CapsP capses
|
||||
MemoryP memories
|
||||
struct kMemory : public kObject:
|
||||
kFree *frees
|
||||
kPageP pages
|
||||
kThreadP threads
|
||||
kReceiverP receivers
|
||||
kCapsP capses
|
||||
kMemoryP memories
|
||||
unsigned limit, used
|
||||
Memory_arch arch
|
||||
kMemory_arch arch
|
||||
|
||||
inline bool map (Page *page, unsigned address, bool write)
|
||||
inline void unmap (Page *page, unsigned address)
|
||||
inline Page *get_mapping (unsigned address, bool *writable)
|
||||
inline bool map (kPage *page, unsigned address, bool write)
|
||||
inline void unmap (kPage *page, unsigned address)
|
||||
inline kPage *get_mapping (unsigned address, bool *readonly)
|
||||
|
||||
// Allocation of pages.
|
||||
bool use (unsigned num = 1)
|
||||
@ -180,28 +181,28 @@ struct Memory : public Object:
|
||||
|
||||
// Allocation routines for kernel structures
|
||||
void *search_free (unsigned size, void **first)
|
||||
Page *alloc_page ()
|
||||
Thread *alloc_thread (unsigned size)
|
||||
Message *alloc_message (Receiver *target)
|
||||
Receiver *alloc_receiver ()
|
||||
Caps *alloc_caps (unsigned size)
|
||||
Memory *alloc_memory ()
|
||||
kPage *alloc_page ()
|
||||
kThread *alloc_thread (unsigned size)
|
||||
kMessage *alloc_message (kReceiver *target)
|
||||
kReceiver *alloc_receiver ()
|
||||
kCaps *alloc_caps (unsigned size)
|
||||
kMemory *alloc_memory ()
|
||||
|
||||
void free_page (Page *page)
|
||||
void free_thread (Thread *thread)
|
||||
void free_message (Receiver *owner, Message *message)
|
||||
void free_receiver (Receiver *receiver)
|
||||
void free_caps (Caps *page)
|
||||
void free_memory (Memory *mem)
|
||||
void free_page (kPage *page)
|
||||
void free_thread (kThread *thread)
|
||||
void free_message (kReceiver *owner, kMessage *message)
|
||||
void free_receiver (kReceiver *receiver)
|
||||
void free_caps (kCaps *page)
|
||||
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.
|
||||
extern "C":
|
||||
// Panic. n is sent over caps led. message is currently ignored.
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
|
||||
EXTERN unsigned dbg_code
|
||||
EXTERN CapRef dbg_cap
|
||||
EXTERN kCapRef dbg_cap
|
||||
void dbg_log_char (unsigned ch)
|
||||
void dbg_log (char const *str)
|
||||
void dbg_log_num (unsigned num)
|
||||
@ -212,46 +213,51 @@ extern "C":
|
||||
void schedule ()
|
||||
void timer_interrupt ()
|
||||
|
||||
EXTERN Memory top_memory
|
||||
EXTERN ReceiverP first_alarm
|
||||
EXTERN Thread idle
|
||||
EXTERN Memory idle_memory
|
||||
EXTERN Page idle_page
|
||||
EXTERN ThreadP first_scheduled
|
||||
EXTERN ThreadP current, old_current
|
||||
EXTERN kMemory top_memory
|
||||
EXTERN kReceiverP first_alarm
|
||||
EXTERN kThread idle
|
||||
EXTERN kMemory idle_memory
|
||||
EXTERN kPage idle_page
|
||||
EXTERN kThreadP first_scheduled
|
||||
EXTERN kThreadP current, old_current
|
||||
EXTERN bool do_schedule
|
||||
|
||||
// Defined in memory.cc
|
||||
// Defined in memory.ccp
|
||||
unsigned init_memory (unsigned mem)
|
||||
unsigned raw_zalloc ()
|
||||
void raw_pfree (unsigned page)
|
||||
unsigned phys_alloc (unsigned num)
|
||||
void phys_free (unsigned page, unsigned num)
|
||||
|
||||
// Defined by architecture-specific files.
|
||||
void Thread_arch_init (Thread *thread)
|
||||
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)
|
||||
// Defind in invoke.ccp
|
||||
void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self)
|
||||
|
||||
bool Memory::map (Page *page, unsigned address, bool write):
|
||||
return Memory_arch_map (this, page, address, write)
|
||||
void Memory::unmap (Page *page, unsigned address):
|
||||
Memory_arch_unmap (this, page, address)
|
||||
Page *Memory::get_mapping (unsigned address, bool *writable):
|
||||
return Memory_arch_get_mapping (this, address, writable)
|
||||
Capability *CapRef::deref ():
|
||||
// Defined by architecture-specific files.
|
||||
void kThread_arch_init (kThread *thread)
|
||||
void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data)
|
||||
unsigned *kThread_arch_info (kThread *thread, unsigned num)
|
||||
void kMemory_arch_init (kMemory *mem)
|
||||
void kMemory_arch_free (kMemory *mem)
|
||||
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
|
||||
void CapRef::clone (CapRef source, bool copy):
|
||||
void kCapRef::clone (kCapRef source, bool 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)
|
||||
void kCapability::invoke (kCapability::Context *c):
|
||||
::invoke (target, cap_protected, c, this)
|
||||
|
||||
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)
|
||||
|
||||
|
28
memory.ccp
28
memory.ccp
@ -31,22 +31,22 @@ void phys_free (unsigned page, unsigned num):
|
||||
|
||||
#else
|
||||
|
||||
struct FreePages:
|
||||
FreePages *prev, *next
|
||||
struct kFreePages:
|
||||
kFreePages *prev, *next
|
||||
unsigned num
|
||||
|
||||
static FreePages *first_free
|
||||
static kFreePages *first_free
|
||||
|
||||
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->next = NULL
|
||||
first_free->num = ((mem & PAGE_MASK) - ((unsigned)first_free - 0x80000000)) >> PAGE_BITS
|
||||
return first_free->num
|
||||
|
||||
unsigned phys_alloc (unsigned num):
|
||||
FreePages *choice = NULL
|
||||
for FreePages *p = first_free; p; p = p->next:
|
||||
kFreePages *choice = NULL
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
if p->num < num:
|
||||
continue
|
||||
if choice && choice->num < p->num:
|
||||
@ -75,7 +75,7 @@ void phys_free (unsigned page, unsigned num):
|
||||
unsigned size = num << PAGE_BITS
|
||||
if !first_free || (unsigned)first_free > page:
|
||||
// This is the first free block.
|
||||
FreePages *n = (FreePages *)page
|
||||
kFreePages *n = (kFreePages *)page
|
||||
n->prev = NULL
|
||||
if (unsigned)first_free == page + size:
|
||||
// It fits exactly before the previous first free block.
|
||||
@ -89,13 +89,13 @@ void phys_free (unsigned page, unsigned num):
|
||||
if n->next:
|
||||
n->next->prev = n
|
||||
return
|
||||
FreePages *p
|
||||
kFreePages *p
|
||||
for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
|
||||
// Do nothing.
|
||||
// The new block should be inserted directly after p.
|
||||
if (unsigned)p->next == page + size:
|
||||
// It can be merged with the block after it: do that.
|
||||
FreePages *n = (FreePages *)page
|
||||
kFreePages *n = (kFreePages *)page
|
||||
n->prev = p
|
||||
n->next = p->next->next
|
||||
if n->next:
|
||||
@ -115,7 +115,7 @@ void phys_free (unsigned page, unsigned num):
|
||||
p->num += num
|
||||
return
|
||||
// The new block cannot be merged at all.
|
||||
FreePages *n = (FreePages *)page
|
||||
kFreePages *n = (kFreePages *)page
|
||||
n->next = p->next
|
||||
n->prev = p
|
||||
if n->next:
|
||||
@ -130,18 +130,18 @@ unsigned raw_zalloc ():
|
||||
void raw_pfree (unsigned page):
|
||||
return phys_free (page, 1)
|
||||
|
||||
unsigned Memory::zalloc ():
|
||||
unsigned kMemory::zalloc ():
|
||||
if !use ():
|
||||
dbg_log ("limit reached: allocation not allowed")
|
||||
return NULL
|
||||
return raw_zalloc ()
|
||||
|
||||
void Memory::pfree (unsigned page):
|
||||
void kMemory::pfree (unsigned page):
|
||||
unuse ()
|
||||
return raw_pfree (page)
|
||||
|
||||
unsigned Memory::palloc ():
|
||||
unsigned kMemory::palloc ():
|
||||
return zalloc ()
|
||||
|
||||
void Memory::zfree (unsigned page):
|
||||
void kMemory::zfree (unsigned page):
|
||||
pfree (page)
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define ARCH
|
||||
#include "../kernel.hh"
|
||||
|
||||
void Thread_arch_init (Thread *thread):
|
||||
void kThread_arch_init (kThread *thread):
|
||||
thread->arch.at = 0
|
||||
thread->arch.v0 = 0
|
||||
thread->arch.v1 = 0
|
||||
@ -45,14 +45,17 @@ void Thread_arch_init (Thread *thread):
|
||||
thread->arch.k0 = 0
|
||||
thread->arch.k1 = 0
|
||||
|
||||
void Thread_arch_receive (Thread *thread, unsigned protected_data, unsigned *data):
|
||||
thread->arch.t0 = data[0]
|
||||
thread->arch.t1 = data[1]
|
||||
thread->arch.t2 = data[2]
|
||||
thread->arch.t3 = data[3]
|
||||
thread->arch.v0 = protected_data
|
||||
void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data):
|
||||
thread->arch.a0 = data[0].l
|
||||
thread->arch.a1 = data[0].h
|
||||
thread->arch.a2 = data[1].l
|
||||
thread->arch.a3 = data[1].h
|
||||
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:
|
||||
case 1:
|
||||
return &thread->arch.at
|
||||
@ -119,29 +122,29 @@ unsigned *Thread_arch_info (Thread *thread, unsigned num):
|
||||
default:
|
||||
return NULL
|
||||
|
||||
void Memory_arch_init (Memory *mem):
|
||||
void kMemory_arch_init (kMemory *mem):
|
||||
mem->arch.asid = 1
|
||||
mem->arch.directory = NULL
|
||||
mem->arch.shadow = NULL
|
||||
|
||||
void Memory_arch_free (Memory *mem):
|
||||
void kMemory_arch_free (kMemory *mem):
|
||||
while mem->arch.first_page_table:
|
||||
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)
|
||||
asids[mem->arch.asid] = asids[0]
|
||||
asids[0] = mem->arch.asid
|
||||
mem->unuse ()
|
||||
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)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->first_page = NULL
|
||||
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)
|
||||
if !ret:
|
||||
return NULL
|
||||
@ -152,7 +155,7 @@ static arch_page *alloc_page (Memory *mem, arch_page_table *t):
|
||||
return ret
|
||||
|
||||
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->arch.directory[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:
|
||||
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:
|
||||
return 0
|
||||
unsigned flags
|
||||
if page->flags & PAGE_FLAG_UNCACHED:
|
||||
if page->flags & Page::UNCACHED:
|
||||
flags = 0x10 | 0x2
|
||||
else:
|
||||
flags = 0x18 | 0x2
|
||||
if write:
|
||||
if !readonly:
|
||||
flags |= 0x4
|
||||
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:
|
||||
return false
|
||||
address &= PAGE_MASK
|
||||
@ -243,10 +246,10 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
|
||||
return false
|
||||
unsigned idx = (address >> 12) & ((1 << 9) - 1)
|
||||
if table[idx]:
|
||||
mem->unmap ((Page *)table[idx + 0x200], address)
|
||||
table[idx] = make_entry_lo (page, write)
|
||||
mem->unmap ((kPage *)table[idx + 0x200], address)
|
||||
table[idx] = make_entry_lo (page, readonly)
|
||||
table[idx + 0x200] = (unsigned)p
|
||||
p->mapping = address + write
|
||||
p->mapping = address + readonly
|
||||
p->page = page
|
||||
p->next_mapped = page->arch.first_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
|
||||
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 tidx = (address >> 12) & ((1 << 9) - 1)
|
||||
unsigned *table = mem->arch.directory[didx]
|
||||
@ -264,34 +267,34 @@ void Memory_arch_unmap (Memory *mem, Page *page, unsigned address):
|
||||
table[tidx + 0x200] = 0
|
||||
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:
|
||||
return NULL
|
||||
unsigned *table = mem->arch.directory[address >> 21]
|
||||
unsigned idx = (address >> 12) & ((1 << 9) - 1)
|
||||
arch_page *page = (arch_page *)table[idx + 0x200]
|
||||
if writable:
|
||||
*writable = table[idx] & 4
|
||||
if readonly:
|
||||
*readonly = !(table[idx] & 4)
|
||||
return page->page
|
||||
|
||||
void Page_arch_update_mapping (Page *page):
|
||||
void kPage_arch_update_mapping (kPage *page):
|
||||
if !page->arch.first_mapped:
|
||||
return
|
||||
Memory *as = page->address_space
|
||||
unsigned target = make_entry_lo (page, page->flags & PAGE_FLAG_WRITABLE)
|
||||
kMemory *as = page->address_space
|
||||
unsigned target = make_entry_lo (page, page->flags & Page::READONLY)
|
||||
for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped:
|
||||
unsigned de = p->mapping >> 21
|
||||
unsigned te = (p->mapping >> 12) & ((1 << 9) - 1)
|
||||
bool write = p->mapping & 1
|
||||
bool readonly = p->mapping & 1
|
||||
unsigned t
|
||||
if p->mapping & 1:
|
||||
t = target
|
||||
else:
|
||||
if readonly:
|
||||
t = target & ~0x4
|
||||
else:
|
||||
t = target
|
||||
as->arch.directory[de][te] = 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
|
||||
// And enable or disable the interrupt.
|
||||
if r:
|
||||
|
@ -68,7 +68,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL
|
||||
// register save positions in Thread
|
||||
// register save positions in kThread
|
||||
#define SAVE_PC (6 * 4)
|
||||
#define SAVE_SP (SAVE_PC + 4)
|
||||
#define SAVE_AT (SAVE_SP + 4)
|
||||
@ -108,7 +108,7 @@
|
||||
|
||||
void flush_tlb (unsigned asid)
|
||||
|
||||
struct Thread_arch:
|
||||
struct kThread_arch:
|
||||
unsigned at, v0, v1, a0, a1, a2, a3
|
||||
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
|
||||
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
|
||||
// are an index in the page directory and bit 31 is always 0.
|
||||
|
||||
struct arch_page : public Object :
|
||||
Page *page
|
||||
struct arch_page : public kObject :
|
||||
kPage *page
|
||||
unsigned mapping
|
||||
arch_page *prev_mapped, *next_mapped
|
||||
|
||||
struct arch_page_table : public Object :
|
||||
struct arch_page_table : public kObject :
|
||||
arch_page *first_page
|
||||
|
||||
struct Page_arch:
|
||||
struct kPage_arch:
|
||||
arch_page *first_mapped
|
||||
|
||||
struct Memory_arch:
|
||||
struct kMemory_arch:
|
||||
unsigned asid
|
||||
unsigned **directory
|
||||
arch_page_table **shadow
|
||||
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.
|
||||
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.
|
||||
extern "C":
|
||||
// Kernel entry points, called from entry.S.
|
||||
Thread *interrupt ()
|
||||
Thread *cache_error ()
|
||||
Thread *exception ()
|
||||
Thread *tlb_refill ()
|
||||
kThread *interrupt ()
|
||||
kThread *cache_error ()
|
||||
kThread *exception ()
|
||||
kThread *tlb_refill ()
|
||||
|
||||
#ifdef INIT
|
||||
// Initialize most things (the rest is done in boot.S)
|
||||
void init (unsigned mem)
|
||||
// Start running the idle task for the first time.
|
||||
void run_idle (Thread *self)
|
||||
void run_idle (kThread *self)
|
||||
#endif
|
||||
|
||||
// These are "extern", not "EXTERN", because they really are defined elsewhere.
|
||||
|
@ -30,7 +30,7 @@ static void init_idle ():
|
||||
idle.schedule_next = NULL
|
||||
idle.address_space = &idle_memory
|
||||
idle.refs.reset ()
|
||||
idle.flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
|
||||
idle.flags = Thread::RUNNING | Thread::PRIV
|
||||
// initialize idle_memory.
|
||||
idle_memory.prev = NULL
|
||||
idle_memory.next = NULL
|
||||
@ -49,7 +49,7 @@ static void init_idle ():
|
||||
idle_page.prev = NULL
|
||||
idle_page.next = NULL
|
||||
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.address_space = NULL
|
||||
current = &idle
|
||||
@ -104,15 +104,15 @@ static void init_cp0 ():
|
||||
// exceptions in the bootup code will fill EPC and friends.
|
||||
|
||||
static void init_threads ():
|
||||
Thread *previous = NULL
|
||||
kThread *previous = NULL
|
||||
first_scheduled = NULL
|
||||
first_alarm = NULL
|
||||
Receiver *init_receiver = NULL
|
||||
kReceiver *init_receiver = NULL
|
||||
for unsigned i = 0; i < NUM_THREADS; ++i:
|
||||
Memory *mem = top_memory.alloc_memory ()
|
||||
kMemory *mem = top_memory.alloc_memory ()
|
||||
assert (mem)
|
||||
Thread *thread = mem->alloc_thread (3)
|
||||
Page **pages = (Page **)mem->zalloc ()
|
||||
kThread *thread = mem->alloc_thread (3)
|
||||
kPage **pages = (kPage **)mem->zalloc ()
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
|
||||
for unsigned j = 0; j < SELFMAG; ++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)
|
||||
if ~shdr->sh_flags & SHF_ALLOC:
|
||||
continue
|
||||
bool writable = shdr->sh_flags & SHF_WRITE
|
||||
bool readonly = !(shdr->sh_flags & SHF_WRITE)
|
||||
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
|
||||
if shdr->sh_type != SHT_NOBITS:
|
||||
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
|
||||
@ -152,18 +152,18 @@ static void init_threads ():
|
||||
if !pages[idx]:
|
||||
pages[idx] = mem->alloc_page ()
|
||||
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
|
||||
mem->use ()
|
||||
if !mem->map (pages[idx], p, writable):
|
||||
if !mem->map (pages[idx], p, readonly):
|
||||
panic (0x22446688, "unable to map initial page")
|
||||
return
|
||||
else:
|
||||
if !writable:
|
||||
if readonly:
|
||||
panic (0x33399993, "unwritable bss section")
|
||||
return
|
||||
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:
|
||||
page = mem->alloc_page ()
|
||||
if !page:
|
||||
@ -173,12 +173,12 @@ static void init_threads ():
|
||||
if !page->frame:
|
||||
panic (0x02220022, "out of memory");
|
||||
return
|
||||
page->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
page->flags = Page::PAYING | Page::FRAME
|
||||
if !mem->map (page, p, true):
|
||||
panic (0x33557799, "unable to map initial bss page")
|
||||
return
|
||||
else:
|
||||
if !writable:
|
||||
if readonly:
|
||||
panic (0x20203030, "bss section starts on read-only page")
|
||||
return
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
@ -192,28 +192,26 @@ static void init_threads ():
|
||||
continue
|
||||
++top_memory.limit
|
||||
top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
|
||||
Page *stackpage = mem->alloc_page ()
|
||||
kPage *stackpage = mem->alloc_page ()
|
||||
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):
|
||||
panic (0x13151719, "unable to map initial stack page")
|
||||
return
|
||||
thread->caps[0] = mem->alloc_caps (16)
|
||||
for unsigned r = 0; r < 4; ++r:
|
||||
thread->rcaps[r] = CapRef ()
|
||||
Receiver *recv = mem->alloc_receiver ()
|
||||
kReceiver *recv = mem->alloc_receiver ()
|
||||
recv->owner = thread
|
||||
thread->receivers = recv
|
||||
thread->caps[0]->set (__my_receiver, (ReceiverP)(CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS), (Protected)recv, CapRef ())
|
||||
thread->caps[0]->set (__my_thread, (ReceiverP)(CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS), (Protected)thread, CapRef ())
|
||||
thread->caps[0]->set (__my_memory, (ReceiverP)(CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS), (Protected)mem, CapRef ())
|
||||
thread->caps[0]->set (__my_call, (ReceiverP)(CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)), (Protected)recv, CapRef ())
|
||||
thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
|
||||
thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Num ((unsigned)recv), kCapRef (), &recv->refs)
|
||||
thread->caps[0]->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Num ((unsigned)thread), kCapRef (), &thread->refs)
|
||||
thread->caps[0]->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Num ((unsigned)mem), kCapRef (), &mem->refs)
|
||||
thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Receiver::CALL), Num ((unsigned)recv), kCapRef (), &recv->refs)
|
||||
thread->flags = Thread::RUNNING | Thread::PRIV
|
||||
if !i:
|
||||
first_scheduled = thread
|
||||
init_receiver = recv
|
||||
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
|
||||
thread->schedule_prev = previous
|
||||
thread->schedule_next = NULL
|
||||
|
@ -29,7 +29,7 @@ static void handle_exit ():
|
||||
schedule ()
|
||||
if !current:
|
||||
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")
|
||||
if !current:
|
||||
current = &idle
|
||||
@ -37,7 +37,7 @@ static void handle_exit ():
|
||||
return
|
||||
arch_flush_cache ()
|
||||
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]:
|
||||
current->address_space->arch.asid = 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
|
||||
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
|
||||
directory = current->address_space->arch.directory
|
||||
if current->flags & THREAD_FLAG_PRIV:
|
||||
if current->flags & Thread::PRIV:
|
||||
cp0_set (CP0_STATUS, 0x1000ff13)
|
||||
else:
|
||||
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
|
||||
/// when k0 or k1 is not 0, or when an error occurs.
|
||||
/// Otherwise, the ultra-fast code in entry.S is used.
|
||||
Thread *tlb_refill ():
|
||||
kThread *tlb_refill ():
|
||||
old_current = current
|
||||
if !directory:
|
||||
unsigned addr
|
||||
@ -85,7 +85,7 @@ Thread *tlb_refill ():
|
||||
return current
|
||||
|
||||
/// An interrupt which is not an exception has occurred.
|
||||
Thread *interrupt ():
|
||||
kThread *interrupt ():
|
||||
old_current = current
|
||||
unsigned ipr = INTC_IPR
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
@ -98,11 +98,10 @@ Thread *interrupt ():
|
||||
intc_ack_irq (i)
|
||||
// Send message to interrupt handler.
|
||||
if arch_interrupt_receiver[i]:
|
||||
Capability::Context c
|
||||
for unsigned j = 0; j < 4; ++j:
|
||||
kCapability::Context c
|
||||
for unsigned j = 0; j < 2; ++j:
|
||||
c.data[j] = 0
|
||||
c.cap[j].reset ()
|
||||
c.copy[j] = false
|
||||
c.caps = NULL
|
||||
arch_interrupt_receiver[i]->send_message (i, &c)
|
||||
arch_interrupt_receiver[i] = NULL
|
||||
if ipr & (1 << IRQ_OST0):
|
||||
@ -124,42 +123,49 @@ void flush_tlb (unsigned asid):
|
||||
__asm__ volatile ("tlbwi")
|
||||
|
||||
static void arch_invoke ():
|
||||
CapRef target
|
||||
kCapRef target
|
||||
bool wait
|
||||
target = old_current->find_capability (old_current->arch.v0, &wait)
|
||||
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], ©)
|
||||
if t:
|
||||
msg.caps->clone (i, t, copy)
|
||||
else:
|
||||
msg.caps = NULL
|
||||
else:
|
||||
msg.caps = NULL
|
||||
if wait:
|
||||
bool dummy
|
||||
CapRef c0, c1, c2, c3
|
||||
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)
|
||||
old_current->recv_slot = old_current->arch.s1
|
||||
old_current->wait ()
|
||||
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")
|
||||
// There must be no action here.
|
||||
return
|
||||
Capability::Context c
|
||||
c.cap[0] = old_current->find_capability (old_current->arch.a0, &c.copy[0])
|
||||
c.cap[1] = old_current->find_capability (old_current->arch.a1, &c.copy[1])
|
||||
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)
|
||||
msg.data[0] = Num (old_current->arch.a0, old_current->arch.a1)
|
||||
msg.data[1] = Num (old_current->arch.a2, old_current->arch.a3)
|
||||
target->invoke (&msg)
|
||||
if do_schedule && !wait:
|
||||
// If the call was to schedule without wait, it isn't done yet.
|
||||
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.
|
||||
current = old_current
|
||||
|
||||
/// A general exception has occurred.
|
||||
Thread *exception ():
|
||||
kThread *exception ():
|
||||
old_current = current
|
||||
unsigned cause
|
||||
cp0_get (CP0_CAUSE, cause)
|
||||
@ -288,7 +294,7 @@ Thread *exception ():
|
||||
return current
|
||||
|
||||
/// There's a cache error. Big trouble. Probably not worth trying to recover.
|
||||
Thread *cache_error ():
|
||||
kThread *cache_error ():
|
||||
panic (0x33333333, "cache error")
|
||||
old_current = current
|
||||
handle_exit ()
|
||||
|
@ -136,13 +136,13 @@
|
||||
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
|
||||
|
||||
// Map IO memory (requires a priviledged __my_thread capability).
|
||||
#include <iris.h>
|
||||
#include <iris.hh>
|
||||
static void __map_io (unsigned physical, unsigned mapping):
|
||||
memory_create_page (6, __my_memory)
|
||||
// 0 means not cachable; 0 means don't free when done.
|
||||
alloc_physical (6, physical, 0, 0)
|
||||
// 1 means writable.
|
||||
memory_map (__my_memory, 6, mapping, 1)
|
||||
Page p = __my_memory.create_page ()
|
||||
// false means not cachable; false means don't free when done.
|
||||
p.alloc_physical (physical, 0, 0)
|
||||
// true means writable.
|
||||
__my_memory.map (p, mapping, true)
|
||||
|
||||
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_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)
|
||||
|
||||
#ifndef __KERNEL
|
||||
static __inline__ void ddelay (unsigned ds):
|
||||
Message m
|
||||
my_sleep (ds, &m)
|
||||
static __inline__ void cdelay (unsigned ds):
|
||||
__my_receiver.set_alarm (ds * (HZ / 100))
|
||||
Cap ().call (~0)
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
@ -3034,9 +3034,7 @@ static __inline__ void i2c_open ():
|
||||
|
||||
// Note that this kills messages from the queue.
|
||||
static __inline__ void i2c_close ():
|
||||
Message msg
|
||||
receiver_set_alarm (__my_receiver, 3 * HZ / 10)
|
||||
call_00 (0)
|
||||
cdelay (30)
|
||||
i2c_disable ()
|
||||
|
||||
static __inline__ bool i2c_send (unsigned data):
|
||||
|
@ -24,11 +24,10 @@ void dbg_log_char (unsigned ch):
|
||||
if !dbg_cap:
|
||||
return
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
c.data[i] = 0
|
||||
c->recv_memory = NULL
|
||||
c->caps = NULL
|
||||
c.data[0] = ch
|
||||
c.data[1] = 0
|
||||
dbg_cap->invoke (&c)
|
||||
if dbg_cap->target->owner:
|
||||
current = dbg_cap->target->owner
|
||||
|
3
plan
3
plan
@ -1,6 +1,5 @@
|
||||
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
|
||||
caps is stored in designated (by receiver) slot
|
||||
caps zonder size limit?
|
||||
invoke ipc: try sync; try receiver memory; try caller memory; fail.
|
||||
|
49
schedule.ccp
49
schedule.ccp
@ -18,14 +18,14 @@
|
||||
|
||||
#include "kernel.hh"
|
||||
|
||||
static void run_thread (Thread *thread):
|
||||
static void run_thread (kThread *thread):
|
||||
thread->schedule_next = first_scheduled
|
||||
if thread->schedule_next:
|
||||
thread->schedule_next->schedule_prev = thread
|
||||
thread->schedule_prev = NULL
|
||||
first_scheduled = thread
|
||||
|
||||
static void unrun_thread (Thread *thread):
|
||||
static void unrun_thread (kThread *thread):
|
||||
if current == thread:
|
||||
current = thread->schedule_next
|
||||
if thread->schedule_prev:
|
||||
@ -35,35 +35,34 @@ static void unrun_thread (Thread *thread):
|
||||
if thread->schedule_next:
|
||||
thread->schedule_next->schedule_prev = thread->schedule_prev
|
||||
|
||||
void Thread::run ():
|
||||
if flags & THREAD_FLAG_RUNNING:
|
||||
void kThread::run ():
|
||||
if flags & Thread::RUNNING:
|
||||
return
|
||||
flags |= THREAD_FLAG_RUNNING
|
||||
flags |= Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
run_thread (this)
|
||||
|
||||
void Thread::unrun ():
|
||||
if !(flags & THREAD_FLAG_RUNNING):
|
||||
void kThread::unrun ():
|
||||
if !(flags & Thread::RUNNING):
|
||||
return
|
||||
flags &= ~THREAD_FLAG_RUNNING
|
||||
flags &= ~Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
unrun_thread (this)
|
||||
|
||||
void Thread::unwait ():
|
||||
flags &= ~THREAD_FLAG_WAITING
|
||||
if flags & THREAD_FLAG_RUNNING:
|
||||
void kThread::unwait ():
|
||||
flags &= ~Thread::WAITING
|
||||
if flags & Thread::RUNNING:
|
||||
run_thread (this)
|
||||
|
||||
static void alarm_tick (Receiver *recv):
|
||||
static void alarm_tick (kReceiver *recv):
|
||||
if !recv->alarm_count:
|
||||
// Send message and stop counting.
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
kCapability::Context c
|
||||
c.caps = NULL
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
c.data[i] = 0
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
recv->send_message (~0, &c)
|
||||
if recv->prev_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.
|
||||
--recv->alarm_count
|
||||
|
||||
void Thread::wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3):
|
||||
if flags & THREAD_FLAG_RUNNING:
|
||||
void kThread::wait ():
|
||||
if flags & Thread::RUNNING:
|
||||
unrun_thread (this)
|
||||
flags |= THREAD_FLAG_WAITING
|
||||
rcaps[0] = c0
|
||||
rcaps[1] = c1
|
||||
rcaps[2] = c2
|
||||
rcaps[3] = c3
|
||||
// Try to receive a message from a Receiver immediately.
|
||||
for Receiver *r = receivers; r; r = r->next_owned:
|
||||
flags |= Thread::WAITING
|
||||
// Try to receive a message from a kReceiver immediately.
|
||||
for kReceiver *r = receivers; r; r = r->next_owned:
|
||||
if r->try_deliver ():
|
||||
return
|
||||
|
||||
@ -94,8 +89,8 @@ void schedule ():
|
||||
current = first_scheduled
|
||||
|
||||
void timer_interrupt ():
|
||||
Receiver *recv, *next
|
||||
kReceiver *recv, *next
|
||||
for recv = first_alarm; recv; recv = next:
|
||||
next = (Receiver *)recv->next
|
||||
next = (kReceiver *)recv->next
|
||||
alarm_tick (recv)
|
||||
//schedule ()
|
||||
|
Loading…
x
Reference in New Issue
Block a user