From 7dc6ecb0ea0d89ff2d5048efa4d4a4cf509d0b29 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sat, 16 Jan 2010 16:13:54 +0100 Subject: [PATCH] usb fs mostly working --- .gitignore | 2 +- boot-programs/crt0.ccp | 14 +- boot-programs/init.ccp | 185 ++++++++++---- boot-programs/udc.ccp | 384 ++++++++++++++++++++-------- devices.hhp | 6 +- invoke.ccp | 41 ++- iris.hhp | 8 +- kernel.hhp | 8 +- mips/arch.ccp | 6 +- mips/init.ccp | 2 +- mips/nanonote/Makefile.arch | 22 +- mips/nanonote/jz4740.hhp | 14 +- mips/nanonote/server/usb-server.ccp | 73 +++++- panic.ccp | 8 +- source/crt0.ccp | 8 +- source/lcd.ccp | 2 +- 16 files changed, 563 insertions(+), 220 deletions(-) diff --git a/.gitignore b/.gitignore index 5bf04dd..f4d612f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ uimage *.elf *.cc *.hh -boot-programs/charset.data +source/charset.data mips/nanonote/sdram-setup.raw nanonote-boot mips/nanonote/server/.deps/ diff --git a/boot-programs/crt0.ccp b/boot-programs/crt0.ccp index f0e7703..355fabb 100644 --- a/boot-programs/crt0.ccp +++ b/boot-programs/crt0.ccp @@ -38,17 +38,17 @@ namespace Kernel: __recv_data_t recv void print_caps (): - // Assume __caps to be 16. - bool used[16] - for unsigned i = 0; i < 16; ++i: + // Assume __caps to be 32. + bool used[32] + for unsigned i = 0; i < 32; ++i: used[i] = true unsigned num = 0 for list *i = __first_free_cap; i; i = i->next: used[i - __cap_admin] = false ++num - kdebug_num (num, 1) + kdebug_num (num, 2) kdebug (":") - for unsigned i = 0; i < 16; ++i: + for unsigned i = 0; i < 32; ++i: kdebug_char (used[i] ? '#' : '.') kdebug_char ('\n') @@ -77,6 +77,7 @@ namespace Kernel: if !__first_free_slot: // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. kdebug ("out of slots!\n") + Kernel::panic (0) return ~0 list *ret = __first_free_slot __first_free_slot = ret->next @@ -89,6 +90,7 @@ namespace Kernel: if !__first_free_cap: // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE kdebug ("out of capabilities!\n") + Kernel::panic (0) return Cap (0, CAP_NONE) list *ret = __first_free_cap __first_free_cap = ret->next @@ -116,7 +118,7 @@ extern "C": Kernel::recv.reply = Kernel::alloc_cap () Kernel::recv.arg = Kernel::alloc_cap () Kernel::Num ret = start () - Kernel::my_parent.invoke (~0, ret) + Kernel::my_parent.exit (ret) Kernel::my_memory.destroy (Kernel::my_thread) // The program no longer exists. If it somehow does, generate an address fault. while true: diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index 1c536cd..35b5bf9 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -21,13 +21,13 @@ #include #define NUM_SLOTS 4 -#define NUM_CAPS 16 +#define NUM_CAPS 32 static unsigned _free extern unsigned _end void init_alloc (): - _free = _end + _free = (unsigned)&_end char *alloc_space (unsigned pages): unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK @@ -37,18 +37,20 @@ char *alloc_space (unsigned pages): void *operator new[] (unsigned size): void *ret = (void *)_free size = (size + 3) & ~3 - unsigned rest = PAGE_SIZE - (size & ~PAGE_MASK) - if rest <= size: - _free += size - return ret - unsigned pages = ((size - rest) + PAGE_SIZE - 1) & PAGE_MASK - char *space = alloc_space (pages) - for unsigned p = 0; p < pages; ++p: - Kernel::Page page = Kernel::my_memory.create_page () - page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME) - Kernel::my_memory.map (page, (unsigned)&space[p << PAGE_BITS]) - Kernel::free_cap (page) + unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1) + if rest < size: + unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS + char *space = alloc_space (pages) + for unsigned p = 0; p < pages; ++p: + Kernel::Page page = Kernel::my_memory.create_page () + page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME) + Kernel::my_memory.map (page, (unsigned)&space[p << PAGE_BITS]) + Kernel::free_cap (page) _free += size + //kdebug_num ((unsigned)ret) + //kdebug ("+") + //kdebug_num (size) + //kdebug ("\n") return ret struct file: @@ -72,8 +74,8 @@ static Directory receive_devices (): String data Filesystem fs bool have_data = false, have_fs = false + Device fs_dev, data_dev for unsigned i = 0; i < 2; ++i: - Device dev Kernel::wait () if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE: kdebug ("Invalid bootstrap request.\n") @@ -83,23 +85,17 @@ static Directory receive_devices (): if have_data: kdebug ("duplicate device.\n") Kernel::panic (0) - dev = Kernel::get_arg () - have_data = true + data_dev = Kernel::get_arg () Kernel::recv.reply.invoke () - data = dev.create_user (Kernel::my_memory) - dev.use (data) - Kernel::free_cap (dev) + have_data = true break case Filesystem::ID: if have_fs: kdebug ("duplicate filesystem.\n") Kernel::panic (0) - dev = Kernel::get_arg () - have_fs = true - fs = dev.create_user (Kernel::my_memory) - dev.use (fs) - Kernel::free_cap (dev) + fs_dev = Kernel::get_arg () Kernel::recv.reply.invoke () + have_fs = true break default: kdebug ("unexpected device: ") @@ -107,35 +103,58 @@ static Directory receive_devices (): kdebug_char ('\n') Kernel::panic (0) // Initialize the root file system. + data = data_dev.create_user (Kernel::my_memory) + data_dev.use (data) + fs = fs_dev.create_user (Kernel::my_memory) + fs_dev.use (fs) Directory root = fs.use_device_ro (data.copy ()) Kernel::free_cap (data) Kernel::free_cap (fs) + Kernel::free_cap (data_dev) + Kernel::free_cap (fs_dev) return root // Make a list of all files. static void list_files (Directory root): Kernel::Num fullsize = root.get_size () if fullsize.h != 0: - kdebug ("Too many files in bootstrap directory.\n") + kdebug ("Too many files in bootstrap directory:") + kdebug_num (fullsize.h) + kdebug (":") + kdebug_num (fullsize.l) + kdebug ("\n") Kernel::panic (0) num_files = fullsize.l + kdebug ("files in directory: ") + kdebug_num (num_files) + kdebug ("\n") files = new file[num_files] - Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2) + Kernel::Caps caps = Kernel::my_memory.create_caps (num_files) unsigned slot = Kernel::alloc_slot () caps.use (slot) + Kernel::free_cap (caps) for unsigned i = 0; i < num_files; ++i: - Kernel::set_recv_arg (Kernel::Cap (slot, i * 2)) String n = root.get_name (i) n.get_chars (0, files[i].name) - Kernel::set_recv_arg (Kernel::Cap (slot, i * 2 + 1)) + kdebug ("file: ") + for unsigned j = 0; j < 16; ++j: + if files[i].name[j] != 0: + kdebug_char (files[i].name[j]) + kdebug_char ('\n') + Kernel::free_cap (n) + Kernel::set_recv_arg (Kernel::Cap (slot, i)) files[i].string = root.get_file_ro (i) Kernel::Num fullsize = files[i].string.get_size () if fullsize.h != 0: - kdebug ("initial file size too large.\n") + kdebug ("initial file size too large: ") + kdebug_num (fullsize.h) + kdebug (":") + kdebug_num (fullsize.l) + kdebug (".\n") Kernel::panic (0) files[i].size = fullsize.l - if max_pages < (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK: - max_pages = (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK + if max_pages < (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS: + max_pages = (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS // Sort the list of files. static bool is_less (file *f1, file *f2): @@ -163,11 +182,17 @@ static void sort (): static void run (file *f, bool priv): Kernel::Memory mem = top_memory.create_memory () - unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK + unsigned num_pages = (f->size + PAGE_SIZE - 1) >> PAGE_BITS for unsigned p = 0; p < num_pages; ++p: + kdebug_num (p) + kdebug ("/") + kdebug_num (num_pages) + kdebug ("\n") Kernel::set_recv_arg (Kernel::Cap (slot, p)) - mem.create_page () + Kernel::my_memory.create_page () + Kernel::Page (slot, p).set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING) f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p)) + kdebug_line () Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS]) Kernel::Thread thread = mem.create_thread (NUM_SLOTS) if priv: @@ -179,7 +204,11 @@ static void run (file *f, bool priv): Kernel::panic (0) return if header->e_ident[EI_CLASS] != ELFCLASS32: - kdebug ("invalid ELF class\n") + kdebug ("invalid ELF class:") + kdebug_num (header->e_ident[EI_CLASS]) + kdebug (" != ") + kdebug_num (ELFCLASS32) + kdebug ("\n") Kernel::panic (0) return if header->e_ident[EI_DATA] != ELFDATA2LSB: @@ -200,18 +229,24 @@ static void run (file *f, bool priv): return thread.set_pc (header->e_entry) thread.set_sp (0x80000000) + kdebug_line () for unsigned section = 0; section < header->e_shnum; ++section: + kdebug_line () Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize) if ~shdr->sh_flags & SHF_ALLOC: continue + kdebug_line () bool readonly = !(shdr->sh_flags & SHF_WRITE) //bool executable = shdr->sh_flags & SHF_EXEC_INSTR + kdebug_line () if shdr->sh_type != SHT_NOBITS: + kdebug_line () unsigned file_offset = shdr->sh_offset >> PAGE_BITS if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2): kdebug ("thread too large\n") Kernel::panic (0) return + kdebug_line () 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 @@ -220,22 +255,39 @@ static void run (file *f, bool priv): // The address already has a mapping; assume that it is correct. Kernel::free_cap (page) continue + Kernel::free_cap (page) page = mem.create_page () + page.set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING) Kernel::Page (slot, idx).share (page, 0) + kdebug ("mapping at ") + kdebug_num (p) + kdebug ("\n") if !mem.map (page, p, readonly): kdebug ("unable to map page\n") Kernel::panic (0) return Kernel::free_cap (page) + kdebug_line () else: + kdebug_line () if readonly: kdebug ("unwritable bss section\n") Kernel::panic (0) return + kdebug_line () for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: Kernel::Page page = mem.mapping ((void *)p) if Kernel::recv.data[0].l == Kernel::NO_ERROR: - // No error means there is no mapping. + // No error means there is a mapping. + Kernel::free_cap (page) + for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4: + if a >= shdr->sh_addr + shdr->sh_size: + break + if a < shdr->sh_addr: + continue + ((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0 + else: + Kernel::free_cap (page) page = mem.create_page () if Kernel::recv.data[0].l != Kernel::NO_ERROR: kdebug ("out of memory\n") @@ -250,56 +302,103 @@ static void run (file *f, bool priv): Kernel::panic (0) return Kernel::free_cap (page) - else: - for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4: - if a >= shdr->sh_addr + shdr->sh_size: - break - if a < shdr->sh_addr: - continue - ((unsigned *)&mapping[p])[(a & ~PAGE_MASK) >> 2] = 0 + kdebug_line () + kdebug_line () for unsigned p = 0; p <= num_pages; ++p: - mem.destroy (Kernel::Page (slot, p)) + Kernel::my_memory.destroy (Kernel::Page (slot, p)) + kdebug_line () Kernel::Page stackpage = mem.create_page () + kdebug_line () stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME) + kdebug_line () if Kernel::recv.data[0].l != Kernel::NO_ERROR || !mem.map (stackpage, 0x7ffff000): kdebug ("unable to map initial stack page\n") Kernel::panic (0) return + kdebug_line () Kernel::free_cap (stackpage) Kernel::Caps caps = mem.create_caps (NUM_CAPS) + kdebug_line () thread.use (caps, 0) thread.set_info (Kernel::Thread::A0, NUM_SLOTS) thread.set_info (Kernel::Thread::A1, NUM_CAPS) + kdebug_line () Kernel::Receiver receiver = mem.create_receiver () receiver.set_owner (thread.copy ()) Kernel::Cap call = receiver.create_call_capability () Kernel::Cap parent = Kernel::my_receiver.create_capability (++current_thread) + kdebug_line () caps.set (__receiver_num, receiver.copy ()) caps.set (__thread_num, thread.copy ()) caps.set (__memory_num, mem.copy ()) caps.set (__call_num, call.copy ()) caps.set (__parent_num, parent.copy ()) + kdebug_line () thread.run () + kdebug_line () Kernel::free_cap (receiver) Kernel::free_cap (thread) Kernel::free_cap (mem) Kernel::free_cap (call) Kernel::free_cap (parent) + kdebug_line () + Kernel::print_caps () + +static void dump_devices (): + kdebug ("String: ") + kdebug_num (String::ID, 3) + kdebug ("\nWString: ") + kdebug_num (WString::ID, 3) + kdebug ("\nDevice: ") + kdebug_num (Device::ID, 3) + kdebug ("\nParent: ") + kdebug_num (Parent::ID, 3) + kdebug ("\nKeyboard: ") + kdebug_num (Keyboard::ID, 3) + kdebug ("\nBuzzer: ") + kdebug_num (Buzzer::ID, 3) + kdebug ("\nDisplay: ") + kdebug_num (Display::ID, 3) + kdebug ("\nSetting: ") + kdebug_num (Setting::ID, 3) + kdebug ("\nDirectory: ") + kdebug_num (Directory::ID, 3) + kdebug ("\nWDirectory: ") + kdebug_num (WDirectory::ID, 3) + kdebug ("\nFilesystem: ") + kdebug_num (Filesystem::ID, 3) + kdebug ("\nStream: ") + kdebug_num (Stream::ID, 3) + kdebug ("\n") Kernel::Num start (): // Wait for the debugging device to be active, in case there is one. Kernel::schedule () + init_alloc () + dump_devices () top_memory = Kernel::get_top_memory () Directory root = receive_devices () root.lock_ro () + kdebug_line () list_files (root) + kdebug_line () sort () + kdebug_line () Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages) + kdebug ("max pages: ") + kdebug_num (max_pages) + kdebug ("\n") slot = caps.use () mapping = alloc_space (max_pages) for unsigned i = 0; i < num_files; ++i: + kdebug_line () run (&files[index[i]], files[index[i]].name[0] == '#') + kdebug_line () + kdebug_line () root.unlock_ro () + kdebug_line () Kernel::free_slot (slot) + kdebug_line () Kernel::my_memory.destroy (caps) + kdebug_line () return 0 diff --git a/boot-programs/udc.ccp b/boot-programs/udc.ccp index 167d458..bf13925 100644 --- a/boot-programs/udc.ccp +++ b/boot-programs/udc.ccp @@ -108,7 +108,7 @@ class Udc: u16 data[size]; } __attribute__ ((packed)) static unsigned const max_packet_size0 = 64 - static unsigned const max_packet_size_bulk = 512 + static unsigned const max_packet_size_bulk = 64 enum Requests: GET_STATUS = 0 CLEAR_FEATURE = 1 @@ -149,28 +149,29 @@ class Udc: State state char configuration unsigned size + unsigned rx_request char const *ptr unsigned cmd_code, cmd_arg bool rebooting bool vendor (Setup *s, unsigned cmd) bool get_descriptor (unsigned type, unsigned idx, unsigned len) bool handle_setup (Setup *s, unsigned cmd) + void irq_usb (unsigned cmd) + void irq_in (unsigned cmd) + void irq_out (unsigned cmd) char log_buffer[1000] unsigned log_buffer_size unsigned log_buffer_start - Kernel::Cap caller + Kernel::Cap caller, caller_arg bool have_caller + unsigned *page + unsigned *p + Kernel::Page buffer_page public: void init () void log (unsigned c) void interrupt (unsigned cmd) - void send (unsigned code, unsigned arg) - void set_caller (Kernel::Cap c): - if have_caller: - kdebug ("set_caller double-called\n") - Kernel::panic (0) - caller = c - have_caller = true + void send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg) Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 } Udc::my_config Udc::config_descriptor = { @@ -212,53 +213,43 @@ void Udc::init (): cmd_code = ~0 cmd_arg = 0 + // Use the space which is reserved for the framebuffer, because it will not be in use. + // Normally a normal new page should be allocated here, but new isn't implemented at this point. + page = (unsigned *)LCD_FRAMEBUFFER_BASE + p = page + buffer_page = Kernel::my_memory.create_page () + buffer_page.set_flags (Kernel::Page::FRAME | Kernel::Page::PAYING, Kernel::Page::FRAME | Kernel::Page::PAYING) + Kernel::my_memory.map (buffer_page, (unsigned)page) + // Disconnect from the bus and don't try to get high-speed. - UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB) + UDC_POWER = 0 + UDC_TESTMODE = 0 + UDC_INDEX = 0 state = IDLE configuration = 0 size = 0 // exit suspend mode by reading the interrupt register. cpm_start_udc () - unsigned i = UDC_INTRUSB // reset all pending endpoint interrupts. + unsigned i = UDC_INTRUSB i = UDC_INTRIN i = UDC_INTROUT // enable interrupt on bus reset. - UDC_INTRUSB = UDC_INTR_RESET + UDC_INTRUSBE = UDC_INTR_RESET // enable interrupts on endpoint 0. - UDC_INTRINE |= 1 << 0 - UDC_INDEX = 0 + UDC_INTRINE = 1 << 0 + // and on out endpoint 1. + UDC_INTROUTE = 1 << 1 // Wait a while. for unsigned w = 0; w < 10000; ++w: Kernel::schedule () // Connect to the host. - UDC_POWER |= UDC_POWER_SOFTCONN + UDC_POWER = UDC_POWER_SOFTCONN bool Udc::vendor (Setup *s, unsigned cmd): if !(s->request_type & 0x80): - switch s->request: - case Directory::GET_SIZE: - if !have_caller: - kdebug ("received size from server without a caller waiting\n") - Kernel::panic (0) - unsigned size_l = UDC_FIFO (0) - unsigned size_h = UDC_FIFO (0) - caller.invoke (Kernel::Num (size_l, size_h)) - have_caller = false - break - case Directory::GET_NAME: - if !have_caller: - kdebug ("received size from server without a caller waiting\n") - Kernel::panic (0) - unsigned n[4] - for unsigned i = 0; i < 4; ++i: - n[i] = UDC_FIFO (0) - caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3])) - have_caller = false - break - default: - kdebug ("invalid vendor request\n") - Kernel::panic (0) + kdebug ("data to device without size\n") + Kernel::panic (0) return true if s->request == 10: static unsigned b[2] @@ -267,6 +258,12 @@ bool Udc::vendor (Setup *s, unsigned cmd): if cmd_code != ~0: b[0] = cmd_code b[1] = cmd_arg + if cmd_code == Directory::LOCK_RO || cmd_code == Directory::UNLOCK_RO: + caller.invoke () + Kernel::free_cap (caller) + Kernel::free_cap (caller_arg) + have_caller = false + //kdebug ("(un)lock response\n") cmd_code = ~0 else: if log_buffer_start == log_buffer_size: @@ -286,12 +283,15 @@ bool Udc::vendor (Setup *s, unsigned cmd): state = TX return true -void Udc::send (unsigned code, unsigned arg): - if code != ~0: +void Udc::send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg): + if cmd_code != ~0: kdebug ("new code sent while old one wasn't finished.\n") Kernel::panic (0) cmd_code = code - cmd_arg = arg + cmd_arg = narg + caller = reply + caller_arg = arg + have_caller = true bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): switch type: @@ -355,6 +355,9 @@ bool Udc::handle_setup (Setup *s, unsigned cmd): break default: return false + UDC_OUTMAXP = 64 + UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF + UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF break case STANDARD_FROM_DEVICE: switch s->request: @@ -385,69 +388,165 @@ bool Udc::handle_setup (Setup *s, unsigned cmd): return false return true -void Udc::interrupt (unsigned cmd): - unsigned i = UDC_INTRUSB - if i & UDC_INTR_RESET: +void Udc::irq_usb (unsigned cmd): + // Reset. + state = IDLE + +void Udc::irq_in (unsigned cmd): + // Interrupt on endpoint 0. + unsigned csr = UDC_CSR0 + if csr & UDC_CSR0_SENTSTALL: + csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL) state = IDLE - return - i = UDC_INTRIN - if i & (1 << 0): - // Interrupt on endpoint 0. - UDC_INDEX = 0 - unsigned csr = UDC_CSR0 - if csr & UDC_CSR0_SENTSTALL: - csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL) - state = IDLE - if csr & UDC_CSR0_SETUPEND: - csr |= UDC_CSR0_SVDSETUPEND - state = IDLE - switch state: - case IDLE: - if rebooting: - Kernel::reboot () - if !(csr & UDC_CSR0_OUTPKTRDY): - return - union { unsigned d[2]; Setup s; } packet - packet.d[0] = UDC_FIFO (0) - packet.d[1] = UDC_FIFO (0) - UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY - if !handle_setup (&packet.s, cmd): - csr |= UDC_CSR0_SENDSTALL - break - if size == 0: - return - // Fall through. - case TX: - unsigned i - for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4: - UDC_FIFO (0) = *(unsigned *)ptr - ptr += 4 - for ; size > 0 && i < max_packet_size0; ++i, --size: - UDC_FIFO8 (0) = *ptr++ - if i == max_packet_size0: - csr |= UDC_CSR0_INPKTRDY - else: - state = IDLE - csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND + if csr & UDC_CSR0_SETUPEND: + csr |= UDC_CSR0_SVDSETUPEND + state = IDLE + switch state: + case IDLE: + if rebooting: + Kernel::reboot () + if !(csr & UDC_CSR0_OUTPKTRDY): + return + union { unsigned d[2]; Setup s; } packet + packet.d[0] = UDC_FIFO (0) + packet.d[1] = UDC_FIFO (0) + if !(packet.s.request_type & 0x80) && packet.s.length > 0: + // More data will follow; delay handling of packet. + state = RX + UDC_CSR0 = csr | UDC_CSR0_SVDOUTPKTRDY + rx_request = packet.s.request + return + UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY + if !handle_setup (&packet.s, cmd): + csr |= UDC_CSR0_SENDSTALL break - case RX: - // Not supported. - csr |= UDC_CSR0_SVDOUTPKTRDY | UDC_CSR0_SENDSTALL + if size == 0: + return + // Fall through. + case TX: + unsigned i + for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4: + UDC_FIFO (0) = *(unsigned *)ptr + ptr += 4 + for ; size > 0 && i < max_packet_size0; ++i, --size: + UDC_FIFO8 (0) = *ptr++ + if i == max_packet_size0: + csr |= UDC_CSR0_INPKTRDY + else: state = IDLE - break - UDC_CSR0 = csr - unsigned i = UDC_INTROUT - if i & (1 << 1): - // Interrupt on OUT endpoint 1. - UDC_INDEX = 1 - unsigned csr = UDC_OUTCSR - if !csr & UDC_CSR_OUTPKTRDY: - kdebug ("unrecognized interrupt on bulk out ep 1\n") - return - for unsigned i = 0; i < 16; ++i: - *p++ = UDC_FIFO (1) - if p - page == PAGE_SIZE: - // TODO: notify caller; reset buffer. + csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND + break + case RX: + // The protocol that is used doesn't allow large packets, so being here always means the entire packet is received. + switch rx_request & 0xff: + case Directory::GET_SIZE & 0xff: + if !have_caller: + kdebug ("received dir size from server without a caller waiting\n") + Kernel::panic (0) + unsigned size_l = UDC_FIFO (0) + unsigned size_h = UDC_FIFO (0) + caller.invoke (Kernel::Num (size_l, size_h)) + Kernel::free_cap (caller) + Kernel::free_cap (caller_arg) + have_caller = false + //kdebug ("get_size response\n") + break + case Directory::GET_NAME & 0xff: + if !have_caller: + kdebug ("received filename from server without a caller waiting\n") + Kernel::panic (0) + unsigned n[4] + for unsigned i = 0; i < 4; ++i: + n[i] = UDC_FIFO (0) + caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3])) + Kernel::free_cap (caller) + Kernel::free_cap (caller_arg) + //kdebug ("get_name response\n") + have_caller = false + break + case ::String::GET_SIZE & 0xff: + if !have_caller: + kdebug ("received string size from server without a caller waiting\n") + Kernel::panic (0) + unsigned size_l = UDC_FIFO (0) + unsigned size_h = UDC_FIFO (0) + caller.invoke (Kernel::Num (size_l, size_h)) + Kernel::free_cap (caller) + Kernel::free_cap (caller_arg) + have_caller = false + //kdebug ("get_filesize response\n") + break + case ::String::GET_CHARS & 0xff: + if !have_caller: + kdebug ("received string char data from server without a caller waiting\n") + Kernel::panic (0) + unsigned n[4] + for unsigned i = 0; i < 4; ++i: + n[i] = UDC_FIFO (0) + caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3])) + Kernel::free_cap (caller) + Kernel::free_cap (caller_arg) + have_caller = false + //kdebug ("get_chars response\n") + break + default: + kdebug ("invalid vendor request: ") + kdebug_num (rx_request) + kdebug ("\n") + Kernel::panic (0) + UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY + state = IDLE + break + UDC_CSR0 = csr + +void Udc::irq_out (unsigned cmd): + // Interrupt on OUT endpoint 1. + UDC_INDEX = 1 + if !have_caller: + kdebug ("received bulk data from server without a caller waiting\n") + Kernel::panic (0) + unsigned size = UDC_OUTCOUNT + unsigned csr = UDC_OUTCSR + //kdebug ("handling bulk interrupt for ") + //kdebug_num (csr) + //kdebug (" with ") + //kdebug_num (size) + //kdebug (" bytes.\n") + csr &= ~UDC_OUTCSR_OUTPKTRDY + for unsigned i = 0; i < size; i += 4: + *p++ = UDC_FIFO (1) + if p - page == PAGE_SIZE >> 2: + buffer_page.share (caller_arg, Kernel::Page::FORGET) + buffer_page.set_flags (Kernel::Page::FRAME, Kernel::Page::FRAME) + caller.invoke () + Kernel::free_cap (caller) + Kernel::free_cap (caller_arg) + have_caller = false + //kdebug ("bulk response\n") + p = page + UDC_OUTCSR = csr + UDC_INDEX = 0 + +void Udc::interrupt (unsigned cmd): + while true: + unsigned usb = UDC_INTRUSB + unsigned in = UDC_INTRIN + unsigned out = UDC_INTROUT + if !(usb & 4) && !(in & 1) && !(out & 2): + break + //kdebug ("interrupt: ") + //kdebug_num (usb, 1) + //kdebug ("/") + //kdebug_num (in, 1) + //kdebug ("/") + //kdebug_num (out, 1) + //kdebug ("\n") + if usb & 4: + irq_usb (cmd) + if in & 1: + irq_in (cmd) + if out & 2: + irq_out (cmd) void Udc::log (unsigned c): if log_buffer_size >= sizeof (log_buffer): @@ -459,6 +558,8 @@ enum pdata: FS DATA DIRECTORY + FILE + NAME Kernel::Num start (): map_udc () @@ -466,18 +567,23 @@ Kernel::Num start (): map_cpm () Udc udc - Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG) - __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") + //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) + Device data_dev = Kernel::my_receiver.create_capability (DATA) + Kernel::my_parent.provide_device (fs_dev.copy ()) + Kernel::my_parent.provide_device (data_dev.copy ()) + Kernel::free_cap (fs_dev) + Kernel::free_cap (data_dev) unsigned data_current_user = 0, fs_current_user = 0 unsigned next_user unsigned state = 0 while true: Kernel::wait () Kernel::Cap reply = Kernel::get_reply () + Kernel::Cap arg = Kernel::get_arg () switch Kernel::recv.protected_data.h: case 0: switch Kernel::recv.protected_data.l: @@ -489,10 +595,10 @@ Kernel::Num start (): udc.log (Kernel::recv.data[0].l) break case FS: - Device::host (FS, fs_current_user, reply) + Device::host (FS, fs_current_user, reply, arg) continue case DATA: - Device::host (DATA, data_current_user, reply) + Device::host (DATA, data_current_user, reply, arg) continue default: udc.log ('~') @@ -501,19 +607,22 @@ Kernel::Num start (): udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf]) udc.log ('\n') break + break case DATA: if data_current_user != Kernel::recv.protected_data.l: break switch Kernel::recv.data[0].l: - case String::GET_SIZE: - case String::GET_CHARS: + case ::String::GET_SIZE: + case ::String::GET_CHARS: reply.invoke (0) Kernel::free_cap (reply) + Kernel::free_cap (arg) continue - case String::GET_PAGE: + case ::String::GET_PAGE: default: reply.invoke (Kernel::ERR_INVALID_OPERATION) Kernel::free_cap (reply) + Kernel::free_cap (arg) continue break case FS: @@ -526,30 +635,79 @@ Kernel::Num start (): reply.invoke (0, 0, dir.copy ()) Kernel::free_cap (dir) Kernel::free_cap (reply) + Kernel::free_cap (arg) continue default: reply.invoke (Kernel::ERR_INVALID_OPERATION) Kernel::free_cap (reply) + Kernel::free_cap (arg) continue + break case DIRECTORY: switch Kernel::recv.data[0].l: - case Directory::GET_SIZE: case Directory::GET_NAME: + Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, NAME)) + reply.invoke (0, 0, name.copy ()) + Kernel::free_cap (name) + Kernel::free_cap (reply) + Kernel::free_cap (arg) + continue + case Directory::GET_SIZE: case Directory::LOCK_RO: case Directory::UNLOCK_RO: state = Kernel::recv.data[0].l if Kernel::recv.data[1].h != 0: kdebug ("index out of supported range\n") Kernel::panic (0) - udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l) - Kernel::free_cap (reply) + udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l, reply, arg) continue case Directory::GET_FILE_RO: - //TODO + if Kernel::recv.data[1].h != 0: + kdebug ("index out of supported range\n") + Kernel::panic (0) + //kdebug ("sending file\n") + Kernel::Cap file = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, FILE)) + reply.invoke (0, 0, file.copy ()) + Kernel::free_cap (file) + Kernel::free_cap (reply) + Kernel::free_cap (arg) + continue case Directory::GET_FILE_INFO: default: reply.invoke (Kernel::ERR_INVALID_OPERATION) Kernel::free_cap (reply) + Kernel::free_cap (arg) + continue + break + case FILE: + switch Kernel::recv.data[0].l: + case ::String::GET_SIZE: + case ::String::GET_CHARS: + case ::String::GET_PAGE: + udc.send (Kernel::recv.data[0].l | ((Kernel::recv.data[1].l >> PAGE_BITS) << 16), Kernel::recv.protected_data.l, reply, arg) + continue + default: + reply.invoke (Kernel::ERR_INVALID_OPERATION) + Kernel::free_cap (reply) + Kernel::free_cap (arg) + continue + break + case NAME: + switch Kernel::recv.data[0].l: + case ::String::GET_SIZE: + reply.invoke (16) + Kernel::free_cap (reply) + Kernel::free_cap (arg) + continue + case ::String::GET_CHARS: + state = Kernel::recv.data[0].l + udc.send (Directory::GET_NAME, Kernel::recv.protected_data.l, reply, arg) + continue + default: + reply.invoke (Kernel::ERR_INVALID_OPERATION) + Kernel::free_cap (reply) + Kernel::free_cap (arg) continue reply.invoke () Kernel::free_cap (reply) + Kernel::free_cap (arg) diff --git a/devices.hhp b/devices.hhp index 6412b80..262edcc 100644 --- a/devices.hhp +++ b/devices.hhp @@ -99,7 +99,7 @@ struct Device : public Kernel::Cap: void use (Kernel::Cap user): ocall (user, CAP_MASTER_DIRECT | USE) // Convenience function for threads implementing a device. - static void host (unsigned id, unsigned ¤t_user, Kernel::Cap &reply): + static void host (unsigned id, unsigned ¤t_user, Kernel::Cap &reply, Kernel::Cap &arg): static unsigned last_user switch Kernel::recv.data[0].l: case Device::CREATE_USER: @@ -111,20 +111,20 @@ struct Device : public Kernel::Cap: reply.invoke (0, 0, c.copy ()) Kernel::free_cap (c) Kernel::free_cap (reply) + Kernel::free_cap (arg) break case Device::DESTROY_USER: reply.invoke () Kernel::free_cap (reply) + Kernel::free_cap (arg) break case Device::USE: - Kernel::Cap arg = Kernel::get_arg () current_user = Kernel::my_receiver.get_protected (arg).l reply.invoke () Kernel::free_cap (reply) Kernel::free_cap (arg) break case Device::UNUSE: - Kernel::Cap arg = Kernel::get_arg () Kernel::Num p = Kernel::my_receiver.get_protected (arg) if p.h == id && current_user == p.l: current_user = 0 diff --git a/invoke.ccp b/invoke.ccp index 1cf22c5..f612118 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -210,6 +210,16 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte return case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK: if !c->arg.valid () || c->arg->target != receiver: + if !c->arg.valid (): + dbg_log ("invalid arg\n") + else: + dbg_log ("target: ") + dbg_log_num ((unsigned)c->arg->target) + dbg_log ("/") + dbg_log_num ((unsigned)c->arg->protected_data.h) + dbg_log (":") + dbg_log_num ((unsigned)c->arg->protected_data.l) + dbg_log ("\n") dpanic (0, "wrong argument for get_protected") reply_num (Kernel::ERR_INVALID_ARGUMENT) return @@ -289,6 +299,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_ kPage *ret = mem->alloc_page () if ret: reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs) + dbg_log ("page created\n") else: dpanic (0x33311992, "out of memory creating page") reply_num (Kernel::ERR_OUT_OF_MEMORY) @@ -574,10 +585,12 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da case Kernel::Page::SHARE & REQUEST_MASK: if !c->arg.valid (): // Cannot share without a target page. + dpanic (0, "no target page for share") reply_num (Kernel::ERR_INVALID_ARGUMENT) return if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: // FIXME: This makes it impossible to use a fake kPage capability. + dpanic (0, "share target is no page") reply_num (Kernel::ERR_INVALID_ARGUMENT) return kPage *t = (kPage *)c->arg->protected_data.l @@ -585,6 +598,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY: t->flags |= Kernel::Page::READONLY if !(page->flags & Kernel::Page::FRAME): + dpanic (0, "sharing nothing results in lost page") break if c->data[0].h & Kernel::Page::COPY: if ~t->flags & Kernel::Page::PAYING: @@ -606,7 +620,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da else: t->flags |= Kernel::Page::FRAME t->frame = raw_zalloc () - for unsigned i = 0; i <= (c->data[0].h & ~PAGE_MASK); i += 4: + for unsigned i = 0; i < PAGE_SIZE; i += 4: ((unsigned *)t->frame)[i >> 2] = d[i >> 2] else: if t != page: @@ -618,6 +632,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da kPage_arch_update_mapping (t) else: if t == page: + dpanic (0, "sharing page with itself") break if c->data[0].h & Kernel::Page::FORGET: if ~page->flags & Kernel::Page::SHARED: @@ -644,10 +659,13 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da page->share_prev = t if t->share_prev: t->share_prev->share_next = t + t->frame = page->frame + t->flags |= Kernel::Page::FRAME kPage_arch_update_mapping (t) break case Kernel::Page::SET_FLAGS & REQUEST_MASK: if cmd & Kernel::Page::READONLY: + dpanic (0, "setting page flags denied") reply_num (Kernel::ERR_WRITE_DENIED) return // Always refuse to set reserved flags. @@ -655,25 +673,27 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da // Remember the old flags. unsigned old = page->flags // Compute the new flags. - unsigned new_flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h) + page->flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h) // If we stop paying, see if the frame is still paid for. If not, free it. - if ~new_flags & old & Kernel::Page::PAYING: + if ~page->flags & old & Kernel::Page::PAYING: // Decrease the use counter in any case. page->address_space->unuse () if !page_check_payment (page): - new_flags &= ~Kernel::Page::FRAME + page->flags &= ~Kernel::Page::FRAME // If we start paying, increase the use counter. - if new_flags & ~old & Kernel::Page::PAYING: + if page->flags & ~old & Kernel::Page::PAYING: if !page->address_space->use(): + dpanic (0, "cannot pay for frame") // If it doesn't work, refuse to set the flag, and refuse to allocate a frame. - new_flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME) + page->flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME) + // However, if there already was a frame, keep it. if old & Kernel::Page::FRAME: - new_flags |= Kernel::Page::FRAME + page->flags |= Kernel::Page::FRAME // If we want a frame, see if we can get it. - if ~old & new_flags & Kernel::Page::FRAME: + if ~old & page->flags & Kernel::Page::FRAME: kPage *p for p = page; p; p = p->share_prev: if p->flags & Kernel::Page::PAYING: @@ -683,9 +703,10 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da if p->flags & Kernel::Page::PAYING: break if !p: - new_flags &= ~Kernel::Page::FRAME + dpanic (0, "cannot have frame without payer") + page->flags &= ~Kernel::Page::FRAME // If we can get the new frame, get it. - if ~old & new_flags & Kernel::Page::FRAME: + if ~old & page->flags & Kernel::Page::FRAME: page->frame = page->address_space->zalloc () kPage_arch_update_mapping (page) break diff --git a/iris.hhp b/iris.hhp index fced34a..4a7f12e 100644 --- a/iris.hhp +++ b/iris.hhp @@ -433,9 +433,9 @@ namespace Kernel: enum share_detail: // Operation details for PAGE_SHARE // Forget the source page during the operation. This makes it a move. - FORGET + FORGET = 1 // Make the target independent of the source (make a copy if needed). - COPY + COPY = 2 // Make the target unwritable. //READONLY: use the value from request. enum flag_values: @@ -452,7 +452,7 @@ namespace Kernel: // This is a read-only flag, saying if this is uncachable memory. UNCACHED = 0x20 void share (Cap target, unsigned flags): - ocall (target, CAP_MASTER_DIRECT | SHARE, flags) + ocall (target, Kernel::Num (CAP_MASTER_DIRECT | SHARE, flags)) unsigned get_flags (): return call (CAP_MASTER_DIRECT | GET_FLAGS).l bool set_flags (unsigned new_flags, unsigned mask): @@ -587,7 +587,7 @@ Kernel::Num start () #define kdebug(str) do { const char *s = (str); while (*s) { kdebug_char (*s); ++s; } } while (0) #define __stringify2(x) #x #define __stringify(x) __stringify2 (x) -#define kdebug_line() do { kdebug (__stringify (__LINE__)); kdebug_char ('\n'); } while (0) +#define kdebug_line() do { kdebug (__FILE__ ":"); kdebug (__PRETTY_FUNCTION__); kdebug (":"); kdebug (__stringify (__LINE__)); kdebug_char ('\n'); } while (0) static void kdebug_num (unsigned n, unsigned digits = 8): unsigned i diff --git a/kernel.hhp b/kernel.hhp index 0b3bc13..034f0d0 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -252,8 +252,8 @@ struct kMemory : public kObject: // Functions which can be called from assembly must not be mangled. extern "C": // Panic. n is sent over caps led. message is sent to dbg_caps (when in use). - #define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m)) - void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "") + #define panic(n, m) panic_impl ((n), __stringify (__LINE__), __PRETTY_FUNCTION__, (m)) + void panic_impl (unsigned n, char const *line, char const *name, char const *message = "") #ifndef NDEBUG EXTERN Kernel::Num dbg_code EXTERN kCapRef dbg_cap @@ -324,6 +324,8 @@ void kCapability::invoke (kCapability::Context *c): ::invoke (target, protected_data, c) #define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0) -#define dbg_log_line() do { dbg_log ("debug: "); dbg_log (__PRETTY_FUNCTION__); dbg_log (" line "); dbg_log_num (__LINE__); dbg_log_char ('\n'); } while (0) +#define __stringify2(x) #x +#define __stringify(x) __stringify2 (x) +#define dbg_log_line() do { dbg_log (__FILE__ ":"); dbg_log (__PRETTY_FUNCTION__); dbg_log (":"); dbg_log (__stringify (__LINE__)); dbg_log_char ('\n'); } while (0) #endif diff --git a/mips/arch.ccp b/mips/arch.ccp index d8e3c62..5554172 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -190,6 +190,7 @@ static void free_page (arch_page_table *t, arch_page *p): static unsigned make_entry_lo (kPage *page, bool readonly): //dbg_log_line () if !page->frame: + dbg_log ("not mapping because there is no frame\n") return 0 unsigned flags if page->flags & Kernel::Page::UNCACHED: @@ -204,7 +205,7 @@ static unsigned make_entry_lo (kPage *page, bool readonly): bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool readonly): //dbg_log_line () if address >= 0x80000000: - panic (0x32134293, "trying to map to kernel address") + dpanic (address, "trying to map to kernel address") return false address &= PAGE_MASK if !mem->arch.directory: @@ -258,6 +259,9 @@ bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool readonl mem->unmap ((kPage *)table[idx + 0x200], address) table[idx] = make_entry_lo (page, readonly) table[idx + 0x200] = (unsigned)p + dbg_log ("mapped at address ") + dbg_log_num (address) + dbg_log_char ('\n') p->mapping = address + readonly p->page = page p->next_mapped = page->arch.first_mapped diff --git a/mips/init.ccp b/mips/init.ccp index 1b4887b..2ad6593 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -23,7 +23,7 @@ #include #define NUM_SLOTS 4 -#define NUM_CAPS 16 +#define NUM_CAPS 32 static void init_idle (): // initialize idle task as if it is currently running. diff --git a/mips/nanonote/Makefile.arch b/mips/nanonote/Makefile.arch index ee27a7d..68946b4 100644 --- a/mips/nanonote/Makefile.arch +++ b/mips/nanonote/Makefile.arch @@ -31,11 +31,10 @@ arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh boot_threads = init udc programs = nanonote-gpio buzzer metronome lcd -all: test $(addsuffix .elf,$(addprefix fs/,$(programs))) +all: test -test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw +test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw $(addsuffix .elf,$(addprefix fs/,$(programs))) 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 @@ -59,10 +58,11 @@ mips/init.o: TARGET_FLAGS = -I/usr/include boot-programs/init.o: TARGET_FLAGS = -I/usr/include $(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I. $(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL +$(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL $(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh -boot-programs/lcd.o: boot-programs/charset.data +source/lcd.o: source/charset.data -boot-programs/charset.data: boot-programs/charset +source/charset.data: source/charset $< > $@ %.o:%.S Makefile Makefile.arch mips/arch.hh @@ -78,7 +78,15 @@ server: servers: while : ; do $(MAKE) server ; 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 +monitor: + stty -F /dev/ttyS0 raw 9600 + cat /dev/ttyS0 + +setup: + x-terminal-emulator -e make monitor + x-terminal-emulator -e make servers + +ARCH_CLEAN_FILES = $(boot_sources) $(addsuffix .elf,$(boot_threads)) $(arch_headers) devices.hh keys.hh mips/*.o mips/nanonote/*.o source/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 +.PHONY: test all monitor server servers setup diff --git a/mips/nanonote/jz4740.hhp b/mips/nanonote/jz4740.hhp index 1032865..1dbec69 100644 --- a/mips/nanonote/jz4740.hhp +++ b/mips/nanonote/jz4740.hhp @@ -1883,13 +1883,13 @@ void cdelay (unsigned cs): #define UDC_TESTMODE REG8 (UDC_BASE + 0x0f) // USB test mode 8-bit #define UDC_CSR0 REG8 (UDC_BASE + 0x12) // EP0 CSR 8-bit -#define UDC_INMAXP(ep) REG16 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x10) // EP1-2 IN Max Pkt Size 16-bit -#define UDC_INCSR(ep) REG16 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x12) // EP1-2 IN CSR LSB 8/16bit -#define UDC_INCSRH(ep) REG8 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x13) // EP1-2 IN CSR MSB 8-bit -#define UDC_OUTMAXP(ep) REG16 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x14) // EP1 OUT Max Pkt Size 16-bit -#define UDC_OUTCSR(ep) REG16 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x16) // EP1 OUT CSR LSB 8/16bit -#define UDC_OUTCSRH(ep) REG8 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x17) // EP1 OUT CSR MSB 8-bit -#define UDC_OUTCOUNT(ep) REG16 (UDC_BASE + 0x100 + 0x10 * (ep) + 0x18) // bytes in EP0/1 OUT FIFO 16-bit +#define UDC_INMAXP REG16 (UDC_BASE + 0x10) // EP1-2 IN Max Pkt Size 16-bit +#define UDC_INCSR REG16 (UDC_BASE + 0x12) // EP1-2 IN CSR LSB 8/16bit +#define UDC_INCSRH REG8 (UDC_BASE + 0x13) // EP1-2 IN CSR MSB 8-bit +#define UDC_OUTMAXP REG16 (UDC_BASE + 0x14) // EP1 OUT Max Pkt Size 16-bit +#define UDC_OUTCSR REG16 (UDC_BASE + 0x16) // EP1 OUT CSR LSB 8/16bit +#define UDC_OUTCSRH REG8 (UDC_BASE + 0x17) // EP1 OUT CSR MSB 8-bit +#define UDC_OUTCOUNT REG16 (UDC_BASE + 0x18) // bytes in EP0/1 OUT FIFO 16-bit #define UDC_FIFO(ep) REG32 (UDC_BASE + 0x20 + 4 * (ep)) #define UDC_FIFO8(ep) REG8 (UDC_BASE + 0x20 + 4 * (ep)) diff --git a/mips/nanonote/server/usb-server.ccp b/mips/nanonote/server/usb-server.ccp index ab7e97a..9519f02 100644 --- a/mips/nanonote/server/usb-server.ccp +++ b/mips/nanonote/server/usb-server.ccp @@ -27,6 +27,7 @@ #include #include #include +#include #include "devices.hh" struct client @@ -70,15 +71,15 @@ struct data: void get_device (unsigned vendor, unsigned product, unsigned tries) void poll () +static std::string files ("fs") struct Name: char name[16] std::string full Name (std::string const &n): - full = n + full = files + '/' + n memset (name, 0, 16) memcpy (name, n.data (), n.size () > 16 ? 16 : n.size ()) static std::vector dir -static std::string files (".") unsigned lock (0) void data::poll (): @@ -101,6 +102,12 @@ void data::poll (): break case Directory::GET_SIZE: unsigned long long size = dir.size () + std::cerr << "sending dir size\n" + std::cerr << Directory::GET_SIZE << '\n' + char *str = (char *)&size + for unsigned i = 0; i < 8; ++i: + std::cerr << " " << (unsigned)(str[i] & 0xff) + std::cerr << '\n' if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8: std::cerr << "unable to send size to device: " << usb_strerror () << std::endl usb_release_interface (handle, 0) @@ -115,6 +122,7 @@ void data::poll (): usb_close (handle) handle = NULL return + std::cerr << "sending filename\n" if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_NAME, 0, 0, dir[buffer[1]].name, 16, timeout) != 16: std::cerr << "unable to send name to device: " << usb_strerror () << std::endl usb_release_interface (handle, 0) @@ -123,13 +131,17 @@ void data::poll (): return continue case Directory::LOCK_RO: + std::cerr << "lock\n" if !lock++: + std::cerr << "freezing file list\n" shevek::dir d (files) dir.clear () - for shevek::dir::const_iterator i = d.begin (); i == d.end (); ++i: - dir.push_back (Name (i->name)) + for shevek::dir::const_iterator i = d.begin (); i != d.end (); ++i: + if !i->name.empty () && i->name[0] != '.': + dir.push_back (Name (i->name)) continue case Directory::UNLOCK_RO: + std::cerr << "unlock\n" if !lock: std::cerr << "unlocking without lock" << std::endl usb_release_interface (handle, 0) @@ -139,19 +151,22 @@ void data::poll (): if !--lock: dir.clear () continue - case Directory::GET_FILE_RO: - unsigned f = buffer[0] >> 16 - if f >= dir.size (): + case String::GET_PAGE: + if buffer[1] >= dir.size (): std::cerr << "reading invalid file" << std::endl usb_release_interface (handle, 0) usb_close (handle) handle = NULL return - std::ifstream file (dir[f].full.c_str ()) - file.seekg (buffer[1] << 12) + unsigned pos = buffer[0] >> 16 + std::cerr << "getting data from " << pos << '\n' + std::ifstream file (dir[buffer[1]].full.c_str ()) + file.seekg (pos << 12) char page[1 << 12] memset (page, 0, 1 << 12) file.read (page, 1 << 12) + shevek::dump (std::string (page, 32), std::cerr) + std::cerr << "sending bulk\n" for unsigned i = 0; i < (1 << 12); i += 64: if usb_bulk_write (handle, 1 | USB_ENDPOINT_OUT, &page[i], 64, timeout) != 64: std::cerr << "unable to send file to device: " << usb_strerror () << std::endl @@ -160,15 +175,33 @@ void data::poll (): handle = NULL return continue + case String::GET_SIZE: + if buffer[1] >= dir.size (): + std::cerr << "reading invalid file size" << std::endl + usb_release_interface (handle, 0) + usb_close (handle) + handle = NULL + return + std::ifstream file (dir[buffer[1]].full.c_str ()) + file.seekg (0, std::ios_base::end) + unsigned long long size = file.tellg () + std::cerr << "sending file size " << size << "\n" + if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, String::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8: + std::cerr << "unable to send size to device: " << usb_strerror () << std::endl + usb_release_interface (handle, 0) + usb_close (handle) + handle = NULL + return + continue default: - std::cerr << "invalid request" << std::endl + std::cerr << "invalid request " << buffer[0] << std::endl usb_release_interface (handle, 0) usb_close (handle) handle = NULL return // If the code reaches this point, break out of the loop. The loop continues if a continue statement is reached. break - (shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll)) + (shevek::absolute_time () + shevek::relative_time (0, 100000000)).schedule (sigc::mem_fun (*this, &data::poll)) struct client : public shevek::server ::connection: static Glib::RefPtr create (): @@ -225,7 +258,7 @@ void data::get_device (unsigned vendor, unsigned product, unsigned tries): usb_close (handle) handle = NULL continue - (shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll)) + (shevek::absolute_time () + shevek::relative_time (0, 100000000)).schedule (sigc::mem_fun (*this, &data::poll)) return if i + 1 < tries: //std::cerr << "failed to find device, still trying...\n" @@ -277,6 +310,21 @@ void data::boot (unsigned entry): return std::cerr << "(re)booted NanoNote\n" +static void dump_devices (): + std::cerr << std::hex << "String: " << String::ID + std::cerr << "\nWString: " << WString::ID + std::cerr << "\nDevice: " << Device::ID + std::cerr << "\nParent: " << Parent::ID + std::cerr << "\nKeyboard: " << Keyboard::ID + std::cerr << "\nBuzzer: " << Buzzer::ID + std::cerr << "\nDisplay: " << Display::ID + std::cerr << "\nSetting: " << Setting::ID + std::cerr << "\nDirectory: " << Directory::ID + std::cerr << "\nWDirectory: " << WDirectory::ID + std::cerr << "\nFilesystem: " << Filesystem::ID + std::cerr << "\nStream: " << Stream::ID + std::cerr << "\n" + int main (int argc, char **argv): usb_init () std::string port ("5050") @@ -285,5 +333,6 @@ int main (int argc, char **argv): } shevek::args args (argc, argv, opts, 0, 0, "device server for testing Iris on NanoNote", "2009") data d (port) + dump_devices () shevek::loop () return 0 diff --git a/panic.ccp b/panic.ccp index ed6be1d..f385aff 100644 --- a/panic.ccp +++ b/panic.ccp @@ -45,7 +45,7 @@ void dbg_log_num (unsigned num, unsigned digits): return #if 1 || defined (NDEBUG) -static void panic_message (unsigned n, unsigned line, char const *name, char const *message): +static void panic_message (unsigned n, const char *line, char const *name, char const *message): dbg_log ("Panic: caller = ") if old_current: dbg_log_num (old_current->id, 2) @@ -57,7 +57,7 @@ static void panic_message (unsigned n, unsigned line, char const *name, char con dbg_log ("; ") dbg_log (name) dbg_log_char (':') - dbg_log_num (line) + dbg_log (line) dbg_log (": ") dbg_log (message) dbg_log_char ('/') @@ -73,7 +73,7 @@ static void panic_message (unsigned n, unsigned line, char const *name, char con dbg_log_num (a) dbg_log_char ('\n') -void panic_impl (unsigned n, unsigned line, char const *name, char const *message): +void panic_impl (unsigned n, const char *line, char const *name, char const *message): // Stop all threads. while first_scheduled: first_scheduled->unrun () @@ -133,7 +133,7 @@ void dbg_send (unsigned n, unsigned bits): delay (50) set_leds (false, false) delay (50) -void panic_impl (unsigned n, unsigned line, char const *name, char const *message): +void panic_impl (unsigned n, const char *line, char const *name, char const *message): unsigned epc cp0_get (CP0_EPC, epc) dbg_send (epc, 32) diff --git a/source/crt0.ccp b/source/crt0.ccp index f0e7703..70e0c12 100644 --- a/source/crt0.ccp +++ b/source/crt0.ccp @@ -38,9 +38,9 @@ namespace Kernel: __recv_data_t recv void print_caps (): - // Assume __caps to be 16. - bool used[16] - for unsigned i = 0; i < 16; ++i: + // Assume __caps to be 32. + bool used[32] + for unsigned i = 0; i < 32; ++i: used[i] = true unsigned num = 0 for list *i = __first_free_cap; i; i = i->next: @@ -48,7 +48,7 @@ namespace Kernel: ++num kdebug_num (num, 1) kdebug (":") - for unsigned i = 0; i < 16; ++i: + for unsigned i = 0; i < 32; ++i: kdebug_char (used[i] ? '#' : '.') kdebug_char ('\n') diff --git a/source/lcd.ccp b/source/lcd.ccp index f81d1e5..f69ecb2 100644 --- a/source/lcd.ccp +++ b/source/lcd.ccp @@ -20,7 +20,7 @@ #define ARCH #include "arch.hh" -__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"boot-programs/charset.data\"\n.section .text") +__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"source/charset.data\"\n.section .text") extern unsigned char const charset[127-32][8][6] #define assert(x) do { if (!(x)) { kdebug ("assertion failed " #x); while (true) {} } } while (0)