From fb5a3215549345277326716c3a36ed2581429183 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Wed, 5 Aug 2009 10:16:24 +0200 Subject: [PATCH] reorganize capabilities; doesn't work yet --- alloc.ccp | 232 +++++++------- boot-programs/crt0.S | 16 - boot-programs/devices.hhp | 36 ++- boot-programs/gpio.ccp | 224 ++++++-------- boot-programs/init.ccp | 56 ++-- boot-programs/lcd.ccp | 36 +-- invoke.ccp | 633 +++++++++++++++----------------------- iris.h | 275 +++++++++-------- kernel.hhp | 170 +++++----- mips/Makefile.arch | 4 +- mips/arch.ccp | 22 +- mips/arch.hhp | 6 +- mips/init.ccp | 47 ++- mips/interrupts.ccp | 26 +- mips/jz4730.hhp | 7 +- panic.ccp | 42 ++- report/kernel.tex | 37 +++ schedule.ccp | 10 +- 18 files changed, 883 insertions(+), 996 deletions(-) diff --git a/alloc.ccp b/alloc.ccp index f947c4b..8a6b21f 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -25,9 +25,9 @@ // The prev/next-lists contain only objects of one type, unsorted. // All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV. -#define PREV(x) (((Object_base **)(x))[-2]) -#define NEXT(x) (((Object_base **)(x))[-1]) -#define SIZE (2 * sizeof (Object_base *)) +#define PREV(x) (((Object **)(x))[-2]) +#define NEXT(x) (((Object **)(x))[-1]) +#define SIZE (2 * sizeof (Object *)) bool Memory::use (unsigned num): // Go up to parents, incrementing used. @@ -52,7 +52,7 @@ void *Memory::search_free (unsigned size, void **first): Free *f unsigned s = 0 // Let's see if there already is a Free chunk which is large enough. - for f = frees; f; f = f->next: + for f = frees; f; f = (Free *)f->next: if NEXT (f): s = (unsigned)NEXT (f) - (unsigned)f else: @@ -75,7 +75,7 @@ void *Memory::search_free (unsigned size, void **first): f->prev = NULL frees = f if f->next: - f->next->prev = f + ((Free *)f->next)->prev = f // There are no other objects in this page. NEXT (f) = NULL PREV (f) = NULL @@ -100,32 +100,35 @@ void *Memory::search_free (unsigned size, void **first): // The block was only just large enough: turn it into a new type. It is already linked into the page. // Unlink it from the free list. if f->prev: - f->prev->next = f->next + ((Free *)f->prev)->next = f->next else: - frees = f->next + frees = (Free *)f->next if f->next: - f->next->prev = f->prev + ((Free *)f->next)->prev = f->prev // f is now a block which is linked in the page, but not in any list. Link it into first. f->next = (Free *)*first f->prev = NULL if f->next: - f->next->prev = f + ((Free *)f->next)->prev = f *first = f // Set common initial values. f->address_space = this - f->refs = NULL + f->refs.reset () return f // Free an object; it is still in its list, and it is still in the page list. -void Memory::free_obj (Object_base *obj, void **first): +void Memory::free_obj (Object *obj, Pointer *first): Free *self = (Free *)obj + // Invalidate references. + while self->refs: + self->refs->invalidate () // Free it from its list. if self->prev: - self->prev->next = self->next + ((Free *)self->prev)->next = self->next else: - *(Object_base **)first = self->next + *(Pointer *)first = (Pointer)self->next if self->next: - self->next->prev = self->prev + ((Free *)self->next)->prev = self->prev // Merge with previous, if it exists and is a Free. if PREV (self) && PREV (self)->is_free (): self = (Free *)PREV (self) @@ -139,7 +142,7 @@ void Memory::free_obj (Object_base *obj, void **first): self->next = frees self->prev = NULL if self->next: - self->next->prev = self + ((Free *)self->next)->prev = self frees = self // Mark it as a Free. self->marker = ~0 @@ -148,11 +151,11 @@ void Memory::free_obj (Object_base *obj, void **first): // Unlink the next from the frees list. Free *n = (Free *)NEXT (self) if n->prev: - n->prev->next = n->next + ((Free *)n->prev)->next = n->next else: - frees = n->next + frees = (Free *)n->next if n->next: - n->next->prev = n->prev + ((Free *)n->next)->prev = n->prev // Unlink the next from the page list. NEXT (self) = NEXT (NEXT (self)) if NEXT (self): @@ -160,34 +163,34 @@ void Memory::free_obj (Object_base *obj, void **first): // Free page if the resulting object is the only thing in it. if !PREV (self) && !NEXT (self): if self->next: - self->next->prev = self->prev + ((Free *)self->next)->prev = self->prev if self->prev: - self->prev->next = self->next + ((Free *)self->prev)->next = self->next else: - frees = self->next + frees = (Free *)self->next pfree ((unsigned)self - SIZE) Page *Memory::alloc_page (): Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages) if !ret: return NULL - ret->data.frame = 0 - ret->data.flags = 0 + ret->frame = 0 + ret->flags = 0 return ret -Thread *Memory::alloc_thread (): - Thread *ret = (Thread *)search_free (sizeof (Thread), (void **)&threads) +Thread *Memory::alloc_thread (unsigned size): + Thread *ret = (Thread *)search_free (sizeof (Thread) + (size - 1) * sizeof (CapsP), (void **)&threads) if !ret: return NULL - ret->address_space = this + ret->receivers = NULL ret->pc = 0 ret->sp = 0 Thread_arch_init (ret) ret->flags = 0 ret->schedule_prev = NULL ret->schedule_next = NULL - ret->receivers = NULL - top_memory.alloc_capability (NULL, NULL, NULL, 0, &ret->exception) + for unsigned i = 0; i < size; ++i: + ret->caps[i] = NULL return ret Message *Memory::alloc_message (Receiver *target): @@ -206,55 +209,21 @@ Receiver *Memory::alloc_receiver (): ret->prev_owned = NULL ret->next_owned = NULL ret->alarm_count = ~0 - ret->capabilities = NULL + ret->caps = NULL + ret->capabilities.reset () ret->messages = NULL ret->last_message = NULL ret->reply_protected_data = ~0 ret->protected_only = false return ret -Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret): - if !ret: - ret = (Capability *)search_free (sizeof (Capability), (void **)&capabilities) - if !ret: - return NULL - ret->target = target - ret->protected_data = protected_data - ret->parent = parent - ret->children = NULL - ret->sibling_prev = NULL - if parent: - ret->sibling_next = parent->children - parent->children = ret - else: - if parent_ptr: - ret->sibling_next = *parent_ptr - else: - ret->sibling_next = NULL - if ret->sibling_next: - ret->sibling_next->sibling_prev = ret - return ret - -Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret): - if copy: - if source->parent: - return alloc_capability (source->target, source->parent, &source->parent->children, source->protected_data, ret) - else if (unsigned)source->target & ~KERNEL_MASK: - return alloc_capability (source->target, source->parent, &source->target->capabilities, source->protected_data, ret) - else: - return alloc_capability (source->target, source->parent, &((Object_base *)source->protected_data)->refs, source->protected_data, ret) - else: - return alloc_capability (source->target, source, &source->children, source->protected_data, ret) - -Cappage *Memory::alloc_cappage (): - Cappage *ret = (Cappage *)search_free (sizeof (Cappage), (void **)&cappages) +Caps *Memory::alloc_caps (unsigned size): + Caps *ret = (Caps *)search_free (sizeof (Caps) + (size - 1) * sizeof (Capability), (void **)&capses) if !ret: return NULL - ret->data.frame = zalloc () - if !ret->data.frame: - free_cappage (ret) - return NULL - ret->data.flags = 0 + ret->size = size + for unsigned i = 0; i < size; ++i: + ret->set (i, NULL, 0, CapRef (), NULL) return ret Memory *Memory::alloc_memory (): @@ -264,32 +233,59 @@ Memory *Memory::alloc_memory (): ret->frees = NULL ret->pages = NULL ret->threads = NULL + ret->capses = NULL + ret->receivers = NULL ret->memories = NULL ret->limit = ~0 ret->used = 0 Memory_arch_init (ret) return ret +void Caps::set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr): + caps[index].target = target + caps[index].protected_data = pdata + caps[index].parent = parent + caps[index].children.reset () + caps[index].sibling_prev.reset () + if parent: + caps[index].sibling_next = parent->children + parent->children = CapRef (this, index) + else: + if parent_ptr: + caps[index].sibling_next = *parent_ptr + *parent_ptr = CapRef (this, index) + else: + caps[index].sibling_next.reset () + if caps[index].sibling_next: + caps[index].sibling_next->sibling_prev = CapRef (this, index) + +void Caps::clone (unsigned index, CapRef source, bool copy): + if copy: + if source->parent: + set (index, source->target, source->protected_data, source->parent) + else if (unsigned)source->target & ~KERNEL_MASK: + set (index, source->target, source->protected_data, CapRef (), &source->target->capabilities) + else: + set (index, source->target, source->protected_data, CapRef (), &((Object *)source->protected_data)->refs) + else: + set (index, source->target, source->protected_data, source) + void Memory::free_page (Page *page): - if page->data.flags & PAGE_FLAG_PAYING: + if page->flags & PAGE_FLAG_PAYING: unuse () - if page->data.frame: - pfree (page->data.frame) - free_obj (page, (void **)&pages) + if page->frame: + pfree (page->frame) + free_obj (page, (Pointer *)&pages) void Memory::free_thread (Thread *thread): thread->unrun () while thread->receivers: thread->receivers->orphan () - thread->exception.invalidate () free_obj (thread, (void **)&threads) void Memory::free_message (Receiver *owner, Message *message): if !message->next: - owner->last_message = message->prev - for unsigned i = 0; i < 4; ++i: - if message->capabilities[i]: - free_capability (message->capabilities[i]) + owner->last_message = (MessageP)message->prev free_obj (message, (void **)&owner->messages) void Memory::free_receiver (Receiver *receiver): @@ -318,10 +314,6 @@ void Receiver::own (Thread *o): next_owned->prev_owned = this o->receivers = this -void Memory::free_capability (Capability *capability): - capability->invalidate () - free_obj (capability, (void **)&capabilities) - void Capability::invalidate (): if !target: return @@ -330,78 +322,60 @@ void Capability::invalidate (): else if (unsigned)target & ~KERNEL_MASK: target->capabilities = sibling_next else: - ((Object_base *)protected_data)->refs = sibling_next + ((Object *)protected_data)->refs = sibling_next if sibling_next: sibling_next->sibling_prev = sibling_prev - parent = NULL - sibling_prev = NULL - sibling_next = NULL + parent.reset () + sibling_prev.reset () + sibling_next.reset () Capability *c = this - while c->children: - c = c->children while c: - Capability *next = c->sibling_next + while c->children: + c = c->children.deref () + Capability *next = c->sibling_next.deref () if !next: - next = c->parent + next = c->parent.deref () c->target = NULL - c->parent = NULL - c->children = NULL - c->sibling_prev = NULL - c->sibling_next = NULL + c->parent.reset () + c->children.reset () + c->sibling_prev.reset () + c->sibling_next.reset () c->protected_data = 0 c = next -void Memory::free_cappage (Cappage *p): - for unsigned i = 0; i < CAPPAGE_SIZE; ++i: - ((Capability *)p->data.frame)[i].invalidate () - zfree (p->data.frame) - free_obj (p, (void **)&cappages) +void Memory::free_caps (Caps *c): + for unsigned i = 0; i < c->size; ++i: + c->caps[i].invalidate () + free_obj (c, (void **)&capses) void Memory::free_memory (Memory *mem): while mem->pages: free_page (mem->pages) - while mem->cappages: - free_cappage (mem->cappages) + while mem->capses: + free_caps (mem->capses) while mem->threads: free_thread (mem->threads) while mem->memories: free_memory (mem->memories) while mem->receivers: free_receiver (mem->receivers) - while mem->capabilities: - free_capability (mem->capabilities) Memory_arch_free (mem) if mem->frees: panic (0, "kernel memory leak: memory still in use") free_obj (mem, (void **)&memories) void Page::forget (): - if data.share_prev || data.share_next: - if data.share_prev: - ((Page *)data.share_prev)->data.share_next = data.share_next - if data.share_next: - ((Page *)data.share_next)->data.share_prev = data.share_prev - data.share_prev = NULL - data.share_next = NULL + if share_prev || share_next: + if share_prev: + share_prev->share_next = share_next + if share_next: + share_next->share_prev = share_prev + share_prev = NULL + share_next = NULL else: // If the page has a frame and should be freed, free it. - if !((data.flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)): - raw_pfree (data.frame) - data.frame = 0 - data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) + if !((flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)): + raw_pfree (frame) + frame = 0 + flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) Page_arch_update_mapping (this) - -void Cappage::forget (): - if data.share_prev || data.share_next: - if data.share_prev: - ((Cappage *)data.share_prev)->data.share_next = data.share_next - if data.share_next: - ((Cappage *)data.share_next)->data.share_prev = data.share_prev - data.share_prev = NULL - data.share_next = NULL - else: - for unsigned i = 0; i < CAPPAGE_SIZE; ++i: - ((Capability *)data.frame)[i].invalidate () - raw_pfree (data.frame) - data.frame = 0 - data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED) diff --git a/boot-programs/crt0.S b/boot-programs/crt0.S index be5cfe8..f1e9d6d 100644 --- a/boot-programs/crt0.S +++ b/boot-programs/crt0.S @@ -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 diff --git a/boot-programs/devices.hhp b/boot-programs/devices.hhp index dcf4a98..6e8c8ea 100644 --- a/boot-programs/devices.hhp +++ b/boot-programs/devices.hhp @@ -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) diff --git a/boot-programs/gpio.ccp b/boot-programs/gpio.ccp index 74be5fc..ff90ee2 100644 --- a/boot-programs/gpio.ccp +++ b/boot-programs/gpio.ccp @@ -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]) diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index d93127b..f518666 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -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 diff --git a/boot-programs/lcd.ccp b/boot-programs/lcd.ccp index e385f0d..b3da451 100644 --- a/boot-programs/lcd.ccp +++ b/boot-programs/lcd.ccp @@ -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) diff --git a/invoke.ccp b/invoke.ccp index 62dd861..8869b2d 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -19,6 +19,7 @@ #include "kernel.hh" void Thread::raise (unsigned code, unsigned data): + panic (code, "raise") dbg_log ("raise ") dbg_log_num ((unsigned)current) dbg_log_char ('/') @@ -31,47 +32,32 @@ void Thread::raise (unsigned code, unsigned data): dbg_log_num (data) dbg_log_char ('\n') unrun () - if !exception.target: + if !caps[0] || !caps[0]->caps[0].target: return Capability::Context c for unsigned i = 0; i < 4; ++i: - c.cap[i] = NULL + c.cap[i] = CapRef () c.copy[i] = false c.data[0] = code c.data[1] = data c.data[2] = 0 c.data[3] = 0 - exception.invoke (&c) + caps[0]->caps[0].invoke (&c) // From user-provided, thus untrusted, data, find a capability. -Capability *Memory::find_capability (unsigned code, bool *copy): - *copy = code & 2 ? true : false - if !(code & ~3): - return NULL - if code & 1: - // Cappage capability - unsigned num = (code & ~PAGE_MASK) >> 2 - if num >= CAPPAGE_SIZE: +CapRef Thread::find_capability (unsigned code, bool *copy): + *copy = code & CAPABILITY_COPY + unsigned c = code & ~CAPABILITY_COPY + unsigned slot = c >> 16 + unsigned num = c & 0xffff + if slot >= slots || !caps[slot] || num >= caps[slot]->size || !caps[slot]->caps[num].target: + if c != CAPABILITY_NONE: dbg_log_num ((unsigned)old_current) - dbg_log (": invalid cappage index ") - dbg_log_num (num) + dbg_log (": invalid capability ") + dbg_log_num (code) dbg_log_char ('\n') - return NULL - unsigned page = code & PAGE_MASK - for Cappage *p = cappages; p; p = p->next: - if p->data.frame == page: - return p->cap (num) - else: - // Normal capability - Capability *target = (Capability *)(code & ~3) - for Capability *c = capabilities; c; c = c->next: - if c == target: - return c - dbg_log_num ((unsigned)old_current) - dbg_log (": invalid capability ") - dbg_log_num (code) - dbg_log_char ('\n') - return NULL + return CapRef () + return CapRef (caps[slot], num) // Try to deliver a message. bool Receiver::try_deliver (): @@ -81,148 +67,125 @@ bool Receiver::try_deliver (): return false Message *m = last_message if protected_only: - for ; m; m = m->prev: + for ; m; m = (Message *)m->prev: if m->protected_data == reply_protected_data: protected_only = false break if !m: return false - Capability::Context c for unsigned i = 0; i < 4; ++i: - c.data[i] = m->data[i] - if m->capabilities[i]: - c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true) - if !c.cap[i]: - owner->raise (ERR_OUT_OF_MEMORY, 0) - for unsigned j = 0; j < i; ++j: - owner->address_space->free_capability (c.cap[i]) - return false - else: - c.cap[i] = NULL - Thread_arch_receive (owner, m->protected_data, &c) + if owner->rcaps[i]: + owner->rcaps[i]->invalidate () + if m->capabilities[i] < caps->size: + owner->rcaps[i].clone (CapRef (caps, m->capabilities[i]), true) + Thread_arch_receive (owner, m->protected_data, m->data) address_space->free_message (this, m) owner->unwait () return true // Send a message to a receiver; try to deliver it immediately. bool Receiver::send_message (unsigned protected_data, Capability::Context *c): - bool tried_direct = false if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only): - Capability *orig[4] - for unsigned i = 0; i < 4; ++i: - if c->cap[i]: - orig[i] = c->cap[i] - c->cap[i] = owner->address_space->clone_capability (orig[i], c->copy[i]) - if !c->cap[i]: - owner->raise (ERR_OUT_OF_MEMORY, 0) - for unsigned j = 0; j < i; ++j: - owner->address_space->free_capability (c->cap[j]) - c->cap[j] = orig[j] - c->cap[i] = orig[i] - return false - if protected_data == reply_protected_data: + if protected_only: protected_only = false - Thread_arch_receive (owner, protected_data, c) + for unsigned i = 0; i < 4; ++i: + if owner->rcaps[i]: + owner->rcaps[i]->invalidate () + if c->cap[i]: + owner->rcaps[i].clone (c->cap[i], c->copy[i]) + Thread_arch_receive (owner, protected_data, c->data) owner->unwait () return true // The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. Message *msg = address_space->alloc_message (this) if !msg: if owner: + // TODO: avoid loops. owner->raise (ERR_OUT_OF_MEMORY, 0) return false msg->protected_data = protected_data - if protected_data == reply_protected_data: + if protected_only && protected_data == reply_protected_data: // Put this message in the end (where it will be first seen). Clear the protected_only flag. protected_only = false if msg->next: - msg->next->prev = NULL - messages = msg->next + ((Message *)msg->next)->prev = NULL + messages = (Message *)msg->next msg->next = NULL msg->prev = last_message - msg->prev->next = msg + ((Message *)msg->prev)->next = msg last_message = msg for unsigned i = 0; i < 4; ++i: msg->data[i] = c->data[i] - if !c->cap[i]: - msg->capabilities[i] = NULL + if !c->cap[i] || !caps: + msg->capabilities[i] = 0xff else: - msg->capabilities[i] = address_space->clone_capability (c->cap[i], c->copy[i]) - if !msg->capabilities[i]: + unsigned t + random = (random + 1) % caps->size + for t = (random + 1) % caps->size; t != random; t = (t + 1) % caps->size: + if caps->caps[t].target: + continue + if t == random: if owner: + // TODO: avoid loops. owner->raise (ERR_OUT_OF_MEMORY, 0) for unsigned j = 0; j < i; ++j: - address_space->free_capability (msg->capabilities[j]) + if msg->capabilities[j] != 0xff: + caps->caps[msg->capabilities[j]].invalidate () address_space->free_message (this, msg) return false + msg->capabilities[i] = t + caps->clone (t, c->cap[i], c->copy[i]) return true static Capability *reply static Receiver *reply_receiver -static void fill_cap (Capability *r, unsigned target, unsigned protected_data): - Capability **ref +static void fill_cap (CapRef r, unsigned target, unsigned protected_data): + CapRef *ref if target & ~KERNEL_MASK: ref = &((Receiver *)target)->capabilities else: - ref = &((Object_base *)protected_data)->refs - // alloc_capability needs a Memory, but it isn't used if return storage is given. - top_memory.alloc_capability ((Receiver *)target, NULL, ref, protected_data, r) + ref = &((Object *)protected_data)->refs + r.set ((Receiver *)target, protected_data, CapRef (), ref) static void reply_cap (unsigned target, unsigned protected_data): - Capability r - fill_cap (&r, target, protected_data) + Caps r + fill_cap (CapRef (&r, 0), target, protected_data) Capability::Context c for unsigned i = 0; i < 4; ++i: c.data[i] = 0 - c.cap[0] = &r + c.cap[0] = CapRef (&r, 0) c.copy[0] = true for unsigned i = 1; i < 4; ++i: - c.cap[i] = NULL + c.cap[i].reset () c.copy[i] = false if reply: reply->invoke (&c) else if reply_receiver: reply_receiver->send_message (reply_receiver->reply_protected_data, &c) - r.invalidate () + r.caps[0].invalidate () -static void reply_cap (Capability *cap, bool copy): +static void reply_cap (CapRef cap, bool copy): Capability::Context c for unsigned i = 0; i < 4; ++i: c.data[i] = 0 c.cap[0] = cap c.copy[0] = copy for unsigned i = 1; i < 4; ++i: - c.cap[i] = NULL + c.cap[i].reset () c.copy[i] = false if reply: reply->invoke (&c) else if reply_receiver: reply_receiver->send_message (reply_receiver->reply_protected_data, &c) -static void reply_cappage (Cappage *cap, unsigned target): - Capability r - fill_cap (&r, target, (unsigned)cap) - Capability::Context c - for unsigned i = 1; i < 4; ++i: - c.data[i] = 0 - c.cap[i] = NULL - c.copy[i] = false - c.data[0] = cap->data.frame - c.cap[0] = &r - c.copy[0] = true - if reply: - reply->invoke (&c) - else if reply_receiver: - reply_receiver->send_message (reply_receiver->reply_protected_data, &c) - static void reply_num (unsigned num): Capability::Context c c.data[0] = num for unsigned i = 1; i < 4; ++i: c.data[i] = 0 for unsigned i = 0; i < 4; ++i: - c.cap[i] = NULL + c.cap[i].reset () c.copy[i] = false if reply: reply->invoke (&c) @@ -236,7 +199,7 @@ static void reply_nums (unsigned num1, unsigned num2): c.data[2] = 0 c.data[3] = 0 for unsigned i = 0; i < 4; ++i: - c.cap[i] = NULL + c.cap[i].reset () c.copy[i] = false if reply: reply->invoke (&c) @@ -313,7 +276,7 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability: reply_num (0) break case CAPTYPE_THREAD: - Thread *ret = mem->alloc_thread () + Thread *ret = mem->alloc_thread (c->data[2]) if ret: reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret) else: @@ -326,10 +289,10 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability: else: reply_num (0) break - case CAPTYPE_CAPPAGE: - Cappage *ret = mem->alloc_cappage () + case CAPTYPE_CAPS: + Caps *ret = mem->alloc_caps (c->data[2]) if ret: - reply_cappage (ret, CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS)) + reply_cap (CAPTYPE_CAPS | (rights & CAP_CAPS_ALL_RIGHTS), (unsigned)ret) else: reply_num (0) break @@ -352,11 +315,8 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability: case CAPTYPE_PAGE: mem->free_page ((Page *)c->cap[0]->protected_data) break - case CAPTYPE_CAPABILITY: - mem->free_capability ((Capability *)c->cap[0]->protected_data) - break - case CAPTYPE_CAPPAGE: - mem->free_cappage ((Cappage *)c->cap[0]->protected_data) + case CAPTYPE_CAPS: + mem->free_caps ((Caps *)c->cap[0]->protected_data) break default: panic (0x55228930, "invalid case") @@ -388,11 +348,6 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability: if c->data[2]: mem->limit = c->data[1] break - case CAP_MEMORY_DROP: - if !c->cap[0] || c->cap[0]->address_space != mem: - break - mem->free_capability (c->cap[0]) - break default: break @@ -416,7 +371,7 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability: unsigned v = (*value & c->data[3]) | (c->data[2] & c->data[3]) if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING): if v & THREAD_FLAG_WAITING: - thread->wait () + thread->wait (CapRef (), CapRef (), CapRef (), CapRef ()) else thread->unwait () if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING): @@ -437,281 +392,186 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability: case CAP_THREAD_SCHEDULE: do_schedule = true break - case CAP_THREAD_REGISTER_INTERRUPT: - // Threads with access to this call are trusted, so no sanity checking is done. - arch_register_interrupt (c->data[1], c->cap[0] ? (Receiver *)c->cap[0]->protected_data : NULL) - break - case CAP_THREAD_GET_TOP_MEMORY: - // Threads with access to this call are trusted, so no sanity checking is done. - reply_cap (CAPTYPE_MEMORY | (c->data[1] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory) - break - case CAP_THREAD_MAKE_PRIV: - // Threads with access to this call are trusted, so no sanity checking is done. - if c->data[1] & THREAD_FLAG_PRIV: - ((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV - reply_cap (CAPTYPE_THREAD | (c->data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data) - break - case CAP_THREAD_ALLOC_RANGE: - // Threads with access to this call are trusted, so not much sanity checking is done. - Memory *mem = (Memory *)c->cap[1]->protected_data - if !mem->use (c->data[1]): - reply_num (0) - break - unsigned data = phys_alloc (c->data[1]) - if !data: - mem->unuse (c->data[1]) - reply_num (0) - break - reply_num (data - 0x80000000) - break - case CAP_THREAD_ALLOC_PHYSICAL: - // Threads with access to this call are trusted, so no sanity checking is done. - Page *page = (Page *)c->cap[0]->protected_data - page->forget () - if !(c->data[2] & 2): - if page->data.flags & PAGE_FLAG_PAYING: - page->data.flags &= ~PAGE_FLAG_PAYING - page->address_space->unuse () - else: - // This is for mapping allocated ranges. They are already paid for. Record that. - if page->data.flags & PAGE_FLAG_PAYING: - page->address_space->unuse () - else: - page->data.flags |= PAGE_FLAG_PAYING - page->data.frame = c->data[1] - page->data.flags |= PAGE_FLAG_FRAME - if !(c->data[2] & 1): - page->data.flags |= PAGE_FLAG_UNCACHED - if !(c->data[2] & 2): - page->data.flags |= PAGE_FLAG_PHYSICAL - Page_arch_update_mapping (page) - break - case CAP_THREAD_PHYSICAL_ADDRESS: - // Threads with access to this call are trusted, so no sanity checking is done. - Page *page = (Page *)c->cap[1]->protected_data - reply_num (page->data.frame & ~0xc0000000) + case CAP_THREAD_CAP_CLONE: + reply_cap (c->cap[0], c->copy[0]) break + case CAP_THREAD_PRIV: + switch c->data[1]: + case CAP_THREAD_PRIV_REGISTER_INTERRUPT: + // Threads with access to this call are trusted, so no sanity checking is done. + arch_register_interrupt (c->data[2], c->cap[0] ? (Receiver *)c->cap[0]->protected_data : NULL) + break + case CAP_THREAD_PRIV_GET_TOP_MEMORY: + // Threads with access to this call are trusted, so no sanity checking is done. + reply_cap (CAPTYPE_MEMORY | (c->data[2] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory) + break + case CAP_THREAD_PRIV_MAKE_PRIV: + // Threads with access to this call are trusted, so no sanity checking is done. + if c->data[2] & THREAD_FLAG_PRIV: + ((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV + reply_cap (CAPTYPE_THREAD | (c->data[2] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data) + break + case CAP_THREAD_PRIV_ALLOC_RANGE: + // Threads with access to this call are trusted, so not much sanity checking is done. + Memory *mem = (Memory *)c->cap[1]->protected_data + if !mem->use (c->data[2]): + reply_num (0) + break + unsigned data = phys_alloc (c->data[2]) + if !data: + mem->unuse (c->data[2]) + reply_num (0) + break + reply_num (data - 0x80000000) + break + case CAP_THREAD_PRIV_ALLOC_PHYSICAL: + // Threads with access to this call are trusted, so no sanity checking is done. + Page *page = (Page *)c->cap[0]->protected_data + page->forget () + if !(c->data[3] & 2): + if page->flags & PAGE_FLAG_PAYING: + page->flags &= ~PAGE_FLAG_PAYING + page->address_space->unuse () + else: + // This is for mapping allocated ranges. They are already paid for. Record that. + if page->flags & PAGE_FLAG_PAYING: + page->address_space->unuse () + else: + page->flags |= PAGE_FLAG_PAYING + page->frame = c->data[2] + page->flags |= PAGE_FLAG_FRAME + if !(c->data[3] & 1): + page->flags |= PAGE_FLAG_UNCACHED + if !(c->data[3] & 2): + page->flags |= PAGE_FLAG_PHYSICAL + Page_arch_update_mapping (page) + break + case CAP_THREAD_PRIV_PHYSICAL_ADDRESS: + // Threads with access to this call are trusted, so no sanity checking is done. + Page *page = (Page *)c->cap[1]->protected_data + reply_num (page->frame & ~0xc0000000) + break + default: + break default: break static bool page_check_payment (Page *page): Page *p - for p = (Page *)page->data.share_prev; p; p = (Page *)p->data.share_prev: - if p->data.flags & PAGE_FLAG_PAYING: + for p = page->share_prev; p; p = p->share_prev: + if p->flags & PAGE_FLAG_PAYING: return true - for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next: - if p->data.flags & PAGE_FLAG_PAYING: + for p = page->share_next; p; p = p->share_next: + if p->flags & PAGE_FLAG_PAYING: return true // No Page is paying for this frame anymore. - raw_pfree (page->data.frame) + raw_pfree (page->frame) Page *next - for p = (Page *)page->data.share_prev, next = (Page *)p->data.share_prev; p; p = next, next = (Page *)p->data.share_prev: - p->data.frame = NULL - p->data.share_prev = NULL - p->data.share_next = NULL - p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) + for p = page->share_prev, next = p->share_prev; p; p = next, next = p->share_prev: + p->frame = NULL + p->share_prev = NULL + p->share_next = NULL + p->flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) Page_arch_update_mapping (p) - for p = page, next = (Page *)p->data.share_next; p; p = next, next = (Page *)p->data.share_next: - p->data.frame = NULL - p->data.share_prev = NULL - p->data.share_next = NULL - p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) + for p = page, next = p->share_next; p; p = next, next = p->share_next: + p->frame = NULL + p->share_prev = NULL + p->share_next = NULL + p->flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) Page_arch_update_mapping (p) return false -static bool cappage_check_payment (Cappage *cappage): - Cappage *p - for p = (Cappage *)cappage->data.share_prev; p; p = (Cappage *)p->data.share_prev: - if p->data.flags & PAGE_FLAG_PAYING: - return true - for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next: - if p->data.flags & PAGE_FLAG_PAYING: - return true - // No Page is paying for this frame anymore. - for unsigned i = 0; i < CAPPAGE_SIZE; ++i: - ((Capability *)cappage->data.frame)[i].invalidate () - raw_pfree (cappage->data.frame) - Cappage *next - for p = (Cappage *)cappage->data.share_prev, next = (Cappage *)p->data.share_prev; p; p = next, next = (Cappage *)p->data.share_prev: - p->data.frame = NULL - p->data.share_prev = NULL - p->data.share_next = NULL - p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) - for p = cappage, next = (Cappage *)p->data.share_next; p; p = next, next = (Cappage *)p->data.share_next: - p->data.frame = NULL - p->data.share_prev = NULL - p->data.share_next = NULL - p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) - return false - static void page_invoke (unsigned target, unsigned protected_data, Capability::Context *c): - Page *page - Cappage *cappage - ShareData *share_data - if (target & CAPTYPE_MASK) == CAPTYPE_PAGE: - page = (Page *)protected_data - cappage = NULL - share_data = &page->data - else: - page = NULL - cappage = (Cappage *)protected_data - share_data = &cappage->data + Page *page = (Page *)protected_data switch c->data[0]: case CAP_PAGE_SHARE: - if !c->cap[0] || ((unsigned)c->cap[0]->target & CAPTYPE_MASK) != (target & CAPTYPE_MASK): + if !c->cap[0] || ((unsigned)c->cap[0]->target & ~REQUEST_MASK) != CAPTYPE_PAGE: // FIXME: This makes it impossible to use a fake Page capability. break - if page: - Page *t = (Page *)c->cap[0]->protected_data - t->forget () - if c->data[1] & PAGE_SHARE_READONLY: - t->data.flags &= ~PAGE_FLAG_WRITABLE - if !page->data.flags & PAGE_FLAG_FRAME: + Page *t = (Page *)c->cap[0]->protected_data + t->forget () + if c->data[1] & PAGE_SHARE_READONLY: + t->flags &= ~PAGE_FLAG_WRITABLE + if !page->flags & PAGE_FLAG_FRAME: + break + if c->data[1] & PAGE_SHARE_COPY: + if ~t->flags & PAGE_FLAG_PAYING: break - if c->data[1] & PAGE_SHARE_COPY: - if ~t->data.flags & PAGE_FLAG_PAYING: - break - if ~c->data[1] & PAGE_SHARE_FORGET || page->data.flags & PAGE_FLAG_SHARED: - unsigned *d = (unsigned *)page->data.frame - if t == page: - Page *other = page->data.share_next ? (Page *)page->data.share_next : (Page *)page->data.share_prev - if !other: - Page_arch_update_mapping (t) - break - if page->data.share_next: - ((Page *)page->data.share_next)->data.share_prev = page->data.share_prev - if page->data.share_prev: - ((Page *)page->data.share_prev)->data.share_next = page->data.share_next - page->data.share_next = NULL - page->data.share_prev = NULL - page_check_payment (other) - else: - t->data.flags |= PAGE_FLAG_FRAME - t->data.frame = raw_zalloc () - for unsigned i = 0; i <= (c->data[1] & ~PAGE_MASK); i += 4: - ((unsigned *)t->data.frame)[i >> 2] = d[i >> 2] - else: - if t != page: - t->data.frame = page->data.frame - t->data.flags |= PAGE_FLAG_FRAME - page->data.frame = NULL - page->data.flags &= ~PAGE_FLAG_FRAME - Page_arch_update_mapping (page) - Page_arch_update_mapping (t) - else: + if ~c->data[1] & PAGE_SHARE_FORGET || page->flags & PAGE_FLAG_SHARED: + unsigned *d = (unsigned *)page->frame if t == page: - break - if c->data[1] & PAGE_SHARE_FORGET: - if ~page->data.flags & PAGE_FLAG_SHARED: - if t->data.flags & PAGE_FLAG_PAYING: - t->data.frame = page->data.frame - t->data.flags |= PAGE_FLAG_FRAME - page->data.frame = NULL - page->data.flags &= ~PAGE_FLAG_FRAME - Page_arch_update_mapping (page) - else: - t->data.share_prev = page->data.share_prev - t->data.share_next = page->data.share_next - if t->data.share_prev: - ((Page *)t->data.share_prev)->data.share_next = t - if t->data.share_next: - ((Page *)t->data.share_next)->data.share_prev = t - page->data.share_prev = NULL - page->data.share_next = NULL - page->forget () - page_check_payment (t) + Page *other = page->share_next ? page->share_next : page->share_prev + if !other: + Page_arch_update_mapping (t) + break + if page->share_next: + page->share_next->share_prev = page->share_prev + if page->share_prev: + page->share_prev->share_next = page->share_next + page->share_next = NULL + page->share_prev = NULL + page_check_payment (other) else: - t->data.share_prev = page->data.share_prev - t->data.share_next = page - page->data.share_prev = t - if t->data.share_prev: - ((Page *)t->data.share_prev)->data.share_next = t - Page_arch_update_mapping (t) - else: - Cappage *t = (Cappage *)c->cap[0]->protected_data - t->forget () - if c->data[1] & PAGE_SHARE_READONLY: - t->data.flags &= ~PAGE_FLAG_WRITABLE - if !cappage->data.flags & PAGE_FLAG_FRAME: - break - if c->data[1] & PAGE_SHARE_COPY: - if ~t->data.flags & PAGE_FLAG_PAYING: - break - if ~c->data[1] & PAGE_SHARE_FORGET || cappage->data.flags & PAGE_FLAG_SHARED: - unsigned *d = (unsigned *)cappage->data.frame - if t == cappage: - Cappage *other = cappage->data.share_next ? (Cappage *)cappage->data.share_next : (Cappage *)cappage->data.share_prev - if !other: - break - if cappage->data.share_next: - ((Cappage *)cappage->data.share_next)->data.share_prev = cappage->data.share_prev - if cappage->data.share_prev: - ((Cappage *)cappage->data.share_prev)->data.share_next = cappage->data.share_next - cappage->data.share_next = NULL - cappage->data.share_prev = NULL - cappage_check_payment (other) - else: - t->data.flags |= PAGE_FLAG_FRAME - t->data.frame = raw_zalloc () - for unsigned i = 0; i < ((c->data[1] & ~PAGE_MASK) + 1) * sizeof (Capability); i += 4: - ((unsigned *)t->data.frame)[i >> 2] = d[i >> 2] - else: - if t != cappage: - t->data.frame = cappage->data.frame - t->data.flags |= PAGE_FLAG_FRAME - cappage->data.frame = NULL - cappage->data.flags &= ~PAGE_FLAG_FRAME + t->flags |= PAGE_FLAG_FRAME + t->frame = raw_zalloc () + for unsigned i = 0; i <= (c->data[1] & ~PAGE_MASK); i += 4: + ((unsigned *)t->frame)[i >> 2] = d[i >> 2] else: - if t == cappage: - break - if c->data[1] & PAGE_SHARE_FORGET: - if ~cappage->data.flags & PAGE_FLAG_SHARED: - if t->data.flags & PAGE_FLAG_PAYING: - t->data.frame = cappage->data.frame - t->data.flags |= PAGE_FLAG_FRAME - cappage->data.frame = NULL - cappage->data.flags &= ~PAGE_FLAG_FRAME - else: - t->data.share_prev = cappage->data.share_prev - t->data.share_next = cappage->data.share_next - if t->data.share_prev: - ((Cappage *)t->data.share_prev)->data.share_next = t - if t->data.share_next: - ((Cappage *)t->data.share_next)->data.share_prev = t - cappage->data.share_prev = NULL - cappage->data.share_next = NULL - cappage->forget () - cappage_check_payment (t) + if t != page: + t->frame = page->frame + t->flags |= PAGE_FLAG_FRAME + page->frame = NULL + page->flags &= ~PAGE_FLAG_FRAME + Page_arch_update_mapping (page) + Page_arch_update_mapping (t) + else: + if t == page: + break + if c->data[1] & PAGE_SHARE_FORGET: + if ~page->flags & PAGE_FLAG_SHARED: + if t->flags & PAGE_FLAG_PAYING: + t->frame = page->frame + t->flags |= PAGE_FLAG_FRAME + page->frame = NULL + page->flags &= ~PAGE_FLAG_FRAME + Page_arch_update_mapping (page) else: - t->data.share_prev = cappage->data.share_prev - t->data.share_next = cappage - cappage->data.share_prev = t - if t->data.share_prev: - ((Cappage *)t->data.share_prev)->data.share_next = t + t->share_prev = page->share_prev + t->share_next = page->share_next + if t->share_prev: + t->share_prev->share_next = t + if t->share_next: + t->share_next->share_prev = t + page->share_prev = NULL + page->share_next = NULL + page->forget () + page_check_payment (t) + else: + t->share_prev = page->share_prev + t->share_next = page + page->share_prev = t + if t->share_prev: + t->share_prev->share_next = t + Page_arch_update_mapping (t) + break case CAP_PAGE_FLAGS: // Always refuse to set reserved flags. c->data[2] &= ~(PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) // Remember the old flags. - unsigned old = share_data->flags + unsigned old = page->flags // Compute the new flags. - unsigned new_flags = (share_data->flags & ~c->data[2]) | (c->data[1] & c->data[2]) + unsigned new_flags = (page->flags & ~c->data[2]) | (c->data[1] & c->data[2]) // If we stop paying, see if the frame is still paid for. If not, free it. if ~new_flags & old & PAGE_FLAG_PAYING: - if page: - // Decrease the use counter in any case. - page->address_space->unuse () - if !page_check_payment (page): - new_flags &= ~PAGE_FLAG_FRAME - else: - // Decrease the use counter in any case. - cappage->address_space->unuse () - if !cappage_check_payment (cappage): - new_flags &= ~PAGE_FLAG_FRAME + // Decrease the use counter in any case. + page->address_space->unuse () + if !page_check_payment (page): + new_flags &= ~PAGE_FLAG_FRAME // If we start paying, increase the use counter. if new_flags & ~old & PAGE_FLAG_PAYING: - if !(page ? page->address_space : cappage->address_space)->use(): + if !page->address_space->use(): // If it doesn't work, refuse to set the flag, and refuse to allocate a frame. new_flags &= ~(PAGE_FLAG_PAYING | PAGE_FLAG_FRAME) if old & PAGE_FLAG_FRAME: @@ -719,42 +579,32 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability::C // If we want a frame, see if we can get it. if ~old & new_flags & PAGE_FLAG_FRAME: - if page: - Page *p - for p = page; p; p = (Page *)p->data.share_prev: - if p->data.flags & PAGE_FLAG_PAYING: + Page *p + for p = page; p; p = p->share_prev: + if p->flags & PAGE_FLAG_PAYING: + break + if !p: + for p = page->share_next; p; p = p->share_next: + if p->flags & PAGE_FLAG_PAYING: break if !p: - for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next: - if p->data.flags & PAGE_FLAG_PAYING: - break - if !p: - new_flags &= ~PAGE_FLAG_FRAME - else: - Cappage *p - for p = cappage; p; p = (Cappage *)p->data.share_prev: - if p->data.flags & PAGE_FLAG_PAYING: - break - if !p: - for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next: - if p->data.flags & PAGE_FLAG_PAYING: - break - if !p: - new_flags &= ~PAGE_FLAG_FRAME + new_flags &= ~PAGE_FLAG_FRAME // If we can get the new frame, get it. - Capability *cap = &((Capability *)cappage->data.frame)[c->data[1]] - cap->invalidate () - // clone_capability needs a Memory, but doesn't use it when storage is provided. - top_memory.clone_capability (c->cap[0], c->copy[0], cap) + if ~old & new_flags & PAGE_FLAG_FRAME: + page->frame = page->address_space->zalloc () + Page_arch_update_mapping (page) break default: break -static void capability_invoke (unsigned target, unsigned protected_data, Capability::Context *c): - Capability *capability = (Capability *)protected_data +static void caps_invoke (unsigned target, unsigned protected_data, Capability::Context *c): + Caps *caps = (CapsP)protected_data switch c->data[0]: - case CAP_CAPABILITY_GET: - reply_cap (capability, true) + case CAP_CAPS_SET: + if c->data[1] >= caps->size: + break + caps->caps[c->data[1]].invalidate () + caps->clone (c->data[1], c->cap[0], c->copy[0]) break default: break @@ -768,26 +618,26 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability: // This is a call capability. cap[0] is the capability to call. reply_receiver = (Receiver *)protected_data reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC)) - Capability *c0 = c->cap[0] + CapRef c0 = c->cap[0] if c0: if ((unsigned)c0->target & ~KERNEL_MASK) != 0: - Capability r - fill_cap (&r, protected_data, reply_receiver->reply_protected_data) - c->cap[0] = &r + Caps r + fill_cap (CapRef (&r, 0), protected_data, reply_receiver->reply_protected_data) + c->cap[0] = CapRef (&r, 0) c->copy[0] = true c0->target->send_message (c0->protected_data, c) - r.invalidate () + r.caps[0].invalidate () else: // Kernel call: don't create actual capablities. - c->cap[0] = NULL - kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0) + c->cap[0].reset () + kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0.deref ()) return if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)): // This is a reply capability. Receiver *r = (Receiver *)protected_data r->send_message (r->reply_protected_data, c) while self->parent: - self = self->parent + self = self->parent.deref () while self->sibling_prev: self->sibling_prev->invalidate () while self->sibling_next: @@ -801,7 +651,7 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability: dbg_log ("; target = ") dbg_log_num (target) return - reply = c->cap[0] + reply = c->cap[0].deref () if c->data[0] == CAP_DEGRADE: reply_cap (target & c->data[1], protected_data) return @@ -818,11 +668,8 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability: case CAPTYPE_PAGE: page_invoke (target, protected_data, c) break - case CAPTYPE_CAPABILITY: - capability_invoke (target, protected_data, c) - break - case CAPTYPE_CAPPAGE: - page_invoke (target, protected_data, c) + case CAPTYPE_CAPS: + caps_invoke (target, protected_data, c) break default: panic (0x99337744, "invalid capability type invoked") diff --git a/iris.h b/iris.h index 8def656..23adb8e 100644 --- a/iris.h +++ b/iris.h @@ -30,7 +30,7 @@ extern "C" { #endif // Number of clock interrupts per second. -#define HZ 20 +#define HZ 100 #define PAGE_BITS (12) #define PAGE_SIZE (1 << PAGE_BITS) @@ -47,6 +47,7 @@ enum Exception_code { ERR_OVERFLOW, ERR_TRAP, ERR_WATCHPOINT, + ERR_BREAKPOINT, ERR_NO_PAGE_DIRECTORY, ERR_NO_PAGE_TABLE, ERR_OUT_OF_MEMORY, @@ -65,6 +66,7 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = { "overflow", "trap", "watchpoint", + "breakpoint", "no page directory", "no page table", "out of memory" @@ -78,8 +80,8 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = { #define CAPTYPE_MEMORY 0x200 #define CAPTYPE_THREAD 0x400 #define CAPTYPE_PAGE 0x600 -#define CAPTYPE_CAPABILITY 0x800 -#define CAPTYPE_CAPPAGE 0xa00 +#define CAPTYPE_CAPS 0x800 +/*#define CAPTYPE_??? 0xa00*/ /*#define CAPTYPE_??? 0xc00*/ /*#define CAPTYPE_??? 0xe00*/ @@ -106,19 +108,20 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = { #define CAP_MEMORY_MAP 4 #define CAP_MEMORY_MAPPING 5 #define CAP_MEMORY_LIMIT 6 -#define CAP_MEMORY_DROP 8 #define CAP_MEMORY_ALL_RIGHTS 0x1ff #define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */ #define CAP_THREAD_SCHEDULE 2 -#define CAP_THREAD_ALLOC_RANGE 3 -#define CAP_THREAD_PHYSICAL_ADDRESS 4 -#define CAP_THREAD_ALLOC_PHYSICAL 5 -#define CAP_THREAD_MAKE_PRIV 6 -#define CAP_THREAD_GET_TOP_MEMORY 7 -#define CAP_THREAD_REGISTER_INTERRUPT 8 -#define CAP_THREAD_ALL_RIGHTS 0x07 -#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV) | (1 << CAP_THREAD_ALLOC_PHYSICAL) | (1 << CAP_THREAD_PHYSICAL_ADDRESS) | (1 << CAP_THREAD_ALLOC_RANGE)) +#define CAP_THREAD_CAP_CLONE 3 +#define CAP_THREAD_PRIV 8 +#define CAP_THREAD_PRIV_ALLOC_RANGE 0 +#define CAP_THREAD_PRIV_PHYSICAL_ADDRESS 1 +#define CAP_THREAD_PRIV_ALLOC_PHYSICAL 2 +#define CAP_THREAD_PRIV_MAKE_PRIV 3 +#define CAP_THREAD_PRIV_GET_TOP_MEMORY 4 +#define CAP_THREAD_PRIV_REGISTER_INTERRUPT 5 +#define CAP_THREAD_ALL_RIGHTS 0x0ff +#define CAP_THREAD_ALL_PRIV_RIGHTS 0x1ff /* These get/set_info are not arch-specific. */ #define CAP_THREAD_INFO_PC ~0 @@ -130,6 +133,9 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = { #define THREAD_FLAG_RUNNING 0x20000000 #define THREAD_FLAG_USER 0x1fffffff +#define CAP_CAPS_SET 1 +#define CAP_CAPS_ALL_RIGHTS 0x1ff + #define CAP_PAGE_SHARE 1 #define CAP_PAGE_FLAGS 2 /* Not an operation; a capability without this bit cannot write to the page. */ @@ -158,31 +164,24 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = { /* This is a read-only flag, saying if this is uncachable memory. */ #define PAGE_FLAG_UNCACHED 0x20 -#define CAP_CAPABILITY_GET 1 -#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff +/* If this flag is set in a capability, it is copied instead of mapped. */ +/* If it is set in the target capability, the Thread waits after the request. */ +#define CAPABILITY_COPY 0x80000000 +/* This constant can be used to signify that no capability is passed or accepted. */ +#define CAPABILITY_NONE (~CAPABILITY_COPY) -#define CAPPAGE_SIZE 102 -/* Cappage has Page's operations as well. */ -#define CAP_CAPPAGE_SET 4 -#define CAP_CAPPAGE_ALL_RIGHTS 0x1ff +#define __my_receiver 1 +#define __my_thread 2 +#define __my_memory 3 +#define __my_call 4 +#define __my_parent 5 #ifndef __KERNEL typedef unsigned Capability; -extern Capability __my_receiver; -extern Capability __my_thread; -extern Capability __my_memory; -extern Capability __my_call; -extern Capability __my_parent; - static Capability cap_copy (Capability src) { - return src | 2; -} - -static Capability cappage_cap (unsigned base, unsigned idx) -{ - return base | (idx << 2) | 1; + return src | CAPABILITY_COPY; } typedef struct Message @@ -211,30 +210,34 @@ static void invoke (Capability target, Message *msg) : "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); } -static void wait (Message *msg) +static void wait (Message *msg, Capability r0, Capability r1, Capability r2, Capability r3) { - __asm__ volatile ("li $v0, 2\n" + __asm__ volatile ("li $v0, 0x80000000\n" + "\tlw $t4, %1\n" + "\tlw $t5, %2\n" + "\tlw $t6, %3\n" + "\tlw $t7, %4\n" "\tsyscall\n" "\tlw $v1, %0\n" "\tsw $t0, 0($v1)\n" "\tsw $t1, 4($v1)\n" "\tsw $t2, 8($v1)\n" "\tsw $t3, 12($v1)\n" - "\tsw $a0, 16($v1)\n" - "\tsw $a1, 20($v1)\n" - "\tsw $a2, 24($v1)\n" - "\tsw $a3, 28($v1)\n" "\tsw $v0, 32($v1)" : - : "m"(msg) - : "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); + : "m"(msg), "m"(r0), "m"(r1), "m"(r2), "m"(r3) + : "memory", "v0", "v1", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "a0", "a1", "a2", "a3"); } -static void call (Capability target, Message *msg) +static void call (Capability target, Message *msg, Capability r0, Capability r1, Capability r2, Capability r3) { Capability t = cap_copy (target); __asm__ volatile ("lw $v0, %0\n" "\tlw $v1, %1\n" + "\tlw $t4, %1\n" + "\tlw $t5, %2\n" + "\tlw $t6, %3\n" + "\tlw $t7, %4\n" "\tlw $t0, 0($v1)\n" "\tlw $t1, 4($v1)\n" "\tlw $t2, 8($v1)\n" @@ -249,14 +252,10 @@ static void call (Capability target, Message *msg) "\tsw $t1, 4($v1)\n" "\tsw $t2, 8($v1)\n" "\tsw $t3, 12($v1)\n" - "\tsw $a0, 16($v1)\n" - "\tsw $a1, 20($v1)\n" - "\tsw $a2, 24($v1)\n" - "\tsw $a3, 28($v1)\n" "\tsw $v0, 32($v1)" : - : "m"(t), "m"(msg) - : "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); + : "m" (t), "m" (msg), "m" (r0), "m" (r1), "m" (r2), "m" (r3) + : "memory", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"); } static void invoke_00 (Capability t) @@ -385,6 +384,20 @@ static void invoke_13 (Capability t, Capability c, unsigned d0, unsigned d1, uns invoke (t, &msg); } +static void invoke_14 (Capability t, Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + Message msg; + msg.cap[0] = c; + msg.data[0] = d0; + msg.data[1] = d1; + msg.data[2] = d2; + msg.data[3] = d3; + msg.cap[1] = 0; + msg.cap[2] = 0; + msg.cap[3] = 0; + invoke (t, &msg); +} + static void invoke_20 (Capability t, Capability c0, Capability c1) { Message msg; @@ -452,7 +465,7 @@ static void call_00 (Capability c) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } static unsigned call_n00 (Capability c) @@ -466,11 +479,11 @@ static unsigned call_n00 (Capability c) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } -static Capability call_c00 (Capability c) +static void call_c00 (Capability c, Capability target) { Message msg; msg.cap[0] = c; @@ -481,11 +494,10 @@ static Capability call_c00 (Capability c) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); - return msg.cap[0]; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } -static Capability call_c01 (Capability c, unsigned d) +static void call_c01 (Capability c, Capability target, unsigned d) { Message msg; msg.cap[0] = c; @@ -496,8 +508,7 @@ static Capability call_c01 (Capability c, unsigned d) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); - return msg.cap[0]; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } static unsigned long long call_l01 (Capability c, unsigned d) @@ -511,11 +522,11 @@ static unsigned long long call_l01 (Capability c, unsigned d) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32); } -static Capability call_c02 (Capability c, unsigned d0, unsigned d1) +static void call_c02 (Capability c, Capability target, unsigned d0, unsigned d1) { Message msg; msg.cap[0] = c; @@ -526,8 +537,7 @@ static Capability call_c02 (Capability c, unsigned d0, unsigned d1) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); - return msg.cap[0]; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1) @@ -541,11 +551,11 @@ static unsigned long long call_l02 (Capability c, unsigned d0, unsigned d1) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32); } -static Capability call_c03 (Capability c, unsigned d0, unsigned d1, unsigned d2) +static void call_c03 (Capability c, Capability target, unsigned d0, unsigned d1, unsigned d2) { Message msg; msg.cap[0] = c; @@ -556,8 +566,7 @@ static Capability call_c03 (Capability c, unsigned d0, unsigned d1, unsigned d2) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); - return msg.cap[0]; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3) @@ -571,11 +580,11 @@ static unsigned long long call_l04 (Capability c, unsigned d0, unsigned d1, unsi msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return (unsigned long long)msg.data[0] | ((unsigned long long)msg.data[1] << 32); } -static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d1) +static void call_c12 (Capability c, Capability target, Capability c1, unsigned d0, unsigned d1) { Message msg; msg.cap[0] = c; @@ -586,8 +595,21 @@ static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d msg.data[3] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); - return msg.cap[0]; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); +} + +static void call_c13 (Capability c, Capability target, Capability c1, unsigned d0, unsigned d1, unsigned d2) +{ + Message msg; + msg.cap[0] = c; + msg.cap[1] = c1; + msg.data[0] = d0; + msg.data[1] = d1; + msg.data[2] = d2; + msg.data[3] = 0; + msg.cap[2] = 0; + msg.cap[3] = 0; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } static unsigned call_n01 (Capability c, unsigned d) @@ -601,7 +623,7 @@ static unsigned call_n01 (Capability c, unsigned d) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -616,7 +638,7 @@ static unsigned call_n11 (Capability c, Capability c1, unsigned d) msg.data[3] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -631,7 +653,7 @@ static unsigned call_n12 (Capability c, Capability c1, unsigned d0, unsigned d1) msg.data[3] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -646,7 +668,7 @@ static unsigned call_n14 (Capability c, Capability c1, unsigned d0, unsigned d1, msg.data[3] = d3; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -661,7 +683,7 @@ static unsigned call_n02 (Capability c, unsigned d0, unsigned d1) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -676,7 +698,7 @@ static Capability call_p02 (Capability c, unsigned d0, unsigned d1, unsigned *ba msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); *base_return = msg.data[0]; return msg.cap[0]; } @@ -692,7 +714,7 @@ static unsigned call_n03 (Capability c, unsigned d0, unsigned d1, unsigned d2) msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -708,10 +730,24 @@ static unsigned call_n04 (Capability c, unsigned d0, unsigned d1, unsigned d2, u msg.cap[1] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } +static void call_c11 (Capability target, Capability c, Capability c1, unsigned d) +{ + Message msg; + msg.cap[0] = c; + msg.cap[1] = c1; + msg.data[0] = d; + msg.data[1] = 0; + msg.data[2] = 0; + msg.data[3] = 0; + msg.cap[2] = 0; + msg.cap[3] = 0; + call (__my_call, &msg, target, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); +} + static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1, unsigned d2) { Message msg; @@ -723,7 +759,7 @@ static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1, msg.data[3] = 0; msg.cap[2] = 0; msg.cap[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } @@ -738,13 +774,13 @@ static unsigned call_n33 (Capability c, Capability c1, Capability c2, Capability msg.data[1] = d1; msg.data[2] = d2; msg.data[3] = 0; - call (__my_call, &msg); + call (__my_call, &msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); return msg.data[0]; } -static Capability degrade (Capability src, unsigned mask) +static void degrade (Capability target, Capability src, unsigned mask) { - return call_c02 (src, CAP_DEGRADE, mask); + call_c02 (src, target, CAP_DEGRADE, mask); } static void schedule () @@ -752,29 +788,34 @@ static void schedule () invoke_01 (__my_thread, CAP_THREAD_SCHEDULE); } +static void capability_clone (Capability target, Capability src) +{ + call_c11 (__my_thread, target, src, CAP_THREAD_CAP_CLONE); +} + static void register_interrupt (unsigned num) { - invoke_12 (__my_thread, __my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num); + invoke_13 (__my_thread, __my_receiver, CAP_THREAD_PRIV, CAP_THREAD_PRIV_REGISTER_INTERRUPT, num); } static void unregister_interrupt (unsigned num) { - invoke_02 (__my_thread, CAP_THREAD_REGISTER_INTERRUPT, num); + invoke_03 (__my_thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_REGISTER_INTERRUPT, num); } -static Capability get_top_memory () +static void get_top_memory (Capability target) { - return call_c01 (__my_thread, CAP_THREAD_GET_TOP_MEMORY); + return call_c02 (__my_thread, target, CAP_THREAD_PRIV, CAP_THREAD_PRIV_GET_TOP_MEMORY); } static void alloc_physical (Capability page, unsigned address, int cachable, int freeable) { - invoke_13 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0)); + invoke_14 (__my_thread, page, CAP_THREAD_PRIV, CAP_THREAD_PRIV_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0)); } static unsigned alloc_range (Capability memory, unsigned pages) { - return call_n12 (__my_thread, memory, CAP_THREAD_ALLOC_RANGE, pages); + return call_n13 (__my_thread, memory, CAP_THREAD_PRIV, CAP_THREAD_PRIV_ALLOC_RANGE, pages); } static void receiver_set_owner (Capability receiver, Capability owner) @@ -782,9 +823,9 @@ static void receiver_set_owner (Capability receiver, Capability owner) invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER); } -static Capability receiver_create_capability (Capability receiver, unsigned protected_data) +static void receiver_create_capability (Capability target, Capability receiver, unsigned protected_data) { - return call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data); + return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CAPABILITY, protected_data); } static unsigned receiver_reply_protected_data (Capability receiver, int set, unsigned data) @@ -825,47 +866,47 @@ static unsigned receiver_set_alarm (Capability receiver, unsigned data) static void my_sleep (unsigned value, Message *ret) { receiver_set_alarm (__my_receiver, value); - wait (ret); + wait (ret, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE); } -static Capability receiver_create_call_capability (Capability receiver) +static void receiver_create_call_capability (Capability target, Capability receiver) { - return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0); + return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0); } -static Capability receiver_create_async_call_capability (Capability receiver) +static void receiver_create_async_call_capability (Capability target, Capability receiver) { - return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1); + return call_c02 (receiver, target, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1); } -static Capability memory_create (Capability memory, unsigned type) +static void memory_create (Capability target, Capability memory, unsigned type) { - return call_c02 (memory, CAP_MEMORY_CREATE, type); + return call_c02 (memory, target, CAP_MEMORY_CREATE, type); } -static Capability memory_create_page (Capability memory) +static void memory_create_page (Capability target, Capability memory) { - return memory_create (memory, CAPTYPE_PAGE | REQUEST_MASK); + return memory_create (memory, target, CAPTYPE_PAGE | REQUEST_MASK); } -static Capability memory_create_thread (Capability memory) +static void memory_create_thread (Capability target, Capability memory) { - return memory_create (memory, CAPTYPE_THREAD | REQUEST_MASK); + return memory_create (memory, target, CAPTYPE_THREAD | REQUEST_MASK); } -static Capability memory_create_receiver (Capability memory) +static void memory_create_receiver (Capability target, Capability memory) { - return memory_create (memory, CAPTYPE_RECEIVER | REQUEST_MASK); + return memory_create (memory, target, CAPTYPE_RECEIVER | REQUEST_MASK); } -static Capability memory_create_memory (Capability memory) +static void memory_create_memory (Capability target, Capability memory) { - return memory_create (memory, CAPTYPE_MEMORY | REQUEST_MASK); + return memory_create (memory, target, CAPTYPE_MEMORY | REQUEST_MASK); } -static Capability memory_create_cappage (Capability memory, unsigned *base_return) +static void memory_create_caps (Capability target, Capability memory) { - return call_p02 (memory, CAP_MEMORY_CREATE, CAPTYPE_CAPPAGE | REQUEST_MASK, base_return); + return memory_create (memory, target, CAPTYPE_CAPS | REQUEST_MASK); } static void memory_destroy (Capability memory, Capability target) @@ -882,24 +923,19 @@ static void memory_map (Capability memory, Capability page, unsigned address, in invoke_12 (memory, page, CAP_MEMORY_MAP, address); } -static Capability memory_mapping (Capability memory, void *address) +static void memory_mapping (Capability target, Capability memory, void *address) { - return call_c02 (memory, CAP_MEMORY_MAPPING, (unsigned)address); + call_c02 (memory, target, CAP_MEMORY_MAPPING, (unsigned)address); } static unsigned memory_limit (Capability memory, unsigned limit) { - return call_c02 (memory, CAP_MEMORY_LIMIT, limit); + return call_n02 (memory, CAP_MEMORY_LIMIT, limit); } -static void drop (Capability cap) +static void thread_make_priv (Capability target, Capability thread) { - invoke_11 (__my_memory, cap, CAP_MEMORY_DROP); -} - -static Capability thread_make_priv (Capability thread) -{ - return call_c12 (__my_thread, thread, CAP_THREAD_MAKE_PRIV, ~0); + call_c13 (__my_thread, target, thread, CAP_THREAD_PRIV, CAP_THREAD_PRIV_MAKE_PRIV, ~0); } static unsigned thread_info (Capability thread, unsigned info, unsigned value, unsigned mask) @@ -954,21 +990,20 @@ static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask) static unsigned page_physical_address (Capability page) { - return call_n11 (__my_thread, page, CAP_THREAD_PHYSICAL_ADDRESS); + return call_n12 (__my_thread, page, CAP_THREAD_PRIV, CAP_THREAD_PRIV_PHYSICAL_ADDRESS); } -static Capability capability_get (Capability cap) +static void caps_set (Capability caps, Capability cap, unsigned index) { - return call_c01 (cap, CAP_CAPABILITY_GET); -} - -static void cappage_set (Capability page, Capability cap, unsigned index) -{ - invoke_12 (page, cap, CAP_CAPPAGE_SET, index); + invoke_12 (caps, cap, CAP_CAPS_SET, index); } +#if 0 /* Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. */ #define kdebug_char(c) do { unsigned d = (c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(d) : "a0", "a1", "memory"); } while (0) +#else +#define kdebug_char(c) do {} while (0) +#endif #define kdebug(str) do { const char *s = (str); while (*s) kdebug_char (*s++); } while (0) static void kdebug_num (unsigned n) diff --git a/kernel.hhp b/kernel.hhp index 349a65d..3cb3e85 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -30,110 +30,139 @@ #define EXTERN extern #endif -struct Object_base struct Page struct Thread struct Message struct Receiver struct Capability -struct Cappage +struct Caps struct Memory -struct Object_base: - Capability *refs - Memory *address_space +typedef Page *PageP +typedef Thread *ThreadP +typedef Message *MessageP +typedef Receiver *ReceiverP +typedef Capability *CapabilityP +typedef Caps *CapsP +typedef Memory *MemoryP +typedef void *Pointer + +typedef unsigned Protected + +struct CapRef: + CapsP caps + unsigned index + inline Capability *deref () + operator bool (): + return deref () != NULL + Capability *operator-> (): + return deref () + void reset (): + caps = NULL + CapRef (CapsP c, unsigned i) : caps (c), index (i): + CapRef () : caps (NULL), index (~0): + inline void clone (CapRef source, bool copy) + inline void set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL) + +struct Object: + CapRef refs + MemoryP address_space + // Next and previous object of the same type in any page. + Pointer prev, next inline bool is_free () -template // -struct Object : public Object_base: - // Next and previous object of the same type in any page. - _T *prev, *next - -struct Free : public Object : +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 : - Capability *capabilities[4] +struct Message : public Object: + Protected protected_data unsigned data[4] - unsigned protected_data + unsigned char capabilities[4] -struct Capability : public Object : +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 : - 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 : - 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 : - ShareData data + PageP share_first + PageP share_prev, share_next Page_arch arch void forget () -struct Cappage : public Object : - 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 : +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 : // 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) diff --git a/mips/Makefile.arch b/mips/Makefile.arch index 6197776..e76fc7f 100644 --- a/mips/Makefile.arch +++ b/mips/Makefile.arch @@ -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 diff --git a/mips/arch.ccp b/mips/arch.ccp index 390c224..edf3f4a 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -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) diff --git a/mips/arch.hhp b/mips/arch.hhp index ff0b994..ae1489e 100644 --- a/mips/arch.hhp +++ b/mips/arch.hhp @@ -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 : +struct arch_page : public Object : Page *page unsigned mapping arch_page *prev_mapped, *next_mapped -struct arch_page_table : public Object : +struct arch_page_table : public Object : arch_page *first_page struct Page_arch: diff --git a/mips/init.ccp b/mips/init.ccp index fc477f5..04988f8 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -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 diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 9a084ea..8e52db0 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -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 diff --git a/mips/jz4730.hhp b/mips/jz4730.hhp index 34e1e36..6540c23 100644 --- a/mips/jz4730.hhp +++ b/mips/jz4730.hhp @@ -138,12 +138,11 @@ // Map IO memory (requires a priviledged __my_thread capability). #include 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) diff --git a/panic.ccp b/panic.ccp index ed37780..3666388 100644 --- a/panic.ccp +++ b/panic.ccp @@ -19,12 +19,13 @@ #define ARCH #include "kernel.hh" +#if 0 void dbg_log_char (unsigned ch): if !dbg_cap: return Capability::Context c for unsigned i = 0; i < 4; ++i: - c.cap[i] = NULL + c.cap[i].reset () c.copy[i] = false c.data[i] = 0 c.data[0] = ch @@ -72,3 +73,42 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag dbg_log_num (n) dbg_log_char ('\n') // If no log capability is registered, the machine just hangs. +#else +void delay (unsigned ms): + for unsigned t = 0; t < 8000 * ms; ++t: + GPIO_GPDIR (0) = GPIO_GPDIR (0) + +void set_leds (bool a, bool b): + gpio_as_output (GPIO_NUM_PORT, GPIO_NUM) + gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS) + if a: + GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM) + else: + GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM + if b: + GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS) + else: + GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS + +void dbg_log_char (unsigned ch): +void dbg_log (char const *str): +void dbg_log_num (unsigned num): +void send (unsigned n): + for unsigned i = 0; i < 32; ++i: + bool v = n & (1 << 31) + set_leds (v, !v) + delay (350) + set_leds (false, false) + delay (150) + n <<= 1 + set_leds (true, true) + delay (50) + set_leds (false, false) + delay (50) +void panic_impl (unsigned n, unsigned line, char const *name, char const *message): + unsigned epc + cp0_get (CP0_EPC, epc) + send (epc) + while true: + send (n) +#endif diff --git a/report/kernel.tex b/report/kernel.tex index 200bc3d..2b2179d 100644 --- a/report/kernel.tex +++ b/report/kernel.tex @@ -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 diff --git a/schedule.ccp b/schedule.ccp index 2da2bd6..ef5a66a 100644 --- a/schedule.ccp +++ b/schedule.ccp @@ -62,7 +62,7 @@ static void alarm_tick (Receiver *recv): Capability::Context c for unsigned i = 0; i < 4; ++i: c.data[i] = 0 - c.cap[i] = NULL + c.cap[i].reset () c.copy[i] = false recv->send_message (~0, &c) if recv->prev_alarm: @@ -74,10 +74,14 @@ static void alarm_tick (Receiver *recv): // Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm. --recv->alarm_count -void Thread::wait (): +void Thread::wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3): if flags & THREAD_FLAG_RUNNING: unrun_thread (this) flags |= THREAD_FLAG_WAITING + rcaps[0] = c0 + rcaps[1] = c1 + rcaps[2] = c2 + rcaps[3] = c3 // Try to receive a message from a Receiver immediately. for Receiver *r = receivers; r; r = r->next_owned: if r->try_deliver (): @@ -92,6 +96,6 @@ void schedule (): void timer_interrupt (): Receiver *recv, *next for recv = first_alarm; recv; recv = next: - next = recv->next + next = (Receiver *)recv->next alarm_tick (recv) //schedule ()