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

View File

@ -30,16 +30,6 @@ __hack_label:
.word _gp
1:
lw $gp, 0($ra)
la $v0, __my_receiver
sw $a0, ($v0)
la $v0, __my_thread
sw $a1, ($v0)
la $v0, __my_memory
sw $a2, ($v0)
la $v0, __my_call
sw $a3, ($v0)
la $v0, __my_parent
sw $t0, ($v0)
la $t9, main
la $ra, 1f
jr $t9
@ -49,9 +39,3 @@ __hack_label:
// This should not be reached: generate an address fault.
b 1b
lw $a0, -4($zero)
.comm __my_receiver, 4
.comm __my_thread, 4
.comm __my_memory, 4
.comm __my_call, 4
.comm __my_parent, 4

View File

@ -24,19 +24,25 @@
// This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves.
enum init_requests:
INIT_SET_GPIO_0
INIT_SET_GPIO_1
INIT_SET_GPIO
INIT_SET_LCD
// Keyboard interface.
// Startup: kbd_set_cb
enum Keyboard_request:
KEYBOARD_SET_CB
KEYBOARD_GET_KEYS
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
static __inline__ void keyboard_set_cb (Capability kbd_set_cb, Capability cb):
invoke_10 (kbd_set_cb, cb)
static __inline__ void keyboard_set_cb (Capability kbd, Capability cb):
invoke_11 (kbd, cb, KEYBOARD_SET_CB)
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
#define KEYBOARD_RELEASE (1 << 31)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps. The returned capability is a read-only list of strings.
static __inline__ void keyboard_get_keys (Capability target, Capability kbd):
call_c01 (kbd, target, KEYBOARD_GET_KEYS)
// Display interface.
@ -93,8 +99,8 @@ static __inline__ unsigned long long file_get_info (Capability file, unsigned ty
static __inline__ void file_close (Capability file):
invoke_01 (file, FILE_CLOSE)
// Copy a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
static __inline__ Capability file_copy_handle (Capability file):
return call_c01 (file, FILE_COPY_HANDLE)
static __inline__ void file_copy_handle (Capability target, Capability file):
call_c01 (file, target, FILE_COPY_HANDLE)
// Directory interface.
// Get the number of entries in this directory.
@ -104,17 +110,17 @@ static __inline__ unsigned long long directory_get_size (Capability dir):
static __inline__ unsigned directory_get_name (Capability dir, unsigned long long idx, Capability page):
return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32)
// Get the file.
static __inline__ Capability directory_get_file (Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
static __inline__ void directory_get_file (Capability target, Capability dir, unsigned long long idx, Capability page):
call_c03 (dir, target, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
// Get file info. This returns the same information as file_get_info, without opening the file.
static __inline__ unsigned long long directory_get_file_info (Capability dir, unsigned long long idx, unsigned type):
return call_l04 (dir, DIRECTORY_GET_FILE_INFO, idx & 0xffffffff, idx >> 32, type)
// Create a new file. After this, any index may map to a different file.
static __inline__ Capability directory_create_file (Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
static __inline__ void directory_create_file (Capability target, Capability dir, unsigned long long idx, Capability page):
call_c03 (dir, target, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
// Delete a file. After this, any index may map to a different file.
static __inline__ Capability directory_delete_file (Capability dir, unsigned long long idx, Capability page):
return call_c03 (dir, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
static __inline__ void directory_delete_file (Capability target, Capability dir, unsigned long long idx, Capability page):
call_c03 (dir, target, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
// Stream interface.
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
@ -148,8 +154,8 @@ static __inline__ unsigned block_get_size (Capability blk_get_size):
return call_n00 (blk_get_size)
// Get file capability. Returns a seekable mappable non-stream file.
static __inline__ Capability block_get_file (Capability blk_get_file):
call_c00 (blk_get_file)
static __inline__ void block_get_file (Capability target, Capability blk_get_file):
call_c00 (blk_get_file, target)

View File

@ -20,8 +20,8 @@
#define ARCH
#include "arch.hh"
// Interval between polls for keyboard (when keys are pressed) and battery/power (always) events
#define ALARM_INTERVAL (HZ / 20)
// Interval between polls for keyboard events (when keys are pressed)
#define ALARM_INTERVAL (HZ / 50)
// GPIO pins for the devices (port.pin)
@ -42,13 +42,6 @@
// Scroll lock: 0.9
// interrupts: no, output only.
// Power output (setting to 0 switches off the machine): 2.2
// interrupts: no, output only.
// Power button: 3.1 (note that this is also a keyboard column.)
// Battery presence and charge detection: 3.29 (note that this is also a keyboard column.)
// interrupts: no; it would be possible, but setting these to input makes it impossible to detect certain key presses as interrupts.
// interrupt summary
// Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad
// Port 1: None.
@ -58,43 +51,28 @@
enum event_type:
KEYBOARD_EVENT
TOUCHPAD_EVENT
POWERBUTTON_EVENT
BATTERY_EVENT
NUM_EVENTS
enum cap_type:
CAP_KEYBOARD = 32
CAP_TOUCHPAD
CAP_POWEROFF
CAP_POWERBUTTON
CAP_BATTERY
CAP_LOCKLEDS
CAP_PWM
static Capability cbs[NUM_EVENTS]
static void event (event_type type, unsigned data):
if !cbs[type]:
return
invoke_01 (cbs[type], data)
invoke_01 (11 + type, data)
static void set_cb (event_type type, Capability cb):
if cbs[type]:
drop (cbs[type])
cbs[type] = cb
enum battery_type:
BATTERY_ABSENT
BATTERY_CHARGING
BATTERY_CHARGED
static void set_cb (event_type type):
capability_clone (11 + type, 6)
class Keyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
unsigned keys[GPIO_KBD_NUM_COLS]
bool scanning
void parse (unsigned col, unsigned data):
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
if (data ^ keys[col]) & (1 << row):
unsigned code = (col << 3) | row
unsigned code = encode[col][row]
if data & (1 << row):
code |= KEYBOARD_RELEASE
event (KEYBOARD_EVENT, code)
@ -115,32 +93,38 @@ class Keyboard:
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
// Set scanning to false before first parse.
scanning = false
// Clear all pins. This is only required once, because it's done at the end of the loop as well.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
// clear pin
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// output
// Set pin to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
for unsigned i = 0; i < 100000; ++i:
// Delay for stabalization.
for unsigned i = 0; i < 100; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Read the result.
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
// Generate events.
parse (col, data)
// set pin
// Set pin to get rid of capacitance effects.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
// input
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir
// Delay to make the above trick work.
for unsigned i = 0; i < 100; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Pin is set to input at the start of the loop.
// set all to 0.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// set all to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
// Set interrupts on change.
// Delay for stabalization.
for unsigned i = 0; i < 100; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
// Set interrupts.
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
for unsigned i = 0; i < 8; ++i:
if data & (1 << i):
gpio_irq_fall (GPIO_KBD_ROW_PORT, i)
gpio_irq_low (GPIO_KBD_ROW_PORT, i)
else:
gpio_irq_rise (GPIO_KBD_ROW_PORT, i)
// Clear pending interrupts.
GPIO_GPFR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
gpio_irq_high (GPIO_KBD_ROW_PORT, i)
// Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
Keyboard ():
@ -151,11 +135,43 @@ class Keyboard:
// Set all rows to input and enable the pull-ups.
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// Initialize matrix.
for unsigned i = 0; i < GPIO_KBD_NUM_COLS; ++i:
keys[i] = 0xff
// Perform initial scan to get real values into matrix and set up the rest.
// Initialize things in the same way as when a new callback is set up.
send_initial ()
void send_initial ():
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
keys[col] = 0xff
scan ()
event (KEYBOARD_EVENT, ~0)
enum Keys:
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10
SPACE, TAB, ENTER, LBRACE, RBRACE, COMMA, PERIOD, MINUS, EQUAL, SLASH, BACKSLASH, SEMICOLON, EXTRA, BACKQUOTE, QUOTE
UP, DOWN, LEFT, RIGHT
ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
LSHIFT, RSHIFT, CTRL, ALT
CAPS, NUM
NONE = ~0 & ~KEYBOARD_RELEASE
unsigned const Keyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
{ PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
{ E, F3, D, F4, C, NONE, NONE, N3 },
{ R, T, F, G, V, B, N5, N4 },
{ U, Y, J, H, M, N, N6, N7 },
{ I, RBRACE, K, F6, COMMA, NONE, EQUAL, N8 },
{ O, F7, L, NONE, PERIOD, MENU, F8, N9 },
{ NONE, NONE, NONE, SPACE, NUM, NONE, DELETE, NONE },
{ NONE, BACKSPACE, NONE, NONE, ENTER, NONE, F9, NONE },
{ NONE, NONE, NONE, ALT, NONE, NONE, NONE, SYSRQ },
{ P, LBRACE, SEMICOLON, QUOTE, BACKSLASH, SLASH, MINUS, N0 },
{ NONE, ZZZ, NONE, NONE, NONE, NONE, NONE, F10 },
{ NONE, NONE, NONE, NONE, NONE, NONE, F2, NONE },
{ NONE, NONE, NONE, NONE, NONE, NONE, INSERT, NONE },
{ NONE, NONE, UP, DOWN, LEFT, RIGHT, NONE, NONE },
{ NONE, LSHIFT, RSHIFT, NONE, NONE, NONE, F1, FN }}
class Touchpad:
unsigned old_state
@ -163,33 +179,35 @@ class Touchpad:
void check_events ():
unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
if state & (1 << GPIO_TP_LEFT):
gpio_irq_fall (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_irq_low (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0)
else:
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_irq_high (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0x10000)
if state & (1 << GPIO_TP_RIGHT):
gpio_irq_fall (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
gpio_irq_low (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 1)
else:
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
gpio_irq_high (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 0x10001)
old_state = state
// Ack interrupts.
GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
//GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
Touchpad ():
// Set pins to input with pull-ups.
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
// See if they are already pressed. Also set up interrupts. This is done like when a new callback is registered.
send_initial ()
void send_initial ():
old_state = 0
// See if they are already pressed. Also set up interrupts.
check_events ()
// Now enable the interrupts.
event (TOUCHPAD_EVENT, ~0)
class Lockleds:
// Note that num lock is in port 2. The others are in port 0.
@ -215,58 +233,6 @@ class Lockleds:
else:
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
class Power:
// Power out is in port 2, the rest in port 3.
unsigned old_state
bool was_present
public:
void poll ():
#if 0
// Switch off keyboard interrupts, because this may interfere with them.
GPIO_GPIER (0) &= ~0xff
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
GPIO_GPPUR (3) &= ~(PWR_IN | BATTERY)
//udelay (100)
unsigned state = GPIO_GPDR (3)
if (state ^ old_state) & PWR_IN:
event (POWERBUTTON_EVENT, state & PWR_IN ? 0 : 0x10000)
if (state ^ old_state) & BATTERY:
if !(state & BATTERY):
GPIO_GPPUR (3) |= BATTERY
//udelay (100)
if GPIO_GPDR (3) & BATTERY:
if !was_present:
event (BATTERY_EVENT, BATTERY_CHARGED)
was_present = true
else:
if was_present:
event (BATTERY_EVENT, BATTERY_ABSENT)
was_present = false
else:
event (BATTERY_EVENT, BATTERY_CHARGING)
old_state = state
GPIO_GPPUR (3) &= ~BATTERY
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
//udelay (100)
GPIO_GPIER (3) |= 0xff
#endif
Power ():
was_present = true
//old_state = BATTERY
poll ()
void poweroff ():
// TODO: doesn't work.
i2c_open ()
i2c_write_page (I2C_DEV_MCU, I2C_MCU_SHUTDOWN, "\1", 1)
i2c_close ()
while true:
// Do nothing; wait until the device stops running.
void reboot ():
wdt_set_count (0xffffffff - 32)
wdt_start ()
while true:
// Do nothing; wait until the device reboots.
// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
class Pwm:
public:
@ -288,43 +254,39 @@ class Pwm:
int main ():
map_gpio ()
map_pwm0 ()
map_wdt ()
map_i2c ()
Keyboard kbd
Touchpad tp
Lockleds leds
Power power
Pwm pwm
// Enable interrupts. All are in port 0.
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
register_interrupt (IRQ_GPIO0)
Capability cap_kbd = receiver_create_capability (__my_receiver, CAP_KEYBOARD)
Capability cap_tp = receiver_create_capability (__my_receiver, CAP_TOUCHPAD)
Capability cap_poweroff = receiver_create_capability (__my_receiver, CAP_POWEROFF)
Capability cap_powerbutton = receiver_create_capability (__my_receiver, CAP_POWERBUTTON)
Capability cap_battery = receiver_create_capability (__my_receiver, CAP_BATTERY)
Capability cap_lockleds = receiver_create_capability (__my_receiver, CAP_LOCKLEDS)
Capability cap_pwm = receiver_create_capability (__my_receiver, CAP_PWM)
Capability cap_kbd = 7
Capability cap_tp = 8
Capability cap_lockleds = 9
Capability cap_pwm = 10
receiver_create_capability (cap_kbd, __my_receiver, CAP_KEYBOARD)
receiver_create_capability (cap_tp, __my_receiver, CAP_TOUCHPAD)
receiver_create_capability (cap_lockleds, __my_receiver, CAP_LOCKLEDS)
receiver_create_capability (cap_pwm, __my_receiver, CAP_PWM)
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_poweroff), cap_copy (cap_powerbutton), INIT_SET_GPIO_0)
invoke_31 (__my_parent, cap_copy (cap_battery), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO_1)
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO)
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
if kbd.is_scanning ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
while true:
schedule ()
Message msg
wait (&msg)
wait (&msg, 6, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
switch msg.protected_data:
case ~0:
// Alarm.
// Periodically scan several devices.
kbd.scan ()
if kbd.is_scanning ():
kbd.scan ()
power.poll ()
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
break
case IRQ_GPIO0:
// Always scan keyboard and touchpad on any interrupt.
@ -334,22 +296,12 @@ int main ():
register_interrupt (IRQ_GPIO0)
break
case CAP_KEYBOARD:
set_cb (KEYBOARD_EVENT, msg.cap[0])
set_cb (KEYBOARD_EVENT)
kbd.send_initial ()
break
case CAP_TOUCHPAD:
set_cb (TOUCHPAD_EVENT, msg.cap[0])
break
case CAP_POWEROFF:
if msg.data[0]:
power.poweroff ()
else:
power.reboot ()
break
case CAP_POWERBUTTON:
set_cb (POWERBUTTON_EVENT, msg.cap[0])
break
case CAP_BATTERY:
set_cb (BATTERY_EVENT, msg.cap[0])
set_cb (TOUCHPAD_EVENT)
tp.send_initial ()
break
case CAP_LOCKLEDS:
leds.set (msg.data[0])

View File

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

View File

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

View File

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

275
iris.h
View File

@ -30,7 +30,7 @@ extern "C" {
#endif
// Number of clock interrupts per second.
#define HZ 20
#define HZ 100
#define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS)
@ -47,6 +47,7 @@ enum Exception_code {
ERR_OVERFLOW,
ERR_TRAP,
ERR_WATCHPOINT,
ERR_BREAKPOINT,
ERR_NO_PAGE_DIRECTORY,
ERR_NO_PAGE_TABLE,
ERR_OUT_OF_MEMORY,
@ -65,6 +66,7 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
"overflow",
"trap",
"watchpoint",
"breakpoint",
"no page directory",
"no page table",
"out of memory"
@ -78,8 +80,8 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
#define CAPTYPE_MEMORY 0x200
#define CAPTYPE_THREAD 0x400
#define CAPTYPE_PAGE 0x600
#define CAPTYPE_CAPABILITY 0x800
#define CAPTYPE_CAPPAGE 0xa00
#define CAPTYPE_CAPS 0x800
/*#define CAPTYPE_??? 0xa00*/
/*#define CAPTYPE_??? 0xc00*/
/*#define CAPTYPE_??? 0xe00*/
@ -106,19 +108,20 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
#define CAP_MEMORY_MAP 4
#define CAP_MEMORY_MAPPING 5
#define CAP_MEMORY_LIMIT 6
#define CAP_MEMORY_DROP 8
#define CAP_MEMORY_ALL_RIGHTS 0x1ff
#define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */
#define CAP_THREAD_SCHEDULE 2
#define CAP_THREAD_ALLOC_RANGE 3
#define CAP_THREAD_PHYSICAL_ADDRESS 4
#define CAP_THREAD_ALLOC_PHYSICAL 5
#define CAP_THREAD_MAKE_PRIV 6
#define CAP_THREAD_GET_TOP_MEMORY 7
#define CAP_THREAD_REGISTER_INTERRUPT 8
#define CAP_THREAD_ALL_RIGHTS 0x07
#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV) | (1 << CAP_THREAD_ALLOC_PHYSICAL) | (1 << CAP_THREAD_PHYSICAL_ADDRESS) | (1 << CAP_THREAD_ALLOC_RANGE))
#define CAP_THREAD_CAP_CLONE 3
#define CAP_THREAD_PRIV 8
#define CAP_THREAD_PRIV_ALLOC_RANGE 0
#define CAP_THREAD_PRIV_PHYSICAL_ADDRESS 1
#define CAP_THREAD_PRIV_ALLOC_PHYSICAL 2
#define CAP_THREAD_PRIV_MAKE_PRIV 3
#define CAP_THREAD_PRIV_GET_TOP_MEMORY 4
#define CAP_THREAD_PRIV_REGISTER_INTERRUPT 5
#define CAP_THREAD_ALL_RIGHTS 0x0ff
#define CAP_THREAD_ALL_PRIV_RIGHTS 0x1ff
/* These get/set_info are not arch-specific. */
#define CAP_THREAD_INFO_PC ~0
@ -130,6 +133,9 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
#define THREAD_FLAG_RUNNING 0x20000000
#define THREAD_FLAG_USER 0x1fffffff
#define CAP_CAPS_SET 1
#define CAP_CAPS_ALL_RIGHTS 0x1ff
#define CAP_PAGE_SHARE 1
#define CAP_PAGE_FLAGS 2
/* Not an operation; a capability without this bit cannot write to the page. */
@ -158,31 +164,24 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
/* This is a read-only flag, saying if this is uncachable memory. */
#define PAGE_FLAG_UNCACHED 0x20
#define CAP_CAPABILITY_GET 1
#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff
/* If this flag is set in a capability, it is copied instead of mapped. */
/* If it is set in the target capability, the Thread waits after the request. */
#define CAPABILITY_COPY 0x80000000
/* This constant can be used to signify that no capability is passed or accepted. */
#define CAPABILITY_NONE (~CAPABILITY_COPY)
#define CAPPAGE_SIZE 102
/* Cappage has Page's operations as well. */
#define CAP_CAPPAGE_SET 4
#define CAP_CAPPAGE_ALL_RIGHTS 0x1ff
#define __my_receiver 1
#define __my_thread 2
#define __my_memory 3
#define __my_call 4
#define __my_parent 5
#ifndef __KERNEL
typedef unsigned Capability;
extern Capability __my_receiver;
extern Capability __my_thread;
extern Capability __my_memory;
extern Capability __my_call;
extern Capability __my_parent;
static Capability cap_copy (Capability src)
{
return src | 2;
}
static Capability cappage_cap (unsigned base, unsigned idx)
{
return base | (idx << 2) | 1;
return src | CAPABILITY_COPY;
}
typedef struct Message
@ -211,30 +210,34 @@ static void invoke (Capability target, Message *msg)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
}
static void wait (Message *msg)
static void wait (Message *msg, Capability r0, Capability r1, Capability r2, Capability r3)
{
__asm__ volatile ("li $v0, 2\n"
__asm__ volatile ("li $v0, 0x80000000\n"
"\tlw $t4, %1\n"
"\tlw $t5, %2\n"
"\tlw $t6, %3\n"
"\tlw $t7, %4\n"
"\tsyscall\n"
"\tlw $v1, %0\n"
"\tsw $t0, 0($v1)\n"
"\tsw $t1, 4($v1)\n"
"\tsw $t2, 8($v1)\n"
"\tsw $t3, 12($v1)\n"
"\tsw $a0, 16($v1)\n"
"\tsw $a1, 20($v1)\n"
"\tsw $a2, 24($v1)\n"
"\tsw $a3, 28($v1)\n"
"\tsw $v0, 32($v1)"
:
: "m"(msg)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
: "m"(msg), "m"(r0), "m"(r1), "m"(r2), "m"(r3)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "a0", "a1", "a2", "a3");
}
static void call (Capability target, Message *msg)
static void call (Capability target, Message *msg, Capability r0, Capability r1, Capability r2, Capability r3)
{
Capability t = cap_copy (target);
__asm__ volatile ("lw $v0, %0\n"
"\tlw $v1, %1\n"
"\tlw $t4, %1\n"
"\tlw $t5, %2\n"
"\tlw $t6, %3\n"
"\tlw $t7, %4\n"
"\tlw $t0, 0($v1)\n"
"\tlw $t1, 4($v1)\n"
"\tlw $t2, 8($v1)\n"
@ -249,14 +252,10 @@ static void call (Capability target, Message *msg)
"\tsw $t1, 4($v1)\n"
"\tsw $t2, 8($v1)\n"
"\tsw $t3, 12($v1)\n"
"\tsw $a0, 16($v1)\n"
"\tsw $a1, 20($v1)\n"
"\tsw $a2, 24($v1)\n"
"\tsw $a3, 28($v1)\n"
"\tsw $v0, 32($v1)"
:
: "m"(t), "m"(msg)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
: "m" (t), "m" (msg), "m" (r0), "m" (r1), "m" (r2), "m" (r3)
: "memory", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7");
}
static void invoke_00 (Capability t)
@ -385,6 +384,20 @@ static void invoke_13 (Capability t, Capability c, unsigned d0, unsigned d1, uns
invoke (t, &msg);
}
static void invoke_14 (Capability t, Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
{
Message msg;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = d3;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static void invoke_20 (Capability t, Capability c0, Capability c1)
{
Message msg;
@ -452,7 +465,7 @@ static void call_00 (Capability c)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static unsigned call_n00 (Capability c)
@ -466,11 +479,11 @@ static unsigned call_n00 (Capability c)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
static Capability call_c00 (Capability c)
static void call_c00 (Capability c, Capability target)
{
Message msg;
msg.cap[0] = c;
@ -481,11 +494,10 @@ static Capability call_c00 (Capability c)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static Capability call_c01 (Capability c, unsigned d)
static void call_c01 (Capability c, Capability target, unsigned d)
{
Message msg;
msg.cap[0] = c;
@ -496,8 +508,7 @@ static Capability call_c01 (Capability c, unsigned d)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static unsigned long long call_l01 (Capability c, unsigned d)
@ -511,11 +522,11 @@ static unsigned long long call_l01 (Capability c, unsigned d)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32);
}
static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
static void call_c02 (Capability c, Capability target, unsigned d0, unsigned d1)
{
Message msg;
msg.cap[0] = c;
@ -526,8 +537,7 @@ static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1)
@ -541,11 +551,11 @@ static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32);
}
static Capability call_c03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
static void call_c03 (Capability c, Capability target, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
msg.cap[0] = c;
@ -556,8 +566,7 @@ static Capability call_c03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
@ -571,11 +580,11 @@ static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsi
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32);
}
static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d1)
static void call_c12 (Capability c, Capability target, Capability c1, unsigned d0, unsigned d1)
{
Message msg;
msg.cap[0] = c;
@ -586,8 +595,21 @@ static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static void call_c13 (Capability c, Capability target, Capability c1, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static unsigned call_n01 (Capability c, unsigned d)
@ -601,7 +623,7 @@ static unsigned call_n01 (Capability c, unsigned d)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -616,7 +638,7 @@ static unsigned call_n11 (Capability c, Capability c1, unsigned d)
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -631,7 +653,7 @@ static unsigned call_n12 (Capability c, Capability c1, unsigned d0, unsigned d1)
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -646,7 +668,7 @@ static unsigned call_n14 (Capability c, Capability c1, unsigned d0, unsigned d1,
msg.data[3] = d3;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -661,7 +683,7 @@ static unsigned call_n02 (Capability c, unsigned d0, unsigned d1)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -676,7 +698,7 @@ static Capability call_p02 (Capability c, unsigned d0, unsigned d1, unsigned *ba
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
*base_return = msg.data[0];
return msg.cap[0];
}
@ -692,7 +714,7 @@ static unsigned call_n03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -708,10 +730,24 @@ static unsigned call_n04 (Capability c, unsigned d0, unsigned d1, unsigned d2, u
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
static void call_c11 (Capability target, Capability c, Capability c1, unsigned d)
{
Message msg;
msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d;
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
@ -723,7 +759,7 @@ static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1,
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
@ -738,13 +774,13 @@ static unsigned call_n33 (Capability c, Capability c1, Capability c2, Capability
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = 0;
call (__my_call, &msg);
call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
return msg.data[0];
}
static Capability degrade (Capability src, unsigned mask)
static void degrade (Capability target, Capability src, unsigned mask)
{
return call_c02 (src, CAP_DEGRADE, mask);
call_c02 (src, target, CAP_DEGRADE, mask);
}
static void schedule ()
@ -752,29 +788,34 @@ static void schedule ()
invoke_01 (__my_thread, CAP_THREAD_SCHEDULE);
}
static void capability_clone (Capability target, Capability src)
{
call_c11 (__my_thread, target, src, CAP_THREAD_CAP_CLONE);
}
static void register_interrupt (unsigned num)
{
invoke_12 (__my_thread, __my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num);
invoke_13 (__my_thread, __my_receiver, CAP_THREAD_PRIV, CAP_THREAD_PRIV_REGISTER_INTERRUPT, num);
}
static void unregister_interrupt (unsigned num)
{
invoke_02 (__my_thread, CAP_THREAD_REGISTER_INTERRUPT, num);
invoke_03 (__my_thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_REGISTER_INTERRUPT, num);
}
static Capability get_top_memory ()
static void get_top_memory (Capability target)
{
return call_c01 (__my_thread, CAP_THREAD_GET_TOP_MEMORY);
return call_c02 (__my_thread, target, CAP_THREAD_PRIV, CAP_THREAD_PRIV_GET_TOP_MEMORY);
}
static void alloc_physical (Capability page, unsigned address, int cachable, int freeable)
{
invoke_13 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0));
invoke_14 (__my_thread, page, CAP_THREAD_PRIV, CAP_THREAD_PRIV_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0));
}
static unsigned alloc_range (Capability memory, unsigned pages)
{
return call_n12 (__my_thread, memory, CAP_THREAD_ALLOC_RANGE, pages);
return call_n13 (__my_thread, memory, CAP_THREAD_PRIV, CAP_THREAD_PRIV_ALLOC_RANGE, pages);
}
static void receiver_set_owner (Capability receiver, Capability owner)
@ -782,9 +823,9 @@ static void receiver_set_owner (Capability receiver, Capability owner)
invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
}
static Capability receiver_create_capability (Capability receiver, unsigned protected_data)
static void receiver_create_capability (Capability target, Capability receiver, unsigned protected_data)
{
return call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
}
static unsigned receiver_reply_protected_data (Capability receiver, int set, unsigned data)
@ -825,47 +866,47 @@ static unsigned receiver_set_alarm (Capability receiver, unsigned data)
static void my_sleep (unsigned value, Message *ret)
{
receiver_set_alarm (__my_receiver, value);
wait (ret);
wait (ret, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE);
}
static Capability receiver_create_call_capability (Capability receiver)
static void receiver_create_call_capability (Capability target, Capability receiver)
{
return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0);
return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0);
}
static Capability receiver_create_async_call_capability (Capability receiver)
static void receiver_create_async_call_capability (Capability target, Capability receiver)
{
return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1);
return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1);
}
static Capability memory_create (Capability memory, unsigned type)
static void memory_create (Capability target, Capability memory, unsigned type)
{
return call_c02 (memory, CAP_MEMORY_CREATE, type);
return call_c02 (memory, target, CAP_MEMORY_CREATE, type);
}
static Capability memory_create_page (Capability memory)
static void memory_create_page (Capability target, Capability memory)
{
return memory_create (memory, CAPTYPE_PAGE | REQUEST_MASK);
return memory_create (memory, target, CAPTYPE_PAGE | REQUEST_MASK);
}
static Capability memory_create_thread (Capability memory)
static void memory_create_thread (Capability target, Capability memory)
{
return memory_create (memory, CAPTYPE_THREAD | REQUEST_MASK);
return memory_create (memory, target, CAPTYPE_THREAD | REQUEST_MASK);
}
static Capability memory_create_receiver (Capability memory)
static void memory_create_receiver (Capability target, Capability memory)
{
return memory_create (memory, CAPTYPE_RECEIVER | REQUEST_MASK);
return memory_create (memory, target, CAPTYPE_RECEIVER | REQUEST_MASK);
}
static Capability memory_create_memory (Capability memory)
static void memory_create_memory (Capability target, Capability memory)
{
return memory_create (memory, CAPTYPE_MEMORY | REQUEST_MASK);
return memory_create (memory, target, CAPTYPE_MEMORY | REQUEST_MASK);
}
static Capability memory_create_cappage (Capability memory, unsigned *base_return)
static void memory_create_caps (Capability target, Capability memory)
{
return call_p02 (memory, CAP_MEMORY_CREATE, CAPTYPE_CAPPAGE | REQUEST_MASK, base_return);
return memory_create (memory, target, CAPTYPE_CAPS | REQUEST_MASK);
}
static void memory_destroy (Capability memory, Capability target)
@ -882,24 +923,19 @@ static void memory_map (Capability memory, Capability page, unsigned address, in
invoke_12 (memory, page, CAP_MEMORY_MAP, address);
}
static Capability memory_mapping (Capability memory, void *address)
static void memory_mapping (Capability target, Capability memory, void *address)
{
return call_c02 (memory, CAP_MEMORY_MAPPING, (unsigned)address);
call_c02 (memory, target, CAP_MEMORY_MAPPING, (unsigned)address);
}
static unsigned memory_limit (Capability memory, unsigned limit)
{
return call_c02 (memory, CAP_MEMORY_LIMIT, limit);
return call_n02 (memory, CAP_MEMORY_LIMIT, limit);
}
static void drop (Capability cap)
static void thread_make_priv (Capability target, Capability thread)
{
invoke_11 (__my_memory, cap, CAP_MEMORY_DROP);
}
static Capability thread_make_priv (Capability thread)
{
return call_c12 (__my_thread, thread, CAP_THREAD_MAKE_PRIV, ~0);
call_c13 (__my_thread, target, thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_MAKE_PRIV, ~0);
}
static unsigned thread_info (Capability thread, unsigned info, unsigned value, unsigned mask)
@ -954,21 +990,20 @@ static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask)
static unsigned page_physical_address (Capability page)
{
return call_n11 (__my_thread, page, CAP_THREAD_PHYSICAL_ADDRESS);
return call_n12 (__my_thread, page, CAP_THREAD_PRIV, CAP_THREAD_PRIV_PHYSICAL_ADDRESS);
}
static Capability capability_get (Capability cap)
static void caps_set (Capability caps, Capability cap, unsigned index)
{
return call_c01 (cap, CAP_CAPABILITY_GET);
}
static void cappage_set (Capability page, Capability cap, unsigned index)
{
invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
invoke_12 (caps, cap, CAP_CAPS_SET, index);
}
#if 0
/* Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. */
#define kdebug_char(c) do { unsigned d = (c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(d) : "a0", "a1", "memory"); } while (0)
#else
#define kdebug_char(c) do {} while (0)
#endif
#define kdebug(str) do { const char *s = (str); while (*s) kdebug_char (*s++); } while (0)
static void kdebug_num (unsigned n)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -138,12 +138,11 @@
// Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h>
static void __map_io (unsigned physical, unsigned mapping):
Capability page = memory_create_page (__my_memory)
memory_create_page (6, __my_memory)
// 0 means not cachable; 0 means don't free when done.
alloc_physical (page, physical, 0, 0)
alloc_physical (6, physical, 0, 0)
// 1 means writable.
memory_map (__my_memory, page, mapping, 1)
drop (page)
memory_map (__my_memory, 6, mapping, 1)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)

View File

@ -19,12 +19,13 @@
#define ARCH
#include "kernel.hh"
#if 0
void dbg_log_char (unsigned ch):
if !dbg_cap:
return
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL
c.cap[i].reset ()
c.copy[i] = false
c.data[i] = 0
c.data[0] = ch
@ -72,3 +73,42 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag
dbg_log_num (n)
dbg_log_char ('\n')
// If no log capability is registered, the machine just hangs.
#else
void delay (unsigned ms):
for unsigned t = 0; t < 8000 * ms; ++t:
GPIO_GPDIR (0) = GPIO_GPDIR (0)
void set_leds (bool a, bool b):
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
if a:
GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
else:
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
if b:
GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
else:
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
void dbg_log_char (unsigned ch):
void dbg_log (char const *str):
void dbg_log_num (unsigned num):
void send (unsigned n):
for unsigned i = 0; i < 32; ++i:
bool v = n & (1 << 31)
set_leds (v, !v)
delay (350)
set_leds (false, false)
delay (150)
n <<= 1
set_leds (true, true)
delay (50)
set_leds (false, false)
delay (50)
void panic_impl (unsigned n, unsigned line, char const *name, char const *message):
unsigned epc
cp0_get (CP0_EPC, epc)
send (epc)
while true:
send (n)
#endif

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).
This is a very good thing.
\section{Communication}
This section shortly describes how communication between threads is performed
by Iris. Below are more details about the kernel structures, this section just
explains which steps are taken.
Iris doesn't hold any state about the communication, other than the state that
it holds for threads on request of the threads (in the memory paid for by the
threads). For Iris, there is no such thing as a \textit{conversation}. There
are messages. When there is a conversation, Iris just sees several messages
going both ways. For Iris these are not connected\footnote{This is not
entirely true; Iris has call capabilities as an optimization feature. They do
implement some conversation aspects. But they are only an optimization: Iris
doesn't require them to be used.}.
So understanding communication between threads boils down to understanding the
transfer of a single message. A message is short: four 32-bit words of data,
plus four capabilities. Besides that, a 64-bit protected value is sent. This
value is set by the creator of the capability, usually the server, and cannot
be changed by the invoker.
Sending a message between threads is mostly about a Receiver object. The
server has a Receiver, for which it creates a capability (with the mentioned
protected data). If a client wants to contact the server, it must get this
capability.
The client then invokes the capability with four data words and four
capabilities (possibly set to 0). The message is queued by the receiver. The
capabilities are stored into a Caps object.
When the server is ready for it, it queries the receiver for new messages. It
then gets the protected data, the four data words and copies of the
capabilities. The ones in the receiver's Caps are invalidated and can be
reused after that. Note that it does not get a capability of the sender,
unless the sender sends it. There is no way for the server to know who is
sending the message, only which capability was used (through the protected
data).
\section{Kernel objects}
This section describes all kernel objects of Iris, and the operations that can
be performed on them. One operation is possible on any kernel object (except a

View File

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