1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-06-30 22:36:23 +03:00

things are working

This commit is contained in:
Bas Wijnen 2009-07-25 00:54:12 +02:00
parent b7d9b1554c
commit df38266bb8
13 changed files with 393 additions and 220 deletions

137
alloc.ccp
View File

@ -18,6 +18,13 @@
#include "kernel.hh"
// Memory model used for kernel structure storage
// Each Memory object has several pointers, one for each type of objects it contains. These pointers are the start of double-linked lists.
// Each object also has a NEXT and PREV pointer, which point to the next and previous object in the same page. These pointers are 0 for the first (or last) object in a page. There is no pointer to the first object, it always starts at page_base + SIZE.
// The PREV/NEXT-list contains all objects in the page, including Free objects, in the order they appear in the page.
// The prev/next-lists contain only objects of one type, unsorted.
// All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV.
#define PREV(x) (((Object_base **)(x))[-2])
#define NEXT(x) (((Object_base **)(x))[-1])
#define SIZE (2 * sizeof (Object_base *))
@ -37,75 +44,116 @@ void Memory::unuse (unsigned num):
for Memory *m = this; m; m = m->address_space:
m->used -= num
// This allocates a new block of memory for use by the kernel.
// size is the requires size of the block (excluding SIZE)
// first is a pointer to the first object pointer of this type.
// The result is a block of size at least size, which is linked as an object in the list of first.
void *Memory::search_free (unsigned size, void **first):
Free *f
unsigned s = 0
// Let's see if there already is a Free chunk which is large enough.
for f = frees; f; f = f->next:
if NEXT (f):
s = (unsigned)NEXT (f) - (unsigned)f
else:
s = PAGE_SIZE - ((unsigned)f & ~PAGE_MASK) + SIZE
// s is now the size of the current free block, including SIZE.
// The requirement is to fit a block of size, plus its SIZE header.
if s >= size + SIZE:
break
if !f:
// No chunk was found; allocate a new page and add a chunk in it. It is always large enough.
unsigned p = palloc ()
if !p:
assert (false)
dbg_log ("no free space: kernel allocation failed")
return NULL
f = (Free *)(p + SIZE)
// Mark it as a Free object.
f->marker = ~0
// Link it in the Free list.
f->next = frees
f->prev = NULL
frees = f
if f->next:
f->next->prev = f
// There are no other objects in this page.
NEXT (f) = NULL
PREV (f) = NULL
// The size of this block is the entire page.
s = PAGE_SIZE
// We have a free block, possibly too large.
// We have a free block, possibly too large. The block is linked in frees, and in the page.
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)
// f is the start of the free block
// f + (s - SIZE) is the end of the free block, compensated for the header of the next block.
// f + (s - SIZE) - size is the address where the new block should start.
Free *obj = (Free *)((unsigned)f + (s - SIZE) - size)
// Link the new object in the page.
NEXT (obj) = NEXT (f)
if NEXT (obj):
PREV (NEXT (obj)) = obj
PREV (obj) = f
NEXT (f) = obj
// Set f to the new object, because it is used by that name later.
f = obj
else:
// The block was only just large enough: turn it into a new type. It is already linked into the page.
// Unlink it from the free list.
if f->prev:
f->prev->next = f->next
else:
frees = f->next
if f->next:
f->next->prev = f->prev
f->address_space = this
f->refs = NULL
// f is now a block which is linked in the page, but not in any list. Link it into first.
f->next = (Free *)*first
f->prev = NULL
if f->next:
f->next->prev = f
*first = f
// Set common initial values.
f->address_space = this
f->refs = NULL
return f
void Memory::free_obj (Object_base *obj):
Free *self
// Merge with previous, if it exists and is a Free.
if PREV (obj) && PREV (obj)->is_free ():
self = (Free *)PREV (obj)
NEXT (self) = NEXT (obj)
if NEXT (obj):
PREV (NEXT (obj)) = self
// Free an object; it is still in its list, and it is still in the page list.
void Memory::free_obj (Object_base *obj, void **first):
Free *self = (Free *)obj
// Free it from its list.
if self->prev:
self->prev->next = self->next
else:
self = (Free *)obj
*(Object_base **)first = self->next
if self->next:
self->next->prev = self->prev
// Merge with previous, if it exists and is a Free.
if PREV (self) && PREV (self)->is_free ():
self = (Free *)PREV (self)
// Remove the object from the page list.
NEXT (self) = NEXT (obj)
if NEXT (self):
PREV (NEXT (self)) = self
else:
// The previous object is not a Free, so create a new one.
// It is already linked in the page, but needs to be linked into the free list.
self->next = frees
self->prev = NULL
if self->next:
self->next->prev = self
frees = self
// Mark it as a Free.
self->marker = ~0
// Merge with next, if it exists and is a Free.
if NEXT (self) && NEXT (self)->is_free ():
// Unlink the next from the frees list.
Free *n = (Free *)NEXT (self)
if n->prev:
n->prev->next = n->next
else:
frees = n->next
if n->next:
n->next->prev = n->prev
// Unlink the next from the page list.
NEXT (self) = NEXT (NEXT (self))
if NEXT (self):
PREV (NEXT (self)) = self
@ -139,6 +187,7 @@ Thread *Memory::alloc_thread ():
ret->schedule_prev = NULL
ret->schedule_next = NULL
ret->receivers = NULL
top_memory.alloc_capability (NULL, NULL, NULL, 0, &ret->exception)
return ret
Message *Memory::alloc_message (Receiver *target):
@ -222,48 +271,26 @@ Memory *Memory::alloc_memory ():
return ret
void Memory::free_page (Page *page):
if page->prev:
page->prev->next = page->next
else:
pages = page->next
if page->next:
page->next->prev = page->prev
unuse ()
if page->data.flags & PAGE_FLAG_PAYING:
unuse ()
if page->data.frame:
pfree (page->data.frame)
free_obj (page)
free_obj (page, (void **)&pages)
void Memory::free_thread (Thread *thread):
if thread->prev:
thread->prev->next = thread->next
else:
threads = thread->next
if thread->next:
thread->next->prev = thread->prev
// Unschedule.
if thread->schedule_prev:
thread->schedule_prev->schedule_next = thread->schedule_next
else if first_scheduled == thread:
first_scheduled = thread->schedule_next
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev
thread->unrun ()
while thread->receivers:
thread->receivers->orphan ()
free_obj (thread)
thread->exception.invalidate ()
free_obj (thread, (void **)&threads)
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:
if !message->next:
owner->last_message = message->prev
for unsigned i = 0; i < 4; ++i:
if message->capabilities[i]:
free_capability (message->capabilities[i])
free_obj (message)
free_obj (message, (void **)&owner->messages)
void Memory::free_receiver (Receiver *receiver):
receiver->orphan ()
@ -271,7 +298,7 @@ void Memory::free_receiver (Receiver *receiver):
receiver->capabilities->invalidate ()
while receiver->messages:
free_message (receiver, receiver->messages)
free_obj (receiver)
free_obj (receiver, (void **)&receivers)
void Receiver::orphan ():
if prev_owned:
@ -293,7 +320,7 @@ void Receiver::own (Thread *o):
void Memory::free_capability (Capability *capability):
capability->invalidate ()
free_obj (capability)
free_obj (capability, (void **)&capabilities)
void Capability::invalidate ():
if !target:
@ -328,23 +355,25 @@ void Memory::free_cappage (Cappage *p):
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
((Capability *)p->data.frame)[i].invalidate ()
zfree (p->data.frame)
free_obj (p)
free_obj (p, (void **)&cappages)
void Memory::free_memory (Memory *mem):
if mem->prev:
mem->prev->next = mem->next
else:
memories = mem->next
if mem->next:
mem->next->prev = mem->prev
while mem->pages:
free_page (mem->pages)
while mem->cappages:
free_cappage (mem->cappages)
while mem->threads:
free_thread (mem->threads)
while mem->memories:
free_memory (mem->memories)
while mem->receivers:
free_receiver (mem->receivers)
while mem->capabilities:
free_capability (mem->capabilities)
Memory_arch_free (mem)
free_obj (mem)
if mem->frees:
panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories)
void Page::forget ():
if data.share_prev || data.share_next:

View File

@ -20,6 +20,9 @@
#define ARCH
#include "arch.hh"
// Interval between polls for keyboard (when keys are pressed) and battery/power (always) events
#define ALARM_INTERVAL (HZ / 10)
// GPIO pins for the devices (port.pin)
// keyboard
@ -111,14 +114,15 @@ class Keyboard:
for unsigned i = 0; i < NUM_COLS; ++i:
keys[i] = 0xff
scan ()
void scan ():
// Set all columns to 0 when the become output.
// Set all columns to 0 when they become output.
GPIO_GPDR (3) &= ~COL_MASK
bool key_pressed = false
scanning = false
int const cols[NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
for unsigned col = 0; col < NUM_COLS; ++col:
GPIO_GPDIR (3) = (GPIO_GPDIR (3) & ~COL_MASK) | (1 << cols[col])
udelay (100)
//udelay (100)
unsigned data = GPIO_GPDR (0) & ROW_MASK
// Generate events.
for unsigned row = 0; row < 8; ++row:
@ -129,45 +133,46 @@ class Keyboard:
event (KEYBOARD_EVENT, code)
keys[col] = data
if data != ROW_MASK:
key_pressed = true
if key_pressed:
scanning = true
scanning = true
scanning = true
if scanning:
GPIO_GPDIR (3) &= ~COL_MASK
else:
GPIO_GPDIR (3) |= COL_MASK
class Touchpad:
unsigned old_state
public:
enum buttons:
LEFT = 1 << 16
RIGHT = 1 << 13
void check_events ():
unsigned state = GPIO_GPDR (0)
if (state ^ old_state) & LEFT:
if state & LEFT:
GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & (3 << (2 * 0))) | (GPIO_IRQ_FALLEDG << (2 * 0))
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
if state & (1 << GPIO_TP_LEFT):
gpio_irq_fall (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
event (TOUCHPAD_EVENT, 0)
else:
GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & (3 << (2 * 0))) | (GPIO_IRQ_RAISEDG << (2 * 0))
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
event (TOUCHPAD_EVENT, 0x10000)
if (state ^ old_state) & RIGHT:
if state & RIGHT:
GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & (3 << (2 * 13))) | (GPIO_IRQ_FALLEDG << (2 * 13))
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
if state & (1 << GPIO_TP_RIGHT):
gpio_irq_fall (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
event (TOUCHPAD_EVENT, 1)
else:
GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & (3 << (2 * 13))) | (GPIO_IRQ_RAISEDG << (2 * 13))
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
event (TOUCHPAD_EVENT, 0x10001)
old_state = state
Touchpad ():
// Set pins to input with pull-ups.
GPIO_GPDIR (0) &= ~(LEFT | RIGHT)
GPIO_GPPUR (0) |= LEFT | RIGHT
// Enable interrupts.
GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & (3 << (2 * 0))) | (GPIO_IRQ_FALLEDG << (2 * 0))
GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & (3 << (2 * 13))) | (GPIO_IRQ_FALLEDG << (2 * 13))
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
// Set up interrupts.
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
old_state = 0
// See if they are already pressed. If so, the interrupt detection is changed.
check_events ()
// Now enable the interrupts.
GPIO_GPIER (0) |= LEFT | RIGHT
GPIO_GPIER (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
class Lockleds:
// Note that num lock is in port 2. The others are in port 0.
@ -176,23 +181,25 @@ class Lockleds:
enum { SCROLL = 1 << 9 }
public:
Lockleds ():
GPIO_GPDR (2) &= ~NUM
GPIO_GPDR (0) &= ~(SCROLL | CAPS)
GPIO_GPDIR (2) |= NUM
GPIO_GPDIR (0) |= CAPS | SCROLL
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
gpio_as_output (GPIO_SCROLL_PORT, GPIO_SCROLL)
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
void set (unsigned state):
if state & 4:
GPIO_GPDR (2) &= ~NUM
GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
else:
GPIO_GPDR (2) |= NUM
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
if state & 2:
GPIO_GPDR (0) &= ~CAPS
GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
else:
GPIO_GPDR (0) |= CAPS
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
if state & 1:
GPIO_GPDR (0) &= ~SCROLL
GPIO_GPDR (GPIO_SCROLL_PORT) &= ~(1 << GPIO_SCROLL)
else:
GPIO_GPDR (0) |= SCROLL
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
class Power:
// Power out is in port 2, the rest in port 3.
@ -207,14 +214,14 @@ class Power:
GPIO_GPIER (0) &= ~0xff
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
GPIO_GPPUR (3) &= ~(PWR_IN | BATTERY)
udelay (100)
//udelay (100)
unsigned state = GPIO_GPDR (3)
if (state ^ old_state) & PWR_IN:
event (POWERBUTTON_EVENT, state & PWR_IN ? 0 : 0x10000)
if (state ^ old_state) & BATTERY:
if !(state & BATTERY):
GPIO_GPPUR (3) |= BATTERY
udelay (100)
//udelay (100)
if GPIO_GPDR (3) & BATTERY:
if !was_present:
event (BATTERY_EVENT, BATTERY_CHARGED)
@ -228,7 +235,7 @@ class Power:
old_state = state
GPIO_GPPUR (3) &= ~BATTERY
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
udelay (100)
//udelay (100)
GPIO_GPIER (3) |= 0xff
Power ():
GPIO_GPDR (2) |= PWR_OUT
@ -237,10 +244,16 @@ class Power:
old_state = BATTERY
poll ()
void poweroff ():
GPIO_GPDR (2) &= ~PWR_OUT
GPIO_GPDIR (2) |= PWR_OUT
gpio_as_gpio (GPIO_PW_O_PORT, GPIO_PW_O)
gpio_as_output (GPIO_PW_O_PORT, GPIO_PW_O)
GPIO_GPDR (GPIO_PW_O) &= ~(1 << GPIO_PW_O)
while true:
// Do nothing; wait until the device stops running.
void reboot ():
wdt_set_count (0xffffffff - 32)
wdt_start ()
while true:
// Do nothing; wait until the device reboots.
// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
class Pwm:
@ -263,14 +276,14 @@ class Pwm:
int main ():
schedule ()
*(unsigned *)~3 = 0
map_gpio ()
map_pwm0 ()
map_wdt ()
Keyboard kbd
Touchpad tp
//Lockleds leds
Lockleds leds
Power power
Pwm pwm
@ -287,7 +300,7 @@ int main ():
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_poweroff), cap_copy (cap_powerbutton), INIT_SET_GPIO_0)
invoke_31 (__my_parent, cap_copy (cap_battery), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO_1)
receiver_set_alarm (__my_receiver, HZ / 5)
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
while true:
Message msg
wait (&msg)
@ -296,17 +309,20 @@ int main ():
// Alarm.
if kbd.is_scanning ():
kbd.scan ()
power.poll ()
receiver_set_alarm (__my_receiver, HZ / 5)
//power.poll ()
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
break
case IRQ_GPIO0:
kdebug ("gpio interrupt")
unsigned irq = GPIO_GPFR (0)
// Ack all. This works because they are all edge triggered.
GPIO_GPFR (0) = irq
if irq & 0xff:
kbd.scan ()
if irq & (Touchpad::LEFT | Touchpad::RIGHT):
if irq & ((1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)):
tp.check_events ()
register_interrupt (IRQ_GPIO0)
break
case CAP_KEYBOARD:
set_cb (KEYBOARD_EVENT, msg.cap[0])
break
@ -314,7 +330,10 @@ int main ():
set_cb (TOUCHPAD_EVENT, msg.cap[0])
break
case CAP_POWEROFF:
power.poweroff ()
if msg.data[0]:
power.poweroff ()
else:
power.reboot ()
break
case CAP_POWERBUTTON:
set_cb (POWERBUTTON_EVENT, msg.cap[0])
@ -323,7 +342,7 @@ int main ():
set_cb (BATTERY_EVENT, msg.cap[0])
break
case CAP_LOCKLEDS:
//leds.set (msg.data[0])
leds.set (msg.data[0])
break
case CAP_PWM:
pwm.set_backlight (msg.data[0])

View File

@ -76,14 +76,18 @@ int main ():
wait (&msg)
switch msg.protected_data:
case KBD:
kdebug ("keyboard event")
kdebug ("keyboard event: ")
kdebug_num (msg.data[0])
kdebug_char ('\n')
break
case TP:
kdebug ("touchpad event")
if msg.data[0] == 0:
// Press left button.
invoke_00 (poweroff)
break
case POWERBUTTON:
kdebug ("powerbutton event")
kdebug ("powerbutton event\n")
break
case BATTERY:
kdebug ("battery event")
kdebug ("battery event\n")
break

View File

@ -18,6 +18,31 @@
#include "kernel.hh"
void Thread::raise (unsigned code, unsigned data):
dbg_log ("raise ")
dbg_log_num ((unsigned)current)
dbg_log_char ('/')
if code < NUM_EXCEPTION_CODES:
dbg_log (exception_name[code])
else:
dbg_log ("invalid code:")
dbg_log_num (code)
dbg_log_char ('/')
dbg_log_num (data)
dbg_log_char ('\n')
unrun ()
if !exception.target:
return
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL
c.copy[i] = false
c.data[0] = code
c.data[1] = data
c.data[2] = 0
c.data[3] = 0
exception.invoke (&c)
// From user-provided, thus untrusted, data, find a capability.
Capability *Memory::find_capability (unsigned code, bool *copy):
*copy = code & 2 ? true : false
@ -27,7 +52,10 @@ Capability *Memory::find_capability (unsigned code, bool *copy):
// Cappage capability
unsigned num = (code & ~PAGE_MASK) >> 2
if num >= CAPPAGE_SIZE:
panic (0x15544551, "invalid cappage index")
dbg_log_num ((unsigned)old_current)
dbg_log (": invalid cappage index ")
dbg_log_num (num)
dbg_log_char ('\n')
return NULL
unsigned page = code & PAGE_MASK
for Cappage *p = cappages; p; p = p->next:
@ -39,8 +67,10 @@ Capability *Memory::find_capability (unsigned code, bool *copy):
for Capability *c = capabilities; c; c = c->next:
if c == target:
return c
dbg_send (code)
panic (0xfffeee00, "invalid capability")
dbg_log_num ((unsigned)old_current)
dbg_log (": invalid capability ")
dbg_log_num (code)
dbg_log_char ('\n')
return NULL
// Try to deliver a message.
@ -56,7 +86,6 @@ bool Receiver::try_deliver ():
protected_only = false
break
if !m:
//panic (0x32547688, "protected only")
return false
Capability::Context c
for unsigned i = 0; i < 4; ++i:
@ -64,7 +93,7 @@ bool Receiver::try_deliver ():
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")
owner->raise (ERR_OUT_OF_MEMORY, 0)
for unsigned j = 0; j < i; ++j:
owner->address_space->free_capability (c.cap[i])
return false
@ -85,24 +114,22 @@ bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
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")
return false
owner->raise (ERR_OUT_OF_MEMORY, 0)
for unsigned j = 0; j < i; ++j:
owner->address_space->free_capability (c->cap[j])
c->cap[j] = orig[j]
c->cap[i] = orig[i]
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
return false
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)
if !msg:
panic (0xbbbbbbbb, "out of memory")
if owner:
owner->raise (ERR_OUT_OF_MEMORY, 0)
return false
msg->protected_data = protected_data
if protected_data == reply_protected_data:
@ -122,7 +149,8 @@ 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")
if owner:
owner->raise (ERR_OUT_OF_MEMORY, 0)
for unsigned j = 0; j < i; ++j:
address_space->free_capability (msg->capabilities[j])
address_space->free_message (this, msg)
@ -768,8 +796,10 @@ static void kernel_invoke (unsigned target, unsigned protected_data, Capability:
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])
dbg_log ("operation not allowed: ")
dbg_log_num (c->data[0])
dbg_log ("; target = ")
dbg_log_num (target)
return
reply = c->cap[0]
if c->data[0] == CAP_DEGRADE:

45
iris.h
View File

@ -36,6 +36,41 @@ extern "C" {
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
enum Exception_code {
ERR_WRITE_DENIED,
ERR_UNMAPPED_READ,
ERR_UNMAPPED_WRITE,
ERR_INVALID_ADDRESS_READ,
ERR_INVALID_ADDRESS_WRITE,
ERR_RESERVED_INSTRUCTION,
ERR_COPROCESSOR_UNUSABLE,
ERR_OVERFLOW,
ERR_TRAP,
ERR_WATCHPOINT,
ERR_NO_PAGE_DIRECTORY,
ERR_NO_PAGE_TABLE,
ERR_OUT_OF_MEMORY,
NUM_EXCEPTION_CODES
};
#ifndef NDEBUG
static const char *exception_name[NUM_EXCEPTION_CODES] = {
"write denied",
"unmapped read",
"unmapped write",
"invalid address read",
"invalid address write",
"reserved instruction",
"coprocessor unusable",
"overflow",
"trap",
"watchpoint",
"no page directory",
"no page table",
"out of memory"
};
#endif
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
@ -801,7 +836,15 @@ static void cappage_set (Capability page, Capability cap, unsigned index)
/* Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. */
#define kdebug_char(c) do { unsigned d = (c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(d) : "a0", "a1", "memory"); } while (0)
#define kdebug(str) do { const char *s = (str); while (*s) kdebug_char (*s++); kdebug_char ('\n'); } while (0)
#define kdebug(str) do { const char *s = (str); while (*s) kdebug_char (*s++); } while (0)
static void kdebug_num (unsigned n)
{
unsigned i;
const char *encode = "0123456789abcdef";
for (i = 0; i < 8; ++i)
kdebug_char (encode[(n >> (4 * (7 - i))) & 0xf]);
}
#endif

View File

@ -60,21 +60,6 @@ bool Object_base::is_free ():
// Include architecture-specific parts.
#include "arch.hh"
struct Thread : public Object <Thread>:
Receiver *receivers
unsigned pc, sp
Thread_arch arch
unsigned flags
Thread *schedule_prev, *schedule_next
Thread *exception
void raise (unsigned code)
void run ()
void unrun ()
void wait ()
void unwait ()
bool is_waiting ():
return flags & THREAD_FLAG_WAITING
struct Message : public Object <Message>:
Capability *capabilities[4]
unsigned data[4]
@ -93,6 +78,22 @@ struct Capability : public Object <Capability>:
void invoke (Context *c)
void invalidate ()
struct Thread : public Object <Thread>:
Receiver *receivers
unsigned pc, sp
Thread_arch arch
unsigned flags
Thread *schedule_prev, *schedule_next
// This is not a pointer, but a real Capability. That means that at capability destroy, no check is needed if it is used for an exception handler.
Capability exception
void raise (unsigned code, unsigned data)
void run ()
void unrun ()
void wait ()
void unwait ()
bool is_waiting ():
return flags & THREAD_FLAG_WAITING
struct Receiver : public Object <Receiver>:
Thread *owner
Receiver *prev_owned, *next_owned
@ -167,20 +168,21 @@ struct Memory : public Object <Memory>:
void free_cappage (Cappage *page)
void free_memory (Memory *mem)
void free_obj (Object_base *obj)
void free_obj (Object_base *obj, void **first)
Capability *find_capability (unsigned code, bool *copy)
// Functions which can be called from assembly must not be mangled.
extern "C":
// Panic. n is sent over caps led. message is currently ignored.
void panic (unsigned n, char const *message = "")
// Debug: send a message to the user.
void dbg_send (unsigned code, unsigned bits = 32)
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
EXTERN unsigned dbg_code
EXTERN Capability *dbg_cap
void dbg_log_char (unsigned ch)
void dbg_log (char const *str)
void dbg_log_num (unsigned num)
#define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m))
/// Defined in schedule.ccp
void schedule ()

View File

@ -19,7 +19,7 @@ unsigned init_memory (unsigned mem):
unsigned phys_alloc (unsigned num):
if free_begin + num * PAGE_SIZE > free_end:
panic (0xaaaaaaaa, "out of memory")
dbg_log ("memory allocation failed\n")
return 0
unsigned ret = free_begin
free_begin += num * PAGE_SIZE
@ -54,7 +54,7 @@ unsigned phys_alloc (unsigned num):
choice = p
if !choice:
// TODO: reorganizing may work to allow allocation.
panic (0x01100223, "out of large enough memory")
dbg_log ("range memory allocation failed")
return 0
if choice->num == num:
if choice->prev:
@ -132,7 +132,7 @@ void raw_pfree (unsigned page):
unsigned Memory::zalloc ():
if !use ():
panic (0x4536928, "no memory due to limit")
dbg_log ("limit reached: allocation not allowed")
return NULL
return raw_zalloc ()

View File

@ -157,16 +157,10 @@ static arch_page *alloc_page (Memory *mem, arch_page_table *t):
static void free_page_table (arch_page_table *t, unsigned idx):
Memory *mem = t->address_space
if t->next:
t->next->prev = t->prev
if t->prev:
t->prev->next = t->next
else:
mem->arch.first_page_table = t->next
mem->zfree ((unsigned)mem->arch.directory[idx])
mem->arch.directory[idx] = NULL
mem->arch.shadow[idx] = NULL
mem->free_obj (t)
mem->free_obj (t, (void **)&mem->arch.first_page_table)
if !mem->arch.first_page_table:
mem->zfree ((unsigned)mem->arch.directory)
mem->zfree ((unsigned)mem->arch.shadow)
@ -186,12 +180,6 @@ static void tlb_reset (unsigned address, unsigned asid, unsigned value):
__asm__ volatile ("tlbwi")
static void free_page (arch_page_table *t, arch_page *p):
if p->next:
p->next->prev = p->prev
if p->prev:
p->prev->next = p->next
else:
t->first_page = p->next
if p->prev_mapped:
p->prev_mapped->next_mapped = p->next_mapped
else:
@ -200,7 +188,7 @@ static void free_page (arch_page_table *t, arch_page *p):
p->next_mapped->prev_mapped = p->prev_mapped
tlb_reset (p->mapping, p->address_space->arch.asid, 0)
unsigned idx = p->mapping >> 21
p->address_space->free_obj (p)
p->address_space->free_obj (p, (void **)&t->first_page)
if !t->first_page:
free_page_table (t, idx)

View File

@ -274,6 +274,12 @@ void init (unsigned mem):
gpio_as_ssi()
gpio_as_msc ()
gpio_as_gpio (GPIO_CAPS_PORT, GPIO_CAPS)
gpio_as_gpio (GPIO_SCROLL_PORT, GPIO_SCROLL)
gpio_as_gpio (GPIO_NUM_PORT, GPIO_NUM)
gpio_as_gpio (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_gpio (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
// Start the operating system timer, and set it to give an interrupt immediately.
// This is better, because the kernel starts with jumping into the idle task and
// waiting for the first interrupt.

View File

@ -30,7 +30,7 @@ static void handle_exit ():
if !current:
current = &idle
if (current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) != THREAD_FLAG_RUNNING:
panic (0x99338844, "non-scheduled thread running")
panic (current->flags, "non-scheduled thread running")
if !current:
current = &idle
if old_current == current:
@ -61,22 +61,20 @@ static void handle_exit ():
/// when k0 or k1 is not 0, or when an error occurs.
/// Otherwise, the ultra-fast code in entry.S is used.
Thread *tlb_refill ():
//panic (0x88776655, "TLB refill")
old_current = current
if !directory:
panic (0x44449999, "No directory")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_NO_PAGE_DIRECTORY, addr)
handle_exit ()
return current
unsigned EntryHi
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")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_NO_PAGE_TABLE, addr)
else:
// - 2 instead of - 1 means reset bit 0
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
@ -88,7 +86,6 @@ Thread *tlb_refill ():
/// An interrupt which is not an exception has occurred.
Thread *interrupt ():
//panic (0x88877722, "Interrupt")
old_current = current
unsigned ipr = INTC_IPR
for unsigned i = 0; i < 32; ++i:
@ -134,7 +131,6 @@ static void arch_invoke ():
if wait:
old_current->wait ()
if !target:
//dbg_send (0, 0)
// There must be no action here.
else:
Capability::Context c
@ -164,55 +160,45 @@ Thread *exception ():
switch (cause >> 2) & 0x1f:
case 0:
// Interrupt. This shouldn't happen, since CAUSE[IV] == 1.
panic (0x01223344, "Interrupt on exception vector.")
panic (0, "Interrupt on exception vector.")
break
case 1:
// TLB modification.
panic (0x11223344, "TLB modification.")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_WRITE_DENIED, addr)
break
case 2:
// TLB load or instruction fetch.
unsigned a
cp0_get (CP0_EPC, a)
//dbg_send (a)
panic (0x21223344, "TLB load or instruction fetch.")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_UNMAPPED_READ, addr)
break
case 3:
// TLB store.
unsigned a
cp0_get (CP0_EPC, a)
//dbg_send (a)
cp0_get (CP0_BAD_V_ADDR, a)
//dbg_send (a)
panic (0x31223344, "TLB store.")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_UNMAPPED_WRITE, addr)
break
case 4:
// Address error load or instruction fetch.
unsigned a
cp0_get (CP0_EPC, a)
//dbg_send (a)
cp0_get (CP0_BAD_V_ADDR, a)
//dbg_send (a)
panic (0x41223344, "Address error load or instruction fetch.")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_INVALID_ADDRESS_READ, addr)
break
case 5:
// Address error store.
//dbg_send (current->arch.v1, 4)
//unsigned a
//cp0_get (CP0_EPC, a)
//dbg_send (*(unsigned *)(a & ~3), 32)
//dbg_send (a, 32)
//cp0_get (CP0_BAD_V_ADDR, a)
//dbg_send (a, 32)
panic (0x51223344, "Address error store.")
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_INVALID_ADDRESS_WRITE, addr)
break
case 6:
// Bus error instruction fetch.
panic (0x61223344, "Bus error instruction fetch.")
panic (0, "Bus error instruction fetch.")
break
case 7:
// Bus error load or store.
panic (0x71223344, "Bus error load or store.")
panic (0, "Bus error load or store.")
break
case 8:
// Syscall.
@ -221,37 +207,40 @@ Thread *exception ():
break
case 9:
// Breakpoint.
//panic (0x91223344, "Breakpoint.")
#if 0
current->raise (ERR_BREAKPOINT, 0)
#else
current->pc += 4
if current->arch.a0:
if dbg_cap:
panic (0x34259380, "Break instruction while log capability was already set")
panic (0, "Break instruction while log capability was already set")
break
bool dummy
dbg_cap = current->address_space->find_capability (current->arch.a1, &dummy)
if !dbg_cap:
panic (0x06111129, "no log capability provided")
panic (0, "no log capability provided")
break
break
if dbg_cap:
dbg_log_char (current->arch.a1)
break
break
#endif
case 10:
// Reserved instruction.
panic (0xa1223344, "Reserved instruction.")
current->raise (ERR_RESERVED_INSTRUCTION, 0)
break
case 11:
// Coprocessor unusable.
panic (0xb1223344, "Coprocessor unusable.")
current->raise (ERR_COPROCESSOR_UNUSABLE, 0)
break
case 12:
// Arithmetic overflow.
panic (0xc1223344, "Arithmetic overflow.")
current->raise (ERR_OVERFLOW, 0)
break
case 13:
// Trap.
panic (0xd1223344, "Trap.")
current->raise (ERR_TRAP, 0)
break
case 15:
// Floating point exception.
@ -259,7 +248,7 @@ Thread *exception ():
break
case 23:
// Reference to WatchHi/WatchLo address.
panic (0xf1223344, "Reference to WatchHi/WatchLo address.")
current->raise (ERR_WATCHPOINT, 0)
break
case 24:
// Machine check.

View File

@ -2837,6 +2837,66 @@ static __inline__ unsigned msc_calc_slow_clk_divisor (bool is_sd):
#define GPIO_CHARG_STAT 29
#define GPIO_TS_PENIRQ_PORT 2
#define GPIO_TS_PENIRQ 4
#define GPIO_CAPS_PORT 0
#define GPIO_CAPS 27
#define GPIO_SCROLL_PORT 0
#define GPIO_SCROLL 9
#define GPIO_NUM_PORT 2
#define GPIO_NUM 22
#define GPIO_TP_LEFT_PORT 0
#define GPIO_TP_LEFT 16
#define GPIO_TP_RIGHT_PORT 0
#define GPIO_TP_RIGHT 13
#define GPIO_HALF(x) (((x) & 0xf) << 1)
static __inline__ void gpio_as_gpio (unsigned port, unsigned pin):
unsigned mask = 3 << GPIO_HALF (pin)
if pin < 16:
GPIO_GPALR (port) &= ~mask
else:
GPIO_GPAUR (port) &= ~mask
static __inline__ void gpio_as_input (unsigned port, unsigned pin):
#if 0
unsigned mask = 3 << GPIO_HALF (pin)
if pin < 16:
GPIO_GPIDLR (port) &= ~mask
else:
GPIO_GPIDUR (port) &= ~mask
#else
GPIO_GPDIR (port) &= ~(1 << pin)
#endif
static __inline__ void gpio_as_output (unsigned port, unsigned pin):
#if 0
unsigned half = 1 << GPIO_HALF (pin)
if pin < 16:
GPIO_GPIDLR (port) = (GPIO_GPIDLR (port) & ~(3 * half)) | half
else:
GPIO_GPIDUR (port) = (GPIO_GPIDUR (port) & ~(3 * half)) | half
#else
GPIO_GPDIR (port) |= 1 << pin
#endif
static __inline__ void gpio_irq (unsigned port, unsigned pin, unsigned how):
unsigned half = 1 << GPIO_HALF (pin)
if pin < 16:
GPIO_GPIDLR (port) = (GPIO_GPIDLR (port) & ~(3 * half)) | (how * half)
else:
GPIO_GPIDUR (port) = (GPIO_GPIDUR (port) & ~(3 * half)) | (how * half)
static __inline__ void gpio_irq_low (unsigned port, unsigned pin):
gpio_irq (port, pin, GPIO_IRQ_LOLEVEL)
static __inline__ void gpio_irq_high (unsigned port, unsigned pin):
gpio_irq (port, pin, GPIO_IRQ_HILEVEL)
static __inline__ void gpio_irq_fall (unsigned port, unsigned pin):
gpio_irq (port, pin, GPIO_IRQ_FALLEDG)
static __inline__ void gpio_irq_rise (unsigned port, unsigned pin):
gpio_irq (port, pin, GPIO_IRQ_RAISEDG)
/* Init the alternate function pins */

View File

@ -36,20 +36,13 @@ void dbg_log (char const *str):
while *str:
dbg_log_char (*str++)
void dbg_send (unsigned code, unsigned bits):
if bits > 32:
bits = 32
void dbg_log_num (unsigned num):
char const *encode = "0123456789abcdef"
dbg_log_char ('[')
dbg_log_char (encode[(bits >> 4) & 0xf])
dbg_log_char (encode[bits & 0xf])
dbg_log_char (':')
for unsigned i = 0; i < 8; ++i:
dbg_log_char (encode[(code >> (4 * (7 - i))) & 0xf])
dbg_log_char (']')
dbg_log_char (encode[(num >> (4 * (7 - i))) & 0xf])
return
void panic (unsigned n, char const *message):
void panic_impl (unsigned n, unsigned line, char const *name, char const *message):
Thread *who = current
// Stop all threads.
while first_scheduled:
@ -64,8 +57,18 @@ void panic (unsigned n, char const *message):
if dbg_cap && dbg_cap->target->owner:
dbg_cap->target->owner->run ()
// Use the (now running) log thread to display the message.
dbg_log ("Panic: ")
dbg_send (n)
dbg_log ("Panic: current = ")
dbg_log_num ((unsigned)who)
if who:
dbg_log_char ('@')
dbg_log_num ((unsigned)who->pc)
dbg_log ("; ")
dbg_log (name)
dbg_log_char (':')
dbg_log_num (line)
dbg_log (": ")
dbg_log (message)
dbg_log_char ('/')
dbg_log_num (n)
dbg_log_char ('\n')
// If no log capability is registered, the machine just hangs.

View File

@ -71,7 +71,7 @@ static void alarm_tick (Receiver *recv):
first_alarm = recv->next_alarm
if recv->next_alarm:
recv->next_alarm->prev_alarm = recv->prev_alarm
return
// Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm.
--recv->alarm_count
void Thread::wait ():