1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-29 20:23:00 +02:00

reorganize capabilities; doesn't work yet

This commit is contained in:
Bas Wijnen 2009-08-05 10:16:24 +02:00
parent 561535234d
commit fb5a321554
18 changed files with 883 additions and 996 deletions

232
alloc.ccp
View File

@ -25,9 +25,9 @@
// The prev/next-lists contain only objects of one type, unsorted. // The prev/next-lists contain only objects of one type, unsorted.
// All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV. // All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV.
#define PREV(x) (((Object_base **)(x))[-2]) #define PREV(x) (((Object **)(x))[-2])
#define NEXT(x) (((Object_base **)(x))[-1]) #define NEXT(x) (((Object **)(x))[-1])
#define SIZE (2 * sizeof (Object_base *)) #define SIZE (2 * sizeof (Object *))
bool Memory::use (unsigned num): bool Memory::use (unsigned num):
// Go up to parents, incrementing used. // Go up to parents, incrementing used.
@ -52,7 +52,7 @@ void *Memory::search_free (unsigned size, void **first):
Free *f Free *f
unsigned s = 0 unsigned s = 0
// Let's see if there already is a Free chunk which is large enough. // Let's see if there already is a Free chunk which is large enough.
for f = frees; f; f = f->next: for f = frees; f; f = (Free *)f->next:
if NEXT (f): if NEXT (f):
s = (unsigned)NEXT (f) - (unsigned)f s = (unsigned)NEXT (f) - (unsigned)f
else: else:
@ -75,7 +75,7 @@ void *Memory::search_free (unsigned size, void **first):
f->prev = NULL f->prev = NULL
frees = f frees = f
if f->next: if f->next:
f->next->prev = f ((Free *)f->next)->prev = f
// There are no other objects in this page. // There are no other objects in this page.
NEXT (f) = NULL NEXT (f) = NULL
PREV (f) = NULL PREV (f) = NULL
@ -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. // The block was only just large enough: turn it into a new type. It is already linked into the page.
// Unlink it from the free list. // Unlink it from the free list.
if f->prev: if f->prev:
f->prev->next = f->next ((Free *)f->prev)->next = f->next
else: else:
frees = f->next frees = (Free *)f->next
if 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 is now a block which is linked in the page, but not in any list. Link it into first.
f->next = (Free *)*first f->next = (Free *)*first
f->prev = NULL f->prev = NULL
if f->next: if f->next:
f->next->prev = f ((Free *)f->next)->prev = f
*first = f *first = f
// Set common initial values. // Set common initial values.
f->address_space = this f->address_space = this
f->refs = NULL f->refs.reset ()
return f return f
// Free an object; it is still in its list, and it is still in the page list. // Free an object; it is still in its list, and it is still in the page list.
void Memory::free_obj (Object_base *obj, void **first): void Memory::free_obj (Object *obj, Pointer *first):
Free *self = (Free *)obj Free *self = (Free *)obj
// Invalidate references.
while self->refs:
self->refs->invalidate ()
// Free it from its list. // Free it from its list.
if self->prev: if self->prev:
self->prev->next = self->next ((Free *)self->prev)->next = self->next
else: else:
*(Object_base **)first = self->next *(Pointer *)first = (Pointer)self->next
if 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. // Merge with previous, if it exists and is a Free.
if PREV (self) && PREV (self)->is_free (): if PREV (self) && PREV (self)->is_free ():
self = (Free *)PREV (self) self = (Free *)PREV (self)
@ -139,7 +142,7 @@ void Memory::free_obj (Object_base *obj, void **first):
self->next = frees self->next = frees
self->prev = NULL self->prev = NULL
if self->next: if self->next:
self->next->prev = self ((Free *)self->next)->prev = self
frees = self frees = self
// Mark it as a Free. // Mark it as a Free.
self->marker = ~0 self->marker = ~0
@ -148,11 +151,11 @@ void Memory::free_obj (Object_base *obj, void **first):
// Unlink the next from the frees list. // Unlink the next from the frees list.
Free *n = (Free *)NEXT (self) Free *n = (Free *)NEXT (self)
if n->prev: if n->prev:
n->prev->next = n->next ((Free *)n->prev)->next = n->next
else: else:
frees = n->next frees = (Free *)n->next
if n->next: if n->next:
n->next->prev = n->prev ((Free *)n->next)->prev = n->prev
// Unlink the next from the page list. // Unlink the next from the page list.
NEXT (self) = NEXT (NEXT (self)) NEXT (self) = NEXT (NEXT (self))
if NEXT (self): if NEXT (self):
@ -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. // Free page if the resulting object is the only thing in it.
if !PREV (self) && !NEXT (self): if !PREV (self) && !NEXT (self):
if self->next: if self->next:
self->next->prev = self->prev ((Free *)self->next)->prev = self->prev
if self->prev: if self->prev:
self->prev->next = self->next ((Free *)self->prev)->next = self->next
else: else:
frees = self->next frees = (Free *)self->next
pfree ((unsigned)self - SIZE) pfree ((unsigned)self - SIZE)
Page *Memory::alloc_page (): Page *Memory::alloc_page ():
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages) Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages)
if !ret: if !ret:
return NULL return NULL
ret->data.frame = 0 ret->frame = 0
ret->data.flags = 0 ret->flags = 0
return ret return ret
Thread *Memory::alloc_thread (): Thread *Memory::alloc_thread (unsigned size):
Thread *ret = (Thread *)search_free (sizeof (Thread), (void **)&threads) Thread *ret = (Thread *)search_free (sizeof (Thread) + (size - 1) * sizeof (CapsP), (void **)&threads)
if !ret: if !ret:
return NULL return NULL
ret->address_space = this ret->receivers = NULL
ret->pc = 0 ret->pc = 0
ret->sp = 0 ret->sp = 0
Thread_arch_init (ret) Thread_arch_init (ret)
ret->flags = 0 ret->flags = 0
ret->schedule_prev = NULL ret->schedule_prev = NULL
ret->schedule_next = NULL ret->schedule_next = NULL
ret->receivers = NULL for unsigned i = 0; i < size; ++i:
top_memory.alloc_capability (NULL, NULL, NULL, 0, &ret->exception) ret->caps[i] = NULL
return ret return ret
Message *Memory::alloc_message (Receiver *target): Message *Memory::alloc_message (Receiver *target):
@ -206,55 +209,21 @@ Receiver *Memory::alloc_receiver ():
ret->prev_owned = NULL ret->prev_owned = NULL
ret->next_owned = NULL ret->next_owned = NULL
ret->alarm_count = ~0 ret->alarm_count = ~0
ret->capabilities = NULL ret->caps = NULL
ret->capabilities.reset ()
ret->messages = NULL ret->messages = NULL
ret->last_message = NULL ret->last_message = NULL
ret->reply_protected_data = ~0 ret->reply_protected_data = ~0
ret->protected_only = false ret->protected_only = false
return ret return ret
Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret): Caps *Memory::alloc_caps (unsigned size):
if !ret: Caps *ret = (Caps *)search_free (sizeof (Caps) + (size - 1) * sizeof (Capability), (void **)&capses)
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)
if !ret: if !ret:
return NULL return NULL
ret->data.frame = zalloc () ret->size = size
if !ret->data.frame: for unsigned i = 0; i < size; ++i:
free_cappage (ret) ret->set (i, NULL, 0, CapRef (), NULL)
return NULL
ret->data.flags = 0
return ret return ret
Memory *Memory::alloc_memory (): Memory *Memory::alloc_memory ():
@ -264,32 +233,59 @@ Memory *Memory::alloc_memory ():
ret->frees = NULL ret->frees = NULL
ret->pages = NULL ret->pages = NULL
ret->threads = NULL ret->threads = NULL
ret->capses = NULL
ret->receivers = NULL
ret->memories = NULL ret->memories = NULL
ret->limit = ~0 ret->limit = ~0
ret->used = 0 ret->used = 0
Memory_arch_init (ret) Memory_arch_init (ret)
return 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): void Memory::free_page (Page *page):
if page->data.flags & PAGE_FLAG_PAYING: if page->flags & PAGE_FLAG_PAYING:
unuse () unuse ()
if page->data.frame: if page->frame:
pfree (page->data.frame) pfree (page->frame)
free_obj (page, (void **)&pages) free_obj (page, (Pointer *)&pages)
void Memory::free_thread (Thread *thread): void Memory::free_thread (Thread *thread):
thread->unrun () thread->unrun ()
while thread->receivers: while thread->receivers:
thread->receivers->orphan () thread->receivers->orphan ()
thread->exception.invalidate ()
free_obj (thread, (void **)&threads) free_obj (thread, (void **)&threads)
void Memory::free_message (Receiver *owner, Message *message): void Memory::free_message (Receiver *owner, Message *message):
if !message->next: if !message->next:
owner->last_message = message->prev owner->last_message = (MessageP)message->prev
for unsigned i = 0; i < 4; ++i:
if message->capabilities[i]:
free_capability (message->capabilities[i])
free_obj (message, (void **)&owner->messages) free_obj (message, (void **)&owner->messages)
void Memory::free_receiver (Receiver *receiver): void Memory::free_receiver (Receiver *receiver):
@ -318,10 +314,6 @@ void Receiver::own (Thread *o):
next_owned->prev_owned = this next_owned->prev_owned = this
o->receivers = this o->receivers = this
void Memory::free_capability (Capability *capability):
capability->invalidate ()
free_obj (capability, (void **)&capabilities)
void Capability::invalidate (): void Capability::invalidate ():
if !target: if !target:
return return
@ -330,78 +322,60 @@ void Capability::invalidate ():
else if (unsigned)target & ~KERNEL_MASK: else if (unsigned)target & ~KERNEL_MASK:
target->capabilities = sibling_next target->capabilities = sibling_next
else: else:
((Object_base *)protected_data)->refs = sibling_next ((Object *)protected_data)->refs = sibling_next
if sibling_next: if sibling_next:
sibling_next->sibling_prev = sibling_prev sibling_next->sibling_prev = sibling_prev
parent = NULL parent.reset ()
sibling_prev = NULL sibling_prev.reset ()
sibling_next = NULL sibling_next.reset ()
Capability *c = this Capability *c = this
while c->children:
c = c->children
while c: while c:
Capability *next = c->sibling_next while c->children:
c = c->children.deref ()
Capability *next = c->sibling_next.deref ()
if !next: if !next:
next = c->parent next = c->parent.deref ()
c->target = NULL c->target = NULL
c->parent = NULL c->parent.reset ()
c->children = NULL c->children.reset ()
c->sibling_prev = NULL c->sibling_prev.reset ()
c->sibling_next = NULL c->sibling_next.reset ()
c->protected_data = 0 c->protected_data = 0
c = next c = next
void Memory::free_cappage (Cappage *p): void Memory::free_caps (Caps *c):
for unsigned i = 0; i < CAPPAGE_SIZE; ++i: for unsigned i = 0; i < c->size; ++i:
((Capability *)p->data.frame)[i].invalidate () c->caps[i].invalidate ()
zfree (p->data.frame) free_obj (c, (void **)&capses)
free_obj (p, (void **)&cappages)
void Memory::free_memory (Memory *mem): void Memory::free_memory (Memory *mem):
while mem->pages: while mem->pages:
free_page (mem->pages) free_page (mem->pages)
while mem->cappages: while mem->capses:
free_cappage (mem->cappages) free_caps (mem->capses)
while mem->threads: while mem->threads:
free_thread (mem->threads) free_thread (mem->threads)
while mem->memories: while mem->memories:
free_memory (mem->memories) free_memory (mem->memories)
while mem->receivers: while mem->receivers:
free_receiver (mem->receivers) free_receiver (mem->receivers)
while mem->capabilities:
free_capability (mem->capabilities)
Memory_arch_free (mem) Memory_arch_free (mem)
if mem->frees: if mem->frees:
panic (0, "kernel memory leak: memory still in use") panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories) free_obj (mem, (void **)&memories)
void Page::forget (): void Page::forget ():
if data.share_prev || data.share_next: if share_prev || share_next:
if data.share_prev: if share_prev:
((Page *)data.share_prev)->data.share_next = data.share_next share_prev->share_next = share_next
if data.share_next: if share_next:
((Page *)data.share_next)->data.share_prev = data.share_prev share_next->share_prev = share_prev
data.share_prev = NULL share_prev = NULL
data.share_next = NULL share_next = NULL
else: else:
// If the page has a frame and should be freed, free it. // If the page has a frame and should be freed, free it.
if !((data.flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)): if !((flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)):
raw_pfree (data.frame) raw_pfree (frame)
data.frame = 0 frame = 0
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
Page_arch_update_mapping (this) 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)

View File

@ -30,16 +30,6 @@ __hack_label:
.word _gp .word _gp
1: 1:
lw $gp, 0($ra) 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 $t9, main
la $ra, 1f la $ra, 1f
jr $t9 jr $t9
@ -49,9 +39,3 @@ __hack_label:
// This should not be reached: generate an address fault. // This should not be reached: generate an address fault.
b 1b b 1b
lw $a0, -4($zero) lw $a0, -4($zero)
.comm __my_receiver, 4
.comm __my_thread, 4
.comm __my_memory, 4
.comm __my_call, 4
.comm __my_parent, 4

View File

@ -24,19 +24,25 @@
// This shouldn't really be here. But where should it be? // This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves. // Requests made by initial threads to tell init about themselves.
enum init_requests: enum init_requests:
INIT_SET_GPIO_0 INIT_SET_GPIO
INIT_SET_GPIO_1
INIT_SET_LCD INIT_SET_LCD
// Keyboard interface. // 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. // 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): static __inline__ void keyboard_set_cb (Capability kbd, Capability cb):
invoke_10 (kbd_set_cb, cb) invoke_11 (kbd, cb, KEYBOARD_SET_CB)
// At event: the callback is called with a keycode. One bit defines if it's a press or release event. // At event: the callback is called with a keycode. One bit defines if it's a press or release event.
#define KEYBOARD_RELEASE (1 << 31) #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. // 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): static __inline__ void file_close (Capability file):
invoke_01 (file, FILE_CLOSE) 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. // 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): static __inline__ void file_copy_handle (Capability target, Capability file):
return call_c01 (file, FILE_COPY_HANDLE) call_c01 (file, target, FILE_COPY_HANDLE)
// Directory interface. // Directory interface.
// Get the number of entries in this directory. // 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): 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) return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32)
// Get the file. // Get the file.
static __inline__ Capability directory_get_file (Capability dir, unsigned long long idx, Capability page): static __inline__ void directory_get_file (Capability target, Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32) 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. // 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): 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) 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. // 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): static __inline__ void directory_create_file (Capability target, Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32) call_c03 (dir, target, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
// Delete a file. After this, any index may map to a different file. // Delete a file. After this, any index may map to a different file.
static __inline__ Capability directory_delete_file (Capability dir, unsigned long long idx, Capability page): static __inline__ void directory_delete_file (Capability target, Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32) call_c03 (dir, target, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
// Stream interface. // Stream interface.
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE. // 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) return call_n00 (blk_get_size)
// Get file capability. Returns a seekable mappable non-stream file. // Get file capability. Returns a seekable mappable non-stream file.
static __inline__ Capability block_get_file (Capability blk_get_file): static __inline__ void block_get_file (Capability target, Capability blk_get_file):
call_c00 (blk_get_file) call_c00 (blk_get_file, target)

View File

@ -20,8 +20,8 @@
#define ARCH #define ARCH
#include "arch.hh" #include "arch.hh"
// Interval between polls for keyboard (when keys are pressed) and battery/power (always) events // Interval between polls for keyboard events (when keys are pressed)
#define ALARM_INTERVAL (HZ / 20) #define ALARM_INTERVAL (HZ / 50)
// GPIO pins for the devices (port.pin) // GPIO pins for the devices (port.pin)
@ -42,13 +42,6 @@
// Scroll lock: 0.9 // Scroll lock: 0.9
// interrupts: no, output only. // 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 // interrupt summary
// Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad // Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad
// Port 1: None. // Port 1: None.
@ -58,43 +51,28 @@
enum event_type: enum event_type:
KEYBOARD_EVENT KEYBOARD_EVENT
TOUCHPAD_EVENT TOUCHPAD_EVENT
POWERBUTTON_EVENT
BATTERY_EVENT
NUM_EVENTS NUM_EVENTS
enum cap_type: enum cap_type:
CAP_KEYBOARD = 32 CAP_KEYBOARD = 32
CAP_TOUCHPAD CAP_TOUCHPAD
CAP_POWEROFF
CAP_POWERBUTTON
CAP_BATTERY
CAP_LOCKLEDS CAP_LOCKLEDS
CAP_PWM CAP_PWM
static Capability cbs[NUM_EVENTS]
static void event (event_type type, unsigned data): static void event (event_type type, unsigned data):
if !cbs[type]: invoke_01 (11 + type, data)
return
invoke_01 (cbs[type], data)
static void set_cb (event_type type, Capability cb): static void set_cb (event_type type):
if cbs[type]: capability_clone (11 + type, 6)
drop (cbs[type])
cbs[type] = cb
enum battery_type:
BATTERY_ABSENT
BATTERY_CHARGING
BATTERY_CHARGED
class Keyboard: class Keyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
unsigned keys[GPIO_KBD_NUM_COLS] unsigned keys[GPIO_KBD_NUM_COLS]
bool scanning bool scanning
void parse (unsigned col, unsigned data): void parse (unsigned col, unsigned data):
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row: for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
if (data ^ keys[col]) & (1 << row): if (data ^ keys[col]) & (1 << row):
unsigned code = (col << 3) | row unsigned code = encode[col][row]
if data & (1 << row): if data & (1 << row):
code |= KEYBOARD_RELEASE code |= KEYBOARD_RELEASE
event (KEYBOARD_EVENT, code) event (KEYBOARD_EVENT, code)
@ -115,32 +93,38 @@ class Keyboard:
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
// Set scanning to false before first parse. // Set scanning to false before first parse.
scanning = false 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: for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
// clear pin // Set pin to output.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// output
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col]) 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]) 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 unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
// Generate events.
parse (col, data) parse (col, data)
// set pin // Set pin to get rid of capacitance effects.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col]) GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
// input // Delay to make the above trick work.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir 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. // set all to 0.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// set all to output. // set all to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK 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) unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
for unsigned i = 0; i < 8; ++i: for unsigned i = 0; i < 8; ++i:
if data & (1 << i): if data & (1 << i):
gpio_irq_fall (GPIO_KBD_ROW_PORT, i) gpio_irq_low (GPIO_KBD_ROW_PORT, i)
else: else:
gpio_irq_rise (GPIO_KBD_ROW_PORT, i) gpio_irq_high (GPIO_KBD_ROW_PORT, i)
// Clear pending interrupts.
GPIO_GPFR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
// Reenable interrupts. // Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
Keyboard (): Keyboard ():
@ -151,11 +135,43 @@ class Keyboard:
// Set all rows to input and enable the pull-ups. // Set all rows to input and enable the pull-ups.
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// Initialize matrix. // Initialize things in the same way as when a new callback is set up.
for unsigned i = 0; i < GPIO_KBD_NUM_COLS; ++i: send_initial ()
keys[i] = 0xff void send_initial ():
// Perform initial scan to get real values into matrix and set up the rest. for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
keys[col] = 0xff
scan () 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: class Touchpad:
unsigned old_state unsigned old_state
@ -163,33 +179,35 @@ class Touchpad:
void check_events (): void check_events ():
unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT) unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
if state & (1 << GPIO_TP_LEFT): 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): if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0) event (TOUCHPAD_EVENT, 0)
else: 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): if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0x10000) event (TOUCHPAD_EVENT, 0x10000)
if state & (1 << GPIO_TP_RIGHT): 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): if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 1) event (TOUCHPAD_EVENT, 1)
else: 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): if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 0x10001) event (TOUCHPAD_EVENT, 0x10001)
old_state = state old_state = state
// Ack interrupts. // 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 (): Touchpad ():
// Set pins to input with pull-ups. // Set pins to input with pull-ups.
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT) gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT) gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << 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 old_state = 0
// See if they are already pressed. Also set up interrupts.
check_events () check_events ()
// Now enable the interrupts. event (TOUCHPAD_EVENT, ~0)
class Lockleds: class Lockleds:
// Note that num lock is in port 2. The others are in port 0. // Note that num lock is in port 2. The others are in port 0.
@ -215,58 +233,6 @@ class Lockleds:
else: else:
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL 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. // Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
class Pwm: class Pwm:
public: public:
@ -288,43 +254,39 @@ class Pwm:
int main (): int main ():
map_gpio () map_gpio ()
map_pwm0 () map_pwm0 ()
map_wdt ()
map_i2c ()
Keyboard kbd Keyboard kbd
Touchpad tp Touchpad tp
Lockleds leds Lockleds leds
Power power
Pwm pwm Pwm pwm
// Enable interrupts. All are in port 0. // Enable interrupts. All are in port 0.
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
register_interrupt (IRQ_GPIO0) register_interrupt (IRQ_GPIO0)
Capability cap_kbd = receiver_create_capability (__my_receiver, CAP_KEYBOARD) Capability cap_kbd = 7
Capability cap_tp = receiver_create_capability (__my_receiver, CAP_TOUCHPAD) Capability cap_tp = 8
Capability cap_poweroff = receiver_create_capability (__my_receiver, CAP_POWEROFF) Capability cap_lockleds = 9
Capability cap_powerbutton = receiver_create_capability (__my_receiver, CAP_POWERBUTTON) Capability cap_pwm = 10
Capability cap_battery = receiver_create_capability (__my_receiver, CAP_BATTERY) receiver_create_capability (cap_kbd, __my_receiver, CAP_KEYBOARD)
Capability cap_lockleds = receiver_create_capability (__my_receiver, CAP_LOCKLEDS) receiver_create_capability (cap_tp, __my_receiver, CAP_TOUCHPAD)
Capability cap_pwm = receiver_create_capability (__my_receiver, CAP_PWM) 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_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO)
invoke_31 (__my_parent, cap_copy (cap_battery), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO_1)
receiver_set_alarm (__my_receiver, ALARM_INTERVAL) if kbd.is_scanning ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
while true: while true:
schedule () schedule ()
Message msg Message msg
wait (&msg) wait (&msg, 6, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
switch msg.protected_data: switch msg.protected_data:
case ~0: case ~0:
// Alarm. // Alarm.
// Periodically scan several devices. kbd.scan ()
if kbd.is_scanning (): if kbd.is_scanning ():
kbd.scan () receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
power.poll ()
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
break break
case IRQ_GPIO0: case IRQ_GPIO0:
// Always scan keyboard and touchpad on any interrupt. // Always scan keyboard and touchpad on any interrupt.
@ -334,22 +296,12 @@ int main ():
register_interrupt (IRQ_GPIO0) register_interrupt (IRQ_GPIO0)
break break
case CAP_KEYBOARD: case CAP_KEYBOARD:
set_cb (KEYBOARD_EVENT, msg.cap[0]) set_cb (KEYBOARD_EVENT)
kbd.send_initial ()
break break
case CAP_TOUCHPAD: case CAP_TOUCHPAD:
set_cb (TOUCHPAD_EVENT, msg.cap[0]) set_cb (TOUCHPAD_EVENT)
break tp.send_initial ()
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])
break break
case CAP_LOCKLEDS: case CAP_LOCKLEDS:
leds.set (msg.data[0]) leds.set (msg.data[0])

View File

@ -19,53 +19,46 @@
#include "devices.hh" #include "devices.hh"
#include "iris.h" #include "iris.h"
static Capability kbd, tp, poweroff, powerbutton, battery, lockleds, pwm, lcd static Capability kbd, tp, lockleds, pwm, lcd
enum type: enum type:
KBD = 0x10000 KBD = 0x10000
TP TP
POWERBUTTON
BATTERY
static void send (Capability c, unsigned d): static void send (Capability c, unsigned d):
Capability n = receiver_create_capability (__my_receiver, d) receiver_create_capability (6, __my_receiver, d)
invoke_10 (c, cap_copy (n)) invoke_10 (c, cap_copy (6))
drop (n)
static void setup (): static void setup ():
unsigned state = 0 unsigned state = 0
Capability base = 7
while true: while true:
Message msg Message msg
wait (&msg) wait (&msg, base, base + 1, base + 2, base + 3)
switch msg.data[0]: switch msg.data[0]:
case INIT_SET_GPIO_0: case INIT_SET_GPIO:
kdebug ("gpio 0\n") kdebug ("gpio\n")
kbd = msg.cap[0] kbd = base
tp = msg.cap[1] tp = base + 1
poweroff = msg.cap[2] lockleds = base + 2
powerbutton = msg.cap[3] pwm = base + 3
++state base += 4
break
case INIT_SET_GPIO_1:
kdebug ("gpio 1\n")
battery = msg.cap[0]
lockleds = msg.cap[1]
pwm = msg.cap[2]
++state ++state
break break
case INIT_SET_LCD: case INIT_SET_LCD:
kdebug ("lcd\n") kdebug ("lcd\n")
lcd = msg.cap[0] lcd = base
++base
++state ++state
break break
if state == 3: if state == 2:
break break
send (kbd, KBD) send (kbd, KBD)
send (tp, TP) send (tp, TP)
send (powerbutton, POWERBUTTON)
send (battery, BATTERY)
invoke_01 (pwm, 1) invoke_01 (pwm, 1)
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
int main (): int main ():
// Set up lcd first // Set up lcd first
schedule () schedule ()
@ -74,12 +67,13 @@ int main ():
kdebug ("run init\n") kdebug ("run init\n")
while true: while true:
Message msg Message msg
wait (&msg) wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
switch msg.protected_data: switch msg.protected_data:
case KBD: case KBD:
kdebug ("keyboard event: ") unsigned code = msg.data[0]
kdebug_num (msg.data[0]) if code & KEYBOARD_RELEASE:
kdebug_char ('\n') break
kdebug_char (decode_kbd[code])
break break
case TP: case TP:
unsigned leds = 0 unsigned leds = 0
@ -91,9 +85,3 @@ int main ():
leds |= 0x2 leds |= 0x2
invoke_01 (lockleds, leds) invoke_01 (lockleds, leds)
break break
case POWERBUTTON:
kdebug ("powerbutton event\n")
break
case BATTERY:
kdebug ("battery event\n")
break

View File

@ -121,30 +121,23 @@ static void log_msg (Message *msg):
log_char ('\n') log_char ('\n')
int main (): int main ():
__asm__ volatile ("break")
map_lcd () map_lcd ()
map_cpm () map_cpm ()
Descriptor descriptor __attribute__ ((aligned (16))) Descriptor descriptor __attribute__ ((aligned (16)))
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
assert (pages > CAPPAGE_SIZE && pages <= 2 * CAPPAGE_SIZE)
unsigned physical = alloc_range (__my_memory, pages) unsigned physical = alloc_range (__my_memory, pages)
assert (physical) assert (physical)
//Capability cappage[2] //Capability cappage[2]
//unsigned base[2] //unsigned base[2]
//cappage[0] = memory_create_cappage (__my_memory, &base[0]) //cappage[0] = memory_create_cappage (__my_memory, &base[0])
//cappage[1] = memory_create_cappage (__my_memory, &base[1]) //cappage[1] = memory_create_cappage (__my_memory, &base[1])
for unsigned i = 0; i < CAPPAGE_SIZE; ++i: for unsigned i = 0; i < pages; ++i:
Capability page = memory_create_page (__my_memory) memory_create_page (6, __my_memory)
//cappage_set (cappage[0], page, i) alloc_physical (6, physical + i * PAGE_SIZE, 0, 1)
alloc_physical (page, physical + i * PAGE_SIZE, 0, 1) memory_map (__my_memory, 6, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 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 y = 0; y < 480; ++y: for unsigned y = 0; y < 480; ++y:
unsigned g = (y << 6) / 480 unsigned g = (y << 6) / 480
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480) unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
@ -161,8 +154,8 @@ int main ():
ob = b ob = b
b = 0x1f b = 0x1f
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b) LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
Capability page = memory_mapping (__my_memory, &descriptor) memory_mapping (6, __my_memory, &descriptor)
unsigned physical_descriptor = page_physical_address (page) + ((unsigned)&descriptor & ~PAGE_MASK) unsigned physical_descriptor = page_physical_address (cap_copy (6)) + ((unsigned)&descriptor & ~PAGE_MASK)
descriptor.next = physical_descriptor descriptor.next = physical_descriptor
descriptor.frame = physical descriptor.frame = physical
descriptor.id = 0xdeadbeef descriptor.id = 0xdeadbeef
@ -173,16 +166,15 @@ int main ():
Capability eof_cb = 0 Capability eof_cb = 0
Capability cap = receiver_create_capability (__my_receiver, LCD_EOF_CB) receiver_create_capability (6, __my_receiver, LCD_EOF_CB)
invoke_11 (__my_parent, cap, INIT_SET_LCD) invoke_11 (__my_parent, cap_copy (6), INIT_SET_LCD)
drop (cap)
Capability logcap = receiver_create_capability (__my_receiver, LCD_LOG) receiver_create_capability (15, __my_receiver, LCD_LOG)
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap) : "a0", "a1", "memory") __asm__ volatile ("li $a0, 1\nlw $a1, 15\nbreak" ::: "a0", "a1", "memory")
while true: while true:
Message msg Message msg
wait (&msg) wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
//log_msg (&msg) //log_msg (&msg)
switch msg.protected_data: switch msg.protected_data:
case IRQ_LCD: case IRQ_LCD:
@ -192,8 +184,6 @@ int main ():
invoke_00 (eof_cb) invoke_00 (eof_cb)
break break
case LCD_EOF_CB: case LCD_EOF_CB:
if eof_cb:
drop (eof_cb)
eof_cb = msg.cap[0] eof_cb = msg.cap[0]
if eof_cb: if eof_cb:
register_interrupt (IRQ_LCD) register_interrupt (IRQ_LCD)

View File

@ -19,6 +19,7 @@
#include "kernel.hh" #include "kernel.hh"
void Thread::raise (unsigned code, unsigned data): void Thread::raise (unsigned code, unsigned data):
panic (code, "raise")
dbg_log ("raise ") dbg_log ("raise ")
dbg_log_num ((unsigned)current) dbg_log_num ((unsigned)current)
dbg_log_char ('/') dbg_log_char ('/')
@ -31,47 +32,32 @@ void Thread::raise (unsigned code, unsigned data):
dbg_log_num (data) dbg_log_num (data)
dbg_log_char ('\n') dbg_log_char ('\n')
unrun () unrun ()
if !exception.target: if !caps[0] || !caps[0]->caps[0].target:
return return
Capability::Context c Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL c.cap[i] = CapRef ()
c.copy[i] = false c.copy[i] = false
c.data[0] = code c.data[0] = code
c.data[1] = data c.data[1] = data
c.data[2] = 0 c.data[2] = 0
c.data[3] = 0 c.data[3] = 0
exception.invoke (&c) caps[0]->caps[0].invoke (&c)
// From user-provided, thus untrusted, data, find a capability. // From user-provided, thus untrusted, data, find a capability.
Capability *Memory::find_capability (unsigned code, bool *copy): CapRef Thread::find_capability (unsigned code, bool *copy):
*copy = code & 2 ? true : false *copy = code & CAPABILITY_COPY
if !(code & ~3): unsigned c = code & ~CAPABILITY_COPY
return NULL unsigned slot = c >> 16
if code & 1: unsigned num = c & 0xffff
// Cappage capability if slot >= slots || !caps[slot] || num >= caps[slot]->size || !caps[slot]->caps[num].target:
unsigned num = (code & ~PAGE_MASK) >> 2 if c != CAPABILITY_NONE:
if num >= CAPPAGE_SIZE:
dbg_log_num ((unsigned)old_current) dbg_log_num ((unsigned)old_current)
dbg_log (": invalid cappage index ") dbg_log (": invalid capability ")
dbg_log_num (num) dbg_log_num (code)
dbg_log_char ('\n') dbg_log_char ('\n')
return NULL return CapRef ()
unsigned page = code & PAGE_MASK return CapRef (caps[slot], num)
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
// Try to deliver a message. // Try to deliver a message.
bool Receiver::try_deliver (): bool Receiver::try_deliver ():
@ -81,148 +67,125 @@ bool Receiver::try_deliver ():
return false return false
Message *m = last_message Message *m = last_message
if protected_only: if protected_only:
for ; m; m = m->prev: for ; m; m = (Message *)m->prev:
if m->protected_data == reply_protected_data: if m->protected_data == reply_protected_data:
protected_only = false protected_only = false
break break
if !m: if !m:
return false return false
Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.data[i] = m->data[i] if owner->rcaps[i]:
if m->capabilities[i]: owner->rcaps[i]->invalidate ()
c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true) if m->capabilities[i] < caps->size:
if !c.cap[i]: owner->rcaps[i].clone (CapRef (caps, m->capabilities[i]), true)
owner->raise (ERR_OUT_OF_MEMORY, 0) Thread_arch_receive (owner, m->protected_data, m->data)
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)
address_space->free_message (this, m) address_space->free_message (this, m)
owner->unwait () owner->unwait ()
return true return true
// Send a message to a receiver; try to deliver it immediately. // Send a message to a receiver; try to deliver it immediately.
bool Receiver::send_message (unsigned protected_data, Capability::Context *c): 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): if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
Capability *orig[4] if protected_only:
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:
protected_only = false 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 () owner->unwait ()
return true return true
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. // 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) Message *msg = address_space->alloc_message (this)
if !msg: if !msg:
if owner: if owner:
// TODO: avoid loops.
owner->raise (ERR_OUT_OF_MEMORY, 0) owner->raise (ERR_OUT_OF_MEMORY, 0)
return false return false
msg->protected_data = protected_data 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. // Put this message in the end (where it will be first seen). Clear the protected_only flag.
protected_only = false protected_only = false
if msg->next: if msg->next:
msg->next->prev = NULL ((Message *)msg->next)->prev = NULL
messages = msg->next messages = (Message *)msg->next
msg->next = NULL msg->next = NULL
msg->prev = last_message msg->prev = last_message
msg->prev->next = msg ((Message *)msg->prev)->next = msg
last_message = msg last_message = msg
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
msg->data[i] = c->data[i] msg->data[i] = c->data[i]
if !c->cap[i]: if !c->cap[i] || !caps:
msg->capabilities[i] = NULL msg->capabilities[i] = 0xff
else: else:
msg->capabilities[i] = address_space->clone_capability (c->cap[i], c->copy[i]) unsigned t
if !msg->capabilities[i]: 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: if owner:
// TODO: avoid loops.
owner->raise (ERR_OUT_OF_MEMORY, 0) owner->raise (ERR_OUT_OF_MEMORY, 0)
for unsigned j = 0; j < i; ++j: 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) address_space->free_message (this, msg)
return false return false
msg->capabilities[i] = t
caps->clone (t, c->cap[i], c->copy[i])
return true return true
static Capability *reply static Capability *reply
static Receiver *reply_receiver static Receiver *reply_receiver
static void fill_cap (Capability *r, unsigned target, unsigned protected_data): static void fill_cap (CapRef r, unsigned target, unsigned protected_data):
Capability **ref CapRef *ref
if target & ~KERNEL_MASK: if target & ~KERNEL_MASK:
ref = &((Receiver *)target)->capabilities ref = &((Receiver *)target)->capabilities
else: else:
ref = &((Object_base *)protected_data)->refs ref = &((Object *)protected_data)->refs
// alloc_capability needs a Memory, but it isn't used if return storage is given. r.set ((Receiver *)target, protected_data, CapRef (), ref)
top_memory.alloc_capability ((Receiver *)target, NULL, ref, protected_data, r)
static void reply_cap (unsigned target, unsigned protected_data): static void reply_cap (unsigned target, unsigned protected_data):
Capability r Caps r
fill_cap (&r, target, protected_data) fill_cap (CapRef (&r, 0), target, protected_data)
Capability::Context c Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.data[i] = 0 c.data[i] = 0
c.cap[0] = &r c.cap[0] = CapRef (&r, 0)
c.copy[0] = true c.copy[0] = true
for unsigned i = 1; i < 4; ++i: for unsigned i = 1; i < 4; ++i:
c.cap[i] = NULL c.cap[i].reset ()
c.copy[i] = false c.copy[i] = false
if reply: if reply:
reply->invoke (&c) reply->invoke (&c)
else if reply_receiver: else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c) 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 Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.data[i] = 0 c.data[i] = 0
c.cap[0] = cap c.cap[0] = cap
c.copy[0] = copy c.copy[0] = copy
for unsigned i = 1; i < 4; ++i: for unsigned i = 1; i < 4; ++i:
c.cap[i] = NULL c.cap[i].reset ()
c.copy[i] = false c.copy[i] = false
if reply: if reply:
reply->invoke (&c) reply->invoke (&c)
else if reply_receiver: else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c) 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): static void reply_num (unsigned num):
Capability::Context c Capability::Context c
c.data[0] = num c.data[0] = num
for unsigned i = 1; i < 4; ++i: for unsigned i = 1; i < 4; ++i:
c.data[i] = 0 c.data[i] = 0
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL c.cap[i].reset ()
c.copy[i] = false c.copy[i] = false
if reply: if reply:
reply->invoke (&c) reply->invoke (&c)
@ -236,7 +199,7 @@ static void reply_nums (unsigned num1, unsigned num2):
c.data[2] = 0 c.data[2] = 0
c.data[3] = 0 c.data[3] = 0
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL c.cap[i].reset ()
c.copy[i] = false c.copy[i] = false
if reply: if reply:
reply->invoke (&c) reply->invoke (&c)
@ -313,7 +276,7 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
reply_num (0) reply_num (0)
break break
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
Thread *ret = mem->alloc_thread () Thread *ret = mem->alloc_thread (c->data[2])
if ret: if ret:
reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret) reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret)
else: else:
@ -326,10 +289,10 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
else: else:
reply_num (0) reply_num (0)
break break
case CAPTYPE_CAPPAGE: case CAPTYPE_CAPS:
Cappage *ret = mem->alloc_cappage () Caps *ret = mem->alloc_caps (c->data[2])
if ret: if ret:
reply_cappage (ret, CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS)) reply_cap (CAPTYPE_CAPS | (rights & CAP_CAPS_ALL_RIGHTS), (unsigned)ret)
else: else:
reply_num (0) reply_num (0)
break break
@ -352,11 +315,8 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
mem->free_page ((Page *)c->cap[0]->protected_data) mem->free_page ((Page *)c->cap[0]->protected_data)
break break
case CAPTYPE_CAPABILITY: case CAPTYPE_CAPS:
mem->free_capability ((Capability *)c->cap[0]->protected_data) mem->free_caps ((Caps *)c->cap[0]->protected_data)
break
case CAPTYPE_CAPPAGE:
mem->free_cappage ((Cappage *)c->cap[0]->protected_data)
break break
default: default:
panic (0x55228930, "invalid case") panic (0x55228930, "invalid case")
@ -388,11 +348,6 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
if c->data[2]: if c->data[2]:
mem->limit = c->data[1] mem->limit = c->data[1]
break break
case CAP_MEMORY_DROP:
if !c->cap[0] || c->cap[0]->address_space != mem:
break
mem->free_capability (c->cap[0])
break
default: default:
break 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]) 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) != (*value & THREAD_FLAG_WAITING):
if v & THREAD_FLAG_WAITING: if v & THREAD_FLAG_WAITING:
thread->wait () thread->wait (CapRef (), CapRef (), CapRef (), CapRef ())
else else
thread->unwait () thread->unwait ()
if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING): 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: case CAP_THREAD_SCHEDULE:
do_schedule = true do_schedule = true
break break
case CAP_THREAD_REGISTER_INTERRUPT: case CAP_THREAD_CAP_CLONE:
// Threads with access to this call are trusted, so no sanity checking is done. reply_cap (c->cap[0], c->copy[0])
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)
break 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: default:
break break
static bool page_check_payment (Page *page): static bool page_check_payment (Page *page):
Page *p Page *p
for p = (Page *)page->data.share_prev; p; p = (Page *)p->data.share_prev: for p = page->share_prev; p; p = p->share_prev:
if p->data.flags & PAGE_FLAG_PAYING: if p->flags & PAGE_FLAG_PAYING:
return true return true
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next: for p = page->share_next; p; p = p->share_next:
if p->data.flags & PAGE_FLAG_PAYING: if p->flags & PAGE_FLAG_PAYING:
return true return true
// No Page is paying for this frame anymore. // No Page is paying for this frame anymore.
raw_pfree (page->data.frame) raw_pfree (page->frame)
Page *next Page *next
for p = (Page *)page->data.share_prev, next = (Page *)p->data.share_prev; p; p = next, next = (Page *)p->data.share_prev: for p = page->share_prev, next = p->share_prev; p; p = next, next = p->share_prev:
p->data.frame = NULL p->frame = NULL
p->data.share_prev = NULL p->share_prev = NULL
p->data.share_next = NULL p->share_next = NULL
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) p->flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
Page_arch_update_mapping (p) Page_arch_update_mapping (p)
for p = page, next = (Page *)p->data.share_next; p; p = next, next = (Page *)p->data.share_next: for p = page, next = p->share_next; p; p = next, next = p->share_next:
p->data.frame = NULL p->frame = NULL
p->data.share_prev = NULL p->share_prev = NULL
p->data.share_next = NULL p->share_next = NULL
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) p->flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
Page_arch_update_mapping (p) Page_arch_update_mapping (p)
return false 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): static void page_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
Page *page Page *page = (Page *)protected_data
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
switch c->data[0]: switch c->data[0]:
case CAP_PAGE_SHARE: 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. // FIXME: This makes it impossible to use a fake Page capability.
break break
if page: Page *t = (Page *)c->cap[0]->protected_data
Page *t = (Page *)c->cap[0]->protected_data t->forget ()
t->forget () if c->data[1] & PAGE_SHARE_READONLY:
if c->data[1] & PAGE_SHARE_READONLY: t->flags &= ~PAGE_FLAG_WRITABLE
t->data.flags &= ~PAGE_FLAG_WRITABLE if !page->flags & PAGE_FLAG_FRAME:
if !page->data.flags & PAGE_FLAG_FRAME: break
if c->data[1] & PAGE_SHARE_COPY:
if ~t->flags & PAGE_FLAG_PAYING:
break break
if c->data[1] & PAGE_SHARE_COPY: if ~c->data[1] & PAGE_SHARE_FORGET || page->flags & PAGE_FLAG_SHARED:
if ~t->data.flags & PAGE_FLAG_PAYING: unsigned *d = (unsigned *)page->frame
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 t == page: if t == page:
break Page *other = page->share_next ? page->share_next : page->share_prev
if c->data[1] & PAGE_SHARE_FORGET: if !other:
if ~page->data.flags & PAGE_FLAG_SHARED: Page_arch_update_mapping (t)
if t->data.flags & PAGE_FLAG_PAYING: break
t->data.frame = page->data.frame if page->share_next:
t->data.flags |= PAGE_FLAG_FRAME page->share_next->share_prev = page->share_prev
page->data.frame = NULL if page->share_prev:
page->data.flags &= ~PAGE_FLAG_FRAME page->share_prev->share_next = page->share_next
Page_arch_update_mapping (page) page->share_next = NULL
else: page->share_prev = NULL
t->data.share_prev = page->data.share_prev page_check_payment (other)
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)
else: else:
t->data.share_prev = page->data.share_prev t->flags |= PAGE_FLAG_FRAME
t->data.share_next = page t->frame = raw_zalloc ()
page->data.share_prev = t for unsigned i = 0; i <= (c->data[1] & ~PAGE_MASK); i += 4:
if t->data.share_prev: ((unsigned *)t->frame)[i >> 2] = d[i >> 2]
((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
else: else:
if t == cappage: if t != page:
break t->frame = page->frame
if c->data[1] & PAGE_SHARE_FORGET: t->flags |= PAGE_FLAG_FRAME
if ~cappage->data.flags & PAGE_FLAG_SHARED: page->frame = NULL
if t->data.flags & PAGE_FLAG_PAYING: page->flags &= ~PAGE_FLAG_FRAME
t->data.frame = cappage->data.frame Page_arch_update_mapping (page)
t->data.flags |= PAGE_FLAG_FRAME Page_arch_update_mapping (t)
cappage->data.frame = NULL else:
cappage->data.flags &= ~PAGE_FLAG_FRAME if t == page:
else: break
t->data.share_prev = cappage->data.share_prev if c->data[1] & PAGE_SHARE_FORGET:
t->data.share_next = cappage->data.share_next if ~page->flags & PAGE_FLAG_SHARED:
if t->data.share_prev: if t->flags & PAGE_FLAG_PAYING:
((Cappage *)t->data.share_prev)->data.share_next = t t->frame = page->frame
if t->data.share_next: t->flags |= PAGE_FLAG_FRAME
((Cappage *)t->data.share_next)->data.share_prev = t page->frame = NULL
cappage->data.share_prev = NULL page->flags &= ~PAGE_FLAG_FRAME
cappage->data.share_next = NULL Page_arch_update_mapping (page)
cappage->forget ()
cappage_check_payment (t)
else: else:
t->data.share_prev = cappage->data.share_prev t->share_prev = page->share_prev
t->data.share_next = cappage t->share_next = page->share_next
cappage->data.share_prev = t if t->share_prev:
if t->data.share_prev: t->share_prev->share_next = t
((Cappage *)t->data.share_prev)->data.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: case CAP_PAGE_FLAGS:
// Always refuse to set reserved flags. // Always refuse to set reserved flags.
c->data[2] &= ~(PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) c->data[2] &= ~(PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
// Remember the old flags. // Remember the old flags.
unsigned old = share_data->flags unsigned old = page->flags
// Compute the new 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 we stop paying, see if the frame is still paid for. If not, free it.
if ~new_flags & old & PAGE_FLAG_PAYING: if ~new_flags & old & PAGE_FLAG_PAYING:
if page: // Decrease the use counter in any case.
// Decrease the use counter in any case. page->address_space->unuse ()
page->address_space->unuse () if !page_check_payment (page):
if !page_check_payment (page): new_flags &= ~PAGE_FLAG_FRAME
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
// If we start paying, increase the use counter. // If we start paying, increase the use counter.
if new_flags & ~old & PAGE_FLAG_PAYING: 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. // If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
new_flags &= ~(PAGE_FLAG_PAYING | PAGE_FLAG_FRAME) new_flags &= ~(PAGE_FLAG_PAYING | PAGE_FLAG_FRAME)
if old & 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 we want a frame, see if we can get it.
if ~old & new_flags & PAGE_FLAG_FRAME: if ~old & new_flags & PAGE_FLAG_FRAME:
if page: Page *p
Page *p for p = page; p; p = p->share_prev:
for p = page; p; p = (Page *)p->data.share_prev: if p->flags & PAGE_FLAG_PAYING:
if p->data.flags & PAGE_FLAG_PAYING: break
if !p:
for p = page->share_next; p; p = p->share_next:
if p->flags & PAGE_FLAG_PAYING:
break break
if !p: if !p:
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next: new_flags &= ~PAGE_FLAG_FRAME
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
// If we can get the new frame, get it. // If we can get the new frame, get it.
Capability *cap = &((Capability *)cappage->data.frame)[c->data[1]] if ~old & new_flags & PAGE_FLAG_FRAME:
cap->invalidate () page->frame = page->address_space->zalloc ()
// clone_capability needs a Memory, but doesn't use it when storage is provided. Page_arch_update_mapping (page)
top_memory.clone_capability (c->cap[0], c->copy[0], cap)
break break
default: default:
break break
static void capability_invoke (unsigned target, unsigned protected_data, Capability::Context *c): static void caps_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
Capability *capability = (Capability *)protected_data Caps *caps = (CapsP)protected_data
switch c->data[0]: switch c->data[0]:
case CAP_CAPABILITY_GET: case CAP_CAPS_SET:
reply_cap (capability, true) 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 break
default: default:
break 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. // This is a call capability. cap[0] is the capability to call.
reply_receiver = (Receiver *)protected_data reply_receiver = (Receiver *)protected_data
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC)) reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
Capability *c0 = c->cap[0] CapRef c0 = c->cap[0]
if c0: if c0:
if ((unsigned)c0->target & ~KERNEL_MASK) != 0: if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
Capability r Caps r
fill_cap (&r, protected_data, reply_receiver->reply_protected_data) fill_cap (CapRef (&r, 0), protected_data, reply_receiver->reply_protected_data)
c->cap[0] = &r c->cap[0] = CapRef (&r, 0)
c->copy[0] = true c->copy[0] = true
c0->target->send_message (c0->protected_data, c) c0->target->send_message (c0->protected_data, c)
r.invalidate () r.caps[0].invalidate ()
else: else:
// Kernel call: don't create actual capablities. // Kernel call: don't create actual capablities.
c->cap[0] = NULL c->cap[0].reset ()
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0) kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0.deref ())
return return
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)): if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability. // This is a reply capability.
Receiver *r = (Receiver *)protected_data Receiver *r = (Receiver *)protected_data
r->send_message (r->reply_protected_data, c) r->send_message (r->reply_protected_data, c)
while self->parent: while self->parent:
self = self->parent self = self->parent.deref ()
while self->sibling_prev: while self->sibling_prev:
self->sibling_prev->invalidate () self->sibling_prev->invalidate ()
while self->sibling_next: while self->sibling_next:
@ -801,7 +651,7 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability:
dbg_log ("; target = ") dbg_log ("; target = ")
dbg_log_num (target) dbg_log_num (target)
return return
reply = c->cap[0] reply = c->cap[0].deref ()
if c->data[0] == CAP_DEGRADE: if c->data[0] == CAP_DEGRADE:
reply_cap (target & c->data[1], protected_data) reply_cap (target & c->data[1], protected_data)
return return
@ -818,11 +668,8 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability:
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
page_invoke (target, protected_data, c) page_invoke (target, protected_data, c)
break break
case CAPTYPE_CAPABILITY: case CAPTYPE_CAPS:
capability_invoke (target, protected_data, c) caps_invoke (target, protected_data, c)
break
case CAPTYPE_CAPPAGE:
page_invoke (target, protected_data, c)
break break
default: default:
panic (0x99337744, "invalid capability type invoked") panic (0x99337744, "invalid capability type invoked")

275
iris.h
View File

@ -30,7 +30,7 @@ extern "C" {
#endif #endif
// Number of clock interrupts per second. // Number of clock interrupts per second.
#define HZ 20 #define HZ 100
#define PAGE_BITS (12) #define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS) #define PAGE_SIZE (1 << PAGE_BITS)
@ -47,6 +47,7 @@ enum Exception_code {
ERR_OVERFLOW, ERR_OVERFLOW,
ERR_TRAP, ERR_TRAP,
ERR_WATCHPOINT, ERR_WATCHPOINT,
ERR_BREAKPOINT,
ERR_NO_PAGE_DIRECTORY, ERR_NO_PAGE_DIRECTORY,
ERR_NO_PAGE_TABLE, ERR_NO_PAGE_TABLE,
ERR_OUT_OF_MEMORY, ERR_OUT_OF_MEMORY,
@ -65,6 +66,7 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
"overflow", "overflow",
"trap", "trap",
"watchpoint", "watchpoint",
"breakpoint",
"no page directory", "no page directory",
"no page table", "no page table",
"out of memory" "out of memory"
@ -78,8 +80,8 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
#define CAPTYPE_MEMORY 0x200 #define CAPTYPE_MEMORY 0x200
#define CAPTYPE_THREAD 0x400 #define CAPTYPE_THREAD 0x400
#define CAPTYPE_PAGE 0x600 #define CAPTYPE_PAGE 0x600
#define CAPTYPE_CAPABILITY 0x800 #define CAPTYPE_CAPS 0x800
#define CAPTYPE_CAPPAGE 0xa00 /*#define CAPTYPE_??? 0xa00*/
/*#define CAPTYPE_??? 0xc00*/ /*#define CAPTYPE_??? 0xc00*/
/*#define CAPTYPE_??? 0xe00*/ /*#define CAPTYPE_??? 0xe00*/
@ -106,19 +108,20 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
#define CAP_MEMORY_MAP 4 #define CAP_MEMORY_MAP 4
#define CAP_MEMORY_MAPPING 5 #define CAP_MEMORY_MAPPING 5
#define CAP_MEMORY_LIMIT 6 #define CAP_MEMORY_LIMIT 6
#define CAP_MEMORY_DROP 8
#define CAP_MEMORY_ALL_RIGHTS 0x1ff #define CAP_MEMORY_ALL_RIGHTS 0x1ff
#define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */ #define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */
#define CAP_THREAD_SCHEDULE 2 #define CAP_THREAD_SCHEDULE 2
#define CAP_THREAD_ALLOC_RANGE 3 #define CAP_THREAD_CAP_CLONE 3
#define CAP_THREAD_PHYSICAL_ADDRESS 4 #define CAP_THREAD_PRIV 8
#define CAP_THREAD_ALLOC_PHYSICAL 5 #define CAP_THREAD_PRIV_ALLOC_RANGE 0
#define CAP_THREAD_MAKE_PRIV 6 #define CAP_THREAD_PRIV_PHYSICAL_ADDRESS 1
#define CAP_THREAD_GET_TOP_MEMORY 7 #define CAP_THREAD_PRIV_ALLOC_PHYSICAL 2
#define CAP_THREAD_REGISTER_INTERRUPT 8 #define CAP_THREAD_PRIV_MAKE_PRIV 3
#define CAP_THREAD_ALL_RIGHTS 0x07 #define CAP_THREAD_PRIV_GET_TOP_MEMORY 4
#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_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. */ /* These get/set_info are not arch-specific. */
#define CAP_THREAD_INFO_PC ~0 #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_RUNNING 0x20000000
#define THREAD_FLAG_USER 0x1fffffff #define THREAD_FLAG_USER 0x1fffffff
#define CAP_CAPS_SET 1
#define CAP_CAPS_ALL_RIGHTS 0x1ff
#define CAP_PAGE_SHARE 1 #define CAP_PAGE_SHARE 1
#define CAP_PAGE_FLAGS 2 #define CAP_PAGE_FLAGS 2
/* Not an operation; a capability without this bit cannot write to the page. */ /* 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. */ /* This is a read-only flag, saying if this is uncachable memory. */
#define PAGE_FLAG_UNCACHED 0x20 #define PAGE_FLAG_UNCACHED 0x20
#define CAP_CAPABILITY_GET 1 /* If this flag is set in a capability, it is copied instead of mapped. */
#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff /* 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 #define __my_receiver 1
/* Cappage has Page's operations as well. */ #define __my_thread 2
#define CAP_CAPPAGE_SET 4 #define __my_memory 3
#define CAP_CAPPAGE_ALL_RIGHTS 0x1ff #define __my_call 4
#define __my_parent 5
#ifndef __KERNEL #ifndef __KERNEL
typedef unsigned Capability; 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) static Capability cap_copy (Capability src)
{ {
return src | 2; return src | CAPABILITY_COPY;
}
static Capability cappage_cap (unsigned base, unsigned idx)
{
return base | (idx << 2) | 1;
} }
typedef struct Message 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"); : "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" "\tsyscall\n"
"\tlw $v1, %0\n" "\tlw $v1, %0\n"
"\tsw $t0, 0($v1)\n" "\tsw $t0, 0($v1)\n"
"\tsw $t1, 4($v1)\n" "\tsw $t1, 4($v1)\n"
"\tsw $t2, 8($v1)\n" "\tsw $t2, 8($v1)\n"
"\tsw $t3, 12($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)" "\tsw $v0, 32($v1)"
: :
: "m"(msg) : "m"(msg), "m"(r0), "m"(r1), "m"(r2), "m"(r3)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); : "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); Capability t = cap_copy (target);
__asm__ volatile ("lw $v0, %0\n" __asm__ volatile ("lw $v0, %0\n"
"\tlw $v1, %1\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 $t0, 0($v1)\n"
"\tlw $t1, 4($v1)\n" "\tlw $t1, 4($v1)\n"
"\tlw $t2, 8($v1)\n" "\tlw $t2, 8($v1)\n"
@ -249,14 +252,10 @@ static void call (Capability target, Message *msg)
"\tsw $t1, 4($v1)\n" "\tsw $t1, 4($v1)\n"
"\tsw $t2, 8($v1)\n" "\tsw $t2, 8($v1)\n"
"\tsw $t3, 12($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)" "\tsw $v0, 32($v1)"
: :
: "m"(t), "m"(msg) : "m" (t), "m" (msg), "m" (r0), "m" (r1), "m" (r2), "m" (r3)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); : "memory", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7");
} }
static void invoke_00 (Capability t) 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); 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) static void invoke_20 (Capability t, Capability c0, Capability c1)
{ {
Message msg; Message msg;
@ -452,7 +465,7 @@ static void call_00 (Capability c)
msg.cap[1] = 0; msg.cap[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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) static unsigned call_n00 (Capability c)
@ -466,11 +479,11 @@ static unsigned call_n00 (Capability c)
msg.cap[1] = 0; msg.cap[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; return msg.data[0];
} }
static Capability call_c00 (Capability c) static void call_c00 (Capability c, Capability target)
{ {
Message msg; Message msg;
msg.cap[0] = c; msg.cap[0] = c;
@ -481,11 +494,10 @@ static Capability call_c00 (Capability c)
msg.cap[1] = 0; msg.cap[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 0; msg.cap[3] = 0;
call (__my_call, &msg); call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.cap[0];
} }
static Capability call_c01 (Capability c, unsigned d) static void call_c01 (Capability c, Capability target, unsigned d)
{ {
Message msg; Message msg;
msg.cap[0] = c; msg.cap[0] = c;
@ -496,8 +508,7 @@ static Capability call_c01 (Capability c, unsigned d)
msg.cap[1] = 0; msg.cap[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 0; msg.cap[3] = 0;
call (__my_call, &msg); call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.cap[0];
} }
static unsigned long long call_l01 (Capability c, unsigned d) 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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); 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; Message msg;
msg.cap[0] = c; msg.cap[0] = c;
@ -526,8 +537,7 @@ static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
msg.cap[1] = 0; msg.cap[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 0; msg.cap[3] = 0;
call (__my_call, &msg); call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.cap[0];
} }
static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1) 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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); 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; Message msg;
msg.cap[0] = c; 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 0; msg.cap[3] = 0;
call (__my_call, &msg); call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.cap[0];
} }
static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3) 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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); 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; Message msg;
msg.cap[0] = c; 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.data[3] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 0; msg.cap[3] = 0;
call (__my_call, &msg); call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.cap[0]; }
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) 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; return msg.data[0];
} }
@ -616,7 +638,7 @@ static unsigned call_n11 (Capability c, Capability c1, unsigned d)
msg.data[3] = 0; msg.data[3] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; 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.data[3] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; 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.data[3] = d3;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; return msg.data[0];
} }
@ -661,7 +683,7 @@ static unsigned call_n02 (Capability c, unsigned d0, unsigned d1)
msg.cap[1] = 0; msg.cap[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; *base_return = msg.data[0];
return msg.cap[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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; 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[1] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; 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) static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1, unsigned d2)
{ {
Message msg; Message msg;
@ -723,7 +759,7 @@ static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1,
msg.data[3] = 0; msg.data[3] = 0;
msg.cap[2] = 0; msg.cap[2] = 0;
msg.cap[3] = 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]; 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[1] = d1;
msg.data[2] = d2; msg.data[2] = d2;
msg.data[3] = 0; msg.data[3] = 0;
call (__my_call, &msg); call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0]; 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 () static void schedule ()
@ -752,29 +788,34 @@ static void schedule ()
invoke_01 (__my_thread, CAP_THREAD_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) 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) 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) 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) 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) 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); 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) 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) static void my_sleep (unsigned value, Message *ret)
{ {
receiver_set_alarm (__my_receiver, value); 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) 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); 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) 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); call_c13 (__my_thread, target, thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_MAKE_PRIV, ~0);
}
static Capability thread_make_priv (Capability thread)
{
return call_c12 (__my_thread, thread, CAP_THREAD_MAKE_PRIV, ~0);
} }
static unsigned thread_info (Capability thread, unsigned info, unsigned value, unsigned mask) 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) 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); invoke_12 (caps, cap, CAP_CAPS_SET, index);
}
static void cappage_set (Capability page, Capability cap, unsigned index)
{
invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
} }
#if 0
/* Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. */ /* 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) #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) #define kdebug(str) do { const char *s = (str); while (*s) kdebug_char (*s++); } while (0)
static void kdebug_num (unsigned n) static void kdebug_num (unsigned n)

View File

@ -30,110 +30,139 @@
#define EXTERN extern #define EXTERN extern
#endif #endif
struct Object_base
struct Page struct Page
struct Thread struct Thread
struct Message struct Message
struct Receiver struct Receiver
struct Capability struct Capability
struct Cappage struct Caps
struct Memory struct Memory
struct Object_base: typedef Page *PageP
Capability *refs typedef Thread *ThreadP
Memory *address_space 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 () inline bool is_free ()
template <typename _T> // struct Free : public Object:
struct Object : public Object_base:
// Next and previous object of the same type in any page.
_T *prev, *next
struct Free : public Object <Free>:
// This marker is ~0. No other kernel structure may allow this value // This marker is ~0. No other kernel structure may allow this value
// at this point. It is used to recognize free chunks. // at this point. It is used to recognize free chunks.
unsigned marker unsigned marker
bool Object_base::is_free (): bool Object::is_free ():
return ((Free *)this)->marker == ~0 return ((Free *)this)->marker == ~0
// Include architecture-specific parts. // Include architecture-specific parts.
#include "arch.hh" #include "arch.hh"
struct Message : public Object <Message>: struct Message : public Object:
Capability *capabilities[4] Protected protected_data
unsigned data[4] unsigned data[4]
unsigned protected_data unsigned char capabilities[4]
struct Capability : public Object <Capability>: struct Capability : public Object:
struct Context: struct Context:
unsigned data[4] unsigned data[4]
Capability *cap[4] CapRef cap[4]
bool copy[4] bool copy[4]
Receiver *target ReceiverP target
Capability *parent CapRef parent
Capability *children CapRef children
Capability *sibling_prev, *sibling_next CapRef sibling_prev, sibling_next
unsigned protected_data Protected protected_data
void invoke (Context *c) void invoke (Context *c)
void invalidate () void invalidate ()
struct Thread : public Object <Thread>: struct Thread : public Object:
Receiver *receivers ReceiverP receivers
unsigned pc, sp unsigned pc, sp
Thread_arch arch Thread_arch arch
unsigned flags unsigned flags
Thread *schedule_prev, *schedule_next ThreadP 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. CapRef rcaps[4]
Capability exception // 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 raise (unsigned code, unsigned data)
void run () void run ()
void unrun () void unrun ()
void wait () void wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3)
void unwait () void unwait ()
bool is_waiting (): bool is_waiting ():
return flags & THREAD_FLAG_WAITING return flags & THREAD_FLAG_WAITING
CapRef find_capability (unsigned code, bool *copy)
struct Receiver : public Object <Receiver>: struct Receiver : public Object:
Thread *owner ThreadP owner
Receiver *prev_owned, *next_owned ReceiverP prev_owned, next_owned
Receiver *prev_alarm, *next_alarm ReceiverP prev_alarm, next_alarm
unsigned alarm_count unsigned alarm_count
Capability *capabilities // random is used like the tlb random register to find invalid caps to store the message to.
Message *messages unsigned random
Message *last_message CapsP caps
unsigned reply_protected_data // 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 bool protected_only
void own (Thread *o) void own (ThreadP o)
void orphan () void orphan ()
bool try_deliver () 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 frame
unsigned flags unsigned flags
void *share_first PageP share_first
void *share_prev, *share_next PageP share_prev, share_next
struct Page : public Object <Page>:
ShareData data
Page_arch arch Page_arch arch
void forget () void forget ()
struct Cappage : public Object <Cappage>: struct Caps : public Object:
ShareData data unsigned size
Capability caps[1]
Capability *cap (unsigned idx): Capability *cap (unsigned idx):
return &((Capability *)data.frame)[idx] return &caps[idx]
void forget () 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 Free *frees
Page *pages PageP pages
Thread *threads ThreadP threads
Receiver *receivers ReceiverP receivers
Capability *capabilities CapsP capses
Cappage *cappages MemoryP memories
Memory *memories
unsigned limit, used unsigned limit, used
Memory_arch arch Memory_arch arch
@ -152,32 +181,27 @@ struct Memory : public Object <Memory>:
// Allocation routines for kernel structures // Allocation routines for kernel structures
void *search_free (unsigned size, void **first) void *search_free (unsigned size, void **first)
Page *alloc_page () Page *alloc_page ()
Thread *alloc_thread () Thread *alloc_thread (unsigned size)
Message *alloc_message (Receiver *target) Message *alloc_message (Receiver *target)
Receiver *alloc_receiver () Receiver *alloc_receiver ()
Capability *alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret = NULL) Caps *alloc_caps (unsigned size)
Capability *clone_capability (Capability *source, bool copy, Capability *ret = NULL)
Cappage *alloc_cappage ()
Memory *alloc_memory () Memory *alloc_memory ()
void free_page (Page *page) void free_page (Page *page)
void free_thread (Thread *thread) void free_thread (Thread *thread)
void free_message (Receiver *owner, Message *message) void free_message (Receiver *owner, Message *message)
void free_receiver (Receiver *receiver) void free_receiver (Receiver *receiver)
void free_capability (Capability *capability) void free_caps (Caps *page)
void free_cappage (Cappage *page)
void free_memory (Memory *mem) void free_memory (Memory *mem)
void free_obj (Object_base *obj, void **first) void free_obj (Object *obj, void **first)
Capability *find_capability (unsigned code, bool *copy)
// Functions which can be called from assembly must not be mangled. // Functions which can be called from assembly must not be mangled.
extern "C": extern "C":
// Panic. n is sent over caps led. message is currently ignored. // Panic. n is sent over caps led. message is currently ignored.
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "") void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
EXTERN unsigned dbg_code EXTERN unsigned dbg_code
EXTERN Capability *dbg_cap EXTERN CapRef dbg_cap
void dbg_log_char (unsigned ch) void dbg_log_char (unsigned ch)
void dbg_log (char const *str) void dbg_log (char const *str)
void dbg_log_num (unsigned num) void dbg_log_num (unsigned num)
@ -189,12 +213,12 @@ void schedule ()
void timer_interrupt () void timer_interrupt ()
EXTERN Memory top_memory EXTERN Memory top_memory
EXTERN Receiver *first_alarm EXTERN ReceiverP first_alarm
EXTERN Thread idle EXTERN Thread idle
EXTERN Memory idle_memory EXTERN Memory idle_memory
EXTERN Page idle_page EXTERN Page idle_page
EXTERN Thread *first_scheduled EXTERN ThreadP first_scheduled
EXTERN Thread *current, *old_current EXTERN ThreadP current, old_current
EXTERN bool do_schedule EXTERN bool do_schedule
// Defined in memory.cc // Defined in memory.cc
@ -206,7 +230,7 @@ void phys_free (unsigned page, unsigned num)
// Defined by architecture-specific files. // Defined by architecture-specific files.
void Thread_arch_init (Thread *thread) 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) unsigned *Thread_arch_info (Thread *thread, unsigned num)
void Memory_arch_init (Memory *mem) void Memory_arch_init (Memory *mem)
void Memory_arch_free (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) void Memory_arch_unmap (Memory *mem, Page *page, unsigned address)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable) Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable)
void Page_arch_update_mapping (Page *page) 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): bool Memory::map (Page *page, unsigned address, bool write):
return Memory_arch_map (this, page, address, 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) Memory_arch_unmap (this, page, address)
Page *Memory::get_mapping (unsigned address, bool *writable): Page *Memory::get_mapping (unsigned address, bool *writable):
return Memory_arch_get_mapping (this, address, 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) #define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)

View File

@ -17,7 +17,7 @@
load = 0x80000000 load = 0x80000000
ARCH_CXXFLAGS = -DNUM_THREADS=3 ARCH_CXXFLAGS = -DNUM_THREADS=2
ARCH_CPPFLAGS = -Imips -Wa,-mips32 ARCH_CPPFLAGS = -Imips -Wa,-mips32
CROSS = mipsel-linux-gnu- CROSS = mipsel-linux-gnu-
OBJDUMP = $(CROSS)objdump OBJDUMP = $(CROSS)objdump
@ -34,7 +34,7 @@ uimage:
mips/entry.o: $(boot_threads) mips/entry.o: $(boot_threads)
mips/init.o: TARGET_FLAGS = -I/usr/include mips/init.o: TARGET_FLAGS = -I/usr/include
$(boot_threads): TARGET_FLAGS = -I. $(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 lcd: boot-programs/charset.data
boot-programs/charset.data: boot-programs/charset boot-programs/charset.data: boot-programs/charset

View File

@ -45,15 +45,11 @@ void Thread_arch_init (Thread *thread):
thread->arch.k0 = 0 thread->arch.k0 = 0
thread->arch.k1 = 0 thread->arch.k1 = 0
void Thread_arch_receive (Thread *thread, unsigned protected_data, Capability::Context *c): void Thread_arch_receive (Thread *thread, unsigned protected_data, unsigned *data):
thread->arch.a0 = (unsigned)c->cap[0] thread->arch.t0 = data[0]
thread->arch.a1 = (unsigned)c->cap[1] thread->arch.t1 = data[1]
thread->arch.a2 = (unsigned)c->cap[2] thread->arch.t2 = data[2]
thread->arch.a3 = (unsigned)c->cap[3] thread->arch.t3 = data[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]
thread->arch.v0 = protected_data thread->arch.v0 = protected_data
unsigned *Thread_arch_info (Thread *thread, unsigned num): 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) free_page_table (t, idx)
static unsigned make_entry_lo (Page *page, bool write): static unsigned make_entry_lo (Page *page, bool write):
if !page->data.frame: if !page->frame:
return 0 return 0
unsigned flags unsigned flags
if page->data.flags & PAGE_FLAG_UNCACHED: if page->flags & PAGE_FLAG_UNCACHED:
flags = 0x10 | 0x2 flags = 0x10 | 0x2
else: else:
flags = 0x18 | 0x2 flags = 0x18 | 0x2
if write: if write:
flags |= 0x4 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): bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
if address >= 0x80000000: if address >= 0x80000000:
@ -282,7 +278,7 @@ void Page_arch_update_mapping (Page *page):
if !page->arch.first_mapped: if !page->arch.first_mapped:
return return
Memory *as = page->address_space 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: for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped:
unsigned de = p->mapping >> 21 unsigned de = p->mapping >> 21
unsigned te = (p->mapping >> 12) & ((1 << 9) - 1) unsigned te = (p->mapping >> 12) & ((1 << 9) - 1)

View File

@ -69,7 +69,7 @@
#ifdef __KERNEL #ifdef __KERNEL
// register save positions in Thread // register save positions in Thread
#define SAVE_PC (5 * 4) #define SAVE_PC (6 * 4)
#define SAVE_SP (SAVE_PC + 4) #define SAVE_SP (SAVE_PC + 4)
#define SAVE_AT (SAVE_SP + 4) #define SAVE_AT (SAVE_SP + 4)
#define SAVE_V0 (SAVE_AT + 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 // bits 12-20 are an index in the page table, bits 21-30
// are an index in the page directory and bit 31 is always 0. // are an index in the page directory and bit 31 is always 0.
struct arch_page : public Object <arch_page> : struct arch_page : public Object :
Page *page Page *page
unsigned mapping unsigned mapping
arch_page *prev_mapped, *next_mapped 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 arch_page *first_page
struct Page_arch: struct Page_arch:

View File

@ -29,13 +29,13 @@ static void init_idle ():
idle.schedule_prev = NULL idle.schedule_prev = NULL
idle.schedule_next = NULL idle.schedule_next = NULL
idle.address_space = &idle_memory idle.address_space = &idle_memory
idle.refs = NULL idle.refs.reset ()
idle.flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV idle.flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
// initialize idle_memory. // initialize idle_memory.
idle_memory.prev = NULL idle_memory.prev = NULL
idle_memory.next = NULL idle_memory.next = NULL
idle_memory.address_space = NULL idle_memory.address_space = NULL
idle_memory.refs = NULL idle_memory.refs.reset ()
idle_memory.pages = &idle_page idle_memory.pages = &idle_page
idle_memory.threads = &idle idle_memory.threads = &idle
idle_memory.memories = NULL idle_memory.memories = NULL
@ -48,9 +48,9 @@ static void init_idle ():
// initialize idle_page // initialize idle_page
idle_page.prev = NULL idle_page.prev = NULL
idle_page.next = NULL idle_page.next = NULL
idle_page.data.frame = 0x80000000 idle_page.frame = 0x80000000
idle_page.data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME idle_page.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
idle_page.refs = NULL idle_page.refs.reset ()
idle_page.address_space = NULL idle_page.address_space = NULL
current = &idle current = &idle
directory = idle_memory.arch.directory 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 // Wait with initializing the status register until the last moment, so that
// exceptions in the bootup code will fill EPC and friends. // 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 (): static void init_threads ():
Thread *previous = NULL Thread *previous = NULL
first_scheduled = NULL first_scheduled = NULL
@ -115,7 +111,7 @@ static void init_threads ():
for unsigned i = 0; i < NUM_THREADS; ++i: for unsigned i = 0; i < NUM_THREADS; ++i:
Memory *mem = top_memory.alloc_memory () Memory *mem = top_memory.alloc_memory ()
assert (mem) assert (mem)
Thread *thread = mem->alloc_thread () Thread *thread = mem->alloc_thread (3)
Page **pages = (Page **)mem->zalloc () Page **pages = (Page **)mem->zalloc ()
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i] Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
for unsigned j = 0; j < SELFMAG; ++j: for unsigned j = 0; j < SELFMAG; ++j:
@ -155,8 +151,8 @@ static void init_threads ():
unsigned idx = file_offset + section_offset unsigned idx = file_offset + section_offset
if !pages[idx]: if !pages[idx]:
pages[idx] = mem->alloc_page () pages[idx] = mem->alloc_page ()
pages[idx]->data.frame = thread_start[i] + (idx << PAGE_BITS) pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS)
pages[idx]->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME pages[idx]->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
++top_memory.limit ++top_memory.limit
mem->use () mem->use ()
if !mem->map (pages[idx], p, writable): if !mem->map (pages[idx], p, writable):
@ -173,11 +169,11 @@ static void init_threads ():
if !page: if !page:
panic (0x00220022, "out of memory") panic (0x00220022, "out of memory")
return return
page->data.frame = mem->zalloc () page->frame = mem->zalloc ()
if !page->data.frame: if !page->frame:
panic (0x02220022, "out of memory"); panic (0x02220022, "out of memory");
return 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): if !mem->map (page, p, true):
panic (0x33557799, "unable to map initial bss page") panic (0x33557799, "unable to map initial bss page")
return return
@ -190,31 +186,34 @@ static void init_threads ():
break break
if a < shdr->sh_addr: if a < shdr->sh_addr:
continue 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: for unsigned p = 0; p <= ((thread_start[i + 1] - thread_start[i] - 1) >> PAGE_BITS); ++p:
if pages[p]: if pages[p]:
continue continue
++top_memory.limit ++top_memory.limit
top_memory.pfree (thread_start[i] + (p << PAGE_BITS)) top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
Page *stackpage = mem->alloc_page () Page *stackpage = mem->alloc_page ()
stackpage->data.frame = mem->zalloc () stackpage->frame = mem->zalloc ()
stackpage->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME stackpage->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
if !stackpage || !mem->map (stackpage, 0x7ffff000, true): if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
panic (0x13151719, "unable to map initial stack page") panic (0x13151719, "unable to map initial stack page")
return return
thread->caps[0] = mem->alloc_caps (16)
for unsigned r = 0; r < 4; ++r:
thread->rcaps[r] = CapRef ()
Receiver *recv = mem->alloc_receiver () Receiver *recv = mem->alloc_receiver ()
recv->owner = thread recv->owner = thread
thread->receivers = recv thread->receivers = recv
thread->arch.a0 = mkcap (mem, CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS, recv) thread->caps[0]->set (__my_receiver, (ReceiverP)(CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS), (Protected)recv, CapRef ())
thread->arch.a1 = mkcap (mem, CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS, thread) thread->caps[0]->set (__my_thread, (ReceiverP)(CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS), (Protected)thread, CapRef ())
thread->arch.a2 = mkcap (mem, CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS, mem) thread->caps[0]->set (__my_memory, (ReceiverP)(CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS), (Protected)mem, CapRef ())
thread->arch.a3 = mkcap (mem, CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL), recv) thread->caps[0]->set (__my_call, (ReceiverP)(CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)), (Protected)recv, CapRef ())
thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
if !i: if !i:
first_scheduled = thread first_scheduled = thread
init_receiver = recv init_receiver = recv
else: 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 previous->schedule_next = thread
thread->schedule_prev = previous thread->schedule_prev = previous
thread->schedule_next = NULL thread->schedule_next = NULL
@ -236,7 +235,7 @@ void init (unsigned mem):
top_memory.prev = NULL top_memory.prev = NULL
top_memory.next = NULL top_memory.next = NULL
top_memory.address_space = NULL top_memory.address_space = NULL
top_memory.refs = NULL top_memory.refs.reset ()
top_memory.pages = NULL top_memory.pages = NULL
top_memory.threads = NULL top_memory.threads = NULL
top_memory.memories = NULL top_memory.memories = NULL

View File

@ -101,7 +101,7 @@ Thread *interrupt ():
Capability::Context c Capability::Context c
for unsigned j = 0; j < 4; ++j: for unsigned j = 0; j < 4; ++j:
c.data[j] = 0 c.data[j] = 0
c.cap[j] = NULL c.cap[j].reset ()
c.copy[j] = false c.copy[j] = false
arch_interrupt_receiver[i]->send_message (i, &c) arch_interrupt_receiver[i]->send_message (i, &c)
arch_interrupt_receiver[i] = NULL arch_interrupt_receiver[i] = NULL
@ -124,20 +124,26 @@ void flush_tlb (unsigned asid):
__asm__ volatile ("tlbwi") __asm__ volatile ("tlbwi")
static void arch_invoke (): static void arch_invoke ():
Capability *target CapRef target
bool wait 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 do_schedule = false
if wait: 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: if !target:
// There must be no action here. // There must be no action here.
else: else:
Capability::Context c Capability::Context c
c.cap[0] = old_current->address_space->find_capability (old_current->arch.a0, &c.copy[0]) c.cap[0] = old_current->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[1] = old_current->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[2] = old_current->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[3] = old_current->find_capability (old_current->arch.a3, &c.copy[3])
c.data[0] = old_current->arch.t0 c.data[0] = old_current->arch.t0
c.data[1] = old_current->arch.t1 c.data[1] = old_current->arch.t1
c.data[2] = old_current->arch.t2 c.data[2] = old_current->arch.t2
@ -207,7 +213,7 @@ Thread *exception ():
break break
case 9: case 9:
// Breakpoint. // Breakpoint.
#if 0 #if 1
current->raise (ERR_BREAKPOINT, 0) current->raise (ERR_BREAKPOINT, 0)
#else #else
current->pc += 4 current->pc += 4
@ -216,7 +222,7 @@ Thread *exception ():
panic (0, "Break instruction while log capability was already set") panic (0, "Break instruction while log capability was already set")
break break
bool dummy 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: if !dbg_cap:
panic (0, "no log capability provided") panic (0, "no log capability provided")
break break

View File

@ -138,12 +138,11 @@
// Map IO memory (requires a priviledged __my_thread capability). // Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h> #include <iris.h>
static void __map_io (unsigned physical, unsigned mapping): 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. // 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. // 1 means writable.
memory_map (__my_memory, page, mapping, 1) memory_map (__my_memory, 6, mapping, 1)
drop (page)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0) #define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0) #define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)

View File

@ -19,12 +19,13 @@
#define ARCH #define ARCH
#include "kernel.hh" #include "kernel.hh"
#if 0
void dbg_log_char (unsigned ch): void dbg_log_char (unsigned ch):
if !dbg_cap: if !dbg_cap:
return return
Capability::Context c Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL c.cap[i].reset ()
c.copy[i] = false c.copy[i] = false
c.data[i] = 0 c.data[i] = 0
c.data[0] = ch 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_num (n)
dbg_log_char ('\n') dbg_log_char ('\n')
// If no log capability is registered, the machine just hangs. // 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

View File

@ -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). into the hands of the user (as far as allowed by the system administrator).
This is a very good thing. 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} \section{Kernel objects}
This section describes all kernel objects of Iris, and the operations that can 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 be performed on them. One operation is possible on any kernel object (except a

View File

@ -62,7 +62,7 @@ static void alarm_tick (Receiver *recv):
Capability::Context c Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.data[i] = 0 c.data[i] = 0
c.cap[i] = NULL c.cap[i].reset ()
c.copy[i] = false c.copy[i] = false
recv->send_message (~0, &c) recv->send_message (~0, &c)
if recv->prev_alarm: 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. // Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm.
--recv->alarm_count --recv->alarm_count
void Thread::wait (): void Thread::wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3):
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
unrun_thread (this) unrun_thread (this)
flags |= THREAD_FLAG_WAITING 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. // Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned: for Receiver *r = receivers; r; r = r->next_owned:
if r->try_deliver (): if r->try_deliver ():
@ -92,6 +96,6 @@ void schedule ():
void timer_interrupt (): void timer_interrupt ():
Receiver *recv, *next Receiver *recv, *next
for recv = first_alarm; recv; recv = next: for recv = first_alarm; recv; recv = next:
next = recv->next next = (Receiver *)recv->next
alarm_tick (recv) alarm_tick (recv)
//schedule () //schedule ()