1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 01:26:43 +03: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.
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)

View File

@ -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 ():

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.
#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

View File

@ -16,10 +16,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
.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)

View File

@ -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

View File

@ -20,4 +20,4 @@
int main ():
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:
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)

116
iris.h
View File

@ -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);
}

View File

@ -83,6 +83,19 @@ struct Message : public Object <Message>:
unsigned data[4]
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>:
Thread *owner
Receiver *prev_owned, *next_owned
@ -93,16 +106,7 @@ struct Receiver : public Object <Receiver>:
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 <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 ()
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)

View File

@ -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

View File

@ -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, &copy[0])
c[1] = caller->address_space->find_capability (caller->arch.a1, &copy[1])
c[2] = caller->address_space->find_capability (caller->arch.a2, &copy[2])
c[3] = caller->address_space->find_capability (caller->arch.a3, &copy[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]:

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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