From 9a7abe2fd5623a5a2dee343ccdd4c8a2ff755850 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Mon, 8 Jun 2009 13:46:13 +0200 Subject: [PATCH] working keyboard --- Makefile | 4 +- alloc.ccp | 33 +++- boot-programs/gpio.txt | 133 +++++++++++++++- boot-programs/init.S | 5 + boot-programs/thread0.ccp | 104 +++++++++---- boot-programs/thread1.ccp | 2 +- invoke.ccp | 317 ++++++++++++++++++++++---------------- iris.h | 116 +++++++++----- kernel.hhp | 26 ++-- mips/Makefile.arch | 7 +- mips/arch.ccp | 60 ++++---- mips/arch.hhp | 4 - mips/entry.S | 2 +- mips/init.ccp | 4 +- mips/interrupts.ccp | 23 ++- schedule.ccp | 40 ++--- 16 files changed, 589 insertions(+), 291 deletions(-) diff --git a/Makefile b/Makefile index 8703515..421998a 100644 --- a/Makefile +++ b/Makefile @@ -17,11 +17,11 @@ # Define some variables. CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc $(ARCH_CXXFLAGS) -CPPFLAGS = -O5 $(ARCH_CPPFLAGS) +CPPFLAGS = -O5 -fno-inline $(ARCH_CPPFLAGS) CC = $(CROSS)gcc LD = $(CROSS)ld OBJCOPY = $(CROSS)objcopy -STRIP = $(CROSS)strip +STRIP = : $(CROSS)strip headers = kernel.hh iris.h $(arch_headers) kernel_sources = panic.cc data.cc alloc.cc invoke.cc schedule.cc $(arch_kernel_sources) diff --git a/alloc.ccp b/alloc.ccp index 8efe396..87e3e0c 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -20,7 +20,7 @@ #define PREV(x) (((Object_base **)(x))[-2]) #define NEXT(x) (((Object_base **)(x))[-1]) -#define SIZE (2 * sizeof (unsigned)) +#define SIZE (2 * sizeof (Object_base *)) bool Memory::use (): // Go up to parents, incrementing used. @@ -50,6 +50,8 @@ unsigned raw_zalloc (): return (unsigned)ret void raw_pfree (unsigned page): + if !page: + return FreePage *p = (FreePage *)page p->next = junk_pages junk_pages = p @@ -105,7 +107,7 @@ void *Memory::search_free (unsigned size, void **first): PREV (f) = NULL s = PAGE_SIZE // We have a free block, possibly too large. - if s >= size + sizeof (Free) + SIZE: + if s >= size + sizeof (Free) + 2 * SIZE: // Create the new object at the end and keep the Free. Free *obj = (Free *)((unsigned)f + s - size - SIZE) NEXT (obj) = NEXT (f) @@ -212,18 +214,30 @@ Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capa if !ret: return NULL ret->target = target + ret->protected_data = protected_data ret->parent = parent ret->children = NULL ret->sibling_prev = NULL - ret->sibling_next = parent_ptr ? *parent_ptr : 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 - ret->protected_data = protected_data return ret Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret): if copy: - return alloc_capability (source->target, source->parent, source->parent ? &source->parent->children : &source->target->capabilities, source->protected_data, ret) + 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) @@ -321,8 +335,10 @@ void Capability::invalidate (): return if sibling_prev: sibling_prev->sibling_next = sibling_next - else if target: + else if (unsigned)target & ~KERNEL_MASK: target->capabilities = sibling_next + else: + ((Object_base *)protected_data)->refs = sibling_next if sibling_next: sibling_next->sibling_prev = sibling_prev parent = NULL @@ -374,9 +390,10 @@ void Page::forget (): data.share_prev = NULL data.share_next = NULL else: - raw_pfree (data.frame) + if ~data.flags & PAGE_FLAG_PHYSICAL: + raw_pfree (data.frame) data.frame = 0 - data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED) + data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED) Page_arch_update_mapping (this) void Cappage::forget (): diff --git a/boot-programs/gpio.txt b/boot-programs/gpio.txt index e86b0f8..ee11be7 100644 --- a/boot-programs/gpio.txt +++ b/boot-programs/gpio.txt @@ -14,7 +14,7 @@ GPIO control: // GP ... Registers: one set for each port of 32 pins; total 128 pins means 4 groups. Total size: 4 * 0x30 == 0xc0. #define GPIO_GPDR(n) (GPIO_BASE + (0x00 + (n)*0x30)) // D: data -#define GPIO_GPDIR(n) (GPIO_BASE + (0x04 + (n)*0x30)) // DI: data in: 1 is input; 0 is output. Disable interrupts on the pin before touching this. +#define GPIO_GPDIR(n) (GPIO_BASE + (0x04 + (n)*0x30)) // DI: data in: 0 is input; 1 is output. Disable interrupts on the pin before touching this. #define GPIO_GPODR(n) (GPIO_BASE + (0x08 + (n)*0x30)) // OD: #define GPIO_GPPUR(n) (GPIO_BASE + (0x0c + (n)*0x30)) // PU: pull-up (1 is enable) #define GPIO_GPALR(n) (GPIO_BASE + (0x10 + (n)*0x30)) // AL: alternate lower: per 2 bit; 00 means use as gpio; other values mean use as alternate function @@ -180,3 +180,134 @@ do { \ REG_GPIO_GPALR(0) &= 0xFF000000; \ REG_GPIO_GPALR(0) |= 0x00555555; \ } while (0) + + +// Pins on the trendtac: +0 keyboard +1 keyboard +2 keyboard +3 keyboard +4 keyboard +5 keyboard +6 keyboard +7 keyboard +8 keyboard interrupt +9 +10 +11 +12 +13 touchpad right button +14 +15 +16 touchpad left button +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 keyboard +97 keyboard +98 keyboard +99 keyboard +100 keyboard +101 keyboard +102 keyboard +103 keyboard +104 keyboard +105 keyboard +106 keyboard +107 keyboard +108 keyboard +109 keyboard +110 keyboard +111 keyboard +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 keyboard +126 +127 diff --git a/boot-programs/init.S b/boot-programs/init.S index 032742b..ef56ad5 100644 --- a/boot-programs/init.S +++ b/boot-programs/init.S @@ -16,10 +16,15 @@ // along with this program. If not, see . .globl __start + .globl __my_receiver + .globl __my_thread + .globl __my_memory + .globl __my_call .set noreorder __start: bal 1f + nop .word _gp 1: lw $gp, 0($ra) diff --git a/boot-programs/thread0.ccp b/boot-programs/thread0.ccp index 5f3cee1..4506a15 100644 --- a/boot-programs/thread0.ccp +++ b/boot-programs/thread0.ccp @@ -18,63 +18,101 @@ #include "iris.h" -// GPIO pins for the keyboard: Rows = +// GPIO pins for the keyboard:// // Rows = 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 125 // Cols = 0, 1, 2, 3, 4, 5, 6, 7 // Rows: 60...6f; 7d -// Nicely aligned to a port: use cols as output; rows as input. +// Nicely aligned to a port: use rows as output; cols as input. // Map memory from b0010000, which is really 10010000 in kseg1. -#define D(n) (*(volatile unsigned *)(0x00 + 0x30 * n + address)) -#define DI(n) (*(volatile unsigned *)(0x04 + 0x30 * n + address)) -#define AL(n) (*(volatile unsigned *)(0x10 + 0x30 * n + address)) -#define AU(n) (*(volatile unsigned *)(0x14 + 0x30 * n + address)) +#define D(n) (*(volatile unsigned *)(0x00 + 0x30 * n + address)) +#define DI(n) (*(volatile unsigned *)(0x04 + 0x30 * n + address)) +#define PU(n) (*(volatile unsigned *)(0x0c + 0x30 * n + address)) +#define AL(n) (*(volatile unsigned *)(0x10 + 0x30 * n + address)) +#define AU(n) (*(volatile unsigned *)(0x14 + 0x30 * n + address)) #define IE(n) (*(volatile unsigned *)(0x20 + 0x30 * n + address)) -void event (bool release, unsigned col, unsigned row): - debug_set_led ((col & 1) | (row & 2) | (release ? 4 : 0)) +unsigned const address = 0x00010000 + +static void event (bool release, unsigned row, unsigned col): + debug_set_led (col * 2 + (release ? 1 : 0)) + +static void delay (): + for unsigned i = 0; i < 100000; ++i: + IE (3) &= ~0x2000ffff int main (): // map memory Capability page = memory_create_page (__my_memory) alloc_physical (page, 0x10010000, 0) - unsigned const address = 0x00010000 - memory_map (__my_memory, page, address) + memory_map (__my_memory, page, address, 1) + #if 0 + // Keyboard stuff doesn't seem to work. Try the simpler part: touchpad buttons. + IE (0) &= ~0x00012000 + AL (0) &= ~0x0c000000 + AU (0) &= ~0x00000003 + DI (0) &= ~0x00012000 + PU (0) &= ~0x00012000 + + unsigned old = 0 + while true: + unsigned data = D (0) & 0x00012000 + if data == old: + continue + if data & ~old & 0x00010000: + event (true, 0, 0) + else if ~data & old & 0x00010000: + event (false, 0, 0) + if data & ~old & 0x00002000: + event (true, 1, 1) + else if ~data & old & 0x00002000: + event (false, 1, 1) + old = data + #else // Disable all interrupts. IE (3) &= ~0x2000ffff - IE (0) &= ~0x000000ff + IE (0) &= ~0x000001ff - // Set all to GPIO + // Set all to GPIO. AL (3) = 0 AU (3) &= ~0x0c000000 - AL (0) &= ~0x0000ffff + AL (0) &= ~0x0003ffff - // Set all to input + // Set all rows to input and enable the pull-ups. + DI (0) &= ~0x000000ff + PU (0) |= 0x000000ff + + // Set all columns to output, 0. DI (3) |= 0x2000ffff - DI (0) |= 0x000000ff + D (3) &= ~0x2000ffff - unsigned keys[2][8] - for unsigned i = 0; i < 8; ++i: - keys[1][i] = 0x2000ffff + #define NUM_COLS 17 + unsigned keys[NUM_COLS] + for unsigned i = 0; i < NUM_COLS; ++i: + keys[i] = 0 + + // Pin numbers for the cols, relative to the start of the port (so minus 0x60). + int const cols[NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 } while true: // read keyboard - for unsigned col = 0; col < 8; ++col: - // set col to output, all others to input - DI (0) = (DI (0) & ~0x000000ff) | (1 << col) - // read input - keys[0][col] = D (3) & ~0x2000ffff - // Generate events - if keys[0][col] == keys[1][col]: - continue - unsigned bit, b - for bit = 1, b = 0; bit < 0x10000; bit <<= 1, ++b: - if (keys[0][col] ^ keys[1][col]) & bit: - event (keys[0][col] & bit, col, b) - if (keys[0][col] ^ keys[1][col]) & 0x20000000: - // Not really bit 16, but it's easier to handle. - event (keys[0][col] & 0x20000000, col, 16) + unsigned data[NUM_COLS] + for unsigned col = 0; col < NUM_COLS; ++col: + D (3) &= ~0x2000ffff + delay () + unsigned zero = ~D (0) & 0x000000ff + D (3) = (D (3) & ~0x2000ffff) | (1 << cols[col]) + delay () + data[col] = D (0) & zero + + // Generate events. + for unsigned col = 0; col < NUM_COLS; ++col: + for unsigned row = 0; row < 8; ++row: + if (data[col] ^ keys[col]) & (1 << row): + event (data[col] & (1 << row), row, col) + keys[col] = data[col] schedule () + #endif diff --git a/boot-programs/thread1.ccp b/boot-programs/thread1.ccp index 9cd032a..a3e3096 100644 --- a/boot-programs/thread1.ccp +++ b/boot-programs/thread1.ccp @@ -20,4 +20,4 @@ int main (): while true: - __asm__ volatile ("move $v0, $zero; li $a0, 1 ; move $a1, $zero ; move $a2, $a0 ; syscall") + schedule () diff --git a/invoke.ccp b/invoke.ccp index 229c8fa..d3c5c19 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -30,6 +30,7 @@ Capability *Memory::find_capability (unsigned code, bool *copy): if p->data.frame == (unsigned)page: return &page[num] else: + code &= ~3 // Normal capability for Capability *c = capabilities; c; c = c->next: if c == (Capability *)code: @@ -46,36 +47,37 @@ bool Receiver::try_deliver (): break if !m: return false - Capability *c[4] + Capability::Context c for unsigned i = 0; i < 4; ++i: + c.data[i] = m->data[i] if !m->capabilities[i]: - c[i] = NULL + c.cap[i] = NULL else: - c[i] = owner->address_space->clone_capability (m->capabilities[i], true) - if !c[i]: + c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true) + if !c.cap[i]: for unsigned j = 0; j < i; ++j: - owner->address_space->free_capability (c[i]) + owner->address_space->free_capability (c.cap[i]) return false - Thread_arch_receive (owner, m->data, c) + Thread_arch_receive (owner, &c) owner->unwait () return true -bool Receiver::send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4]): +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 *c[4] + Capability::Context n for unsigned i = 0; i < 4; ++i: - if !cap[i]: - c[i] = NULL + if !c->cap[i]: + n.cap[i] = NULL else: - c[i] = owner->address_space->clone_capability (cap[i], copy[i]) - if !c[i]: + n.cap[i] = owner->address_space->clone_capability (c->cap[i], c->copy[i]) + if !n.cap[i]: for unsigned j = 0; j < i; ++j: - owner->address_space->free_capability (c[i]) + owner->address_space->free_capability (n.cap[i]) tried_direct = true break if !tried_direct: - Thread_arch_receive (owner, data, c) + Thread_arch_receive (owner, &n) owner->unwait () return true // The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. @@ -83,11 +85,11 @@ bool Receiver::send_message (unsigned protected_data, unsigned data[4], Capabili if !msg: return false for unsigned i = 0; i < 4; ++i: - msg->data[i] = data[i] - if !cap[i]: + msg->data[i] = c->data[i] + if !c->cap[i]: msg->capabilities[i] = NULL else: - msg->capabilities[i] = address_space->clone_capability (cap[i], copy[i]) + msg->capabilities[i] = address_space->clone_capability (c->cap[i], c->copy[i]) if !msg->capabilities[i]: for unsigned j = 0; j < i; ++j: address_space->free_capability (msg->capabilities[j]) @@ -113,106 +115,125 @@ static void fill_cap (Capability *r, unsigned target, unsigned protected_data): static void reply_cap (unsigned target, unsigned protected_data): Capability r fill_cap (&r, target, protected_data) - unsigned d[4] = { 0, 0, 0, 0 } - Capability *caps[4] = { &r, NULL, NULL, NULL } - bool cops[4] = { true, false, false, false } + Capability::Context c + for unsigned i = 0; i < 4; ++i: + c.data[i] = 0 + c.cap[0] = &r + c.copy[0] = true + for unsigned i = 1; i < 4; ++i: + c.cap[i] = NULL + c.copy[i] = false if reply: - reply->invoke (d, caps, cops) - else: - reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) + reply->invoke (&c) + else if reply_receiver: + reply_receiver->send_message (reply_receiver->reply_protected_data, &c) r.invalidate () static void reply_cap (Capability *cap, bool copy): - unsigned d[4] = { 0, 0, 0, 0 } - Capability *caps[4] = { cap, NULL, NULL, NULL } - bool cops[4] = { copy, false, false, false } + 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.copy[i] = false if reply: - reply->invoke (d, caps, cops) - else: - reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) + reply->invoke (&c) + else if reply_receiver: + reply_receiver->send_message (reply_receiver->reply_protected_data, &c) static void reply_num (unsigned num): - unsigned d[4] = { num, 0, 0, 0 } - Capability *caps[4] = { NULL, NULL, NULL, NULL } - bool cops[4] = { false, false, false, false } + 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.copy[i] = false if reply: - reply->invoke (d, caps, cops) - else: - reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) + reply->invoke (&c) + else if reply_receiver: + reply_receiver->send_message (reply_receiver->reply_protected_data, &c) static void reply_nums (unsigned num1, unsigned num2): - unsigned d[4] = { num1, num2, 0, 0 } - Capability *caps[4] = { NULL, NULL, NULL, NULL } - bool cops[4] = { false, false, false, false } + Capability::Context c + c.data[0] = num1 + c.data[1] = num2 + c.data[2] = 0 + c.data[3] = 0 + for unsigned i = 0; i < 4; ++i: + c.cap[i] = NULL + c.copy[i] = false if reply: - reply->invoke (d, caps, cops) - else: - reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) + reply->invoke (&c) + else if reply_receiver: + reply_receiver->send_message (reply_receiver->reply_protected_data, &c) -static void receiver_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned data[4]): +static void receiver_invoke (unsigned target, unsigned protected_data, Capability::Context *c): Receiver *receiver = (Receiver *)protected_data - switch data[0]: + switch c->data[0]: case CAP_RECEIVER_SET_OWNER: - if ((unsigned)cap->target & (CAPTYPE_MASK | ~KERNEL_MASK)) != CAPTYPE_THREAD: + if !c->cap[0] || ((unsigned)c->cap[0]->target & (CAPTYPE_MASK | ~KERNEL_MASK)) != CAPTYPE_THREAD: // FIXME: This makes it impossible to use a fake Thread capability. return - receiver->own ((Thread *)cap->protected_data) + receiver->own ((Thread *)c->cap[0]->protected_data) break case CAP_RECEIVER_CREATE_CAPABILITY: - reply_cap ((unsigned)receiver, data[1]) + reply_cap ((unsigned)receiver, c->data[1]) break case CAP_RECEIVER_CREATE_CALL_CAPABILITY: - reply_cap (CAPTYPE_RECEIVER | CAP_RECEIVER_CALL | (data[1] ? CAP_RECEIVER_CALL_ASYNC : 0), protected_data) + reply_cap (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL) | (c->data[1] ? 1 << CAP_RECEIVER_CALL_ASYNC : 0), protected_data) break case CAP_RECEIVER_GET_REPLY_PROTECTED_DATA: reply_nums (receiver->reply_protected_data, receiver->protected_only ? 1 : 0) break case CAP_RECEIVER_SET_REPLY_PROTECTED_DATA: - receiver->reply_protected_data = data[1] - receiver->protected_only = data[2] + receiver->reply_protected_data = c->data[1] + receiver->protected_only = c->data[2] break default: break -static void memory_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data): +static void memory_invoke (unsigned target, unsigned protected_data, Capability::Context *c): Memory *mem = (Memory *)protected_data - switch request: + switch c->data[0]: case CAP_MEMORY_CREATE: - unsigned rights = data & REQUEST_MASK - data &= CAPTYPE_MASK - switch data: + unsigned rights = c->data[1] & REQUEST_MASK + unsigned type = c->data[1] & CAPTYPE_MASK + switch type: case CAPTYPE_RECEIVER: Receiver *ret = mem->alloc_receiver () if ret: - reply_cap (data | (rights & CAP_RECEIVER_ALL_RIGHTS), (unsigned)ret) + reply_cap (CAPTYPE_RECEIVER | (rights & CAP_RECEIVER_ALL_RIGHTS), (unsigned)ret) else: reply_num (0) break case CAPTYPE_MEMORY: Memory *ret = mem->alloc_memory () if ret: - reply_cap (data | (rights & CAP_MEMORY_ALL_RIGHTS), (unsigned)ret) + reply_cap (CAPTYPE_MEMORY | (rights & CAP_MEMORY_ALL_RIGHTS), (unsigned)ret) else: reply_num (0) break case CAPTYPE_THREAD: Thread *ret = mem->alloc_thread () if ret: - reply_cap (data | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret) + reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret) else: reply_num (0) break case CAPTYPE_PAGE: Page *ret = mem->alloc_page () if ret: - reply_cap (data | (rights & CAP_PAGE_ALL_RIGHTS), (unsigned)ret) + reply_cap (CAPTYPE_PAGE | (rights & CAP_PAGE_ALL_RIGHTS), (unsigned)ret) else: reply_num (0) break case CAPTYPE_CAPPAGE: Cappage *ret = mem->alloc_cappage () if ret: - reply_cap (data | (rights & CAP_CAPPAGE_ALL_RIGHTS), (unsigned)ret) + reply_cap (CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS), (unsigned)ret) else: reply_num (0) break @@ -220,26 +241,26 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability return break case CAP_MEMORY_DESTROY: - if !cap || cap->address_space != mem || (unsigned)cap->target & ~KERNEL_MASK: + if !c->cap[0] || c->cap[0]->address_space != mem || (unsigned)c->cap[0]->target & ~KERNEL_MASK: return - switch (unsigned)cap->target & CAPTYPE_MASK: + switch (unsigned)c->cap[0]->target & CAPTYPE_MASK: case CAPTYPE_RECEIVER: - mem->free_receiver ((Receiver *)cap->protected_data) + mem->free_receiver ((Receiver *)c->cap[0]->protected_data) return case CAPTYPE_MEMORY: - mem->free_memory ((Memory *)cap->protected_data) + mem->free_memory ((Memory *)c->cap[0]->protected_data) return case CAPTYPE_THREAD: - mem->free_thread ((Thread *)cap->protected_data) + mem->free_thread ((Thread *)c->cap[0]->protected_data) return case CAPTYPE_PAGE: - mem->free_page ((Page *)cap->protected_data) + mem->free_page ((Page *)c->cap[0]->protected_data) return case CAPTYPE_CAPABILITY: - mem->free_capability ((Capability *)cap->protected_data) + mem->free_capability ((Capability *)c->cap[0]->protected_data) return case CAPTYPE_CAPPAGE: - mem->free_cappage ((Cappage *)cap->protected_data) + mem->free_cappage ((Cappage *)c->cap[0]->protected_data) return default: panic (0x55228930, "invalid case") @@ -249,41 +270,42 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability break case CAP_MEMORY_MAP: // FIXME: this should work for fake pages as well. - if (unsigned)cap->target & ~KERNEL_MASK || ((unsigned)cap->target & CAPTYPE_MASK) != CAPTYPE_PAGE: + if !c->cap[0] || (unsigned)c->cap[0]->target & ~KERNEL_MASK || ((unsigned)c->cap[0]->target & CAPTYPE_MASK) != CAPTYPE_PAGE: break - Page *page = (Page *)cap->protected_data + Page *page = (Page *)c->cap[0]->protected_data if page->address_space != mem: break - mem->map (page, data & PAGE_MASK, data & (unsigned)cap->target & (1 << CAP_PAGE_WRITE)) + bool writable = c->data[1] & (unsigned)c->cap[0]->target & (1 << CAP_PAGE_WRITE) + mem->map (page, c->data[1] & PAGE_MASK, writable) break case CAP_MEMORY_MAPPING: bool write - Page *page = mem->get_mapping (data, &write) + Page *page = mem->get_mapping (c->data[1], &write) unsigned t = CAPTYPE_PAGE | REQUEST_MASK if !write: t &= ~CAP_PAGE_WRITE reply_cap (t, (unsigned)page) break case CAP_MEMORY_SET_LIMIT: - mem->limit = data + mem->limit = c->data[1] break case CAP_MEMORY_GET_LIMIT: reply_num (mem->limit) break case CAP_MEMORY_DROP: - if cap->address_space != mem: + if !c->cap[0] || c->cap[0]->address_space != mem: break - mem->free_capability (cap) + mem->free_capability (c->cap[0]) break default: break -static void thread_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned data[4]): +static void thread_invoke (unsigned target, unsigned protected_data, Capability::Context *c): Thread *thread = (Thread *)protected_data - switch data[0]: + switch c->data[0]: case CAP_THREAD_INFO: unsigned *value - switch data[1]: + switch c->data[1]: case CAP_THREAD_INFO_PC: value = &thread->pc break @@ -292,10 +314,10 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability break case CAP_THREAD_INFO_FLAGS: // It is not possible to set the PRIV flag, but it can be reset. - data[2] &= ~THREAD_FLAG_PRIV + c->data[2] &= ~THREAD_FLAG_PRIV value = &thread->flags - if data[3] & ~THREAD_FLAG_USER: - unsigned v = (*value & data[3]) | (data[2] & data[3]) + if c->data[3] & ~THREAD_FLAG_USER: + 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 () @@ -308,11 +330,11 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability thread->unrun () break default: - value = Thread_arch_info (thread, data[1]) + value = Thread_arch_info (thread, c->data[1]) break if value: - *value &= ~data[3] - *value |= data[2] & data[3] + *value &= ~c->data[3] + *value |= c->data[2] & c->data[3] reply_num (*value) else: reply_num (0) @@ -321,24 +343,39 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability schedule () break case CAP_THREAD_DEBUG: - dbg_leds (data[1] & 1, data[1] & 2, data[1] & 4) + for unsigned i = 0; i < 2; ++i: + dbg_led (true, true, true) + dbg_sleep (100) + dbg_led (false, false, false) + dbg_sleep (100) + //dbg_send (c->data[1], 5) break case CAP_THREAD_REGISTER_INTERRUPT: // Threads with access to this call are trusted, so no sanity checking is done. - arch_register_interrupt (data[1], cap ? (Receiver *)cap->protected_data : NULL) + 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 | (data[1] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory) + 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 data[1] & THREAD_FLAG_PRIV: - ((Thread *)cap->protected_data)->flags |= THREAD_FLAG_PRIV - reply_cap (CAPTYPE_THREAD | (data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), cap->protected_data) + 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_PHYSICAL: - // TODO + // 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 page->data.flags & PAGE_FLAG_PAYING: + page->data.flags &= ~PAGE_FLAG_PAYING + page->address_space->unuse () + page->data.frame = c->data[1] & PAGE_MASK + if c->data[1] & 1: + page->data.flags |= PAGE_FLAG_FRAME | PAGE_FLAG_PHYSICAL + else: + page->data.flags |= PAGE_FLAG_FRAME | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED break default: break @@ -393,7 +430,7 @@ static bool cappage_check_payment (Cappage *cappage): p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) return false -static void page_invoke (unsigned target, unsigned protected_data, Capability *cap, bool copy, unsigned data[4]): +static void page_invoke (unsigned target, unsigned protected_data, Capability::Context *c): Page *page Cappage *cappage ShareData *share_data @@ -405,22 +442,22 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c page = NULL cappage = (Cappage *)protected_data share_data = &cappage->data - switch data[0]: + switch c->data[0]: case CAP_PAGE_SHARE: - if ((unsigned)cap->target & CAPTYPE_MASK) != (target & CAPTYPE_MASK): + if !c->cap[0] || ((unsigned)c->cap[0]->target & CAPTYPE_MASK) != (target & CAPTYPE_MASK): // FIXME: This makes it impossible to use a fake Page capability. break if page: - Page *t = (Page *)cap->protected_data + Page *t = (Page *)c->cap[0]->protected_data t->forget () - if data[1] & PAGE_SHARE_READONLY: + if c->data[1] & PAGE_SHARE_READONLY: t->data.flags &= ~PAGE_FLAG_WRITABLE if !page->data.flags & PAGE_FLAG_FRAME: break - if data[1] & PAGE_SHARE_COPY: + if c->data[1] & PAGE_SHARE_COPY: if ~t->data.flags & PAGE_FLAG_PAYING: break - if ~data[1] & PAGE_SHARE_FORGET || page->data.flags & PAGE_FLAG_SHARED: + 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 @@ -437,7 +474,7 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c else: t->data.flags |= PAGE_FLAG_FRAME t->data.frame = raw_zalloc () - for unsigned i = 0; i <= (data[1] & ~PAGE_MASK); i += 4: + 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: @@ -450,7 +487,7 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c else: if t == page: break - if data[1] & PAGE_SHARE_FORGET: + 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 @@ -477,16 +514,16 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c ((Page *)t->data.share_prev)->data.share_next = t Page_arch_update_mapping (t) else: - Cappage *t = (Cappage *)cap->protected_data + Cappage *t = (Cappage *)c->cap[0]->protected_data t->forget () - if data[1] & PAGE_SHARE_READONLY: + if c->data[1] & PAGE_SHARE_READONLY: t->data.flags &= ~PAGE_FLAG_WRITABLE if !cappage->data.flags & PAGE_FLAG_FRAME: break - if data[1] & PAGE_SHARE_COPY: + if c->data[1] & PAGE_SHARE_COPY: if ~t->data.flags & PAGE_FLAG_PAYING: break - if ~data[1] & PAGE_SHARE_FORGET || cappage->data.flags & PAGE_FLAG_SHARED: + 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 @@ -502,7 +539,7 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c else: t->data.flags |= PAGE_FLAG_FRAME t->data.frame = raw_zalloc () - for unsigned i = 0; i < ((data[1] & ~PAGE_MASK) + 1) * sizeof (Capability); i += 4: + 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: @@ -513,7 +550,7 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c else: if t == cappage: break - if data[1] & PAGE_SHARE_FORGET: + 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 @@ -538,10 +575,12 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c if t->data.share_prev: ((Cappage *)t->data.share_prev)->data.share_next = t 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 // Compute the new flags. - unsigned new_flags = (share_data->flags & ~data[2]) | (data[1] & data[2]) + unsigned new_flags = (share_data->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: @@ -626,54 +665,54 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c reply_num (share_data->flags) break case CAP_CAPPAGE_SET: - if !cappage || data[1] >= CAPPAGE_SIZE || !(target & CAP_PAGE_WRITE): + if !cappage || c->data[1] >= CAPPAGE_SIZE || !(target & CAP_PAGE_WRITE): return - Capability *c = &((Capability *)cappage->data.frame)[data[1]] - c->invalidate () - // clone_capability needs a Memory, but doesn't use it when storage is provided. - top_memory.clone_capability (cap, copy, c) + Capability *cap = &((Capability *)cappage->data.frame)[c->data[1]] + if cap: + 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) break default: break -static void capability_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data): +static void capability_invoke (unsigned target, unsigned protected_data, Capability::Context *c): Capability *capability = (Capability *)protected_data - switch request: + switch c->data[0]: case CAP_CAPABILITY_GET: reply_cap (capability, true) break default: break -static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[4], Capability *c[4], bool copy[4], Capability *self): +static bool kernel_invoke (unsigned target, unsigned protected_data, Capability::Context *c, Capability *self): // Kernel calling convention: // data[0] is the request. // cap[0] is the reply capability // other parameters' meanings depend on the operation. - if !((1 << d[0]) & target & ~REQUEST_MASK): - // You are not allowed to perform this operation. - return true if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_CALL))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)): // This is a call capability. reply_receiver = (Receiver *)protected_data reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC)) Capability r - Capability *c0 = c[0] - if ~(unsigned)c0->target & ~KERNEL_MASK: + Capability *c0 = c->cap[0] + if (unsigned)c0->target & ~KERNEL_MASK: + // The call is not to a kernel capability. fill_cap (&r, protected_data, reply_receiver->reply_protected_data) - c[0] = &r - copy[0] = true - bool ret = kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0) + c->cap[0] = &r + c->copy[0] = true + bool ret = c0->target->send_message (c0->protected_data, c) r.invalidate () return ret else: // Kernel call: don't create actual capablities. reply = NULL - return kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0) + kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0) + return true 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, d, c, copy) + r->send_message (r->reply_protected_data, c) while self->parent: self = self->parent while self->sibling_prev: @@ -682,36 +721,42 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[ self->sibling_next->invalidate () self->invalidate () return true - reply = c[0] - if d[0] == CAP_DEGRADE: - reply_cap (target & d[1], protected_data) + // It's a normal kernel capability; check permission. + if !((1 << c->data[0]) & target & REQUEST_MASK): + // You are not allowed to perform this operation. + dbg_send (c->data[0], 5) + schedule () + return true + if c->data[0] == CAP_DEGRADE: + reply_cap (target & (CAPTYPE_MASK | (c->data[1] & REQUEST_MASK)), protected_data) return true switch target & CAPTYPE_MASK: case CAPTYPE_RECEIVER: - receiver_invoke (target, protected_data, c[1], d) + receiver_invoke (target, protected_data, c) break case CAPTYPE_MEMORY: - memory_invoke (target, protected_data, c[1], d[0], d[1]) + memory_invoke (target, protected_data, c) break case CAPTYPE_THREAD: - thread_invoke (target, protected_data, c[1], d) + thread_invoke (target, protected_data, c) break case CAPTYPE_PAGE: - page_invoke (target, protected_data, c[1], copy[1], d) + page_invoke (target, protected_data, c) break case CAPTYPE_CAPABILITY: - capability_invoke (target, protected_data, c[1], d[0], d[1]) + capability_invoke (target, protected_data, c) break case CAPTYPE_CAPPAGE: - page_invoke (target, protected_data, c[1], copy[1], d) break default: panic (0x99337744, "invalid capability type invoked") return true -bool Capability::invoke (unsigned data[4], Capability *cap[4], bool copy[4]): +bool Capability::invoke (Context *c): if (unsigned)target & ~KERNEL_MASK: // This is not a kernel capability: send a message to the receiver. - return target->send_message (protected_data, data, cap, copy) + return target->send_message (protected_data, c) // This is a kernel capability. Use a function to allow optimized call capabilities. - return kernel_invoke ((unsigned)target, protected_data, data, cap, copy, this) + reply = c->cap[0] + reply_receiver = NULL + return kernel_invoke ((unsigned)target, protected_data, c, this) diff --git a/iris.h b/iris.h index 6f9a088..81c24a2 100644 --- a/iris.h +++ b/iris.h @@ -22,6 +22,10 @@ extern "C" { #endif +#define PAGE_BITS (12) +#define PAGE_SIZE (1 << PAGE_BITS) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + #define KERNEL_MASK 0xfff #define CAPTYPE_MASK 0xe00 #define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK) @@ -98,12 +102,16 @@ extern "C" { /* Flag values for Page and Cappage objects. */ /* A writable page can be written to. This flag can not be set while the frame is shared. */ #define PAGE_FLAG_WRITABLE 1 - /* When paying, the memory's use is incremented if the page holds a frame. It cannot be lost. Frames are lost when the last payer forgets them. */ + /* When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them. */ #define PAGE_FLAG_PAYING 2 /* Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems. */ #define PAGE_FLAG_FRAME 4 /* This is a read-only flag, which is set if the Page is shared. */ #define PAGE_FLAG_SHARED 8 + /* This is a read-only flag, saying if this is physical memory, which mustn't be freed. */ +#define PAGE_FLAG_PHYSICAL 0x10 + /* 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 @@ -134,42 +142,70 @@ typedef struct Message static int invoke (Capability target, Message *msg) { - register int ret __asm__ ("v0"); - register unsigned v0 __asm__ ("v0") = target; - register unsigned a0 __asm__ ("a0") = msg->cap[0]; - register unsigned a1 __asm__ ("a1") = msg->cap[1]; - register unsigned a2 __asm__ ("a2") = msg->cap[2]; - register unsigned a3 __asm__ ("a3") = msg->cap[3]; - register unsigned t0 __asm__ ("t0") = msg->data[0]; - register unsigned t1 __asm__ ("t1") = msg->data[1]; - register unsigned t2 __asm__ ("t2") = msg->data[2]; - register unsigned t3 __asm__ ("t3") = msg->data[3]; - __asm__ volatile ("syscall" : "+r" (v0), "=r" (a0), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (t0), "=r" (t1), "=r" (t2), "=r" (t3)); + unsigned ret; + __asm__ volatile ("lw $v0, %1\n" + "\tlw $a3, %2\n" + "\tlw $t0, 0($a3)\n" + "\tlw $t1, 4($a3)\n" + "\tlw $t2, 8($a3)\n" + "\tlw $t3, 12($a3)\n" + "\tlw $a0, 16($a3)\n" + "\tlw $a1, 20($a3)\n" + "\tlw $a2, 24($a3)\n" + "\tlw $a3, 28($a3)\n" + "\tsyscall\n" + "\tmove %0, $v0" + : "=r"(ret) + : "m"(target), "m"(msg) + : "v0", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); return ret; } +static void wait (Message *msg) +{ + __asm__ volatile ("li $v0, 2\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)" + : + : "m"(msg) + : "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); +} + static int call (Capability target, Message *msg) { - register int ret __asm__ ("v0"); - register unsigned v0 __asm__ ("v0") = target; - register unsigned a0 __asm__ ("a0") = msg->cap[0]; - register unsigned a1 __asm__ ("a1") = msg->cap[1]; - register unsigned a2 __asm__ ("a2") = msg->cap[2]; - register unsigned a3 __asm__ ("a3") = msg->cap[3]; - register unsigned t0 __asm__ ("t0") = msg->data[0]; - register unsigned t1 __asm__ ("t1") = msg->data[1]; - register unsigned t2 __asm__ ("t2") = msg->data[2]; - register unsigned t3 __asm__ ("t3") = msg->data[3]; - __asm__ volatile ("syscall" : "+r" (v0), "+r" (a0), "+r" (a1), "+r" (a2), "+r" (a3), "+r" (t0), "+r" (t1), "+r" (t2), "+r" (t3)); - msg->cap[0] = a0; - msg->cap[1] = a1; - msg->cap[2] = a2; - msg->cap[3] = a3; - msg->data[0] = t0; - msg->data[1] = t1; - msg->data[2] = t2; - msg->data[3] = t3; - return ret; + unsigned ret; + Capability t = cap_copy (target); + __asm__ volatile ("lw $v0, %1\n" + "\tlw $v1, %2\n" + "\tlw $t0, 0($v1)\n" + "\tlw $t1, 4($v1)\n" + "\tlw $t2, 8($v1)\n" + "\tlw $t3, 12($v1)\n" + "\tlw $a0, 16($v1)\n" + "\tlw $a1, 20($v1)\n" + "\tlw $a2, 24($v1)\n" + "\tlw $a3, 28($v1)\n" + "\tsyscall\n" + "\tmove %0, $v0\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)" + : "=r"(ret) + : "m"(t), "m"(msg) + : "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3"); } static int invoke_01 (Capability t, unsigned d) @@ -330,7 +366,7 @@ static void unregister_interrupt (unsigned num) static void alloc_physical (Capability page, unsigned address, int cachable) { - invoke_12 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, address | (cachable ? 1 : 0)); + invoke_12 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0)); } static int receiver_set_owner (Capability receiver, Capability owner) @@ -370,27 +406,27 @@ static Capability memory_create (Capability memory, unsigned type) static Capability memory_create_page (Capability memory) { - return memory_create (memory, CAPTYPE_PAGE); + return memory_create (memory, CAPTYPE_PAGE | REQUEST_MASK); } static Capability memory_create_thread (Capability memory) { - return memory_create (memory, CAPTYPE_THREAD); + return memory_create (memory, CAPTYPE_THREAD | REQUEST_MASK); } static Capability memory_create_receiver (Capability memory) { - return memory_create (memory, CAPTYPE_RECEIVER); + return memory_create (memory, CAPTYPE_RECEIVER | REQUEST_MASK); } static Capability memory_create_memory (Capability memory) { - return memory_create (memory, CAPTYPE_MEMORY); + return memory_create (memory, CAPTYPE_MEMORY | REQUEST_MASK); } static Capability memory_create_cappage (Capability memory) { - return memory_create (memory, CAPTYPE_CAPPAGE); + return memory_create (memory, CAPTYPE_CAPPAGE | REQUEST_MASK); } static int memory_destroy (Capability memory, Capability target) @@ -400,8 +436,10 @@ static int memory_destroy (Capability memory, Capability target) /* TODO: #define CAP_MEMORY_LIST 3 */ -static int memory_map (Capability memory, Capability page, unsigned address) +static int memory_map (Capability memory, Capability page, unsigned address, int writable) { + if (writable) + address |= 1 << CAP_PAGE_WRITE; return invoke_12 (memory, page, CAP_MEMORY_MAP, address); } diff --git a/kernel.hhp b/kernel.hhp index a7de36f..1fde22d 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -83,6 +83,19 @@ struct Message : public Object : unsigned data[4] unsigned protected_data +struct Capability : public Object : + struct Context: + unsigned data[4] + Capability *cap[4] + bool copy[4] + Receiver *target + Capability *parent + Capability *children + Capability *sibling_prev, *sibling_next + unsigned protected_data + bool invoke (Context *c) + void invalidate () + struct Receiver : public Object : Thread *owner Receiver *prev_owned, *next_owned @@ -93,16 +106,7 @@ struct Receiver : public Object : void own (Thread *o) void orphan () bool try_deliver () - bool send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4]) - -struct Capability : public Object : - Receiver *target - Capability *parent - Capability *children - Capability *sibling_prev, *sibling_next - unsigned protected_data - bool invoke (unsigned data[4], Capability *cap[4], bool copy[4]) - void invalidate () + bool send_message (unsigned protected_data, Capability::Context *c) struct ShareData : unsigned frame @@ -194,7 +198,7 @@ void raw_pfree (unsigned page) // Defined by architecture-specific files. void Thread_arch_init (Thread *thread) -void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]) +void Thread_arch_receive (Thread *thread, Capability::Context *c) void Thread_arch_receive_fail (Thread *thread) unsigned *Thread_arch_info (Thread *thread, unsigned num) void Memory_arch_init (Memory *mem) diff --git a/mips/Makefile.arch b/mips/Makefile.arch index a816fae..069b633 100644 --- a/mips/Makefile.arch +++ b/mips/Makefile.arch @@ -17,7 +17,7 @@ load = 0x80000000 -ARCH_CXXFLAGS = -DNUM_THREADS=2 +ARCH_CXXFLAGS = -DNUM_THREADS=1 ARCH_CPPFLAGS = -Imips -Wa,-mips32 CROSS = mipsel-linux-gnu- OBJDUMP = $(CROSS)objdump @@ -40,9 +40,6 @@ $(boot_threads): TARGET_FLAGS = -I. uimage: kernel.raw.gz Makefile mips/Makefile.arch mkimage -A MIPS -O Linux -C gzip -a $(load) -e 0x$(shell /bin/sh -c '$(OBJDUMP) -t kernel | grep __start$$ | cut -b-8') -n "Shevek's kernel" -d $< $@ | sed -e 's/:/;/g' -elf.h: /usr/include/elf.h - ln -s $< $@ - %.o:%.S Makefile mips/Makefile.arch mips/arch.hh $(CC) $(CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@ @@ -56,4 +53,4 @@ kernel: mips/entry.o $(subst .cc,.o,$(kernel_sources)) mips/boot.o $(subst .cc,. %.gz: % gzip < $< > $@ -ARCH_CLEAN_FILES = uimage kernel kernel.raw kernel.raw.gz elf.h $(boot_threads) mips/*.o +ARCH_CLEAN_FILES = uimage kernel kernel.raw kernel.raw.gz $(boot_threads) mips/*.o diff --git a/mips/arch.ccp b/mips/arch.ccp index 18da85f..2161e7e 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -45,15 +45,15 @@ void Thread_arch_init (Thread *thread): thread->arch.k0 = 0 thread->arch.k1 = 0 -void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]): - thread->arch.a0 = (unsigned)c[0] - thread->arch.a1 = (unsigned)c[1] - thread->arch.a2 = (unsigned)c[2] - thread->arch.a3 = (unsigned)c[3] - thread->arch.t0 = d[0] - thread->arch.t1 = d[1] - thread->arch.t2 = d[2] - thread->arch.t3 = d[3] +void Thread_arch_receive (Thread *thread, 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] thread->arch.v0 = 1 void Thread_arch_receive_fail (Thread *thread): @@ -222,10 +222,12 @@ static unsigned make_entry_lo (Page *page, bool write): if !page->data.frame: return 0 unsigned flags - if write: - flags = 0x18 | 0x4 | 0x2 - else + if page->data.flags & PAGE_FLAG_UNCACHED: + flags = 0x10 | 0x2 + else: flags = 0x18 | 0x2 + if write: + flags |= 0x4 return ((page->data.frame & ~0x80000000) >> 6) | flags bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write): @@ -320,30 +322,36 @@ void Page_arch_update_mapping (Page *page): tlb_reset (p->mapping & ~1, as->arch.asid, t) void arch_invoke (): - Capability *target, *c[4] - bool wait, copy[4] + Capability *target + bool wait Thread *caller = current target = caller->address_space->find_capability (current->arch.v0, &wait) if !target: // TODO: there must be no action here. This is just because the rest doesn't work yet. - dbg_led (caller->arch.a0, caller->arch.a1, caller->arch.a2) - dbg_sleep (1000) + dbg_send (3, 2) schedule () // Calling an invalid capability always fails. caller->arch.v0 = 0 else: if wait: caller->wait () - c[0] = caller->address_space->find_capability (caller->arch.a0, ©[0]) - c[1] = caller->address_space->find_capability (caller->arch.a1, ©[1]) - c[2] = caller->address_space->find_capability (caller->arch.a2, ©[2]) - c[3] = caller->address_space->find_capability (caller->arch.a3, ©[3]) - unsigned d[4] - d[0] = caller->arch.t0 - d[1] = caller->arch.t1 - d[2] = caller->arch.t2 - d[3] = caller->arch.t3 - caller->arch.v0 = target->invoke (d, c, copy) ? 1 : 0 + Capability::Context c + c.cap[0] = caller->address_space->find_capability (caller->arch.a0, &c.copy[0]) + c.cap[1] = caller->address_space->find_capability (caller->arch.a1, &c.copy[1]) + c.cap[2] = caller->address_space->find_capability (caller->arch.a2, &c.copy[2]) + c.cap[3] = caller->address_space->find_capability (caller->arch.a3, &c.copy[3]) + c.data[0] = caller->arch.t0 + c.data[1] = caller->arch.t1 + c.data[2] = caller->arch.t2 + c.data[3] = caller->arch.t3 + caller->arch.v0 = target->invoke (&c) ? 1 : 0 + if !current: + if caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING: + current = caller + else: + schedule () + if !current: + current = &idle if caller != current: if (Memory *)asids[current->address_space->arch.asid] != current->address_space: if asids[0]: diff --git a/mips/arch.hhp b/mips/arch.hhp index 296c3df..b3248f2 100644 --- a/mips/arch.hhp +++ b/mips/arch.hhp @@ -61,10 +61,6 @@ #define CP0_DESAVE 31 #endif -#define PAGE_BITS (12) -#define PAGE_SIZE (1 << PAGE_BITS) -#define PAGE_MASK (~(PAGE_SIZE - 1)) - // register save positions in Thread #define SAVE_PC (5 * 4) #define SAVE_SP (SAVE_PC + 4) diff --git a/mips/entry.S b/mips/entry.S index 6dc278c..8e8e622 100644 --- a/mips/entry.S +++ b/mips/entry.S @@ -80,7 +80,7 @@ addr_100: addr_180: // General exception // Allow new exceptions to update EPC and friends. - //mtc0 $zero, $CP0_STATUS + mtc0 $zero, $CP0_STATUS sw $ra, -0xd88($zero) bal save_regs nop diff --git a/mips/init.ccp b/mips/init.ccp index 38629c3..6cdb43b 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -178,10 +178,12 @@ static void init_threads (): if !stackpage || !mem->map (stackpage, 0x7ffff000, true): panic (0x13151719, "unable to map initial stack page") 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 | CAP_RECEIVER_CALL, recv) + thread->arch.a3 = mkcap (mem, CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL), recv) mem->pfree ((unsigned)pages) thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV thread->schedule_next = NULL diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 5baf340..830a343 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -30,6 +30,11 @@ Thread *tlb_refill (): cp0_get (CP0_ENTRY_HI, EntryHi) unsigned *t = directory[EntryHi >> 21] if !t: + unsigned a + cp0_get (CP0_EPC, a) + dbg_send (a) + cp0_get (CP0_BAD_V_ADDR, a) + dbg_send (a) panic (0x99992222, "No page table") // - 2 instead of - 1 means reset bit 0 unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2) @@ -50,17 +55,18 @@ Thread *interrupt (): status &= ~(1 << (i + 8)) // Send message to interrupt handler. if arch_interrupt_receiver[i]: - unsigned data[4] = {0, 0, 0, 0} - Capability *cap[4] = {NULL, NULL, NULL, NULL} - bool copy[4] = {false, false, false, false} - arch_interrupt_receiver[i]->send_message (i, data, cap, copy) + Capability::Context c + for unsigned j = 0; j < 4; ++j: + c.data[j] = 0 + c.cap[j] = NULL + c.copy[j] = false + arch_interrupt_receiver[i]->send_message (i, &c) return current /// A general exception has occurred. Thread *exception (): unsigned cause cp0_get (CP0_CAUSE, cause) - //dbg_send (cause >> 2, 5) switch (cause >> 2) & 0x1f: case 0: // Interrupt. This shouldn't happen, since CAUSE[IV] == 1. @@ -70,6 +76,9 @@ Thread *exception (): panic (0x21223344, "TLB modification.") case 2: // TLB load or instruction fetch. + unsigned a + cp0_get (CP0_EPC, a) + dbg_send (a) panic (0x31223344, "TLB load or instruction fetch.") case 3: // TLB store. @@ -79,6 +88,9 @@ Thread *exception (): panic (0x51223344, "Address error load or instruction fetch.") case 5: // Address error store. + unsigned a + cp0_get (CP0_EPC, a) + dbg_send (a, 16) panic (0x61223344, "Address error store.") case 6: // Bus error instruction fetch. @@ -88,6 +100,7 @@ Thread *exception (): panic (0x81223344, "Bus error load or store.") case 8: // Syscall. + current->pc += 4 arch_invoke () break case 9: diff --git a/schedule.ccp b/schedule.ccp index 2415ab4..3095e62 100644 --- a/schedule.ccp +++ b/schedule.ccp @@ -18,36 +18,43 @@ #include "kernel.hh" +static void run_thread (Thread *thread): + thread->schedule_next = first_scheduled + if thread->schedule_next: + thread->schedule_next->schedule_prev = thread + first_scheduled = thread + +static void unrun_thread (Thread *thread): + if current == thread: + current = thread->schedule_next + if thread->schedule_prev: + thread->schedule_prev->schedule_next = thread->schedule_next + else: + first_scheduled = thread->schedule_next + if thread->schedule_next: + thread->schedule_next->schedule_prev = thread->schedule_prev + void Thread::run (): if flags & THREAD_FLAG_RUNNING: return flags |= THREAD_FLAG_RUNNING if flags & THREAD_FLAG_WAITING: return - schedule_next = first_scheduled - if schedule_next: - schedule_next->schedule_prev = this - first_scheduled = this + run_thread (this) void Thread::unrun (): if !(flags & THREAD_FLAG_RUNNING): return flags &= ~THREAD_FLAG_RUNNING - if !(flags & THREAD_FLAG_WAITING): - if current == this: - current = schedule_next - if schedule_prev: - schedule_prev->schedule_next = schedule_next - else: - first_scheduled = schedule_next - if schedule_next: - schedule_next->schedule_prev = schedule_prev + if flags & THREAD_FLAG_WAITING: + return + unrun_thread (this) void Thread::wait (): if flags & THREAD_FLAG_WAITING: return if flags & THREAD_FLAG_RUNNING: - unrun () + unrun_thread (this) flags |= THREAD_FLAG_WAITING // Try to receive a message from a Receiver immediately. for Receiver *r = receivers; r; r = r->next_owned: @@ -59,8 +66,7 @@ void Thread::unwait (): return flags &= ~THREAD_FLAG_WAITING if flags & THREAD_FLAG_RUNNING: - flags &= ~THREAD_FLAG_RUNNING - run () + run_thread (this) void schedule (): Thread *old = current @@ -68,5 +74,3 @@ void schedule (): current = current->schedule_next if !current: current = first_scheduled - if !current: - current = &idle