mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 19:44:16 +02:00
reorganize capabilities; doesn't work yet
This commit is contained in:
parent
561535234d
commit
fb5a321554
232
alloc.ccp
232
alloc.ccp
@ -25,9 +25,9 @@
|
||||
// The prev/next-lists contain only objects of one type, unsorted.
|
||||
// All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV.
|
||||
|
||||
#define PREV(x) (((Object_base **)(x))[-2])
|
||||
#define NEXT(x) (((Object_base **)(x))[-1])
|
||||
#define SIZE (2 * sizeof (Object_base *))
|
||||
#define PREV(x) (((Object **)(x))[-2])
|
||||
#define NEXT(x) (((Object **)(x))[-1])
|
||||
#define SIZE (2 * sizeof (Object *))
|
||||
|
||||
bool Memory::use (unsigned num):
|
||||
// Go up to parents, incrementing used.
|
||||
@ -52,7 +52,7 @@ void *Memory::search_free (unsigned size, void **first):
|
||||
Free *f
|
||||
unsigned s = 0
|
||||
// Let's see if there already is a Free chunk which is large enough.
|
||||
for f = frees; f; f = f->next:
|
||||
for f = frees; f; f = (Free *)f->next:
|
||||
if NEXT (f):
|
||||
s = (unsigned)NEXT (f) - (unsigned)f
|
||||
else:
|
||||
@ -75,7 +75,7 @@ void *Memory::search_free (unsigned size, void **first):
|
||||
f->prev = NULL
|
||||
frees = f
|
||||
if f->next:
|
||||
f->next->prev = f
|
||||
((Free *)f->next)->prev = f
|
||||
// There are no other objects in this page.
|
||||
NEXT (f) = NULL
|
||||
PREV (f) = NULL
|
||||
@ -100,32 +100,35 @@ void *Memory::search_free (unsigned size, void **first):
|
||||
// The block was only just large enough: turn it into a new type. It is already linked into the page.
|
||||
// Unlink it from the free list.
|
||||
if f->prev:
|
||||
f->prev->next = f->next
|
||||
((Free *)f->prev)->next = f->next
|
||||
else:
|
||||
frees = f->next
|
||||
frees = (Free *)f->next
|
||||
if f->next:
|
||||
f->next->prev = f->prev
|
||||
((Free *)f->next)->prev = f->prev
|
||||
// f is now a block which is linked in the page, but not in any list. Link it into first.
|
||||
f->next = (Free *)*first
|
||||
f->prev = NULL
|
||||
if f->next:
|
||||
f->next->prev = f
|
||||
((Free *)f->next)->prev = f
|
||||
*first = f
|
||||
// Set common initial values.
|
||||
f->address_space = this
|
||||
f->refs = NULL
|
||||
f->refs.reset ()
|
||||
return f
|
||||
|
||||
// Free an object; it is still in its list, and it is still in the page list.
|
||||
void Memory::free_obj (Object_base *obj, void **first):
|
||||
void Memory::free_obj (Object *obj, Pointer *first):
|
||||
Free *self = (Free *)obj
|
||||
// Invalidate references.
|
||||
while self->refs:
|
||||
self->refs->invalidate ()
|
||||
// Free it from its list.
|
||||
if self->prev:
|
||||
self->prev->next = self->next
|
||||
((Free *)self->prev)->next = self->next
|
||||
else:
|
||||
*(Object_base **)first = self->next
|
||||
*(Pointer *)first = (Pointer)self->next
|
||||
if self->next:
|
||||
self->next->prev = self->prev
|
||||
((Free *)self->next)->prev = self->prev
|
||||
// Merge with previous, if it exists and is a Free.
|
||||
if PREV (self) && PREV (self)->is_free ():
|
||||
self = (Free *)PREV (self)
|
||||
@ -139,7 +142,7 @@ void Memory::free_obj (Object_base *obj, void **first):
|
||||
self->next = frees
|
||||
self->prev = NULL
|
||||
if self->next:
|
||||
self->next->prev = self
|
||||
((Free *)self->next)->prev = self
|
||||
frees = self
|
||||
// Mark it as a Free.
|
||||
self->marker = ~0
|
||||
@ -148,11 +151,11 @@ void Memory::free_obj (Object_base *obj, void **first):
|
||||
// Unlink the next from the frees list.
|
||||
Free *n = (Free *)NEXT (self)
|
||||
if n->prev:
|
||||
n->prev->next = n->next
|
||||
((Free *)n->prev)->next = n->next
|
||||
else:
|
||||
frees = n->next
|
||||
frees = (Free *)n->next
|
||||
if n->next:
|
||||
n->next->prev = n->prev
|
||||
((Free *)n->next)->prev = n->prev
|
||||
// Unlink the next from the page list.
|
||||
NEXT (self) = NEXT (NEXT (self))
|
||||
if NEXT (self):
|
||||
@ -160,34 +163,34 @@ void Memory::free_obj (Object_base *obj, void **first):
|
||||
// Free page if the resulting object is the only thing in it.
|
||||
if !PREV (self) && !NEXT (self):
|
||||
if self->next:
|
||||
self->next->prev = self->prev
|
||||
((Free *)self->next)->prev = self->prev
|
||||
if self->prev:
|
||||
self->prev->next = self->next
|
||||
((Free *)self->prev)->next = self->next
|
||||
else:
|
||||
frees = self->next
|
||||
frees = (Free *)self->next
|
||||
pfree ((unsigned)self - SIZE)
|
||||
|
||||
Page *Memory::alloc_page ():
|
||||
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->data.frame = 0
|
||||
ret->data.flags = 0
|
||||
ret->frame = 0
|
||||
ret->flags = 0
|
||||
return ret
|
||||
|
||||
Thread *Memory::alloc_thread ():
|
||||
Thread *ret = (Thread *)search_free (sizeof (Thread), (void **)&threads)
|
||||
Thread *Memory::alloc_thread (unsigned size):
|
||||
Thread *ret = (Thread *)search_free (sizeof (Thread) + (size - 1) * sizeof (CapsP), (void **)&threads)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->address_space = this
|
||||
ret->receivers = NULL
|
||||
ret->pc = 0
|
||||
ret->sp = 0
|
||||
Thread_arch_init (ret)
|
||||
ret->flags = 0
|
||||
ret->schedule_prev = NULL
|
||||
ret->schedule_next = NULL
|
||||
ret->receivers = NULL
|
||||
top_memory.alloc_capability (NULL, NULL, NULL, 0, &ret->exception)
|
||||
for unsigned i = 0; i < size; ++i:
|
||||
ret->caps[i] = NULL
|
||||
return ret
|
||||
|
||||
Message *Memory::alloc_message (Receiver *target):
|
||||
@ -206,55 +209,21 @@ Receiver *Memory::alloc_receiver ():
|
||||
ret->prev_owned = NULL
|
||||
ret->next_owned = NULL
|
||||
ret->alarm_count = ~0
|
||||
ret->capabilities = NULL
|
||||
ret->caps = NULL
|
||||
ret->capabilities.reset ()
|
||||
ret->messages = NULL
|
||||
ret->last_message = NULL
|
||||
ret->reply_protected_data = ~0
|
||||
ret->protected_only = false
|
||||
return ret
|
||||
|
||||
Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret):
|
||||
if !ret:
|
||||
ret = (Capability *)search_free (sizeof (Capability), (void **)&capabilities)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->target = target
|
||||
ret->protected_data = protected_data
|
||||
ret->parent = parent
|
||||
ret->children = NULL
|
||||
ret->sibling_prev = NULL
|
||||
if parent:
|
||||
ret->sibling_next = parent->children
|
||||
parent->children = ret
|
||||
else:
|
||||
if parent_ptr:
|
||||
ret->sibling_next = *parent_ptr
|
||||
else:
|
||||
ret->sibling_next = NULL
|
||||
if ret->sibling_next:
|
||||
ret->sibling_next->sibling_prev = ret
|
||||
return ret
|
||||
|
||||
Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret):
|
||||
if copy:
|
||||
if source->parent:
|
||||
return alloc_capability (source->target, source->parent, &source->parent->children, source->protected_data, ret)
|
||||
else if (unsigned)source->target & ~KERNEL_MASK:
|
||||
return alloc_capability (source->target, source->parent, &source->target->capabilities, source->protected_data, ret)
|
||||
else:
|
||||
return alloc_capability (source->target, source->parent, &((Object_base *)source->protected_data)->refs, source->protected_data, ret)
|
||||
else:
|
||||
return alloc_capability (source->target, source, &source->children, source->protected_data, ret)
|
||||
|
||||
Cappage *Memory::alloc_cappage ():
|
||||
Cappage *ret = (Cappage *)search_free (sizeof (Cappage), (void **)&cappages)
|
||||
Caps *Memory::alloc_caps (unsigned size):
|
||||
Caps *ret = (Caps *)search_free (sizeof (Caps) + (size - 1) * sizeof (Capability), (void **)&capses)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->data.frame = zalloc ()
|
||||
if !ret->data.frame:
|
||||
free_cappage (ret)
|
||||
return NULL
|
||||
ret->data.flags = 0
|
||||
ret->size = size
|
||||
for unsigned i = 0; i < size; ++i:
|
||||
ret->set (i, NULL, 0, CapRef (), NULL)
|
||||
return ret
|
||||
|
||||
Memory *Memory::alloc_memory ():
|
||||
@ -264,32 +233,59 @@ Memory *Memory::alloc_memory ():
|
||||
ret->frees = NULL
|
||||
ret->pages = NULL
|
||||
ret->threads = NULL
|
||||
ret->capses = NULL
|
||||
ret->receivers = NULL
|
||||
ret->memories = NULL
|
||||
ret->limit = ~0
|
||||
ret->used = 0
|
||||
Memory_arch_init (ret)
|
||||
return ret
|
||||
|
||||
void Caps::set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr):
|
||||
caps[index].target = target
|
||||
caps[index].protected_data = pdata
|
||||
caps[index].parent = parent
|
||||
caps[index].children.reset ()
|
||||
caps[index].sibling_prev.reset ()
|
||||
if parent:
|
||||
caps[index].sibling_next = parent->children
|
||||
parent->children = CapRef (this, index)
|
||||
else:
|
||||
if parent_ptr:
|
||||
caps[index].sibling_next = *parent_ptr
|
||||
*parent_ptr = CapRef (this, index)
|
||||
else:
|
||||
caps[index].sibling_next.reset ()
|
||||
if caps[index].sibling_next:
|
||||
caps[index].sibling_next->sibling_prev = CapRef (this, index)
|
||||
|
||||
void Caps::clone (unsigned index, CapRef source, bool copy):
|
||||
if copy:
|
||||
if source->parent:
|
||||
set (index, source->target, source->protected_data, source->parent)
|
||||
else if (unsigned)source->target & ~KERNEL_MASK:
|
||||
set (index, source->target, source->protected_data, CapRef (), &source->target->capabilities)
|
||||
else:
|
||||
set (index, source->target, source->protected_data, CapRef (), &((Object *)source->protected_data)->refs)
|
||||
else:
|
||||
set (index, source->target, source->protected_data, source)
|
||||
|
||||
void Memory::free_page (Page *page):
|
||||
if page->data.flags & PAGE_FLAG_PAYING:
|
||||
if page->flags & PAGE_FLAG_PAYING:
|
||||
unuse ()
|
||||
if page->data.frame:
|
||||
pfree (page->data.frame)
|
||||
free_obj (page, (void **)&pages)
|
||||
if page->frame:
|
||||
pfree (page->frame)
|
||||
free_obj (page, (Pointer *)&pages)
|
||||
|
||||
void Memory::free_thread (Thread *thread):
|
||||
thread->unrun ()
|
||||
while thread->receivers:
|
||||
thread->receivers->orphan ()
|
||||
thread->exception.invalidate ()
|
||||
free_obj (thread, (void **)&threads)
|
||||
|
||||
void Memory::free_message (Receiver *owner, Message *message):
|
||||
if !message->next:
|
||||
owner->last_message = message->prev
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
if message->capabilities[i]:
|
||||
free_capability (message->capabilities[i])
|
||||
owner->last_message = (MessageP)message->prev
|
||||
free_obj (message, (void **)&owner->messages)
|
||||
|
||||
void Memory::free_receiver (Receiver *receiver):
|
||||
@ -318,10 +314,6 @@ void Receiver::own (Thread *o):
|
||||
next_owned->prev_owned = this
|
||||
o->receivers = this
|
||||
|
||||
void Memory::free_capability (Capability *capability):
|
||||
capability->invalidate ()
|
||||
free_obj (capability, (void **)&capabilities)
|
||||
|
||||
void Capability::invalidate ():
|
||||
if !target:
|
||||
return
|
||||
@ -330,78 +322,60 @@ void Capability::invalidate ():
|
||||
else if (unsigned)target & ~KERNEL_MASK:
|
||||
target->capabilities = sibling_next
|
||||
else:
|
||||
((Object_base *)protected_data)->refs = sibling_next
|
||||
((Object *)protected_data)->refs = sibling_next
|
||||
if sibling_next:
|
||||
sibling_next->sibling_prev = sibling_prev
|
||||
parent = NULL
|
||||
sibling_prev = NULL
|
||||
sibling_next = NULL
|
||||
parent.reset ()
|
||||
sibling_prev.reset ()
|
||||
sibling_next.reset ()
|
||||
Capability *c = this
|
||||
while c->children:
|
||||
c = c->children
|
||||
while c:
|
||||
Capability *next = c->sibling_next
|
||||
while c->children:
|
||||
c = c->children.deref ()
|
||||
Capability *next = c->sibling_next.deref ()
|
||||
if !next:
|
||||
next = c->parent
|
||||
next = c->parent.deref ()
|
||||
c->target = NULL
|
||||
c->parent = NULL
|
||||
c->children = NULL
|
||||
c->sibling_prev = NULL
|
||||
c->sibling_next = NULL
|
||||
c->parent.reset ()
|
||||
c->children.reset ()
|
||||
c->sibling_prev.reset ()
|
||||
c->sibling_next.reset ()
|
||||
c->protected_data = 0
|
||||
c = next
|
||||
|
||||
void Memory::free_cappage (Cappage *p):
|
||||
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
|
||||
((Capability *)p->data.frame)[i].invalidate ()
|
||||
zfree (p->data.frame)
|
||||
free_obj (p, (void **)&cappages)
|
||||
void Memory::free_caps (Caps *c):
|
||||
for unsigned i = 0; i < c->size; ++i:
|
||||
c->caps[i].invalidate ()
|
||||
free_obj (c, (void **)&capses)
|
||||
|
||||
void Memory::free_memory (Memory *mem):
|
||||
while mem->pages:
|
||||
free_page (mem->pages)
|
||||
while mem->cappages:
|
||||
free_cappage (mem->cappages)
|
||||
while mem->capses:
|
||||
free_caps (mem->capses)
|
||||
while mem->threads:
|
||||
free_thread (mem->threads)
|
||||
while mem->memories:
|
||||
free_memory (mem->memories)
|
||||
while mem->receivers:
|
||||
free_receiver (mem->receivers)
|
||||
while mem->capabilities:
|
||||
free_capability (mem->capabilities)
|
||||
Memory_arch_free (mem)
|
||||
if mem->frees:
|
||||
panic (0, "kernel memory leak: memory still in use")
|
||||
free_obj (mem, (void **)&memories)
|
||||
|
||||
void Page::forget ():
|
||||
if data.share_prev || data.share_next:
|
||||
if data.share_prev:
|
||||
((Page *)data.share_prev)->data.share_next = data.share_next
|
||||
if data.share_next:
|
||||
((Page *)data.share_next)->data.share_prev = data.share_prev
|
||||
data.share_prev = NULL
|
||||
data.share_next = NULL
|
||||
if share_prev || share_next:
|
||||
if share_prev:
|
||||
share_prev->share_next = share_next
|
||||
if share_next:
|
||||
share_next->share_prev = share_prev
|
||||
share_prev = NULL
|
||||
share_next = NULL
|
||||
else:
|
||||
// If the page has a frame and should be freed, free it.
|
||||
if !((data.flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)):
|
||||
raw_pfree (data.frame)
|
||||
data.frame = 0
|
||||
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
|
||||
if !((flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)):
|
||||
raw_pfree (frame)
|
||||
frame = 0
|
||||
flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
|
||||
Page_arch_update_mapping (this)
|
||||
|
||||
void Cappage::forget ():
|
||||
if data.share_prev || data.share_next:
|
||||
if data.share_prev:
|
||||
((Cappage *)data.share_prev)->data.share_next = data.share_next
|
||||
if data.share_next:
|
||||
((Cappage *)data.share_next)->data.share_prev = data.share_prev
|
||||
data.share_prev = NULL
|
||||
data.share_next = NULL
|
||||
else:
|
||||
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
|
||||
((Capability *)data.frame)[i].invalidate ()
|
||||
raw_pfree (data.frame)
|
||||
data.frame = 0
|
||||
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED)
|
||||
|
@ -30,16 +30,6 @@ __hack_label:
|
||||
.word _gp
|
||||
1:
|
||||
lw $gp, 0($ra)
|
||||
la $v0, __my_receiver
|
||||
sw $a0, ($v0)
|
||||
la $v0, __my_thread
|
||||
sw $a1, ($v0)
|
||||
la $v0, __my_memory
|
||||
sw $a2, ($v0)
|
||||
la $v0, __my_call
|
||||
sw $a3, ($v0)
|
||||
la $v0, __my_parent
|
||||
sw $t0, ($v0)
|
||||
la $t9, main
|
||||
la $ra, 1f
|
||||
jr $t9
|
||||
@ -49,9 +39,3 @@ __hack_label:
|
||||
// This should not be reached: generate an address fault.
|
||||
b 1b
|
||||
lw $a0, -4($zero)
|
||||
|
||||
.comm __my_receiver, 4
|
||||
.comm __my_thread, 4
|
||||
.comm __my_memory, 4
|
||||
.comm __my_call, 4
|
||||
.comm __my_parent, 4
|
||||
|
@ -24,19 +24,25 @@
|
||||
// This shouldn't really be here. But where should it be?
|
||||
// Requests made by initial threads to tell init about themselves.
|
||||
enum init_requests:
|
||||
INIT_SET_GPIO_0
|
||||
INIT_SET_GPIO_1
|
||||
INIT_SET_GPIO
|
||||
INIT_SET_LCD
|
||||
|
||||
|
||||
// Keyboard interface.
|
||||
// Startup: kbd_set_cb
|
||||
enum Keyboard_request:
|
||||
KEYBOARD_SET_CB
|
||||
KEYBOARD_GET_KEYS
|
||||
|
||||
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
|
||||
static __inline__ void keyboard_set_cb (Capability kbd_set_cb, Capability cb):
|
||||
invoke_10 (kbd_set_cb, cb)
|
||||
static __inline__ void keyboard_set_cb (Capability kbd, Capability cb):
|
||||
invoke_11 (kbd, cb, KEYBOARD_SET_CB)
|
||||
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
||||
#define KEYBOARD_RELEASE (1 << 31)
|
||||
|
||||
// Get a list of keys on this keyboard. The key codes start at zero with no gaps. The returned capability is a read-only list of strings.
|
||||
static __inline__ void keyboard_get_keys (Capability target, Capability kbd):
|
||||
call_c01 (kbd, target, KEYBOARD_GET_KEYS)
|
||||
|
||||
|
||||
|
||||
// Display interface.
|
||||
@ -93,8 +99,8 @@ static __inline__ unsigned long long file_get_info (Capability file, unsigned ty
|
||||
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__ Capability file_copy_handle (Capability file):
|
||||
return call_c01 (file, FILE_COPY_HANDLE)
|
||||
static __inline__ void file_copy_handle (Capability target, Capability file):
|
||||
call_c01 (file, target, FILE_COPY_HANDLE)
|
||||
|
||||
// Directory interface.
|
||||
// Get the number of entries in this directory.
|
||||
@ -104,17 +110,17 @@ static __inline__ unsigned long long directory_get_size (Capability dir):
|
||||
static __inline__ unsigned directory_get_name (Capability dir, unsigned long long idx, Capability page):
|
||||
return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32)
|
||||
// Get the file.
|
||||
static __inline__ Capability directory_get_file (Capability dir, unsigned long long idx, Capability page):
|
||||
return call_c03 (dir, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
|
||||
static __inline__ void directory_get_file (Capability target, Capability dir, unsigned long long idx, Capability page):
|
||||
call_c03 (dir, target, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
|
||||
// Get file info. This returns the same information as file_get_info, without opening the file.
|
||||
static __inline__ unsigned long long directory_get_file_info (Capability dir, unsigned long long idx, unsigned type):
|
||||
return call_l04 (dir, DIRECTORY_GET_FILE_INFO, idx & 0xffffffff, idx >> 32, type)
|
||||
// Create a new file. After this, any index may map to a different file.
|
||||
static __inline__ Capability directory_create_file (Capability dir, unsigned long long idx, Capability page):
|
||||
return call_c03 (dir, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
|
||||
static __inline__ void directory_create_file (Capability target, Capability dir, unsigned long long idx, Capability page):
|
||||
call_c03 (dir, target, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
|
||||
// Delete a file. After this, any index may map to a different file.
|
||||
static __inline__ Capability directory_delete_file (Capability dir, unsigned long long idx, Capability page):
|
||||
return call_c03 (dir, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
|
||||
static __inline__ void directory_delete_file (Capability target, Capability dir, unsigned long long idx, Capability page):
|
||||
call_c03 (dir, target, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
|
||||
|
||||
// Stream interface.
|
||||
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
|
||||
@ -148,8 +154,8 @@ 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__ Capability block_get_file (Capability blk_get_file):
|
||||
call_c00 (blk_get_file)
|
||||
static __inline__ void block_get_file (Capability target, Capability blk_get_file):
|
||||
call_c00 (blk_get_file, target)
|
||||
|
||||
|
||||
|
||||
|
@ -20,8 +20,8 @@
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
// Interval between polls for keyboard (when keys are pressed) and battery/power (always) events
|
||||
#define ALARM_INTERVAL (HZ / 20)
|
||||
// Interval between polls for keyboard events (when keys are pressed)
|
||||
#define ALARM_INTERVAL (HZ / 50)
|
||||
|
||||
// GPIO pins for the devices (port.pin)
|
||||
|
||||
@ -42,13 +42,6 @@
|
||||
// Scroll lock: 0.9
|
||||
// interrupts: no, output only.
|
||||
|
||||
// Power output (setting to 0 switches off the machine): 2.2
|
||||
// interrupts: no, output only.
|
||||
|
||||
// Power button: 3.1 (note that this is also a keyboard column.)
|
||||
// Battery presence and charge detection: 3.29 (note that this is also a keyboard column.)
|
||||
// interrupts: no; it would be possible, but setting these to input makes it impossible to detect certain key presses as interrupts.
|
||||
|
||||
// interrupt summary
|
||||
// Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad
|
||||
// Port 1: None.
|
||||
@ -58,43 +51,28 @@
|
||||
enum event_type:
|
||||
KEYBOARD_EVENT
|
||||
TOUCHPAD_EVENT
|
||||
POWERBUTTON_EVENT
|
||||
BATTERY_EVENT
|
||||
NUM_EVENTS
|
||||
|
||||
enum cap_type:
|
||||
CAP_KEYBOARD = 32
|
||||
CAP_TOUCHPAD
|
||||
CAP_POWEROFF
|
||||
CAP_POWERBUTTON
|
||||
CAP_BATTERY
|
||||
CAP_LOCKLEDS
|
||||
CAP_PWM
|
||||
|
||||
static Capability cbs[NUM_EVENTS]
|
||||
|
||||
static void event (event_type type, unsigned data):
|
||||
if !cbs[type]:
|
||||
return
|
||||
invoke_01 (cbs[type], data)
|
||||
invoke_01 (11 + type, data)
|
||||
|
||||
static void set_cb (event_type type, Capability cb):
|
||||
if cbs[type]:
|
||||
drop (cbs[type])
|
||||
cbs[type] = cb
|
||||
|
||||
enum battery_type:
|
||||
BATTERY_ABSENT
|
||||
BATTERY_CHARGING
|
||||
BATTERY_CHARGED
|
||||
static void set_cb (event_type type):
|
||||
capability_clone (11 + type, 6)
|
||||
|
||||
class Keyboard:
|
||||
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
|
||||
unsigned keys[GPIO_KBD_NUM_COLS]
|
||||
bool scanning
|
||||
void parse (unsigned col, unsigned data):
|
||||
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
|
||||
if (data ^ keys[col]) & (1 << row):
|
||||
unsigned code = (col << 3) | row
|
||||
unsigned code = encode[col][row]
|
||||
if data & (1 << row):
|
||||
code |= KEYBOARD_RELEASE
|
||||
event (KEYBOARD_EVENT, code)
|
||||
@ -115,32 +93,38 @@ class Keyboard:
|
||||
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
|
||||
// Set scanning to false before first parse.
|
||||
scanning = false
|
||||
// Clear all pins. This is only required once, because it's done at the end of the loop as well.
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
|
||||
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
|
||||
// clear pin
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
|
||||
// output
|
||||
// Set pin to output.
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
|
||||
for unsigned i = 0; i < 100000; ++i:
|
||||
// Delay for stabalization.
|
||||
for unsigned i = 0; i < 100; ++i:
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
|
||||
// Read the result.
|
||||
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
|
||||
// Generate events.
|
||||
parse (col, data)
|
||||
// set pin
|
||||
// Set pin to get rid of capacitance effects.
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
|
||||
// input
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir
|
||||
// Delay to make the above trick work.
|
||||
for unsigned i = 0; i < 100; ++i:
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
|
||||
// Pin is set to input at the start of the loop.
|
||||
// set all to 0.
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
|
||||
// set all to output.
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
|
||||
// Set interrupts on change.
|
||||
// Delay for stabalization.
|
||||
for unsigned i = 0; i < 100; ++i:
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
|
||||
// Set interrupts.
|
||||
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
if data & (1 << i):
|
||||
gpio_irq_fall (GPIO_KBD_ROW_PORT, i)
|
||||
gpio_irq_low (GPIO_KBD_ROW_PORT, i)
|
||||
else:
|
||||
gpio_irq_rise (GPIO_KBD_ROW_PORT, i)
|
||||
// Clear pending interrupts.
|
||||
GPIO_GPFR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
|
||||
gpio_irq_high (GPIO_KBD_ROW_PORT, i)
|
||||
// Reenable interrupts.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
|
||||
Keyboard ():
|
||||
@ -151,11 +135,43 @@ class Keyboard:
|
||||
// Set all rows to input and enable the pull-ups.
|
||||
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
|
||||
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
|
||||
// Initialize matrix.
|
||||
for unsigned i = 0; i < GPIO_KBD_NUM_COLS; ++i:
|
||||
keys[i] = 0xff
|
||||
// Perform initial scan to get real values into matrix and set up the rest.
|
||||
// Initialize things in the same way as when a new callback is set up.
|
||||
send_initial ()
|
||||
void send_initial ():
|
||||
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
|
||||
keys[col] = 0xff
|
||||
scan ()
|
||||
event (KEYBOARD_EVENT, ~0)
|
||||
|
||||
enum Keys:
|
||||
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10
|
||||
SPACE, TAB, ENTER, LBRACE, RBRACE, COMMA, PERIOD, MINUS, EQUAL, SLASH, BACKSLASH, SEMICOLON, EXTRA, BACKQUOTE, QUOTE
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
|
||||
LSHIFT, RSHIFT, CTRL, ALT
|
||||
CAPS, NUM
|
||||
NONE = ~0 & ~KEYBOARD_RELEASE
|
||||
|
||||
unsigned const Keyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
|
||||
{ PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
|
||||
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
|
||||
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
|
||||
{ E, F3, D, F4, C, NONE, NONE, N3 },
|
||||
{ R, T, F, G, V, B, N5, N4 },
|
||||
{ U, Y, J, H, M, N, N6, N7 },
|
||||
{ I, RBRACE, K, F6, COMMA, NONE, EQUAL, N8 },
|
||||
{ O, F7, L, NONE, PERIOD, MENU, F8, N9 },
|
||||
{ NONE, NONE, NONE, SPACE, NUM, NONE, DELETE, NONE },
|
||||
{ NONE, BACKSPACE, NONE, NONE, ENTER, NONE, F9, NONE },
|
||||
{ NONE, NONE, NONE, ALT, NONE, NONE, NONE, SYSRQ },
|
||||
{ P, LBRACE, SEMICOLON, QUOTE, BACKSLASH, SLASH, MINUS, N0 },
|
||||
{ NONE, ZZZ, NONE, NONE, NONE, NONE, NONE, F10 },
|
||||
{ NONE, NONE, NONE, NONE, NONE, NONE, F2, NONE },
|
||||
{ NONE, NONE, NONE, NONE, NONE, NONE, INSERT, NONE },
|
||||
{ NONE, NONE, UP, DOWN, LEFT, RIGHT, NONE, NONE },
|
||||
{ NONE, LSHIFT, RSHIFT, NONE, NONE, NONE, F1, FN }}
|
||||
|
||||
class Touchpad:
|
||||
unsigned old_state
|
||||
@ -163,33 +179,35 @@ class Touchpad:
|
||||
void check_events ():
|
||||
unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
|
||||
if state & (1 << GPIO_TP_LEFT):
|
||||
gpio_irq_fall (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
gpio_irq_low (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
|
||||
event (TOUCHPAD_EVENT, 0)
|
||||
else:
|
||||
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
gpio_irq_high (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
|
||||
event (TOUCHPAD_EVENT, 0x10000)
|
||||
if state & (1 << GPIO_TP_RIGHT):
|
||||
gpio_irq_fall (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
gpio_irq_low (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
|
||||
event (TOUCHPAD_EVENT, 1)
|
||||
else:
|
||||
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
gpio_irq_high (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
|
||||
event (TOUCHPAD_EVENT, 0x10001)
|
||||
old_state = state
|
||||
// Ack interrupts.
|
||||
GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
|
||||
//GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
|
||||
Touchpad ():
|
||||
// Set pins to input with pull-ups.
|
||||
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
|
||||
// See if they are already pressed. Also set up interrupts. This is done like when a new callback is registered.
|
||||
send_initial ()
|
||||
void send_initial ():
|
||||
old_state = 0
|
||||
// See if they are already pressed. Also set up interrupts.
|
||||
check_events ()
|
||||
// Now enable the interrupts.
|
||||
event (TOUCHPAD_EVENT, ~0)
|
||||
|
||||
class Lockleds:
|
||||
// Note that num lock is in port 2. The others are in port 0.
|
||||
@ -215,58 +233,6 @@ class Lockleds:
|
||||
else:
|
||||
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
|
||||
|
||||
class Power:
|
||||
// Power out is in port 2, the rest in port 3.
|
||||
unsigned old_state
|
||||
bool was_present
|
||||
public:
|
||||
void poll ():
|
||||
#if 0
|
||||
// Switch off keyboard interrupts, because this may interfere with them.
|
||||
GPIO_GPIER (0) &= ~0xff
|
||||
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
|
||||
GPIO_GPPUR (3) &= ~(PWR_IN | BATTERY)
|
||||
//udelay (100)
|
||||
unsigned state = GPIO_GPDR (3)
|
||||
if (state ^ old_state) & PWR_IN:
|
||||
event (POWERBUTTON_EVENT, state & PWR_IN ? 0 : 0x10000)
|
||||
if (state ^ old_state) & BATTERY:
|
||||
if !(state & BATTERY):
|
||||
GPIO_GPPUR (3) |= BATTERY
|
||||
//udelay (100)
|
||||
if GPIO_GPDR (3) & BATTERY:
|
||||
if !was_present:
|
||||
event (BATTERY_EVENT, BATTERY_CHARGED)
|
||||
was_present = true
|
||||
else:
|
||||
if was_present:
|
||||
event (BATTERY_EVENT, BATTERY_ABSENT)
|
||||
was_present = false
|
||||
else:
|
||||
event (BATTERY_EVENT, BATTERY_CHARGING)
|
||||
old_state = state
|
||||
GPIO_GPPUR (3) &= ~BATTERY
|
||||
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
|
||||
//udelay (100)
|
||||
GPIO_GPIER (3) |= 0xff
|
||||
#endif
|
||||
Power ():
|
||||
was_present = true
|
||||
//old_state = BATTERY
|
||||
poll ()
|
||||
void poweroff ():
|
||||
// TODO: doesn't work.
|
||||
i2c_open ()
|
||||
i2c_write_page (I2C_DEV_MCU, I2C_MCU_SHUTDOWN, "\1", 1)
|
||||
i2c_close ()
|
||||
while true:
|
||||
// Do nothing; wait until the device stops running.
|
||||
void reboot ():
|
||||
wdt_set_count (0xffffffff - 32)
|
||||
wdt_start ()
|
||||
while true:
|
||||
// Do nothing; wait until the device reboots.
|
||||
|
||||
// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
|
||||
class Pwm:
|
||||
public:
|
||||
@ -288,43 +254,39 @@ class Pwm:
|
||||
int main ():
|
||||
map_gpio ()
|
||||
map_pwm0 ()
|
||||
map_wdt ()
|
||||
map_i2c ()
|
||||
|
||||
Keyboard kbd
|
||||
Touchpad tp
|
||||
Lockleds leds
|
||||
Power power
|
||||
Pwm pwm
|
||||
|
||||
// Enable interrupts. All are in port 0.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
|
||||
register_interrupt (IRQ_GPIO0)
|
||||
|
||||
Capability cap_kbd = receiver_create_capability (__my_receiver, CAP_KEYBOARD)
|
||||
Capability cap_tp = receiver_create_capability (__my_receiver, CAP_TOUCHPAD)
|
||||
Capability cap_poweroff = receiver_create_capability (__my_receiver, CAP_POWEROFF)
|
||||
Capability cap_powerbutton = receiver_create_capability (__my_receiver, CAP_POWERBUTTON)
|
||||
Capability cap_battery = receiver_create_capability (__my_receiver, CAP_BATTERY)
|
||||
Capability cap_lockleds = receiver_create_capability (__my_receiver, CAP_LOCKLEDS)
|
||||
Capability cap_pwm = receiver_create_capability (__my_receiver, CAP_PWM)
|
||||
Capability cap_kbd = 7
|
||||
Capability cap_tp = 8
|
||||
Capability cap_lockleds = 9
|
||||
Capability cap_pwm = 10
|
||||
receiver_create_capability (cap_kbd, __my_receiver, CAP_KEYBOARD)
|
||||
receiver_create_capability (cap_tp, __my_receiver, CAP_TOUCHPAD)
|
||||
receiver_create_capability (cap_lockleds, __my_receiver, CAP_LOCKLEDS)
|
||||
receiver_create_capability (cap_pwm, __my_receiver, CAP_PWM)
|
||||
|
||||
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_poweroff), cap_copy (cap_powerbutton), INIT_SET_GPIO_0)
|
||||
invoke_31 (__my_parent, cap_copy (cap_battery), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO_1)
|
||||
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO)
|
||||
|
||||
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
|
||||
if kbd.is_scanning ():
|
||||
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
|
||||
while true:
|
||||
schedule ()
|
||||
Message msg
|
||||
wait (&msg)
|
||||
wait (&msg, 6, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
|
||||
switch msg.protected_data:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
// Periodically scan several devices.
|
||||
kbd.scan ()
|
||||
if kbd.is_scanning ():
|
||||
kbd.scan ()
|
||||
power.poll ()
|
||||
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
|
||||
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
|
||||
break
|
||||
case IRQ_GPIO0:
|
||||
// Always scan keyboard and touchpad on any interrupt.
|
||||
@ -334,22 +296,12 @@ int main ():
|
||||
register_interrupt (IRQ_GPIO0)
|
||||
break
|
||||
case CAP_KEYBOARD:
|
||||
set_cb (KEYBOARD_EVENT, msg.cap[0])
|
||||
set_cb (KEYBOARD_EVENT)
|
||||
kbd.send_initial ()
|
||||
break
|
||||
case CAP_TOUCHPAD:
|
||||
set_cb (TOUCHPAD_EVENT, msg.cap[0])
|
||||
break
|
||||
case CAP_POWEROFF:
|
||||
if msg.data[0]:
|
||||
power.poweroff ()
|
||||
else:
|
||||
power.reboot ()
|
||||
break
|
||||
case CAP_POWERBUTTON:
|
||||
set_cb (POWERBUTTON_EVENT, msg.cap[0])
|
||||
break
|
||||
case CAP_BATTERY:
|
||||
set_cb (BATTERY_EVENT, msg.cap[0])
|
||||
set_cb (TOUCHPAD_EVENT)
|
||||
tp.send_initial ()
|
||||
break
|
||||
case CAP_LOCKLEDS:
|
||||
leds.set (msg.data[0])
|
||||
|
@ -19,53 +19,46 @@
|
||||
#include "devices.hh"
|
||||
#include "iris.h"
|
||||
|
||||
static Capability kbd, tp, poweroff, powerbutton, battery, lockleds, pwm, lcd
|
||||
static Capability kbd, tp, lockleds, pwm, lcd
|
||||
|
||||
enum type:
|
||||
KBD = 0x10000
|
||||
TP
|
||||
POWERBUTTON
|
||||
BATTERY
|
||||
|
||||
static void send (Capability c, unsigned d):
|
||||
Capability n = receiver_create_capability (__my_receiver, d)
|
||||
invoke_10 (c, cap_copy (n))
|
||||
drop (n)
|
||||
receiver_create_capability (6, __my_receiver, d)
|
||||
invoke_10 (c, cap_copy (6))
|
||||
|
||||
static void setup ():
|
||||
unsigned state = 0
|
||||
Capability base = 7
|
||||
while true:
|
||||
Message msg
|
||||
wait (&msg)
|
||||
wait (&msg, base, base + 1, base + 2, base + 3)
|
||||
switch msg.data[0]:
|
||||
case INIT_SET_GPIO_0:
|
||||
kdebug ("gpio 0\n")
|
||||
kbd = msg.cap[0]
|
||||
tp = msg.cap[1]
|
||||
poweroff = msg.cap[2]
|
||||
powerbutton = msg.cap[3]
|
||||
++state
|
||||
break
|
||||
case INIT_SET_GPIO_1:
|
||||
kdebug ("gpio 1\n")
|
||||
battery = msg.cap[0]
|
||||
lockleds = msg.cap[1]
|
||||
pwm = msg.cap[2]
|
||||
case INIT_SET_GPIO:
|
||||
kdebug ("gpio\n")
|
||||
kbd = base
|
||||
tp = base + 1
|
||||
lockleds = base + 2
|
||||
pwm = base + 3
|
||||
base += 4
|
||||
++state
|
||||
break
|
||||
case INIT_SET_LCD:
|
||||
kdebug ("lcd\n")
|
||||
lcd = msg.cap[0]
|
||||
lcd = base
|
||||
++base
|
||||
++state
|
||||
break
|
||||
if state == 3:
|
||||
if state == 2:
|
||||
break
|
||||
send (kbd, KBD)
|
||||
send (tp, TP)
|
||||
send (powerbutton, POWERBUTTON)
|
||||
send (battery, BATTERY)
|
||||
invoke_01 (pwm, 1)
|
||||
|
||||
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
|
||||
|
||||
int main ():
|
||||
// Set up lcd first
|
||||
schedule ()
|
||||
@ -74,12 +67,13 @@ int main ():
|
||||
kdebug ("run init\n")
|
||||
while true:
|
||||
Message msg
|
||||
wait (&msg)
|
||||
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
|
||||
switch msg.protected_data:
|
||||
case KBD:
|
||||
kdebug ("keyboard event: ")
|
||||
kdebug_num (msg.data[0])
|
||||
kdebug_char ('\n')
|
||||
unsigned code = msg.data[0]
|
||||
if code & KEYBOARD_RELEASE:
|
||||
break
|
||||
kdebug_char (decode_kbd[code])
|
||||
break
|
||||
case TP:
|
||||
unsigned leds = 0
|
||||
@ -91,9 +85,3 @@ int main ():
|
||||
leds |= 0x2
|
||||
invoke_01 (lockleds, leds)
|
||||
break
|
||||
case POWERBUTTON:
|
||||
kdebug ("powerbutton event\n")
|
||||
break
|
||||
case BATTERY:
|
||||
kdebug ("battery event\n")
|
||||
break
|
||||
|
@ -121,30 +121,23 @@ static void log_msg (Message *msg):
|
||||
log_char ('\n')
|
||||
|
||||
int main ():
|
||||
__asm__ volatile ("break")
|
||||
|
||||
map_lcd ()
|
||||
map_cpm ()
|
||||
|
||||
Descriptor descriptor __attribute__ ((aligned (16)))
|
||||
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
|
||||
assert (pages > CAPPAGE_SIZE && pages <= 2 * CAPPAGE_SIZE)
|
||||
unsigned physical = alloc_range (__my_memory, pages)
|
||||
assert (physical)
|
||||
//Capability cappage[2]
|
||||
//unsigned base[2]
|
||||
//cappage[0] = memory_create_cappage (__my_memory, &base[0])
|
||||
//cappage[1] = memory_create_cappage (__my_memory, &base[1])
|
||||
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
|
||||
Capability page = memory_create_page (__my_memory)
|
||||
//cappage_set (cappage[0], page, i)
|
||||
alloc_physical (page, physical + i * PAGE_SIZE, 0, 1)
|
||||
memory_map (__my_memory, page, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1)
|
||||
drop (page)
|
||||
for unsigned i = 0; i < pages - CAPPAGE_SIZE; ++i:
|
||||
Capability page = memory_create_page (__my_memory)
|
||||
//cappage_set (cappage[1], page, i)
|
||||
alloc_physical (page, physical + (i + CAPPAGE_SIZE) * PAGE_SIZE, 0, 1)
|
||||
memory_map (__my_memory, page, (unsigned)LCD_FRAMEBUFFER_BASE + (i + CAPPAGE_SIZE) * PAGE_SIZE, 1)
|
||||
drop (page)
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
memory_create_page (6, __my_memory)
|
||||
alloc_physical (6, physical + i * PAGE_SIZE, 0, 1)
|
||||
memory_map (__my_memory, 6, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1)
|
||||
for unsigned y = 0; y < 480; ++y:
|
||||
unsigned g = (y << 6) / 480
|
||||
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
||||
@ -161,8 +154,8 @@ int main ():
|
||||
ob = b
|
||||
b = 0x1f
|
||||
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
|
||||
Capability page = memory_mapping (__my_memory, &descriptor)
|
||||
unsigned physical_descriptor = page_physical_address (page) + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
memory_mapping (6, __my_memory, &descriptor)
|
||||
unsigned physical_descriptor = page_physical_address (cap_copy (6)) + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
descriptor.next = physical_descriptor
|
||||
descriptor.frame = physical
|
||||
descriptor.id = 0xdeadbeef
|
||||
@ -173,16 +166,15 @@ int main ():
|
||||
|
||||
Capability eof_cb = 0
|
||||
|
||||
Capability cap = receiver_create_capability (__my_receiver, LCD_EOF_CB)
|
||||
invoke_11 (__my_parent, cap, INIT_SET_LCD)
|
||||
drop (cap)
|
||||
receiver_create_capability (6, __my_receiver, LCD_EOF_CB)
|
||||
invoke_11 (__my_parent, cap_copy (6), INIT_SET_LCD)
|
||||
|
||||
Capability logcap = receiver_create_capability (__my_receiver, LCD_LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap) : "a0", "a1", "memory")
|
||||
receiver_create_capability (15, __my_receiver, LCD_LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, 15\nbreak" ::: "a0", "a1", "memory")
|
||||
|
||||
while true:
|
||||
Message msg
|
||||
wait (&msg)
|
||||
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
|
||||
//log_msg (&msg)
|
||||
switch msg.protected_data:
|
||||
case IRQ_LCD:
|
||||
@ -192,8 +184,6 @@ int main ():
|
||||
invoke_00 (eof_cb)
|
||||
break
|
||||
case LCD_EOF_CB:
|
||||
if eof_cb:
|
||||
drop (eof_cb)
|
||||
eof_cb = msg.cap[0]
|
||||
if eof_cb:
|
||||
register_interrupt (IRQ_LCD)
|
||||
|
633
invoke.ccp
633
invoke.ccp
@ -19,6 +19,7 @@
|
||||
#include "kernel.hh"
|
||||
|
||||
void Thread::raise (unsigned code, unsigned data):
|
||||
panic (code, "raise")
|
||||
dbg_log ("raise ")
|
||||
dbg_log_num ((unsigned)current)
|
||||
dbg_log_char ('/')
|
||||
@ -31,47 +32,32 @@ void Thread::raise (unsigned code, unsigned data):
|
||||
dbg_log_num (data)
|
||||
dbg_log_char ('\n')
|
||||
unrun ()
|
||||
if !exception.target:
|
||||
if !caps[0] || !caps[0]->caps[0].target:
|
||||
return
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.cap[i] = NULL
|
||||
c.cap[i] = CapRef ()
|
||||
c.copy[i] = false
|
||||
c.data[0] = code
|
||||
c.data[1] = data
|
||||
c.data[2] = 0
|
||||
c.data[3] = 0
|
||||
exception.invoke (&c)
|
||||
caps[0]->caps[0].invoke (&c)
|
||||
|
||||
// From user-provided, thus untrusted, data, find a capability.
|
||||
Capability *Memory::find_capability (unsigned code, bool *copy):
|
||||
*copy = code & 2 ? true : false
|
||||
if !(code & ~3):
|
||||
return NULL
|
||||
if code & 1:
|
||||
// Cappage capability
|
||||
unsigned num = (code & ~PAGE_MASK) >> 2
|
||||
if num >= CAPPAGE_SIZE:
|
||||
CapRef Thread::find_capability (unsigned code, bool *copy):
|
||||
*copy = code & CAPABILITY_COPY
|
||||
unsigned c = code & ~CAPABILITY_COPY
|
||||
unsigned slot = c >> 16
|
||||
unsigned num = c & 0xffff
|
||||
if slot >= slots || !caps[slot] || num >= caps[slot]->size || !caps[slot]->caps[num].target:
|
||||
if c != CAPABILITY_NONE:
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
dbg_log (": invalid cappage index ")
|
||||
dbg_log_num (num)
|
||||
dbg_log (": invalid capability ")
|
||||
dbg_log_num (code)
|
||||
dbg_log_char ('\n')
|
||||
return NULL
|
||||
unsigned page = code & PAGE_MASK
|
||||
for Cappage *p = cappages; p; p = p->next:
|
||||
if p->data.frame == page:
|
||||
return p->cap (num)
|
||||
else:
|
||||
// Normal capability
|
||||
Capability *target = (Capability *)(code & ~3)
|
||||
for Capability *c = capabilities; c; c = c->next:
|
||||
if c == target:
|
||||
return c
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
dbg_log (": invalid capability ")
|
||||
dbg_log_num (code)
|
||||
dbg_log_char ('\n')
|
||||
return NULL
|
||||
return CapRef ()
|
||||
return CapRef (caps[slot], num)
|
||||
|
||||
// Try to deliver a message.
|
||||
bool Receiver::try_deliver ():
|
||||
@ -81,148 +67,125 @@ bool Receiver::try_deliver ():
|
||||
return false
|
||||
Message *m = last_message
|
||||
if protected_only:
|
||||
for ; m; m = m->prev:
|
||||
for ; m; m = (Message *)m->prev:
|
||||
if m->protected_data == reply_protected_data:
|
||||
protected_only = false
|
||||
break
|
||||
if !m:
|
||||
return false
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.data[i] = m->data[i]
|
||||
if m->capabilities[i]:
|
||||
c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true)
|
||||
if !c.cap[i]:
|
||||
owner->raise (ERR_OUT_OF_MEMORY, 0)
|
||||
for unsigned j = 0; j < i; ++j:
|
||||
owner->address_space->free_capability (c.cap[i])
|
||||
return false
|
||||
else:
|
||||
c.cap[i] = NULL
|
||||
Thread_arch_receive (owner, m->protected_data, &c)
|
||||
if owner->rcaps[i]:
|
||||
owner->rcaps[i]->invalidate ()
|
||||
if m->capabilities[i] < caps->size:
|
||||
owner->rcaps[i].clone (CapRef (caps, m->capabilities[i]), true)
|
||||
Thread_arch_receive (owner, m->protected_data, m->data)
|
||||
address_space->free_message (this, m)
|
||||
owner->unwait ()
|
||||
return true
|
||||
|
||||
// Send a message to a receiver; try to deliver it immediately.
|
||||
bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
|
||||
bool tried_direct = false
|
||||
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
|
||||
Capability *orig[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
if c->cap[i]:
|
||||
orig[i] = c->cap[i]
|
||||
c->cap[i] = owner->address_space->clone_capability (orig[i], c->copy[i])
|
||||
if !c->cap[i]:
|
||||
owner->raise (ERR_OUT_OF_MEMORY, 0)
|
||||
for unsigned j = 0; j < i; ++j:
|
||||
owner->address_space->free_capability (c->cap[j])
|
||||
c->cap[j] = orig[j]
|
||||
c->cap[i] = orig[i]
|
||||
return false
|
||||
if protected_data == reply_protected_data:
|
||||
if protected_only:
|
||||
protected_only = false
|
||||
Thread_arch_receive (owner, protected_data, c)
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
if owner->rcaps[i]:
|
||||
owner->rcaps[i]->invalidate ()
|
||||
if c->cap[i]:
|
||||
owner->rcaps[i].clone (c->cap[i], c->copy[i])
|
||||
Thread_arch_receive (owner, protected_data, c->data)
|
||||
owner->unwait ()
|
||||
return true
|
||||
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
|
||||
Message *msg = address_space->alloc_message (this)
|
||||
if !msg:
|
||||
if owner:
|
||||
// TODO: avoid loops.
|
||||
owner->raise (ERR_OUT_OF_MEMORY, 0)
|
||||
return false
|
||||
msg->protected_data = protected_data
|
||||
if protected_data == reply_protected_data:
|
||||
if protected_only && protected_data == reply_protected_data:
|
||||
// Put this message in the end (where it will be first seen). Clear the protected_only flag.
|
||||
protected_only = false
|
||||
if msg->next:
|
||||
msg->next->prev = NULL
|
||||
messages = msg->next
|
||||
((Message *)msg->next)->prev = NULL
|
||||
messages = (Message *)msg->next
|
||||
msg->next = NULL
|
||||
msg->prev = last_message
|
||||
msg->prev->next = msg
|
||||
((Message *)msg->prev)->next = msg
|
||||
last_message = msg
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
msg->data[i] = c->data[i]
|
||||
if !c->cap[i]:
|
||||
msg->capabilities[i] = NULL
|
||||
if !c->cap[i] || !caps:
|
||||
msg->capabilities[i] = 0xff
|
||||
else:
|
||||
msg->capabilities[i] = address_space->clone_capability (c->cap[i], c->copy[i])
|
||||
if !msg->capabilities[i]:
|
||||
unsigned t
|
||||
random = (random + 1) % caps->size
|
||||
for t = (random + 1) % caps->size; t != random; t = (t + 1) % caps->size:
|
||||
if caps->caps[t].target:
|
||||
continue
|
||||
if t == random:
|
||||
if owner:
|
||||
// TODO: avoid loops.
|
||||
owner->raise (ERR_OUT_OF_MEMORY, 0)
|
||||
for unsigned j = 0; j < i; ++j:
|
||||
address_space->free_capability (msg->capabilities[j])
|
||||
if msg->capabilities[j] != 0xff:
|
||||
caps->caps[msg->capabilities[j]].invalidate ()
|
||||
address_space->free_message (this, msg)
|
||||
return false
|
||||
msg->capabilities[i] = t
|
||||
caps->clone (t, c->cap[i], c->copy[i])
|
||||
return true
|
||||
|
||||
static Capability *reply
|
||||
static Receiver *reply_receiver
|
||||
|
||||
static void fill_cap (Capability *r, unsigned target, unsigned protected_data):
|
||||
Capability **ref
|
||||
static void fill_cap (CapRef r, unsigned target, unsigned protected_data):
|
||||
CapRef *ref
|
||||
if target & ~KERNEL_MASK:
|
||||
ref = &((Receiver *)target)->capabilities
|
||||
else:
|
||||
ref = &((Object_base *)protected_data)->refs
|
||||
// alloc_capability needs a Memory, but it isn't used if return storage is given.
|
||||
top_memory.alloc_capability ((Receiver *)target, NULL, ref, protected_data, r)
|
||||
ref = &((Object *)protected_data)->refs
|
||||
r.set ((Receiver *)target, protected_data, CapRef (), ref)
|
||||
|
||||
static void reply_cap (unsigned target, unsigned protected_data):
|
||||
Capability r
|
||||
fill_cap (&r, target, protected_data)
|
||||
Caps r
|
||||
fill_cap (CapRef (&r, 0), target, protected_data)
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.data[i] = 0
|
||||
c.cap[0] = &r
|
||||
c.cap[0] = CapRef (&r, 0)
|
||||
c.copy[0] = true
|
||||
for unsigned i = 1; i < 4; ++i:
|
||||
c.cap[i] = NULL
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
if reply:
|
||||
reply->invoke (&c)
|
||||
else if reply_receiver:
|
||||
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
|
||||
r.invalidate ()
|
||||
r.caps[0].invalidate ()
|
||||
|
||||
static void reply_cap (Capability *cap, bool copy):
|
||||
static void reply_cap (CapRef cap, bool copy):
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.data[i] = 0
|
||||
c.cap[0] = cap
|
||||
c.copy[0] = copy
|
||||
for unsigned i = 1; i < 4; ++i:
|
||||
c.cap[i] = NULL
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
if reply:
|
||||
reply->invoke (&c)
|
||||
else if reply_receiver:
|
||||
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
|
||||
|
||||
static void reply_cappage (Cappage *cap, unsigned target):
|
||||
Capability r
|
||||
fill_cap (&r, target, (unsigned)cap)
|
||||
Capability::Context c
|
||||
for unsigned i = 1; i < 4; ++i:
|
||||
c.data[i] = 0
|
||||
c.cap[i] = NULL
|
||||
c.copy[i] = false
|
||||
c.data[0] = cap->data.frame
|
||||
c.cap[0] = &r
|
||||
c.copy[0] = true
|
||||
if reply:
|
||||
reply->invoke (&c)
|
||||
else if reply_receiver:
|
||||
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
|
||||
|
||||
static void reply_num (unsigned num):
|
||||
Capability::Context c
|
||||
c.data[0] = num
|
||||
for unsigned i = 1; i < 4; ++i:
|
||||
c.data[i] = 0
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.cap[i] = NULL
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
if reply:
|
||||
reply->invoke (&c)
|
||||
@ -236,7 +199,7 @@ static void reply_nums (unsigned num1, unsigned num2):
|
||||
c.data[2] = 0
|
||||
c.data[3] = 0
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.cap[i] = NULL
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
if reply:
|
||||
reply->invoke (&c)
|
||||
@ -313,7 +276,7 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
reply_num (0)
|
||||
break
|
||||
case CAPTYPE_THREAD:
|
||||
Thread *ret = mem->alloc_thread ()
|
||||
Thread *ret = mem->alloc_thread (c->data[2])
|
||||
if ret:
|
||||
reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret)
|
||||
else:
|
||||
@ -326,10 +289,10 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
else:
|
||||
reply_num (0)
|
||||
break
|
||||
case CAPTYPE_CAPPAGE:
|
||||
Cappage *ret = mem->alloc_cappage ()
|
||||
case CAPTYPE_CAPS:
|
||||
Caps *ret = mem->alloc_caps (c->data[2])
|
||||
if ret:
|
||||
reply_cappage (ret, CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS))
|
||||
reply_cap (CAPTYPE_CAPS | (rights & CAP_CAPS_ALL_RIGHTS), (unsigned)ret)
|
||||
else:
|
||||
reply_num (0)
|
||||
break
|
||||
@ -352,11 +315,8 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
case CAPTYPE_PAGE:
|
||||
mem->free_page ((Page *)c->cap[0]->protected_data)
|
||||
break
|
||||
case CAPTYPE_CAPABILITY:
|
||||
mem->free_capability ((Capability *)c->cap[0]->protected_data)
|
||||
break
|
||||
case CAPTYPE_CAPPAGE:
|
||||
mem->free_cappage ((Cappage *)c->cap[0]->protected_data)
|
||||
case CAPTYPE_CAPS:
|
||||
mem->free_caps ((Caps *)c->cap[0]->protected_data)
|
||||
break
|
||||
default:
|
||||
panic (0x55228930, "invalid case")
|
||||
@ -388,11 +348,6 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
if c->data[2]:
|
||||
mem->limit = c->data[1]
|
||||
break
|
||||
case CAP_MEMORY_DROP:
|
||||
if !c->cap[0] || c->cap[0]->address_space != mem:
|
||||
break
|
||||
mem->free_capability (c->cap[0])
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
@ -416,7 +371,7 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
unsigned v = (*value & c->data[3]) | (c->data[2] & c->data[3])
|
||||
if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING):
|
||||
if v & THREAD_FLAG_WAITING:
|
||||
thread->wait ()
|
||||
thread->wait (CapRef (), CapRef (), CapRef (), CapRef ())
|
||||
else
|
||||
thread->unwait ()
|
||||
if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING):
|
||||
@ -437,281 +392,186 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
case CAP_THREAD_SCHEDULE:
|
||||
do_schedule = true
|
||||
break
|
||||
case CAP_THREAD_REGISTER_INTERRUPT:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
arch_register_interrupt (c->data[1], c->cap[0] ? (Receiver *)c->cap[0]->protected_data : NULL)
|
||||
break
|
||||
case CAP_THREAD_GET_TOP_MEMORY:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
reply_cap (CAPTYPE_MEMORY | (c->data[1] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory)
|
||||
break
|
||||
case CAP_THREAD_MAKE_PRIV:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
if c->data[1] & THREAD_FLAG_PRIV:
|
||||
((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV
|
||||
reply_cap (CAPTYPE_THREAD | (c->data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data)
|
||||
break
|
||||
case CAP_THREAD_ALLOC_RANGE:
|
||||
// Threads with access to this call are trusted, so not much sanity checking is done.
|
||||
Memory *mem = (Memory *)c->cap[1]->protected_data
|
||||
if !mem->use (c->data[1]):
|
||||
reply_num (0)
|
||||
break
|
||||
unsigned data = phys_alloc (c->data[1])
|
||||
if !data:
|
||||
mem->unuse (c->data[1])
|
||||
reply_num (0)
|
||||
break
|
||||
reply_num (data - 0x80000000)
|
||||
break
|
||||
case CAP_THREAD_ALLOC_PHYSICAL:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
Page *page = (Page *)c->cap[0]->protected_data
|
||||
page->forget ()
|
||||
if !(c->data[2] & 2):
|
||||
if page->data.flags & PAGE_FLAG_PAYING:
|
||||
page->data.flags &= ~PAGE_FLAG_PAYING
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
// This is for mapping allocated ranges. They are already paid for. Record that.
|
||||
if page->data.flags & PAGE_FLAG_PAYING:
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
page->data.flags |= PAGE_FLAG_PAYING
|
||||
page->data.frame = c->data[1]
|
||||
page->data.flags |= PAGE_FLAG_FRAME
|
||||
if !(c->data[2] & 1):
|
||||
page->data.flags |= PAGE_FLAG_UNCACHED
|
||||
if !(c->data[2] & 2):
|
||||
page->data.flags |= PAGE_FLAG_PHYSICAL
|
||||
Page_arch_update_mapping (page)
|
||||
break
|
||||
case CAP_THREAD_PHYSICAL_ADDRESS:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
Page *page = (Page *)c->cap[1]->protected_data
|
||||
reply_num (page->data.frame & ~0xc0000000)
|
||||
case CAP_THREAD_CAP_CLONE:
|
||||
reply_cap (c->cap[0], c->copy[0])
|
||||
break
|
||||
case CAP_THREAD_PRIV:
|
||||
switch c->data[1]:
|
||||
case CAP_THREAD_PRIV_REGISTER_INTERRUPT:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
arch_register_interrupt (c->data[2], c->cap[0] ? (Receiver *)c->cap[0]->protected_data : NULL)
|
||||
break
|
||||
case CAP_THREAD_PRIV_GET_TOP_MEMORY:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
reply_cap (CAPTYPE_MEMORY | (c->data[2] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory)
|
||||
break
|
||||
case CAP_THREAD_PRIV_MAKE_PRIV:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
if c->data[2] & THREAD_FLAG_PRIV:
|
||||
((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV
|
||||
reply_cap (CAPTYPE_THREAD | (c->data[2] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data)
|
||||
break
|
||||
case CAP_THREAD_PRIV_ALLOC_RANGE:
|
||||
// Threads with access to this call are trusted, so not much sanity checking is done.
|
||||
Memory *mem = (Memory *)c->cap[1]->protected_data
|
||||
if !mem->use (c->data[2]):
|
||||
reply_num (0)
|
||||
break
|
||||
unsigned data = phys_alloc (c->data[2])
|
||||
if !data:
|
||||
mem->unuse (c->data[2])
|
||||
reply_num (0)
|
||||
break
|
||||
reply_num (data - 0x80000000)
|
||||
break
|
||||
case CAP_THREAD_PRIV_ALLOC_PHYSICAL:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
Page *page = (Page *)c->cap[0]->protected_data
|
||||
page->forget ()
|
||||
if !(c->data[3] & 2):
|
||||
if page->flags & PAGE_FLAG_PAYING:
|
||||
page->flags &= ~PAGE_FLAG_PAYING
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
// This is for mapping allocated ranges. They are already paid for. Record that.
|
||||
if page->flags & PAGE_FLAG_PAYING:
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
page->flags |= PAGE_FLAG_PAYING
|
||||
page->frame = c->data[2]
|
||||
page->flags |= PAGE_FLAG_FRAME
|
||||
if !(c->data[3] & 1):
|
||||
page->flags |= PAGE_FLAG_UNCACHED
|
||||
if !(c->data[3] & 2):
|
||||
page->flags |= PAGE_FLAG_PHYSICAL
|
||||
Page_arch_update_mapping (page)
|
||||
break
|
||||
case CAP_THREAD_PRIV_PHYSICAL_ADDRESS:
|
||||
// Threads with access to this call are trusted, so no sanity checking is done.
|
||||
Page *page = (Page *)c->cap[1]->protected_data
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
break
|
||||
default:
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
static bool page_check_payment (Page *page):
|
||||
Page *p
|
||||
for p = (Page *)page->data.share_prev; p; p = (Page *)p->data.share_prev:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
for p = page->share_prev; p; p = p->share_prev:
|
||||
if p->flags & PAGE_FLAG_PAYING:
|
||||
return true
|
||||
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
for p = page->share_next; p; p = p->share_next:
|
||||
if p->flags & PAGE_FLAG_PAYING:
|
||||
return true
|
||||
// No Page is paying for this frame anymore.
|
||||
raw_pfree (page->data.frame)
|
||||
raw_pfree (page->frame)
|
||||
Page *next
|
||||
for p = (Page *)page->data.share_prev, next = (Page *)p->data.share_prev; p; p = next, next = (Page *)p->data.share_prev:
|
||||
p->data.frame = NULL
|
||||
p->data.share_prev = NULL
|
||||
p->data.share_next = NULL
|
||||
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
|
||||
for p = page->share_prev, next = p->share_prev; p; p = next, next = p->share_prev:
|
||||
p->frame = NULL
|
||||
p->share_prev = NULL
|
||||
p->share_next = NULL
|
||||
p->flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
|
||||
Page_arch_update_mapping (p)
|
||||
for p = page, next = (Page *)p->data.share_next; p; p = next, next = (Page *)p->data.share_next:
|
||||
p->data.frame = NULL
|
||||
p->data.share_prev = NULL
|
||||
p->data.share_next = NULL
|
||||
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
|
||||
for p = page, next = p->share_next; p; p = next, next = p->share_next:
|
||||
p->frame = NULL
|
||||
p->share_prev = NULL
|
||||
p->share_next = NULL
|
||||
p->flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
|
||||
Page_arch_update_mapping (p)
|
||||
return false
|
||||
|
||||
static bool cappage_check_payment (Cappage *cappage):
|
||||
Cappage *p
|
||||
for p = (Cappage *)cappage->data.share_prev; p; p = (Cappage *)p->data.share_prev:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
return true
|
||||
for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
return true
|
||||
// No Page is paying for this frame anymore.
|
||||
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
|
||||
((Capability *)cappage->data.frame)[i].invalidate ()
|
||||
raw_pfree (cappage->data.frame)
|
||||
Cappage *next
|
||||
for p = (Cappage *)cappage->data.share_prev, next = (Cappage *)p->data.share_prev; p; p = next, next = (Cappage *)p->data.share_prev:
|
||||
p->data.frame = NULL
|
||||
p->data.share_prev = NULL
|
||||
p->data.share_next = NULL
|
||||
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
|
||||
for p = cappage, next = (Cappage *)p->data.share_next; p; p = next, next = (Cappage *)p->data.share_next:
|
||||
p->data.frame = NULL
|
||||
p->data.share_prev = NULL
|
||||
p->data.share_next = NULL
|
||||
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
|
||||
return false
|
||||
|
||||
static void page_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
|
||||
Page *page
|
||||
Cappage *cappage
|
||||
ShareData *share_data
|
||||
if (target & CAPTYPE_MASK) == CAPTYPE_PAGE:
|
||||
page = (Page *)protected_data
|
||||
cappage = NULL
|
||||
share_data = &page->data
|
||||
else:
|
||||
page = NULL
|
||||
cappage = (Cappage *)protected_data
|
||||
share_data = &cappage->data
|
||||
Page *page = (Page *)protected_data
|
||||
switch c->data[0]:
|
||||
case CAP_PAGE_SHARE:
|
||||
if !c->cap[0] || ((unsigned)c->cap[0]->target & CAPTYPE_MASK) != (target & CAPTYPE_MASK):
|
||||
if !c->cap[0] || ((unsigned)c->cap[0]->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
// FIXME: This makes it impossible to use a fake Page capability.
|
||||
break
|
||||
if page:
|
||||
Page *t = (Page *)c->cap[0]->protected_data
|
||||
t->forget ()
|
||||
if c->data[1] & PAGE_SHARE_READONLY:
|
||||
t->data.flags &= ~PAGE_FLAG_WRITABLE
|
||||
if !page->data.flags & PAGE_FLAG_FRAME:
|
||||
Page *t = (Page *)c->cap[0]->protected_data
|
||||
t->forget ()
|
||||
if c->data[1] & PAGE_SHARE_READONLY:
|
||||
t->flags &= ~PAGE_FLAG_WRITABLE
|
||||
if !page->flags & PAGE_FLAG_FRAME:
|
||||
break
|
||||
if c->data[1] & PAGE_SHARE_COPY:
|
||||
if ~t->flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if c->data[1] & PAGE_SHARE_COPY:
|
||||
if ~t->data.flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if ~c->data[1] & PAGE_SHARE_FORGET || page->data.flags & PAGE_FLAG_SHARED:
|
||||
unsigned *d = (unsigned *)page->data.frame
|
||||
if t == page:
|
||||
Page *other = page->data.share_next ? (Page *)page->data.share_next : (Page *)page->data.share_prev
|
||||
if !other:
|
||||
Page_arch_update_mapping (t)
|
||||
break
|
||||
if page->data.share_next:
|
||||
((Page *)page->data.share_next)->data.share_prev = page->data.share_prev
|
||||
if page->data.share_prev:
|
||||
((Page *)page->data.share_prev)->data.share_next = page->data.share_next
|
||||
page->data.share_next = NULL
|
||||
page->data.share_prev = NULL
|
||||
page_check_payment (other)
|
||||
else:
|
||||
t->data.flags |= PAGE_FLAG_FRAME
|
||||
t->data.frame = raw_zalloc ()
|
||||
for unsigned i = 0; i <= (c->data[1] & ~PAGE_MASK); i += 4:
|
||||
((unsigned *)t->data.frame)[i >> 2] = d[i >> 2]
|
||||
else:
|
||||
if t != page:
|
||||
t->data.frame = page->data.frame
|
||||
t->data.flags |= PAGE_FLAG_FRAME
|
||||
page->data.frame = NULL
|
||||
page->data.flags &= ~PAGE_FLAG_FRAME
|
||||
Page_arch_update_mapping (page)
|
||||
Page_arch_update_mapping (t)
|
||||
else:
|
||||
if ~c->data[1] & PAGE_SHARE_FORGET || page->flags & PAGE_FLAG_SHARED:
|
||||
unsigned *d = (unsigned *)page->frame
|
||||
if t == page:
|
||||
break
|
||||
if c->data[1] & PAGE_SHARE_FORGET:
|
||||
if ~page->data.flags & PAGE_FLAG_SHARED:
|
||||
if t->data.flags & PAGE_FLAG_PAYING:
|
||||
t->data.frame = page->data.frame
|
||||
t->data.flags |= PAGE_FLAG_FRAME
|
||||
page->data.frame = NULL
|
||||
page->data.flags &= ~PAGE_FLAG_FRAME
|
||||
Page_arch_update_mapping (page)
|
||||
else:
|
||||
t->data.share_prev = page->data.share_prev
|
||||
t->data.share_next = page->data.share_next
|
||||
if t->data.share_prev:
|
||||
((Page *)t->data.share_prev)->data.share_next = t
|
||||
if t->data.share_next:
|
||||
((Page *)t->data.share_next)->data.share_prev = t
|
||||
page->data.share_prev = NULL
|
||||
page->data.share_next = NULL
|
||||
page->forget ()
|
||||
page_check_payment (t)
|
||||
Page *other = page->share_next ? page->share_next : page->share_prev
|
||||
if !other:
|
||||
Page_arch_update_mapping (t)
|
||||
break
|
||||
if page->share_next:
|
||||
page->share_next->share_prev = page->share_prev
|
||||
if page->share_prev:
|
||||
page->share_prev->share_next = page->share_next
|
||||
page->share_next = NULL
|
||||
page->share_prev = NULL
|
||||
page_check_payment (other)
|
||||
else:
|
||||
t->data.share_prev = page->data.share_prev
|
||||
t->data.share_next = page
|
||||
page->data.share_prev = t
|
||||
if t->data.share_prev:
|
||||
((Page *)t->data.share_prev)->data.share_next = t
|
||||
Page_arch_update_mapping (t)
|
||||
else:
|
||||
Cappage *t = (Cappage *)c->cap[0]->protected_data
|
||||
t->forget ()
|
||||
if c->data[1] & PAGE_SHARE_READONLY:
|
||||
t->data.flags &= ~PAGE_FLAG_WRITABLE
|
||||
if !cappage->data.flags & PAGE_FLAG_FRAME:
|
||||
break
|
||||
if c->data[1] & PAGE_SHARE_COPY:
|
||||
if ~t->data.flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if ~c->data[1] & PAGE_SHARE_FORGET || cappage->data.flags & PAGE_FLAG_SHARED:
|
||||
unsigned *d = (unsigned *)cappage->data.frame
|
||||
if t == cappage:
|
||||
Cappage *other = cappage->data.share_next ? (Cappage *)cappage->data.share_next : (Cappage *)cappage->data.share_prev
|
||||
if !other:
|
||||
break
|
||||
if cappage->data.share_next:
|
||||
((Cappage *)cappage->data.share_next)->data.share_prev = cappage->data.share_prev
|
||||
if cappage->data.share_prev:
|
||||
((Cappage *)cappage->data.share_prev)->data.share_next = cappage->data.share_next
|
||||
cappage->data.share_next = NULL
|
||||
cappage->data.share_prev = NULL
|
||||
cappage_check_payment (other)
|
||||
else:
|
||||
t->data.flags |= PAGE_FLAG_FRAME
|
||||
t->data.frame = raw_zalloc ()
|
||||
for unsigned i = 0; i < ((c->data[1] & ~PAGE_MASK) + 1) * sizeof (Capability); i += 4:
|
||||
((unsigned *)t->data.frame)[i >> 2] = d[i >> 2]
|
||||
else:
|
||||
if t != cappage:
|
||||
t->data.frame = cappage->data.frame
|
||||
t->data.flags |= PAGE_FLAG_FRAME
|
||||
cappage->data.frame = NULL
|
||||
cappage->data.flags &= ~PAGE_FLAG_FRAME
|
||||
t->flags |= PAGE_FLAG_FRAME
|
||||
t->frame = raw_zalloc ()
|
||||
for unsigned i = 0; i <= (c->data[1] & ~PAGE_MASK); i += 4:
|
||||
((unsigned *)t->frame)[i >> 2] = d[i >> 2]
|
||||
else:
|
||||
if t == cappage:
|
||||
break
|
||||
if c->data[1] & PAGE_SHARE_FORGET:
|
||||
if ~cappage->data.flags & PAGE_FLAG_SHARED:
|
||||
if t->data.flags & PAGE_FLAG_PAYING:
|
||||
t->data.frame = cappage->data.frame
|
||||
t->data.flags |= PAGE_FLAG_FRAME
|
||||
cappage->data.frame = NULL
|
||||
cappage->data.flags &= ~PAGE_FLAG_FRAME
|
||||
else:
|
||||
t->data.share_prev = cappage->data.share_prev
|
||||
t->data.share_next = cappage->data.share_next
|
||||
if t->data.share_prev:
|
||||
((Cappage *)t->data.share_prev)->data.share_next = t
|
||||
if t->data.share_next:
|
||||
((Cappage *)t->data.share_next)->data.share_prev = t
|
||||
cappage->data.share_prev = NULL
|
||||
cappage->data.share_next = NULL
|
||||
cappage->forget ()
|
||||
cappage_check_payment (t)
|
||||
if t != page:
|
||||
t->frame = page->frame
|
||||
t->flags |= PAGE_FLAG_FRAME
|
||||
page->frame = NULL
|
||||
page->flags &= ~PAGE_FLAG_FRAME
|
||||
Page_arch_update_mapping (page)
|
||||
Page_arch_update_mapping (t)
|
||||
else:
|
||||
if t == page:
|
||||
break
|
||||
if c->data[1] & PAGE_SHARE_FORGET:
|
||||
if ~page->flags & PAGE_FLAG_SHARED:
|
||||
if t->flags & PAGE_FLAG_PAYING:
|
||||
t->frame = page->frame
|
||||
t->flags |= PAGE_FLAG_FRAME
|
||||
page->frame = NULL
|
||||
page->flags &= ~PAGE_FLAG_FRAME
|
||||
Page_arch_update_mapping (page)
|
||||
else:
|
||||
t->data.share_prev = cappage->data.share_prev
|
||||
t->data.share_next = cappage
|
||||
cappage->data.share_prev = t
|
||||
if t->data.share_prev:
|
||||
((Cappage *)t->data.share_prev)->data.share_next = t
|
||||
t->share_prev = page->share_prev
|
||||
t->share_next = page->share_next
|
||||
if t->share_prev:
|
||||
t->share_prev->share_next = t
|
||||
if t->share_next:
|
||||
t->share_next->share_prev = t
|
||||
page->share_prev = NULL
|
||||
page->share_next = NULL
|
||||
page->forget ()
|
||||
page_check_payment (t)
|
||||
else:
|
||||
t->share_prev = page->share_prev
|
||||
t->share_next = page
|
||||
page->share_prev = t
|
||||
if t->share_prev:
|
||||
t->share_prev->share_next = t
|
||||
Page_arch_update_mapping (t)
|
||||
break
|
||||
case CAP_PAGE_FLAGS:
|
||||
// Always refuse to set reserved flags.
|
||||
c->data[2] &= ~(PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
|
||||
// Remember the old flags.
|
||||
unsigned old = share_data->flags
|
||||
unsigned old = page->flags
|
||||
// Compute the new flags.
|
||||
unsigned new_flags = (share_data->flags & ~c->data[2]) | (c->data[1] & c->data[2])
|
||||
unsigned new_flags = (page->flags & ~c->data[2]) | (c->data[1] & c->data[2])
|
||||
|
||||
// If we stop paying, see if the frame is still paid for. If not, free it.
|
||||
if ~new_flags & old & PAGE_FLAG_PAYING:
|
||||
if page:
|
||||
// Decrease the use counter in any case.
|
||||
page->address_space->unuse ()
|
||||
if !page_check_payment (page):
|
||||
new_flags &= ~PAGE_FLAG_FRAME
|
||||
else:
|
||||
// Decrease the use counter in any case.
|
||||
cappage->address_space->unuse ()
|
||||
if !cappage_check_payment (cappage):
|
||||
new_flags &= ~PAGE_FLAG_FRAME
|
||||
// Decrease the use counter in any case.
|
||||
page->address_space->unuse ()
|
||||
if !page_check_payment (page):
|
||||
new_flags &= ~PAGE_FLAG_FRAME
|
||||
|
||||
// If we start paying, increase the use counter.
|
||||
if new_flags & ~old & PAGE_FLAG_PAYING:
|
||||
if !(page ? page->address_space : cappage->address_space)->use():
|
||||
if !page->address_space->use():
|
||||
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
|
||||
new_flags &= ~(PAGE_FLAG_PAYING | PAGE_FLAG_FRAME)
|
||||
if old & PAGE_FLAG_FRAME:
|
||||
@ -719,42 +579,32 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability::C
|
||||
|
||||
// If we want a frame, see if we can get it.
|
||||
if ~old & new_flags & PAGE_FLAG_FRAME:
|
||||
if page:
|
||||
Page *p
|
||||
for p = page; p; p = (Page *)p->data.share_prev:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
Page *p
|
||||
for p = page; p; p = p->share_prev:
|
||||
if p->flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if !p:
|
||||
for p = page->share_next; p; p = p->share_next:
|
||||
if p->flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if !p:
|
||||
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if !p:
|
||||
new_flags &= ~PAGE_FLAG_FRAME
|
||||
else:
|
||||
Cappage *p
|
||||
for p = cappage; p; p = (Cappage *)p->data.share_prev:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if !p:
|
||||
for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next:
|
||||
if p->data.flags & PAGE_FLAG_PAYING:
|
||||
break
|
||||
if !p:
|
||||
new_flags &= ~PAGE_FLAG_FRAME
|
||||
new_flags &= ~PAGE_FLAG_FRAME
|
||||
// If we can get the new frame, get it.
|
||||
Capability *cap = &((Capability *)cappage->data.frame)[c->data[1]]
|
||||
cap->invalidate ()
|
||||
// clone_capability needs a Memory, but doesn't use it when storage is provided.
|
||||
top_memory.clone_capability (c->cap[0], c->copy[0], cap)
|
||||
if ~old & new_flags & PAGE_FLAG_FRAME:
|
||||
page->frame = page->address_space->zalloc ()
|
||||
Page_arch_update_mapping (page)
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
static void capability_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
|
||||
Capability *capability = (Capability *)protected_data
|
||||
static void caps_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
|
||||
Caps *caps = (CapsP)protected_data
|
||||
switch c->data[0]:
|
||||
case CAP_CAPABILITY_GET:
|
||||
reply_cap (capability, true)
|
||||
case CAP_CAPS_SET:
|
||||
if c->data[1] >= caps->size:
|
||||
break
|
||||
caps->caps[c->data[1]].invalidate ()
|
||||
caps->clone (c->data[1], c->cap[0], c->copy[0])
|
||||
break
|
||||
default:
|
||||
break
|
||||
@ -768,26 +618,26 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
// This is a call capability. cap[0] is the capability to call.
|
||||
reply_receiver = (Receiver *)protected_data
|
||||
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
|
||||
Capability *c0 = c->cap[0]
|
||||
CapRef c0 = c->cap[0]
|
||||
if c0:
|
||||
if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
|
||||
Capability r
|
||||
fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
|
||||
c->cap[0] = &r
|
||||
Caps r
|
||||
fill_cap (CapRef (&r, 0), protected_data, reply_receiver->reply_protected_data)
|
||||
c->cap[0] = CapRef (&r, 0)
|
||||
c->copy[0] = true
|
||||
c0->target->send_message (c0->protected_data, c)
|
||||
r.invalidate ()
|
||||
r.caps[0].invalidate ()
|
||||
else:
|
||||
// Kernel call: don't create actual capablities.
|
||||
c->cap[0] = NULL
|
||||
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0)
|
||||
c->cap[0].reset ()
|
||||
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0.deref ())
|
||||
return
|
||||
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
|
||||
// This is a reply capability.
|
||||
Receiver *r = (Receiver *)protected_data
|
||||
r->send_message (r->reply_protected_data, c)
|
||||
while self->parent:
|
||||
self = self->parent
|
||||
self = self->parent.deref ()
|
||||
while self->sibling_prev:
|
||||
self->sibling_prev->invalidate ()
|
||||
while self->sibling_next:
|
||||
@ -801,7 +651,7 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
dbg_log ("; target = ")
|
||||
dbg_log_num (target)
|
||||
return
|
||||
reply = c->cap[0]
|
||||
reply = c->cap[0].deref ()
|
||||
if c->data[0] == CAP_DEGRADE:
|
||||
reply_cap (target & c->data[1], protected_data)
|
||||
return
|
||||
@ -818,11 +668,8 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
case CAPTYPE_PAGE:
|
||||
page_invoke (target, protected_data, c)
|
||||
break
|
||||
case CAPTYPE_CAPABILITY:
|
||||
capability_invoke (target, protected_data, c)
|
||||
break
|
||||
case CAPTYPE_CAPPAGE:
|
||||
page_invoke (target, protected_data, c)
|
||||
case CAPTYPE_CAPS:
|
||||
caps_invoke (target, protected_data, c)
|
||||
break
|
||||
default:
|
||||
panic (0x99337744, "invalid capability type invoked")
|
||||
|
275
iris.h
275
iris.h
@ -30,7 +30,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
// Number of clock interrupts per second.
|
||||
#define HZ 20
|
||||
#define HZ 100
|
||||
|
||||
#define PAGE_BITS (12)
|
||||
#define PAGE_SIZE (1 << PAGE_BITS)
|
||||
@ -47,6 +47,7 @@ enum Exception_code {
|
||||
ERR_OVERFLOW,
|
||||
ERR_TRAP,
|
||||
ERR_WATCHPOINT,
|
||||
ERR_BREAKPOINT,
|
||||
ERR_NO_PAGE_DIRECTORY,
|
||||
ERR_NO_PAGE_TABLE,
|
||||
ERR_OUT_OF_MEMORY,
|
||||
@ -65,6 +66,7 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
"overflow",
|
||||
"trap",
|
||||
"watchpoint",
|
||||
"breakpoint",
|
||||
"no page directory",
|
||||
"no page table",
|
||||
"out of memory"
|
||||
@ -78,8 +80,8 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
#define CAPTYPE_MEMORY 0x200
|
||||
#define CAPTYPE_THREAD 0x400
|
||||
#define CAPTYPE_PAGE 0x600
|
||||
#define CAPTYPE_CAPABILITY 0x800
|
||||
#define CAPTYPE_CAPPAGE 0xa00
|
||||
#define CAPTYPE_CAPS 0x800
|
||||
/*#define CAPTYPE_??? 0xa00*/
|
||||
/*#define CAPTYPE_??? 0xc00*/
|
||||
/*#define CAPTYPE_??? 0xe00*/
|
||||
|
||||
@ -106,19 +108,20 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
#define CAP_MEMORY_MAP 4
|
||||
#define CAP_MEMORY_MAPPING 5
|
||||
#define CAP_MEMORY_LIMIT 6
|
||||
#define CAP_MEMORY_DROP 8
|
||||
#define CAP_MEMORY_ALL_RIGHTS 0x1ff
|
||||
|
||||
#define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */
|
||||
#define CAP_THREAD_SCHEDULE 2
|
||||
#define CAP_THREAD_ALLOC_RANGE 3
|
||||
#define CAP_THREAD_PHYSICAL_ADDRESS 4
|
||||
#define CAP_THREAD_ALLOC_PHYSICAL 5
|
||||
#define CAP_THREAD_MAKE_PRIV 6
|
||||
#define CAP_THREAD_GET_TOP_MEMORY 7
|
||||
#define CAP_THREAD_REGISTER_INTERRUPT 8
|
||||
#define CAP_THREAD_ALL_RIGHTS 0x07
|
||||
#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV) | (1 << CAP_THREAD_ALLOC_PHYSICAL) | (1 << CAP_THREAD_PHYSICAL_ADDRESS) | (1 << CAP_THREAD_ALLOC_RANGE))
|
||||
#define CAP_THREAD_CAP_CLONE 3
|
||||
#define CAP_THREAD_PRIV 8
|
||||
#define CAP_THREAD_PRIV_ALLOC_RANGE 0
|
||||
#define CAP_THREAD_PRIV_PHYSICAL_ADDRESS 1
|
||||
#define CAP_THREAD_PRIV_ALLOC_PHYSICAL 2
|
||||
#define CAP_THREAD_PRIV_MAKE_PRIV 3
|
||||
#define CAP_THREAD_PRIV_GET_TOP_MEMORY 4
|
||||
#define CAP_THREAD_PRIV_REGISTER_INTERRUPT 5
|
||||
#define CAP_THREAD_ALL_RIGHTS 0x0ff
|
||||
#define CAP_THREAD_ALL_PRIV_RIGHTS 0x1ff
|
||||
|
||||
/* These get/set_info are not arch-specific. */
|
||||
#define CAP_THREAD_INFO_PC ~0
|
||||
@ -130,6 +133,9 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
#define THREAD_FLAG_RUNNING 0x20000000
|
||||
#define THREAD_FLAG_USER 0x1fffffff
|
||||
|
||||
#define CAP_CAPS_SET 1
|
||||
#define CAP_CAPS_ALL_RIGHTS 0x1ff
|
||||
|
||||
#define CAP_PAGE_SHARE 1
|
||||
#define CAP_PAGE_FLAGS 2
|
||||
/* Not an operation; a capability without this bit cannot write to the page. */
|
||||
@ -158,31 +164,24 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
/* This is a read-only flag, saying if this is uncachable memory. */
|
||||
#define PAGE_FLAG_UNCACHED 0x20
|
||||
|
||||
#define CAP_CAPABILITY_GET 1
|
||||
#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff
|
||||
/* 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 CAPABILITY_COPY 0x80000000
|
||||
/* This constant can be used to signify that no capability is passed or accepted. */
|
||||
#define CAPABILITY_NONE (~CAPABILITY_COPY)
|
||||
|
||||
#define CAPPAGE_SIZE 102
|
||||
/* Cappage has Page's operations as well. */
|
||||
#define CAP_CAPPAGE_SET 4
|
||||
#define CAP_CAPPAGE_ALL_RIGHTS 0x1ff
|
||||
#define __my_receiver 1
|
||||
#define __my_thread 2
|
||||
#define __my_memory 3
|
||||
#define __my_call 4
|
||||
#define __my_parent 5
|
||||
|
||||
#ifndef __KERNEL
|
||||
typedef unsigned Capability;
|
||||
|
||||
extern Capability __my_receiver;
|
||||
extern Capability __my_thread;
|
||||
extern Capability __my_memory;
|
||||
extern Capability __my_call;
|
||||
extern Capability __my_parent;
|
||||
|
||||
static Capability cap_copy (Capability src)
|
||||
{
|
||||
return src | 2;
|
||||
}
|
||||
|
||||
static Capability cappage_cap (unsigned base, unsigned idx)
|
||||
{
|
||||
return base | (idx << 2) | 1;
|
||||
return src | CAPABILITY_COPY;
|
||||
}
|
||||
|
||||
typedef struct Message
|
||||
@ -211,30 +210,34 @@ static void invoke (Capability target, Message *msg)
|
||||
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
|
||||
}
|
||||
|
||||
static void wait (Message *msg)
|
||||
static void wait (Message *msg, Capability r0, Capability r1, Capability r2, Capability r3)
|
||||
{
|
||||
__asm__ volatile ("li $v0, 2\n"
|
||||
__asm__ volatile ("li $v0, 0x80000000\n"
|
||||
"\tlw $t4, %1\n"
|
||||
"\tlw $t5, %2\n"
|
||||
"\tlw $t6, %3\n"
|
||||
"\tlw $t7, %4\n"
|
||||
"\tsyscall\n"
|
||||
"\tlw $v1, %0\n"
|
||||
"\tsw $t0, 0($v1)\n"
|
||||
"\tsw $t1, 4($v1)\n"
|
||||
"\tsw $t2, 8($v1)\n"
|
||||
"\tsw $t3, 12($v1)\n"
|
||||
"\tsw $a0, 16($v1)\n"
|
||||
"\tsw $a1, 20($v1)\n"
|
||||
"\tsw $a2, 24($v1)\n"
|
||||
"\tsw $a3, 28($v1)\n"
|
||||
"\tsw $v0, 32($v1)"
|
||||
:
|
||||
: "m"(msg)
|
||||
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
|
||||
: "m"(msg), "m"(r0), "m"(r1), "m"(r2), "m"(r3)
|
||||
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "a0", "a1", "a2", "a3");
|
||||
}
|
||||
|
||||
static void call (Capability target, Message *msg)
|
||||
static void call (Capability target, Message *msg, Capability r0, Capability r1, Capability r2, Capability r3)
|
||||
{
|
||||
Capability t = cap_copy (target);
|
||||
__asm__ volatile ("lw $v0, %0\n"
|
||||
"\tlw $v1, %1\n"
|
||||
"\tlw $t4, %1\n"
|
||||
"\tlw $t5, %2\n"
|
||||
"\tlw $t6, %3\n"
|
||||
"\tlw $t7, %4\n"
|
||||
"\tlw $t0, 0($v1)\n"
|
||||
"\tlw $t1, 4($v1)\n"
|
||||
"\tlw $t2, 8($v1)\n"
|
||||
@ -249,14 +252,10 @@ static void call (Capability target, Message *msg)
|
||||
"\tsw $t1, 4($v1)\n"
|
||||
"\tsw $t2, 8($v1)\n"
|
||||
"\tsw $t3, 12($v1)\n"
|
||||
"\tsw $a0, 16($v1)\n"
|
||||
"\tsw $a1, 20($v1)\n"
|
||||
"\tsw $a2, 24($v1)\n"
|
||||
"\tsw $a3, 28($v1)\n"
|
||||
"\tsw $v0, 32($v1)"
|
||||
:
|
||||
: "m"(t), "m"(msg)
|
||||
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
|
||||
: "m" (t), "m" (msg), "m" (r0), "m" (r1), "m" (r2), "m" (r3)
|
||||
: "memory", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7");
|
||||
}
|
||||
|
||||
static void invoke_00 (Capability t)
|
||||
@ -385,6 +384,20 @@ static void invoke_13 (Capability t, Capability c, unsigned d0, unsigned d1, uns
|
||||
invoke (t, &msg);
|
||||
}
|
||||
|
||||
static void invoke_14 (Capability t, Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
msg.data[2] = d2;
|
||||
msg.data[3] = d3;
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
invoke (t, &msg);
|
||||
}
|
||||
|
||||
static void invoke_20 (Capability t, Capability c0, Capability c1)
|
||||
{
|
||||
Message msg;
|
||||
@ -452,7 +465,7 @@ static void call_00 (Capability c)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static unsigned call_n00 (Capability c)
|
||||
@ -466,11 +479,11 @@ static unsigned call_n00 (Capability c)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
static Capability call_c00 (Capability c)
|
||||
static void call_c00 (Capability c, Capability target)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
@ -481,11 +494,10 @@ static Capability call_c00 (Capability c)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
return msg.cap[0];
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static Capability call_c01 (Capability c, unsigned d)
|
||||
static void call_c01 (Capability c, Capability target, unsigned d)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
@ -496,8 +508,7 @@ static Capability call_c01 (Capability c, unsigned d)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
return msg.cap[0];
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static unsigned long long call_l01 (Capability c, unsigned d)
|
||||
@ -511,11 +522,11 @@ static unsigned long long call_l01 (Capability c, unsigned d)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32);
|
||||
}
|
||||
|
||||
static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
|
||||
static void call_c02 (Capability c, Capability target, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
@ -526,8 +537,7 @@ static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
return msg.cap[0];
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1)
|
||||
@ -541,11 +551,11 @@ static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32);
|
||||
}
|
||||
|
||||
static Capability call_c03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
|
||||
static void call_c03 (Capability c, Capability target, unsigned d0, unsigned d1, unsigned d2)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
@ -556,8 +566,7 @@ static Capability call_c03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
return msg.cap[0];
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
|
||||
@ -571,11 +580,11 @@ static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsi
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32);
|
||||
}
|
||||
|
||||
static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d1)
|
||||
static void call_c12 (Capability c, Capability target, Capability c1, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
@ -586,8 +595,21 @@ static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d
|
||||
msg.data[3] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
return msg.cap[0];
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static void call_c13 (Capability c, Capability target, Capability c1, unsigned d0, unsigned d1, unsigned d2)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
msg.cap[1] = c1;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
msg.data[2] = d2;
|
||||
msg.data[3] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static unsigned call_n01 (Capability c, unsigned d)
|
||||
@ -601,7 +623,7 @@ static unsigned call_n01 (Capability c, unsigned d)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -616,7 +638,7 @@ static unsigned call_n11 (Capability c, Capability c1, unsigned d)
|
||||
msg.data[3] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -631,7 +653,7 @@ static unsigned call_n12 (Capability c, Capability c1, unsigned d0, unsigned d1)
|
||||
msg.data[3] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -646,7 +668,7 @@ static unsigned call_n14 (Capability c, Capability c1, unsigned d0, unsigned d1,
|
||||
msg.data[3] = d3;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -661,7 +683,7 @@ static unsigned call_n02 (Capability c, unsigned d0, unsigned d1)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -676,7 +698,7 @@ static Capability call_p02 (Capability c, unsigned d0, unsigned d1, unsigned *ba
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
*base_return = msg.data[0];
|
||||
return msg.cap[0];
|
||||
}
|
||||
@ -692,7 +714,7 @@ static unsigned call_n03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -708,10 +730,24 @@ static unsigned call_n04 (Capability c, unsigned d0, unsigned d1, unsigned d2, u
|
||||
msg.cap[1] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
static void call_c11 (Capability target, Capability c, Capability c1, unsigned d)
|
||||
{
|
||||
Message msg;
|
||||
msg.cap[0] = c;
|
||||
msg.cap[1] = c1;
|
||||
msg.data[0] = d;
|
||||
msg.data[1] = 0;
|
||||
msg.data[2] = 0;
|
||||
msg.data[3] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1, unsigned d2)
|
||||
{
|
||||
Message msg;
|
||||
@ -723,7 +759,7 @@ static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1,
|
||||
msg.data[3] = 0;
|
||||
msg.cap[2] = 0;
|
||||
msg.cap[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
@ -738,13 +774,13 @@ static unsigned call_n33 (Capability c, Capability c1, Capability c2, Capability
|
||||
msg.data[1] = d1;
|
||||
msg.data[2] = d2;
|
||||
msg.data[3] = 0;
|
||||
call (__my_call, &msg);
|
||||
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
return msg.data[0];
|
||||
}
|
||||
|
||||
static Capability degrade (Capability src, unsigned mask)
|
||||
static void degrade (Capability target, Capability src, unsigned mask)
|
||||
{
|
||||
return call_c02 (src, CAP_DEGRADE, mask);
|
||||
call_c02 (src, target, CAP_DEGRADE, mask);
|
||||
}
|
||||
|
||||
static void schedule ()
|
||||
@ -752,29 +788,34 @@ static void schedule ()
|
||||
invoke_01 (__my_thread, CAP_THREAD_SCHEDULE);
|
||||
}
|
||||
|
||||
static void capability_clone (Capability target, Capability src)
|
||||
{
|
||||
call_c11 (__my_thread, target, src, CAP_THREAD_CAP_CLONE);
|
||||
}
|
||||
|
||||
static void register_interrupt (unsigned num)
|
||||
{
|
||||
invoke_12 (__my_thread, __my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num);
|
||||
invoke_13 (__my_thread, __my_receiver, CAP_THREAD_PRIV, CAP_THREAD_PRIV_REGISTER_INTERRUPT, num);
|
||||
}
|
||||
|
||||
static void unregister_interrupt (unsigned num)
|
||||
{
|
||||
invoke_02 (__my_thread, CAP_THREAD_REGISTER_INTERRUPT, num);
|
||||
invoke_03 (__my_thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_REGISTER_INTERRUPT, num);
|
||||
}
|
||||
|
||||
static Capability get_top_memory ()
|
||||
static void get_top_memory (Capability target)
|
||||
{
|
||||
return call_c01 (__my_thread, CAP_THREAD_GET_TOP_MEMORY);
|
||||
return call_c02 (__my_thread, target, CAP_THREAD_PRIV, CAP_THREAD_PRIV_GET_TOP_MEMORY);
|
||||
}
|
||||
|
||||
static void alloc_physical (Capability page, unsigned address, int cachable, int freeable)
|
||||
{
|
||||
invoke_13 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0));
|
||||
invoke_14 (__my_thread, page, CAP_THREAD_PRIV, CAP_THREAD_PRIV_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0));
|
||||
}
|
||||
|
||||
static unsigned alloc_range (Capability memory, unsigned pages)
|
||||
{
|
||||
return call_n12 (__my_thread, memory, CAP_THREAD_ALLOC_RANGE, pages);
|
||||
return call_n13 (__my_thread, memory, CAP_THREAD_PRIV, CAP_THREAD_PRIV_ALLOC_RANGE, pages);
|
||||
}
|
||||
|
||||
static void receiver_set_owner (Capability receiver, Capability owner)
|
||||
@ -782,9 +823,9 @@ static void receiver_set_owner (Capability receiver, Capability owner)
|
||||
invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
|
||||
}
|
||||
|
||||
static Capability receiver_create_capability (Capability receiver, unsigned protected_data)
|
||||
static void receiver_create_capability (Capability target, Capability receiver, unsigned protected_data)
|
||||
{
|
||||
return call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
|
||||
return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
|
||||
}
|
||||
|
||||
static unsigned receiver_reply_protected_data (Capability receiver, int set, unsigned data)
|
||||
@ -825,47 +866,47 @@ static unsigned receiver_set_alarm (Capability receiver, unsigned data)
|
||||
static void my_sleep (unsigned value, Message *ret)
|
||||
{
|
||||
receiver_set_alarm (__my_receiver, value);
|
||||
wait (ret);
|
||||
wait (ret, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
|
||||
}
|
||||
|
||||
static Capability receiver_create_call_capability (Capability receiver)
|
||||
static void receiver_create_call_capability (Capability target, Capability receiver)
|
||||
{
|
||||
return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0);
|
||||
return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0);
|
||||
}
|
||||
|
||||
static Capability receiver_create_async_call_capability (Capability receiver)
|
||||
static void receiver_create_async_call_capability (Capability target, Capability receiver)
|
||||
{
|
||||
return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1);
|
||||
return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1);
|
||||
}
|
||||
|
||||
static Capability memory_create (Capability memory, unsigned type)
|
||||
static void memory_create (Capability target, Capability memory, unsigned type)
|
||||
{
|
||||
return call_c02 (memory, CAP_MEMORY_CREATE, type);
|
||||
return call_c02 (memory, target, CAP_MEMORY_CREATE, type);
|
||||
}
|
||||
|
||||
static Capability memory_create_page (Capability memory)
|
||||
static void memory_create_page (Capability target, Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_PAGE | REQUEST_MASK);
|
||||
return memory_create (memory, target, CAPTYPE_PAGE | REQUEST_MASK);
|
||||
}
|
||||
|
||||
static Capability memory_create_thread (Capability memory)
|
||||
static void memory_create_thread (Capability target, Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_THREAD | REQUEST_MASK);
|
||||
return memory_create (memory, target, CAPTYPE_THREAD | REQUEST_MASK);
|
||||
}
|
||||
|
||||
static Capability memory_create_receiver (Capability memory)
|
||||
static void memory_create_receiver (Capability target, Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_RECEIVER | REQUEST_MASK);
|
||||
return memory_create (memory, target, CAPTYPE_RECEIVER | REQUEST_MASK);
|
||||
}
|
||||
|
||||
static Capability memory_create_memory (Capability memory)
|
||||
static void memory_create_memory (Capability target, Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_MEMORY | REQUEST_MASK);
|
||||
return memory_create (memory, target, CAPTYPE_MEMORY | REQUEST_MASK);
|
||||
}
|
||||
|
||||
static Capability memory_create_cappage (Capability memory, unsigned *base_return)
|
||||
static void memory_create_caps (Capability target, Capability memory)
|
||||
{
|
||||
return call_p02 (memory, CAP_MEMORY_CREATE, CAPTYPE_CAPPAGE | REQUEST_MASK, base_return);
|
||||
return memory_create (memory, target, CAPTYPE_CAPS | REQUEST_MASK);
|
||||
}
|
||||
|
||||
static void memory_destroy (Capability memory, Capability target)
|
||||
@ -882,24 +923,19 @@ static void memory_map (Capability memory, Capability page, unsigned address, in
|
||||
invoke_12 (memory, page, CAP_MEMORY_MAP, address);
|
||||
}
|
||||
|
||||
static Capability memory_mapping (Capability memory, void *address)
|
||||
static void memory_mapping (Capability target, Capability memory, void *address)
|
||||
{
|
||||
return call_c02 (memory, CAP_MEMORY_MAPPING, (unsigned)address);
|
||||
call_c02 (memory, target, CAP_MEMORY_MAPPING, (unsigned)address);
|
||||
}
|
||||
|
||||
static unsigned memory_limit (Capability memory, unsigned limit)
|
||||
{
|
||||
return call_c02 (memory, CAP_MEMORY_LIMIT, limit);
|
||||
return call_n02 (memory, CAP_MEMORY_LIMIT, limit);
|
||||
}
|
||||
|
||||
static void drop (Capability cap)
|
||||
static void thread_make_priv (Capability target, Capability thread)
|
||||
{
|
||||
invoke_11 (__my_memory, cap, CAP_MEMORY_DROP);
|
||||
}
|
||||
|
||||
static Capability thread_make_priv (Capability thread)
|
||||
{
|
||||
return call_c12 (__my_thread, thread, CAP_THREAD_MAKE_PRIV, ~0);
|
||||
call_c13 (__my_thread, target, thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_MAKE_PRIV, ~0);
|
||||
}
|
||||
|
||||
static unsigned thread_info (Capability thread, unsigned info, unsigned value, unsigned mask)
|
||||
@ -954,21 +990,20 @@ static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask)
|
||||
|
||||
static unsigned page_physical_address (Capability page)
|
||||
{
|
||||
return call_n11 (__my_thread, page, CAP_THREAD_PHYSICAL_ADDRESS);
|
||||
return call_n12 (__my_thread, page, CAP_THREAD_PRIV, CAP_THREAD_PRIV_PHYSICAL_ADDRESS);
|
||||
}
|
||||
|
||||
static Capability capability_get (Capability cap)
|
||||
static void caps_set (Capability caps, Capability cap, unsigned index)
|
||||
{
|
||||
return call_c01 (cap, CAP_CAPABILITY_GET);
|
||||
}
|
||||
|
||||
static void cappage_set (Capability page, Capability cap, unsigned index)
|
||||
{
|
||||
invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
|
||||
invoke_12 (caps, cap, CAP_CAPS_SET, index);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* 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++); } while (0)
|
||||
|
||||
static void kdebug_num (unsigned n)
|
||||
|
170
kernel.hhp
170
kernel.hhp
@ -30,110 +30,139 @@
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
struct Object_base
|
||||
struct Page
|
||||
struct Thread
|
||||
struct Message
|
||||
struct Receiver
|
||||
struct Capability
|
||||
struct Cappage
|
||||
struct Caps
|
||||
struct Memory
|
||||
|
||||
struct Object_base:
|
||||
Capability *refs
|
||||
Memory *address_space
|
||||
typedef Page *PageP
|
||||
typedef Thread *ThreadP
|
||||
typedef Message *MessageP
|
||||
typedef Receiver *ReceiverP
|
||||
typedef Capability *CapabilityP
|
||||
typedef Caps *CapsP
|
||||
typedef Memory *MemoryP
|
||||
typedef void *Pointer
|
||||
|
||||
typedef unsigned Protected
|
||||
|
||||
struct CapRef:
|
||||
CapsP caps
|
||||
unsigned index
|
||||
inline Capability *deref ()
|
||||
operator bool ():
|
||||
return deref () != NULL
|
||||
Capability *operator-> ():
|
||||
return deref ()
|
||||
void reset ():
|
||||
caps = NULL
|
||||
CapRef (CapsP c, unsigned i) : caps (c), index (i):
|
||||
CapRef () : caps (NULL), index (~0):
|
||||
inline void clone (CapRef source, bool copy)
|
||||
inline void set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL)
|
||||
|
||||
struct Object:
|
||||
CapRef refs
|
||||
MemoryP address_space
|
||||
// Next and previous object of the same type in any page.
|
||||
Pointer prev, next
|
||||
inline bool is_free ()
|
||||
|
||||
template <typename _T> //
|
||||
struct Object : public Object_base:
|
||||
// Next and previous object of the same type in any page.
|
||||
_T *prev, *next
|
||||
|
||||
struct Free : public Object <Free>:
|
||||
struct Free : public Object:
|
||||
// This marker is ~0. No other kernel structure may allow this value
|
||||
// at this point. It is used to recognize free chunks.
|
||||
unsigned marker
|
||||
|
||||
bool Object_base::is_free ():
|
||||
bool Object::is_free ():
|
||||
return ((Free *)this)->marker == ~0
|
||||
|
||||
// Include architecture-specific parts.
|
||||
#include "arch.hh"
|
||||
|
||||
struct Message : public Object <Message>:
|
||||
Capability *capabilities[4]
|
||||
struct Message : public Object:
|
||||
Protected protected_data
|
||||
unsigned data[4]
|
||||
unsigned protected_data
|
||||
unsigned char capabilities[4]
|
||||
|
||||
struct Capability : public Object <Capability>:
|
||||
struct Capability : public Object:
|
||||
struct Context:
|
||||
unsigned data[4]
|
||||
Capability *cap[4]
|
||||
CapRef cap[4]
|
||||
bool copy[4]
|
||||
Receiver *target
|
||||
Capability *parent
|
||||
Capability *children
|
||||
Capability *sibling_prev, *sibling_next
|
||||
unsigned protected_data
|
||||
ReceiverP target
|
||||
CapRef parent
|
||||
CapRef children
|
||||
CapRef sibling_prev, sibling_next
|
||||
Protected protected_data
|
||||
void invoke (Context *c)
|
||||
void invalidate ()
|
||||
|
||||
struct Thread : public Object <Thread>:
|
||||
Receiver *receivers
|
||||
struct Thread : public Object:
|
||||
ReceiverP receivers
|
||||
unsigned pc, sp
|
||||
Thread_arch arch
|
||||
unsigned flags
|
||||
Thread *schedule_prev, *schedule_next
|
||||
// This is not a pointer, but a real Capability. That means that at capability destroy, no check is needed if it is used for an exception handler.
|
||||
Capability exception
|
||||
ThreadP schedule_prev, schedule_next
|
||||
CapRef rcaps[4]
|
||||
// caps is an array of slots pointers to Capses.
|
||||
unsigned slots
|
||||
// TODO: handle freeing of capses which are in use.
|
||||
CapsP caps[1]
|
||||
void raise (unsigned code, unsigned data)
|
||||
void run ()
|
||||
void unrun ()
|
||||
void wait ()
|
||||
void wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3)
|
||||
void unwait ()
|
||||
bool is_waiting ():
|
||||
return flags & THREAD_FLAG_WAITING
|
||||
CapRef find_capability (unsigned code, bool *copy)
|
||||
|
||||
struct Receiver : public Object <Receiver>:
|
||||
Thread *owner
|
||||
Receiver *prev_owned, *next_owned
|
||||
Receiver *prev_alarm, *next_alarm
|
||||
struct Receiver : public Object:
|
||||
ThreadP owner
|
||||
ReceiverP prev_owned, next_owned
|
||||
ReceiverP prev_alarm, next_alarm
|
||||
unsigned alarm_count
|
||||
Capability *capabilities
|
||||
Message *messages
|
||||
Message *last_message
|
||||
unsigned reply_protected_data
|
||||
// random is used like the tlb random register to find invalid caps to store the message to.
|
||||
unsigned random
|
||||
CapsP caps
|
||||
// These are capabilities which call this receiver on invoke.
|
||||
CapRef capabilities
|
||||
// The message queue. Messages are added at the tail, and removed at the front.
|
||||
MessageP messages
|
||||
MessageP last_message
|
||||
Protected reply_protected_data
|
||||
bool protected_only
|
||||
void own (Thread *o)
|
||||
void own (ThreadP o)
|
||||
void orphan ()
|
||||
bool try_deliver ()
|
||||
bool send_message (unsigned protected_data, Capability::Context *c)
|
||||
bool send_message (Protected protected_data, Capability::Context *c)
|
||||
|
||||
struct ShareData :
|
||||
struct Page : public Object:
|
||||
unsigned frame
|
||||
unsigned flags
|
||||
void *share_first
|
||||
void *share_prev, *share_next
|
||||
|
||||
struct Page : public Object <Page>:
|
||||
ShareData data
|
||||
PageP share_first
|
||||
PageP share_prev, share_next
|
||||
Page_arch arch
|
||||
void forget ()
|
||||
|
||||
struct Cappage : public Object <Cappage>:
|
||||
ShareData data
|
||||
struct Caps : public Object:
|
||||
unsigned size
|
||||
Capability caps[1]
|
||||
Capability *cap (unsigned idx):
|
||||
return &((Capability *)data.frame)[idx]
|
||||
void forget ()
|
||||
return &caps[idx]
|
||||
void set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL)
|
||||
void clone (unsigned index, CapRef source, bool copy)
|
||||
|
||||
struct Memory : public Object <Memory>:
|
||||
struct Memory : public Object:
|
||||
Free *frees
|
||||
Page *pages
|
||||
Thread *threads
|
||||
Receiver *receivers
|
||||
Capability *capabilities
|
||||
Cappage *cappages
|
||||
Memory *memories
|
||||
PageP pages
|
||||
ThreadP threads
|
||||
ReceiverP receivers
|
||||
CapsP capses
|
||||
MemoryP memories
|
||||
unsigned limit, used
|
||||
Memory_arch arch
|
||||
|
||||
@ -152,32 +181,27 @@ struct Memory : public Object <Memory>:
|
||||
// Allocation routines for kernel structures
|
||||
void *search_free (unsigned size, void **first)
|
||||
Page *alloc_page ()
|
||||
Thread *alloc_thread ()
|
||||
Thread *alloc_thread (unsigned size)
|
||||
Message *alloc_message (Receiver *target)
|
||||
Receiver *alloc_receiver ()
|
||||
Capability *alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret = NULL)
|
||||
Capability *clone_capability (Capability *source, bool copy, Capability *ret = NULL)
|
||||
Cappage *alloc_cappage ()
|
||||
Caps *alloc_caps (unsigned size)
|
||||
Memory *alloc_memory ()
|
||||
|
||||
void free_page (Page *page)
|
||||
void free_thread (Thread *thread)
|
||||
void free_message (Receiver *owner, Message *message)
|
||||
void free_receiver (Receiver *receiver)
|
||||
void free_capability (Capability *capability)
|
||||
void free_cappage (Cappage *page)
|
||||
void free_caps (Caps *page)
|
||||
void free_memory (Memory *mem)
|
||||
|
||||
void free_obj (Object_base *obj, void **first)
|
||||
|
||||
Capability *find_capability (unsigned code, bool *copy)
|
||||
void free_obj (Object *obj, void **first)
|
||||
|
||||
// Functions which can be called from assembly must not be mangled.
|
||||
extern "C":
|
||||
// Panic. n is sent over caps led. message is currently ignored.
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
|
||||
EXTERN unsigned dbg_code
|
||||
EXTERN Capability *dbg_cap
|
||||
EXTERN CapRef dbg_cap
|
||||
void dbg_log_char (unsigned ch)
|
||||
void dbg_log (char const *str)
|
||||
void dbg_log_num (unsigned num)
|
||||
@ -189,12 +213,12 @@ void schedule ()
|
||||
void timer_interrupt ()
|
||||
|
||||
EXTERN Memory top_memory
|
||||
EXTERN Receiver *first_alarm
|
||||
EXTERN ReceiverP first_alarm
|
||||
EXTERN Thread idle
|
||||
EXTERN Memory idle_memory
|
||||
EXTERN Page idle_page
|
||||
EXTERN Thread *first_scheduled
|
||||
EXTERN Thread *current, *old_current
|
||||
EXTERN ThreadP first_scheduled
|
||||
EXTERN ThreadP current, old_current
|
||||
EXTERN bool do_schedule
|
||||
|
||||
// Defined in memory.cc
|
||||
@ -206,7 +230,7 @@ void phys_free (unsigned page, unsigned num)
|
||||
|
||||
// Defined by architecture-specific files.
|
||||
void Thread_arch_init (Thread *thread)
|
||||
void Thread_arch_receive (Thread *thread, unsigned protected_data, Capability::Context *c)
|
||||
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)
|
||||
@ -214,7 +238,7 @@ 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, Receiver *r)
|
||||
void arch_register_interrupt (unsigned num, ReceiverP r)
|
||||
|
||||
bool Memory::map (Page *page, unsigned address, bool write):
|
||||
return Memory_arch_map (this, page, address, write)
|
||||
@ -222,6 +246,12 @@ void Memory::unmap (Page *page, unsigned address):
|
||||
Memory_arch_unmap (this, page, address)
|
||||
Page *Memory::get_mapping (unsigned address, bool *writable):
|
||||
return Memory_arch_get_mapping (this, address, writable)
|
||||
Capability *CapRef::deref ():
|
||||
return caps ? caps->cap (index) : NULL
|
||||
void CapRef::clone (CapRef source, bool copy):
|
||||
caps->clone (index, source, copy)
|
||||
void CapRef::set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr):
|
||||
caps->set (index, target, pdata, parent, parent_ptr)
|
||||
|
||||
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
load = 0x80000000
|
||||
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=3
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=2
|
||||
ARCH_CPPFLAGS = -Imips -Wa,-mips32
|
||||
CROSS = mipsel-linux-gnu-
|
||||
OBJDUMP = $(CROSS)objdump
|
||||
@ -34,7 +34,7 @@ uimage:
|
||||
mips/entry.o: $(boot_threads)
|
||||
mips/init.o: TARGET_FLAGS = -I/usr/include
|
||||
$(boot_threads): TARGET_FLAGS = -I.
|
||||
$(boot_threads): boot-programs/devices.hh
|
||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh
|
||||
lcd: boot-programs/charset.data
|
||||
|
||||
boot-programs/charset.data: boot-programs/charset
|
||||
|
@ -45,15 +45,11 @@ void Thread_arch_init (Thread *thread):
|
||||
thread->arch.k0 = 0
|
||||
thread->arch.k1 = 0
|
||||
|
||||
void Thread_arch_receive (Thread *thread, unsigned protected_data, Capability::Context *c):
|
||||
thread->arch.a0 = (unsigned)c->cap[0]
|
||||
thread->arch.a1 = (unsigned)c->cap[1]
|
||||
thread->arch.a2 = (unsigned)c->cap[2]
|
||||
thread->arch.a3 = (unsigned)c->cap[3]
|
||||
thread->arch.t0 = c->data[0]
|
||||
thread->arch.t1 = c->data[1]
|
||||
thread->arch.t2 = c->data[2]
|
||||
thread->arch.t3 = c->data[3]
|
||||
void Thread_arch_receive (Thread *thread, unsigned protected_data, unsigned *data):
|
||||
thread->arch.t0 = data[0]
|
||||
thread->arch.t1 = data[1]
|
||||
thread->arch.t2 = data[2]
|
||||
thread->arch.t3 = data[3]
|
||||
thread->arch.v0 = protected_data
|
||||
|
||||
unsigned *Thread_arch_info (Thread *thread, unsigned num):
|
||||
@ -193,16 +189,16 @@ static void free_page (arch_page_table *t, arch_page *p):
|
||||
free_page_table (t, idx)
|
||||
|
||||
static unsigned make_entry_lo (Page *page, bool write):
|
||||
if !page->data.frame:
|
||||
if !page->frame:
|
||||
return 0
|
||||
unsigned flags
|
||||
if page->data.flags & PAGE_FLAG_UNCACHED:
|
||||
if page->flags & PAGE_FLAG_UNCACHED:
|
||||
flags = 0x10 | 0x2
|
||||
else:
|
||||
flags = 0x18 | 0x2
|
||||
if write:
|
||||
flags |= 0x4
|
||||
return ((page->data.frame & ~0x80000000) >> 6) | flags
|
||||
return ((page->frame & ~0x80000000) >> 6) | flags
|
||||
|
||||
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
|
||||
if address >= 0x80000000:
|
||||
@ -282,7 +278,7 @@ void Page_arch_update_mapping (Page *page):
|
||||
if !page->arch.first_mapped:
|
||||
return
|
||||
Memory *as = page->address_space
|
||||
unsigned target = make_entry_lo (page, page->data.flags & PAGE_FLAG_WRITABLE)
|
||||
unsigned target = make_entry_lo (page, page->flags & PAGE_FLAG_WRITABLE)
|
||||
for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped:
|
||||
unsigned de = p->mapping >> 21
|
||||
unsigned te = (p->mapping >> 12) & ((1 << 9) - 1)
|
||||
|
@ -69,7 +69,7 @@
|
||||
|
||||
#ifdef __KERNEL
|
||||
// register save positions in Thread
|
||||
#define SAVE_PC (5 * 4)
|
||||
#define SAVE_PC (6 * 4)
|
||||
#define SAVE_SP (SAVE_PC + 4)
|
||||
#define SAVE_AT (SAVE_SP + 4)
|
||||
#define SAVE_V0 (SAVE_AT + 4)
|
||||
@ -122,12 +122,12 @@ struct Thread_arch:
|
||||
// bits 12-20 are an index in the page table, bits 21-30
|
||||
// are an index in the page directory and bit 31 is always 0.
|
||||
|
||||
struct arch_page : public Object <arch_page> :
|
||||
struct arch_page : public Object :
|
||||
Page *page
|
||||
unsigned mapping
|
||||
arch_page *prev_mapped, *next_mapped
|
||||
|
||||
struct arch_page_table : public Object <arch_page_table> :
|
||||
struct arch_page_table : public Object :
|
||||
arch_page *first_page
|
||||
|
||||
struct Page_arch:
|
||||
|
@ -29,13 +29,13 @@ static void init_idle ():
|
||||
idle.schedule_prev = NULL
|
||||
idle.schedule_next = NULL
|
||||
idle.address_space = &idle_memory
|
||||
idle.refs = NULL
|
||||
idle.refs.reset ()
|
||||
idle.flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
|
||||
// initialize idle_memory.
|
||||
idle_memory.prev = NULL
|
||||
idle_memory.next = NULL
|
||||
idle_memory.address_space = NULL
|
||||
idle_memory.refs = NULL
|
||||
idle_memory.refs.reset ()
|
||||
idle_memory.pages = &idle_page
|
||||
idle_memory.threads = &idle
|
||||
idle_memory.memories = NULL
|
||||
@ -48,9 +48,9 @@ static void init_idle ():
|
||||
// initialize idle_page
|
||||
idle_page.prev = NULL
|
||||
idle_page.next = NULL
|
||||
idle_page.data.frame = 0x80000000
|
||||
idle_page.data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
idle_page.refs = NULL
|
||||
idle_page.frame = 0x80000000
|
||||
idle_page.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
idle_page.refs.reset ()
|
||||
idle_page.address_space = NULL
|
||||
current = &idle
|
||||
directory = idle_memory.arch.directory
|
||||
@ -103,10 +103,6 @@ static void init_cp0 ():
|
||||
// Wait with initializing the status register until the last moment, so that
|
||||
// exceptions in the bootup code will fill EPC and friends.
|
||||
|
||||
// This returns unsigned, because the value is used to fill thread->arch.a*.
|
||||
static unsigned mkcap (Memory *mem, unsigned type, void *obj):
|
||||
return (unsigned)mem->alloc_capability ((Receiver *)type, NULL, &mem->capabilities, (unsigned)obj)
|
||||
|
||||
static void init_threads ():
|
||||
Thread *previous = NULL
|
||||
first_scheduled = NULL
|
||||
@ -115,7 +111,7 @@ static void init_threads ():
|
||||
for unsigned i = 0; i < NUM_THREADS; ++i:
|
||||
Memory *mem = top_memory.alloc_memory ()
|
||||
assert (mem)
|
||||
Thread *thread = mem->alloc_thread ()
|
||||
Thread *thread = mem->alloc_thread (3)
|
||||
Page **pages = (Page **)mem->zalloc ()
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
@ -155,8 +151,8 @@ static void init_threads ():
|
||||
unsigned idx = file_offset + section_offset
|
||||
if !pages[idx]:
|
||||
pages[idx] = mem->alloc_page ()
|
||||
pages[idx]->data.frame = thread_start[i] + (idx << PAGE_BITS)
|
||||
pages[idx]->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS)
|
||||
pages[idx]->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
++top_memory.limit
|
||||
mem->use ()
|
||||
if !mem->map (pages[idx], p, writable):
|
||||
@ -173,11 +169,11 @@ static void init_threads ():
|
||||
if !page:
|
||||
panic (0x00220022, "out of memory")
|
||||
return
|
||||
page->data.frame = mem->zalloc ()
|
||||
if !page->data.frame:
|
||||
page->frame = mem->zalloc ()
|
||||
if !page->frame:
|
||||
panic (0x02220022, "out of memory");
|
||||
return
|
||||
page->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
page->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
if !mem->map (page, p, true):
|
||||
panic (0x33557799, "unable to map initial bss page")
|
||||
return
|
||||
@ -190,31 +186,34 @@ static void init_threads ():
|
||||
break
|
||||
if a < shdr->sh_addr:
|
||||
continue
|
||||
((unsigned *)page->data.frame)[(a & ~PAGE_MASK) >> 2] = 0
|
||||
((unsigned *)page->frame)[(a & ~PAGE_MASK) >> 2] = 0
|
||||
for unsigned p = 0; p <= ((thread_start[i + 1] - thread_start[i] - 1) >> PAGE_BITS); ++p:
|
||||
if pages[p]:
|
||||
continue
|
||||
++top_memory.limit
|
||||
top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
|
||||
Page *stackpage = mem->alloc_page ()
|
||||
stackpage->data.frame = mem->zalloc ()
|
||||
stackpage->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
stackpage->frame = mem->zalloc ()
|
||||
stackpage->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
|
||||
if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
|
||||
panic (0x13151719, "unable to map initial stack page")
|
||||
return
|
||||
thread->caps[0] = mem->alloc_caps (16)
|
||||
for unsigned r = 0; r < 4; ++r:
|
||||
thread->rcaps[r] = CapRef ()
|
||||
Receiver *recv = mem->alloc_receiver ()
|
||||
recv->owner = thread
|
||||
thread->receivers = recv
|
||||
thread->arch.a0 = mkcap (mem, CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS, recv)
|
||||
thread->arch.a1 = mkcap (mem, CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS, thread)
|
||||
thread->arch.a2 = mkcap (mem, CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS, mem)
|
||||
thread->arch.a3 = mkcap (mem, CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL), recv)
|
||||
thread->caps[0]->set (__my_receiver, (ReceiverP)(CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS), (Protected)recv, CapRef ())
|
||||
thread->caps[0]->set (__my_thread, (ReceiverP)(CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS), (Protected)thread, CapRef ())
|
||||
thread->caps[0]->set (__my_memory, (ReceiverP)(CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS), (Protected)mem, CapRef ())
|
||||
thread->caps[0]->set (__my_call, (ReceiverP)(CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)), (Protected)recv, CapRef ())
|
||||
thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
|
||||
if !i:
|
||||
first_scheduled = thread
|
||||
init_receiver = recv
|
||||
else:
|
||||
thread->arch.t0 = mkcap (mem, (unsigned)init_receiver, (void *)i)
|
||||
thread->caps[0]->set (__my_parent, init_receiver, i, CapRef ())
|
||||
previous->schedule_next = thread
|
||||
thread->schedule_prev = previous
|
||||
thread->schedule_next = NULL
|
||||
@ -236,7 +235,7 @@ void init (unsigned mem):
|
||||
top_memory.prev = NULL
|
||||
top_memory.next = NULL
|
||||
top_memory.address_space = NULL
|
||||
top_memory.refs = NULL
|
||||
top_memory.refs.reset ()
|
||||
top_memory.pages = NULL
|
||||
top_memory.threads = NULL
|
||||
top_memory.memories = NULL
|
||||
|
@ -101,7 +101,7 @@ Thread *interrupt ():
|
||||
Capability::Context c
|
||||
for unsigned j = 0; j < 4; ++j:
|
||||
c.data[j] = 0
|
||||
c.cap[j] = NULL
|
||||
c.cap[j].reset ()
|
||||
c.copy[j] = false
|
||||
arch_interrupt_receiver[i]->send_message (i, &c)
|
||||
arch_interrupt_receiver[i] = NULL
|
||||
@ -124,20 +124,26 @@ void flush_tlb (unsigned asid):
|
||||
__asm__ volatile ("tlbwi")
|
||||
|
||||
static void arch_invoke ():
|
||||
Capability *target
|
||||
CapRef target
|
||||
bool wait
|
||||
target = old_current->address_space->find_capability (old_current->arch.v0, &wait)
|
||||
target = old_current->find_capability (old_current->arch.v0, &wait)
|
||||
do_schedule = false
|
||||
if wait:
|
||||
old_current->wait ()
|
||||
bool dummy
|
||||
CapRef c0, c1, c2, c3
|
||||
c0 = old_current->find_capability (old_current->arch.t4, &dummy)
|
||||
c1 = old_current->find_capability (old_current->arch.t5, &dummy)
|
||||
c2 = old_current->find_capability (old_current->arch.t6, &dummy)
|
||||
c3 = old_current->find_capability (old_current->arch.t7, &dummy)
|
||||
old_current->wait (c0, c1, c2, c3)
|
||||
if !target:
|
||||
// There must be no action here.
|
||||
else:
|
||||
Capability::Context c
|
||||
c.cap[0] = old_current->address_space->find_capability (old_current->arch.a0, &c.copy[0])
|
||||
c.cap[1] = old_current->address_space->find_capability (old_current->arch.a1, &c.copy[1])
|
||||
c.cap[2] = old_current->address_space->find_capability (old_current->arch.a2, &c.copy[2])
|
||||
c.cap[3] = old_current->address_space->find_capability (old_current->arch.a3, &c.copy[3])
|
||||
c.cap[0] = old_current->find_capability (old_current->arch.a0, &c.copy[0])
|
||||
c.cap[1] = old_current->find_capability (old_current->arch.a1, &c.copy[1])
|
||||
c.cap[2] = old_current->find_capability (old_current->arch.a2, &c.copy[2])
|
||||
c.cap[3] = old_current->find_capability (old_current->arch.a3, &c.copy[3])
|
||||
c.data[0] = old_current->arch.t0
|
||||
c.data[1] = old_current->arch.t1
|
||||
c.data[2] = old_current->arch.t2
|
||||
@ -207,7 +213,7 @@ Thread *exception ():
|
||||
break
|
||||
case 9:
|
||||
// Breakpoint.
|
||||
#if 0
|
||||
#if 1
|
||||
current->raise (ERR_BREAKPOINT, 0)
|
||||
#else
|
||||
current->pc += 4
|
||||
@ -216,7 +222,7 @@ Thread *exception ():
|
||||
panic (0, "Break instruction while log capability was already set")
|
||||
break
|
||||
bool dummy
|
||||
dbg_cap = current->address_space->find_capability (current->arch.a1, &dummy)
|
||||
dbg_cap = current->find_capability (current->arch.a1, &dummy)
|
||||
if !dbg_cap:
|
||||
panic (0, "no log capability provided")
|
||||
break
|
||||
|
@ -138,12 +138,11 @@
|
||||
// Map IO memory (requires a priviledged __my_thread capability).
|
||||
#include <iris.h>
|
||||
static void __map_io (unsigned physical, unsigned mapping):
|
||||
Capability page = memory_create_page (__my_memory)
|
||||
memory_create_page (6, __my_memory)
|
||||
// 0 means not cachable; 0 means don't free when done.
|
||||
alloc_physical (page, physical, 0, 0)
|
||||
alloc_physical (6, physical, 0, 0)
|
||||
// 1 means writable.
|
||||
memory_map (__my_memory, page, mapping, 1)
|
||||
drop (page)
|
||||
memory_map (__my_memory, 6, mapping, 1)
|
||||
|
||||
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
|
||||
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
|
||||
|
42
panic.ccp
42
panic.ccp
@ -19,12 +19,13 @@
|
||||
#define ARCH
|
||||
#include "kernel.hh"
|
||||
|
||||
#if 0
|
||||
void dbg_log_char (unsigned ch):
|
||||
if !dbg_cap:
|
||||
return
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.cap[i] = NULL
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
c.data[i] = 0
|
||||
c.data[0] = ch
|
||||
@ -72,3 +73,42 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag
|
||||
dbg_log_num (n)
|
||||
dbg_log_char ('\n')
|
||||
// If no log capability is registered, the machine just hangs.
|
||||
#else
|
||||
void delay (unsigned ms):
|
||||
for unsigned t = 0; t < 8000 * ms; ++t:
|
||||
GPIO_GPDIR (0) = GPIO_GPDIR (0)
|
||||
|
||||
void set_leds (bool a, bool b):
|
||||
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
|
||||
gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
|
||||
if a:
|
||||
GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
|
||||
if b:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
|
||||
|
||||
void dbg_log_char (unsigned ch):
|
||||
void dbg_log (char const *str):
|
||||
void dbg_log_num (unsigned num):
|
||||
void send (unsigned n):
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
bool v = n & (1 << 31)
|
||||
set_leds (v, !v)
|
||||
delay (350)
|
||||
set_leds (false, false)
|
||||
delay (150)
|
||||
n <<= 1
|
||||
set_leds (true, true)
|
||||
delay (50)
|
||||
set_leds (false, false)
|
||||
delay (50)
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message):
|
||||
unsigned epc
|
||||
cp0_get (CP0_EPC, epc)
|
||||
send (epc)
|
||||
while true:
|
||||
send (n)
|
||||
#endif
|
||||
|
@ -176,6 +176,43 @@ windows. In other words, it puts control of the computer from the programmer
|
||||
into the hands of the user (as far as allowed by the system administrator).
|
||||
This is a very good thing.
|
||||
|
||||
\section{Communication}
|
||||
This section shortly describes how communication between threads is performed
|
||||
by Iris. Below are more details about the kernel structures, this section just
|
||||
explains which steps are taken.
|
||||
|
||||
Iris doesn't hold any state about the communication, other than the state that
|
||||
it holds for threads on request of the threads (in the memory paid for by the
|
||||
threads). For Iris, there is no such thing as a \textit{conversation}. There
|
||||
are messages. When there is a conversation, Iris just sees several messages
|
||||
going both ways. For Iris these are not connected\footnote{This is not
|
||||
entirely true; Iris has call capabilities as an optimization feature. They do
|
||||
implement some conversation aspects. But they are only an optimization: Iris
|
||||
doesn't require them to be used.}.
|
||||
|
||||
So understanding communication between threads boils down to understanding the
|
||||
transfer of a single message. A message is short: four 32-bit words of data,
|
||||
plus four capabilities. Besides that, a 64-bit protected value is sent. This
|
||||
value is set by the creator of the capability, usually the server, and cannot
|
||||
be changed by the invoker.
|
||||
|
||||
Sending a message between threads is mostly about a Receiver object. The
|
||||
server has a Receiver, for which it creates a capability (with the mentioned
|
||||
protected data). If a client wants to contact the server, it must get this
|
||||
capability.
|
||||
|
||||
The client then invokes the capability with four data words and four
|
||||
capabilities (possibly set to 0). The message is queued by the receiver. The
|
||||
capabilities are stored into a Caps object.
|
||||
|
||||
When the server is ready for it, it queries the receiver for new messages. It
|
||||
then gets the protected data, the four data words and copies of the
|
||||
capabilities. The ones in the receiver's Caps are invalidated and can be
|
||||
reused after that. Note that it does not get a capability of the sender,
|
||||
unless the sender sends it. There is no way for the server to know who is
|
||||
sending the message, only which capability was used (through the protected
|
||||
data).
|
||||
|
||||
\section{Kernel objects}
|
||||
This section describes all kernel objects of Iris, and the operations that can
|
||||
be performed on them. One operation is possible on any kernel object (except a
|
||||
|
10
schedule.ccp
10
schedule.ccp
@ -62,7 +62,7 @@ static void alarm_tick (Receiver *recv):
|
||||
Capability::Context c
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
c.data[i] = 0
|
||||
c.cap[i] = NULL
|
||||
c.cap[i].reset ()
|
||||
c.copy[i] = false
|
||||
recv->send_message (~0, &c)
|
||||
if recv->prev_alarm:
|
||||
@ -74,10 +74,14 @@ static void alarm_tick (Receiver *recv):
|
||||
// Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm.
|
||||
--recv->alarm_count
|
||||
|
||||
void Thread::wait ():
|
||||
void Thread::wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3):
|
||||
if flags & THREAD_FLAG_RUNNING:
|
||||
unrun_thread (this)
|
||||
flags |= THREAD_FLAG_WAITING
|
||||
rcaps[0] = c0
|
||||
rcaps[1] = c1
|
||||
rcaps[2] = c2
|
||||
rcaps[3] = c3
|
||||
// Try to receive a message from a Receiver immediately.
|
||||
for Receiver *r = receivers; r; r = r->next_owned:
|
||||
if r->try_deliver ():
|
||||
@ -92,6 +96,6 @@ void schedule ():
|
||||
void timer_interrupt ():
|
||||
Receiver *recv, *next
|
||||
for recv = first_alarm; recv; recv = next:
|
||||
next = recv->next
|
||||
next = (Receiver *)recv->next
|
||||
alarm_tick (recv)
|
||||
//schedule ()
|
||||
|
Loading…
Reference in New Issue
Block a user