1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-29 19:32:25 +02:00

lcd working

This commit is contained in:
Bas Wijnen 2009-07-20 00:23:45 +02:00
parent cc1dc267d5
commit bee84d53ec
16 changed files with 790 additions and 400 deletions

View File

@ -22,20 +22,20 @@
#define NEXT(x) (((Object_base **)(x))[-1])
#define SIZE (2 * sizeof (Object_base *))
bool Memory::use ():
bool Memory::use (unsigned num):
// Go up to parents, incrementing used.
for Memory *m = this; m; m = m->address_space:
if used >= limit:
if used + num > limit:
// Not allowed. Restore used for all children.
for Memory *r = this; r != m; r = r->address_space:
--r->used
r->used -= num
return false
++m->used
m->used += num
return true
void Memory::unuse ():
void Memory::unuse (unsigned num):
for Memory *m = this; m; m = m->address_space:
--m->used
m->used -= num
void *Memory::search_free (unsigned size, void **first):
Free *f
@ -50,6 +50,7 @@ void *Memory::search_free (unsigned size, void **first):
if !f:
unsigned p = palloc ()
if !p:
assert (false)
return NULL
f = (Free *)(p + SIZE)
f->marker = ~0
@ -134,21 +135,18 @@ Thread *Memory::alloc_thread ():
ret->pc = 0
ret->sp = 0
Thread_arch_init (ret)
ret->sleep_count = ~0
ret->flags = 0
ret->schedule_prev = NULL
ret->schedule_next = NULL
ret->receivers = NULL
return ret
Message *Memory::alloc_message (Receiver *target, unsigned protected_data):
Message *Memory::alloc_message (Receiver *target):
Message *ret = (Message *)search_free (sizeof (Message), (void **)&target->messages)
if !ret:
return NULL
for unsigned i = 0; i < 4; ++i:
ret->capabilities[i] = NULL
ret->data[i] = 0
ret->protected_data = protected_data
if !ret->next:
target->last_message = ret
return ret
Receiver *Memory::alloc_receiver ():
@ -158,8 +156,10 @@ Receiver *Memory::alloc_receiver ():
ret->owner = NULL
ret->prev_owned = NULL
ret->next_owned = NULL
ret->alarm_count = ~0
ret->capabilities = NULL
ret->messages = NULL
ret->last_message = NULL
ret->reply_protected_data = ~0
ret->protected_only = false
return ret
@ -251,9 +251,18 @@ void Memory::free_thread (Thread *thread):
thread->receivers->orphan ()
free_obj (thread)
void Memory::free_message (Message *message):
void Memory::free_message (Receiver *owner, Message *message):
if message->prev:
message->prev->next = message->next
else:
owner->messages = message->next
if message->next:
message->next->prev = message->prev
else:
owner->last_message = message->prev
for unsigned i = 0; i < 4; ++i:
free_capability (message->capabilities[i])
if message->capabilities[i]:
free_capability (message->capabilities[i])
free_obj (message)
void Memory::free_receiver (Receiver *receiver):
@ -261,7 +270,7 @@ void Memory::free_receiver (Receiver *receiver):
while receiver->capabilities:
receiver->capabilities->invalidate ()
while receiver->messages:
free_message (receiver->messages)
free_message (receiver, receiver->messages)
free_obj (receiver)
void Receiver::orphan ():
@ -346,7 +355,8 @@ void Page::forget ():
data.share_prev = NULL
data.share_next = NULL
else:
if ~data.flags & PAGE_FLAG_PHYSICAL:
// If the page has a frame and should be freed, free it.
if !((data.flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)):
raw_pfree (data.frame)
data.frame = 0
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)

View File

@ -24,6 +24,7 @@
__start:
bal 1f
__hack_label:
nop
.word _gp
1:

View File

@ -26,7 +26,6 @@
// For some reason, it only works if the rows are input and the columns are output.
static void event (bool release, unsigned row, unsigned col):
kdebug ((release ? 0x10000 : 0) | (row << 8) | col)
#define COL_MASK 0x2000ffff
#define ROW_MASK 0x000000ff

View File

@ -20,6 +20,13 @@
#define ARCH
#include "arch.hh"
#define assert(x) do { while (!(x)) kdebug (0, 0); } while (0)
// For now, support only 16 bpp.
// Screen is 800x480 tft.
unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
#define frame_size (v * h * Bpp)
// Pin definitions, all in port 2.
#define PWM_ENABLE (1 << 30)
#define SPEN (1 << 0) //LCD_SPL
@ -37,22 +44,25 @@ static void set_backlight (bool state):
PWM_CTR (0) = 0x3f
GPIO_GPDR (2) &= ~PWM_ENABLE
static void reset ():
struct Descriptor:
unsigned next
unsigned frame
unsigned id
unsigned cmd
static void reset (unsigned physical_descriptor):
PWM_PER (0) = 300
set_backlight (false)
set_backlight (true)
// initialize things.
GPIO_GPIER (2) &= ~(PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA)
GPIO_GPDIR (2) |= PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA
GPIO_GPDIR (2) |= PWM_ENABLE | LCD_RET
udelay (50)
GPIO_GPDR (2) &= ~LCD_RET
ddelay (2)
GPIO_GPDR (2) |= LCD_RET
ddelay (1)
// For now, support only 16 bpp.
// Screen is 800x480 tft.
unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
LCD_VSYNC = vs
LCD_HSYNC = hs
@ -60,55 +70,99 @@ static void reset ():
LCD_DAH = (hs << 16) | (hs + h)
LCD_VAT = ((hs + h) << 16) | (vs + v)
#define MODE_TFT_GEN 0
#define PCLK_N (1 << 10)
#define VSYNC_N (1 << 8)
LCD_CFG = MODE_TFT_GEN | PCLK_N | VSYNC_N
LCD_CFG = MODE_TFT_GEN | VSYNC_N
cpm_stop_lcd ()
unsigned pllout = cpm_get_pllout ()
unsigned pixclock = fps * (hs + h) * (vs + v)
unsigned pllout = cpm_get_pllout ()
CPM_CFCR2 = pllout / pixclock - 1
unsigned val = pllout / (pixclock * 4) - 1
while val < 0xf && pllout / (val + 1) > 150000000:
++val
assert (pllout / (val + 1) <= 150000000)
assert (val <= 0xf)
cpm_set_lcdclk_div (val)
CPM_CFCR |= CPM_CFCR_UPE
cpm_start_lcd ()
udelay (1000)
//LCD_DA0 = framebuffer
unsigned frame_size = v * h * Bpp
LCD_CMD0 = LCD_CMD_SOFINT | LCD_CMD_EOFINT | (frame_size << LCD_CMD_LEN_BIT)
LCD_DA0 = physical_descriptor
lcd_set_ena ()
lcd_enable_eof_intr ()
int main ():
// TODO: The descriptor takes an entire uncached page, because I don't know how to force a cache write-back. It's much better to do that instead.
map_gpio ()
map_pwm0 ()
map_lcd ()
map_cpm ()
reset ()
unsigned pages = (frame_size + 16 + ~PAGE_MASK) >> PAGE_BITS
assert (pages > CAPPAGE_SIZE && pages <= 2 * CAPPAGE_SIZE)
unsigned physical = alloc_range (__my_memory, pages)
assert (physical)
//Capability cappage[2]
//unsigned base[2]
//cappage[0] = memory_create_cappage (__my_memory, &base[0])
//cappage[1] = memory_create_cappage (__my_memory, &base[1])
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
Capability page = memory_create_page (__my_memory)
//cappage_set (cappage[0], page, i)
alloc_physical (page, physical + i * PAGE_SIZE, 0, 1)
memory_map (__my_memory, page, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1)
drop (page)
for unsigned i = 0; i < pages - CAPPAGE_SIZE; ++i:
Capability page = memory_create_page (__my_memory)
//cappage_set (cappage[1], page, i)
alloc_physical (page, physical + (i + CAPPAGE_SIZE) * PAGE_SIZE, 0, 1)
memory_map (__my_memory, page, (unsigned)LCD_FRAMEBUFFER_BASE + (i + CAPPAGE_SIZE) * PAGE_SIZE, 1)
drop (page)
unsigned og = 0
for unsigned y = 0; y < 480; ++y:
unsigned g = (y << 6) / 480
if g != og:
og = g
g = 0x3f
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
for unsigned x = 0; x < 800; ++x:
unsigned r = (x << 5) / 800
unsigned b = ((9 * x * x + 25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
if r != olr:
olr = r
r = 0x1f
unsigned oyb = b
if y > 0:
oyb = ((9 * x * x + 25 * (y - 1) * (y - 1)) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
if b != ob || b != oyb:
ob = b
b = 0x1f
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
Descriptor *descriptor = (Descriptor *)((unsigned)LCD_FRAMEBUFFER_BASE + frame_size)
unsigned physical_descriptor = physical + frame_size
descriptor->next = physical_descriptor
descriptor->frame = physical
descriptor->id = 0xdeadbeef
descriptor->cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT)
reset (physical_descriptor)
register_interrupt (IRQ_LCD)
set_backlight (true)
while true:
Message msg
if !wait (&msg):
continue
wait (&msg)
switch msg.protected_data:
case IRQ_LCD:
kdebug (0)
LCD_STATE &= ~LCD_STATE_EOF
lcd_clr_eof ()
register_interrupt (IRQ_LCD)
// TODO: allow callback
break
#if 0
case LCD_BACKLIGHT:
set_backlight (msg.data[0])
break
case LCD_RESET:
reset ()
//reset (physical_descriptor)
break
#endif

View File

@ -20,46 +20,59 @@
// From user-provided, thus untrusted, data, find a capability.
Capability *Memory::find_capability (unsigned code, bool *copy):
if !code:
return NULL
*copy = code & 2 ? true : false
if !(code & ~3):
return NULL
if code & 1:
// Cappage capability
unsigned num = (code & ~PAGE_MASK) >> 2
if num >= CAPPAGE_SIZE:
panic (0x15544551, "invalid cappage index")
return NULL
Capability *page = (Capability *)(code & PAGE_MASK)
unsigned page = code & PAGE_MASK
for Cappage *p = cappages; p; p = p->next:
if p->data.frame == (unsigned)page:
return &page[num]
if p->data.frame == page:
return p->cap (num)
else:
// Normal capability
code &= ~3
Capability *target = (Capability *)(code & ~3)
for Capability *c = capabilities; c; c = c->next:
if c == (Capability *)code:
if c == target:
return c
dbg_send (code)
panic (0xfffeee00, "invalid capability")
return NULL
// Try to deliver a message.
bool Receiver::try_deliver ():
if !messages || !owner || !owner->is_waiting ():
if !messages:
return false
Message *m = messages
if !owner || !owner->is_waiting ():
dbg_send (3, 3)
return false
Message *m = last_message
if protected_only:
for ; m; m = m->next:
for ; m; m = m->prev:
if m->protected_data == reply_protected_data:
protected_only = false
break
if !m:
return false
if !m:
panic (0x32547688, "protected only")
return false
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.data[i] = m->data[i]
if m->capabilities[i]:
c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true)
if !c.cap[i]:
panic (0xffaaaaaa, "out of memory")
for unsigned j = 0; j < i; ++j:
owner->address_space->free_capability (c.cap[i])
return false
else:
c.cap[i] = NULL
Thread_arch_receive (owner, m->protected_data, &c)
address_space->free_message (this, m)
owner->unwait ()
return true
@ -67,22 +80,41 @@ bool Receiver::try_deliver ():
bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
bool tried_direct = false
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
Capability *orig[4]
for unsigned i = 0; i < 4; ++i:
if c->cap[i]:
c->cap[i] = owner->address_space->clone_capability (c->cap[i], c->copy[i])
orig[i] = c->cap[i]
c->cap[i] = owner->address_space->clone_capability (orig[i], c->copy[i])
if !c->cap[i]:
panic (0xdddddddd, "out of memory")
for unsigned j = 0; j < i; ++j:
owner->address_space->free_capability (c->cap[i])
owner->address_space->free_capability (c->cap[j])
c->cap[j] = orig[j]
c->cap[i] = orig[i]
tried_direct = true
break
if !tried_direct:
if protected_data == reply_protected_data:
protected_only = false
Thread_arch_receive (owner, protected_data, c)
owner->unwait ()
return true
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
Message *msg = address_space->alloc_message (this, protected_data)
Message *msg = address_space->alloc_message (this)
if !msg:
panic (0xbbbbbbbb, "out of memory")
return false
msg->protected_data = protected_data
if protected_data == reply_protected_data:
// Put this message in the end (where it will be first seen). Clear the protected_only flag.
protected_only = false
if msg->next:
msg->next->prev = NULL
messages = msg->next
msg->next = NULL
msg->prev = last_message
msg->prev->next = msg
last_message = msg
for unsigned i = 0; i < 4; ++i:
msg->data[i] = c->data[i]
if !c->cap[i]:
@ -90,9 +122,10 @@ bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
else:
msg->capabilities[i] = address_space->clone_capability (c->cap[i], c->copy[i])
if !msg->capabilities[i]:
panic (0xcccccccc, "out of memory")
for unsigned j = 0; j < i; ++j:
address_space->free_capability (msg->capabilities[j])
address_space->free_message (msg)
address_space->free_message (this, msg)
return false
if tried_direct:
Thread_arch_receive_fail (owner)
@ -144,6 +177,22 @@ static void reply_cap (Capability *cap, bool copy):
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
static void reply_cappage (Cappage *cap, unsigned target):
Capability r
fill_cap (&r, target, (unsigned)cap)
Capability::Context c
for unsigned i = 1; i < 4; ++i:
c.data[i] = 0
c.cap[i] = NULL
c.copy[i] = false
c.data[0] = cap->data.frame
c.cap[0] = &r
c.copy[0] = true
if reply:
reply->invoke (&c)
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
static void reply_num (unsigned num):
Capability::Context c
c.data[0] = num
@ -186,12 +235,35 @@ static void receiver_invoke (unsigned target, unsigned protected_data, Capabilit
case CAP_RECEIVER_CREATE_CALL_CAPABILITY:
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:
case CAP_RECEIVER_REPLY_PROTECTED_DATA:
reply_nums (receiver->reply_protected_data, receiver->protected_only ? 1 : 0)
if c->data[1]:
receiver->reply_protected_data = c->data[2]
break
case CAP_RECEIVER_SET_REPLY_PROTECTED_DATA:
receiver->reply_protected_data = c->data[1]
receiver->protected_only = c->data[2]
case CAP_RECEIVER_ALARM:
unsigned old = receiver->alarm_count
reply_num (old)
if c->data[1]:
receiver->alarm_count = c->data[2]
else:
receiver->alarm_count += c->data[2]
if (old == ~0) ^ (receiver->alarm_count == ~0):
// The alarm stopped or started.
if old == ~0:
// It started.
receiver->prev_alarm = NULL
receiver->next_alarm = first_alarm
if receiver->next_alarm:
receiver->next_alarm->prev_alarm = receiver
first_alarm = receiver
else:
// It stopped.
if receiver->prev_alarm:
receiver->prev_alarm->next_alarm = receiver->next_alarm
else:
first_alarm = receiver->next_alarm
if receiver->next_alarm:
receiver->next_alarm->prev_alarm = receiver->prev_alarm
break
default:
break
@ -234,7 +306,7 @@ static void memory_invoke (unsigned target, unsigned protected_data, Capability:
case CAPTYPE_CAPPAGE:
Cappage *ret = mem->alloc_cappage ()
if ret:
reply_cap (CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS), (unsigned)ret)
reply_cappage (ret, CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS))
else:
reply_num (0)
break
@ -320,24 +392,17 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
unsigned v = (*value & c->data[3]) | (c->data[2] & c->data[3])
if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING):
if v & THREAD_FLAG_WAITING:
thread->wait ()
if !(thread->is_waiting ()):
thread->wait ()
else
thread->unwait ()
if thread->is_waiting ():
thread->unwait ()
if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING):
if v & THREAD_FLAG_RUNNING:
thread->run ()
else
thread->unrun ()
break
case CAP_THREAD_INFO_SLEEP:
value = &thread->sleep_count
if thread->flags & THREAD_FLAG_WAITING:
unsigned newval = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
if *value == ~0 && newval != ~0:
thread->sleep ()
else if *value != ~0 && newval == ~0:
thread->unsleep ()
break
default:
value = Thread_arch_info (thread, c->data[1])
break
@ -349,13 +414,7 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
break
case CAP_THREAD_SCHEDULE:
schedule ()
break
case CAP_THREAD_DEBUG:
dbg_led (true, true, true)
dbg_sleep (100)
dbg_led (false, false, false)
dbg_sleep (100)
//dbg_send (c->data[1], 5)
do_schedule = true
break
case CAP_THREAD_REGISTER_INTERRUPT:
// Threads with access to this call are trusted, so no sanity checking is done.
@ -371,18 +430,45 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV
reply_cap (CAPTYPE_THREAD | (c->data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data)
break
case CAP_THREAD_ALLOC_RANGE:
// Threads with access to this call are trusted, so not much sanity checking is done.
Memory *mem = (Memory *)c->cap[1]->protected_data
if !mem->use (c->data[1]):
reply_num (0)
break
unsigned data = phys_alloc (c->data[1])
if !data:
mem->unuse (c->data[1])
reply_num (0)
break
reply_num (data - 0x80000000)
break
case CAP_THREAD_ALLOC_PHYSICAL:
// Threads with access to this call are trusted, so no sanity checking is done.
Page *page = (Page *)c->cap[0]->protected_data
page->forget ()
if 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
if !(c->data[2] & 2):
if page->data.flags & PAGE_FLAG_PAYING:
page->data.flags &= ~PAGE_FLAG_PAYING
page->address_space->unuse ()
else:
page->data.flags |= PAGE_FLAG_FRAME | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED
// This is for mapping allocated ranges. They are already paid for. Record that.
if page->data.flags & PAGE_FLAG_PAYING:
page->address_space->unuse ()
else:
page->data.flags |= PAGE_FLAG_PAYING
page->data.frame = c->data[1]
page->data.flags |= PAGE_FLAG_FRAME
if !(c->data[2] & 1):
page->data.flags |= PAGE_FLAG_UNCACHED
if !(c->data[2] & 2):
page->data.flags |= PAGE_FLAG_PHYSICAL
Page_arch_update_mapping (page)
break
case CAP_THREAD_PHYSICAL_ADDRESS:
// Threads with access to this call are trusted, so no sanity checking is done.
Page *page = (Page *)c->cap[1]->protected_data
reply_num (page->data.frame & ~0xc0000000)
break
default:
break
@ -652,7 +738,7 @@ static void capability_invoke (unsigned target, unsigned protected_data, Capabil
default:
break
static bool kernel_invoke (unsigned target, unsigned protected_data, Capability::Context *c, Capability *self):
static void 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
@ -674,7 +760,7 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
// Kernel call: don't create actual capablities.
c->cap[0] = NULL
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0)
return true
return
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability.
Receiver *r = (Receiver *)protected_data
@ -686,16 +772,16 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
while self->sibling_next:
self->sibling_next->invalidate ()
self->invalidate ()
return true
return
if !((1 << c->data[0]) & target & REQUEST_MASK):
// You are not allowed to perform this operation.
dbg_send (1, 2)
dbg_send (c->data[0])
return true
return
reply = c->cap[0]
if c->data[0] == CAP_DEGRADE:
reply_cap (target & c->data[1], protected_data)
return true
return
switch target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER:
receiver_invoke (target, protected_data, c)
@ -717,12 +803,13 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
break
default:
panic (0x99337744, "invalid capability type invoked")
return true
return
bool Capability::invoke (Capability::Context *c):
void Capability::invoke (Capability::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, c)
target->send_message (protected_data, c)
return
// This is a kernel capability. Use a function to allow optimized call capabilities.
reply_receiver = NULL
return kernel_invoke ((unsigned)target, protected_data, c, this)
kernel_invoke ((unsigned)target, protected_data, c, this)

432
iris.h
View File

@ -52,8 +52,8 @@ extern "C" {
#define CAP_RECEIVER_SET_OWNER 1
#define CAP_RECEIVER_CREATE_CAPABILITY 2
#define CAP_RECEIVER_CREATE_CALL_CAPABILITY 3
#define CAP_RECEIVER_GET_REPLY_PROTECTED_DATA 4
#define CAP_RECEIVER_SET_REPLY_PROTECTED_DATA 5
#define CAP_RECEIVER_REPLY_PROTECTED_DATA 4
#define CAP_RECEIVER_ALARM 5
#define CAP_RECEIVER_ALL_RIGHTS 0x7f
/* Not an operation; a capability with this bit set is a call capability. */
#define CAP_RECEIVER_CALL 7
@ -73,19 +73,19 @@ extern "C" {
#define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */
#define CAP_THREAD_SCHEDULE 2
#define CAP_THREAD_DEBUG 3
#define CAP_THREAD_ALLOC_RANGE 3
#define CAP_THREAD_PHYSICAL_ADDRESS 4
#define CAP_THREAD_ALLOC_PHYSICAL 5
#define CAP_THREAD_MAKE_PRIV 6
#define CAP_THREAD_GET_TOP_MEMORY 7
#define CAP_THREAD_REGISTER_INTERRUPT 8
#define CAP_THREAD_ALL_RIGHTS 0x1f
#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV) | (1 << CAP_THREAD_ALLOC_PHYSICAL))
#define CAP_THREAD_ALL_RIGHTS 0x0f
#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV) | (1 << CAP_THREAD_ALLOC_PHYSICAL) | (1 << CAP_THREAD_PHYSICAL_ADDRESS))
/* These get/set_info are not arch-specific. */
#define CAP_THREAD_INFO_PC ~0
#define CAP_THREAD_INFO_SP ~1
#define CAP_THREAD_INFO_FLAGS ~2
#define CAP_THREAD_INFO_SLEEP ~3
/* Flag values for processor state */
#define THREAD_FLAG_PRIV 0x80000000
#define THREAD_FLAG_WAITING 0x40000000
@ -141,6 +141,11 @@ Capability cap_copy (Capability src)
return src | 2;
}
Capability cappage_cap (unsigned base, unsigned idx)
{
return base | (idx << 2) | 1;
}
typedef struct Message
{
unsigned data[4];
@ -148,11 +153,11 @@ typedef struct Message
unsigned protected_data; /* only used for receiving. */
} Message;
static int invoke (Capability target, Message *msg)
static void invoke (Capability target, Message *msg)
{
unsigned ret;
__asm__ volatile ("lw $v0, %1\n"
"\tlw $a3, %2\n"
__asm__ volatile ("lw $v0, %0\n"
"\tlw $a3, %1\n"
"\tlw $t0, 0($a3)\n"
"\tlw $t1, 4($a3)\n"
"\tlw $t2, 8($a3)\n"
@ -161,20 +166,45 @@ static int invoke (Capability target, Message *msg)
"\tlw $a1, 20($a3)\n"
"\tlw $a2, 24($a3)\n"
"\tlw $a3, 28($a3)\n"
"\tsyscall\n"
"\tmove %0, $v0"
: "=r"(ret)
"\tsyscall"
:
: "m"(target), "m"(msg)
: "v0", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
return ret;
}
static int wait (Message *msg)
static void wait (Message *msg)
{
int ret;
__asm__ volatile ("li $v0, 2\n"
"\tsyscall\n"
"\tsw $v0, %0\n"
"\tlw $v0, %0\n"
"\tsw $t0, 0($v0)\n"
"\tsw $t1, 4($v0)\n"
"\tsw $t2, 8($v0)\n"
"\tsw $t3, 12($v0)\n"
"\tsw $a0, 16($v0)\n"
"\tsw $a1, 20($v0)\n"
"\tsw $a2, 24($v0)\n"
"\tsw $a3, 28($v0)\n"
"\tsw $v1, 32($v0)"
:
: "m"(msg)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
}
static void call (Capability target, Message *msg)
{
Capability t = cap_copy (target);
__asm__ volatile ("lw $v0, %0\n"
"\tlw $v1, %1\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"
"\tlw $v0, %1\n"
"\tsw $t0, 0($v0)\n"
"\tsw $t1, 4($v0)\n"
@ -185,167 +215,274 @@ static int wait (Message *msg)
"\tsw $a2, 24($v0)\n"
"\tsw $a3, 28($v0)\n"
"\tsw $v1, 32($v0)"
: "=m"(ret)
: "m"(msg)
: "memory", "v0", "v1", "t0", "t1", "t2", "t3", "a0", "a1", "a2", "a3");
return ret;
}
static int call (Capability target, Message *msg)
{
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"
"\tsw $v0, %0\n"
"\tlw $v0, %2\n"
"\tsw $t0, 0($v0)\n"
"\tsw $t1, 4($v0)\n"
"\tsw $t2, 8($v0)\n"
"\tsw $t3, 12($v0)\n"
"\tsw $a0, 16($v0)\n"
"\tsw $a1, 20($v0)\n"
"\tsw $a2, 24($v0)\n"
"\tsw $a3, 28($v0)\n"
"\tsw $v1, 32($v0)"
: "=m"(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 void invoke_01 (Capability t, unsigned d)
{
Message msg;
int ret;
msg.data[0] = d;
return invoke (t, &msg);
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[0] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static int invoke_02 (Capability t, unsigned d0, unsigned d1)
static void invoke_02 (Capability t, unsigned d0, unsigned d1)
{
Message msg;
int ret;
msg.data[0] = d0;
msg.data[1] = d1;
return invoke (t, &msg);
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[0] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static int invoke_04 (Capability t, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
static void invoke_03 (Capability t, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = 0;
msg.cap[0] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static void invoke_04 (Capability t, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
{
Message msg;
int ret;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = d3;
return invoke (t, &msg);
msg.cap[0] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static int invoke_11 (Capability t, Capability c, unsigned d)
static void invoke_11 (Capability t, Capability c, unsigned d)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d;
return invoke (t, &msg);
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static int invoke_12 (Capability t, Capability c, unsigned d0, unsigned d1)
static void invoke_12 (Capability t, Capability c, unsigned d0, unsigned d1)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
return invoke (t, &msg);
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static void invoke_13 (Capability t, Capability c, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
invoke (t, &msg);
}
static Capability call_c01 (Capability c, unsigned d)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d;
ret = call (__my_call, &msg);
return ret ? msg.cap[0] : 0;
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
}
static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
ret = call (__my_call, &msg);
return ret ? msg.cap[0] : 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
}
static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d1)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d0;
msg.data[1] = d1;
ret = call (__my_call, &msg);
return ret ? msg.cap[0] : 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.cap[0];
}
static unsigned call_n01 (Capability c, unsigned d)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d;
ret = call (__my_call, &msg);
return ret ? msg.data[0] : 0;
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static unsigned call_n11 (Capability c, Capability c1, unsigned d)
{
Message msg;
msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d;
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static unsigned call_n12 (Capability c, Capability c1, unsigned d0, unsigned d1)
{
Message msg;
msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static unsigned call_n02 (Capability c, unsigned d0, unsigned d1)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
ret = call (__my_call, &msg);
return ret ? msg.data[0] : 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static unsigned call_n03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
ret = call (__my_call, &msg);
return ret ? msg.data[0] : 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static unsigned call_n13 (Capability c, Capability c1, unsigned d0, unsigned d1, unsigned d2)
{
Message msg;
msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static unsigned call_n04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = d3;
ret = call (__my_call, &msg);
return ret ? msg.data[0] : 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
return msg.data[0];
}
static Capability call_p02 (Capability c, unsigned d0, unsigned d1, unsigned *base_return)
{
Message msg;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
*base_return = msg.data[0];
return msg.cap[0];
}
static Capability degrade (Capability src, unsigned mask)
@ -353,11 +490,6 @@ static Capability degrade (Capability src, unsigned mask)
return call_c02 (src, CAP_DEGRADE, mask);
}
static void kdebug (unsigned code)
{
invoke_02 (__my_thread, CAP_THREAD_DEBUG, code);
}
static void schedule ()
{
invoke_01 (__my_thread, CAP_THREAD_SCHEDULE);
@ -368,24 +500,29 @@ static void register_interrupt (unsigned num)
invoke_12 (__my_thread, __my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num);
}
static Capability get_top_memory ()
{
return call_c01 (__my_thread, CAP_THREAD_GET_TOP_MEMORY);
}
static void unregister_interrupt (unsigned num)
{
invoke_02 (__my_thread, CAP_THREAD_REGISTER_INTERRUPT, num);
}
static void alloc_physical (Capability page, unsigned address, int cachable)
static Capability get_top_memory ()
{
invoke_12 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0));
return call_c01 (__my_thread, CAP_THREAD_GET_TOP_MEMORY);
}
static int receiver_set_owner (Capability receiver, Capability owner)
static void alloc_physical (Capability page, unsigned address, int cachable, int freeable)
{
return invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
invoke_13 (__my_thread, page, CAP_THREAD_ALLOC_PHYSICAL, address & PAGE_MASK, (cachable ? 1 : 0) | (freeable ? 2 : 0));
}
static unsigned alloc_range (Capability memory, unsigned pages)
{
return call_n12 (__my_thread, memory, CAP_THREAD_ALLOC_RANGE, pages);
}
static void receiver_set_owner (Capability receiver, Capability owner)
{
invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
}
static Capability receiver_create_capability (Capability receiver, unsigned protected_data)
@ -393,14 +530,45 @@ static Capability receiver_create_capability (Capability receiver, unsigned prot
return call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
}
static int receiver_get_reply_protected_data (Capability receiver, unsigned data)
static unsigned receiver_reply_protected_data (Capability receiver, int set, unsigned data)
{
return call_n01 (receiver, CAP_RECEIVER_GET_REPLY_PROTECTED_DATA);
return call_n03 (receiver, CAP_RECEIVER_REPLY_PROTECTED_DATA, (unsigned)set, data);
}
static int receiver_set_reply_protected_data (Capability receiver, unsigned data)
static unsigned receiver_get_reply_protected_data (Capability receiver)
{
return invoke_02 (receiver, CAP_RECEIVER_SET_REPLY_PROTECTED_DATA, data);
return receiver_reply_protected_data (receiver, 0, 0);
}
static unsigned receiver_set_reply_protected_data (Capability receiver, unsigned data)
{
return receiver_reply_protected_data (receiver, 1, data);
}
static unsigned receiver_alarm (Capability receiver, int set, unsigned data)
{
return call_n03 (receiver, CAP_RECEIVER_ALARM, (unsigned)set, data);
}
static unsigned receiver_get_alarm (Capability receiver)
{
return receiver_alarm (receiver, 0, 0);
}
static unsigned receiver_add_alarm (Capability receiver, unsigned data)
{
return receiver_alarm (receiver, 0, data);
}
static unsigned receiver_set_alarm (Capability receiver, unsigned data)
{
return receiver_alarm (receiver, 1, data);
}
static void my_sleep (unsigned value, Message *ret)
{
receiver_set_alarm (__my_receiver, value);
wait (ret);
}
static Capability receiver_create_call_capability (Capability receiver)
@ -438,37 +606,38 @@ static Capability memory_create_memory (Capability memory)
return memory_create (memory, CAPTYPE_MEMORY | REQUEST_MASK);
}
static Capability memory_create_cappage (Capability memory)
static Capability memory_create_cappage (Capability memory, unsigned *base_return)
{
return memory_create (memory, CAPTYPE_CAPPAGE | REQUEST_MASK);
return call_p02 (memory, CAP_MEMORY_CREATE, CAPTYPE_CAPPAGE | REQUEST_MASK, base_return);
}
static int memory_destroy (Capability memory, Capability target)
static void memory_destroy (Capability memory, Capability target)
{
return invoke_11 (memory, target, CAP_MEMORY_DESTROY);
invoke_11 (memory, target, CAP_MEMORY_DESTROY);
}
/* TODO: #define CAP_MEMORY_LIST 3 */
static int memory_map (Capability memory, Capability page, unsigned address, int writable)
static void 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);
invoke_12 (memory, page, CAP_MEMORY_MAP, address);
}
static Capability memory_mapping (Capability memory, unsigned address)
static Capability memory_mapping (Capability memory, void *address)
{
return call_c02 (memory, CAP_MEMORY_MAPPING, address);
return call_c02 (memory, CAP_MEMORY_MAPPING, (unsigned)address);
}
static unsigned memory_limit (Capability memory, unsigned limit)
{
return call_c02 (memory, CAP_MEMORY_MAPPING, address);
return call_c02 (memory, CAP_MEMORY_LIMIT, limit);
}
static void drop (Capability cap)
{
return;
invoke_11 (__my_memory, cap, CAP_MEMORY_DROP);
}
@ -507,29 +676,6 @@ static unsigned thread_wait (Capability thread, int wait)
return thread_flags (thread, wait ? THREAD_FLAG_WAITING : 0, THREAD_FLAG_WAITING);
}
static unsigned thread_sleep (Capability thread, unsigned value)
{
return thread_info (thread, CAP_THREAD_INFO_SLEEP, value, ~0);
}
static int my_sleep (unsigned value, Message *ret)
{
ret->data[0] = CAP_THREAD_INFO;
ret->data[1] = CAP_THREAD_INFO_SLEEP;
ret->data[2] = value;
ret->data[3] = ~0;
ret->cap[0] = 0;
ret->cap[1] = 0;
ret->cap[2] = 0;
ret->cap[3] = 0;
return call (__my_thread, ret);
}
static unsigned thread_get_sleep (Capability thread)
{
return thread_info (thread, CAP_THREAD_INFO_SLEEP, 0, 0);
}
static unsigned thread_get_pc (Capability thread)
{
return thread_info (thread, CAP_THREAD_INFO_PC, 0, 0);
@ -540,9 +686,9 @@ static unsigned thread_get_sp (Capability thread)
return thread_info (thread, CAP_THREAD_INFO_SP, 0, 0);
}
static int page_share (Capability page, Capability target, unsigned flags)
static void page_share (Capability page, Capability target, unsigned flags)
{
return invoke_12 (page, target, CAP_PAGE_SHARE, flags);
invoke_12 (page, target, CAP_PAGE_SHARE, flags);
}
static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask)
@ -550,16 +696,24 @@ static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask)
return call_n03 (page, CAP_PAGE_FLAGS, new_flags, mask);
}
static unsigned page_physical_address (Capability page)
{
return call_n11 (__my_thread, page, CAP_THREAD_PHYSICAL_ADDRESS);
}
static Capability capability_get (Capability cap)
{
return call_c01 (cap, CAP_CAPABILITY_GET);
}
static int cappage_set (Capability page, Capability cap, unsigned index)
static void cappage_set (Capability page, Capability cap, unsigned index)
{
return invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
}
/* Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. */
#define kdebug(d0, d1) do { unsigned data0 = (unsigned)(d0); unsigned data1 = (unsigned)(d1); __asm__ volatile ("lw $a0, %0\n" "\tlw $a1, %1\n" "\tbreak" :: "m" (data0), "m" (data1)); } while (0)
#endif
#ifdef __cplusplus

View File

@ -68,10 +68,7 @@ struct Thread : public Object <Thread>:
unsigned pc, sp
Thread_arch arch
unsigned flags
unsigned sleep_count
Thread *schedule_prev, *schedule_next
void sleep ()
void unsleep ()
void run ()
void unrun ()
void wait ()
@ -94,14 +91,17 @@ struct Capability : public Object <Capability>:
Capability *children
Capability *sibling_prev, *sibling_next
unsigned protected_data
bool invoke (Context *c)
void invoke (Context *c)
void invalidate ()
struct Receiver : public Object <Receiver>:
Thread *owner
Receiver *prev_owned, *next_owned
Receiver *prev_alarm, *next_alarm
unsigned alarm_count
Capability *capabilities
Message *messages
Message *last_message
unsigned reply_protected_data
bool protected_only
void own (Thread *o)
@ -122,6 +122,8 @@ struct Page : public Object <Page>:
struct Cappage : public Object <Cappage>:
ShareData data
Capability *cap (unsigned idx):
return &((Capability *)data.frame)[idx]
void forget ()
struct Memory : public Object <Memory>:
@ -140,8 +142,8 @@ struct Memory : public Object <Memory>:
inline Page *get_mapping (unsigned address, bool *writable)
// Allocation of pages.
bool use ()
void unuse ()
bool use (unsigned num = 1)
void unuse (unsigned num = 1)
unsigned palloc ()
unsigned zalloc ()
void pfree (unsigned page)
@ -151,7 +153,7 @@ struct Memory : public Object <Memory>:
void *search_free (unsigned size, void **first)
Page *alloc_page ()
Thread *alloc_thread ()
Message *alloc_message (Receiver *target, unsigned protected_data)
Message *alloc_message (Receiver *target)
Receiver *alloc_receiver ()
Capability *alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret = NULL)
Capability *clone_capability (Capability *source, bool copy, Capability *ret = NULL)
@ -160,7 +162,7 @@ struct Memory : public Object <Memory>:
void free_page (Page *page)
void free_thread (Thread *thread)
void free_message (Message *message)
void free_message (Receiver *owner, Message *message)
void free_receiver (Receiver *receiver)
void free_capability (Capability *capability)
void free_cappage (Cappage *page)
@ -178,26 +180,27 @@ extern "C":
void dbg_led (bool one, bool two, bool three)
void dbg_sleep (unsigned ms)
void dbg_send (unsigned code, unsigned bits = 32)
EXTERN unsigned dbg_code
/// Defined in schedule.ccp
void schedule ()
void timer_interrupt ()
struct FreePage:
FreePage *next
EXTERN Memory top_memory
EXTERN Thread *sleepers, *runners
EXTERN Receiver *first_alarm
EXTERN Thread idle
EXTERN Memory idle_memory
EXTERN Page idle_page
EXTERN Thread *first_scheduled, *first_sleeper
EXTERN Thread *first_scheduled
EXTERN Thread *current
EXTERN bool do_schedule
// Defined in memory.cc
unsigned init_memory (unsigned mem)
unsigned raw_zalloc ()
void raw_pfree (unsigned page)
unsigned phys_alloc (unsigned num)
void phys_free (unsigned page, unsigned num)
// Defined by architecture-specific files.
void Thread_arch_init (Thread *thread)
@ -219,4 +222,6 @@ void Memory::unmap (Page *page, unsigned address):
Page *Memory::get_mapping (unsigned address, bool *writable):
return Memory_arch_get_mapping (this, address, writable)
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)
#endif

View File

@ -1,53 +1,135 @@
#pypp 0
#include "kernel.hh"
static FreePage *zero_pages, *junk_pages
extern unsigned _end
static void clear_page (unsigned page):
for unsigned i = 0; i < PAGE_SIZE >> 2; ++i:
((unsigned *)page)[i] = 0
static unsigned free_begin
static unsigned free_end
unsigned init_memory (unsigned mem):
zero_pages = NULL
// Fill junk pages with all memory not currently used.
junk_pages = (FreePage *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
FreePage *p, *next
unsigned count = 1
for p = junk_pages, next = p; (unsigned)next - 0x80000000 < mem; p = next, next = (FreePage *)((unsigned)p + PAGE_SIZE):
p->next = next
++count
p->next = NULL
return count
free_begin = ((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK
free_end = (0x80000000 + mem) & PAGE_MASK
return (free_end - free_begin) >> PAGE_BITS
unsigned phys_alloc (unsigned num):
if free_begin + num * PAGE_SIZE > free_end:
panic (0xaaaaaaaa, "out of memory")
unsigned ret = free_begin
free_begin += num * PAGE_SIZE
for unsigned i = 0; i < num; ++i:
clear_page (ret + i * PAGE_SIZE)
return ret
void phys_free (unsigned page, unsigned num):
// Not supported.
#if 0
struct FreePages:
FreePages *prev, *next
unsigned num
static FreePages *first_free
unsigned init_memory (unsigned mem):
first_free = (FreePages *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
first_free->prev = NULL
first_free->next = NULL
first_free->num = ((mem & PAGE_MASK) - ((unsigned)first_free - 0x80000000)) >> PAGE_BITS
return first_free->num
unsigned phys_alloc (unsigned num):
FreePages *choice = NULL
for FreePages *p = first_free; p; p = p->next:
if p->num < num:
continue
if choice && choice->num < p->num:
continue
choice = p
if !choice:
// TODO: reorganizing may work to allow allocation.
panic (0x01100223, "out of large enough memory")
return 0
if choice->num == num:
if choice->prev:
choice->prev->next = choice->next
else:
first_free = choice->next
if choice->next:
choice->next->prev = choice->prev
clear_page ((unsigned)choice, num)
return (unsigned)choice
choice->num -= num
unsigned ret = (unsigned)choice + (choice->num << PAGE_BITS)
clear_page (ret, num)
return ret
void phys_free (unsigned page, unsigned num):
return
unsigned size = num << PAGE_BITS
if !first_free || (unsigned)first_free > page:
// This is the first free block.
FreePages *n = (FreePages *)page
n->prev = NULL
if (unsigned)first_free == page + size:
// It fits exactly before the previous first free block.
n->next = first_free->next
n->num = num + first_free->num
else:
// It is a new block.
n->next = first_free
n->num = num
first_free = n
if n->next:
n->next->prev = n
return
FreePages *p
for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
// Do nothing.
// The new block should be inserted directly after p.
if (unsigned)p->next == page + size:
// It can be merged with the block after it: do that.
FreePages *n = (FreePages *)page
n->prev = p
n->next = p->next->next
if n->next:
n->next->prev = n
n->num = num + p->next->num
p->next = n
if (unsigned)p + (p->num << PAGE_BITS) == (unsigned)n:
// It can also be merged with the page before it: do that as well.
p->num += n->num
p->next = n->next
if p->next:
p->next->prev = p
return
// The new block cannot be merged with the block after it.
if (unsigned)p + (p->num << PAGE_BITS) == page:
// But it can be merged with the one before it: do that.
p->num += num
return
// The new block cannot be merged at all.
FreePages *n = (FreePages *)page
n->next = p->next
n->prev = p
if n->next:
n->next->prev = n
p->next = n
n->num = num
#endif
unsigned raw_zalloc ():
FreePage *ret = zero_pages
if !ret:
ret = junk_pages
junk_pages = ret->next
for unsigned i = 0; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
else:
zero_pages = ret->next
ret->next = NULL
return (unsigned)ret
return phys_alloc (1)
void raw_pfree (unsigned page):
if !page:
return
FreePage *p = (FreePage *)page
p->next = junk_pages
junk_pages = p
return phys_free (page, 1)
unsigned Memory::palloc ():
if !use ():
return NULL
FreePage *ret = junk_pages
if !ret:
ret = zero_pages
zero_pages = ret->next
else:
junk_pages = ret->next
return (unsigned)ret
unsigned Memory::zalloc ():
if !use ():
assert (false)
return NULL
return raw_zalloc ()
@ -55,9 +137,8 @@ void Memory::pfree (unsigned page):
unuse ()
return raw_pfree (page)
void Memory::zfree (unsigned page):
unuse ()
FreePage *p = (FreePage *)page
p->next = zero_pages
zero_pages = p
unsigned Memory::palloc ():
return zalloc ()
void Memory::zfree (unsigned page):
pfree (page)

View File

@ -27,7 +27,7 @@ OBJCOPYFLAGS = $(addprefix --remove-section=.,$(junk))
arch_kernel_sources = mips/interrupts.cc mips/test.cc mips/arch.cc
boot_sources = mips/init.cc
BUILT_SOURCES = $(kernel_sources) $(boot_sources)
arch_headers = mips/arch.hh
arch_headers = mips/arch.hh mips/jz4730.hh
boot_threads = keyboard lcd
uimage:
@ -35,11 +35,11 @@ uimage:
mips/entry.o: $(boot_threads)
mips/init.o: TARGET_FLAGS = -I/usr/include
$(boot_threads): TARGET_FLAGS = -I.
$(boot_threads): mips/jz4730.hh boot-programs/devices.hh
$(boot_threads): boot-programs/devices.hh
# Transform ':' into ';' so vim doesn't think there are errors.
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 0xa$(shell /bin/sh -c '$(OBJDUMP) -t kernel | grep __start$$ | cut -b2-8') -n "Iris" -d $< $@ | sed -e 's/:/;/g'
%.o:%.S Makefile mips/Makefile.arch mips/arch.hh
$(CC) $(CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@
@ -49,7 +49,7 @@ kernel: mips/entry.o $(subst .cc,.o,$(kernel_sources)) mips/boot.o $(subst .cc,.
$(LD) --omagic -Ttext $(load) $^ -o $@
%.raw: %
$(OBJCOPY) -S $(addprefix --remove-section=.,$(junk)) -Obinary $< $@
$(OBJCOPY) -S $(OBJCOPYFLAGS) -Obinary $< $@
%.gz: %
gzip < $< > $@

View File

@ -318,3 +318,4 @@ void arch_register_interrupt (unsigned num, Receiver *r):
intc_unmask_irq (num)
else:
intc_mask_irq (num)
dbg_code = 0

View File

@ -25,13 +25,15 @@
#define Status 12
#define Config 16
// Note that this code starts at 0xa0000000, even though it is linked for
// 0x80000000. This means that until the jump below, it must be PIC.
__start:
bal 1f
nop
.word _gp
// For some reason the disassembler considers everything
// after __start non-code until the next label. So I add a label.
start_hack_for_disassembler:
nop
.word _gp
1: lw $gp, 0($ra)
la $sp, kernel_stack + KERNEL_STACK_SIZE

View File

@ -110,10 +110,11 @@ static unsigned mkcap (Memory *mem, unsigned type, void *obj):
static void init_threads ():
Thread *previous = NULL
first_scheduled = NULL
first_sleeper = NULL
first_alarm = NULL
Receiver *init_receiver = NULL
for unsigned i = 0; i < NUM_THREADS; ++i:
Memory *mem = top_memory.alloc_memory ()
assert (mem)
Thread *thread = mem->alloc_thread ()
Page **pages = (Page **)mem->zalloc ()
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
@ -134,36 +135,42 @@ static void init_threads ():
thread->sp = 0x80000000
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
if !(shdr->sh_flags & SHF_ALLOC):
if ~shdr->sh_flags & SHF_ALLOC:
continue
bool writable = shdr->sh_flags & SHF_WRITE
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS:
for unsigned p = (shdr->sh_addr & PAGE_MASK); p <= ((shdr->sh_addr + shdr->sh_size - 1) & PAGE_MASK); p += PAGE_SIZE:
unsigned idx = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
if !pages[idx]:
pages[idx] = mem->alloc_page ()
pages[idx]->data.frame = thread_start[i] + (idx << PAGE_BITS)
pages[idx]->data.flags = (writable ? PAGE_FLAG_WRITABLE : 0) | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
pages[idx]->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
++top_memory.limit
mem->use ()
if !mem->map (pages[idx], p, writable):
panic (0x22446688, "unable to map initial page")
else:
for unsigned p = (shdr->sh_addr & PAGE_MASK); p <= ((shdr->sh_addr + shdr->sh_size - 1) & PAGE_MASK); p += PAGE_SIZE:
bool write = false
Page *page = mem->get_mapping (p, &write)
if !writable:
panic (0x33399993, "unwritable bss section")
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Page *page = mem->get_mapping (p, &writable)
if !page:
page = mem->alloc_page ()
if !page:
panic (0x00220022, "out of memory")
page->data.frame = mem->zalloc ()
page->data.flags = (writable ? PAGE_FLAG_WRITABLE : 0) | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
if !page->data.frame || !mem->map (page, p, true):
if !page->data.frame:
panic (0x02220022, "out of memory");
page->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
if !mem->map (page, p, true):
panic (0x33557799, "unable to map initial bss page")
else:
if !write:
if !writable:
panic (0x20203030, "bss section starts on read-only page")
for unsigned a = p; a < p + PAGE_SIZE; a += 4:
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
@ -201,11 +208,10 @@ static void init_threads ():
// Initialize the kernel, finish by falling into the idle task.
void init (unsigned mem):
dbg_code = 0
// Disable interrupts and set interrupt vectors to normal.
cp0_set0 (CP0_STATUS)
// Initialize kernel variables to empty.
sleepers = NULL
runners = NULL
unsigned count = init_memory (mem)
// initialize system control coprocessor.
init_cp0 ()

View File

@ -20,7 +20,7 @@
#include "../kernel.hh"
static void handle_exit (Thread *old_current):
if !current:
if !current || (current == &idle):
schedule ()
if !current:
current = &idle
@ -77,7 +77,6 @@ Thread *tlb_refill ():
Thread *interrupt ():
//panic (0x88877722, "Interrupt")
Thread *old_current = current
//dbg_send (INTC_IPR)
unsigned ipr = INTC_IPR
for unsigned i = 0; i < 32; ++i:
if ipr & (1 << i):
@ -94,6 +93,7 @@ Thread *interrupt ():
c.data[j] = 0
c.cap[j] = NULL
c.copy[j] = false
dbg_code = (unsigned)arch_interrupt_receiver[i]->owner
arch_interrupt_receiver[i]->send_message (i, &c)
if ipr & (1 << IRQ_OST0):
ost_clear_uf (0)
@ -118,15 +118,12 @@ static void arch_invoke ():
bool wait
Thread *caller = current
target = caller->address_space->find_capability (caller->arch.v0, &wait)
do_schedule = false
if wait:
caller->wait ()
if !target:
// There must be no action here.
//dbg_send (3, 2)
//dbg_send (caller->arch.v0)
// Calling an invalid capability always fails.
caller->arch.v0 = 0
else:
if wait:
caller->wait ()
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])
@ -136,8 +133,9 @@ static void arch_invoke ():
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 caller != current && caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
target->invoke (&c)
// If the caller received a reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
if caller != current && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING && !do_schedule:
current = caller
/// A general exception has occurred.
@ -160,15 +158,21 @@ Thread *exception ():
panic (0x31223344, "TLB load or instruction fetch.")
case 3:
// TLB store.
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a)
panic (0x41223344, "TLB store.")
case 4:
// Address error load or instruction fetch.
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a)
panic (0x51223344, "Address error load or instruction fetch.")
case 5:
// Address error store.
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a, 16)
cp0_get (CP0_BAD_V_ADDR, a)
dbg_send (a, 32)
panic (0x61223344, "Address error store.")
case 6:
// Bus error instruction fetch.
@ -183,7 +187,10 @@ Thread *exception ():
break
case 9:
// Breakpoint.
panic (0x91223344, "Breakpoint.")
//panic (0x91223344, "Breakpoint.")
dbg_send (current->arch.a0, current->arch.a1)
current->pc += 4
break
case 10:
// Reserved instruction.
panic (0xa1223344, "Reserved instruction.")

View File

@ -23,7 +23,6 @@
// Main clock, for cpu, serial port, and with divisors for most other hardware
#define JZ_EXTAL 3686400
//#define JZ_EXTAL 3072000
// RTC clock
#define RTC_CLOCK 32768
@ -36,7 +35,7 @@
#define LCD_PHYSICAL 0x13050000
#define CIM_PHYSICAL 0x13060000
#define ETH_PHYSICAL 0x13100000
#define NBM_PHYSICAL 0x13F00000
#define NBM_PHYSICAL 0x13f00000
#define CPM_PHYSICAL 0x10000000
#define INTC_PHYSICAL 0x10001000
#define OST_PHYSICAL 0x10002000
@ -98,49 +97,53 @@
#else
// In user space, they just need a mapping.
#define HARB_BASE 0x00000000
#define EMC_BASE 0x00001000
#define DMAC_BASE 0x00002000
#define UHC_BASE 0x00003000
#define UDC_BASE 0x00004000
#define LCD_BASE 0x00005000
#define CIM_BASE 0x00006000
#define ETH_BASE 0x00007000
#define NBM_BASE 0x00008000
#define CPM_BASE 0x00009000
#define INTC_BASE 0x0000a000
#define OST_BASE 0x0000b000
#define RTC_BASE 0x0000c000
#define WDT_BASE 0x0000d000
#define GPIO_BASE 0x0000e000
#define AIC_BASE 0x0000f000
#define MSC_BASE 0x00010000
#define UART0_BASE 0x00011000
#define UART1_BASE 0x00012000
#define UART2_BASE 0x00013000
#define UART3_BASE 0x00014000
#define FIR_BASE 0x00015000
#define SCC_BASE 0x00016000
#define SCC0_BASE 0x00017000
#define I2C_BASE 0x00018000
#define SSI_BASE 0x00019000
#define SCC1_BASE 0x0001a000
#define PWM0_BASE 0x0001b000
#define PWM1_BASE 0x0001c000
#define DES_BASE 0x0001d000
#define UPRT_BASE 0x0001e000
#define KBC_BASE 0x0001f000
#define UNMAPPED_BASE 0x00000000
#define HARB_BASE 0x00001000
#define EMC_BASE 0x00002000
#define DMAC_BASE 0x00003000
#define UHC_BASE 0x00004000
#define UDC_BASE 0x00005000
#define LCD_BASE 0x00006000
#define CIM_BASE 0x00007000
#define ETH_BASE 0x00008000
#define NBM_BASE 0x00009000
#define CPM_BASE 0x0000a000
#define INTC_BASE 0x0000b000
#define OST_BASE 0x0000c000
#define RTC_BASE 0x0000d000
#define WDT_BASE 0x0000e000
#define GPIO_BASE 0x0000f000
#define AIC_BASE 0x00010000
#define MSC_BASE 0x00011000
#define UART0_BASE 0x00012000
#define UART1_BASE 0x00013000
#define UART2_BASE 0x00014000
#define UART3_BASE 0x00015000
#define FIR_BASE 0x00016000
#define SCC_BASE 0x00017000
#define SCC0_BASE 0x00018000
#define I2C_BASE 0x00019000
#define SSI_BASE 0x0001a000
#define SCC1_BASE 0x0001b000
#define PWM0_BASE 0x0001c000
#define PWM1_BASE 0x0001d000
#define DES_BASE 0x0001e000
#define UPRT_BASE 0x0001f000
#define KBC_BASE 0x00020000
// Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
// Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h>
static void __map_io (unsigned physical, unsigned mapping):
Capability page = memory_create_page (__my_memory)
// 0 means not cachable.
alloc_physical (page, physical, 0)
// 0 means not cachable; 0 means don't free when done.
alloc_physical (page, physical, 0, 0)
// 1 means writable.
memory_map (__my_memory, page, mapping, 1)
//drop (page)
#endif
drop (page)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
@ -175,6 +178,8 @@ static void __map_io (unsigned physical, unsigned mapping):
#define map_uprt() do { __map_io (UPRT_PHYSICAL, UPRT_BASE); } while (0)
#define map_kbc() do { __map_io (KBC_PHYSICAL, KBC_BASE); } while (0)
#endif
#define REG8(x) (*(volatile unsigned char *)(x))
#define REG16(x) (*(volatile unsigned short *)(x))
#define REG32(x) (*(volatile unsigned *)(x))

View File

@ -97,6 +97,8 @@ void dbg_sleep (unsigned ms):
__gpio_as_output (CAPSLOCKLED_IO)
void dbg_send (unsigned code, unsigned bits):
if bits > 32:
bits = 32
for int i = bits - 1; i >= 0; --i:
bool on = code & (1 << i)
dbg_led (false, false, false)

View File

@ -34,28 +34,11 @@ static void unrun_thread (Thread *thread):
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev
void Thread::sleep ():
schedule_next = first_sleeper
if schedule_next:
schedule_next->schedule_prev = this
schedule_prev = NULL
first_sleeper = this
void Thread::unsleep ():
if schedule_next:
schedule_next->schedule_prev = schedule_prev
if schedule_prev:
schedule_prev->schedule_next = schedule_next
else:
first_sleeper = schedule_next
void Thread::run ():
if flags & THREAD_FLAG_RUNNING:
return
flags |= THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING:
if sleep_count != ~0:
sleep ()
if is_waiting ():
return
run_thread (this)
@ -63,48 +46,41 @@ void Thread::unrun ():
if !(flags & THREAD_FLAG_RUNNING):
return
flags &= ~THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING:
if sleep_count != ~0:
unsleep ()
if is_waiting ():
return
unrun_thread (this)
void Thread::unwait ():
if !(flags & THREAD_FLAG_WAITING):
return
flags &= ~THREAD_FLAG_WAITING
if sleep_count != ~0:
unsleep ()
if flags & THREAD_FLAG_RUNNING:
run_thread (this)
static void sleep_tick (Thread *thread):
if !thread->sleep_count:
thread->unwait ()
// Time-out: let the thread know with a special message.
static void alarm_tick (Receiver *recv):
if !recv->alarm_count:
// Send message and stop counting.
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.data[i] = 0
c.cap[i] = NULL
c.copy[i] = false
Thread_arch_receive (thread, ~0, &c)
// Fall through to let sleep be set to ~0, so the next wait will be infinitely long again.
--thread->sleep_count
recv->send_message (~0, &c)
if recv->prev_alarm:
recv->prev_alarm->next_alarm = recv->next_alarm
else:
first_alarm = recv->next_alarm
if recv->next_alarm:
recv->next_alarm->prev_alarm = recv->prev_alarm
// Fall through to let alarm be set to ~0, so the next wait will be infinitely long again.
--recv->alarm_count
void Thread::wait ():
if flags & THREAD_FLAG_WAITING:
return
if flags & THREAD_FLAG_RUNNING:
unrun_thread (this)
flags |= THREAD_FLAG_WAITING
if sleep_count != ~0:
sleep ()
// Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned:
if r->try_deliver ():
return
if sleep_count != ~0:
sleep_tick (this)
void schedule ():
Thread *old = current
@ -117,10 +93,10 @@ void schedule ():
void timer_interrupt ():
//panic (0x88877744, "Timer interrupt")
Thread *thread, *next
for thread = first_sleeper; thread; thread = next:
next = thread->next
sleep_tick (thread)
Receiver *recv, *next
for recv = first_alarm; recv; recv = next:
next = recv->next
alarm_tick (recv)
schedule ()
//#ifndef NDEBUG
//static bool ledstate = false