mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 19:44:16 +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
|
*.elf
|
||||||
*.cc
|
*.cc
|
||||||
*.hh
|
*.hh
|
||||||
gpio
|
|
||||||
lcd
|
|
||||||
init
|
|
||||||
udc
|
|
||||||
buzzer
|
|
||||||
metronome
|
|
||||||
nanonote-gpio
|
|
||||||
boot-programs/charset.data
|
boot-programs/charset.data
|
||||||
mips/nanonote/sdram-setup.raw
|
mips/nanonote/sdram-setup.raw
|
||||||
nanonote-boot
|
nanonote-boot
|
||||||
|
4
Makefile
4
Makefile
@ -46,6 +46,10 @@ PYPP = /usr/bin/pypp
|
|||||||
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
|
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
|
||||||
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
|
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
|
||||||
|
|
||||||
|
fs/%.elf: source/crt0.o source/%.o
|
||||||
|
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
|
||||||
|
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)
|
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ namespace Kernel:
|
|||||||
return Cap (0, ret - __cap_admin)
|
return Cap (0, ret - __cap_admin)
|
||||||
|
|
||||||
extern "C":
|
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
|
__slots = slots
|
||||||
__caps = caps
|
__caps = caps
|
||||||
__slot_admin = slot_admin
|
__slot_admin = slot_admin
|
||||||
@ -137,7 +137,7 @@ __asm__ volatile ("\t.globl __start\n"
|
|||||||
"\tmove $a2, $sp\n"
|
"\tmove $a2, $sp\n"
|
||||||
"\tsubu $sp, $sp, $v1\n"
|
"\tsubu $sp, $sp, $v1\n"
|
||||||
"\tmove $a3, $sp\n"
|
"\tmove $a3, $sp\n"
|
||||||
"\tla $t9, __main\n"
|
"\tla $t9, run__main\n"
|
||||||
"\tjr $t9\n"
|
"\tjr $t9\n"
|
||||||
"\tnop\n"
|
"\tnop\n"
|
||||||
"\t.set reorder")
|
"\t.set reorder")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pypp 0
|
#pypp 0
|
||||||
// Iris: micro-kernel for a capability-based operating system.
|
// 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>
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
@ -18,136 +18,288 @@
|
|||||||
|
|
||||||
#include "devices.hh"
|
#include "devices.hh"
|
||||||
#include "iris.hh"
|
#include "iris.hh"
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
static Keyboard sysreq
|
#define NUM_SLOTS 4
|
||||||
static Device kbd_dev, buz_dev, backlight_dev, rootfs_dev
|
#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 slot
|
||||||
|
static unsigned max_pages
|
||||||
|
static char *mapping
|
||||||
|
static unsigned current_thread
|
||||||
|
|
||||||
// Event types.
|
// Get the initial block device and filesystem.
|
||||||
enum type:
|
static Directory receive_devices ():
|
||||||
SYSREQ
|
String data
|
||||||
KBDDEV
|
Filesystem fs
|
||||||
BUZDEV
|
bool have_data = false, have_fs = false
|
||||||
BACKLIGHTDEV
|
for unsigned i = 0; i < 2; ++i:
|
||||||
ROOTFSDEV
|
Device dev
|
||||||
|
|
||||||
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:
|
|
||||||
Kernel::wait ()
|
Kernel::wait ()
|
||||||
Kernel::Cap reply = Kernel::get_reply ()
|
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
|
||||||
Kernel::Cap arg = Kernel::get_arg ()
|
kdebug ("Invalid bootstrap request.\n")
|
||||||
switch Kernel::recv.data[0].l:
|
Kernel::panic (0)
|
||||||
case Parent::PROVIDE_DEVICE:
|
switch Kernel::recv.data[1].l:
|
||||||
switch Kernel::recv.data[1].l:
|
case String::ID:
|
||||||
case Keyboard::ID:
|
if have_data:
|
||||||
switch Kernel::recv.data[0].h:
|
kdebug ("duplicate device.\n")
|
||||||
case 0:
|
Kernel::panic (0)
|
||||||
caps.set (KBDDEV, arg.copy ())
|
dev = Kernel::get_arg ()
|
||||||
kbd_dev = Kernel::Cap (slot, KBDDEV)
|
have_data = true
|
||||||
break
|
Kernel::recv.reply.invoke ()
|
||||||
case 1:
|
data = dev.create_user (Kernel::my_memory)
|
||||||
caps.set (SYSREQ, arg.copy ())
|
dev.use (data)
|
||||||
sysreq = Kernel::Cap (slot, SYSREQ)
|
Kernel::free_cap (dev)
|
||||||
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
|
|
||||||
break
|
break
|
||||||
case Parent::GET_DEVICE:
|
case Filesystem::ID:
|
||||||
user = reply
|
if have_fs:
|
||||||
device = Kernel::recv.data[1].l
|
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
|
break
|
||||||
default:
|
default:
|
||||||
kdebug ("unknown setup request for init\n")
|
kdebug ("unexpected device: ")
|
||||||
reply.invoke ()
|
kdebug_num (Kernel::recv.data[1].l)
|
||||||
Kernel::free_cap (reply)
|
kdebug_char ('\n')
|
||||||
Kernel::free_cap (arg)
|
Kernel::panic (0)
|
||||||
continue
|
// Initialize the root file system.
|
||||||
Kernel::free_cap (arg)
|
Directory root = fs.use_device_ro (data.copy ())
|
||||||
if ++state == 6:
|
Kernel::free_cap (data)
|
||||||
break
|
Kernel::free_cap (fs)
|
||||||
// sysreq
|
return root
|
||||||
Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
|
|
||||||
sysreq.set_cb (cb.copy ())
|
// Make a list of all files.
|
||||||
Kernel::free_cap (cb)
|
static void list_files (Directory root):
|
||||||
// First user reply.
|
Kernel::Num fullsize = root.get_size ()
|
||||||
user_reply (user, device)
|
if fullsize.h != 0:
|
||||||
Kernel::free_cap (user)
|
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 ():
|
Kernel::Num start ():
|
||||||
|
// Wait for the debugging device to be active, in case there is one.
|
||||||
Kernel::schedule ()
|
Kernel::schedule ()
|
||||||
setup ()
|
top_memory = Kernel::get_top_memory ()
|
||||||
// claim backlight
|
Directory root = receive_devices ()
|
||||||
Setting backlight = backlight_dev.create_user (Kernel::Cap ())
|
root.lock_ro ()
|
||||||
backlight_dev.use (backlight)
|
list_files (root)
|
||||||
bool backlight_state = true
|
sort ()
|
||||||
while true:
|
Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
|
||||||
Kernel::wait ()
|
slot = caps.use ()
|
||||||
switch Kernel::recv.protected_data.value ():
|
mapping = alloc_space (max_pages)
|
||||||
case SYSREQ:
|
for unsigned i = 0; i < num_files; ++i:
|
||||||
unsigned code = Kernel::recv.data[0].l
|
run (&files[index[i]], files[index[i]].name[0] == '#')
|
||||||
if !(code & Keyboard::RELEASE):
|
root.unlock_ro ()
|
||||||
backlight_state = !backlight_state
|
Kernel::free_slot (slot)
|
||||||
backlight.set (backlight_state ? ~0 : 0)
|
Kernel::my_memory.destroy (caps)
|
||||||
break
|
return 0
|
||||||
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
|
|
||||||
|
@ -150,17 +150,19 @@ class Udc:
|
|||||||
char configuration
|
char configuration
|
||||||
unsigned size
|
unsigned size
|
||||||
char const *ptr
|
char const *ptr
|
||||||
|
unsigned cmd_code, cmd_arg
|
||||||
bool rebooting
|
bool rebooting
|
||||||
bool vendor (Setup *s)
|
bool vendor (Setup *s, unsigned cmd)
|
||||||
bool get_descriptor (unsigned type, unsigned idx, unsigned len)
|
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]
|
char log_buffer[1000]
|
||||||
unsigned log_buffer_size
|
unsigned log_buffer_size
|
||||||
unsigned log_buffer_start
|
unsigned log_buffer_start
|
||||||
public:
|
public:
|
||||||
void init ()
|
void init ()
|
||||||
void log (unsigned c)
|
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::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 = {
|
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' } }
|
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_size = 0
|
||||||
log_buffer_start = 0
|
log_buffer_start = 0
|
||||||
|
cmd_code = ~0
|
||||||
|
cmd_arg = 0
|
||||||
|
|
||||||
// Disconnect from the bus and don't try to get high-speed.
|
// Disconnect from the bus and don't try to get high-speed.
|
||||||
UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB)
|
UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB)
|
||||||
@ -221,21 +225,35 @@ void Udc::init ():
|
|||||||
// Connect to the host.
|
// Connect to the host.
|
||||||
UDC_POWER |= UDC_POWER_SOFTCONN
|
UDC_POWER |= UDC_POWER_SOFTCONN
|
||||||
|
|
||||||
bool Udc::vendor (Setup *s):
|
bool Udc::vendor (Setup *s, unsigned cmd):
|
||||||
if !(s->request_type & 0x80):
|
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
|
return true
|
||||||
if s->request == 10:
|
if s->request == 10:
|
||||||
static char b[2]
|
static unsigned b[2]
|
||||||
ptr = b
|
ptr = (char *)b
|
||||||
size = s->length < 2 ? s->length : 2
|
size = s->length < 8 ? s->length : 8
|
||||||
b[0] = '#'
|
if cmd_code != ~0:
|
||||||
if log_buffer_start == log_buffer_size:
|
b[0] = cmd_code
|
||||||
size = 1
|
b[1] = cmd_arg
|
||||||
|
cmd_code = ~0
|
||||||
else:
|
else:
|
||||||
b[1] = log_buffer[log_buffer_start++]
|
if log_buffer_start == log_buffer_size:
|
||||||
if log_buffer_start == log_buffer_size:
|
b[0] = ~1
|
||||||
log_buffer_start = 0
|
b[1] = 0
|
||||||
log_buffer_size = 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:
|
else:
|
||||||
static char const *name = "Reboot"
|
static char const *name = "Reboot"
|
||||||
ptr = name
|
ptr = name
|
||||||
@ -244,6 +262,13 @@ bool Udc::vendor (Setup *s):
|
|||||||
state = TX
|
state = TX
|
||||||
return true
|
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):
|
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||||
switch type:
|
switch type:
|
||||||
case Configuration::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))
|
//size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
|
||||||
//break
|
//break
|
||||||
return false
|
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:
|
case String <6>::Type:
|
||||||
switch idx:
|
switch idx:
|
||||||
case 0:
|
case 0:
|
||||||
@ -288,7 +313,7 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
|||||||
state = TX
|
state = TX
|
||||||
return true
|
return true
|
||||||
|
|
||||||
bool Udc::handle_setup (Setup *s):
|
bool Udc::handle_setup (Setup *s, unsigned cmd):
|
||||||
switch s->request_type:
|
switch s->request_type:
|
||||||
case STANDARD_TO_DEVICE:
|
case STANDARD_TO_DEVICE:
|
||||||
switch s->request:
|
switch s->request:
|
||||||
@ -331,12 +356,12 @@ bool Udc::handle_setup (Setup *s):
|
|||||||
break
|
break
|
||||||
case VENDOR_TO_DEVICE:
|
case VENDOR_TO_DEVICE:
|
||||||
case VENDOR_FROM_DEVICE:
|
case VENDOR_FROM_DEVICE:
|
||||||
return vendor (s)
|
return vendor (s, cmd)
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
void Udc::interrupt ():
|
void Udc::interrupt (unsigned cmd):
|
||||||
unsigned i = UDC_INTRUSB
|
unsigned i = UDC_INTRUSB
|
||||||
if i & UDC_INTR_RESET:
|
if i & UDC_INTR_RESET:
|
||||||
state = IDLE
|
state = IDLE
|
||||||
@ -361,7 +386,7 @@ void Udc::interrupt ():
|
|||||||
packet.d[0] = UDC_FIFO (0)
|
packet.d[0] = UDC_FIFO (0)
|
||||||
packet.d[1] = UDC_FIFO (0)
|
packet.d[1] = UDC_FIFO (0)
|
||||||
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||||
if !handle_setup (&packet.s):
|
if !handle_setup (&packet.s, cmd):
|
||||||
csr |= UDC_CSR0_SENDSTALL
|
csr |= UDC_CSR0_SENDSTALL
|
||||||
break
|
break
|
||||||
if size == 0:
|
if size == 0:
|
||||||
@ -395,6 +420,8 @@ void Udc::log (unsigned c):
|
|||||||
enum pdata:
|
enum pdata:
|
||||||
LOG = 32
|
LOG = 32
|
||||||
FS
|
FS
|
||||||
|
DATA
|
||||||
|
DIRECTORY
|
||||||
|
|
||||||
Kernel::Num start ():
|
Kernel::Num start ():
|
||||||
map_udc ()
|
map_udc ()
|
||||||
@ -408,52 +435,28 @@ Kernel::Num start ():
|
|||||||
Kernel::register_interrupt (IRQ_UDC)
|
Kernel::register_interrupt (IRQ_UDC)
|
||||||
Device fs_dev = Kernel::my_receiver.create_capability (FS)
|
Device fs_dev = Kernel::my_receiver.create_capability (FS)
|
||||||
Kernel::my_parent.provide_device <Directory> (fs_dev)
|
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 next_user
|
||||||
|
unsigned state = 0
|
||||||
while true:
|
while true:
|
||||||
Kernel::wait ()
|
Kernel::wait ()
|
||||||
|
Kernel::Cap reply = Kernel::get_reply ()
|
||||||
switch Kernel::recv.protected_data.h:
|
switch Kernel::recv.protected_data.h:
|
||||||
case 0:
|
case 0:
|
||||||
switch Kernel::recv.protected_data.l:
|
switch Kernel::recv.protected_data.l:
|
||||||
case IRQ_UDC:
|
case IRQ_UDC:
|
||||||
udc.interrupt ()
|
udc.interrupt (state)
|
||||||
Kernel::register_interrupt (IRQ_UDC)
|
Kernel::register_interrupt (IRQ_UDC)
|
||||||
break
|
break
|
||||||
case LOG:
|
case LOG:
|
||||||
udc.log (Kernel::recv.data[0].l)
|
udc.log (Kernel::recv.data[0].l)
|
||||||
break
|
break
|
||||||
case FS:
|
case FS:
|
||||||
switch Kernel::recv.data[0].l:
|
Device::host (FS, fs_current_user, reply)
|
||||||
case Device::CREATE_USER:
|
continue
|
||||||
Kernel::Cap reply = Kernel::get_reply ()
|
case DATA:
|
||||||
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, FS))
|
Device::host (DATA, data_current_user, reply)
|
||||||
reply.invoke (0, 0, c.copy ())
|
continue
|
||||||
Kernel::free_cap (c)
|
|
||||||
Kernel::free_cap (reply)
|
|
||||||
break
|
|
||||||
case Device::DESTROY_USER:
|
|
||||||
Kernel::Cap reply = Kernel::get_reply ()
|
|
||||||
reply.invoke ()
|
|
||||||
Kernel::free_cap (reply)
|
|
||||||
break
|
|
||||||
case Device::USE:
|
|
||||||
Kernel::Cap reply = Kernel::get_reply ()
|
|
||||||
Kernel::Cap arg = Kernel::get_arg ()
|
|
||||||
current_user = Kernel::my_receiver.get_protected (arg)
|
|
||||||
reply.invoke ()
|
|
||||||
Kernel::free_cap (reply)
|
|
||||||
Kernel::free_cap (arg)
|
|
||||||
break
|
|
||||||
case Device::UNUSE:
|
|
||||||
Kernel::Cap reply = Kernel::get_reply ()
|
|
||||||
Kernel::Cap arg = Kernel::get_arg ()
|
|
||||||
if current_user.value () == Kernel::my_receiver.get_protected (arg).value ():
|
|
||||||
current_user = 0
|
|
||||||
reply.invoke ()
|
|
||||||
Kernel::free_cap (reply)
|
|
||||||
Kernel::free_cap (arg)
|
|
||||||
break
|
|
||||||
break
|
|
||||||
default:
|
default:
|
||||||
udc.log ('~')
|
udc.log ('~')
|
||||||
char digit[] = "0123456789abcdef"
|
char digit[] = "0123456789abcdef"
|
||||||
@ -461,18 +464,55 @@ Kernel::Num start ():
|
|||||||
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
||||||
udc.log ('\n')
|
udc.log ('\n')
|
||||||
break
|
break
|
||||||
case FS:
|
case DATA:
|
||||||
if current_user.value () != Kernel::recv.protected_data.value ():
|
if data_current_user != Kernel::recv.protected_data.l:
|
||||||
break
|
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:
|
switch Kernel::recv.data[0].l:
|
||||||
case Directory::GET_SIZE:
|
case Directory::GET_SIZE:
|
||||||
case Directory::GET_NAME:
|
case Directory::GET_NAME:
|
||||||
case Directory::GET_FILE_RO:
|
|
||||||
case Directory::LOCK_RO:
|
case Directory::LOCK_RO:
|
||||||
case Directory::UNLOCK_RO:
|
case Directory::UNLOCK_RO:
|
||||||
Kernel::recv.reply.invoke ()
|
state = Kernel::recv.data[0].l
|
||||||
break
|
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:
|
case Directory::GET_FILE_INFO:
|
||||||
default:
|
default:
|
||||||
Kernel::recv.reply.invoke (~0)
|
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||||
break
|
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.
|
// Make user active. It makes the previous active user inactive.
|
||||||
void use (Kernel::Cap user):
|
void use (Kernel::Cap user):
|
||||||
ocall (user, CAP_MASTER_DIRECT | USE)
|
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.
|
// Interface for talking to the parent process.
|
||||||
struct Parent : public Kernel::Cap:
|
struct Parent : public Kernel::Cap:
|
||||||
@ -270,11 +304,25 @@ struct WDirectory : public Directory:
|
|||||||
void unlock ():
|
void unlock ():
|
||||||
call (CAP_MASTER_DIRECT | 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.
|
// Stream interface.
|
||||||
struct Stream : public Kernel::Cap:
|
struct Stream : public Kernel::Cap:
|
||||||
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
READ = WDirectory::ID
|
READ = Filesystem::ID
|
||||||
WRITE
|
WRITE
|
||||||
ID
|
ID
|
||||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
// 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:
|
switch cmd:
|
||||||
case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
|
case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
|
||||||
if !c->arg.valid ():
|
if !c->arg.valid ():
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
unsigned cap = (unsigned)c->arg->target
|
unsigned cap = (unsigned)c->arg->target
|
||||||
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
|
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:
|
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
|
||||||
if !c->arg.valid () || c->arg->target != receiver:
|
if !c->arg.valid () || c->arg->target != receiver:
|
||||||
dpanic (0, "wrong argument for get_protected")
|
dpanic (0, "wrong argument for get_protected")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
reply_num (c->arg->protected_data)
|
reply_num (c->arg->protected_data)
|
||||||
return
|
return
|
||||||
@ -303,12 +303,12 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
|||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
dpanic (0, "invalid create type")
|
dpanic (0, "invalid create type")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
break
|
break
|
||||||
case Kernel::Memory::DESTROY & REQUEST_MASK:
|
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:
|
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
|
return
|
||||||
switch (unsigned)c->arg->target & CAPTYPE_MASK:
|
switch (unsigned)c->arg->target & CAPTYPE_MASK:
|
||||||
case CAPTYPE_RECEIVER:
|
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.
|
// 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:
|
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")
|
dpanic (0x22993341, "Trying to map non-page")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
kPage *page = (kPage *)c->arg->protected_data.l
|
kPage *page = (kPage *)c->arg->protected_data.l
|
||||||
if page->address_space != mem:
|
if page->address_space != mem:
|
||||||
dpanic (0x52993341, "Trying to map foreign page")
|
dpanic (0x52993341, "Trying to map foreign page")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY
|
bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY
|
||||||
mem->map (page, c->data[1].l & PAGE_MASK, 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:
|
case Kernel::Memory::MAPPING & REQUEST_MASK:
|
||||||
bool readonly
|
bool readonly
|
||||||
kPage *page = mem->get_mapping (c->data[1].l, &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
|
unsigned t = CAPTYPE_PAGE | CAP_MASTER
|
||||||
if readonly:
|
if readonly:
|
||||||
t |= Kernel::Page::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 ():
|
if c->data[1].l >= thread->slots || !c->arg.valid ():
|
||||||
dbg_send (5, 3)
|
dbg_send (5, 3)
|
||||||
dpanic (c->data[1].l, "no argument given for USE_SLOT")
|
dpanic (c->data[1].l, "no argument given for USE_SLOT")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
// FIXME: This doesn't allow using a fake caps.
|
// 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):
|
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")
|
dpanic (0, "argument for USE_SLOT is not a caps")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
unsigned slot = c->data[1].l
|
unsigned slot = c->data[1].l
|
||||||
kCaps *new_caps = (kCaps *)c->arg->protected_data.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
|
return
|
||||||
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
|
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
|
||||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
|
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
|
||||||
break
|
break
|
||||||
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
|
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
|
||||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
||||||
panic (0x54365435, "non-memory argument to alloc_range")
|
panic (0x54365435, "non-memory argument to alloc_range")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
kMemory *mem = (kMemory *)c->arg->protected_data.l
|
kMemory *mem = (kMemory *)c->arg->protected_data.l
|
||||||
if !mem->use (c->data[1].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:
|
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
|
||||||
if !c->arg.valid ():
|
if !c->arg.valid ():
|
||||||
panic (0x71342134, "no argument provided for alloc physical")
|
panic (0x71342134, "no argument provided for alloc physical")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||||
panic (0x21342134, "no page provided for alloc physical")
|
panic (0x21342134, "no page provided for alloc physical")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
kPage *page = (kPage *)c->arg->protected_data.l
|
kPage *page = (kPage *)c->arg->protected_data.l
|
||||||
page->forget ()
|
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:
|
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
|
||||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
|
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
|
||||||
dpanic (0x99049380, "invalid page for physical address")
|
dpanic (0x99049380, "invalid page for physical address")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
kPage *page = (kPage *)c->arg->protected_data.l
|
kPage *page = (kPage *)c->arg->protected_data.l
|
||||||
reply_num (page->frame & ~0xc0000000)
|
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:
|
case Kernel::Page::SHARE & REQUEST_MASK:
|
||||||
if !c->arg.valid ():
|
if !c->arg.valid ():
|
||||||
// Cannot share without a target page.
|
// Cannot share without a target page.
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||||
// FIXME: This makes it impossible to use a fake kPage capability.
|
// FIXME: This makes it impossible to use a fake kPage capability.
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
kPage *t = (kPage *)c->arg->protected_data.l
|
kPage *t = (kPage *)c->arg->protected_data.l
|
||||||
t->forget ()
|
t->forget ()
|
||||||
@ -645,7 +648,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
|||||||
break
|
break
|
||||||
case Kernel::Page::SET_FLAGS & REQUEST_MASK:
|
case Kernel::Page::SET_FLAGS & REQUEST_MASK:
|
||||||
if cmd & Kernel::Page::READONLY:
|
if cmd & Kernel::Page::READONLY:
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_WRITE_DENIED)
|
||||||
return
|
return
|
||||||
// Always refuse to set reserved flags.
|
// Always refuse to set reserved flags.
|
||||||
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
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:
|
else:
|
||||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
|
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
|
||||||
dpanic (0, "invalid request for list: arg is no listitem")
|
dpanic (0, "invalid request for list: arg is no listitem")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
item = (kListitem *)c->arg->protected_data.l
|
item = (kListitem *)c->arg->protected_data.l
|
||||||
if item->list != list:
|
if item->list != list:
|
||||||
dpanic (0, "item list is not equal to called object")
|
dpanic (0, "item list is not equal to called object")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
switch cmd:
|
switch cmd:
|
||||||
case Kernel::List::GET_NEXT & REQUEST_MASK:
|
case Kernel::List::GET_NEXT & REQUEST_MASK:
|
||||||
@ -799,7 +802,7 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
|||||||
else:
|
else:
|
||||||
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::LIST:
|
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")
|
dpanic (0, "trying to get next listitem with insufficient rights")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
item = item->next_item
|
item = item->next_item
|
||||||
if !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:
|
case Kernel::List::ADD_ITEM & REQUEST_MASK:
|
||||||
if !item:
|
if !item:
|
||||||
dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
|
dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::ADD:
|
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")
|
dpanic (0, "trying to add listitem with insufficient rights")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
((kListitem *)c->arg->protected_data.l)->add (list)
|
((kListitem *)c->arg->protected_data.l)->add (list)
|
||||||
break
|
break
|
||||||
case Kernel::List::GET_INFO & REQUEST_MASK:
|
case Kernel::List::GET_INFO & REQUEST_MASK:
|
||||||
if !item:
|
if !item:
|
||||||
dpanic (0, "no item for List::GET_INFO")
|
dpanic (0, "no item for List::GET_INFO")
|
||||||
reply_num (~0, ~0, ~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT, ~0, ~0)
|
||||||
return
|
return
|
||||||
reply_num (item->info)
|
reply_num (item->info)
|
||||||
return
|
return
|
||||||
case Kernel::List::SET_INFO & REQUEST_MASK:
|
case Kernel::List::SET_INFO & REQUEST_MASK:
|
||||||
if !item:
|
if !item:
|
||||||
dpanic (0, "no item for List::SET_INFO")
|
dpanic (0, "no item for List::SET_INFO")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
item->info = c->data[1]
|
item->info = c->data[1]
|
||||||
break
|
break
|
||||||
case Kernel::List::GET_CAP & REQUEST_MASK:
|
case Kernel::List::GET_CAP & REQUEST_MASK:
|
||||||
if !item:
|
if !item:
|
||||||
dpanic (0, "no item for List::GET_CAP")
|
dpanic (0, "no item for List::GET_CAP")
|
||||||
reply_num (~0)
|
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||||
return
|
return
|
||||||
kCapability *cap = item->target.cap (0)
|
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)
|
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
|
ERR_OUT_OF_MEMORY
|
||||||
// The following are not raised, but returned.
|
// The following are not raised, but returned.
|
||||||
ERR_INVALID_OPERATION
|
ERR_INVALID_OPERATION
|
||||||
|
ERR_INVALID_ARGUMENT
|
||||||
NUM_EXCEPTION_CODES
|
NUM_EXCEPTION_CODES
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@ -378,7 +379,7 @@ namespace Kernel:
|
|||||||
return get_info (SP)
|
return get_info (SP)
|
||||||
unsigned get_flags ():
|
unsigned get_flags ():
|
||||||
return get_info (FLAGS)
|
return get_info (FLAGS)
|
||||||
void run (bool run):
|
void run (bool run = true):
|
||||||
set_flags (run ? RUNNING : 0, RUNNING)
|
set_flags (run ? RUNNING : 0, RUNNING)
|
||||||
void wait (bool wait):
|
void wait (bool wait):
|
||||||
set_flags (wait ? WAITING : 0, WAITING)
|
set_flags (wait ? WAITING : 0, WAITING)
|
||||||
@ -454,8 +455,9 @@ namespace Kernel:
|
|||||||
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
|
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
|
||||||
unsigned get_flags ():
|
unsigned get_flags ():
|
||||||
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
|
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))
|
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
|
||||||
|
return recv.data[0].l == NO_ERROR
|
||||||
unsigned physical_address ():
|
unsigned physical_address ():
|
||||||
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
||||||
void alloc_physical (unsigned address, bool cachable, bool freeable):
|
void alloc_physical (unsigned address, bool cachable, bool freeable):
|
||||||
@ -536,10 +538,10 @@ namespace Kernel:
|
|||||||
void destroy (Cap target):
|
void destroy (Cap target):
|
||||||
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
||||||
// TODO: LIST
|
// TODO: LIST
|
||||||
void map (Cap page, unsigned address, bool readonly = false):
|
bool map (Cap page, unsigned address, bool readonly = false):
|
||||||
if readonly:
|
if readonly:
|
||||||
address |= Page::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):
|
Page mapping (void *address):
|
||||||
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
|
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
|
||||||
return get_arg ()
|
return get_arg ()
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
load = 0x80000000
|
load = 0x80000000
|
||||||
|
|
||||||
ARCH_CXXFLAGS = -DNUM_THREADS=6
|
ARCH_CXXFLAGS = -DNUM_THREADS=2
|
||||||
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
|
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
|
||||||
CROSS = mipsel-linux-gnu-
|
CROSS = mipsel-linux-gnu-
|
||||||
OBJDUMP = $(CROSS)objdump
|
OBJDUMP = $(CROSS)objdump
|
||||||
@ -28,7 +28,10 @@ LDFLAGS = --omagic -Ttext $(load)
|
|||||||
arch_iris_sources = mips/interrupts.cc mips/arch.cc
|
arch_iris_sources = mips/interrupts.cc mips/arch.cc
|
||||||
boot_sources = mips/init.cc mips/nanonote/board.cc
|
boot_sources = mips/init.cc mips/nanonote/board.cc
|
||||||
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
|
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
|
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
|
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/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
|
||||||
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
|
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
|
||||||
mips/init.o: TARGET_FLAGS = -I/usr/include
|
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)): TARGET_FLAGS = -I.
|
||||||
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
|
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
|
||||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
|
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
|
||||||
|
@ -22,9 +22,11 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <cstring>
|
||||||
#include <shevek/mainloop.hh>
|
#include <shevek/mainloop.hh>
|
||||||
#include <shevek/server.hh>
|
#include <shevek/server.hh>
|
||||||
#include <shevek/args.hh>
|
#include <shevek/args.hh>
|
||||||
|
#include "devices.hh"
|
||||||
|
|
||||||
struct client
|
struct client
|
||||||
|
|
||||||
@ -69,18 +71,87 @@ struct data:
|
|||||||
|
|
||||||
void data::poll ():
|
void data::poll ():
|
||||||
while true:
|
while true:
|
||||||
char buffer[2]
|
unsigned buffer[2]
|
||||||
int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, buffer, 8, timeout)
|
int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, (char *)buffer, 8, timeout)
|
||||||
if s < 1 || s > 2 || buffer[0] != '#':
|
if s != 8:
|
||||||
std::cerr << "unable to send poll message to device: " << usb_strerror () << std::endl
|
std::cerr << "unable to send poll message to device: " << usb_strerror () << std::endl
|
||||||
usb_release_interface (handle, 0)
|
usb_release_interface (handle, 0)
|
||||||
usb_close (handle)
|
usb_close (handle)
|
||||||
handle = NULL
|
handle = NULL
|
||||||
return
|
return
|
||||||
if s != 1:
|
switch buffer[0] & 0xffff:
|
||||||
std::cout << buffer[1] << std::flush
|
case ~0 & 0xffff:
|
||||||
else:
|
// Log character.
|
||||||
break
|
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))
|
(shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll))
|
||||||
|
|
||||||
struct client : public shevek::server <client, data *>::connection:
|
struct client : public shevek::server <client, data *>::connection:
|
||||||
|
@ -29,22 +29,6 @@ thread1:
|
|||||||
|
|
||||||
.balign 0x1000
|
.balign 0x1000
|
||||||
thread2:
|
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.
|
// Everything from here may be freed after kernel initialization.
|
||||||
init_start:
|
init_start:
|
||||||
@ -53,7 +37,3 @@ thread_start:
|
|||||||
.word thread0
|
.word thread0
|
||||||
.word thread1
|
.word thread1
|
||||||
.word thread2
|
.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