1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-28 12:32:05 +02:00

usb fs mostly working

This commit is contained in:
Bas Wijnen 2010-01-16 16:13:54 +01:00
parent 03e74d38d3
commit 7dc6ecb0ea
16 changed files with 563 additions and 220 deletions

2
.gitignore vendored
View File

@ -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/

View File

@ -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:

View File

@ -21,13 +21,13 @@
#include <elf.h>
#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

View File

@ -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 <Directory> (fs_dev)
Device data_dev = Kernel::my_receiver.create_capability (DATA)
Kernel::my_parent.provide_device <Filesystem> (fs_dev.copy ())
Kernel::my_parent.provide_device <String> (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)

View File

@ -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 &current_user, Kernel::Cap &reply):
static void host (unsigned id, unsigned &current_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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -23,7 +23,7 @@
#include <elf.h>
#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.

View File

@ -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

View File

@ -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))

View File

@ -27,6 +27,7 @@
#include <shevek/server.hh>
#include <shevek/args.hh>
#include <shevek/dir.hh>
#include <shevek/error.hh>
#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 <Name> 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 <client, data *>::connection:
static Glib::RefPtr <client> 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

View File

@ -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)

View File

@ -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')

View File

@ -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)