From d97f1a4ff2d8a44e855ad5fc5b47c2962ec762e5 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sat, 26 Dec 2009 14:17:06 +0100 Subject: [PATCH] bug hunting --- .gitignore | 12 +++ Makefile | 2 +- alloc.ccp | 1 + boot-programs/buzzer.ccp | 1 + boot-programs/init.ccp | 18 +++- boot-programs/lcd.ccp | 124 +++++++++++++++++++++---- boot-programs/metronome.ccp | 1 + boot-programs/nanonote-gpio.ccp | 1 + boot-programs/udc.ccp | 137 +++++++++++++++++++--------- devices.hhp | 18 +++- invoke.ccp | 2 + iris.hhp | 2 +- kernel.hhp | 3 + memory.ccp | 12 ++- mips/arch.ccp | 3 + mips/init.ccp | 14 ++- mips/interrupts.ccp | 12 ++- mips/nanonote/Makefile.arch | 10 +- mips/nanonote/server/Makefile.am | 3 + mips/nanonote/server/usb-server.ccp | 29 +++++- mips/nanonote/threadlist.S | 5 +- mips/trendtac/threadlist.S | 1 + panic.ccp | 6 +- 23 files changed, 334 insertions(+), 83 deletions(-) diff --git a/.gitignore b/.gitignore index e534427..30160cd 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,15 @@ nanonote-gpio boot-programs/charset.data mips/nanonote/sdram-setup.raw nanonote-boot +mips/nanonote/server/.deps/ +mips/nanonote/server/Makefile +mips/nanonote/server/Makefile.in +mips/nanonote/server/aclocal.m4 +mips/nanonote/server/autom4te.cache/ +mips/nanonote/server/config.log +mips/nanonote/server/config.status +mips/nanonote/server/configure +mips/nanonote/server/depcomp +mips/nanonote/server/install-sh +mips/nanonote/server/missing +mips/nanonote/server/usb-server diff --git a/Makefile b/Makefile index 52d6f2d..62ea604 100644 --- a/Makefile +++ b/Makefile @@ -50,4 +50,4 @@ clean: rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES) .PHONY: clean -.PRECIOUS: iris.hh boot-programs/crt0.o +.PRECIOUS: iris.hh kernel.hh boot-programs/crt0.o diff --git a/alloc.ccp b/alloc.ccp index d2792b7..010325a 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -187,6 +187,7 @@ kThread *kMemory::alloc_thread (unsigned size): ret->sp = 0 kThread_arch_init (ret) ret->flags = 0 + ret->id = ~0 ret->schedule_prev = NULL ret->schedule_next = NULL ret->slots = size diff --git a/boot-programs/buzzer.ccp b/boot-programs/buzzer.ccp index d7dd37c..9dad386 100644 --- a/boot-programs/buzzer.ccp +++ b/boot-programs/buzzer.ccp @@ -53,6 +53,7 @@ enum codes: BUZZER = 32 Kernel::Num start (): + Kernel::schedule () map_tcu () DevBuzzer buzzer diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index 00aecc0..174c698 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -20,7 +20,7 @@ #include "iris.hh" static Keyboard sysreq -static Device kbd_dev, buz_dev +static Device kbd_dev, buz_dev, backlight_dev static unsigned slot // Event types. @@ -28,6 +28,7 @@ enum type: SYSREQ KBDDEV BUZDEV + BACKLIGHTDEV static void user_reply (Kernel::Cap target, unsigned dev): switch dev: @@ -91,6 +92,12 @@ static void setup (): reply.invoke () Kernel::free_cap (reply) break + case Setting::ID: + caps.set (BACKLIGHTDEV, arg.copy ()) + backlight_dev = Kernel::Cap (slot, BACKLIGHTDEV) + reply.invoke () + Kernel::free_cap (reply) + break default: kdebug ("unexpected device\n") break @@ -106,7 +113,7 @@ static void setup (): Kernel::free_cap (arg) continue Kernel::free_cap (arg) - if ++state == 4: + if ++state == 5: break // sysreq kdebug ("using sysreq\n") @@ -119,8 +126,13 @@ static void setup (): Kernel::free_cap (user) Kernel::Num start (): + Kernel::schedule () setup () kdebug ("init set up\n") + // claim backlight + kdebug ("claiming backlight\n") + Setting backlight = backlight_dev.create_user (Kernel::Cap ()) + backlight_dev.use (backlight) while true: Kernel::wait () switch Kernel::recv.protected_data.value (): @@ -129,8 +141,10 @@ Kernel::Num start (): kdebug ("\n\nSystem request ") if code & Keyboard::RELEASE: kdebug ("released.\n\n") + backlight.set (~0) else: kdebug ("pressed.\n\n") + backlight.set (0) break default: if Kernel::recv.data[0].l != Parent::GET_DEVICE: diff --git a/boot-programs/lcd.ccp b/boot-programs/lcd.ccp index 092fb9a..9bdb196 100644 --- a/boot-programs/lcd.ccp +++ b/boot-programs/lcd.ccp @@ -28,8 +28,12 @@ extern unsigned char const charset[127-32][6] #if defined (TRENDTAC) static unsigned h = 800, v = 480, fps = 60, Bpp = 2 +#define LOG_X_BASE 1 +#define LOG_Y_BASE 1 #elif defined (NANONOTE) static unsigned h = 320, v = 240, fps = 60, Bpp = 4 +#define LOG_X_BASE 0 +#define LOG_Y_BASE 0 #else #error unknown board #endif @@ -200,12 +204,12 @@ static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff, for unsigned r = 0; r < 8; ++r: LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = lookup[charset[ch][k] & (1 << r) ? 1 : 0] -static unsigned log_x = 1, log_y = 1 +static unsigned log_x = LOG_X_BASE, log_y = LOG_Y_BASE static void inc_logx (): if ++log_x >= h / 6: - log_x = 1 + log_x = LOG_X_BASE if ++log_y >= v / 8: - log_y = 1 + log_y = LOG_Y_BASE static void log_char (unsigned ch): switch ch: @@ -241,10 +245,9 @@ static void log_msg (): log_char ('\n') enum captype: - #ifdef TRENDTAC - LOG - #endif + LOG = 32 SET_EOF_CB + BACKLIGHT static unsigned spot (unsigned x, unsigned y, unsigned cx, unsigned cy): unsigned dx2 = (x - cx) * (x - cx) @@ -256,6 +259,7 @@ static unsigned spot (unsigned x, unsigned y, unsigned cx, unsigned cy): return ((l * l - d2 - 1) << 8) / (l * l) Kernel::Num start (): + Kernel::schedule () map_lcd () map_cpm () #ifdef NANONOTE @@ -300,32 +304,118 @@ Kernel::Num start (): __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") #endif + // Register the backlight device. + Kernel::Cap backlight = Kernel::my_receiver.create_capability (BACKLIGHT) + Kernel::my_parent.provide_device (backlight) + Kernel::Cap eof_cb bool have_eof = false + bool is_on = true + unsigned backlight_user = 0 + Kernel::Num current_backlight = 0 while true: Kernel::wait () //log_msg () - switch Kernel::recv.protected_data.l: - case IRQ_LCD: - lcd_clr_eof () - eof_cb.invoke () + switch Kernel::recv.protected_data.h: + case 0: + switch Kernel::recv.protected_data.l: + case IRQ_LCD: + lcd_clr_eof () + eof_cb.invoke () + have_eof = false + Kernel::free_cap (eof_cb) + break + #if defined (TRENDTAC) + case LOG: + log_char (Kernel::recv.data[0].l) + break + #endif + case BACKLIGHT: + switch Kernel::recv.data[0].l: + case Device::CREATE_USER: + Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (backlight_user++, BACKLIGHT)) + reply.invoke (0, 0, c.copy ()) + Kernel::free_cap (c) + Kernel::free_cap (reply) + break + case Device::DESTROY_USER: + Kernel::recv.reply.invoke () + break + case Device::USE: + Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap arg = Kernel::get_arg () + current_backlight = Kernel::my_receiver.get_protected (arg) + reply.invoke () + Kernel::free_cap (arg) + Kernel::free_cap (reply) + break + case Device::UNUSE: + Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap arg = Kernel::get_arg () + if current_backlight.value () == Kernel::my_receiver.get_protected (arg).value (): + current_backlight = 0 + reply.invoke () + Kernel::free_cap (arg) + Kernel::free_cap (reply) + break + default: + log_char ('@') + break + break + default: + log_char ('#') + log_num (Kernel::recv.protected_data) + log_char ('\n') + break + break + case BACKLIGHT: + if current_backlight.value () != Kernel::recv.protected_data.value (): + log_char ('&') + log_num (current_backlight) + log_num (Kernel::recv.protected_data) + log_char ('\n') + break + switch Kernel::recv.data[0].l: + case Setting::SET: + // TODO + unsigned state = Kernel::recv.data[1].l + if !state: + #if defined (NANONOTE) + if is_on: + write_reg (BACKLIGHT1, 0x5e) + is_on = false + #else + #endif + else: + #if defined (NANONOTE) + if !is_on: + write_reg (BACKLIGHT1, 0x5f) + is_on = true + #else + #endif + Kernel::recv.reply.invoke () + break + case Setting::GET_RANGE: + Kernel::recv.reply.invoke (~0) + break + default: + log_char ('$') + break break case SET_EOF_CB: + Kernel::Cap reply = Kernel::get_reply () if have_eof: Kernel::free_cap (eof_cb) else: + Kernel::register_interrupt (IRQ_LCD) have_eof = true eof_cb = Kernel::get_arg () - Kernel::Cap reply = Kernel::get_reply () - Kernel::register_interrupt (IRQ_LCD) reply.invoke () Kernel::free_cap (reply) break - #ifdef TRENDTAC - case LOG: - log_char (Kernel::recv.data[0].l) - break - #endif default: log_char ('~') + log_num (Kernel::recv.protected_data) + log_char ('\n') break diff --git a/boot-programs/metronome.ccp b/boot-programs/metronome.ccp index 010b043..208a168 100644 --- a/boot-programs/metronome.ccp +++ b/boot-programs/metronome.ccp @@ -20,6 +20,7 @@ #include "keys.hh" Kernel::Num start (): + Kernel::schedule () kdebug ("metronome started\n") Buzzer buzzer = Kernel::my_parent.get_device () Keyboard kbd = Kernel::my_parent.get_device () diff --git a/boot-programs/nanonote-gpio.ccp b/boot-programs/nanonote-gpio.ccp index 50b1510..a0e3ba8 100644 --- a/boot-programs/nanonote-gpio.ccp +++ b/boot-programs/nanonote-gpio.ccp @@ -195,6 +195,7 @@ enum codes: PWR Kernel::Num start (): + Kernel::schedule () map_gpio () DevKbd kbd diff --git a/boot-programs/udc.ccp b/boot-programs/udc.ccp index 06722b5..60040f9 100644 --- a/boot-programs/udc.ccp +++ b/boot-programs/udc.ccp @@ -154,6 +154,9 @@ class Udc: bool vendor (Setup *s) bool get_descriptor (unsigned type, unsigned idx, unsigned len) bool handle_setup (Setup *s) + char log_buffer[1000] + unsigned log_buffer_size + unsigned log_buffer_start public: void init () void log (unsigned c) @@ -193,6 +196,8 @@ void Udc::init (): s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } } s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } } s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } } + log_buffer_size = 0 + log_buffer_start = 0 // Disconnect from the bus and don't try to get high-speed. UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB) @@ -210,31 +215,41 @@ void Udc::init (): // enable interrupts on endpoint 0. UDC_INTRINE |= 1 << 0 UDC_INDEX = 0 - // Wait a bit and connect to the host. - Kernel::my_receiver.sleep (10) + // Connect to the host. UDC_POWER |= UDC_POWER_SOFTCONN bool Udc::vendor (Setup *s): - if s->request_type & 0x80: + if !(s->request_type & 0x80): + return true + if s->request == 10: + static char b[2] + ptr = b + size = s->length < 2 ? s->length : 2 + b[0] = '#' + if log_buffer_start == log_buffer_size: + size = 1 + else: + b[1] = log_buffer[log_buffer_start++] + if log_buffer_start == log_buffer_size: + log_buffer_start = 0 + log_buffer_size = 0 + else: static char const *name = "Reboot" ptr = name size = s->length < 6 ? s->length : 6 - state = TX rebooting = true - return true + state = TX return true bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): switch type: case Configuration::Type: - //kdebug ("config\n") if idx != 0: return false ptr = reinterpret_cast (&config_descriptor) size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor)) break case Device::Type: - //kdebug ("device\n") if idx != 0: return false ptr = reinterpret_cast (&device_descriptor) @@ -249,7 +264,6 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): return false // The 6 is an arbitrary number, except that String <6> in instantiated already. case String <6>::Type: - //kdebug ("string\n") switch idx: case 0: ptr = reinterpret_cast (&s_langs) @@ -272,17 +286,6 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): return true bool Udc::handle_setup (Setup *s): - //kdebug ("udc: setup: type=") - //kdebug_num (s->request_type, 2) - //kdebug ("; request=") - //kdebug_num (s->request, 2) - //kdebug ("; value=") - //kdebug_num (s->value, 4) - //kdebug ("; index=") - //kdebug_num (s->index, 4) - //kdebug ("; length=") - //kdebug_num (s->length, 4) - //kdebug ("\n") switch s->request_type: case STANDARD_TO_DEVICE: switch s->request: @@ -333,7 +336,6 @@ bool Udc::handle_setup (Setup *s): void Udc::interrupt (): unsigned i = UDC_INTRUSB if i & UDC_INTR_RESET: - //kdebug ("udc: reset\n") state = IDLE return i = UDC_INTRIN @@ -357,24 +359,18 @@ void Udc::interrupt (): packet.d[1] = UDC_FIFO (0) UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY if !handle_setup (&packet.s): - //kdebug ("stall 1\n") csr |= UDC_CSR0_SENDSTALL break if size == 0: return // Fall through. case TX: - //kdebug ("udc: send next:") unsigned i for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4: - //for unsigned i = 0; i < 4; ++i: - //kdebug_num (ptr[i], 2) UDC_FIFO (0) = *(unsigned *)ptr ptr += 4 for ; size > 0 && i < max_packet_size0; ++i, --size: - //kdebug_num (*ptr, 2) UDC_FIFO8 (0) = *ptr++ - //kdebug ("\n") if i == max_packet_size0: csr |= UDC_CSR0_INPKTRDY else: @@ -383,19 +379,19 @@ void Udc::interrupt (): break case RX: // Not supported. - //kdebug ("stall 2\n") csr |= UDC_CSR0_SVDOUTPKTRDY | UDC_CSR0_SENDSTALL state = IDLE break UDC_CSR0 = csr void Udc::log (unsigned c): - kdebug ("udc: log ") - kdebug_char (c) - kdebug ("\n") + if log_buffer_size >= sizeof (log_buffer): + return + log_buffer[log_buffer_size++] = c enum pdata: LOG = 32 + FS Kernel::Num start (): map_udc () @@ -403,20 +399,77 @@ Kernel::Num start (): map_cpm () Udc udc - udc.init () Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG) __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") + udc.init () Kernel::register_interrupt (IRQ_UDC) + Device fs_dev = Kernel::my_receiver.create_capability (FS) + Kernel::my_parent.provide_device (fs_dev) + Kernel::Num current_user = 0 + unsigned next_user while true: Kernel::wait () - switch Kernel::recv.protected_data.l: - case IRQ_UDC: - udc.interrupt () - Kernel::register_interrupt (IRQ_UDC) - break - case LOG: - udc.log (Kernel::recv.data[0].l) - break - default: - udc.log ('~') - break + switch Kernel::recv.protected_data.h: + case 0: + switch Kernel::recv.protected_data.l: + case IRQ_UDC: + udc.interrupt () + Kernel::register_interrupt (IRQ_UDC) + break + case LOG: + udc.log (Kernel::recv.data[0].l) + break + case FS: + switch Kernel::recv.data[0].l: + case Device::CREATE_USER: + Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, FS)) + reply.invoke (0, 0, c.copy ()) + Kernel::free_cap (c) + Kernel::free_cap (reply) + break + case Device::DESTROY_USER: + Kernel::Cap reply = Kernel::get_reply () + reply.invoke () + Kernel::free_cap (reply) + break + case Device::USE: + Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap arg = Kernel::get_arg () + current_user = Kernel::my_receiver.get_protected (arg) + reply.invoke () + Kernel::free_cap (reply) + Kernel::free_cap (arg) + break + case Device::UNUSE: + Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap arg = Kernel::get_arg () + if current_user.value () == Kernel::my_receiver.get_protected (arg).value (): + current_user = 0 + reply.invoke () + Kernel::free_cap (reply) + Kernel::free_cap (arg) + break + break + default: + udc.log ('~') + char digit[] = "0123456789abcdef" + for unsigned i = 0; i < 8; ++i: + udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf]) + udc.log ('\n') + break + case FS: + if current_user.value () != Kernel::recv.protected_data.value (): + break + switch Kernel::recv.data[0].l: + case Directory::GET_SIZE: + case Directory::GET_NAME: + case Directory::GET_FILE_RO: + case Directory::LOCK_RO: + case Directory::UNLOCK_RO: + Kernel::recv.reply.invoke () + break + case Directory::GET_FILE_INFO: + default: + Kernel::recv.reply.invoke (~0) + break diff --git a/devices.hhp b/devices.hhp index 9c32f46..dc6e53c 100644 --- a/devices.hhp +++ b/devices.hhp @@ -171,6 +171,7 @@ struct Display : public Kernel::Cap: CREATE_FB USE_FB GET_INFO + SET_STATE ID // Register an end-of-frame callback. // At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events. @@ -192,6 +193,19 @@ struct Display : public Kernel::Cap: // TODO: Interface is to be designed. +// Numeric setting, such as a display backlight. +struct Setting : public Kernel::Cap: + Setting (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): + enum request: + SET = Display::ID + GET_RANGE + ID + // Set a new value. + void set (unsigned value): + call (CAP_MASTER_DIRECT | SET, value) + // Get the maximum value for this setting. Using a higher value with SET gives undefined results. + unsigned get_range (): + return call (CAP_MASTER_DIRECT | GET_RANGE).l // File system interface. // filesystem-related interfaces: directory, stream, seekable. @@ -202,7 +216,7 @@ struct Display : public Kernel::Cap: struct Directory : public Kernel::Cap: Directory (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - GET_SIZE = Display::ID + GET_SIZE = Setting::ID GET_NAME GET_FILE_RO GET_FILE_INFO @@ -254,7 +268,7 @@ struct WDirectory : public Directory: call (CAP_MASTER_DIRECT | LOCK) // Unlock the directory. Write operations can only be done when the directory is locked. void unlock (): - call (CAP_MASTER_DIRECT | LOCK) + call (CAP_MASTER_DIRECT | UNLOCK) // Stream interface. struct Stream : public Kernel::Cap: diff --git a/invoke.ccp b/invoke.ccp index 459fbb2..b9c0110 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -49,6 +49,8 @@ static void log_message (char const *prefix, unsigned target, unsigned pdata, kC void kThread::raise (unsigned code, unsigned data): dpanic (code, "raise") dbg_log ("raise ") + dbg_log_num (old_current->id, 2) + dbg_log_char (':') dbg_log_num ((unsigned)old_current) dbg_log_char ('/') if code < Kernel::NUM_EXCEPTION_CODES: diff --git a/iris.hhp b/iris.hhp index dc8df02..d13dd83 100644 --- a/iris.hhp +++ b/iris.hhp @@ -492,7 +492,7 @@ namespace Kernel: void Receiver::sleep (unsigned value): my_receiver.set_alarm (value) - wait () + Cap ().call () // The start function has this prototype (there is no main function). Kernel::Num start () diff --git a/kernel.hhp b/kernel.hhp index 6f0ef37..e375628 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -120,6 +120,9 @@ struct kThread : public kObject: unsigned recv_reply, recv_arg // caps is an array of slots pointers to kCapses. unsigned slots + #ifndef NDEBUG + unsigned id + #endif struct caps_store: _slot_data prev, next kCapsP caps diff --git a/memory.ccp b/memory.ccp index f2d61c7..ab556e9 100644 --- a/memory.ccp +++ b/memory.ccp @@ -10,7 +10,7 @@ static void clear_page (unsigned page, unsigned num = 1): if *((unsigned *)page) != 0 || ((unsigned *)page)[(num << (PAGE_BITS - 2)) - 1] != 0: dpanic (0, "clear_page didn't work") -#if 0 +#if 1 static unsigned free_begin static unsigned free_end @@ -33,10 +33,12 @@ void phys_free (unsigned page, unsigned num): // Not supported. #ifndef NDEBUG -void check_impl (kObject *o, unsigned num, char const *msg): - for ; o; o = o->next: - if (unsigned)o >= (unsigned)free_begin && (unsigned)o < (unsigned)free_end: - panic (num, msg) +/*void check_impl (kObject *o, unsigned num, char const *msg): +// for ; o; o = (kObject *)o->next: +// if (unsigned)o >= (unsigned)free_begin && (unsigned)o < (unsigned)free_end: +*/ // panic (num, msg) +bool check_free (kObject *o, unsigned size): + return true void print_free (): #endif #else diff --git a/mips/arch.ccp b/mips/arch.ccp index 4da578c..34427ee 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -166,6 +166,9 @@ static void tlb_reset (unsigned address, unsigned asid, unsigned value): __asm__ volatile ("tlbwi") static void free_page (arch_page_table *t, arch_page *p): + dbg_log ("free page ") + dbg_log_num ((unsigned)p) + dbg_log_char ('\n') if p->prev_mapped: p->prev_mapped->next_mapped = p->next_mapped else: diff --git a/mips/init.ccp b/mips/init.ccp index 59b0131..1a6bde4 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -119,6 +119,9 @@ static void init_threads (): kMemory *mem = top_memory.alloc_memory () assert (mem) kThread *thread = mem->alloc_thread (NUM_SLOTS) + #ifndef NDEBUG + thread->id = i + #endif kPage **pages = (kPage **)mem->zalloc () Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i] for unsigned j = 0; j < SELFMAG; ++j: @@ -150,12 +153,21 @@ static void init_threads (): //bool executable = shdr->sh_flags & SHF_EXEC_INSTR if shdr->sh_type != SHT_NOBITS: unsigned file_offset = shdr->sh_offset >> PAGE_BITS - if ((file_offset + shdr->sh_size) >> PAGE_BITS) >= (PAGE_SIZE >> 2): + if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2): panic (0x87446809, "initial thread too large") return for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS unsigned idx = file_offset + section_offset + kPage *page = mem->get_mapping (p, &readonly) + if page: + if !pages[idx]: + panic (0, "multiple pages mapped to one address in initial file") + return + if pages[idx]->frame != page->frame: + panic (0, "different pages mapped to one address in intitial file") + return + continue if !pages[idx]: pages[idx] = mem->alloc_page () pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS) diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 4d333e1..d596b22 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -25,16 +25,15 @@ void arch_flush_cache (): __asm__ volatile ("lw $k0, %0; cache 0, 0($k0); cache 1, 0($k0)" :: "m"(line)) static void handle_exit (): + --dbg_code.h // Set must_wait to false, so random threads are not set to waiting when the kernel invokes something (such as a dbg_cap). must_wait = false if !current || (current == &idle): schedule () if !current: current = &idle - if (current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) != Kernel::Thread::RUNNING: - panic (current->flags, "non-scheduled thread running") - if !current: - current = &idle + //if (current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) != Kernel::Thread::RUNNING: + //panic (current->flags, "non-scheduled thread running") if old_current == current: return //dbg_send ((unsigned)current >> 12, 3) @@ -64,6 +63,7 @@ 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. kThread *tlb_refill (): + ++dbg_code.h old_current = current if !directory: unsigned addr @@ -89,6 +89,7 @@ kThread *tlb_refill (): /// An interrupt which is not an exception has occurred. kThread *interrupt (): + ++dbg_code.h old_current = current unsigned ipr = INTC_IPR for unsigned i = 0; i < 32; ++i: @@ -155,6 +156,7 @@ static void arch_invoke (): /// A general exception has occurred. kThread *exception (): + ++dbg_code.h old_current = current unsigned cause cp0_get (CP0_CAUSE, cause) @@ -225,6 +227,7 @@ kThread *exception (): if !dbg_cap.valid (): dpanic (0, "no log capability provided") break + dbg_log ("log capability registered.\n") break dbg_log_char (current->arch.a[1]) #endif @@ -287,6 +290,7 @@ kThread *exception (): /// There's a cache error. Big trouble. Probably not worth trying to recover. kThread *cache_error (): + ++dbg_code.h panic (0x33333333, "cache error") old_current = current handle_exit () diff --git a/mips/nanonote/Makefile.arch b/mips/nanonote/Makefile.arch index bcaa77c..0062121 100644 --- a/mips/nanonote/Makefile.arch +++ b/mips/nanonote/Makefile.arch @@ -18,7 +18,7 @@ load = 0x80000000 ARCH_CXXFLAGS = -DNUM_THREADS=6 -ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL +ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE #-DUSE_SERIAL CROSS = mipsel-linux-gnu- OBJDUMP = $(CROSS)objdump junk = mdebug.abi32 reginfo comment pdr @@ -30,12 +30,14 @@ boot_sources = mips/init.cc mips/nanonote/board.cc arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh boot_threads = init udc nanonote-gpio buzzer metronome lcd -test: iris.raw mips/nanonote/server/usb-server +test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw echo "reboot 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')" | nc localhost 5050 .PHONY: test mips/nanonote/server/usb-server: mips/nanonote/server/usb-server.ccp mips/nanonote/server/Makefile.am mips/nanonote/server/configure.ac $(MAKE) -C mips/nanonote/server + echo "shutdown" | nc localhost 5050 + sleep 1 %.elf: %.o $(LD) $(LDFLAGS) -o $@ $< @@ -66,6 +68,10 @@ boot-programs/charset.data: boot-programs/charset iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources)) $(LD) $(LDFLAGS) $^ -o $@ +server: + while mips/nanonote/server/usb-server ; do : ; done + ARCH_CLEAN_FILES = $(boot_sources) $(addsuffix .elf,$(boot_threads)) $(arch_headers) devices.hh keys.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw .PRECIOUS: mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh +.PHONY: server diff --git a/mips/nanonote/server/Makefile.am b/mips/nanonote/server/Makefile.am index f75cd03..735585b 100644 --- a/mips/nanonote/server/Makefile.am +++ b/mips/nanonote/server/Makefile.am @@ -27,4 +27,7 @@ PYPP = /usr/bin/pypp %.cc: %.ccp $(PYPP) --name $< < $< > $@ +run: + $(top_buiddir)/usb-server + BUILT_SOURCES = usb-server.cc diff --git a/mips/nanonote/server/usb-server.ccp b/mips/nanonote/server/usb-server.ccp index bf84445..7b0ef35 100644 --- a/mips/nanonote/server/usb-server.ccp +++ b/mips/nanonote/server/usb-server.ccp @@ -54,15 +54,34 @@ struct data: VR_FLUSH_CACHES = 3 VR_PROGRAM_START1 = 4 VR_PROGRAM_START2 = 5 + POLL = 10 void request (requests num, unsigned data = 0) void send_file (unsigned address, unsigned size, char const *data) void reboot (): - // This always fails, because the device doesn't answer. However, that means there's nothing wrong, so don't complain. - usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, VR_GET_CPU_INFO, 0, 0, NULL, 8, timeout) + char buffer[8] + if usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, VR_GET_CPU_INFO, 0, 0, buffer, 8, timeout) < 0: + std::cerr << "unable to send reboot message to device: " << usb_strerror () << std::endl usb_release_interface (handle, 0) usb_close (handle) handle = NULL void get_device (unsigned vendor, unsigned product, unsigned tries) + void poll () + +void data::poll (): + while true: + char buffer[2] + int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, buffer, 8, timeout) + if s < 1 || s > 2 || buffer[0] != '#': + std::cerr << "unable to send poll message to device: " << usb_strerror () << std::endl + usb_release_interface (handle, 0) + usb_close (handle) + handle = NULL + return + if s != 1: + std::cout << buffer[1] << std::flush + else: + break + (shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll)) struct client : public shevek::server ::connection: static Glib::RefPtr create (): @@ -75,6 +94,9 @@ struct client : public shevek::server ::connection: unsigned entry if l ("reboot %x%", entry): get_server ()->data ()->boot (entry) + else if l ("shutdown%"): + std::cerr << "shutting down\n" + shevek::end_loop () else: out->write ("invalid command\n") if !keep: @@ -112,10 +134,11 @@ void data::get_device (unsigned vendor, unsigned product, unsigned tries): continue handle = usb_open (dev) if usb_claim_interface (handle, 0) < 0: - std::cerr << "unable to claim interface\n" + std::cerr << "unable to claim interface: " << usb_strerror () << "\n" usb_close (handle) handle = NULL continue + (shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll)) return if i + 1 < tries: //std::cerr << "failed to find device, still trying...\n" diff --git a/mips/nanonote/threadlist.S b/mips/nanonote/threadlist.S index e970c7b..5127a30 100644 --- a/mips/nanonote/threadlist.S +++ b/mips/nanonote/threadlist.S @@ -25,7 +25,7 @@ thread0: .balign 0x1000 thread1: - .incbin "lcd.elf" + .incbin "udc.elf" .balign 0x1000 thread2: @@ -41,8 +41,9 @@ thread4: .balign 0x1000 thread5: - .incbin "udc.elf" + .incbin "lcd.elf" + .balign 0x1000 thread6: // Everything from here may be freed after kernel initialization. diff --git a/mips/trendtac/threadlist.S b/mips/trendtac/threadlist.S index 417f869..d601a89 100644 --- a/mips/trendtac/threadlist.S +++ b/mips/trendtac/threadlist.S @@ -31,6 +31,7 @@ thread1: thread2: .incbin "gpio.elf" + .balign 0x1000 thread3: // Everything from here may be freed after kernel initialization. diff --git a/panic.ccp b/panic.ccp index 68be030..f3020d6 100644 --- a/panic.ccp +++ b/panic.ccp @@ -25,7 +25,7 @@ void dbg_log_char (unsigned ch): UART0_TDR = ch #else void dbg_log_char (unsigned ch): - if !dbg_cap.valid (): + if !dbg_cap.valid () || dbg_code.l: return kCapability::Context c c.data[0] = ch @@ -63,6 +63,8 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag #endif // Use the (now running) log thread to display the message. dbg_log ("Panic: caller = ") + dbg_log_num (old_current->id, 2) + dbg_log (":") dbg_log_num ((unsigned)old_current) if old_current: dbg_log_char ('@') @@ -75,6 +77,8 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag dbg_log (message) dbg_log_char ('/') dbg_log_num (n) + dbg_log_char (';') + dbg_log_num (dbg_code.h) dbg_log (" bad vaddr = ") unsigned a cp0_get (CP0_BAD_V_ADDR, a)