1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-01-01 20:35:33 +02:00

working keyboard

This commit is contained in:
Bas Wijnen 2009-06-08 13:46:13 +02:00
parent b39c710e87
commit 9a7abe2fd5
16 changed files with 589 additions and 291 deletions

View File

@ -17,11 +17,11 @@
# Define some variables. # Define some variables.
CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc $(ARCH_CXXFLAGS) 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 CC = $(CROSS)gcc
LD = $(CROSS)ld LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy OBJCOPY = $(CROSS)objcopy
STRIP = $(CROSS)strip STRIP = : $(CROSS)strip
headers = kernel.hh iris.h $(arch_headers) headers = kernel.hh iris.h $(arch_headers)
kernel_sources = panic.cc data.cc alloc.cc invoke.cc schedule.cc $(arch_kernel_sources) kernel_sources = panic.cc data.cc alloc.cc invoke.cc schedule.cc $(arch_kernel_sources)

View File

@ -20,7 +20,7 @@
#define PREV(x) (((Object_base **)(x))[-2]) #define PREV(x) (((Object_base **)(x))[-2])
#define NEXT(x) (((Object_base **)(x))[-1]) #define NEXT(x) (((Object_base **)(x))[-1])
#define SIZE (2 * sizeof (unsigned)) #define SIZE (2 * sizeof (Object_base *))
bool Memory::use (): bool Memory::use ():
// Go up to parents, incrementing used. // Go up to parents, incrementing used.
@ -50,6 +50,8 @@ unsigned raw_zalloc ():
return (unsigned)ret return (unsigned)ret
void raw_pfree (unsigned page): void raw_pfree (unsigned page):
if !page:
return
FreePage *p = (FreePage *)page FreePage *p = (FreePage *)page
p->next = junk_pages p->next = junk_pages
junk_pages = p junk_pages = p
@ -105,7 +107,7 @@ void *Memory::search_free (unsigned size, void **first):
PREV (f) = NULL PREV (f) = NULL
s = PAGE_SIZE s = PAGE_SIZE
// We have a free block, possibly too large. // 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. // Create the new object at the end and keep the Free.
Free *obj = (Free *)((unsigned)f + s - size - SIZE) Free *obj = (Free *)((unsigned)f + s - size - SIZE)
NEXT (obj) = NEXT (f) NEXT (obj) = NEXT (f)
@ -212,18 +214,30 @@ Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capa
if !ret: if !ret:
return NULL return NULL
ret->target = target ret->target = target
ret->protected_data = protected_data
ret->parent = parent ret->parent = parent
ret->children = NULL ret->children = NULL
ret->sibling_prev = 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: if ret->sibling_next:
ret->sibling_next->sibling_prev = ret ret->sibling_next->sibling_prev = ret
ret->protected_data = protected_data
return ret return ret
Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret): Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret):
if copy: 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: else:
return alloc_capability (source->target, source, &source->children, source->protected_data, ret) return alloc_capability (source->target, source, &source->children, source->protected_data, ret)
@ -321,8 +335,10 @@ void Capability::invalidate ():
return return
if sibling_prev: if sibling_prev:
sibling_prev->sibling_next = sibling_next sibling_prev->sibling_next = sibling_next
else if target: else if (unsigned)target & ~KERNEL_MASK:
target->capabilities = sibling_next target->capabilities = sibling_next
else:
((Object_base *)protected_data)->refs = sibling_next
if sibling_next: if sibling_next:
sibling_next->sibling_prev = sibling_prev sibling_next->sibling_prev = sibling_prev
parent = NULL parent = NULL
@ -374,9 +390,10 @@ void Page::forget ():
data.share_prev = NULL data.share_prev = NULL
data.share_next = NULL data.share_next = NULL
else: else:
raw_pfree (data.frame) if ~data.flags & PAGE_FLAG_PHYSICAL:
raw_pfree (data.frame)
data.frame = 0 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) Page_arch_update_mapping (this)
void Cappage::forget (): void Cappage::forget ():

View File

@ -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. // 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_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_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_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 #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) &= 0xFF000000; \
REG_GPIO_GPALR(0) |= 0x00555555; \ REG_GPIO_GPALR(0) |= 0x00555555; \
} while (0) } 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

View File

@ -16,10 +16,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
.globl __start .globl __start
.globl __my_receiver
.globl __my_thread
.globl __my_memory
.globl __my_call
.set noreorder .set noreorder
__start: __start:
bal 1f bal 1f
nop
.word _gp .word _gp
1: 1:
lw $gp, 0($ra) lw $gp, 0($ra)

View File

@ -18,63 +18,101 @@
#include "iris.h" #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 // 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 // Cols = 0, 1, 2, 3, 4, 5, 6, 7
// Rows: 60...6f; 7d // 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. // Map memory from b0010000, which is really 10010000 in kseg1.
#define D(n) (*(volatile unsigned *)(0x00 + 0x30 * n + address)) #define D(n) (*(volatile unsigned *)(0x00 + 0x30 * n + address))
#define DI(n) (*(volatile unsigned *)(0x04 + 0x30 * n + address)) #define DI(n) (*(volatile unsigned *)(0x04 + 0x30 * n + address))
#define AL(n) (*(volatile unsigned *)(0x10 + 0x30 * n + address)) #define PU(n) (*(volatile unsigned *)(0x0c + 0x30 * n + address))
#define AU(n) (*(volatile unsigned *)(0x14 + 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)) #define IE(n) (*(volatile unsigned *)(0x20 + 0x30 * n + address))
void event (bool release, unsigned col, unsigned row): unsigned const address = 0x00010000
debug_set_led ((col & 1) | (row & 2) | (release ? 4 : 0))
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 (): int main ():
// map memory // map memory
Capability page = memory_create_page (__my_memory) Capability page = memory_create_page (__my_memory)
alloc_physical (page, 0x10010000, 0) alloc_physical (page, 0x10010000, 0)
unsigned const address = 0x00010000 memory_map (__my_memory, page, address, 1)
memory_map (__my_memory, page, address)
#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. // Disable all interrupts.
IE (3) &= ~0x2000ffff IE (3) &= ~0x2000ffff
IE (0) &= ~0x000000ff IE (0) &= ~0x000001ff
// Set all to GPIO // Set all to GPIO.
AL (3) = 0 AL (3) = 0
AU (3) &= ~0x0c000000 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 (3) |= 0x2000ffff
DI (0) |= 0x000000ff D (3) &= ~0x2000ffff
unsigned keys[2][8] #define NUM_COLS 17
for unsigned i = 0; i < 8; ++i: unsigned keys[NUM_COLS]
keys[1][i] = 0x2000ffff 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: while true:
// read keyboard // read keyboard
for unsigned col = 0; col < 8; ++col: unsigned data[NUM_COLS]
// set col to output, all others to input for unsigned col = 0; col < NUM_COLS; ++col:
DI (0) = (DI (0) & ~0x000000ff) | (1 << col) D (3) &= ~0x2000ffff
// read input delay ()
keys[0][col] = D (3) & ~0x2000ffff unsigned zero = ~D (0) & 0x000000ff
// Generate events D (3) = (D (3) & ~0x2000ffff) | (1 << cols[col])
if keys[0][col] == keys[1][col]: delay ()
continue data[col] = D (0) & zero
unsigned bit, b
for bit = 1, b = 0; bit < 0x10000; bit <<= 1, ++b: // Generate events.
if (keys[0][col] ^ keys[1][col]) & bit: for unsigned col = 0; col < NUM_COLS; ++col:
event (keys[0][col] & bit, col, b) for unsigned row = 0; row < 8; ++row:
if (keys[0][col] ^ keys[1][col]) & 0x20000000: if (data[col] ^ keys[col]) & (1 << row):
// Not really bit 16, but it's easier to handle. event (data[col] & (1 << row), row, col)
event (keys[0][col] & 0x20000000, col, 16) keys[col] = data[col]
schedule () schedule ()
#endif

View File

@ -20,4 +20,4 @@
int main (): int main ():
while true: while true:
__asm__ volatile ("move $v0, $zero; li $a0, 1 ; move $a1, $zero ; move $a2, $a0 ; syscall") schedule ()

View File

@ -30,6 +30,7 @@ Capability *Memory::find_capability (unsigned code, bool *copy):
if p->data.frame == (unsigned)page: if p->data.frame == (unsigned)page:
return &page[num] return &page[num]
else: else:
code &= ~3
// Normal capability // Normal capability
for Capability *c = capabilities; c; c = c->next: for Capability *c = capabilities; c; c = c->next:
if c == (Capability *)code: if c == (Capability *)code:
@ -46,36 +47,37 @@ bool Receiver::try_deliver ():
break break
if !m: if !m:
return false return false
Capability *c[4] Capability::Context c
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
c.data[i] = m->data[i]
if !m->capabilities[i]: if !m->capabilities[i]:
c[i] = NULL c.cap[i] = NULL
else: else:
c[i] = owner->address_space->clone_capability (m->capabilities[i], true) c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true)
if !c[i]: if !c.cap[i]:
for unsigned j = 0; j < i; ++j: for unsigned j = 0; j < i; ++j:
owner->address_space->free_capability (c[i]) owner->address_space->free_capability (c.cap[i])
return false return false
Thread_arch_receive (owner, m->data, c) Thread_arch_receive (owner, &c)
owner->unwait () owner->unwait ()
return true 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 bool tried_direct = false
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only): if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
Capability *c[4] Capability::Context n
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
if !cap[i]: if !c->cap[i]:
c[i] = NULL n.cap[i] = NULL
else: else:
c[i] = owner->address_space->clone_capability (cap[i], copy[i]) n.cap[i] = owner->address_space->clone_capability (c->cap[i], c->copy[i])
if !c[i]: if !n.cap[i]:
for unsigned j = 0; j < i; ++j: 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 tried_direct = true
break break
if !tried_direct: if !tried_direct:
Thread_arch_receive (owner, data, c) Thread_arch_receive (owner, &n)
owner->unwait () owner->unwait ()
return true return true
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. // The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
@ -83,11 +85,11 @@ bool Receiver::send_message (unsigned protected_data, unsigned data[4], Capabili
if !msg: if !msg:
return false return false
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
msg->data[i] = data[i] msg->data[i] = c->data[i]
if !cap[i]: if !c->cap[i]:
msg->capabilities[i] = NULL msg->capabilities[i] = NULL
else: 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]: if !msg->capabilities[i]:
for unsigned j = 0; j < i; ++j: for unsigned j = 0; j < i; ++j:
address_space->free_capability (msg->capabilities[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): static void reply_cap (unsigned target, unsigned protected_data):
Capability r Capability r
fill_cap (&r, target, protected_data) fill_cap (&r, target, protected_data)
unsigned d[4] = { 0, 0, 0, 0 } Capability::Context c
Capability *caps[4] = { &r, NULL, NULL, NULL } for unsigned i = 0; i < 4; ++i:
bool cops[4] = { true, false, false, false } 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: if reply:
reply->invoke (d, caps, cops) reply->invoke (&c)
else: else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
r.invalidate () r.invalidate ()
static void reply_cap (Capability *cap, bool copy): static void reply_cap (Capability *cap, bool copy):
unsigned d[4] = { 0, 0, 0, 0 } Capability::Context c
Capability *caps[4] = { cap, NULL, NULL, NULL } for unsigned i = 0; i < 4; ++i:
bool cops[4] = { copy, false, false, false } 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: if reply:
reply->invoke (d, caps, cops) reply->invoke (&c)
else: else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
static void reply_num (unsigned num): static void reply_num (unsigned num):
unsigned d[4] = { num, 0, 0, 0 } Capability::Context c
Capability *caps[4] = { NULL, NULL, NULL, NULL } c.data[0] = num
bool cops[4] = { false, false, false, false } 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: if reply:
reply->invoke (d, caps, cops) reply->invoke (&c)
else: else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
static void reply_nums (unsigned num1, unsigned num2): static void reply_nums (unsigned num1, unsigned num2):
unsigned d[4] = { num1, num2, 0, 0 } Capability::Context c
Capability *caps[4] = { NULL, NULL, NULL, NULL } c.data[0] = num1
bool cops[4] = { false, false, false, false } 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: if reply:
reply->invoke (d, caps, cops) reply->invoke (&c)
else: else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops) 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 Receiver *receiver = (Receiver *)protected_data
switch data[0]: switch c->data[0]:
case CAP_RECEIVER_SET_OWNER: 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. // FIXME: This makes it impossible to use a fake Thread capability.
return return
receiver->own ((Thread *)cap->protected_data) receiver->own ((Thread *)c->cap[0]->protected_data)
break break
case CAP_RECEIVER_CREATE_CAPABILITY: case CAP_RECEIVER_CREATE_CAPABILITY:
reply_cap ((unsigned)receiver, data[1]) reply_cap ((unsigned)receiver, c->data[1])
break break
case CAP_RECEIVER_CREATE_CALL_CAPABILITY: 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 break
case CAP_RECEIVER_GET_REPLY_PROTECTED_DATA: case CAP_RECEIVER_GET_REPLY_PROTECTED_DATA:
reply_nums (receiver->reply_protected_data, receiver->protected_only ? 1 : 0) reply_nums (receiver->reply_protected_data, receiver->protected_only ? 1 : 0)
break break
case CAP_RECEIVER_SET_REPLY_PROTECTED_DATA: case CAP_RECEIVER_SET_REPLY_PROTECTED_DATA:
receiver->reply_protected_data = data[1] receiver->reply_protected_data = c->data[1]
receiver->protected_only = data[2] receiver->protected_only = c->data[2]
break break
default: default:
break 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 Memory *mem = (Memory *)protected_data
switch request: switch c->data[0]:
case CAP_MEMORY_CREATE: case CAP_MEMORY_CREATE:
unsigned rights = data & REQUEST_MASK unsigned rights = c->data[1] & REQUEST_MASK
data &= CAPTYPE_MASK unsigned type = c->data[1] & CAPTYPE_MASK
switch data: switch type:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
Receiver *ret = mem->alloc_receiver () Receiver *ret = mem->alloc_receiver ()
if ret: if ret:
reply_cap (data | (rights & CAP_RECEIVER_ALL_RIGHTS), (unsigned)ret) reply_cap (CAPTYPE_RECEIVER | (rights & CAP_RECEIVER_ALL_RIGHTS), (unsigned)ret)
else: else:
reply_num (0) reply_num (0)
break break
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
Memory *ret = mem->alloc_memory () Memory *ret = mem->alloc_memory ()
if ret: if ret:
reply_cap (data | (rights & CAP_MEMORY_ALL_RIGHTS), (unsigned)ret) reply_cap (CAPTYPE_MEMORY | (rights & CAP_MEMORY_ALL_RIGHTS), (unsigned)ret)
else: else:
reply_num (0) reply_num (0)
break break
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
Thread *ret = mem->alloc_thread () Thread *ret = mem->alloc_thread ()
if ret: if ret:
reply_cap (data | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret) reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret)
else: else:
reply_num (0) reply_num (0)
break break
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
Page *ret = mem->alloc_page () Page *ret = mem->alloc_page ()
if ret: if ret:
reply_cap (data | (rights & CAP_PAGE_ALL_RIGHTS), (unsigned)ret) reply_cap (CAPTYPE_PAGE | (rights & CAP_PAGE_ALL_RIGHTS), (unsigned)ret)
else: else:
reply_num (0) reply_num (0)
break break
case CAPTYPE_CAPPAGE: case CAPTYPE_CAPPAGE:
Cappage *ret = mem->alloc_cappage () Cappage *ret = mem->alloc_cappage ()
if ret: if ret:
reply_cap (data | (rights & CAP_CAPPAGE_ALL_RIGHTS), (unsigned)ret) reply_cap (CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS), (unsigned)ret)
else: else:
reply_num (0) reply_num (0)
break break
@ -220,26 +241,26 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability
return return
break break
case CAP_MEMORY_DESTROY: 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 return
switch (unsigned)cap->target & CAPTYPE_MASK: switch (unsigned)c->cap[0]->target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
mem->free_receiver ((Receiver *)cap->protected_data) mem->free_receiver ((Receiver *)c->cap[0]->protected_data)
return return
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
mem->free_memory ((Memory *)cap->protected_data) mem->free_memory ((Memory *)c->cap[0]->protected_data)
return return
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
mem->free_thread ((Thread *)cap->protected_data) mem->free_thread ((Thread *)c->cap[0]->protected_data)
return return
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
mem->free_page ((Page *)cap->protected_data) mem->free_page ((Page *)c->cap[0]->protected_data)
return return
case CAPTYPE_CAPABILITY: case CAPTYPE_CAPABILITY:
mem->free_capability ((Capability *)cap->protected_data) mem->free_capability ((Capability *)c->cap[0]->protected_data)
return return
case CAPTYPE_CAPPAGE: case CAPTYPE_CAPPAGE:
mem->free_cappage ((Cappage *)cap->protected_data) mem->free_cappage ((Cappage *)c->cap[0]->protected_data)
return return
default: default:
panic (0x55228930, "invalid case") panic (0x55228930, "invalid case")
@ -249,41 +270,42 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability
break break
case CAP_MEMORY_MAP: case CAP_MEMORY_MAP:
// FIXME: this should work for fake pages as well. // 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 break
Page *page = (Page *)cap->protected_data Page *page = (Page *)c->cap[0]->protected_data
if page->address_space != mem: if page->address_space != mem:
break 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 break
case CAP_MEMORY_MAPPING: case CAP_MEMORY_MAPPING:
bool write bool write
Page *page = mem->get_mapping (data, &write) Page *page = mem->get_mapping (c->data[1], &write)
unsigned t = CAPTYPE_PAGE | REQUEST_MASK unsigned t = CAPTYPE_PAGE | REQUEST_MASK
if !write: if !write:
t &= ~CAP_PAGE_WRITE t &= ~CAP_PAGE_WRITE
reply_cap (t, (unsigned)page) reply_cap (t, (unsigned)page)
break break
case CAP_MEMORY_SET_LIMIT: case CAP_MEMORY_SET_LIMIT:
mem->limit = data mem->limit = c->data[1]
break break
case CAP_MEMORY_GET_LIMIT: case CAP_MEMORY_GET_LIMIT:
reply_num (mem->limit) reply_num (mem->limit)
break break
case CAP_MEMORY_DROP: case CAP_MEMORY_DROP:
if cap->address_space != mem: if !c->cap[0] || c->cap[0]->address_space != mem:
break break
mem->free_capability (cap) mem->free_capability (c->cap[0])
break break
default: default:
break 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 Thread *thread = (Thread *)protected_data
switch data[0]: switch c->data[0]:
case CAP_THREAD_INFO: case CAP_THREAD_INFO:
unsigned *value unsigned *value
switch data[1]: switch c->data[1]:
case CAP_THREAD_INFO_PC: case CAP_THREAD_INFO_PC:
value = &thread->pc value = &thread->pc
break break
@ -292,10 +314,10 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability
break break
case CAP_THREAD_INFO_FLAGS: case CAP_THREAD_INFO_FLAGS:
// It is not possible to set the PRIV flag, but it can be reset. // 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 value = &thread->flags
if data[3] & ~THREAD_FLAG_USER: if c->data[3] & ~THREAD_FLAG_USER:
unsigned v = (*value & data[3]) | (data[2] & data[3]) unsigned v = (*value & c->data[3]) | (c->data[2] & c->data[3])
if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING): if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING):
if v & THREAD_FLAG_WAITING: if v & THREAD_FLAG_WAITING:
thread->wait () thread->wait ()
@ -308,11 +330,11 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability
thread->unrun () thread->unrun ()
break break
default: default:
value = Thread_arch_info (thread, data[1]) value = Thread_arch_info (thread, c->data[1])
break break
if value: if value:
*value &= ~data[3] *value &= ~c->data[3]
*value |= data[2] & data[3] *value |= c->data[2] & c->data[3]
reply_num (*value) reply_num (*value)
else: else:
reply_num (0) reply_num (0)
@ -321,24 +343,39 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability
schedule () schedule ()
break break
case CAP_THREAD_DEBUG: 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 break
case CAP_THREAD_REGISTER_INTERRUPT: case CAP_THREAD_REGISTER_INTERRUPT:
// Threads with access to this call are trusted, so no sanity checking is done. // 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 break
case CAP_THREAD_GET_TOP_MEMORY: case CAP_THREAD_GET_TOP_MEMORY:
// Threads with access to this call are trusted, so no sanity checking is done. // 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 break
case CAP_THREAD_MAKE_PRIV: case CAP_THREAD_MAKE_PRIV:
// Threads with access to this call are trusted, so no sanity checking is done. // Threads with access to this call are trusted, so no sanity checking is done.
if data[1] & THREAD_FLAG_PRIV: if c->data[1] & THREAD_FLAG_PRIV:
((Thread *)cap->protected_data)->flags |= THREAD_FLAG_PRIV ((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV
reply_cap (CAPTYPE_THREAD | (data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), cap->protected_data) reply_cap (CAPTYPE_THREAD | (c->data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data)
break break
case CAP_THREAD_ALLOC_PHYSICAL: 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 break
default: default:
break break
@ -393,7 +430,7 @@ static bool cappage_check_payment (Cappage *cappage):
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME) p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
return false 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 Page *page
Cappage *cappage Cappage *cappage
ShareData *share_data ShareData *share_data
@ -405,22 +442,22 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c
page = NULL page = NULL
cappage = (Cappage *)protected_data cappage = (Cappage *)protected_data
share_data = &cappage->data share_data = &cappage->data
switch data[0]: switch c->data[0]:
case CAP_PAGE_SHARE: 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. // FIXME: This makes it impossible to use a fake Page capability.
break break
if page: if page:
Page *t = (Page *)cap->protected_data Page *t = (Page *)c->cap[0]->protected_data
t->forget () t->forget ()
if data[1] & PAGE_SHARE_READONLY: if c->data[1] & PAGE_SHARE_READONLY:
t->data.flags &= ~PAGE_FLAG_WRITABLE t->data.flags &= ~PAGE_FLAG_WRITABLE
if !page->data.flags & PAGE_FLAG_FRAME: if !page->data.flags & PAGE_FLAG_FRAME:
break break
if data[1] & PAGE_SHARE_COPY: if c->data[1] & PAGE_SHARE_COPY:
if ~t->data.flags & PAGE_FLAG_PAYING: if ~t->data.flags & PAGE_FLAG_PAYING:
break 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 unsigned *d = (unsigned *)page->data.frame
if t == page: if t == page:
Page *other = page->data.share_next ? (Page *)page->data.share_next : (Page *)page->data.share_prev 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: else:
t->data.flags |= PAGE_FLAG_FRAME t->data.flags |= PAGE_FLAG_FRAME
t->data.frame = raw_zalloc () 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] ((unsigned *)t->data.frame)[i >> 2] = d[i >> 2]
else: else:
if t != page: if t != page:
@ -450,7 +487,7 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c
else: else:
if t == page: if t == page:
break break
if data[1] & PAGE_SHARE_FORGET: if c->data[1] & PAGE_SHARE_FORGET:
if ~page->data.flags & PAGE_FLAG_SHARED: if ~page->data.flags & PAGE_FLAG_SHARED:
if t->data.flags & PAGE_FLAG_PAYING: if t->data.flags & PAGE_FLAG_PAYING:
t->data.frame = page->data.frame 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 *)t->data.share_prev)->data.share_next = t
Page_arch_update_mapping (t) Page_arch_update_mapping (t)
else: else:
Cappage *t = (Cappage *)cap->protected_data Cappage *t = (Cappage *)c->cap[0]->protected_data
t->forget () t->forget ()
if data[1] & PAGE_SHARE_READONLY: if c->data[1] & PAGE_SHARE_READONLY:
t->data.flags &= ~PAGE_FLAG_WRITABLE t->data.flags &= ~PAGE_FLAG_WRITABLE
if !cappage->data.flags & PAGE_FLAG_FRAME: if !cappage->data.flags & PAGE_FLAG_FRAME:
break break
if data[1] & PAGE_SHARE_COPY: if c->data[1] & PAGE_SHARE_COPY:
if ~t->data.flags & PAGE_FLAG_PAYING: if ~t->data.flags & PAGE_FLAG_PAYING:
break 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 unsigned *d = (unsigned *)cappage->data.frame
if t == cappage: if t == cappage:
Cappage *other = cappage->data.share_next ? (Cappage *)cappage->data.share_next : (Cappage *)cappage->data.share_prev 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: else:
t->data.flags |= PAGE_FLAG_FRAME t->data.flags |= PAGE_FLAG_FRAME
t->data.frame = raw_zalloc () 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] ((unsigned *)t->data.frame)[i >> 2] = d[i >> 2]
else: else:
if t != cappage: if t != cappage:
@ -513,7 +550,7 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c
else: else:
if t == cappage: if t == cappage:
break break
if data[1] & PAGE_SHARE_FORGET: if c->data[1] & PAGE_SHARE_FORGET:
if ~cappage->data.flags & PAGE_FLAG_SHARED: if ~cappage->data.flags & PAGE_FLAG_SHARED:
if t->data.flags & PAGE_FLAG_PAYING: if t->data.flags & PAGE_FLAG_PAYING:
t->data.frame = cappage->data.frame 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: if t->data.share_prev:
((Cappage *)t->data.share_prev)->data.share_next = t ((Cappage *)t->data.share_prev)->data.share_next = t
case CAP_PAGE_FLAGS: case CAP_PAGE_FLAGS:
// Always refuse to set reserved flags.
c->data[2] &= ~(PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
// Remember the old flags. // Remember the old flags.
unsigned old = share_data->flags unsigned old = share_data->flags
// Compute the new 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 we stop paying, see if the frame is still paid for. If not, free it.
if ~new_flags & old & PAGE_FLAG_PAYING: if ~new_flags & old & PAGE_FLAG_PAYING:
@ -626,54 +665,54 @@ static void page_invoke (unsigned target, unsigned protected_data, Capability *c
reply_num (share_data->flags) reply_num (share_data->flags)
break break
case CAP_CAPPAGE_SET: 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 return
Capability *c = &((Capability *)cappage->data.frame)[data[1]] Capability *cap = &((Capability *)cappage->data.frame)[c->data[1]]
c->invalidate () if cap:
// clone_capability needs a Memory, but doesn't use it when storage is provided. cap->invalidate ()
top_memory.clone_capability (cap, copy, c) // 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 break
default: default:
break 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 Capability *capability = (Capability *)protected_data
switch request: switch c->data[0]:
case CAP_CAPABILITY_GET: case CAP_CAPABILITY_GET:
reply_cap (capability, true) reply_cap (capability, true)
break break
default: default:
break 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: // Kernel calling convention:
// data[0] is the request. // data[0] is the request.
// cap[0] is the reply capability // cap[0] is the reply capability
// other parameters' meanings depend on the operation. // 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)): if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_CALL))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)):
// This is a call capability. // This is a call capability.
reply_receiver = (Receiver *)protected_data reply_receiver = (Receiver *)protected_data
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC)) reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
Capability r Capability r
Capability *c0 = c[0] Capability *c0 = c->cap[0]
if ~(unsigned)c0->target & ~KERNEL_MASK: if (unsigned)c0->target & ~KERNEL_MASK:
// The call is not to a kernel capability.
fill_cap (&r, protected_data, reply_receiver->reply_protected_data) fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
c[0] = &r c->cap[0] = &r
copy[0] = true c->copy[0] = true
bool ret = kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0) bool ret = c0->target->send_message (c0->protected_data, c)
r.invalidate () r.invalidate ()
return ret return ret
else: else:
// Kernel call: don't create actual capablities. // Kernel call: don't create actual capablities.
reply = NULL 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)): if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability. // This is a reply capability.
Receiver *r = (Receiver *)protected_data Receiver *r = (Receiver *)protected_data
r->send_message (r->reply_protected_data, d, c, copy) r->send_message (r->reply_protected_data, c)
while self->parent: while self->parent:
self = self->parent self = self->parent
while self->sibling_prev: while self->sibling_prev:
@ -682,36 +721,42 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[
self->sibling_next->invalidate () self->sibling_next->invalidate ()
self->invalidate () self->invalidate ()
return true return true
reply = c[0] // It's a normal kernel capability; check permission.
if d[0] == CAP_DEGRADE: if !((1 << c->data[0]) & target & REQUEST_MASK):
reply_cap (target & d[1], protected_data) // 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 return true
switch target & CAPTYPE_MASK: switch target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
receiver_invoke (target, protected_data, c[1], d) receiver_invoke (target, protected_data, c)
break break
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
memory_invoke (target, protected_data, c[1], d[0], d[1]) memory_invoke (target, protected_data, c)
break break
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
thread_invoke (target, protected_data, c[1], d) thread_invoke (target, protected_data, c)
break break
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
page_invoke (target, protected_data, c[1], copy[1], d) page_invoke (target, protected_data, c)
break break
case CAPTYPE_CAPABILITY: case CAPTYPE_CAPABILITY:
capability_invoke (target, protected_data, c[1], d[0], d[1]) capability_invoke (target, protected_data, c)
break break
case CAPTYPE_CAPPAGE: case CAPTYPE_CAPPAGE:
page_invoke (target, protected_data, c[1], copy[1], d)
break break
default: default:
panic (0x99337744, "invalid capability type invoked") panic (0x99337744, "invalid capability type invoked")
return true return true
bool Capability::invoke (unsigned data[4], Capability *cap[4], bool copy[4]): bool Capability::invoke (Context *c):
if (unsigned)target & ~KERNEL_MASK: if (unsigned)target & ~KERNEL_MASK:
// This is not a kernel capability: send a message to the receiver. // 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. // 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)

116
iris.h
View File

@ -22,6 +22,10 @@
extern "C" { extern "C" {
#endif #endif
#define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define KERNEL_MASK 0xfff #define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00 #define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK) #define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
@ -98,12 +102,16 @@ extern "C" {
/* Flag values for Page and Cappage objects. */ /* 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. */ /* A writable page can be written to. This flag can not be set while the frame is shared. */
#define PAGE_FLAG_WRITABLE 1 #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 #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. */ /* 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 #define PAGE_FLAG_FRAME 4
/* This is a read-only flag, which is set if the Page is shared. */ /* This is a read-only flag, which is set if the Page is shared. */
#define PAGE_FLAG_SHARED 8 #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_GET 1
#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff #define CAP_CAPABILITY_ALL_RIGHTS 0x1ff
@ -134,42 +142,70 @@ typedef struct Message
static int invoke (Capability target, Message *msg) static int invoke (Capability target, Message *msg)
{ {
register int ret __asm__ ("v0"); unsigned ret;
register unsigned v0 __asm__ ("v0") = target; __asm__ volatile ("lw $v0, %1\n"
register unsigned a0 __asm__ ("a0") = msg->cap[0]; "\tlw $a3, %2\n"
register unsigned a1 __asm__ ("a1") = msg->cap[1]; "\tlw $t0, 0($a3)\n"
register unsigned a2 __asm__ ("a2") = msg->cap[2]; "\tlw $t1, 4($a3)\n"
register unsigned a3 __asm__ ("a3") = msg->cap[3]; "\tlw $t2, 8($a3)\n"
register unsigned t0 __asm__ ("t0") = msg->data[0]; "\tlw $t3, 12($a3)\n"
register unsigned t1 __asm__ ("t1") = msg->data[1]; "\tlw $a0, 16($a3)\n"
register unsigned t2 __asm__ ("t2") = msg->data[2]; "\tlw $a1, 20($a3)\n"
register unsigned t3 __asm__ ("t3") = msg->data[3]; "\tlw $a2, 24($a3)\n"
__asm__ volatile ("syscall" : "+r" (v0), "=r" (a0), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (t0), "=r" (t1), "=r" (t2), "=r" (t3)); "\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; 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) static int call (Capability target, Message *msg)
{ {
register int ret __asm__ ("v0"); unsigned ret;
register unsigned v0 __asm__ ("v0") = target; Capability t = cap_copy (target);
register unsigned a0 __asm__ ("a0") = msg->cap[0]; __asm__ volatile ("lw $v0, %1\n"
register unsigned a1 __asm__ ("a1") = msg->cap[1]; "\tlw $v1, %2\n"
register unsigned a2 __asm__ ("a2") = msg->cap[2]; "\tlw $t0, 0($v1)\n"
register unsigned a3 __asm__ ("a3") = msg->cap[3]; "\tlw $t1, 4($v1)\n"
register unsigned t0 __asm__ ("t0") = msg->data[0]; "\tlw $t2, 8($v1)\n"
register unsigned t1 __asm__ ("t1") = msg->data[1]; "\tlw $t3, 12($v1)\n"
register unsigned t2 __asm__ ("t2") = msg->data[2]; "\tlw $a0, 16($v1)\n"
register unsigned t3 __asm__ ("t3") = msg->data[3]; "\tlw $a1, 20($v1)\n"
__asm__ volatile ("syscall" : "+r" (v0), "+r" (a0), "+r" (a1), "+r" (a2), "+r" (a3), "+r" (t0), "+r" (t1), "+r" (t2), "+r" (t3)); "\tlw $a2, 24($v1)\n"
msg->cap[0] = a0; "\tlw $a3, 28($v1)\n"
msg->cap[1] = a1; "\tsyscall\n"
msg->cap[2] = a2; "\tmove %0, $v0\n"
msg->cap[3] = a3; "\tsw $t0, 0($v1)\n"
msg->data[0] = t0; "\tsw $t1, 4($v1)\n"
msg->data[1] = t1; "\tsw $t2, 8($v1)\n"
msg->data[2] = t2; "\tsw $t3, 12($v1)\n"
msg->data[3] = t3; "\tsw $a0, 16($v1)\n"
return ret; "\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) 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) 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) 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) 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) 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) 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) 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) 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) 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 */ /* 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); return invoke_12 (memory, page, CAP_MEMORY_MAP, address);
} }

View File

@ -83,6 +83,19 @@ struct Message : public Object <Message>:
unsigned data[4] unsigned data[4]
unsigned protected_data unsigned protected_data
struct Capability : public Object <Capability>:
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 <Receiver>: struct Receiver : public Object <Receiver>:
Thread *owner Thread *owner
Receiver *prev_owned, *next_owned Receiver *prev_owned, *next_owned
@ -93,16 +106,7 @@ struct Receiver : public Object <Receiver>:
void own (Thread *o) void own (Thread *o)
void orphan () void orphan ()
bool try_deliver () bool try_deliver ()
bool send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4]) bool send_message (unsigned protected_data, Capability::Context *c)
struct Capability : public Object <Capability>:
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 ()
struct ShareData : struct ShareData :
unsigned frame unsigned frame
@ -194,7 +198,7 @@ void raw_pfree (unsigned page)
// Defined by architecture-specific files. // Defined by architecture-specific files.
void Thread_arch_init (Thread *thread) void Thread_arch_init (Thread *thread)
void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]) void Thread_arch_receive (Thread *thread, Capability::Context *c)
void Thread_arch_receive_fail (Thread *thread) void Thread_arch_receive_fail (Thread *thread)
unsigned *Thread_arch_info (Thread *thread, unsigned num) unsigned *Thread_arch_info (Thread *thread, unsigned num)
void Memory_arch_init (Memory *mem) void Memory_arch_init (Memory *mem)

View File

@ -17,7 +17,7 @@
load = 0x80000000 load = 0x80000000
ARCH_CXXFLAGS = -DNUM_THREADS=2 ARCH_CXXFLAGS = -DNUM_THREADS=1
ARCH_CPPFLAGS = -Imips -Wa,-mips32 ARCH_CPPFLAGS = -Imips -Wa,-mips32
CROSS = mipsel-linux-gnu- CROSS = mipsel-linux-gnu-
OBJDUMP = $(CROSS)objdump OBJDUMP = $(CROSS)objdump
@ -40,9 +40,6 @@ $(boot_threads): TARGET_FLAGS = -I.
uimage: kernel.raw.gz Makefile mips/Makefile.arch 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' 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 %.o:%.S Makefile mips/Makefile.arch mips/arch.hh
$(CC) $(CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@ $(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: % %.gz: %
gzip < $< > $@ 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

View File

@ -45,15 +45,15 @@ void Thread_arch_init (Thread *thread):
thread->arch.k0 = 0 thread->arch.k0 = 0
thread->arch.k1 = 0 thread->arch.k1 = 0
void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]): void Thread_arch_receive (Thread *thread, Capability::Context *c):
thread->arch.a0 = (unsigned)c[0] thread->arch.a0 = (unsigned)c->cap[0]
thread->arch.a1 = (unsigned)c[1] thread->arch.a1 = (unsigned)c->cap[1]
thread->arch.a2 = (unsigned)c[2] thread->arch.a2 = (unsigned)c->cap[2]
thread->arch.a3 = (unsigned)c[3] thread->arch.a3 = (unsigned)c->cap[3]
thread->arch.t0 = d[0] thread->arch.t0 = c->data[0]
thread->arch.t1 = d[1] thread->arch.t1 = c->data[1]
thread->arch.t2 = d[2] thread->arch.t2 = c->data[2]
thread->arch.t3 = d[3] thread->arch.t3 = c->data[3]
thread->arch.v0 = 1 thread->arch.v0 = 1
void Thread_arch_receive_fail (Thread *thread): void Thread_arch_receive_fail (Thread *thread):
@ -222,10 +222,12 @@ static unsigned make_entry_lo (Page *page, bool write):
if !page->data.frame: if !page->data.frame:
return 0 return 0
unsigned flags unsigned flags
if write: if page->data.flags & PAGE_FLAG_UNCACHED:
flags = 0x18 | 0x4 | 0x2 flags = 0x10 | 0x2
else else:
flags = 0x18 | 0x2 flags = 0x18 | 0x2
if write:
flags |= 0x4
return ((page->data.frame & ~0x80000000) >> 6) | flags return ((page->data.frame & ~0x80000000) >> 6) | flags
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write): bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
@ -320,30 +322,36 @@ void Page_arch_update_mapping (Page *page):
tlb_reset (p->mapping & ~1, as->arch.asid, t) tlb_reset (p->mapping & ~1, as->arch.asid, t)
void arch_invoke (): void arch_invoke ():
Capability *target, *c[4] Capability *target
bool wait, copy[4] bool wait
Thread *caller = current Thread *caller = current
target = caller->address_space->find_capability (current->arch.v0, &wait) target = caller->address_space->find_capability (current->arch.v0, &wait)
if !target: if !target:
// TODO: there must be no action here. This is just because the rest doesn't work yet. // 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_send (3, 2)
dbg_sleep (1000)
schedule () schedule ()
// Calling an invalid capability always fails. // Calling an invalid capability always fails.
caller->arch.v0 = 0 caller->arch.v0 = 0
else: else:
if wait: if wait:
caller->wait () caller->wait ()
c[0] = caller->address_space->find_capability (caller->arch.a0, &copy[0]) Capability::Context c
c[1] = caller->address_space->find_capability (caller->arch.a1, &copy[1]) c.cap[0] = caller->address_space->find_capability (caller->arch.a0, &c.copy[0])
c[2] = caller->address_space->find_capability (caller->arch.a2, &copy[2]) c.cap[1] = caller->address_space->find_capability (caller->arch.a1, &c.copy[1])
c[3] = caller->address_space->find_capability (caller->arch.a3, &copy[3]) c.cap[2] = caller->address_space->find_capability (caller->arch.a2, &c.copy[2])
unsigned d[4] c.cap[3] = caller->address_space->find_capability (caller->arch.a3, &c.copy[3])
d[0] = caller->arch.t0 c.data[0] = caller->arch.t0
d[1] = caller->arch.t1 c.data[1] = caller->arch.t1
d[2] = caller->arch.t2 c.data[2] = caller->arch.t2
d[3] = caller->arch.t3 c.data[3] = caller->arch.t3
caller->arch.v0 = target->invoke (d, c, copy) ? 1 : 0 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 caller != current:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space: if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]: if asids[0]:

View File

@ -61,10 +61,6 @@
#define CP0_DESAVE 31 #define CP0_DESAVE 31
#endif #endif
#define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
// register save positions in Thread // register save positions in Thread
#define SAVE_PC (5 * 4) #define SAVE_PC (5 * 4)
#define SAVE_SP (SAVE_PC + 4) #define SAVE_SP (SAVE_PC + 4)

View File

@ -80,7 +80,7 @@ addr_100:
addr_180: addr_180:
// General exception // General exception
// Allow new exceptions to update EPC and friends. // Allow new exceptions to update EPC and friends.
//mtc0 $zero, $CP0_STATUS mtc0 $zero, $CP0_STATUS
sw $ra, -0xd88($zero) sw $ra, -0xd88($zero)
bal save_regs bal save_regs
nop nop

View File

@ -178,10 +178,12 @@ static void init_threads ():
if !stackpage || !mem->map (stackpage, 0x7ffff000, true): if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
panic (0x13151719, "unable to map initial stack page") panic (0x13151719, "unable to map initial stack page")
Receiver *recv = mem->alloc_receiver () 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.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.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.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) mem->pfree ((unsigned)pages)
thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
thread->schedule_next = NULL thread->schedule_next = NULL

View File

@ -30,6 +30,11 @@ Thread *tlb_refill ():
cp0_get (CP0_ENTRY_HI, EntryHi) cp0_get (CP0_ENTRY_HI, EntryHi)
unsigned *t = directory[EntryHi >> 21] unsigned *t = directory[EntryHi >> 21]
if !t: 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") panic (0x99992222, "No page table")
// - 2 instead of - 1 means reset bit 0 // - 2 instead of - 1 means reset bit 0
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2) unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
@ -50,17 +55,18 @@ Thread *interrupt ():
status &= ~(1 << (i + 8)) status &= ~(1 << (i + 8))
// Send message to interrupt handler. // Send message to interrupt handler.
if arch_interrupt_receiver[i]: if arch_interrupt_receiver[i]:
unsigned data[4] = {0, 0, 0, 0} Capability::Context c
Capability *cap[4] = {NULL, NULL, NULL, NULL} for unsigned j = 0; j < 4; ++j:
bool copy[4] = {false, false, false, false} c.data[j] = 0
arch_interrupt_receiver[i]->send_message (i, data, cap, copy) c.cap[j] = NULL
c.copy[j] = false
arch_interrupt_receiver[i]->send_message (i, &c)
return current return current
/// A general exception has occurred. /// A general exception has occurred.
Thread *exception (): Thread *exception ():
unsigned cause unsigned cause
cp0_get (CP0_CAUSE, cause) cp0_get (CP0_CAUSE, cause)
//dbg_send (cause >> 2, 5)
switch (cause >> 2) & 0x1f: switch (cause >> 2) & 0x1f:
case 0: case 0:
// Interrupt. This shouldn't happen, since CAUSE[IV] == 1. // Interrupt. This shouldn't happen, since CAUSE[IV] == 1.
@ -70,6 +76,9 @@ Thread *exception ():
panic (0x21223344, "TLB modification.") panic (0x21223344, "TLB modification.")
case 2: case 2:
// TLB load or instruction fetch. // TLB load or instruction fetch.
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a)
panic (0x31223344, "TLB load or instruction fetch.") panic (0x31223344, "TLB load or instruction fetch.")
case 3: case 3:
// TLB store. // TLB store.
@ -79,6 +88,9 @@ Thread *exception ():
panic (0x51223344, "Address error load or instruction fetch.") panic (0x51223344, "Address error load or instruction fetch.")
case 5: case 5:
// Address error store. // Address error store.
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a, 16)
panic (0x61223344, "Address error store.") panic (0x61223344, "Address error store.")
case 6: case 6:
// Bus error instruction fetch. // Bus error instruction fetch.
@ -88,6 +100,7 @@ Thread *exception ():
panic (0x81223344, "Bus error load or store.") panic (0x81223344, "Bus error load or store.")
case 8: case 8:
// Syscall. // Syscall.
current->pc += 4
arch_invoke () arch_invoke ()
break break
case 9: case 9:

View File

@ -18,36 +18,43 @@
#include "kernel.hh" #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 (): void Thread::run ():
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
return return
flags |= THREAD_FLAG_RUNNING flags |= THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING: if flags & THREAD_FLAG_WAITING:
return return
schedule_next = first_scheduled run_thread (this)
if schedule_next:
schedule_next->schedule_prev = this
first_scheduled = this
void Thread::unrun (): void Thread::unrun ():
if !(flags & THREAD_FLAG_RUNNING): if !(flags & THREAD_FLAG_RUNNING):
return return
flags &= ~THREAD_FLAG_RUNNING flags &= ~THREAD_FLAG_RUNNING
if !(flags & THREAD_FLAG_WAITING): if flags & THREAD_FLAG_WAITING:
if current == this: return
current = schedule_next unrun_thread (this)
if schedule_prev:
schedule_prev->schedule_next = schedule_next
else:
first_scheduled = schedule_next
if schedule_next:
schedule_next->schedule_prev = schedule_prev
void Thread::wait (): void Thread::wait ():
if flags & THREAD_FLAG_WAITING: if flags & THREAD_FLAG_WAITING:
return return
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
unrun () unrun_thread (this)
flags |= THREAD_FLAG_WAITING flags |= THREAD_FLAG_WAITING
// Try to receive a message from a Receiver immediately. // Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned: for Receiver *r = receivers; r; r = r->next_owned:
@ -59,8 +66,7 @@ void Thread::unwait ():
return return
flags &= ~THREAD_FLAG_WAITING flags &= ~THREAD_FLAG_WAITING
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
flags &= ~THREAD_FLAG_RUNNING run_thread (this)
run ()
void schedule (): void schedule ():
Thread *old = current Thread *old = current
@ -68,5 +74,3 @@ void schedule ():
current = current->schedule_next current = current->schedule_next
if !current: if !current:
current = first_scheduled current = first_scheduled
if !current:
current = &idle