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