mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-28 12:32:05 +02:00
towards a usb file system
This commit is contained in:
parent
3debf99082
commit
0c1dfe719b
7
.gitignore
vendored
7
.gitignore
vendored
@ -6,13 +6,6 @@ uimage
|
||||
*.elf
|
||||
*.cc
|
||||
*.hh
|
||||
gpio
|
||||
lcd
|
||||
init
|
||||
udc
|
||||
buzzer
|
||||
metronome
|
||||
nanonote-gpio
|
||||
boot-programs/charset.data
|
||||
mips/nanonote/sdram-setup.raw
|
||||
nanonote-boot
|
||||
|
4
Makefile
4
Makefile
@ -46,6 +46,10 @@ PYPP = /usr/bin/pypp
|
||||
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
|
||||
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
|
||||
|
||||
fs/%.elf: source/crt0.o source/%.o
|
||||
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
|
||||
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
|
||||
|
||||
clean:
|
||||
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)
|
||||
|
||||
|
@ -97,7 +97,7 @@ namespace Kernel:
|
||||
return Cap (0, ret - __cap_admin)
|
||||
|
||||
extern "C":
|
||||
void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
__slots = slots
|
||||
__caps = caps
|
||||
__slot_admin = slot_admin
|
||||
@ -137,7 +137,7 @@ __asm__ volatile ("\t.globl __start\n"
|
||||
"\tmove $a2, $sp\n"
|
||||
"\tsubu $sp, $sp, $v1\n"
|
||||
"\tmove $a3, $sp\n"
|
||||
"\tla $t9, __main\n"
|
||||
"\tla $t9, run__main\n"
|
||||
"\tjr $t9\n"
|
||||
"\tnop\n"
|
||||
"\t.set reorder")
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/init.ccp: System boot manager.
|
||||
// bootstrap/init.ccp: Bootstrapping code.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
@ -18,136 +18,288 @@
|
||||
|
||||
#include "devices.hh"
|
||||
#include "iris.hh"
|
||||
#include <elf.h>
|
||||
|
||||
static Keyboard sysreq
|
||||
static Device kbd_dev, buz_dev, backlight_dev, rootfs_dev
|
||||
#define NUM_SLOTS 4
|
||||
#define NUM_CAPS 16
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = _end
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + pages * PAGE_SIZE
|
||||
return (char *)ret
|
||||
|
||||
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)
|
||||
_free += size
|
||||
return ret
|
||||
|
||||
struct file:
|
||||
unsigned size
|
||||
// Only the first 16 characters of the name are used, because that's much easier.
|
||||
// This means that file names must be different in the first 16 characters if sort order matters.
|
||||
char name[16]
|
||||
String string
|
||||
|
||||
static unsigned num_files
|
||||
static file *files
|
||||
static unsigned *index
|
||||
static Kernel::Memory top_memory
|
||||
static unsigned slot
|
||||
static unsigned max_pages
|
||||
static char *mapping
|
||||
static unsigned current_thread
|
||||
|
||||
// Event types.
|
||||
enum type:
|
||||
SYSREQ
|
||||
KBDDEV
|
||||
BUZDEV
|
||||
BACKLIGHTDEV
|
||||
ROOTFSDEV
|
||||
|
||||
static void user_reply (Kernel::Cap target, unsigned dev):
|
||||
switch dev:
|
||||
case Keyboard::ID:
|
||||
// keyboard user
|
||||
Kernel::Cap kbd = kbd_dev.create_user (Kernel::Cap ())
|
||||
kbd_dev.use (kbd)
|
||||
target.invoke (0, 0, kbd.copy ())
|
||||
Kernel::free_cap (kbd)
|
||||
break
|
||||
case Buzzer::ID:
|
||||
// buzzer user
|
||||
Kernel::Cap buzzer = buz_dev.create_user (Kernel::Cap ())
|
||||
buz_dev.use (buzzer)
|
||||
target.invoke (0, 0, buzzer.copy ())
|
||||
Kernel::free_cap (buzzer)
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid id requested:")
|
||||
kdebug_num (dev)
|
||||
kdebug_char ('\n')
|
||||
break
|
||||
|
||||
static void setup ():
|
||||
unsigned state = 0
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (32)
|
||||
slot = caps.use ()
|
||||
Kernel::Cap user
|
||||
unsigned device
|
||||
while true:
|
||||
// Get the initial block device and filesystem.
|
||||
static Directory receive_devices ():
|
||||
String data
|
||||
Filesystem fs
|
||||
bool have_data = false, have_fs = false
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
Device dev
|
||||
Kernel::wait ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Parent::PROVIDE_DEVICE:
|
||||
switch Kernel::recv.data[1].l:
|
||||
case Keyboard::ID:
|
||||
switch Kernel::recv.data[0].h:
|
||||
case 0:
|
||||
caps.set (KBDDEV, arg.copy ())
|
||||
kbd_dev = Kernel::Cap (slot, KBDDEV)
|
||||
break
|
||||
case 1:
|
||||
caps.set (SYSREQ, arg.copy ())
|
||||
sysreq = Kernel::Cap (slot, SYSREQ)
|
||||
break
|
||||
default:
|
||||
kdebug ("unexpected keyboard\n")
|
||||
break
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Buzzer::ID:
|
||||
caps.set (BUZDEV, arg.copy ())
|
||||
buz_dev = Kernel::Cap (slot, BUZDEV)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Setting::ID:
|
||||
caps.set (BACKLIGHTDEV, arg.copy ())
|
||||
backlight_dev = Kernel::Cap (slot, BACKLIGHTDEV)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Directory::ID:
|
||||
caps.set (ROOTFSDEV, arg.copy ())
|
||||
rootfs_dev = Kernel::Cap (slot, ROOTFSDEV)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("unexpected device: ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug_char ('\n')
|
||||
break
|
||||
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
|
||||
kdebug ("Invalid bootstrap request.\n")
|
||||
Kernel::panic (0)
|
||||
switch Kernel::recv.data[1].l:
|
||||
case String::ID:
|
||||
if have_data:
|
||||
kdebug ("duplicate device.\n")
|
||||
Kernel::panic (0)
|
||||
dev = Kernel::get_arg ()
|
||||
have_data = true
|
||||
Kernel::recv.reply.invoke ()
|
||||
data = dev.create_user (Kernel::my_memory)
|
||||
dev.use (data)
|
||||
Kernel::free_cap (dev)
|
||||
break
|
||||
case Parent::GET_DEVICE:
|
||||
user = reply
|
||||
device = Kernel::recv.data[1].l
|
||||
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)
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("unknown setup request for init\n")
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
Kernel::free_cap (arg)
|
||||
if ++state == 6:
|
||||
break
|
||||
// sysreq
|
||||
Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
|
||||
sysreq.set_cb (cb.copy ())
|
||||
Kernel::free_cap (cb)
|
||||
// First user reply.
|
||||
user_reply (user, device)
|
||||
Kernel::free_cap (user)
|
||||
kdebug ("unexpected device: ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug_char ('\n')
|
||||
Kernel::panic (0)
|
||||
// Initialize the root file system.
|
||||
Directory root = fs.use_device_ro (data.copy ())
|
||||
Kernel::free_cap (data)
|
||||
Kernel::free_cap (fs)
|
||||
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")
|
||||
Kernel::panic (0)
|
||||
num_files = fullsize.l
|
||||
files = new file[num_files]
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2)
|
||||
unsigned slot = Kernel::alloc_slot ()
|
||||
caps.use (slot)
|
||||
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))
|
||||
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")
|
||||
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
|
||||
|
||||
// Sort the list of files.
|
||||
static bool is_less (file *f1, file *f2):
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
if f1->name[i] < f2->name[i]:
|
||||
return true
|
||||
if f1->name[i] > f2->name[i]:
|
||||
return false
|
||||
return false
|
||||
|
||||
// Bubble sort.
|
||||
static void sort ():
|
||||
index = new unsigned[num_files]
|
||||
index[0] = 0
|
||||
// Invariant: index[0...f-1] is sorted.
|
||||
for unsigned f = 1; f < num_files; ++f:
|
||||
// Bubble up until top. Test for less-than, because it wraps to maxunsigned.
|
||||
unsigned i
|
||||
// Invariant: index[0...f] \ index[i+1] is sorted and index[i+1...f] is sorted.
|
||||
for i = f - 1; i < f; --i:
|
||||
if is_less (&files[index[i]], &files[f]):
|
||||
break
|
||||
index[i + 1] = index[i]
|
||||
index[i + 1] = f
|
||||
|
||||
static void run (file *f, bool priv):
|
||||
Kernel::Memory mem = top_memory.create_memory ()
|
||||
unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK
|
||||
for unsigned p = 0; p < num_pages; ++p:
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, p))
|
||||
mem.create_page ()
|
||||
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
|
||||
Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
Kernel::Thread thread = mem.create_thread (NUM_SLOTS)
|
||||
if priv:
|
||||
thread.make_priv ()
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
if header->e_ident[j] != ELFMAG[j]:
|
||||
kdebug ("invalid ELF magic\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
kdebug ("invalid ELF data\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
kdebug ("invalid ELF version\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_type != ET_EXEC:
|
||||
kdebug ("invalid ELF type\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
kdebug ("invalid ELF machine\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
thread.set_pc (header->e_entry)
|
||||
thread.set_sp (0x80000000)
|
||||
for unsigned section = 0; section < header->e_shnum; ++section:
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
|
||||
if ~shdr->sh_flags & SHF_ALLOC:
|
||||
continue
|
||||
bool readonly = !(shdr->sh_flags & SHF_WRITE)
|
||||
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
|
||||
if shdr->sh_type != SHT_NOBITS:
|
||||
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
|
||||
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
|
||||
kdebug ("thread too large\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
unsigned idx = file_offset + section_offset
|
||||
Kernel::Page page = mem.mapping ((void *)p)
|
||||
if Kernel::recv.data[0].l == Kernel::NO_ERROR:
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Kernel::free_cap (page)
|
||||
continue
|
||||
page = mem.create_page ()
|
||||
Kernel::Page (slot, idx).share (page, 0)
|
||||
if !mem.map (page, p, readonly):
|
||||
kdebug ("unable to map page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
kdebug ("unwritable bss section\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
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.
|
||||
page = mem.create_page ()
|
||||
if Kernel::recv.data[0].l != Kernel::NO_ERROR:
|
||||
kdebug ("out of memory\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
|
||||
kdebug ("out of memory\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if !mem.map (page, p):
|
||||
kdebug ("unable to map bss page\n")
|
||||
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
|
||||
for unsigned p = 0; p <= num_pages; ++p:
|
||||
mem.destroy (Kernel::Page (slot, p))
|
||||
Kernel::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
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
|
||||
Kernel::free_cap (stackpage)
|
||||
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Kernel::Thread::A0, NUM_SLOTS)
|
||||
thread.set_info (Kernel::Thread::A1, NUM_CAPS)
|
||||
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)
|
||||
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 ())
|
||||
thread.run ()
|
||||
Kernel::free_cap (receiver)
|
||||
Kernel::free_cap (thread)
|
||||
Kernel::free_cap (mem)
|
||||
Kernel::free_cap (call)
|
||||
Kernel::free_cap (parent)
|
||||
|
||||
Kernel::Num start ():
|
||||
// Wait for the debugging device to be active, in case there is one.
|
||||
Kernel::schedule ()
|
||||
setup ()
|
||||
// claim backlight
|
||||
Setting backlight = backlight_dev.create_user (Kernel::Cap ())
|
||||
backlight_dev.use (backlight)
|
||||
bool backlight_state = true
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.value ():
|
||||
case SYSREQ:
|
||||
unsigned code = Kernel::recv.data[0].l
|
||||
if !(code & Keyboard::RELEASE):
|
||||
backlight_state = !backlight_state
|
||||
backlight.set (backlight_state ? ~0 : 0)
|
||||
break
|
||||
default:
|
||||
if Kernel::recv.data[0].l != Parent::GET_DEVICE:
|
||||
kdebug ("invalid call from user\n")
|
||||
break
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
user_reply (reply, Kernel::recv.data[1].l)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
top_memory = Kernel::get_top_memory ()
|
||||
Directory root = receive_devices ()
|
||||
root.lock_ro ()
|
||||
list_files (root)
|
||||
sort ()
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
|
||||
slot = caps.use ()
|
||||
mapping = alloc_space (max_pages)
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
run (&files[index[i]], files[index[i]].name[0] == '#')
|
||||
root.unlock_ro ()
|
||||
Kernel::free_slot (slot)
|
||||
Kernel::my_memory.destroy (caps)
|
||||
return 0
|
||||
|
@ -150,17 +150,19 @@ class Udc:
|
||||
char configuration
|
||||
unsigned size
|
||||
char const *ptr
|
||||
unsigned cmd_code, cmd_arg
|
||||
bool rebooting
|
||||
bool vendor (Setup *s)
|
||||
bool vendor (Setup *s, unsigned cmd)
|
||||
bool get_descriptor (unsigned type, unsigned idx, unsigned len)
|
||||
bool handle_setup (Setup *s)
|
||||
bool handle_setup (Setup *s, unsigned cmd)
|
||||
char log_buffer[1000]
|
||||
unsigned log_buffer_size
|
||||
unsigned log_buffer_start
|
||||
public:
|
||||
void init ()
|
||||
void log (unsigned c)
|
||||
void interrupt ()
|
||||
void interrupt (unsigned cmd)
|
||||
void send (unsigned code, unsigned 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 = {
|
||||
@ -198,6 +200,8 @@ void Udc::init ():
|
||||
s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
|
||||
log_buffer_size = 0
|
||||
log_buffer_start = 0
|
||||
cmd_code = ~0
|
||||
cmd_arg = 0
|
||||
|
||||
// Disconnect from the bus and don't try to get high-speed.
|
||||
UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB)
|
||||
@ -221,21 +225,35 @@ void Udc::init ():
|
||||
// Connect to the host.
|
||||
UDC_POWER |= UDC_POWER_SOFTCONN
|
||||
|
||||
bool Udc::vendor (Setup *s):
|
||||
bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
if !(s->request_type & 0x80):
|
||||
switch s->request:
|
||||
case Directory::GET_SIZE:
|
||||
//TODO
|
||||
case Directory::GET_NAME:
|
||||
//TODO
|
||||
default:
|
||||
kdebug ("invalid vendor request\n")
|
||||
Kernel::panic (0)
|
||||
return true
|
||||
if s->request == 10:
|
||||
static char b[2]
|
||||
ptr = b
|
||||
size = s->length < 2 ? s->length : 2
|
||||
b[0] = '#'
|
||||
if log_buffer_start == log_buffer_size:
|
||||
size = 1
|
||||
static unsigned b[2]
|
||||
ptr = (char *)b
|
||||
size = s->length < 8 ? s->length : 8
|
||||
if cmd_code != ~0:
|
||||
b[0] = cmd_code
|
||||
b[1] = cmd_arg
|
||||
cmd_code = ~0
|
||||
else:
|
||||
b[1] = log_buffer[log_buffer_start++]
|
||||
if log_buffer_start == log_buffer_size:
|
||||
log_buffer_start = 0
|
||||
log_buffer_size = 0
|
||||
if log_buffer_start == log_buffer_size:
|
||||
b[0] = ~1
|
||||
b[1] = 0
|
||||
else:
|
||||
b[0] = ~0
|
||||
b[1] = (log_buffer[log_buffer_start++] & 0xff) * 0x01010101
|
||||
if log_buffer_start == log_buffer_size:
|
||||
log_buffer_start = 0
|
||||
log_buffer_size = 0
|
||||
else:
|
||||
static char const *name = "Reboot"
|
||||
ptr = name
|
||||
@ -244,6 +262,13 @@ bool Udc::vendor (Setup *s):
|
||||
state = TX
|
||||
return true
|
||||
|
||||
void Udc::send (unsigned code, unsigned arg):
|
||||
if code != ~0:
|
||||
kdebug ("new code sent while old one wasn't finished.\n")
|
||||
Kernel::panic (0)
|
||||
cmd_code = code
|
||||
cmd_arg = arg
|
||||
|
||||
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
switch type:
|
||||
case Configuration::Type:
|
||||
@ -265,7 +290,7 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
//size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
|
||||
//break
|
||||
return false
|
||||
// The 6 is an arbitrary number, except that String <6> in instantiated already.
|
||||
// The 6 is an arbitrary number, except that String <6> is instantiated already.
|
||||
case String <6>::Type:
|
||||
switch idx:
|
||||
case 0:
|
||||
@ -288,7 +313,7 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
state = TX
|
||||
return true
|
||||
|
||||
bool Udc::handle_setup (Setup *s):
|
||||
bool Udc::handle_setup (Setup *s, unsigned cmd):
|
||||
switch s->request_type:
|
||||
case STANDARD_TO_DEVICE:
|
||||
switch s->request:
|
||||
@ -331,12 +356,12 @@ bool Udc::handle_setup (Setup *s):
|
||||
break
|
||||
case VENDOR_TO_DEVICE:
|
||||
case VENDOR_FROM_DEVICE:
|
||||
return vendor (s)
|
||||
return vendor (s, cmd)
|
||||
default:
|
||||
return false
|
||||
return true
|
||||
|
||||
void Udc::interrupt ():
|
||||
void Udc::interrupt (unsigned cmd):
|
||||
unsigned i = UDC_INTRUSB
|
||||
if i & UDC_INTR_RESET:
|
||||
state = IDLE
|
||||
@ -361,7 +386,7 @@ void Udc::interrupt ():
|
||||
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):
|
||||
if !handle_setup (&packet.s, cmd):
|
||||
csr |= UDC_CSR0_SENDSTALL
|
||||
break
|
||||
if size == 0:
|
||||
@ -395,6 +420,8 @@ void Udc::log (unsigned c):
|
||||
enum pdata:
|
||||
LOG = 32
|
||||
FS
|
||||
DATA
|
||||
DIRECTORY
|
||||
|
||||
Kernel::Num start ():
|
||||
map_udc ()
|
||||
@ -408,52 +435,28 @@ Kernel::Num start ():
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
Device fs_dev = Kernel::my_receiver.create_capability (FS)
|
||||
Kernel::my_parent.provide_device <Directory> (fs_dev)
|
||||
Kernel::Num current_user = 0
|
||||
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 ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
case IRQ_UDC:
|
||||
udc.interrupt ()
|
||||
udc.interrupt (state)
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
break
|
||||
case LOG:
|
||||
udc.log (Kernel::recv.data[0].l)
|
||||
break
|
||||
case FS:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, FS))
|
||||
reply.invoke (0, 0, c.copy ())
|
||||
Kernel::free_cap (c)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Device::USE:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
current_user = Kernel::my_receiver.get_protected (arg)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
case Device::UNUSE:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
if current_user.value () == Kernel::my_receiver.get_protected (arg).value ():
|
||||
current_user = 0
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
break
|
||||
Device::host (FS, fs_current_user, reply)
|
||||
continue
|
||||
case DATA:
|
||||
Device::host (DATA, data_current_user, reply)
|
||||
continue
|
||||
default:
|
||||
udc.log ('~')
|
||||
char digit[] = "0123456789abcdef"
|
||||
@ -461,18 +464,55 @@ Kernel::Num start ():
|
||||
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
||||
udc.log ('\n')
|
||||
break
|
||||
case FS:
|
||||
if current_user.value () != Kernel::recv.protected_data.value ():
|
||||
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:
|
||||
reply.invoke (0)
|
||||
Kernel::free_cap (reply)
|
||||
continue
|
||||
case String::GET_PAGE:
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
continue
|
||||
break
|
||||
case FS:
|
||||
if fs_current_user != Kernel::recv.protected_data.l:
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Filesystem::USE_DEVICE:
|
||||
case Filesystem::USE_DEVICE_RO:
|
||||
Directory dir = Kernel::my_receiver.create_capability (Kernel::Num (0, DIRECTORY))
|
||||
reply.invoke (0, 0, dir.copy ())
|
||||
Kernel::free_cap (dir)
|
||||
Kernel::free_cap (reply)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
continue
|
||||
case DIRECTORY:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Directory::GET_SIZE:
|
||||
case Directory::GET_NAME:
|
||||
case Directory::GET_FILE_RO:
|
||||
case Directory::LOCK_RO:
|
||||
case Directory::UNLOCK_RO:
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
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)
|
||||
continue
|
||||
case Directory::GET_FILE_RO:
|
||||
//TODO
|
||||
case Directory::GET_FILE_INFO:
|
||||
default:
|
||||
Kernel::recv.reply.invoke (~0)
|
||||
break
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
continue
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
|
@ -1,257 +0,0 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// bootstrap/init.ccp: Bootstrapping code.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#include "iris.hh"
|
||||
|
||||
struct file:
|
||||
unsigned size
|
||||
// Only the first 16 characters of the name are used, because that's much easier.
|
||||
// This means that file names must be different in the first 16 characters if sort order matters.
|
||||
char name[16]
|
||||
String string
|
||||
|
||||
static unsigned num_files
|
||||
static file *files
|
||||
static unsigned index
|
||||
static Kernel::Memory top_memory
|
||||
static unsigned slot
|
||||
static unsigned max_pages
|
||||
static char *mapping
|
||||
static unsigned current_thread
|
||||
|
||||
// Get the initial block device and filesystem.
|
||||
static Directory receive_devices ():
|
||||
String dev
|
||||
Filesystem fs
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
Kernel::wait ()
|
||||
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
|
||||
kdebug ("Invalid bootstrap request.\n")
|
||||
Kernel::panic (0)
|
||||
switch Kernel::recv.data[1].l:
|
||||
case String::ID:
|
||||
if dev:
|
||||
kdebug ("duplicate device.\n")
|
||||
Kernel::panic (0)
|
||||
dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
case Filesystem::ID:
|
||||
if fs:
|
||||
kdebug ("duplicate filesystem.\n")
|
||||
Kernel::panic (0)
|
||||
fs = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("unexpected device: ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug_char ('\n')
|
||||
Kernel::panic (0)
|
||||
// Initialize the root file system.
|
||||
Directory root = fs.use_device (dev.copy ())
|
||||
Kernel::free_cap (dev)
|
||||
Kernel::free_cap (fs)
|
||||
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")
|
||||
Kernel::panic (0)
|
||||
num_files = fullsize.l
|
||||
files = new file[num_files]
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2)
|
||||
unsigned slot = Kernel::alloc_slot ()
|
||||
caps.use (slot)
|
||||
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))
|
||||
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")
|
||||
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
|
||||
|
||||
// Sort the list of files.
|
||||
static bool is_less (file *f1, file *f2):
|
||||
return
|
||||
|
||||
// Bubble sort.
|
||||
static void sort ():
|
||||
index = new unsigned[num_files]
|
||||
index[0] = 0
|
||||
// Invariant: index[0...f-1] is sorted.
|
||||
for unsigned f = 1; f < num_files; ++f:
|
||||
// Bubble up until top. Test for less-than, because it wraps to maxunsigned.
|
||||
unsigned i
|
||||
// Invariant: index[0...f] \ index[i+1] is sorted and index[i+1...f] is sorted.
|
||||
for i = f - 1; i < f; --i:
|
||||
if is_less (&files[index[i]], &files[f]):
|
||||
break
|
||||
index[i + 1] = index[i]
|
||||
index[i + 1] = f
|
||||
|
||||
static void run (file *f, bool priv):
|
||||
Kernel::Memory mem = top_memory.create_memory ()
|
||||
unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK
|
||||
for unsigned p = 0; p < num_pages; ++p:
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, p))
|
||||
mem.create_page ()
|
||||
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
|
||||
Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
Kernel::Thread *thread = mem.create_thread (NUM_SLOTS)
|
||||
if priv:
|
||||
thread.make_priv ()
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
if header->e_ident[j] != ELFMAG[j]:
|
||||
kdebug ("invalid ELF magic\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
kdebug ("invalid ELF data\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
kdebug ("invalid ELF version\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_type != ET_EXEC:
|
||||
kdebug ("invalid ELF type\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
kdebug ("invalid ELF machine\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
thread.set_pc (header->e_entry)
|
||||
thread.set_sp (0x80000000)
|
||||
for unsigned section = 0; section < header->e_shnum; ++section:
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
|
||||
if ~shdr->sh_flags & SHF_ALLOC:
|
||||
continue
|
||||
bool readonly = !(shdr->sh_flags & SHF_WRITE)
|
||||
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
|
||||
if shdr->sh_type != SHT_NOBITS:
|
||||
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
|
||||
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
|
||||
kdebug ("thread too large\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
unsigned idx = file_offset + section_offset
|
||||
Kernel::Page page = mem.mapping (p)
|
||||
if page:
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Kernel::free_cap (page)
|
||||
continue
|
||||
page = mem.create_page ()
|
||||
Kernel::Cap (slot, idx).share (page, 0)
|
||||
if !mem.map (page, p, readonly):
|
||||
kdebug ("unable to map page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
kdebug ("unwritable bss section\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
kPage *page = mem->get_mapping (p)
|
||||
if !page:
|
||||
page = mem.create_page ()
|
||||
if !page:
|
||||
kdebug ("out of memory\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
|
||||
kdebug ("out of memory\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if !mem.map (page, p):
|
||||
kdebug ("unable to map bss page\n")
|
||||
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[idx << PAGE_BITS])[(a & ~PAGE_MASK) >> 2] = 0
|
||||
for unsigned p = 0; p <= num_pages; ++p:
|
||||
mem.destroy (Kernel::Cap (slot, p))
|
||||
Kernel::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
if !stackpage || !mem.map (stackpage, 0x7ffff000):
|
||||
kdebug ("unable to map initial stack page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::free_cap (stackpage)
|
||||
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Kernel::Thread::A0, NUM_SLOTS)
|
||||
thread.set_info (Kernel::Thread::A1, NUM_CAPS)
|
||||
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)
|
||||
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 ())
|
||||
thread.run ()
|
||||
Kernel::free_cap (receiver)
|
||||
Kernel::free_cap (thread)
|
||||
Kernel::free_cap (mem)
|
||||
Kernel::free_cap (call)
|
||||
Kernel::free_cap (parent)
|
||||
|
||||
Kernel::Num start ():
|
||||
// Wait for the debugging device to be active, in case there is one.
|
||||
Kernel::schedule ()
|
||||
top_memory = Kernel::get_top_memory ()
|
||||
Directory root = receive_devices ()
|
||||
root.lock_ro ()
|
||||
list_files (root)
|
||||
sort ()
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
|
||||
slot = caps.use ()
|
||||
mapping = alloc_space (max_pages)
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
run (files[i], files[i].name[0] == '#')
|
||||
root.unlock_ro ()
|
||||
Kernel::free_slot (slot)
|
||||
Kernel::my_memory.destroy (caps)
|
||||
return 0
|
50
devices.hhp
50
devices.hhp
@ -98,6 +98,40 @@ struct Device : public Kernel::Cap:
|
||||
// Make user active. It makes the previous active user inactive.
|
||||
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 unsigned last_user
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
// Increment last_user; skip 0.
|
||||
// FIXME: if this really wraps, it is possible that two users share their id.
|
||||
if !++last_user:
|
||||
++last_user
|
||||
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (last_user, id))
|
||||
reply.invoke (0, 0, c.copy ())
|
||||
Kernel::free_cap (c)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
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
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
|
||||
// Interface for talking to the parent process.
|
||||
struct Parent : public Kernel::Cap:
|
||||
@ -270,11 +304,25 @@ struct WDirectory : public Directory:
|
||||
void unlock ():
|
||||
call (CAP_MASTER_DIRECT | UNLOCK)
|
||||
|
||||
// A filesystem turns a String into a Directory.
|
||||
struct Filesystem : public Device:
|
||||
Filesystem (Kernel::Cap c = Kernel::Cap ()) : Device (c):
|
||||
enum request:
|
||||
USE_DEVICE = WDirectory::ID
|
||||
USE_DEVICE_RO
|
||||
ID
|
||||
WDirectory use_device (WString dev):
|
||||
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
|
||||
return Kernel::get_arg ()
|
||||
Directory use_device_ro (String dev):
|
||||
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
|
||||
return Kernel::get_arg ()
|
||||
|
||||
// Stream interface.
|
||||
struct Stream : public Kernel::Cap:
|
||||
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
READ = WDirectory::ID
|
||||
READ = Filesystem::ID
|
||||
WRITE
|
||||
ID
|
||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||
|
51
invoke.ccp
51
invoke.ccp
@ -194,7 +194,7 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
|
||||
switch cmd:
|
||||
case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
|
||||
if !c->arg.valid ():
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
unsigned cap = (unsigned)c->arg->target
|
||||
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
|
||||
@ -211,7 +211,7 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
|
||||
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
|
||||
if !c->arg.valid () || c->arg->target != receiver:
|
||||
dpanic (0, "wrong argument for get_protected")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
reply_num (c->arg->protected_data)
|
||||
return
|
||||
@ -303,12 +303,12 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
return
|
||||
default:
|
||||
dpanic (0, "invalid create type")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
break
|
||||
case Kernel::Memory::DESTROY & REQUEST_MASK:
|
||||
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem:
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
switch (unsigned)c->arg->target & CAPTYPE_MASK:
|
||||
case CAPTYPE_RECEIVER:
|
||||
@ -337,12 +337,12 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
// FIXME: this should work for fake pages as well.
|
||||
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
|
||||
dpanic (0x22993341, "Trying to map non-page")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
if page->address_space != mem:
|
||||
dpanic (0x52993341, "Trying to map foreign page")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY
|
||||
mem->map (page, c->data[1].l & PAGE_MASK, readonly)
|
||||
@ -350,6 +350,9 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
case Kernel::Memory::MAPPING & REQUEST_MASK:
|
||||
bool readonly
|
||||
kPage *page = mem->get_mapping (c->data[1].l, &readonly)
|
||||
if !page:
|
||||
reply_num (Kernel::ERR_UNMAPPED_READ)
|
||||
return
|
||||
unsigned t = CAPTYPE_PAGE | CAP_MASTER
|
||||
if readonly:
|
||||
t |= Kernel::Page::READONLY
|
||||
@ -421,12 +424,12 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
if c->data[1].l >= thread->slots || !c->arg.valid ():
|
||||
dbg_send (5, 3)
|
||||
dpanic (c->data[1].l, "no argument given for USE_SLOT")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
// FIXME: This doesn't allow using a fake caps.
|
||||
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE):
|
||||
dpanic (0, "argument for USE_SLOT is not a caps")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
unsigned slot = c->data[1].l
|
||||
kCaps *new_caps = (kCaps *)c->arg->protected_data.l
|
||||
@ -465,14 +468,14 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
return
|
||||
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
|
||||
break
|
||||
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
||||
panic (0x54365435, "non-memory argument to alloc_range")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kMemory *mem = (kMemory *)c->arg->protected_data.l
|
||||
if !mem->use (c->data[1].l):
|
||||
@ -490,11 +493,11 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
|
||||
if !c->arg.valid ():
|
||||
panic (0x71342134, "no argument provided for alloc physical")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
panic (0x21342134, "no page provided for alloc physical")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
page->forget ()
|
||||
@ -519,7 +522,7 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
|
||||
dpanic (0x99049380, "invalid page for physical address")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
@ -571,11 +574,11 @@ 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.
|
||||
reply_num (~0)
|
||||
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.
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *t = (kPage *)c->arg->protected_data.l
|
||||
t->forget ()
|
||||
@ -645,7 +648,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
break
|
||||
case Kernel::Page::SET_FLAGS & REQUEST_MASK:
|
||||
if cmd & Kernel::Page::READONLY:
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_WRITE_DENIED)
|
||||
return
|
||||
// Always refuse to set reserved flags.
|
||||
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
||||
@ -785,12 +788,12 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
else:
|
||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
|
||||
dpanic (0, "invalid request for list: arg is no listitem")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
item = (kListitem *)c->arg->protected_data.l
|
||||
if item->list != list:
|
||||
dpanic (0, "item list is not equal to called object")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
switch cmd:
|
||||
case Kernel::List::GET_NEXT & REQUEST_MASK:
|
||||
@ -799,7 +802,7 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
else:
|
||||
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::LIST:
|
||||
dpanic (0, "trying to get next listitem with insufficient rights")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
item = item->next_item
|
||||
if !item:
|
||||
@ -810,32 +813,32 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
case Kernel::List::ADD_ITEM & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::ADD:
|
||||
dpanic (0, "trying to add listitem with insufficient rights")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
((kListitem *)c->arg->protected_data.l)->add (list)
|
||||
break
|
||||
case Kernel::List::GET_INFO & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "no item for List::GET_INFO")
|
||||
reply_num (~0, ~0, ~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT, ~0, ~0)
|
||||
return
|
||||
reply_num (item->info)
|
||||
return
|
||||
case Kernel::List::SET_INFO & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "no item for List::SET_INFO")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
item->info = c->data[1]
|
||||
break
|
||||
case Kernel::List::GET_CAP & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "no item for List::GET_CAP")
|
||||
reply_num (~0)
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kCapability *cap = item->target.cap (0)
|
||||
reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities)
|
||||
|
10
iris.hhp
10
iris.hhp
@ -86,6 +86,7 @@ namespace Kernel:
|
||||
ERR_OUT_OF_MEMORY
|
||||
// The following are not raised, but returned.
|
||||
ERR_INVALID_OPERATION
|
||||
ERR_INVALID_ARGUMENT
|
||||
NUM_EXCEPTION_CODES
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -378,7 +379,7 @@ namespace Kernel:
|
||||
return get_info (SP)
|
||||
unsigned get_flags ():
|
||||
return get_info (FLAGS)
|
||||
void run (bool run):
|
||||
void run (bool run = true):
|
||||
set_flags (run ? RUNNING : 0, RUNNING)
|
||||
void wait (bool wait):
|
||||
set_flags (wait ? WAITING : 0, WAITING)
|
||||
@ -454,8 +455,9 @@ namespace Kernel:
|
||||
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
|
||||
unsigned get_flags ():
|
||||
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
|
||||
void set_flags (unsigned new_flags, unsigned mask):
|
||||
bool set_flags (unsigned new_flags, unsigned mask):
|
||||
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
|
||||
return recv.data[0].l == NO_ERROR
|
||||
unsigned physical_address ():
|
||||
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
||||
void alloc_physical (unsigned address, bool cachable, bool freeable):
|
||||
@ -536,10 +538,10 @@ namespace Kernel:
|
||||
void destroy (Cap target):
|
||||
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
||||
// TODO: LIST
|
||||
void map (Cap page, unsigned address, bool readonly = false):
|
||||
bool map (Cap page, unsigned address, bool readonly = false):
|
||||
if readonly:
|
||||
address |= Page::READONLY
|
||||
ocall (page, CAP_MASTER_DIRECT | MAP, address)
|
||||
return ocall (page, CAP_MASTER_DIRECT | MAP, address).l != ~0
|
||||
Page mapping (void *address):
|
||||
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
|
||||
return get_arg ()
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
load = 0x80000000
|
||||
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=6
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=2
|
||||
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
|
||||
CROSS = mipsel-linux-gnu-
|
||||
OBJDUMP = $(CROSS)objdump
|
||||
@ -28,7 +28,10 @@ LDFLAGS = --omagic -Ttext $(load)
|
||||
arch_iris_sources = mips/interrupts.cc mips/arch.cc
|
||||
boot_sources = mips/init.cc mips/nanonote/board.cc
|
||||
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
|
||||
boot_threads = init udc nanonote-gpio buzzer metronome lcd
|
||||
boot_threads = init udc
|
||||
programs = nanonote-gpio buzzer metronome lcd
|
||||
|
||||
all: test $(addsuffix .elf,$(addprefix fs/,$(programs)))
|
||||
|
||||
test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw
|
||||
echo "reboot 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')" | nc localhost 5050
|
||||
@ -53,6 +56,7 @@ mips/nanonote/sdram-setup.elf: LDFLAGS = --omagic -T mips/nanonote/sdram-setup.l
|
||||
mips/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
|
||||
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
|
||||
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 boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <shevek/mainloop.hh>
|
||||
#include <shevek/server.hh>
|
||||
#include <shevek/args.hh>
|
||||
#include "devices.hh"
|
||||
|
||||
struct client
|
||||
|
||||
@ -69,18 +71,87 @@ struct data:
|
||||
|
||||
void data::poll ():
|
||||
while true:
|
||||
char buffer[2]
|
||||
int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, buffer, 8, timeout)
|
||||
if s < 1 || s > 2 || buffer[0] != '#':
|
||||
unsigned buffer[2]
|
||||
int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, (char *)buffer, 8, timeout)
|
||||
if s != 8:
|
||||
std::cerr << "unable to send poll message to device: " << usb_strerror () << std::endl
|
||||
usb_release_interface (handle, 0)
|
||||
usb_close (handle)
|
||||
handle = NULL
|
||||
return
|
||||
if s != 1:
|
||||
std::cout << buffer[1] << std::flush
|
||||
else:
|
||||
break
|
||||
switch buffer[0] & 0xffff:
|
||||
case ~0 & 0xffff:
|
||||
// Log character.
|
||||
std::cout << (char)buffer[1] << std::flush
|
||||
continue
|
||||
case ~1 & 0xffff:
|
||||
// No event.
|
||||
break
|
||||
case Directory::GET_SIZE:
|
||||
unsigned long long size = dir.size ()
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_SIZE, 0, 0, (char const *)&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
|
||||
case Directory::GET_NAME:
|
||||
if buffer[1] >= dir.size ():
|
||||
std::cerr << "invalid file name requested" << std::endl;
|
||||
usb_release_interface (handle, 0)
|
||||
usb_close (handle)
|
||||
handle = NULL
|
||||
return
|
||||
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)
|
||||
usb_close (handle)
|
||||
handle = NULL
|
||||
return
|
||||
continue
|
||||
case Directory::LOCK_RO:
|
||||
if !lock++:
|
||||
dir.load (files)
|
||||
continue
|
||||
case Directory::UNLOCK_RO:
|
||||
if !lock:
|
||||
std::cerr << "unlocking without lock" << std::endl
|
||||
usb_release_interface (handle, 0)
|
||||
usb_close (handle)
|
||||
handle = NULL
|
||||
return
|
||||
--lock
|
||||
continue
|
||||
case Directory::GET_FILE_RO:
|
||||
unsigned f = buffer[0] >> 16
|
||||
if f >= 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])
|
||||
file.seek (buffer[1] << 12)
|
||||
char page[1 << 12]
|
||||
memset (page, 0, 1 << 12)
|
||||
file.read (page, 1 << 12)
|
||||
for unsigned i = 0; i < (1 << 12); i += 64:
|
||||
if usb_bulk_write (handle, 1 | USB_ENDPOINT_OUT, p, 64) != 64:
|
||||
std::cerr << "unable to send file 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
|
||||
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))
|
||||
|
||||
struct client : public shevek::server <client, data *>::connection:
|
||||
|
@ -29,22 +29,6 @@ thread1:
|
||||
|
||||
.balign 0x1000
|
||||
thread2:
|
||||
.incbin "nanonote-gpio.elf"
|
||||
|
||||
.balign 0x1000
|
||||
thread3:
|
||||
.incbin "buzzer.elf"
|
||||
|
||||
.balign 0x1000
|
||||
thread4:
|
||||
.incbin "metronome.elf"
|
||||
|
||||
.balign 0x1000
|
||||
thread5:
|
||||
.incbin "lcd.elf"
|
||||
|
||||
.balign 0x1000
|
||||
thread6:
|
||||
|
||||
// Everything from here may be freed after kernel initialization.
|
||||
init_start:
|
||||
@ -53,7 +37,3 @@ thread_start:
|
||||
.word thread0
|
||||
.word thread1
|
||||
.word thread2
|
||||
.word thread3
|
||||
.word thread4
|
||||
.word thread5
|
||||
.word thread6
|
||||
|
143
source/crt0.ccp
Normal file
143
source/crt0.ccp
Normal file
@ -0,0 +1,143 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/init.S: Startup code for initial Threads.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "iris.hh"
|
||||
#include "devices.hh"
|
||||
|
||||
// For some unknown reason, gcc needs this to be defined.
|
||||
unsigned __gxx_personality_v0
|
||||
|
||||
struct list:
|
||||
list *prev, *next
|
||||
|
||||
static unsigned __slots, __caps
|
||||
static list *__slot_admin, *__cap_admin
|
||||
static list *__first_free_slot, *__first_free_cap
|
||||
|
||||
namespace Kernel:
|
||||
Receiver my_receiver
|
||||
Thread my_thread
|
||||
Memory my_memory
|
||||
Cap my_call
|
||||
Parent my_parent
|
||||
__recv_data_t recv
|
||||
|
||||
void print_caps ():
|
||||
// Assume __caps to be 16.
|
||||
bool used[16]
|
||||
for unsigned i = 0; i < 16; ++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 (":")
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
kdebug_char (used[i] ? '#' : '.')
|
||||
kdebug_char ('\n')
|
||||
|
||||
void free_slot (unsigned slot):
|
||||
//kdebug ("free slot\n")
|
||||
__slot_admin[slot].prev = NULL
|
||||
__slot_admin[slot].next = __first_free_slot
|
||||
if __slot_admin[slot].next:
|
||||
__slot_admin[slot].next->prev = &__slot_admin[slot]
|
||||
__first_free_slot = &__slot_admin[slot]
|
||||
|
||||
void free_cap (Cap cap):
|
||||
//kdebug ("free cap\n")
|
||||
if cap.slot () != 0:
|
||||
kdebug ("trying to free capability from non-0 slot\n")
|
||||
return
|
||||
list *l = &__cap_admin[cap.idx ()]
|
||||
l->prev = NULL
|
||||
l->next = __first_free_cap
|
||||
if l->next:
|
||||
l->next->prev = l
|
||||
__first_free_cap = l
|
||||
|
||||
unsigned alloc_slot ():
|
||||
//kdebug ("alloc slot\n")
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
return ~0
|
||||
list *ret = __first_free_slot
|
||||
__first_free_slot = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
return ret - __slot_admin
|
||||
|
||||
Cap alloc_cap ():
|
||||
//kdebug ("alloc cap\n")
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
return Cap (0, CAP_NONE)
|
||||
list *ret = __first_free_cap
|
||||
__first_free_cap = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
return Cap (0, ret - __cap_admin)
|
||||
|
||||
extern "C":
|
||||
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
__slots = slots
|
||||
__caps = caps
|
||||
__slot_admin = slot_admin
|
||||
__cap_admin = cap_admin
|
||||
__first_free_slot = NULL
|
||||
for unsigned i = 2; i < __slots; ++i:
|
||||
Kernel::free_slot (i)
|
||||
__first_free_cap = NULL
|
||||
for unsigned i = 7; i < __caps; ++i:
|
||||
Kernel::free_cap (Kernel::Cap (0, i))
|
||||
Kernel::my_receiver = Kernel::Cap (0, __receiver_num)
|
||||
Kernel::my_thread = Kernel::Cap (0, __thread_num)
|
||||
Kernel::my_memory = Kernel::Cap (0, __memory_num)
|
||||
Kernel::my_call = Kernel::Cap (0, __call_num)
|
||||
Kernel::my_parent = Kernel::Cap (0, __parent_num)
|
||||
Kernel::recv.reply = Kernel::alloc_cap ()
|
||||
Kernel::recv.arg = Kernel::alloc_cap ()
|
||||
Kernel::Num ret = start ()
|
||||
Kernel::my_parent.invoke (~0, ret)
|
||||
Kernel::my_memory.destroy (Kernel::my_thread)
|
||||
// The program no longer exists. If it somehow does, generate an address fault.
|
||||
while true:
|
||||
*(volatile unsigned *)~0
|
||||
|
||||
__asm__ volatile ("\t.globl __start\n"
|
||||
"\t.set noreorder\n"
|
||||
"__start:\n"
|
||||
"\tbal 1f\n"
|
||||
"__hack_label:\n"
|
||||
"\tnop\n"
|
||||
"\t.word _gp\n"
|
||||
"1:\n"
|
||||
"\tlw $gp, 0($ra)\n"
|
||||
"\tsll $v0, $a0, 3\n"
|
||||
"\tsll $v1, $a1, 3\n"
|
||||
"\tsubu $sp, $sp, $v0\n"
|
||||
"\tmove $a2, $sp\n"
|
||||
"\tsubu $sp, $sp, $v1\n"
|
||||
"\tmove $a3, $sp\n"
|
||||
"\tla $t9, run__main\n"
|
||||
"\tjr $t9\n"
|
||||
"\tnop\n"
|
||||
"\t.set reorder")
|
Loading…
Reference in New Issue
Block a user