diff --git a/boot-programs/gpio.ccp b/boot-programs/gpio.ccp index a83142c..6bbae3d 100644 --- a/boot-programs/gpio.ccp +++ b/boot-programs/gpio.ccp @@ -262,6 +262,10 @@ class Pwm: // TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything. int main (): + for unsigned i = 0; i < 10; ++i: + schedule () + *(unsigned *)~3 = 0 + map_gpio () map_pwm0 () diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index 6e01958..505b14f 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -39,7 +39,7 @@ static void setup (): wait (&msg) switch msg.data[0]: case INIT_SET_GPIO_0: - kdebug (0, 2) + kdebug ("gpio 0") kbd = msg.cap[0] tp = msg.cap[1] poweroff = msg.cap[2] @@ -47,14 +47,14 @@ static void setup (): ++state break case INIT_SET_GPIO_1: - kdebug (1, 2) + kdebug ("gpio 1") battery = msg.cap[0] lockleds = msg.cap[1] pwm = msg.cap[2] ++state break case INIT_SET_LCD: - kdebug (2, 2) + kdebug ("lcd") lcd = msg.cap[0] ++state break @@ -67,8 +67,10 @@ static void setup (): invoke_01 (pwm, 1) int main (): + for unsigned i = 0; i < 10; ++i: + schedule () setup () - kdebug (3, 2) + kdebug ("start init") while true: Message msg wait (&msg) diff --git a/boot-programs/lcd.ccp b/boot-programs/lcd.ccp index 760e927..8e71c2e 100644 --- a/boot-programs/lcd.ccp +++ b/boot-programs/lcd.ccp @@ -24,10 +24,11 @@ __asm__ volatile (".globl charset\ncharset:\n.incbin \"boot-programs/charset.dat // I'm too lazy to do this right. The address of charset is really the address of the array. extern unsigned charset -#define assert(x) do { while (!(x)) kdebug (0, 0); } while (0) +#define assert(x) do { while (!(x)) kdebug ("assertion failed " #x); } while (0) enum types: LCD_EOF_CB = 32 + LCD_LOG // For now, support only 16 bpp. // Screen is 800x480 tft. @@ -65,73 +66,20 @@ static void reset (unsigned physical_descriptor): cpm_start_lcd () - udelay (1000) LCD_DA0 = physical_descriptor lcd_set_ena () lcd_enable_eof_intr () -static void putchar (unsigned x, unsigned y, unsigned utf8, unsigned fg = 0xffff, unsigned bg = 0x0000): - if utf8 < 32 || utf8 > 126: - utf8 = 127 - unsigned idx = utf8 - 32 - unsigned char *c = &((unsigned char *)&charset)[idx * 6] +static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff, unsigned bg = 0x0000): + if ch < 32 || ch > 126: + ch = 127 + ch -= 32 + unsigned char *c = &((unsigned char *)&charset)[ch * 6] unsigned lookup[2] = { bg, fg } for unsigned k = 0; k < 6; ++k: for unsigned r = 0; r < 8; ++r: LCD_FRAMEBUFFER_BASE[(y * 8 + r) * 800 + x * 6 + k] = lookup[c[k] & (1 << r) ? 1 : 0] -static unsigned read_rest (unsigned num, char const *&utf8): - unsigned ret = 0 - while num--: - if (*utf8 & 0xc0) != 0x80: - return ~0 - ret <<= 6 - ret |= (*utf8++) & 0x3f - return ret - -static unsigned read_utf8 (char const *&utf8): - unsigned c = *utf8++ - if !(c & 0x80): - return c - if !(c & 0x40): - // Invalid character. - return 0 - if !(c & 0x20): - // 2-byte character. - c &= 0x1f - c <<= 6 - c |= read_rest (1, utf8) - else if !(c & 0x10): - // 3-byte character. - c &= 0xf - c <<= 12 - c |= read_rest (2, utf8) - else if !(c & 0x8): - // 4-byte character. - c &= 0x7 - c <<= 18 - c |= read_rest (3, utf8) - else if !(c & 0x4): - // 5-byte character. - c &= 0x3 - c <<= 24 - c |= read_rest (4, utf8) - else if !(c & 0x2): - // 6-byte character. - c &= 0x1 - c <<= 30 - c |= read_rest (5, utf8) - else - // Invalid character. - return 0 - if c == ~0: - return 0 - return c - -static void putstr (unsigned x, unsigned y, char const *utf8): - while *utf8: - putchar (x++, y, read_utf8 (utf8)) - static unsigned log_x = 1, log_y = 1 static void inc_logx (): if ++log_x >= 800 / 6: @@ -139,27 +87,45 @@ static void inc_logx (): if ++log_y >= 480 / 8: log_y = 1 -static void log (char const *utf8): - while *utf8: - unsigned c = read_utf8 (utf8) - switch c: - case '\n': - while log_x < 800 / 6: - putchar (log_x++, log_y, ' ') - inc_logx () - break - default: - putchar (log_x, log_y, c) - inc_logx () +static void log_char (unsigned ch): + switch ch: + case '\n': + while log_x < 800 / 6: + putchar (log_x++, log_y, ' ') + inc_logx () + break + default: + putchar (log_x, log_y, ch) + inc_logx () + +static void log_str (char const *str): + while *str: + log_char (*str++) + +static void log_num (unsigned n): + char const *encode = "0123456789abcdef" + log_char ('[') + for unsigned i = 0; i < 8; ++i: + log_char (encode[(n >> (7 - i)) & 0xf]) + log_char (']') + +static void log_msg (Message *msg): + log_str ("prot:") + log_num (msg->protected_data) + log_str ("data:") + for unsigned i = 0; i < 4; ++i: + log_num (msg->data[i]) + log_str ("cap:") + for unsigned i = 0; i < 4; ++i: + log_num (msg->cap[i]) + log_char ('\n') 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 () - unsigned pages = (frame_size + 16 + ~PAGE_MASK) >> PAGE_BITS + Descriptor descriptor __attribute__ ((aligned (16))) + unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS assert (pages > CAPPAGE_SIZE && pages <= 2 * CAPPAGE_SIZE) unsigned physical = alloc_range (__my_memory, pages) assert (physical) @@ -195,15 +161,15 @@ int main (): ob = b b = 0x1f LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b) - log ("testing!\nIs dit een werkende console?\nLinks, rechts?\n") - 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) + Capability page = memory_mapping (__my_memory, &descriptor) + unsigned physical_descriptor = page_physical_address (page) + ((unsigned)&descriptor & ~PAGE_MASK) + descriptor.next = physical_descriptor + descriptor.frame = physical + descriptor.id = 0xdeadbeef + descriptor.cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT) + unsigned dptr = (unsigned)&descriptor + __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0") reset (physical_descriptor) - register_interrupt (IRQ_LCD) Capability eof_cb = 0 @@ -211,18 +177,27 @@ int main (): invoke_11 (__my_parent, cap, INIT_SET_LCD) drop (cap) + Capability logcap = receiver_create_capability (__my_receiver, LCD_LOG) + __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap) : "a0", "a1", "memory") + while true: Message msg wait (&msg) + //log_msg (&msg) switch msg.protected_data: case IRQ_LCD: lcd_clr_eof () - register_interrupt (IRQ_LCD) if eof_cb: + register_interrupt (IRQ_LCD) invoke_00 (eof_cb) break case LCD_EOF_CB: if eof_cb: drop (eof_cb) eof_cb = msg.cap[0] + if eof_cb: + register_interrupt (IRQ_LCD) + break + case LCD_LOG: + log_char (msg.data[0]) break diff --git a/invoke.ccp b/invoke.ccp index 0d493c3..645a773 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -48,7 +48,6 @@ bool Receiver::try_deliver (): if !messages: return false if !owner || !owner->is_waiting (): - dbg_send (3, 3) return false Message *m = last_message if protected_only: @@ -56,9 +55,9 @@ bool Receiver::try_deliver (): if m->protected_data == reply_protected_data: protected_only = false break - if !m: - panic (0x32547688, "protected only") - 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] @@ -388,6 +387,8 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability: if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING): if v & THREAD_FLAG_WAITING: if !(thread->is_waiting ()): + if thread == current: + unschedule () thread->wait () else if thread->is_waiting (): @@ -408,7 +409,6 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability: reply_num (0) break case CAP_THREAD_SCHEDULE: - schedule () do_schedule = true break case CAP_THREAD_REGISTER_INTERRUPT: diff --git a/iris.h b/iris.h index fce1c45..e491ddf 100644 --- a/iris.h +++ b/iris.h @@ -140,12 +140,12 @@ extern Capability __my_memory; extern Capability __my_call; extern Capability __my_parent; -Capability cap_copy (Capability src) +static Capability cap_copy (Capability src) { return src | 2; } -Capability cappage_cap (unsigned base, unsigned idx) +static Capability cappage_cap (unsigned base, unsigned idx) { return base | (idx << 2) | 1; } @@ -800,7 +800,8 @@ 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(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) +#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) #endif diff --git a/kernel.hhp b/kernel.hhp index d36d612..a3a70a7 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -178,9 +178,14 @@ extern "C": void dbg_sleep (unsigned ms) void dbg_send (unsigned code, unsigned bits = 32) EXTERN unsigned dbg_code + EXTERN Capability *dbg_cap + void dbg_log_char (unsigned ch) + void dbg_log (char const *str) /// Defined in schedule.ccp void schedule () +// Make sure the current process is no longer scheduled. This is called just before wait (), if the current process is the target. +void unschedule () void timer_interrupt () EXTERN Memory top_memory diff --git a/memory.ccp b/memory.ccp index 9c4e2ea..186f805 100644 --- a/memory.ccp +++ b/memory.ccp @@ -3,10 +3,12 @@ extern unsigned _end -static void clear_page (unsigned page): - for unsigned i = 0; i < PAGE_SIZE >> 2; ++i: +static void clear_page (unsigned page, unsigned num = 1): + for unsigned i = 0; i < (num << (PAGE_BITS - 2)); ++i: ((unsigned *)page)[i] = 0 +#if 0 + static unsigned free_begin static unsigned free_end @@ -20,14 +22,14 @@ unsigned phys_alloc (unsigned num): 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) + clear_page (ret, num) return ret void phys_free (unsigned page, unsigned num): // Not supported. -#if 0 +#else + struct FreePages: FreePages *prev, *next unsigned num diff --git a/mips/Makefile.arch b/mips/Makefile.arch index 9dc43fc..05df707 100644 --- a/mips/Makefile.arch +++ b/mips/Makefile.arch @@ -24,7 +24,7 @@ OBJDUMP = $(CROSS)objdump junk = mdebug.abi32 reginfo comment pdr OBJCOPYFLAGS = $(addprefix --remove-section=.,$(junk)) -arch_kernel_sources = mips/interrupts.cc mips/test.cc mips/arch.cc +arch_kernel_sources = mips/interrupts.cc mips/arch.cc boot_sources = mips/init.cc arch_headers = mips/arch.hh mips/jz4730.hh boot_threads = init gpio lcd diff --git a/mips/entry.S b/mips/entry.S index c869de8..02244b0 100644 --- a/mips/entry.S +++ b/mips/entry.S @@ -216,7 +216,7 @@ save_regs: la $sp, kernel_stack + KERNEL_STACK_SIZE #ifndef NDEBUG - // Allow interrupts to set EPC and friends. + // Allow kernel bugs to set EPC and friends. mfc0 $k0, $CP0_STATUS li $k1, 0x1000ff00 and $k0, $k0, $k1 diff --git a/mips/init.ccp b/mips/init.ccp index 65d2e02..3be46ad 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -203,10 +203,9 @@ static void init_threads (): thread->arch.t0 = mkcap (mem, (unsigned)init_receiver, (void *)i) previous->schedule_next = thread thread->schedule_prev = previous - previous = thread - - mem->pfree ((unsigned)pages) thread->schedule_next = NULL + previous = thread + mem->pfree ((unsigned)pages) // Initialize the kernel, finish by falling into the idle task. void init (unsigned mem): diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 7db2982..570b3f6 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -29,8 +29,12 @@ static void handle_exit (Thread *old_current): schedule () if !current: current = &idle + if (current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) != THREAD_FLAG_RUNNING: + dbg_send ((unsigned)current >> PAGE_BITS, 3) + panic (0x99338844, "non-scheduled thread running") if old_current == current: return + dbg_send ((unsigned)current >> PAGE_BITS, 3) arch_flush_cache () if current != &idle: if (Memory *)asids[current->address_space->arch.asid] != current->address_space: @@ -101,6 +105,7 @@ Thread *interrupt (): c.copy[j] = false dbg_code = (unsigned)arch_interrupt_receiver[i]->owner arch_interrupt_receiver[i]->send_message (i, &c) + arch_interrupt_receiver[i] = NULL if ipr & (1 << IRQ_OST0): ost_clear_uf (0) intc_ack_irq (IRQ_OST0) @@ -126,8 +131,10 @@ static void arch_invoke (): target = caller->address_space->find_capability (caller->arch.v0, &wait) do_schedule = false if wait: + unschedule () caller->wait () if !target: + dbg_send (0, 0) // There must be no action here. else: Capability::Context c @@ -140,9 +147,14 @@ static void arch_invoke (): c.data[2] = caller->arch.t2 c.data[3] = caller->arch.t3 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 + if do_schedule: + // If the call was to schedule without wait, it isn't done yet. + if !wait: + schedule () + else: + // If the caller received an immediate 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: + current = caller /// A general exception has occurred. Thread *exception (): @@ -202,8 +214,18 @@ Thread *exception (): case 9: // Breakpoint. //panic (0x91223344, "Breakpoint.") - dbg_send (current->arch.a0, current->arch.a1) current->pc += 4 + if current->arch.a0: + if dbg_cap: + panic (0x34259380, "Break instruction while log capability was already set") + bool dummy + dbg_cap = current->address_space->find_capability (current->arch.a1, &dummy) + if !dbg_cap: + panic (0x06111129, "no log capability provided") + break + if dbg_cap: + dbg_log_char (current->arch.a1) + break break case 10: // Reserved instruction. diff --git a/mips/test.ccp b/mips/test.ccp deleted file mode 100644 index 15acefe..0000000 --- a/mips/test.ccp +++ /dev/null @@ -1,116 +0,0 @@ -#pypp 0 -// Iris: micro-kernel for a capability-based operating system. -// mips/test.ccp: Telling the user things with LEDs. -// Copyright 2009 Bas Wijnen -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "../kernel.hh" - -#define REG32(addr) *((volatile unsigned int *)(addr)) - -#define GPIO_BASE 0xB0010000 - -#define __gpio_port_data(p) ( REG_GPIO_GPDR(p) ) - -#define GPIO_GPSLR(n) (GPIO_BASE + (0x10 + (n)*0x30)) -#define GPIO_GPSUR(n) (GPIO_BASE + (0x14 + (n)*0x30)) -#define GPIO_GPFLR(n) (GPIO_BASE + (0x18 + (n)*0x30)) -#define GPIO_GPFUR(n) (GPIO_BASE + (0x1c + (n)*0x30)) - -#define GPIO_GPDR(n) (GPIO_BASE + (0x00 + (n)*0x30)) - -#define REG_GPIO_GPSLR(n) REG32(GPIO_GPSLR((n))) -#define REG_GPIO_GPSUR(n) REG32(GPIO_GPSUR((n))) -#define REG_GPIO_GPFLR(n) REG32(GPIO_GPFLR((n))) -#define REG_GPIO_GPFUR(n) REG32(GPIO_GPFUR((n))) - -#define REG_GPIO_GPDR(n) REG32(GPIO_GPDR((n))) - -static void __gpio_port_as_gpiofn (unsigned p, unsigned o, unsigned fn): - unsigned int tmp - if o < 16: - tmp = REG_GPIO_GPSLR(p) - tmp &= ~(3 << ((o) << 1)) - REG_GPIO_GPSLR(p) = tmp - tmp = REG_GPIO_GPFLR(p) - tmp &= ~(3 << ((o) << 1)) - tmp |= fn << ((o) << 1) - REG_GPIO_GPFLR(p) = tmp - else: - tmp = REG_GPIO_GPSUR(p) - tmp &= ~(3 << (((o) - 16) << 1)) - REG_GPIO_GPSUR(p) = tmp - tmp = REG_GPIO_GPFUR(p) - tmp &= ~(3 << (((o) - 16) << 1)) - tmp |= fn << (((o) - 16) << 1) - REG_GPIO_GPFUR(p) = tmp - -static void __gpio_port_as_output (unsigned p, unsigned o): - __gpio_port_as_gpiofn (p, o, 1) -static void __gpio_port_as_input (unsigned p, unsigned o): - __gpio_port_as_gpiofn (p, o, 0) -static void __gpio_as_output (unsigned n): - __gpio_port_as_output(n / 32, n % 32) -static void __gpio_as_input (unsigned n): - __gpio_port_as_input(n / 32, n % 32) -static void __gpio_set_pin (unsigned n): - __gpio_port_data (n / 32) |= (1 << (n % 32)) -static void __gpio_clear_pin (unsigned n): - __gpio_port_data (n / 32) &= ~(1 << (n % 32)) - -#define CAPSLOCKLED_IO 27 -#define NUMLOCKLED_IO 86 -#define NETWORK_IO 9 -#define LIGHT 105 - -void dbg_led (bool one, bool two, bool three): - __gpio_as_output (CAPSLOCKLED_IO) - __gpio_as_output (NUMLOCKLED_IO) - __gpio_as_output (NETWORK_IO) - if one: - __gpio_clear_pin (NUMLOCKLED_IO) - else: - __gpio_set_pin (NUMLOCKLED_IO) - if two: - __gpio_clear_pin (CAPSLOCKLED_IO) - else: - __gpio_set_pin (CAPSLOCKLED_IO) - if three: - __gpio_clear_pin (NETWORK_IO) - else: - __gpio_set_pin (NETWORK_IO) - -void dbg_sleep (unsigned ms): - for unsigned i = 0; i < 2673 * ms; ++i: - __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) - dbg_sleep (200) - if on: - dbg_led (true, false, false) - else: - dbg_led (false, true, false) - dbg_sleep (400) - dbg_led (false, false, false) - dbg_sleep (200) - dbg_led (true, true, false) - dbg_sleep (50) - dbg_led (false, false, false) - dbg_sleep (50) diff --git a/panic.ccp b/panic.ccp index 834659b..3988cdf 100644 --- a/panic.ccp +++ b/panic.ccp @@ -16,8 +16,106 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#define ARCH #include "kernel.hh" +// Port 0 +#define CAPS 27 +#define CAPS_HALF ((CAPS - 16) << 1) +#define SCROLL 9 +#define SCROLL_HALF (SCROLL << 1) +// Port 2 +#define NUM 22 +#define NUM_HALF ((NUM - 16) << 1) + +void dbg_led (bool one, bool two, bool three): + GPIO_GPALR (0) &= ~(3 << SCROLL_HALF) + GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & ~(3 << SCROLL_HALF)) | (1 << SCROLL_HALF) + GPIO_GPAUR (0) &= ~(3 << CAPS_HALF) + GPIO_GPIDUR (0) = (GPIO_GPIDUR (0) & ~(3 << CAPS_HALF)) | (1 << CAPS_HALF) + GPIO_GPAUR (2) &= ~(3 << NUM_HALF) + GPIO_GPIDUR (2) = (GPIO_GPIDUR (2) & ~(3 << NUM_HALF)) | (1 << NUM_HALF) + if one: + GPIO_GPDR (2) &= ~(1 << NUM) + else: + GPIO_GPDR (2) |= 1 << NUM + if two: + GPIO_GPDR (0) &= ~(1 << CAPS) + else: + GPIO_GPDR (0) |= 1 << CAPS + if three: + GPIO_GPDR (0) &= ~(1 << SCROLL) + else: + GPIO_GPDR (0) |= 1 << SCROLL + +void dbg_sleep (unsigned ms): + for unsigned i = 0; i < 2673 * ms; ++i: + GPIO_GPALR (0) = GPIO_GPALR (0) + GPIO_GPIDLR (0) = GPIO_GPIDLR (0) + +void dbg_log_char (unsigned ch): + if !dbg_cap: + return + Capability::Context c + for unsigned i = 0; i < 4; ++i: + c.cap[i] = NULL + c.copy[i] = false + c.data[i] = 0 + c.data[0] = ch + dbg_cap->invoke (&c) + +void dbg_log (char const *str): + while *str: + dbg_log_char (*str++) + +void dbg_send (unsigned code, unsigned bits): + if bits > 32: + bits = 32 + #if 0 + 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 >> (7 - i)) & 0xf]) + dbg_log_char (']') + return + #else + for int i = bits - 1; i >= 0; --i: + bool on = code & (1 << i) + dbg_led (false, false, false) + dbg_sleep (200) + if on: + dbg_led (true, false, false) + else: + dbg_led (false, true, false) + dbg_sleep (400) + dbg_led (false, false, false) + dbg_sleep (200) + dbg_led (true, true, false) + dbg_sleep (50) + dbg_led (false, false, false) + dbg_sleep (50) + #endif + void panic (unsigned n, char const *message): - while (1): - dbg_send (n) + // Stop all threads. + unschedule () + while first_scheduled: + first_scheduled->unrun () + for Receiver *r = first_alarm; r; r = r->next_alarm: + if r->owner: + r->owner->unrun () + for unsigned i = 0; i < 32; ++i: + if arch_interrupt_receiver[i] && arch_interrupt_receiver[i]->owner: + arch_interrupt_receiver[i]->owner->unrun () + // If a log capability is registered, run its owner. + if dbg_cap && dbg_cap->target->owner: + dbg_cap->target->owner->run () + // Use the (now running) log thread to display the message. + dbg_log (message) + dbg_log_char ('\n') + else: + while true: + dbg_send (n) diff --git a/schedule.ccp b/schedule.ccp index f64d444..8a62a9c 100644 --- a/schedule.ccp +++ b/schedule.ccp @@ -22,6 +22,7 @@ static void run_thread (Thread *thread): thread->schedule_next = first_scheduled if thread->schedule_next: thread->schedule_next->schedule_prev = thread + thread->schedule_prev = NULL first_scheduled = thread static void unrun_thread (Thread *thread): @@ -70,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 - // Fall through to let alarm be set to ~0, so the next wait will be infinitely long again. + return --recv->alarm_count void Thread::wait (): @@ -83,13 +84,16 @@ void Thread::wait (): return void schedule (): - Thread *old = current if current: current = current->schedule_next if !current: current = first_scheduled - if !current: - current = &idle + +void unschedule (): + Thread *old = current + schedule () + if old == current: + current = NULL void timer_interrupt (): Receiver *recv, *next