From df38266bb8a740ef9c0ba481010c50553b3b5e98 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sat, 25 Jul 2009 00:54:12 +0200 Subject: [PATCH] things are working --- alloc.ccp | 137 +++++++++++++++++++++++++---------------- boot-programs/gpio.ccp | 111 +++++++++++++++++++-------------- boot-programs/init.ccp | 12 ++-- invoke.ccp | 68 ++++++++++++++------ iris.h | 45 +++++++++++++- kernel.hhp | 40 ++++++------ memory.ccp | 6 +- mips/arch.ccp | 16 +---- mips/init.ccp | 6 ++ mips/interrupts.ccp | 83 +++++++++++-------------- mips/jz4730.hhp | 60 ++++++++++++++++++ panic.ccp | 27 ++++---- schedule.ccp | 2 +- 13 files changed, 393 insertions(+), 220 deletions(-) diff --git a/alloc.ccp b/alloc.ccp index 37a17fc..f947c4b 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -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: diff --git a/boot-programs/gpio.ccp b/boot-programs/gpio.ccp index 8176801..6a8c872 100644 --- a/boot-programs/gpio.ccp +++ b/boot-programs/gpio.ccp @@ -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]) diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index 3f37f1c..a619f2b 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -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 diff --git a/invoke.ccp b/invoke.ccp index 8a5748c..62dd861 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -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: diff --git a/iris.h b/iris.h index e491ddf..34f54bd 100644 --- a/iris.h +++ b/iris.h @@ -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 diff --git a/kernel.hhp b/kernel.hhp index a4a0fdc..349a65d 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -60,21 +60,6 @@ bool Object_base::is_free (): // Include architecture-specific parts. #include "arch.hh" -struct Thread : public Object : - 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 : Capability *capabilities[4] unsigned data[4] @@ -93,6 +78,22 @@ struct Capability : public Object : void invoke (Context *c) void invalidate () +struct Thread : public Object : + 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 : Thread *owner Receiver *prev_owned, *next_owned @@ -167,20 +168,21 @@ struct Memory : public Object : 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 () diff --git a/memory.ccp b/memory.ccp index 351229f..ba129b6 100644 --- a/memory.ccp +++ b/memory.ccp @@ -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 () diff --git a/mips/arch.ccp b/mips/arch.ccp index 2bcc665..390c224 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -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) diff --git a/mips/init.ccp b/mips/init.ccp index 099ae8c..fc477f5 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -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. diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 785e201..9a084ea 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -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. diff --git a/mips/jz4730.hhp b/mips/jz4730.hhp index ff1a530..e8b54de 100644 --- a/mips/jz4730.hhp +++ b/mips/jz4730.hhp @@ -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 */ diff --git a/panic.ccp b/panic.ccp index 00127b4..ed37780 100644 --- a/panic.ccp +++ b/panic.ccp @@ -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. diff --git a/schedule.ccp b/schedule.ccp index 9c213f1..2da2bd6 100644 --- a/schedule.ccp +++ b/schedule.ccp @@ -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 ():