mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-28 12:49:54 +02:00
make things work with unfinished new startup procedure
This commit is contained in:
parent
7c43204a7e
commit
12bfb320f7
1
.gitignore
vendored
1
.gitignore
vendored
@ -21,3 +21,4 @@ mips/nanonote/server/depcomp
|
||||
mips/nanonote/server/install-sh
|
||||
mips/nanonote/server/missing
|
||||
mips/nanonote/server/usb-server
|
||||
fs/
|
||||
|
3
Makefile
3
Makefile
@ -51,6 +51,9 @@ fs/%.elf: source/crt0.o source/%.o
|
||||
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
|
||||
$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
|
||||
|
||||
fs/%: %
|
||||
ln -s ../$< $@
|
||||
|
||||
clean:
|
||||
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)
|
||||
|
||||
|
58
alloc.ccp
58
alloc.ccp
@ -171,6 +171,9 @@ void kMemory::free_obj (kObject *obj, kPointer *first):
|
||||
((kFree *)self->prev)->next = self->next
|
||||
else:
|
||||
frees = (kFree *)self->next
|
||||
//kdebug ("freeing page: ")
|
||||
//kdebug_num ((unsigned)self - SIZE)
|
||||
//kdebug ("\n")
|
||||
pfree ((unsigned)self - SIZE)
|
||||
|
||||
kPage *kMemory::alloc_page ():
|
||||
@ -292,7 +295,7 @@ kMemory *kMemory::alloc_memory ():
|
||||
kMemory_arch_init (ret)
|
||||
return ret
|
||||
|
||||
void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
void kCaps::set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
if index >= size:
|
||||
kdebug ("size: ")
|
||||
kdebug_num (size)
|
||||
@ -300,11 +303,6 @@ void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef p
|
||||
dpanic (index, "index too large for kCaps")
|
||||
return
|
||||
kCapability *c = &caps[index]
|
||||
if (unsigned)target == 0x81fdc350:
|
||||
kdebug ("setting cap ")
|
||||
kdebug_num (index)
|
||||
kdebug (" old target: ")
|
||||
kdebug_num ((unsigned)c->target)
|
||||
c->target = target
|
||||
c->protected_data = pdata
|
||||
c->parent = parent
|
||||
@ -321,8 +319,6 @@ void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef p
|
||||
c->sibling_next.reset ()
|
||||
if c->sibling_next.valid ():
|
||||
c->sibling_next->sibling_prev = kCapRef (this, index)
|
||||
if (unsigned)target == 0x81fdc350:
|
||||
kdebug (" done\n")
|
||||
|
||||
void kCaps::clone (unsigned index, kCapRef source, bool copy):
|
||||
cap (index)->invalidate ()
|
||||
@ -341,10 +337,9 @@ void kCaps::clone (unsigned index, kCapRef source, bool copy):
|
||||
void kMemory::free_page (kPage *page):
|
||||
if page->mapping != ~0:
|
||||
page->address_space->unmap (page)
|
||||
if page->flags & Kernel::Page::PAYING:
|
||||
page->forget ()
|
||||
if page->flags & Iris::Page::PAYING:
|
||||
unuse ()
|
||||
if page->frame:
|
||||
pfree (page->frame)
|
||||
free_obj (page, (kPointer *)&pages)
|
||||
|
||||
void kThread::unset_slot (unsigned s):
|
||||
@ -367,6 +362,8 @@ void kMemory::free_thread (kThread *thread):
|
||||
for unsigned i = 0; i < thread->slots; ++i:
|
||||
thread->unset_slot (i)
|
||||
free_obj (thread, (void **)&threads)
|
||||
if old_current == thread:
|
||||
old_current = NULL
|
||||
|
||||
void kMemory::free_message (kReceiver *owner, kMessage *message):
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
@ -382,11 +379,15 @@ void kMemory::free_receiver (kReceiver *receiver):
|
||||
while receiver->messages:
|
||||
free_message (receiver, receiver->messages)
|
||||
free_obj (receiver, (void **)&receivers)
|
||||
if receiver == reply_target:
|
||||
reply_target = NULL
|
||||
// Signal that it is correct to not reply here.
|
||||
reply_protected.l = 1
|
||||
|
||||
void kReceiver::orphan ():
|
||||
if prev_owned:
|
||||
prev_owned->next_owned = next_owned
|
||||
else:
|
||||
else if owner:
|
||||
owner->receivers = next_owned
|
||||
if next_owned:
|
||||
next_owned->prev_owned = prev_owned
|
||||
@ -404,10 +405,14 @@ void kReceiver::own (kThread *o):
|
||||
void kCapability::invalidate ():
|
||||
if !target:
|
||||
return
|
||||
//kdebug_num ((unsigned)this)
|
||||
//kdebug ("\n")
|
||||
//kdebug_num ((unsigned)target)
|
||||
//kdebug (":")
|
||||
//kdebug_num ((unsigned)protected_data.l)
|
||||
//kdebug ("\n")
|
||||
if (unsigned)this == dbg_code.h:
|
||||
dpanic (0, "invalidating watched capability")
|
||||
if sibling_prev.valid ():
|
||||
sibling_prev->sibling_next = sibling_next
|
||||
else if parent.valid ():
|
||||
@ -429,6 +434,8 @@ void kCapability::invalidate ():
|
||||
if !next:
|
||||
next = c->parent.deref ()
|
||||
c->target = NULL
|
||||
if c->parent.valid ():
|
||||
c->parent->children = c->sibling_next
|
||||
c->parent.reset ()
|
||||
c->children.reset ()
|
||||
c->sibling_prev.reset ()
|
||||
@ -492,19 +499,24 @@ void kMemory::free_list (kList *l):
|
||||
|
||||
void kMemory::free_memory (kMemory *mem):
|
||||
while mem->pages:
|
||||
free_page (mem->pages)
|
||||
//kdebug ("freeing page ")
|
||||
//kdebug_num ((unsigned)mem->pages)
|
||||
//kdebug (", next = ")
|
||||
//kdebug_num ((unsigned)mem->pages->next)
|
||||
//kdebug ("\n")
|
||||
mem->free_page (mem->pages)
|
||||
while mem->capses:
|
||||
free_caps (mem->capses)
|
||||
mem->free_caps (mem->capses)
|
||||
while mem->threads:
|
||||
free_thread (mem->threads)
|
||||
mem->free_thread (mem->threads)
|
||||
while mem->memories:
|
||||
free_memory (mem->memories)
|
||||
mem->free_memory (mem->memories)
|
||||
while mem->receivers:
|
||||
free_receiver (mem->receivers)
|
||||
mem->free_receiver (mem->receivers)
|
||||
while mem->lists:
|
||||
free_list (mem->lists)
|
||||
mem->free_list (mem->lists)
|
||||
while mem->listitems:
|
||||
free_listitem (mem->listitems)
|
||||
mem->free_listitem (mem->listitems)
|
||||
if mem->frees:
|
||||
panic (0, "kernel memory leak: memory still in use")
|
||||
free_obj (mem, (void **)&memories)
|
||||
@ -519,10 +531,10 @@ void kPage::forget ():
|
||||
share_next = NULL
|
||||
else:
|
||||
// If the page has a frame and should be freed, free it.
|
||||
if !((flags ^ Kernel::Page::FRAME) & (Kernel::Page::PHYSICAL | Kernel::Page::FRAME)):
|
||||
if !((flags ^ Iris::Page::FRAME) & (Iris::Page::PHYSICAL | Iris::Page::FRAME)):
|
||||
raw_pfree (frame)
|
||||
frame = 0
|
||||
flags &= ~(Kernel::Page::FRAME | Kernel::Page::SHARED | Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
||||
flags &= ~(Iris::Page::FRAME | Iris::Page::SHARED | Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
|
||||
kPage_arch_update_mapping (this)
|
||||
|
||||
static void check_receiver (kReceiver *r, kCapRef cap, unsigned line):
|
||||
@ -546,6 +558,8 @@ static void check_receiver (kReceiver *r, kCapRef cap, unsigned line):
|
||||
kdebug ("!= receiver\n")
|
||||
dpanic (line, "consistency bug in kernel capabilities")
|
||||
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
||||
if c->protected_data.value () != cap->protected_data.value () || c->target != cap->target:
|
||||
dpanic (line, "capability db bug")
|
||||
check_receiver (r, c, line)
|
||||
|
||||
void kReceiver::check (unsigned line):
|
||||
@ -556,7 +570,7 @@ void kMemory::check (unsigned line):
|
||||
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
|
||||
r->check (line)
|
||||
for kThread *t = threads; t; t = (kThread *)t->next:
|
||||
if t->flags & Kernel::Thread::RUNNING && t->pc == 0:
|
||||
if t->flags & Iris::Thread::RUNNING && t->pc == 0:
|
||||
kdebug_num ((unsigned)t)
|
||||
kdebug ("\n")
|
||||
panic (line, "pc is 0")
|
||||
|
344
boot-programs/bootinit.ccp
Normal file
344
boot-programs/bootinit.ccp
Normal file
@ -0,0 +1,344 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/bootinit.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"
|
||||
#include <elf.h>
|
||||
|
||||
#define ELFRUN_NAME "elfrun.elf"
|
||||
#define INIT_NAME "init.elf"
|
||||
#define NUM_SLOTS 8
|
||||
#define NUM_CAPS 32
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
static bool have_data_mem, have_fs_mem
|
||||
static Iris::Memory data_mem, fs_mem
|
||||
|
||||
// Get the initial block device and filesystem.
|
||||
static Iris::Directory receive_devices ():
|
||||
Iris::Caps data, fs
|
||||
bool have_data = false, have_fs = false
|
||||
Iris::Device fs_dev, data_dev
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
Iris::wait ()
|
||||
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_DEVICE:
|
||||
Iris::panic (Iris::recv.data[0].l, "Invalid bootstrap request.")
|
||||
switch Iris::recv.data[1].l:
|
||||
case Iris::String::ID:
|
||||
if have_data:
|
||||
Iris::panic (0, "duplicate device.")
|
||||
data_dev = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
have_data = true
|
||||
break
|
||||
case Iris::Filesystem::ID:
|
||||
if have_fs:
|
||||
Iris::panic (0, "duplicate filesystem.")
|
||||
fs_dev = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
have_fs = true
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[1].l, "unexpected device")
|
||||
// Initialize the root file system.
|
||||
data = data_dev.create_user (Iris::my_memory)
|
||||
data_dev.use (data)
|
||||
fs = fs_dev.create_user (Iris::my_memory)
|
||||
fs_dev.use (fs)
|
||||
Iris::Filesystem fs_cap = fs.get (0)
|
||||
Iris::Directory root = fs_cap.use_device_ro (data.copy ())
|
||||
have_data_mem = data_dev.call (0).l
|
||||
if have_data_mem:
|
||||
data_mem = Iris::get_arg ()
|
||||
have_fs_mem = fs_dev.call (0).l
|
||||
if have_fs_mem:
|
||||
fs_mem = Iris::get_arg ()
|
||||
Iris::free_cap (data)
|
||||
Iris::free_cap (fs)
|
||||
Iris::free_cap (fs_cap)
|
||||
Iris::free_cap (data_dev)
|
||||
Iris::free_cap (fs_dev)
|
||||
return root
|
||||
|
||||
static bool stringcmp (char const *s1, char const *s2, unsigned size):
|
||||
for unsigned t = 0; t < size; ++t:
|
||||
if s1[t] != s2[t]:
|
||||
return false
|
||||
return true
|
||||
|
||||
static Iris::String find (Iris::Directory root, char const *name):
|
||||
unsigned size = 0
|
||||
while name[size]:
|
||||
++size
|
||||
Iris::Num num_files = root.get_size ()
|
||||
for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
|
||||
Iris::String n = root.get_name (i)
|
||||
char current_name[16]
|
||||
n.get_chars (0, current_name)
|
||||
Iris::free_cap (n)
|
||||
if !stringcmp (current_name, name, size):
|
||||
continue
|
||||
// Found elfrun.
|
||||
Iris::String ret = root.get_file_ro (i)
|
||||
return ret
|
||||
Iris::panic (0, "bootfile not found")
|
||||
|
||||
static void run (Iris::String data, Iris::Memory parent_memory, Iris::Cap parent):
|
||||
// Get the size.
|
||||
Iris::Num size = data.get_size ()
|
||||
if size.value () == 0:
|
||||
Iris::panic (0, "elfrun is empty")
|
||||
// Allocate a caps with all the pages.
|
||||
unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
|
||||
unsigned slot = pages_caps.use ()
|
||||
// Map them into the address space as well.
|
||||
char *mapping = alloc_space (pages)
|
||||
// Create a memory for the program.
|
||||
Iris::Memory mem = parent_memory.create_memory ()
|
||||
// Load the file into memory and map it.
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (pages)
|
||||
//kdebug ("\n")
|
||||
Iris::set_recv_arg (Iris::Cap (slot, p))
|
||||
Iris::my_memory.create_page ()
|
||||
Iris::Page (slot, p).set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
|
||||
data.get_page (p << PAGE_BITS, Iris::Cap (slot, p))
|
||||
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
Iris::Thread thread = mem.create_thread (NUM_SLOTS)
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
if header->e_ident[j] != ELFMAG[j]:
|
||||
Iris::panic (header->e_ident[j], "invalid ELF magic")
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class:")
|
||||
kdebug_num (header->e_ident[EI_CLASS])
|
||||
kdebug (" != ")
|
||||
kdebug_num (ELFCLASS32)
|
||||
kdebug ("\n")
|
||||
Iris::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
|
||||
if header->e_type != ET_EXEC:
|
||||
Iris::panic (header->e_type, "invalid ELF type")
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
Iris::panic (header->e_machine, "invalid ELF machine")
|
||||
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):
|
||||
Iris::panic (shdr->sh_size, "thread too large")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
unsigned idx = file_offset + section_offset
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Iris::free_cap (page)
|
||||
continue
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
unsigned f
|
||||
if readonly:
|
||||
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
|
||||
else:
|
||||
f = Iris::Page::PAYING
|
||||
page.set_flags (f, f)
|
||||
Iris::Page (slot, idx).share (page, 0)
|
||||
//kdebug ("mapping at ")
|
||||
//kdebug_num (p)
|
||||
//if readonly:
|
||||
// kdebug (" (readonly)")
|
||||
//kdebug ("\n")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map page")
|
||||
return
|
||||
Iris::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
Iris::panic (0, "unwritable bss section")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// No error means there is a mapping.
|
||||
Iris::free_cap (page)
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
if a >= shdr->sh_addr + shdr->sh_size:
|
||||
break
|
||||
if a < shdr->sh_addr:
|
||||
continue
|
||||
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
|
||||
else:
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR:
|
||||
Iris::panic (Iris::recv.data[0].l, "out of memory")
|
||||
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
|
||||
Iris::panic (0, "out of memory")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map bss page")
|
||||
Iris::free_cap (page)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Page (slot, p))
|
||||
Iris::my_memory.destroy (pages_caps)
|
||||
Iris::free_slot (slot)
|
||||
Iris::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
|
||||
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
|
||||
Iris::free_cap (stackpage)
|
||||
Iris::Caps caps = mem.create_caps (NUM_CAPS)
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Iris::Thread::A0, NUM_SLOTS)
|
||||
thread.set_info (Iris::Thread::A1, NUM_CAPS)
|
||||
Iris::Receiver receiver = mem.create_receiver ()
|
||||
receiver.set_owner (thread.copy ())
|
||||
Iris::Cap call = receiver.create_call_capability ()
|
||||
caps.set (__caps_num, caps.copy ())
|
||||
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)
|
||||
thread.run ()
|
||||
Iris::free_cap (receiver)
|
||||
Iris::free_cap (thread)
|
||||
Iris::free_cap (call)
|
||||
Iris::free_cap (caps)
|
||||
|
||||
Iris::Num start ():
|
||||
// Wait for the debugging device to be active, in case there is one.
|
||||
Iris::schedule ()
|
||||
kdebug ("Starting bootinit\n")
|
||||
init_alloc ()
|
||||
Iris::Memory top_memory = Iris::get_top_memory ()
|
||||
Iris::Directory root = receive_devices ()
|
||||
root.lock_ro ()
|
||||
Iris::String run_string = find (root, ELFRUN_NAME)
|
||||
Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
|
||||
run (run_string, top_memory, parent_cap)
|
||||
Iris::wait ()
|
||||
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_DEVICE || Iris::recv.data[1].l != Iris::Elfrun::ID:
|
||||
Iris::panic (0, "elfrun doesn't provide correct capability")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Device elfrun_dev = Iris::get_arg ()
|
||||
Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
|
||||
Iris::free_cap (parent_cap)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
|
||||
parent_cap = Iris::my_receiver.create_capability (0)
|
||||
Iris::Caps elfrun = elfrun_dev.create_user (Iris::my_memory)
|
||||
elfrun_dev.use (elfrun)
|
||||
Iris::Elfrun elfrun_cap = elfrun.get (0)
|
||||
Iris::free_cap (elfrun)
|
||||
Iris::String init_string = find (root, INIT_NAME)
|
||||
Iris::Caps init_caps = elfrun_cap.run_string (top_memory.copy (), init_string.copy (), parent_cap.copy ())
|
||||
|
||||
Iris::Thread init = init_caps.get (__thread_num)
|
||||
init.make_priv ()
|
||||
init.run ()
|
||||
Iris::free_cap (init)
|
||||
Iris::free_cap (init_caps)
|
||||
|
||||
bool have_root = false
|
||||
bool have_elfrun = false
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Parent::GET_DEVICE:
|
||||
switch Iris::recv.data[1].l:
|
||||
case Iris::Directory::ID:
|
||||
if have_root:
|
||||
Iris::panic (0, "Init requests root directory twice")
|
||||
Iris::recv.reply.invoke (0, 0, root.copy ())
|
||||
have_root = true
|
||||
break
|
||||
case Iris::Elfrun::ID:
|
||||
if have_elfrun:
|
||||
Iris::panic (0, "Init requests elfrun twice")
|
||||
Iris::recv.reply.invoke (0, 0, elfrun_cap.copy ())
|
||||
have_elfrun = true
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "Invalid device requested by init")
|
||||
break
|
||||
case Iris::Parent::INIT_DONE:
|
||||
if Iris::recv.data[1].value () != 0:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
// Special response: kill boot threads.
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
root.unlock_ro ()
|
||||
if have_data_mem:
|
||||
top_memory.destroy (data_mem)
|
||||
if have_fs_mem:
|
||||
top_memory.destroy (fs_mem)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
top_memory.destroy (Iris::my_memory)
|
||||
Iris::panic (0, "bootinit should be destroyed")
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid operation from init")
|
@ -29,7 +29,8 @@ static unsigned __slots, __caps
|
||||
static list *__slot_admin, *__cap_admin
|
||||
static list *__first_free_slot, *__first_free_cap
|
||||
|
||||
namespace Kernel:
|
||||
namespace Iris:
|
||||
Caps my_caps
|
||||
Receiver my_receiver
|
||||
Thread my_thread
|
||||
Memory my_memory
|
||||
@ -77,7 +78,7 @@ namespace Kernel:
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
return ~0
|
||||
list *ret = __first_free_slot
|
||||
__first_free_slot = ret->next
|
||||
@ -90,7 +91,7 @@ namespace Kernel:
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
return Cap (0, CAP_NONE)
|
||||
list *ret = __first_free_cap
|
||||
__first_free_cap = ret->next
|
||||
@ -106,20 +107,21 @@ extern "C":
|
||||
__cap_admin = cap_admin
|
||||
__first_free_slot = NULL
|
||||
for unsigned i = 1; i < __slots; ++i:
|
||||
Kernel::free_slot (i)
|
||||
Iris::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.exit (ret)
|
||||
Kernel::my_memory.destroy (Kernel::my_thread)
|
||||
for unsigned i = 6; i < __caps; ++i:
|
||||
Iris::free_cap (Iris::Cap (0, i))
|
||||
Iris::my_caps = Iris::Cap (0, __caps_num)
|
||||
Iris::my_receiver = Iris::Cap (0, __receiver_num)
|
||||
Iris::my_thread = Iris::Cap (0, __thread_num)
|
||||
Iris::my_memory = Iris::Cap (0, __memory_num)
|
||||
Iris::my_call = Iris::Cap (0, __call_num)
|
||||
Iris::my_parent = Iris::Cap (0, __parent_num)
|
||||
Iris::recv.reply = Iris::alloc_cap ()
|
||||
Iris::recv.arg = Iris::alloc_cap ()
|
||||
Iris::Num ret = start ()
|
||||
Iris::my_parent.exit (ret)
|
||||
Iris::my_memory.destroy (Iris::my_thread)
|
||||
// The program no longer exists. If it somehow does, generate an address fault.
|
||||
while true:
|
||||
*(volatile unsigned *)~0
|
||||
|
@ -1,592 +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"
|
||||
#include "keys.hh"
|
||||
#include <elf.h>
|
||||
|
||||
#define NUM_SLOTS 8
|
||||
#define NUM_CAPS 32
|
||||
|
||||
enum Cap_codes:
|
||||
SYSREQ = 1 << 16
|
||||
THREAD
|
||||
KEYBOARD
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
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, _free + rest + (p << PAGE_BITS))
|
||||
Kernel::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
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
|
||||
static Kernel::Caps terminals
|
||||
static unsigned terminal_slot
|
||||
static Kernel::Caps memories
|
||||
static unsigned memory_slot
|
||||
static unsigned *inuse
|
||||
|
||||
// Get the initial block device and filesystem.
|
||||
static Directory receive_devices ():
|
||||
Kernel::Caps data, fs
|
||||
bool have_data = false, have_fs = false
|
||||
Device fs_dev, data_dev
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
Kernel::wait ()
|
||||
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
|
||||
Kernel::panic (Kernel::recv.data[0].l, "Invalid bootstrap request.")
|
||||
switch Kernel::recv.data[1].l:
|
||||
case String::ID:
|
||||
if have_data:
|
||||
Kernel::panic (0, "duplicate device.")
|
||||
data_dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
have_data = true
|
||||
break
|
||||
case Filesystem::ID:
|
||||
if have_fs:
|
||||
Kernel::panic (0, "duplicate filesystem.")
|
||||
fs_dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
have_fs = true
|
||||
break
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.data[1].l, "unexpected device")
|
||||
// Initialize the root file system.
|
||||
data = data_dev.create_user (Kernel::my_memory)
|
||||
data_dev.use (data)
|
||||
fs = fs_dev.create_user (Kernel::my_memory)
|
||||
fs_dev.use (fs)
|
||||
Filesystem fs_cap = fs.get (0)
|
||||
Directory root = fs_cap.use_device_ro (data.copy ())
|
||||
Kernel::free_cap (data)
|
||||
Kernel::free_cap (fs)
|
||||
Kernel::free_cap (fs_cap)
|
||||
Kernel::free_cap (data_dev)
|
||||
Kernel::free_cap (fs_dev)
|
||||
return root
|
||||
|
||||
// Make a list of all files.
|
||||
static void list_files (Directory root):
|
||||
Kernel::Num fullsize = root.get_size ()
|
||||
if fullsize.h != 0:
|
||||
kdebug ("Too many files in bootstrap directory:")
|
||||
kdebug_num (fullsize.h)
|
||||
kdebug (":")
|
||||
kdebug_num (fullsize.l)
|
||||
kdebug ("\n")
|
||||
Kernel::panic (0)
|
||||
num_files = fullsize.l
|
||||
files = new file[num_files]
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files)
|
||||
unsigned slot = Kernel::alloc_slot ()
|
||||
caps.use (slot)
|
||||
Kernel::free_cap (caps)
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
String n = root.get_name (i)
|
||||
n.get_chars (0, files[i].name)
|
||||
Kernel::free_cap (n)
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, i))
|
||||
files[i].string = root.get_file_ro (i)
|
||||
Kernel::Num fullsize = files[i].string.get_size ()
|
||||
if fullsize.h != 0:
|
||||
kdebug ("initial file size too large: ")
|
||||
kdebug_num (fullsize.h)
|
||||
kdebug (":")
|
||||
kdebug_num (fullsize.l)
|
||||
kdebug (".\n")
|
||||
Kernel::panic (0)
|
||||
files[i].size = fullsize.l
|
||||
if max_pages < (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS:
|
||||
max_pages = (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
|
||||
// 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, int id):
|
||||
Kernel::Memory mem = Kernel::Cap (memory_slot, id)
|
||||
Kernel::set_recv_arg (mem)
|
||||
top_memory.create_memory ()
|
||||
unsigned num_pages = (f->size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < num_pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (num_pages)
|
||||
//kdebug ("\n")
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, p))
|
||||
Kernel::my_memory.create_page ()
|
||||
Kernel::Page (slot, p).set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
|
||||
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
|
||||
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]:
|
||||
Kernel::panic (header->e_ident[j], "invalid ELF magic")
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class:")
|
||||
kdebug_num (header->e_ident[EI_CLASS])
|
||||
kdebug (" != ")
|
||||
kdebug_num (ELFCLASS32)
|
||||
kdebug ("\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
Kernel::panic (header->e_ident[EI_DATA], "invalid ELF data")
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
Kernel::panic (header->e_ident[EI_VERSION], "invalid ELF version")
|
||||
if header->e_type != ET_EXEC:
|
||||
Kernel::panic (header->e_type, "invalid ELF type")
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
Kernel::panic (header->e_machine, "invalid ELF machine")
|
||||
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):
|
||||
Kernel::panic (shdr->sh_size, "thread too large")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
unsigned idx = file_offset + section_offset
|
||||
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
|
||||
Kernel::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
unsigned f
|
||||
if readonly:
|
||||
f = Kernel::Page::PAYING | Kernel::Page::MAPPED_READONLY
|
||||
else:
|
||||
f = Kernel::Page::PAYING
|
||||
page.set_flags (f, f)
|
||||
Kernel::Page (slot, idx).share (page, 0)
|
||||
//kdebug ("mapping at ")
|
||||
//kdebug_num (p)
|
||||
//if readonly:
|
||||
// kdebug (" (readonly)")
|
||||
//kdebug ("\n")
|
||||
if !mem.map (page, p):
|
||||
Kernel::panic (0, "unable to map page")
|
||||
return
|
||||
Kernel::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
Kernel::panic (0, "unwritable bss section")
|
||||
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 a mapping.
|
||||
Kernel::free_cap (page)
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
if a >= shdr->sh_addr + shdr->sh_size:
|
||||
break
|
||||
if a < shdr->sh_addr:
|
||||
continue
|
||||
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
|
||||
else:
|
||||
Kernel::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Kernel::recv.data[0].l != Kernel::NO_ERROR:
|
||||
Kernel::panic (Kernel::recv.data[0].l, "out of memory")
|
||||
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
|
||||
Kernel::panic (0, "out of memory")
|
||||
if !mem.map (page, p):
|
||||
Kernel::panic (0, "unable to map bss page")
|
||||
Kernel::free_cap (page)
|
||||
for unsigned p = 0; p < num_pages; ++p:
|
||||
Kernel::my_memory.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):
|
||||
Kernel::panic (Kernel::recv.data[0].l, "unable to map initial stack page")
|
||||
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 (Kernel::Num (current_thread++, 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 (call)
|
||||
Kernel::free_cap (parent)
|
||||
Kernel::free_cap (caps)
|
||||
|
||||
static void kdebug_name (char const *t, file *f):
|
||||
kdebug (t)
|
||||
for unsigned j = 0; j < 16; ++j:
|
||||
if f->name[j] != 0:
|
||||
kdebug_char (f->name[j])
|
||||
kdebug ("...")
|
||||
|
||||
static Device sysreq_dev
|
||||
|
||||
struct Dev:
|
||||
static Dev *devs
|
||||
static unsigned num_devs
|
||||
Dev *next
|
||||
unsigned code, idx, id
|
||||
Device dev
|
||||
static Dev *find (unsigned c, unsigned i):
|
||||
for Dev *d = devs; d; d = d->next:
|
||||
if d->code == c && d->idx == i:
|
||||
return d
|
||||
return NULL
|
||||
static void add (unsigned c, unsigned i, Kernel::Cap cap):
|
||||
if c == Keyboard::ID && i == 1:
|
||||
sysreq_dev = cap
|
||||
return
|
||||
while find (c, i):
|
||||
++i
|
||||
Dev *d = new Dev ()
|
||||
d->next = devs
|
||||
d->code = c
|
||||
d->idx = i
|
||||
d->dev = cap
|
||||
devs = d
|
||||
d->id = num_devs++
|
||||
static void kdebug_list ():
|
||||
for Dev *d = devs; d; d = d->next:
|
||||
kdebug (">")
|
||||
kdebug_num (d->code)
|
||||
kdebug (":")
|
||||
kdebug_num (d->idx)
|
||||
|
||||
Dev *Dev::devs
|
||||
unsigned Dev::num_devs
|
||||
|
||||
static void handle_init (unsigned id):
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Parent::PROVIDE_DEVICE:
|
||||
kdebug ("adding dev ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug (":")
|
||||
kdebug_num (Kernel::recv.data[0].h)
|
||||
kdebug (" as ")
|
||||
kdebug_num (Dev::num_devs)
|
||||
kdebug ("\n")
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Dev::add (Kernel::recv.data[1].l, Kernel::recv.data[0].h, Kernel::get_arg ())
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Parent::INIT_DONE:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
memories.set (id + num_files, reply.copy ())
|
||||
Kernel::free_cap (reply)
|
||||
return
|
||||
default:
|
||||
kdebug ("unknown init request\n")
|
||||
Kernel::panic (Kernel::recv.data[0].l)
|
||||
|
||||
static void get_device ():
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
unsigned id = Kernel::recv.protected_data.l
|
||||
Dev *d = Dev::find (Kernel::recv.data[1].l, Kernel::recv.data[0].h)
|
||||
if d:
|
||||
if inuse[id * Dev::num_devs + d->id] > 0:
|
||||
Kernel::panic (id, "requesting device twice")
|
||||
kdebug ("giving dev ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug (":")
|
||||
kdebug_num (Kernel::recv.data[0].h)
|
||||
kdebug (" = ")
|
||||
kdebug_num (d->id)
|
||||
kdebug (" to ")
|
||||
kdebug_num (id)
|
||||
kdebug ("\n")
|
||||
Kernel::Caps cap = d->dev.create_user (Kernel::Memory (memory_slot, id), 0, 0x15000)
|
||||
Kernel::Caps (terminal_slot, id).set (d->id, cap.copy ())
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
if inuse[i * Dev::num_devs + d->id] == 2:
|
||||
inuse[i * Dev::num_devs + d->id] = 1
|
||||
inuse[id * Dev::num_devs + d->id] = 2
|
||||
d->dev.use (cap)
|
||||
Kernel::Cap ret = cap.get (0)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
Kernel::free_cap (ret)
|
||||
Kernel::free_cap (cap)
|
||||
else:
|
||||
kdebug ("device not found: ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug (":")
|
||||
kdebug_num (Kernel::recv.data[0].h)
|
||||
Dev::kdebug_list ()
|
||||
kdebug ("\n")
|
||||
reply.invoke (~0, ~0)
|
||||
Kernel::panic (0)
|
||||
Kernel::free_cap (reply)
|
||||
|
||||
static void draw_ball ():
|
||||
int const r = 50
|
||||
for int y = -r; y < r; ++y:
|
||||
for int x = -r; x < r; ++x:
|
||||
if x * x + y * y > r * r:
|
||||
((unsigned *)0x15000)[(120 + y) * 320 + 160 + x] = 0x000000
|
||||
else:
|
||||
((unsigned *)0x15000)[(120 + y) * 320 + 160 + x] = 0x3f30ff
|
||||
|
||||
static void draw_square ():
|
||||
int const r = 50
|
||||
for int y = -r; y < r; ++y:
|
||||
for int x = -r; x < r; ++x:
|
||||
((unsigned *)0x15000)[(120 + y) * 320 + 160 + x] = 0xffff00
|
||||
|
||||
Kernel::Num start ():
|
||||
// Wait for the debugging device to be active, in case there is one.
|
||||
Kernel::schedule ()
|
||||
Dev::devs = NULL
|
||||
Dev::num_devs = 0
|
||||
init_alloc ()
|
||||
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)
|
||||
terminals = Kernel::my_memory.create_caps (num_files)
|
||||
terminal_slot = terminals.use ()
|
||||
// Two times, because it holds the memory and the init_done reply for each task.
|
||||
memories = Kernel::my_memory.create_caps (num_files * 2)
|
||||
memory_slot = memories.use ()
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
kdebug_name ("loading ", &files[index[i]])
|
||||
run (&files[index[i]], files[index[i]].name[0] == '#', i)
|
||||
kdebug ("running\n")
|
||||
handle_init (i)
|
||||
inuse = new unsigned[num_files * Dev::num_devs]
|
||||
for unsigned f = 0; f < num_files; ++f:
|
||||
for unsigned d = 0; d < Dev::num_devs; ++d:
|
||||
inuse[f * Dev::num_devs + d] = 0
|
||||
// Notify all programs that they may start.
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
Kernel::Cap (memory_slot, i + num_files).invoke ()
|
||||
// create terminals.
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
Kernel::Caps term (terminal_slot, i)
|
||||
Kernel::Memory mem (memory_slot, i)
|
||||
Kernel::set_recv_arg (term)
|
||||
mem.create_caps (Dev::num_devs)
|
||||
// set up system request.
|
||||
Kernel::Caps sysreq_caps = sysreq_dev.create_user (Kernel::my_memory)
|
||||
sysreq_dev.use (sysreq_caps)
|
||||
Keyboard sysreq = sysreq_caps.get (0)
|
||||
Kernel::free_cap (sysreq_dev)
|
||||
Kernel::free_cap (sysreq_caps)
|
||||
Kernel::Cap cap = Kernel::my_receiver.create_capability (Kernel::Num (0, SYSREQ))
|
||||
sysreq.set_cb (cap.copy ())
|
||||
Kernel::free_cap (sysreq)
|
||||
Kernel::free_cap (cap)
|
||||
// set up own capabilities.
|
||||
Dev *display_dev = Dev::find (Display::ID, 0)
|
||||
if !display_dev:
|
||||
Kernel::panic (0, "no display")
|
||||
Kernel::Caps display_caps = display_dev->dev.create_user (Kernel::my_memory, 0, 0x15000)
|
||||
Display display = display_caps.get (0)
|
||||
draw_ball ()
|
||||
Dev *keyboard_dev = Dev::find (Keyboard::ID, 0)
|
||||
if !keyboard_dev:
|
||||
Kernel::panic (0, "no keyboard")
|
||||
Kernel::Caps keyboard_caps = keyboard_dev->dev.create_user (Kernel::my_memory, 0, 0x15000)
|
||||
Keyboard keyboard = keyboard_caps.get (0)
|
||||
kdebug ("init done\n")
|
||||
root.unlock_ro ()
|
||||
Kernel::free_slot (slot)
|
||||
Kernel::my_memory.destroy (caps)
|
||||
Dev **waiter = new Dev *[num_files]
|
||||
Kernel::Cap keyboard_cb = Kernel::my_receiver.create_capability (Kernel::Num (0, KEYBOARD))
|
||||
bool in_system = false
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
case SYSREQ:
|
||||
// System request.
|
||||
if Kernel::recv.data[0].l & Keyboard::RELEASE:
|
||||
continue
|
||||
keyboard_dev->dev.use (keyboard_caps)
|
||||
display_dev->dev.use (display_caps)
|
||||
keyboard.set_cb (keyboard_cb)
|
||||
in_system = true
|
||||
continue
|
||||
case THREAD:
|
||||
// Request for something from a child thread.
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Parent::INIT_DONE:
|
||||
Kernel::panic (Kernel::recv.protected_data.l, "double init_done")
|
||||
case Parent::PROVIDE_DEVICE:
|
||||
Kernel::panic (Kernel::recv.protected_data.l, "too late now for provide")
|
||||
case Parent::GET_DEVICE:
|
||||
get_device ()
|
||||
break
|
||||
case Parent::WAIT:
|
||||
unsigned id = Kernel::recv.protected_data.l
|
||||
Dev *dev = Dev::find (Kernel::recv.data[1].l, 0)
|
||||
if id >= num_files:
|
||||
Kernel::panic (0, "invalid id")
|
||||
if !dev:
|
||||
Kernel::panic (0, "invalid dev")
|
||||
switch inuse[id * Dev::num_devs + dev->id]:
|
||||
case 0:
|
||||
Kernel::panic (0, "waiting for non-owned device")
|
||||
case 2:
|
||||
if !in_system:
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
// fall through.
|
||||
case 1:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
memories.set (id + num_files, reply.copy ())
|
||||
Kernel::free_cap (reply)
|
||||
waiter[id] = dev
|
||||
break
|
||||
break
|
||||
case Parent::EXIT:
|
||||
Kernel::panic (Kernel::recv.protected_data.l, "exit is not supported")
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.data[0].l, "invalid operation from child")
|
||||
break
|
||||
case KEYBOARD:
|
||||
if !in_system:
|
||||
break
|
||||
if Kernel::recv.data[0].l == (Key::ENTER | Keyboard::RELEASE):
|
||||
for Dev *d = Dev::devs; d; d = d->next:
|
||||
if d->idx != 0:
|
||||
continue
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
if inuse[i * Dev::num_devs + d->id] == 2:
|
||||
Kernel::Cap c = Kernel::Caps (terminal_slot, i).get (d->id)
|
||||
d->dev.use (c)
|
||||
Kernel::free_cap (c)
|
||||
if waiter[i] == d:
|
||||
Kernel::Cap (memory_slot, i + num_files).invoke ()
|
||||
waiter[i] = NULL
|
||||
in_system = false
|
||||
break
|
||||
if Kernel::recv.data[0].l & Keyboard::RELEASE:
|
||||
continue
|
||||
unsigned which = 0
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Key::VOLUME_DOWN:
|
||||
// Set ball.
|
||||
draw_ball ()
|
||||
which = 2
|
||||
break
|
||||
case Key::VOLUME_UP:
|
||||
// Set square.
|
||||
draw_square ()
|
||||
which = 1
|
||||
break
|
||||
if which != 0:
|
||||
for Dev *d = Dev::devs; d; d = d->next:
|
||||
if d->code != Display::ID || d->idx != 0:
|
||||
continue
|
||||
for unsigned f = 0; f < num_files; ++f:
|
||||
if inuse[f * Dev::num_devs + d->id] == 0:
|
||||
continue
|
||||
inuse[f * Dev::num_devs + d->id] = (--which ? 2 : 1)
|
||||
break
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.protected_data.h, "unknown source of request")
|
@ -162,16 +162,16 @@ class Udc:
|
||||
char log_buffer[1000]
|
||||
unsigned log_buffer_size
|
||||
unsigned log_buffer_start
|
||||
Kernel::Cap caller, caller_arg
|
||||
Iris::Cap caller, caller_arg
|
||||
bool have_caller
|
||||
unsigned *page
|
||||
unsigned *p
|
||||
Kernel::Page buffer_page
|
||||
Iris::Page buffer_page
|
||||
public:
|
||||
void init ()
|
||||
void log (unsigned c)
|
||||
void interrupt (unsigned cmd)
|
||||
void send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg)
|
||||
void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg)
|
||||
|
||||
Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
|
||||
Udc::my_config Udc::config_descriptor = {
|
||||
@ -217,9 +217,9 @@ void Udc::init ():
|
||||
// Normally a normal new page should be allocated here, but new isn't implemented at this point.
|
||||
page = (unsigned *)LCD_FRAMEBUFFER_BASE
|
||||
p = page
|
||||
buffer_page = Kernel::my_memory.create_page ()
|
||||
buffer_page.set_flags (Kernel::Page::FRAME | Kernel::Page::PAYING, Kernel::Page::FRAME | Kernel::Page::PAYING)
|
||||
Kernel::my_memory.map (buffer_page, (unsigned)page)
|
||||
buffer_page = Iris::my_memory.create_page ()
|
||||
buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING, Iris::Page::FRAME | Iris::Page::PAYING)
|
||||
Iris::my_memory.map (buffer_page, (unsigned)page)
|
||||
|
||||
// Disconnect from the bus and don't try to get high-speed.
|
||||
UDC_POWER = 0
|
||||
@ -242,14 +242,14 @@ void Udc::init ():
|
||||
UDC_INTROUTE = 1 << 1
|
||||
// Wait a while.
|
||||
for unsigned w = 0; w < 10000; ++w:
|
||||
Kernel::schedule ()
|
||||
Iris::schedule ()
|
||||
// Connect to the host.
|
||||
UDC_POWER = UDC_POWER_SOFTCONN
|
||||
|
||||
bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
if !(s->request_type & 0x80):
|
||||
kdebug ("data to device without size\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
return true
|
||||
if s->request == 10:
|
||||
static unsigned b[2]
|
||||
@ -258,10 +258,10 @@ bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
if cmd_code != ~0:
|
||||
b[0] = cmd_code
|
||||
b[1] = cmd_arg
|
||||
if cmd_code == Directory::LOCK_RO || cmd_code == Directory::UNLOCK_RO:
|
||||
if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO:
|
||||
caller.invoke ()
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("(un)lock response\n")
|
||||
cmd_code = ~0
|
||||
@ -283,10 +283,10 @@ bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
state = TX
|
||||
return true
|
||||
|
||||
void Udc::send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg):
|
||||
void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg):
|
||||
if cmd_code != ~0:
|
||||
kdebug ("new code sent while old one wasn't finished.\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
cmd_code = code
|
||||
cmd_arg = narg
|
||||
caller = reply
|
||||
@ -404,7 +404,7 @@ void Udc::irq_in (unsigned cmd):
|
||||
switch state:
|
||||
case IDLE:
|
||||
if rebooting:
|
||||
Kernel::reboot ()
|
||||
Iris::reboot ()
|
||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||
return
|
||||
union { unsigned d[2]; Setup s; } packet
|
||||
@ -439,53 +439,53 @@ void Udc::irq_in (unsigned cmd):
|
||||
case RX:
|
||||
// The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
|
||||
switch rx_request & 0xff:
|
||||
case Directory::GET_SIZE & 0xff:
|
||||
case Iris::Directory::GET_SIZE & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received dir size from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (size_l, size_h))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
caller.invoke (Iris::Num (size_l, size_h))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_size response\n")
|
||||
break
|
||||
case Directory::GET_NAME & 0xff:
|
||||
case Iris::Directory::GET_NAME & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received filename from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
//kdebug ("get_name response\n")
|
||||
have_caller = false
|
||||
break
|
||||
case ::String::GET_SIZE & 0xff:
|
||||
case Iris::String::GET_SIZE & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received string size from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (size_l, size_h))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
caller.invoke (Iris::Num (size_l, size_h))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_filesize response\n")
|
||||
break
|
||||
case ::String::GET_CHARS & 0xff:
|
||||
case Iris::String::GET_CHARS & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received string char data from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_chars response\n")
|
||||
break
|
||||
@ -493,7 +493,7 @@ void Udc::irq_in (unsigned cmd):
|
||||
kdebug ("invalid vendor request: ")
|
||||
kdebug_num (rx_request)
|
||||
kdebug ("\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
state = IDLE
|
||||
break
|
||||
@ -504,7 +504,7 @@ void Udc::irq_out (unsigned cmd):
|
||||
UDC_INDEX = 1
|
||||
if !have_caller:
|
||||
kdebug ("received bulk data from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
unsigned size = UDC_OUTCOUNT
|
||||
unsigned csr = UDC_OUTCSR
|
||||
//kdebug ("handling bulk interrupt for ")
|
||||
@ -516,11 +516,11 @@ void Udc::irq_out (unsigned cmd):
|
||||
for unsigned i = 0; i < size; i += 4:
|
||||
*p++ = UDC_FIFO (1)
|
||||
if p - page == PAGE_SIZE >> 2:
|
||||
buffer_page.share (caller_arg, Kernel::Page::FORGET)
|
||||
buffer_page.set_flags (Kernel::Page::FRAME, Kernel::Page::FRAME)
|
||||
buffer_page.share (caller_arg, Iris::Page::FORGET)
|
||||
buffer_page.set_flags (Iris::Page::FRAME, Iris::Page::FRAME)
|
||||
caller.invoke ()
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("bulk response\n")
|
||||
p = page
|
||||
@ -561,153 +561,153 @@ enum pdata:
|
||||
FILE
|
||||
NAME
|
||||
|
||||
Kernel::Num start ():
|
||||
Iris::Num start ():
|
||||
map_udc ()
|
||||
map_gpio ()
|
||||
map_cpm ()
|
||||
Udc udc
|
||||
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
|
||||
Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
udc.init ()
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
Device fs_dev = Kernel::my_receiver.create_capability (FS)
|
||||
Device data_dev = Kernel::my_receiver.create_capability (DATA)
|
||||
Kernel::my_parent.provide_device <Filesystem> (fs_dev.copy ())
|
||||
Kernel::my_parent.provide_device <String> (data_dev.copy ())
|
||||
Kernel::free_cap (fs_dev)
|
||||
Kernel::free_cap (data_dev)
|
||||
Iris::register_interrupt (IRQ_UDC)
|
||||
Iris::Device fs_dev = Iris::my_receiver.create_capability (FS)
|
||||
Iris::Device data_dev = Iris::my_receiver.create_capability (DATA)
|
||||
Iris::my_parent.provide_device <Iris::Filesystem> (fs_dev.copy ())
|
||||
Iris::my_parent.provide_device <Iris::String> (data_dev.copy ())
|
||||
Iris::free_cap (fs_dev)
|
||||
Iris::free_cap (data_dev)
|
||||
unsigned data_current_user = 0, fs_current_user = 0
|
||||
unsigned next_user
|
||||
unsigned state = 0
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
Iris::wait ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
switch Iris::recv.protected_data.h:
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
switch Iris::recv.protected_data.l:
|
||||
case IRQ_UDC:
|
||||
udc.interrupt (state)
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
Iris::register_interrupt (IRQ_UDC)
|
||||
break
|
||||
case LOG:
|
||||
udc.log (Kernel::recv.data[0].l)
|
||||
udc.log (Iris::recv.data[0].l)
|
||||
break
|
||||
case FS:
|
||||
Device::host (FS, fs_current_user, reply, arg)
|
||||
Iris::Device::host (FS, fs_current_user, reply, arg)
|
||||
continue
|
||||
case DATA:
|
||||
Device::host (DATA, data_current_user, reply, arg)
|
||||
Iris::Device::host (DATA, data_current_user, reply, arg)
|
||||
continue
|
||||
default:
|
||||
udc.log ('~')
|
||||
char digit[] = "0123456789abcdef"
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
||||
udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
||||
udc.log ('\n')
|
||||
break
|
||||
break
|
||||
case DATA:
|
||||
if data_current_user != Kernel::recv.protected_data.l:
|
||||
if data_current_user != Iris::recv.protected_data.l:
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case ::String::GET_SIZE:
|
||||
case ::String::GET_CHARS:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::String::GET_SIZE:
|
||||
case Iris::String::GET_CHARS:
|
||||
reply.invoke (0)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case ::String::GET_PAGE:
|
||||
case Iris::String::GET_PAGE:
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case FS:
|
||||
if fs_current_user != Kernel::recv.protected_data.l:
|
||||
if fs_current_user != Iris::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))
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Filesystem::USE_DEVICE:
|
||||
case Iris::Filesystem::USE_DEVICE_RO:
|
||||
Iris::Directory dir = Iris::my_receiver.create_capability (Iris::Num (0, DIRECTORY))
|
||||
reply.invoke (0, 0, dir.copy ())
|
||||
Kernel::free_cap (dir)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
Iris::free_cap (dir)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case DIRECTORY:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Directory::GET_NAME:
|
||||
Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, NAME))
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Directory::GET_NAME:
|
||||
Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, NAME))
|
||||
reply.invoke (0, 0, name.copy ())
|
||||
Kernel::free_cap (name)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
Iris::free_cap (name)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case Directory::GET_SIZE:
|
||||
case Directory::LOCK_RO:
|
||||
case Directory::UNLOCK_RO:
|
||||
state = Kernel::recv.data[0].l
|
||||
if Kernel::recv.data[1].h != 0:
|
||||
case Iris::Directory::GET_SIZE:
|
||||
case Iris::Directory::LOCK_RO:
|
||||
case Iris::Directory::UNLOCK_RO:
|
||||
state = Iris::recv.data[0].l
|
||||
if Iris::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, reply, arg)
|
||||
Iris::panic (0)
|
||||
udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
|
||||
continue
|
||||
case Directory::GET_FILE_RO:
|
||||
if Kernel::recv.data[1].h != 0:
|
||||
case Iris::Directory::GET_FILE_RO:
|
||||
if Iris::recv.data[1].h != 0:
|
||||
kdebug ("index out of supported range\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
//kdebug ("sending file\n")
|
||||
Kernel::Cap file = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, FILE))
|
||||
Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, FILE))
|
||||
reply.invoke (0, 0, file.copy ())
|
||||
Kernel::free_cap (file)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
Iris::free_cap (file)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case Directory::GET_FILE_INFO:
|
||||
case Iris::Directory::GET_FILE_INFO:
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case FILE:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case ::String::GET_SIZE:
|
||||
case ::String::GET_CHARS:
|
||||
case ::String::GET_PAGE:
|
||||
udc.send (Kernel::recv.data[0].l | ((Kernel::recv.data[1].l >> PAGE_BITS) << 16), Kernel::recv.protected_data.l, reply, arg)
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::String::GET_SIZE:
|
||||
case Iris::String::GET_CHARS:
|
||||
case Iris::String::GET_PAGE:
|
||||
udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.l, reply, arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case NAME:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case ::String::GET_SIZE:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::String::GET_SIZE:
|
||||
reply.invoke (16)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case ::String::GET_CHARS:
|
||||
state = Kernel::recv.data[0].l
|
||||
udc.send (Directory::GET_NAME, Kernel::recv.protected_data.l, reply, arg)
|
||||
case Iris::String::GET_CHARS:
|
||||
state = Iris::recv.data[0].l
|
||||
udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.l, reply, arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
|
724
devices.hhp
724
devices.hhp
@ -21,363 +21,405 @@
|
||||
|
||||
#include "iris.hh"
|
||||
|
||||
// List interface.
|
||||
template <typename _T> //
|
||||
struct List : public Kernel::Caps:
|
||||
List (Kernel::Caps c = Kernel::Cap ()) : Kernel::Caps (c):
|
||||
List <_T> create (unsigned size, Kernel::Memory mem = Kernel::my_memory):
|
||||
return List <_T> (mem.create_caps (size))
|
||||
void set (unsigned idx, _T value):
|
||||
return Kernel::Caps::set (idx, value)
|
||||
_T get (unsigned idx):
|
||||
return _T (Kernel::Caps::get (idx))
|
||||
namespace Iris:
|
||||
// Caplist interface.
|
||||
template <typename _T> //
|
||||
struct Caplist : public Iris::Caps:
|
||||
Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c):
|
||||
Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory):
|
||||
return Caplist <_T> (mem.create_caps (size))
|
||||
void set (unsigned idx, _T value):
|
||||
return Iris::Caps::set (idx, value)
|
||||
_T get (unsigned idx):
|
||||
return _T (Iris::Caps::get (idx))
|
||||
|
||||
/// A block of data with a size and content. Any character can be stored in it (including '\0').
|
||||
struct String : public Kernel::Cap:
|
||||
String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = 0x2001
|
||||
GET_CHARS
|
||||
GET_PAGE
|
||||
ID
|
||||
/// Get the size of the string.
|
||||
Kernel::Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
/// Get exactly 16 characters. The index must be word-aligned.
|
||||
char *get_chars (Kernel::Num idx, char buffer[16]):
|
||||
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
|
||||
unsigned *b = (unsigned *)buffer
|
||||
b[0] = Kernel::recv.data[0].l
|
||||
b[1] = Kernel::recv.data[0].h
|
||||
b[2] = Kernel::recv.data[1].l
|
||||
b[3] = Kernel::recv.data[1].h
|
||||
return buffer
|
||||
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
|
||||
Cap get_page (Kernel::Num idx, Kernel::Page ret = Kernel::my_memory.create_page ()):
|
||||
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
|
||||
return ret
|
||||
/// A block of data with a size and content. Any character can be stored in it (including '\0').
|
||||
struct String : public Iris::Cap:
|
||||
String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = 0x2001
|
||||
GET_CHARS
|
||||
GET_PAGE
|
||||
ID
|
||||
/// Get the size of the string.
|
||||
Iris::Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
/// Get exactly 16 characters. The index must be word-aligned.
|
||||
char *get_chars (Iris::Num idx, char buffer[16]):
|
||||
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
|
||||
unsigned *b = (unsigned *)buffer
|
||||
b[0] = Iris::recv.data[0].l
|
||||
b[1] = Iris::recv.data[0].h
|
||||
b[2] = Iris::recv.data[1].l
|
||||
b[3] = Iris::recv.data[1].h
|
||||
return buffer
|
||||
/// Helper function for get_page.
|
||||
static Iris::Page _create_paying_page ():
|
||||
Iris::Page ret = Iris::my_memory.create_page ()
|
||||
ret.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
|
||||
return ret
|
||||
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
|
||||
Cap get_page (Iris::Num idx, Iris::Page ret = _create_paying_page ()):
|
||||
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
|
||||
return ret
|
||||
|
||||
/// A writable String.
|
||||
struct WString : public String:
|
||||
WString (Kernel::Cap c = Kernel::Cap ()) : String (c):
|
||||
enum request:
|
||||
TRUNCATE = String::ID
|
||||
SET_CHARS
|
||||
SET_PAGE
|
||||
ID
|
||||
/// Set the size of the string. Strings may have a limit to this setting.
|
||||
void truncate (Kernel::Num size):
|
||||
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
||||
/// Set exactly 4 characters. The index must be word-aligned.
|
||||
void set_chars (Kernel::Num idx, char buffer[4]):
|
||||
call (Kernel::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
|
||||
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
|
||||
void set_page (Kernel::Num idx, Kernel::Page page):
|
||||
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
|
||||
/// A writable String.
|
||||
struct WString : public String:
|
||||
WString (Iris::Cap c = Iris::Cap ()) : String (c):
|
||||
enum request:
|
||||
TRUNCATE = String::ID
|
||||
SET_CHARS
|
||||
SET_PAGE
|
||||
ID
|
||||
/// Set the size of the string. Strings may have a limit to this setting.
|
||||
void truncate (Iris::Num size):
|
||||
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
||||
/// Set exactly 4 characters. The index must be word-aligned.
|
||||
void set_chars (Iris::Num idx, char buffer[4]):
|
||||
call (Iris::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
|
||||
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
|
||||
void set_page (Iris::Num idx, Iris::Page page):
|
||||
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
|
||||
|
||||
// Every process which wants to be switchable through a terminal must implement this interface.
|
||||
struct Device : public Kernel::Cap:
|
||||
Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
CREATE_USER = WString::ID
|
||||
DESTROY_USER
|
||||
UNUSE
|
||||
USE
|
||||
ID
|
||||
// Create a new user for this device. It will not be the active user.
|
||||
// The provided storage must allow object creation; no other actions may be used by the terminal.
|
||||
Kernel::Cap create_user (Kernel::Memory storage, unsigned arg1 = 0, Kernel::Num arg2 = 0):
|
||||
iocall (storage, Kernel::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2)
|
||||
return Kernel::get_arg ()
|
||||
// Destroy a user. It is made inactive if it was active.
|
||||
void destroy_user (Kernel::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
|
||||
// Make user inactive.
|
||||
void unuse (Kernel::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | UNUSE)
|
||||
// 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, Kernel::Cap &arg, unsigned capssize = 3, unsigned (*create)(Kernel::Memory mem, Kernel::Caps caps) = NULL, void (*destroy)(unsigned id, Kernel::Caps caps) = NULL, void (*use)(unsigned id, Kernel::Caps caps) = NULL, void (*unuse)(unsigned id, Kernel::Caps caps) = NULL):
|
||||
static unsigned last_user
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
Kernel::Memory mem (arg)
|
||||
Kernel::Caps caps = mem.create_caps (capssize)
|
||||
unsigned user
|
||||
if create:
|
||||
user = create (mem, caps)
|
||||
else:
|
||||
// Increment last_user; skip 0.
|
||||
// FIXME: if this really wraps, it is possible that two users share their id.
|
||||
if !++last_user:
|
||||
++last_user
|
||||
user = last_user
|
||||
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (user, id))
|
||||
caps.set (0, c.copy ())
|
||||
caps.set (1, mem.copy ())
|
||||
reply.invoke (0, 0, caps.copy ())
|
||||
Kernel::free_cap (c)
|
||||
Kernel::free_cap (caps)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
Kernel::Caps caps (arg)
|
||||
Kernel::Cap c = caps.get (0)
|
||||
Kernel::Num user = Kernel::my_receiver.get_protected (c)
|
||||
Kernel::free_cap (c)
|
||||
if user.h != id:
|
||||
Kernel::panic (user.h, "invalid id for destroy")
|
||||
// TODO: unuse.
|
||||
if destroy:
|
||||
destroy (user.l, caps)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
case Device::USE:
|
||||
Kernel::Caps caps (arg)
|
||||
Kernel::Cap c = caps.get (0)
|
||||
Kernel::Num user = Kernel::my_receiver.get_protected (c)
|
||||
Kernel::free_cap (c)
|
||||
if user.h != id:
|
||||
Kernel::panic (user.h, "invalid id for use")
|
||||
// TODO: send unuse signal.
|
||||
current_user = user.l
|
||||
if use:
|
||||
use (user.l, caps)
|
||||
c = caps.get (2)
|
||||
c.invoke (1)
|
||||
Kernel::free_cap (c)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
case Device::UNUSE:
|
||||
Kernel::Caps caps (arg)
|
||||
Kernel::Cap c = caps.get (0)
|
||||
Kernel::Num user = Kernel::my_receiver.get_protected (c)
|
||||
Kernel::free_cap (c)
|
||||
if user.h != id:
|
||||
Kernel::panic (user.h, "invalid id for unuse")
|
||||
if unuse:
|
||||
unuse (user.l, caps)
|
||||
if user.l == current_user:
|
||||
// Every process which wants to be switchable through a terminal must implement this interface.
|
||||
struct Device : public Iris::Cap:
|
||||
Device (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
CREATE_USER = WString::ID
|
||||
DESTROY_USER
|
||||
UNUSE
|
||||
USE
|
||||
ID
|
||||
// Create a new user for this device. It will not be the active user.
|
||||
// The provided storage must allow object creation; no other actions may be used by the terminal.
|
||||
Iris::Cap create_user (Iris::Memory storage, unsigned arg1 = 0, Iris::Num arg2 = 0):
|
||||
iocall (storage, Iris::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2)
|
||||
return Iris::get_arg ()
|
||||
// Destroy a user. It is made inactive if it was active.
|
||||
void destroy_user (Iris::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
|
||||
// Make user inactive.
|
||||
void unuse (Iris::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | UNUSE)
|
||||
// Make user active. It makes the previous active user inactive.
|
||||
void use (Iris::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | USE)
|
||||
// Convenience function for threads implementing a device.
|
||||
static void host (unsigned id, unsigned ¤t_user, Iris::Cap &reply, Iris::Cap &arg, unsigned capssize = 3, unsigned (*create)(Iris::Memory mem, Iris::Caps caps) = NULL, void (*destroy)(unsigned id, Iris::Caps caps) = NULL, void (*use)(unsigned id, Iris::Caps caps) = NULL, void (*unuse)(unsigned id, Iris::Caps caps) = NULL):
|
||||
static unsigned last_user
|
||||
switch Iris::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
Iris::Memory mem (arg)
|
||||
Iris::Caps caps = mem.create_caps (capssize)
|
||||
unsigned user
|
||||
if create:
|
||||
user = create (mem, caps)
|
||||
else:
|
||||
// Increment last_user; skip 0.
|
||||
// FIXME: if this really wraps, it is possible that two users share their id.
|
||||
if !++last_user:
|
||||
++last_user
|
||||
user = last_user
|
||||
Iris::Cap c = Iris::my_receiver.create_capability (Iris::Num (user, id))
|
||||
caps.set (0, c.copy ())
|
||||
caps.set (1, mem.copy ())
|
||||
reply.invoke (0, 0, caps.copy ())
|
||||
Iris::free_cap (c)
|
||||
Iris::free_cap (caps)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
Iris::Caps caps (arg)
|
||||
Iris::Cap c = caps.get (0)
|
||||
Iris::Num user = Iris::my_receiver.get_protected (c)
|
||||
Iris::free_cap (c)
|
||||
if user.h != id:
|
||||
Iris::panic (user.h, "invalid id for destroy")
|
||||
// TODO: unuse.
|
||||
if destroy:
|
||||
destroy (user.l, caps)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
case Device::USE:
|
||||
Iris::Caps caps (arg)
|
||||
Iris::Cap c = caps.get (0)
|
||||
Iris::Num user = Iris::my_receiver.get_protected (c)
|
||||
Iris::free_cap (c)
|
||||
if user.h != id:
|
||||
Iris::panic (user.h, "invalid id for use")
|
||||
// TODO: send unuse signal.
|
||||
current_user = user.l
|
||||
if use:
|
||||
use (user.l, caps)
|
||||
c = caps.get (2)
|
||||
c.invoke (0)
|
||||
Kernel::free_cap (c)
|
||||
current_user = 0
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
break
|
||||
c.invoke (1)
|
||||
Iris::free_cap (c)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
case Device::UNUSE:
|
||||
Iris::Caps caps (arg)
|
||||
Iris::Cap c = caps.get (0)
|
||||
Iris::Num user = Iris::my_receiver.get_protected (c)
|
||||
Iris::free_cap (c)
|
||||
if user.h != id:
|
||||
Iris::panic (user.h, "invalid id for unuse")
|
||||
if unuse:
|
||||
unuse (user.l, caps)
|
||||
if user.l == current_user:
|
||||
c = caps.get (2)
|
||||
c.invoke (0)
|
||||
Iris::free_cap (c)
|
||||
current_user = 0
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid request\n")
|
||||
reply.invoke (~0)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
|
||||
// Interface for talking to the parent process.
|
||||
struct Parent : public Kernel::Cap:
|
||||
Parent (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
GET_DEVICE = Device::ID
|
||||
PROVIDE_DEVICE
|
||||
WAIT
|
||||
GET_MEMORY
|
||||
PROVIDE_MEMORY
|
||||
INIT_DONE
|
||||
EXIT
|
||||
ID
|
||||
// Get a device handle.
|
||||
template <typename _T> _T get_device (unsigned num = 0):
|
||||
icall (Kernel::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID)
|
||||
return Kernel::get_arg ()
|
||||
// Provide a device handle.
|
||||
template <typename _T> void provide_device (Device dev, unsigned num = 0):
|
||||
ocall (dev, Kernel::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID)
|
||||
// Wait until a device is used by the caller again.
|
||||
template <typename _T> void wait (unsigned num = 0):
|
||||
call (Kernel::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
|
||||
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
|
||||
Kernel::Memory get_memory (Kernel::Cap target):
|
||||
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
|
||||
return Kernel::get_arg ()
|
||||
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
|
||||
Kernel::Cap provide_memory (unsigned limit):
|
||||
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
|
||||
return Kernel::get_arg ()
|
||||
// Signal the parent that the initialisation phase is over.
|
||||
void init_done ():
|
||||
call (CAP_MASTER_DIRECT | INIT_DONE)
|
||||
// Exit the program. The parent does not reply, but kills the process.
|
||||
void exit (Kernel::Num code):
|
||||
call (CAP_MASTER_DIRECT | EXIT, code)
|
||||
struct Elfrun : public Iris::Cap:
|
||||
Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
RUN_STRING = Device::ID
|
||||
RUN_CAPS
|
||||
ID
|
||||
enum arg_pos:
|
||||
PARENT_MEMORY
|
||||
DATA
|
||||
PARENT
|
||||
Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
|
||||
Iris::Caps caps = Iris::my_memory.create_caps (3)
|
||||
caps.set (PARENT_MEMORY, parent_memory)
|
||||
caps.set (DATA, data)
|
||||
caps.set (PARENT, parent)
|
||||
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps))
|
||||
Iris::Caps ret = Iris::get_arg ()
|
||||
Iris::my_memory.destroy (caps)
|
||||
Iris::free_cap (caps)
|
||||
return ret
|
||||
Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
|
||||
Iris::Caps caps = Iris::my_memory.create_caps (3)
|
||||
caps.set (PARENT_MEMORY, parent_memory)
|
||||
caps.set (DATA, data)
|
||||
caps.set (PARENT, parent)
|
||||
iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps))
|
||||
Iris::Caps ret = Iris::get_arg ()
|
||||
Iris::my_memory.destroy (caps)
|
||||
Iris::free_cap (caps)
|
||||
return ret
|
||||
|
||||
// Keyboard interface.
|
||||
struct Keyboard : public Kernel::Cap:
|
||||
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
SET_CB = Parent::ID
|
||||
GET_NUM_KEYS
|
||||
GET_KEYS
|
||||
ID
|
||||
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
||||
enum constant:
|
||||
RELEASE = 1 << 31
|
||||
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
|
||||
void set_cb (Kernel::Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
// Get the number of keys on the keyboard.
|
||||
unsigned get_num_keys ():
|
||||
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
||||
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each).
|
||||
void get_keys (unsigned first):
|
||||
call (CAP_MASTER_DIRECT | GET_KEYS, first)
|
||||
// Interface for talking to the parent process.
|
||||
struct Parent : public Iris::Cap:
|
||||
Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
GET_DEVICE = Elfrun::ID
|
||||
PROVIDE_DEVICE
|
||||
WAIT
|
||||
GET_MEMORY
|
||||
PROVIDE_MEMORY
|
||||
INIT_DONE
|
||||
EXIT
|
||||
ID
|
||||
// Get a device handle.
|
||||
template <typename _T> _T get_device (unsigned num = 0):
|
||||
icall (Iris::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID)
|
||||
return Iris::get_arg ()
|
||||
// Provide a device handle.
|
||||
template <typename _T> void provide_device (Device dev, unsigned num = 0):
|
||||
ocall (dev, Iris::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID)
|
||||
// Wait until a device is used by the caller again.
|
||||
template <typename _T> void wait (unsigned num = 0):
|
||||
call (Iris::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
|
||||
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
|
||||
Iris::Memory get_memory (Iris::Cap target):
|
||||
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
|
||||
return Iris::get_arg ()
|
||||
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
|
||||
Iris::Cap provide_memory (unsigned limit):
|
||||
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
|
||||
return Iris::get_arg ()
|
||||
// Signal the parent that the initialisation phase is over.
|
||||
void init_done (Iris::Num stage = 0):
|
||||
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
|
||||
// Exit the program. The parent does not reply, but kills the process.
|
||||
void exit (Iris::Num code):
|
||||
call (CAP_MASTER_DIRECT | EXIT, code)
|
||||
|
||||
// Buzzer interface.
|
||||
struct Buzzer : public Kernel::Cap:
|
||||
Buzzer (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
BEEP = Keyboard::ID
|
||||
STOP
|
||||
ID
|
||||
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
|
||||
void beep (unsigned freq, unsigned ms, unsigned volume, Kernel::Cap cb = Kernel::Cap ()):
|
||||
ocall (cb, Kernel::Num (CAP_MASTER_DIRECT | BEEP, volume), Kernel::Num (freq, ms))
|
||||
// Abort current beep, if any.
|
||||
void stop ():
|
||||
call (CAP_MASTER_DIRECT | STOP)
|
||||
// Keyboard interface.
|
||||
struct Keyboard : public Iris::Cap:
|
||||
Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
SET_CB = Parent::ID
|
||||
GET_NUM_KEYS
|
||||
GET_KEYS
|
||||
ID
|
||||
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
||||
enum constant:
|
||||
RELEASE = 1 << 31
|
||||
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
|
||||
void set_cb (Iris::Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
// Get the number of keys on the keyboard.
|
||||
unsigned get_num_keys ():
|
||||
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
||||
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each).
|
||||
void get_keys (unsigned first):
|
||||
call (CAP_MASTER_DIRECT | GET_KEYS, first)
|
||||
|
||||
// Display interface.
|
||||
struct Display : public Kernel::Cap:
|
||||
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
SET_EOF_CB = Buzzer::ID
|
||||
MAP_FB
|
||||
GET_INFO
|
||||
ID
|
||||
// Register an end-of-frame callback.
|
||||
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
|
||||
void set_eof_cb (Kernel::Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
|
||||
// Map the framebuffer into memory.
|
||||
void map_fb (unsigned address):
|
||||
call (CAP_MASTER_DIRECT | MAP_FB, address)
|
||||
// Get information about the display.
|
||||
void get_info ():
|
||||
// TODO: Interface is to be designed.
|
||||
kdebug ("using undefined interface Display::get_info ()\n")
|
||||
Kernel::panic (0)
|
||||
// Buzzer interface.
|
||||
struct Buzzer : public Iris::Cap:
|
||||
Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
BEEP = Keyboard::ID
|
||||
STOP
|
||||
ID
|
||||
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
|
||||
void beep (unsigned freq, unsigned ms, unsigned volume, Iris::Cap cb = Iris::Cap ()):
|
||||
ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms))
|
||||
// Abort current beep, if any.
|
||||
void stop ():
|
||||
call (CAP_MASTER_DIRECT | STOP)
|
||||
|
||||
// Numerical setting, such as a display backlight.
|
||||
struct Setting : public Kernel::Cap:
|
||||
Setting (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
SET = Display::ID
|
||||
GET_RANGE
|
||||
ID
|
||||
// Set a new value.
|
||||
void set (unsigned value):
|
||||
call (CAP_MASTER_DIRECT | SET, value)
|
||||
// Get the maximum value for this setting. Using a higher value with SET gives undefined results.
|
||||
unsigned get_range ():
|
||||
return call (CAP_MASTER_DIRECT | GET_RANGE).l
|
||||
// Display interface.
|
||||
struct Display : public Iris::Cap:
|
||||
Display (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
SET_EOF_CB = Buzzer::ID
|
||||
MAP_FB
|
||||
GET_INFO
|
||||
ID
|
||||
// Register an end-of-frame callback.
|
||||
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
|
||||
void set_eof_cb (Iris::Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
|
||||
// Map the framebuffer into memory.
|
||||
void map_fb (unsigned address):
|
||||
call (CAP_MASTER_DIRECT | MAP_FB, address)
|
||||
// Get information about the display.
|
||||
void get_info ():
|
||||
// TODO: Interface is to be designed.
|
||||
Iris::panic (0, "using undefined interface Display::get_info ()")
|
||||
|
||||
// File system interface.
|
||||
// filesystem-related interfaces: directory, stream, seekable.
|
||||
// Normal files implement stream and/or seekable. Directories implement directory.
|
||||
// Seekable is not a class, it is identical to [W]String.
|
||||
// Numerical setting, such as a display backlight.
|
||||
struct Setting : public Iris::Cap:
|
||||
Setting (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
SET = Display::ID
|
||||
GET_RANGE
|
||||
ID
|
||||
// Set a new value.
|
||||
void set (unsigned value):
|
||||
call (CAP_MASTER_DIRECT | SET, value)
|
||||
// Get the maximum value for this setting. Using a higher value with SET gives undefined results.
|
||||
unsigned get_range ():
|
||||
return call (CAP_MASTER_DIRECT | GET_RANGE).l
|
||||
|
||||
// Directory interface.
|
||||
struct Directory : public Kernel::Cap:
|
||||
Directory (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = Setting::ID
|
||||
GET_NAME
|
||||
GET_FILE_RO
|
||||
GET_FILE_INFO
|
||||
LOCK_RO
|
||||
UNLOCK_RO
|
||||
ID
|
||||
// Get the number of entries in this directory.
|
||||
Kernel::Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
// Get the filename.
|
||||
String get_name (Kernel::Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||
return Kernel::get_arg ()
|
||||
// Get the file.
|
||||
Kernel::Cap get_file_ro (Kernel::Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
|
||||
return Kernel::get_arg ()
|
||||
// Get file info. TODO: define possible types.
|
||||
Kernel::Num get_file_info (Kernel::Num idx, unsigned type):
|
||||
return icall (Kernel::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
||||
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
|
||||
void lock_ro ():
|
||||
call (CAP_MASTER_DIRECT | LOCK_RO)
|
||||
// Release a read-only lock. Write operations can only be done when the directory is locked.
|
||||
void unlock_ro ():
|
||||
call (CAP_MASTER_DIRECT | UNLOCK_RO)
|
||||
struct WDirectory : public Directory:
|
||||
WDirectory (Kernel::Cap c = Kernel::Cap ()) : Directory (c):
|
||||
enum request:
|
||||
GET_FILE = Directory::ID
|
||||
CREATE_FILE
|
||||
DELETE_FILE
|
||||
LOCK
|
||||
UNLOCK
|
||||
ID
|
||||
// Get the file.
|
||||
Kernel::Cap get_file (Kernel::Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||
return Kernel::get_arg ()
|
||||
// Create a new file. After this, any index may map to a different file.
|
||||
Kernel::Cap create_file (String name):
|
||||
icall (CAP_MASTER_DIRECT | CREATE_FILE)
|
||||
return Kernel::get_arg ()
|
||||
// Delete a file. After this, any index may map to a different file.
|
||||
void delete_file (Kernel::Num idx):
|
||||
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||
// Lock the directory. Write operations can only be done when the directory is locked.
|
||||
void lock ():
|
||||
call (CAP_MASTER_DIRECT | LOCK)
|
||||
// Unlock the directory. Write operations can only be done when the directory is locked.
|
||||
void unlock ():
|
||||
call (CAP_MASTER_DIRECT | UNLOCK)
|
||||
// File system interface.
|
||||
// filesystem-related interfaces: directory, stream, seekable.
|
||||
// Normal files implement stream and/or seekable. Directories implement directory.
|
||||
// Seekable is not a class, it is identical to [W]String.
|
||||
|
||||
// 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 ()
|
||||
// Directory interface.
|
||||
struct Directory : public Iris::Cap:
|
||||
Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = Setting::ID
|
||||
GET_NAME
|
||||
GET_FILE_RO
|
||||
GET_FILE_INFO
|
||||
LOCK_RO
|
||||
UNLOCK_RO
|
||||
ID
|
||||
// Get the number of entries in this directory.
|
||||
Iris::Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
// Get the filename.
|
||||
String get_name (Iris::Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||
return Iris::get_arg ()
|
||||
// Get the file.
|
||||
Iris::Cap get_file_ro (Iris::Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
|
||||
return Iris::get_arg ()
|
||||
// Get file info. TODO: define possible types.
|
||||
Iris::Num get_file_info (Iris::Num idx, unsigned type):
|
||||
return icall (Iris::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
||||
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
|
||||
void lock_ro ():
|
||||
call (CAP_MASTER_DIRECT | LOCK_RO)
|
||||
// Release a read-only lock. Write operations can only be done when the directory is locked.
|
||||
void unlock_ro ():
|
||||
call (CAP_MASTER_DIRECT | UNLOCK_RO)
|
||||
struct WDirectory : public Directory:
|
||||
WDirectory (Iris::Cap c = Iris::Cap ()) : Directory (c):
|
||||
enum request:
|
||||
GET_FILE = Directory::ID
|
||||
CREATE_FILE
|
||||
DELETE_FILE
|
||||
LOCK
|
||||
UNLOCK
|
||||
ID
|
||||
// Get the file.
|
||||
Iris::Cap get_file (Iris::Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||
return Iris::get_arg ()
|
||||
// Create a new file. After this, any index may map to a different file.
|
||||
Iris::Cap create_file (String name):
|
||||
icall (CAP_MASTER_DIRECT | CREATE_FILE)
|
||||
return Iris::get_arg ()
|
||||
// Delete a file. After this, any index may map to a different file.
|
||||
void delete_file (Iris::Num idx):
|
||||
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||
// Lock the directory. Write operations can only be done when the directory is locked.
|
||||
void lock ():
|
||||
call (CAP_MASTER_DIRECT | LOCK)
|
||||
// Unlock the directory. Write operations can only be done when the directory is locked.
|
||||
void unlock ():
|
||||
call (CAP_MASTER_DIRECT | UNLOCK)
|
||||
|
||||
// Stream interface.
|
||||
struct Stream : public Kernel::Cap:
|
||||
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
READ = Filesystem::ID
|
||||
WRITE
|
||||
ID
|
||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||
Kernel::Num read (Kernel::Num size, bool block):
|
||||
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, block), size)
|
||||
// Try to write size bytes. Returns the number of bytes successfully written.
|
||||
Kernel::Num write (String s, Kernel::Num size):
|
||||
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
||||
// A filesystem turns a String into a Directory.
|
||||
struct Filesystem : public Device:
|
||||
Filesystem (Iris::Cap c = Iris::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 Iris::get_arg ()
|
||||
Directory use_device_ro (String dev):
|
||||
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
|
||||
return Iris::get_arg ()
|
||||
|
||||
// Stream interface.
|
||||
struct Stream : public Iris::Cap:
|
||||
Stream (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
||||
enum request:
|
||||
READ = Filesystem::ID
|
||||
WRITE
|
||||
ID
|
||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||
Iris::Num read (Iris::Num size, bool block):
|
||||
return icall (Iris::Num (CAP_MASTER_DIRECT | READ, block), size)
|
||||
// Try to write size bytes. Returns the number of bytes successfully written.
|
||||
Iris::Num write (String s, Iris::Num size):
|
||||
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
||||
|
||||
|
||||
|
||||
// Block device interface.
|
||||
struct Block_device : public WString:
|
||||
Block_device (Kernel::Cap c = Kernel::Cap ()) : WString (c):
|
||||
// TODO: to be designed.
|
||||
// Block device interface.
|
||||
struct Block_device : public WString:
|
||||
Block_device (Iris::Cap c = Iris::Cap ()) : WString (c):
|
||||
// TODO: to be designed.
|
||||
|
||||
|
||||
// TODO.
|
||||
|
59
init.config
Normal file
59
init.config
Normal file
@ -0,0 +1,59 @@
|
||||
# load <name> = '<filename>' load a file into memory. Don't use this after killbootthreads.
|
||||
load session = "session.config"
|
||||
load driver_lcd = "lcd.elf"
|
||||
load driver_buzzer = "buzzer.elf"
|
||||
load driver_gpio = "gpio.elf"
|
||||
# load driver_audio = "audio.elf"
|
||||
# load driver_udc = "udc.elf"
|
||||
# load driver_nand = "nand.elf"
|
||||
|
||||
# load emu_lcd = "emu_display.elf"
|
||||
# load emu_buzzer = "emu_buzzer.elf"
|
||||
# load emu_keyboard = "emu_keyboard.elf"
|
||||
# load emu_audio = "emu_audio.elf"
|
||||
# load emu_udc = "emu_udc.elf"
|
||||
|
||||
# killbootthreads destroy bootinit, bootfs and bootstore.
|
||||
killbootthreads
|
||||
|
||||
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
|
||||
receive driver_lcd / Display = display
|
||||
receive driver_lcd / Setting = display_bright
|
||||
receive driver_buzzer / Buzzer = buzzer
|
||||
receive driver_gpio / Keyboard , 0 = keyboard
|
||||
receive driver_gpio / Keyboard , 1 = sysreq
|
||||
# receive driver_audio / Audio = audio
|
||||
# receive driver_udc / Udc = udc
|
||||
# receive driver_nand / WString = nand
|
||||
|
||||
# driver <name> run a previously loaded program priviledged.
|
||||
driver driver_lcd
|
||||
driver driver_buzzer
|
||||
driver driver_gpio
|
||||
# driver driver_audio
|
||||
# driver driver_udc
|
||||
# driver driver_nand
|
||||
|
||||
# wait wait until all expected capabilities are received.
|
||||
wait
|
||||
|
||||
# sysreq <cap> use a capability as the system request keyboard.
|
||||
sysreq sysreq
|
||||
|
||||
# give <name> (<type> [, <index>]) = <cap> give this capability to this program when it requests it.
|
||||
# give emu_display (display) = display
|
||||
# give emu_display_bright (setting) = display_bright
|
||||
# give emu_buzzer (buzzer) = buzzer
|
||||
# give emu_keyboard (keyboard, 0) = keyboard
|
||||
# give emu_audio (audio) = audio
|
||||
# give emu_udc (udc) = udc
|
||||
|
||||
# run <name> run a previously loaded program (normally).
|
||||
# run emu_lcd
|
||||
# run emu_buzzer
|
||||
# run emu_keyboard
|
||||
# run emu_audio
|
||||
# run emu_udc
|
||||
|
||||
# include <name> include a loaded file as another config file.
|
||||
include session
|
391
invoke.ccp
391
invoke.ccp
@ -60,8 +60,8 @@ void kThread::raise (unsigned code, unsigned data):
|
||||
kdebug (':')
|
||||
kdebug_num ((unsigned)old_current)
|
||||
kdebug ('/')
|
||||
if code < Kernel::NUM_EXCEPTION_CODES:
|
||||
kdebug (Kernel::exception_name[code])
|
||||
if code < Iris::NUM_EXCEPTION_CODES:
|
||||
kdebug (Iris::exception_name[code])
|
||||
else:
|
||||
kdebug ("invalid code:")
|
||||
kdebug_num (code)
|
||||
@ -73,7 +73,7 @@ void kThread::raise (unsigned code, unsigned data):
|
||||
if slots < 1 || !slot[0].caps || !slot[0].caps->cap (0)->target:
|
||||
return
|
||||
kCapability::Context c
|
||||
c.data[0] = Kernel::Num (code, data)
|
||||
c.data[0] = Iris::Num (code, data)
|
||||
slot[0].caps->cap (0)->invoke (&c)
|
||||
|
||||
// From user-provided, thus untrusted, data, find a capability.
|
||||
@ -128,7 +128,7 @@ bool kReceiver::try_deliver ():
|
||||
return true
|
||||
|
||||
// Send a message to a receiver; try to deliver it immediately.
|
||||
bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c):
|
||||
bool kReceiver::send_message (Iris::Num protected_data, kCapability::Context *c):
|
||||
//log_message ("send_message", (unsigned)this, protected_data.l, c)
|
||||
if owner && owner->is_waiting () && (!protected_only || protected_data.value () == reply_protected_data.value ()):
|
||||
if protected_only:
|
||||
@ -161,59 +161,64 @@ bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *
|
||||
return true
|
||||
|
||||
static kCapability::Context *context
|
||||
static kReceiver *reply_target
|
||||
static Kernel::Num reply_protected
|
||||
|
||||
static void reply_num (Kernel::Num num):
|
||||
static void reply_num (Iris::Num num):
|
||||
kCapability::Context c
|
||||
c.data[0] = num
|
||||
c.data[1] = 0
|
||||
if reply_target:
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
else:
|
||||
else if reply_protected.l == 0:
|
||||
dpanic (0, "nothing to reply to")
|
||||
else:
|
||||
kdebug ("not replying, because receiver was destroyed in the operation\n")
|
||||
|
||||
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
|
||||
kCapability::Context c
|
||||
c.data[0] = Kernel::Num (num1, num2)
|
||||
c.data[0] = Iris::Num (num1, num2)
|
||||
c.data[1] = num3
|
||||
if reply_target:
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
else if reply_protected.l == 0:
|
||||
dpanic (0, "nothing to reply to")
|
||||
else:
|
||||
dpanic (0, "nothing to reply to")
|
||||
kdebug ("not replying, because receiver was destroyed in the operation\n")
|
||||
|
||||
static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref, unsigned num = 0):
|
||||
static void reply_cap (unsigned target, Iris::Num protected_data, kCapRef *ref, unsigned num = 0):
|
||||
if !reply_target:
|
||||
dpanic (0, "nothing to reply to")
|
||||
if reply_protected.l == 0:
|
||||
dpanic (0, "nothing to reply to")
|
||||
else:
|
||||
kdebug ("not replying, because receiver was destroyed in the operation\n")
|
||||
return
|
||||
replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref)
|
||||
kCapability::Context c
|
||||
c.arg = kCapRef (&replied_caps, 0)
|
||||
c.copy[1] = true
|
||||
c.data[0] = Kernel::Num (num, 0)
|
||||
c.data[0] = Iris::Num (num, 0)
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
c.arg->invalidate ()
|
||||
|
||||
static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void receiver_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
kReceiver *receiver = (kReceiver *)protected_data.l
|
||||
switch cmd:
|
||||
case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
|
||||
case Iris::Receiver::SET_OWNER & REQUEST_MASK:
|
||||
if !c->arg.valid ():
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
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 | Iris::Thread::SET_OWNER):
|
||||
// FIXME: This makes it impossible to use a fake kThread capability.
|
||||
return
|
||||
receiver->own ((kThread *)c->arg->protected_data.l)
|
||||
break
|
||||
case Kernel::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
|
||||
case Iris::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
|
||||
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
|
||||
return
|
||||
case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
|
||||
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
|
||||
case Iris::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
|
||||
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Iris::Receiver::CALL_ASYNC : Iris::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
|
||||
return
|
||||
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
|
||||
case Iris::Receiver::GET_PROTECTED & REQUEST_MASK:
|
||||
if !c->arg.valid () || c->arg->target != receiver:
|
||||
if !c->arg.valid ():
|
||||
kdebug ("invalid arg\n")
|
||||
@ -226,23 +231,23 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
|
||||
kdebug_num ((unsigned)c->arg->protected_data.l)
|
||||
kdebug ("\n")
|
||||
dpanic (0, "wrong argument for get_protected")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
reply_num (c->arg->protected_data)
|
||||
return
|
||||
case Kernel::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
||||
case Iris::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
||||
reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
|
||||
return
|
||||
case Kernel::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
||||
case Iris::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
||||
receiver->reply_protected_data = c->data[1]
|
||||
break
|
||||
case Kernel::Receiver::GET_ALARM & REQUEST_MASK:
|
||||
case Iris::Receiver::GET_ALARM & REQUEST_MASK:
|
||||
reply_num (receiver->alarm_count)
|
||||
return
|
||||
case Kernel::Receiver::SET_ALARM & REQUEST_MASK:
|
||||
case Kernel::Receiver::ADD_ALARM & REQUEST_MASK:
|
||||
case Iris::Receiver::SET_ALARM & REQUEST_MASK:
|
||||
case Iris::Receiver::ADD_ALARM & REQUEST_MASK:
|
||||
unsigned old = receiver->alarm_count
|
||||
if cmd == (Kernel::Receiver::SET_ALARM & REQUEST_MASK):
|
||||
if cmd == (Iris::Receiver::SET_ALARM & REQUEST_MASK):
|
||||
receiver->alarm_count = c->data[1].l
|
||||
else:
|
||||
receiver->alarm_count += c->data[1].l
|
||||
@ -267,14 +272,14 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
|
||||
return
|
||||
default:
|
||||
dpanic (cmd, "invalid receiver operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void memory_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
kMemory *mem = (kMemory *)protected_data.l
|
||||
switch cmd:
|
||||
case Kernel::Memory::CREATE & REQUEST_MASK:
|
||||
case Iris::Memory::CREATE & REQUEST_MASK:
|
||||
switch c->data[0].h:
|
||||
case CAPTYPE_RECEIVER:
|
||||
kReceiver *ret = mem->alloc_receiver ()
|
||||
@ -282,7 +287,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x03311992, "out of memory creating receiver")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_MEMORY:
|
||||
kMemory *ret = mem->alloc_memory ()
|
||||
@ -290,7 +295,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x13311992, "out of memory creating memory")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_THREAD:
|
||||
kThread *ret = mem->alloc_thread (c->data[1].l)
|
||||
@ -301,7 +306,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
kdebug (")")
|
||||
else:
|
||||
dpanic (0x23311992, "out of memory creating thread")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_PAGE:
|
||||
kPage *ret = mem->alloc_page ()
|
||||
@ -309,7 +314,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x33311992, "out of memory creating page")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_CAPS:
|
||||
kCaps *ret = mem->alloc_caps (c->data[1].l)
|
||||
@ -317,16 +322,16 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x43311992, "out of memory creating caps")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
default:
|
||||
dpanic (0, "invalid create type")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
break
|
||||
case Kernel::Memory::DESTROY & REQUEST_MASK:
|
||||
case Iris::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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
switch (unsigned)c->arg->target & CAPTYPE_MASK:
|
||||
case CAPTYPE_RECEIVER:
|
||||
@ -348,87 +353,88 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
panic (0x55228930, "invalid case")
|
||||
return
|
||||
break
|
||||
case Kernel::Memory::LIST & REQUEST_MASK:
|
||||
case Iris::Memory::LIST & REQUEST_MASK:
|
||||
// TODO
|
||||
break
|
||||
case Kernel::Memory::MAP & REQUEST_MASK:
|
||||
case Iris::Memory::MAP & REQUEST_MASK:
|
||||
// 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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
if c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY:
|
||||
if c->data[1].l & (unsigned)c->arg->target & Iris::Page::READONLY:
|
||||
kdebug ("Mapping readonly because capability is readonly\n")
|
||||
page->flags |= Kernel::Page::MAPPED_READONLY
|
||||
page->flags |= Iris::Page::MAPPED_READONLY
|
||||
mem->map (page, c->data[1].l & PAGE_MASK)
|
||||
break
|
||||
case Kernel::Memory::MAPPING & REQUEST_MASK:
|
||||
case Iris::Memory::MAPPING & REQUEST_MASK:
|
||||
kPage *page = mem->get_mapping (c->data[1].l)
|
||||
if !page:
|
||||
reply_num (Kernel::ERR_UNMAPPED_READ)
|
||||
reply_num (Iris::ERR_UNMAPPED_READ)
|
||||
return
|
||||
unsigned t = CAPTYPE_PAGE | CAP_MASTER
|
||||
if page->flags & Kernel::Page::MAPPED_READONLY:
|
||||
t |= Kernel::Page::READONLY
|
||||
if page->flags & Iris::Page::MAPPED_READONLY:
|
||||
t |= Iris::Page::READONLY
|
||||
reply_cap (t, (unsigned)page, &page->refs)
|
||||
return
|
||||
case Kernel::Memory::GET_LIMIT & REQUEST_MASK:
|
||||
case Iris::Memory::GET_LIMIT & REQUEST_MASK:
|
||||
reply_num (mem->limit)
|
||||
return
|
||||
case Kernel::Memory::SET_LIMIT & REQUEST_MASK:
|
||||
case Iris::Memory::SET_LIMIT & REQUEST_MASK:
|
||||
mem->limit = c->data[1].l
|
||||
break
|
||||
default:
|
||||
dpanic (0, "invalid memory operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void thread_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
dbg_push (__LINE__)
|
||||
kThread *thread = (kThread *)protected_data.l
|
||||
switch cmd:
|
||||
case Kernel::Thread::GET_INFO & REQUEST_MASK:
|
||||
case Iris::Thread::GET_INFO & REQUEST_MASK:
|
||||
switch c->data[0].h:
|
||||
case Kernel::Thread::PC:
|
||||
case Iris::Thread::PC:
|
||||
reply_num (thread->pc)
|
||||
return
|
||||
case Kernel::Thread::SP:
|
||||
case Iris::Thread::SP:
|
||||
reply_num (thread->sp)
|
||||
return
|
||||
case Kernel::Thread::FLAGS:
|
||||
case Iris::Thread::FLAGS:
|
||||
reply_num (thread->flags)
|
||||
return
|
||||
default:
|
||||
reply_num (*kThread_arch_info (thread, c->data[0].h))
|
||||
return
|
||||
case Kernel::Thread::SET_INFO & REQUEST_MASK:
|
||||
case Iris::Thread::SET_INFO & REQUEST_MASK:
|
||||
unsigned *value
|
||||
switch c->data[0].h:
|
||||
case Kernel::Thread::PC:
|
||||
case Iris::Thread::PC:
|
||||
value = &thread->pc
|
||||
break
|
||||
case Kernel::Thread::SP:
|
||||
case Iris::Thread::SP:
|
||||
value = &thread->sp
|
||||
break
|
||||
case Kernel::Thread::FLAGS:
|
||||
case Iris::Thread::FLAGS:
|
||||
// It is not possible to set the PRIV flag (but it can be reset).
|
||||
if c->data[1].l & Kernel::Thread::PRIV:
|
||||
c->data[1].h &= ~Kernel::Thread::PRIV
|
||||
if c->data[1].l & Iris::Thread::PRIV:
|
||||
c->data[1].h &= ~Iris::Thread::PRIV
|
||||
value = &thread->flags
|
||||
if c->data[1].h & ~Kernel::Thread::USER_FLAGS:
|
||||
if c->data[1].h & ~Iris::Thread::USER_FLAGS:
|
||||
unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
||||
if (v & Kernel::Thread::WAITING) != (*value & Kernel::Thread::WAITING):
|
||||
if v & Kernel::Thread::WAITING:
|
||||
if (v & Iris::Thread::WAITING) != (*value & Iris::Thread::WAITING):
|
||||
if v & Iris::Thread::WAITING:
|
||||
thread->wait ()
|
||||
else
|
||||
thread->unwait ()
|
||||
if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING):
|
||||
if v & Kernel::Thread::RUNNING:
|
||||
if (v & Iris::Thread::RUNNING) != (*value & Iris::Thread::RUNNING):
|
||||
if v & Iris::Thread::RUNNING:
|
||||
thread->run ()
|
||||
else:
|
||||
thread->unrun ()
|
||||
@ -439,140 +445,155 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
if value:
|
||||
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
||||
break
|
||||
case Kernel::Thread::USE_SLOT & REQUEST_MASK:
|
||||
case Iris::Thread::USE_SLOT & REQUEST_MASK:
|
||||
dbg_push (__LINE__)
|
||||
if c->data[1].l >= thread->slots || !c->arg.valid ():
|
||||
if c->data[1].l == 0xdeadbeef:
|
||||
bool dummy
|
||||
dbg_code.h = (unsigned)c->arg.deref ()
|
||||
break
|
||||
dbg_send (5, 3)
|
||||
dpanic (c->data[1].l, "no argument given for USE_SLOT")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Iris::Caps::USE):
|
||||
dpanic ((unsigned)c->arg->target, "argument for USE_SLOT is not a caps")
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
dbg_push (__LINE__)
|
||||
unsigned slot = c->data[1].l
|
||||
dbg_push (__LINE__)
|
||||
kCaps *new_caps = (kCaps *)c->arg->protected_data.l
|
||||
dbg_push (__LINE__)
|
||||
if slot >= thread->slots:
|
||||
dpanic (0, "using invalid slot")
|
||||
return
|
||||
dbg_push (__LINE__)
|
||||
thread->unset_slot (slot)
|
||||
dbg_push (__LINE__)
|
||||
thread->slot[slot].caps = new_caps
|
||||
dbg_push (__LINE__)
|
||||
if new_caps:
|
||||
dbg_push (__LINE__)
|
||||
thread->slot[slot].next = new_caps->first_slot
|
||||
thread->slot[slot].caps = new_caps
|
||||
new_caps->first_slot.thread = thread
|
||||
new_caps->first_slot.index = slot
|
||||
dbg_push (__LINE__)
|
||||
break
|
||||
case Kernel::Thread::GET_CAPS & REQUEST_MASK:
|
||||
case Iris::Thread::GET_CAPS & REQUEST_MASK:
|
||||
unsigned slot = c->data[1].l
|
||||
if slot < thread->slots:
|
||||
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots)
|
||||
else:
|
||||
reply_num (thread->slots)
|
||||
return
|
||||
case Kernel::Thread::SCHEDULE & REQUEST_MASK:
|
||||
case Iris::Thread::SCHEDULE & REQUEST_MASK:
|
||||
do_schedule = true
|
||||
return
|
||||
default:
|
||||
if !(thread->flags & Kernel::Thread::PRIV):
|
||||
if !(thread->flags & Iris::Thread::PRIV):
|
||||
dpanic (0, "invalid thread operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
switch cmd:
|
||||
case Kernel::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK:
|
||||
case Iris::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK:
|
||||
arch_register_interrupt (c->data[1].l, c->arg.valid () && (((unsigned)c->arg->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->arg->protected_data.l : NULL)
|
||||
break
|
||||
case Kernel::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK:
|
||||
case Iris::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK:
|
||||
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
|
||||
return
|
||||
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
|
||||
case Iris::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
||||
dpanic (0, "not a thread argument for make priv")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
|
||||
((kThread *)c->arg->protected_data.l)->flags |= Iris::Thread::PRIV
|
||||
break
|
||||
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
|
||||
case Iris::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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kMemory *mem = (kMemory *)c->arg->protected_data.l
|
||||
if !mem->use (c->data[1].l):
|
||||
dpanic (0x34365435, "out of memory during alloc_range")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
unsigned data = phys_alloc (c->data[1].l)
|
||||
if !data:
|
||||
mem->unuse (c->data[1].l)
|
||||
dpanic (0x14365435, "out of memory during alloc_range")
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
reply_num (data & ~0xc0000000)
|
||||
return
|
||||
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
|
||||
case Iris::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
|
||||
if !c->arg.valid ():
|
||||
panic (0x71342134, "no argument provided for alloc physical")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
panic (0x21342134, "no page provided for alloc physical")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
page->forget ()
|
||||
if !(c->data[1].l & 2):
|
||||
if page->flags & Kernel::Page::PAYING:
|
||||
page->flags &= ~Kernel::Page::PAYING
|
||||
if page->flags & Iris::Page::PAYING:
|
||||
page->flags &= ~Iris::Page::PAYING
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
// This is for mapping allocated ranges. They are already paid for. Record that.
|
||||
if page->flags & Kernel::Page::PAYING:
|
||||
if page->flags & Iris::Page::PAYING:
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
page->flags |= Kernel::Page::PAYING
|
||||
page->flags |= Iris::Page::PAYING
|
||||
page->frame = (c->data[1].l & PAGE_MASK) | 0x80000000
|
||||
page->flags |= Kernel::Page::FRAME
|
||||
page->flags |= Iris::Page::FRAME
|
||||
if !(c->data[1].l & 1):
|
||||
page->flags |= Kernel::Page::UNCACHED
|
||||
page->flags |= Iris::Page::UNCACHED
|
||||
if !(c->data[1].l & 2):
|
||||
page->flags |= Kernel::Page::PHYSICAL
|
||||
page->flags |= Iris::Page::PHYSICAL
|
||||
kPage_arch_update_mapping (page)
|
||||
break
|
||||
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
|
||||
case Iris::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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
return
|
||||
case Kernel::Thread::PRIV_REBOOT & REQUEST_MASK:
|
||||
case Iris::Thread::PRIV_REBOOT & REQUEST_MASK:
|
||||
arch_reboot ()
|
||||
case Kernel::Thread::PRIV_PANIC & REQUEST_MASK:
|
||||
case Iris::Thread::PRIV_PANIC & REQUEST_MASK:
|
||||
if c->data[1].l == 0xdeaddead:
|
||||
dbg_code.l = 1
|
||||
break
|
||||
panic (c->data[1].l, "panic requested by thread")
|
||||
reply_num (~0)
|
||||
return
|
||||
case Kernel::Thread::DBG_SEND & REQUEST_MASK:
|
||||
case Iris::Thread::DBG_SEND & REQUEST_MASK:
|
||||
dbg_send (c->data[1].l, c->data[1].h)
|
||||
break
|
||||
default:
|
||||
dpanic (0, "invalid priv thread operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
dbg_push (__LINE__)
|
||||
reply_num (0)
|
||||
dbg_push (__LINE__)
|
||||
return
|
||||
|
||||
static void page_check_payment (kPage *page):
|
||||
kPage *p
|
||||
for p = page; p; p = p->share_prev:
|
||||
if p->flags & Kernel::Page::PAYING:
|
||||
if p->flags & Iris::Page::PAYING:
|
||||
return
|
||||
for p = page->share_next; p; p = p->share_next:
|
||||
if p->flags & Kernel::Page::PAYING:
|
||||
if p->flags & Iris::Page::PAYING:
|
||||
return
|
||||
// No kPage is paying for this frame anymore.
|
||||
raw_pfree (page->frame)
|
||||
@ -581,46 +602,55 @@ static void page_check_payment (kPage *page):
|
||||
p->frame = NULL
|
||||
p->share_prev = NULL
|
||||
p->share_next = NULL
|
||||
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
|
||||
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
|
||||
kPage_arch_update_mapping (p)
|
||||
for p = page, next = p->share_next; p; p = next, next = p->share_next:
|
||||
p->frame = NULL
|
||||
p->share_prev = NULL
|
||||
p->share_next = NULL
|
||||
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
|
||||
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
|
||||
kPage_arch_update_mapping (p)
|
||||
|
||||
static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
kPage *page = (kPage *)protected_data.l
|
||||
switch cmd & ~Kernel::Page::READONLY:
|
||||
case Kernel::Page::SHARE & REQUEST_MASK:
|
||||
switch cmd & ~Iris::Page::READONLY:
|
||||
case Iris::Page::SHARE & REQUEST_MASK:
|
||||
if !c->arg.valid ():
|
||||
// Cannot share without a target page.
|
||||
dpanic (0, "no target page for share")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
// FIXME: This makes it impossible to use a fake kPage capability.
|
||||
dpanic (0, "share target is no page")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
kPage *t = (kPage *)c->arg->protected_data.l
|
||||
//kdebug ("sharing from ")
|
||||
//kdebug_num ((unsigned)page)
|
||||
//kdebug (" (frame ")
|
||||
//kdebug_num (page->frame)
|
||||
//kdebug (") to ")
|
||||
//kdebug_num ((unsigned)t)
|
||||
//kdebug (" (frame ")
|
||||
//kdebug_num (t->frame)
|
||||
//kdebug (")\n")
|
||||
if t != page:
|
||||
t->forget ()
|
||||
if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY:
|
||||
t->flags |= Kernel::Page::READONLY
|
||||
if !(page->flags & Kernel::Page::FRAME):
|
||||
if c->data[0].h & Iris::Page::READONLY || cmd & Iris::Page::READONLY:
|
||||
t->flags |= Iris::Page::READONLY
|
||||
if !(page->flags & Iris::Page::FRAME):
|
||||
kdebug ("share problem: ")
|
||||
kdebug_num (page->flags)
|
||||
kdebug ("\n")
|
||||
dpanic (0, "sharing nothing results in lost page")
|
||||
kPage_arch_update_mapping (t)
|
||||
break
|
||||
if c->data[0].h & Kernel::Page::COPY:
|
||||
if ~t->flags & Kernel::Page::PAYING:
|
||||
if c->data[0].h & Iris::Page::COPY:
|
||||
if ~t->flags & Iris::Page::PAYING:
|
||||
kPage_arch_update_mapping (t)
|
||||
break
|
||||
if !(c->data[0].h & Kernel::Page::FORGET) || page->flags & Kernel::Page::SHARED:
|
||||
if !(c->data[0].h & Iris::Page::FORGET) || page->flags & Iris::Page::SHARED:
|
||||
unsigned *d = (unsigned *)page->frame
|
||||
if t == page:
|
||||
kPage *other = page->share_next ? page->share_next : page->share_prev
|
||||
@ -635,20 +665,20 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
page->share_prev = NULL
|
||||
page_check_payment (other)
|
||||
else:
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
t->flags |= Iris::Page::FRAME
|
||||
t->frame = raw_zalloc ()
|
||||
for unsigned i = 0; i < PAGE_SIZE; i += 4:
|
||||
((unsigned *)t->frame)[i >> 2] = d[i >> 2]
|
||||
if c->data[0].h & Kernel::Page::FORGET:
|
||||
if c->data[0].h & Iris::Page::FORGET:
|
||||
page->frame = NULL
|
||||
page->flags &= ~Kernel::Page::FRAME
|
||||
page->flags &= ~Iris::Page::FRAME
|
||||
kPage_arch_update_mapping (page)
|
||||
else:
|
||||
if t != page:
|
||||
t->frame = page->frame
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
t->flags |= Iris::Page::FRAME
|
||||
page->frame = NULL
|
||||
page->flags &= ~Kernel::Page::FRAME
|
||||
page->flags &= ~Iris::Page::FRAME
|
||||
kPage_arch_update_mapping (page)
|
||||
else:
|
||||
dpanic (0, "sharing page with itself...")
|
||||
@ -657,15 +687,15 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
dpanic (0, "sharing page with itself")
|
||||
kPage_arch_update_mapping (t)
|
||||
break
|
||||
if c->data[0].h & Kernel::Page::FORGET:
|
||||
if ~page->flags & Kernel::Page::SHARED:
|
||||
if t->flags & Kernel::Page::PAYING:
|
||||
if c->data[0].h & Iris::Page::FORGET:
|
||||
if ~page->flags & Iris::Page::SHARED:
|
||||
if t->flags & Iris::Page::PAYING:
|
||||
t->frame = page->frame
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
t->flags |= Iris::Page::FRAME
|
||||
else:
|
||||
dpanic (0, "move page failed because target is not paying")
|
||||
page->frame = NULL
|
||||
page->flags &= ~Kernel::Page::FRAME
|
||||
page->flags &= ~Iris::Page::FRAME
|
||||
kPage_arch_update_mapping (page)
|
||||
else:
|
||||
t->share_prev = page->share_prev
|
||||
@ -685,49 +715,49 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
if t->share_prev:
|
||||
t->share_prev->share_next = t
|
||||
t->frame = page->frame
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
t->flags |= Iris::Page::FRAME
|
||||
kPage_arch_update_mapping (t)
|
||||
break
|
||||
case Kernel::Page::SET_FLAGS & REQUEST_MASK:
|
||||
if cmd & Kernel::Page::READONLY:
|
||||
case Iris::Page::SET_FLAGS & REQUEST_MASK:
|
||||
if cmd & Iris::Page::READONLY:
|
||||
dpanic (0, "setting page flags denied")
|
||||
reply_num (Kernel::ERR_WRITE_DENIED)
|
||||
reply_num (Iris::ERR_WRITE_DENIED)
|
||||
return
|
||||
// Always refuse to set reserved flags.
|
||||
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
||||
c->data[1].h &= ~(Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
|
||||
// Remember the old flags.
|
||||
unsigned old = page->flags
|
||||
// Compute the new flags.
|
||||
page->flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
||||
|
||||
// If we stop paying, see if the frame is still paid for. If not, free it.
|
||||
if ~page->flags & old & Kernel::Page::PAYING:
|
||||
if ~page->flags & old & Iris::Page::PAYING:
|
||||
// Decrease the use counter in any case.
|
||||
page->address_space->unuse ()
|
||||
page_check_payment (page)
|
||||
|
||||
// If we start paying, increase the use counter.
|
||||
if page->flags & ~old & Kernel::Page::PAYING:
|
||||
if page->flags & ~old & Iris::Page::PAYING:
|
||||
if !page->address_space->use():
|
||||
dpanic (0, "cannot pay for frame")
|
||||
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
|
||||
page->flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
page->flags &= ~(Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
// However, if there already was a frame, keep it.
|
||||
if old & Kernel::Page::FRAME:
|
||||
page->flags |= Kernel::Page::FRAME
|
||||
if old & Iris::Page::FRAME:
|
||||
page->flags |= Iris::Page::FRAME
|
||||
|
||||
// If we want a frame, see if we can get it.
|
||||
if ~old & page->flags & Kernel::Page::FRAME:
|
||||
if ~page->flags & Kernel::Page::PAYING:
|
||||
if ~old & page->flags & Iris::Page::FRAME:
|
||||
if ~page->flags & Iris::Page::PAYING:
|
||||
dpanic (0, "cannot have frame without paying")
|
||||
page->flags &= ~Kernel::Page::FRAME
|
||||
page->flags &= ~Iris::Page::FRAME
|
||||
else:
|
||||
page->frame = page->address_space->zalloc ()
|
||||
kPage_arch_update_mapping (page)
|
||||
break
|
||||
default:
|
||||
dpanic (0, "invalid page operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
if page->flags > 0x7f:
|
||||
dpanic (page->flags, "weird output from page operation")
|
||||
@ -755,12 +785,12 @@ static void print_cap (kCapRef cap, kCapRef self):
|
||||
else:
|
||||
kdebug (']')
|
||||
|
||||
static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void caps_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
kCaps *caps = (kCapsP)protected_data.l
|
||||
switch cmd:
|
||||
case Kernel::Caps::GET & REQUEST_MASK:
|
||||
case Iris::Caps::GET & REQUEST_MASK:
|
||||
if c->data[1].l >= caps->size:
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
kdebug_num ((unsigned)caps)
|
||||
kdebug (" size: ")
|
||||
kdebug_num (caps->size)
|
||||
@ -782,10 +812,10 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
#endif
|
||||
reply_cap ((unsigned)ret->target, ret->protected_data, ((unsigned)ret->target & ~KERNEL_MASK) == 0 ? &((kObject *)ret->protected_data.l)->refs : &ret->target->capabilities)
|
||||
return
|
||||
case Kernel::Caps::GET_SIZE & REQUEST_MASK:
|
||||
case Iris::Caps::GET_SIZE & REQUEST_MASK:
|
||||
reply_num (caps->size)
|
||||
return
|
||||
case Kernel::Caps::SET & REQUEST_MASK:
|
||||
case Iris::Caps::SET & REQUEST_MASK:
|
||||
if c->data[1].l >= caps->size:
|
||||
dpanic (0, "invalid index for set caps")
|
||||
return
|
||||
@ -802,10 +832,10 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
//kdebug_num (caps->caps[c->data[1].l].protected_data.l)
|
||||
//kdebug ("\n")
|
||||
return
|
||||
case Kernel::Caps::TRUNCATE & REQUEST_MASK:
|
||||
case Iris::Caps::TRUNCATE & REQUEST_MASK:
|
||||
dpanic (0, "truncate caps is not implemented yet.")
|
||||
return
|
||||
case Kernel::Caps::PRINT & REQUEST_MASK:
|
||||
case Iris::Caps::PRINT & REQUEST_MASK:
|
||||
if c->data[1].l >= caps->size:
|
||||
dpanic (0, "invalid caps for print")
|
||||
return
|
||||
@ -839,12 +869,12 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
return
|
||||
default:
|
||||
dpanic (cmd, "invalid caps operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
|
||||
static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void list_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
kList *list = (kListP)protected_data.l
|
||||
if cmd == Kernel::List::SET_CB & REQUEST_MASK:
|
||||
if cmd == Iris::List::SET_CB & REQUEST_MASK:
|
||||
list->owner.clone (0, c->arg, c->copy[1])
|
||||
return
|
||||
kListitem *item
|
||||
@ -853,81 +883,81 @@ 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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::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 (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
switch cmd:
|
||||
case Kernel::List::GET_NEXT & REQUEST_MASK:
|
||||
case Iris::List::GET_NEXT & REQUEST_MASK:
|
||||
if !item:
|
||||
item = list->first_listitem
|
||||
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) != Iris::Listitem::LIST:
|
||||
dpanic (0, "trying to get next listitem with insufficient rights")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
item = item->next_item
|
||||
if !item:
|
||||
reply_num (0)
|
||||
return
|
||||
reply_cap (CAPTYPE_LISTITEM | Kernel::Listitem::LIST, (unsigned)item, &item->refs)
|
||||
reply_cap (CAPTYPE_LISTITEM | Iris::Listitem::LIST, (unsigned)item, &item->refs)
|
||||
return
|
||||
case Kernel::List::ADD_ITEM & REQUEST_MASK:
|
||||
case Iris::List::ADD_ITEM & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
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) != Iris::Listitem::ADD:
|
||||
dpanic (0, "trying to add listitem with insufficient rights")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
((kListitem *)c->arg->protected_data.l)->add (list)
|
||||
break
|
||||
case Kernel::List::GET_INFO & REQUEST_MASK:
|
||||
case Iris::List::GET_INFO & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "no item for List::GET_INFO")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT, ~0, ~0)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT, ~0, ~0)
|
||||
return
|
||||
reply_num (item->info)
|
||||
return
|
||||
case Kernel::List::SET_INFO & REQUEST_MASK:
|
||||
case Iris::List::SET_INFO & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "no item for List::SET_INFO")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
||||
return
|
||||
item->info = c->data[1]
|
||||
break
|
||||
case Kernel::List::GET_CAP & REQUEST_MASK:
|
||||
case Iris::List::GET_CAP & REQUEST_MASK:
|
||||
if !item:
|
||||
dpanic (0, "no item for List::GET_CAP")
|
||||
reply_num (Kernel::ERR_INVALID_ARGUMENT)
|
||||
reply_num (Iris::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)
|
||||
return
|
||||
default:
|
||||
dpanic (0, "invalid list operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void listitem_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void listitem_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
kListitem *item = (kListitemP)protected_data.l
|
||||
switch cmd:
|
||||
case Kernel::Listitem::CLEAR & REQUEST_MASK:
|
||||
case Iris::Listitem::CLEAR & REQUEST_MASK:
|
||||
// Disable linked capability.
|
||||
item->add (NULL)
|
||||
break
|
||||
case Kernel::Listitem::SET_CAP & REQUEST_MASK:
|
||||
case Iris::Listitem::SET_CAP & REQUEST_MASK:
|
||||
// Set linked capability.
|
||||
item->target.clone (0, c->arg, c->copy[1])
|
||||
break
|
||||
default:
|
||||
dpanic (0, "invalid listitem operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
reply_num (Iris::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
@ -936,18 +966,18 @@ static void kill_reply (kReceiver *r):
|
||||
while cap.valid ():
|
||||
kCapability *c = cap.deref ()
|
||||
cap = c->sibling_next
|
||||
if (unsigned)c->target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
|
||||
if (unsigned)c->target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
|
||||
c->invalidate ()
|
||||
|
||||
static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
static void kernel_invoke (unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
||||
// Kernel calling convention:
|
||||
// data[0].l is the request.
|
||||
// reply is the reply capability, or (for call capabilities) the target to call.
|
||||
// other parameters' meanings depend on the operation.
|
||||
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC):
|
||||
if target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL_ASYNC):
|
||||
// This is a call capability. reply is the capability to call.
|
||||
kReceiver *owner = (kReceiver *)protected_data.l
|
||||
owner->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
|
||||
owner->protected_only = target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL)
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if !reply_target:
|
||||
@ -961,11 +991,11 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
|
||||
// This is a user-implemented object. Create a real reply capability.
|
||||
kReceiver *call_target = reply_target
|
||||
c->reply = kCapRef (&reply_caps, 0)
|
||||
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Kernel::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
|
||||
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Iris::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
|
||||
c->copy[0] = true
|
||||
call_target->send_message (reply_protected, c)
|
||||
c->reply->invalidate ()
|
||||
else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
|
||||
else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
|
||||
// Reply capability: destroy all before invoke.
|
||||
kReceiver *r = (kReceiver *)reply_protected.l
|
||||
kill_reply (r)
|
||||
@ -981,7 +1011,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
|
||||
return
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
|
||||
if target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
|
||||
// This is a reply capability.
|
||||
kReceiver *r = (kReceiver *)protected_data.l
|
||||
kill_reply (r)
|
||||
@ -1026,7 +1056,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
|
||||
return
|
||||
return
|
||||
|
||||
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c):
|
||||
if dbg_code.l && old_current->id != 1:
|
||||
log_message ("invoke", (unsigned)target, protected_data.l, c)
|
||||
if (unsigned)target & ~KERNEL_MASK:
|
||||
@ -1046,4 +1076,5 @@ void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context
|
||||
reply_protected = c->reply->protected_data
|
||||
else:
|
||||
reply_target = NULL
|
||||
reply_protected.l = 0
|
||||
kernel_invoke ((unsigned)target, protected_data, c)
|
||||
|
28
iris.hhp
28
iris.hhp
@ -53,11 +53,12 @@
|
||||
// Master capabilities can create others.
|
||||
#define CAP_MASTER_CREATE (1 << 31)
|
||||
|
||||
#define __receiver_num 0
|
||||
#define __thread_num 1
|
||||
#define __memory_num 2
|
||||
#define __call_num 3
|
||||
#define __parent_num 4
|
||||
#define __caps_num 0
|
||||
#define __receiver_num 1
|
||||
#define __thread_num 2
|
||||
#define __memory_num 3
|
||||
#define __call_num 4
|
||||
#define __parent_num 5
|
||||
|
||||
// If this flag is set in a capability, it is copied instead of mapped.
|
||||
// If it is set in the target capability, the Thread waits after the request.
|
||||
@ -65,9 +66,8 @@
|
||||
// This constant signifies that no capability is passed.
|
||||
#define CAP_NONE (~CAP_COPY)
|
||||
|
||||
struct Parent
|
||||
|
||||
namespace Kernel:
|
||||
namespace Iris:
|
||||
struct Parent
|
||||
enum Exception_code:
|
||||
NO_ERROR
|
||||
ERR_WRITE_DENIED
|
||||
@ -138,6 +138,7 @@ namespace Kernel:
|
||||
Cap alloc_cap ()
|
||||
void free_slot (unsigned slot)
|
||||
void free_cap (Cap cap)
|
||||
extern bool enable_debug
|
||||
|
||||
struct Cap:
|
||||
unsigned code
|
||||
@ -161,6 +162,7 @@ namespace Kernel:
|
||||
Num protected_data
|
||||
Cap reply, arg
|
||||
|
||||
extern Caps my_caps
|
||||
extern Receiver my_receiver
|
||||
extern Thread my_thread
|
||||
extern Memory my_memory
|
||||
@ -280,7 +282,7 @@ namespace Kernel:
|
||||
Cap create_capability (Num protected_data):
|
||||
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
||||
return get_arg ()
|
||||
Num get_protected (Kernel::Cap target):
|
||||
Num get_protected (Cap target):
|
||||
return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED)
|
||||
Num get_reply_protected_data ():
|
||||
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
|
||||
@ -455,8 +457,8 @@ namespace Kernel:
|
||||
PHYSICAL = 0x20
|
||||
// This is a read-only flag, saying if this is uncachable memory.
|
||||
UNCACHED = 0x40
|
||||
void share (Cap target, unsigned flags):
|
||||
ocall (target, Kernel::Num (CAP_MASTER_DIRECT | SHARE, flags))
|
||||
void share (Cap target, unsigned flags = 0):
|
||||
ocall (target, Num (CAP_MASTER_DIRECT | SHARE, flags))
|
||||
unsigned get_flags ():
|
||||
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
|
||||
bool set_flags (unsigned new_flags, unsigned mask):
|
||||
@ -576,7 +578,7 @@ namespace Kernel:
|
||||
Cap ().call ()
|
||||
|
||||
// The start function has this prototype (there is no main function).
|
||||
Kernel::Num start ()
|
||||
Iris::Num start ()
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#if 1
|
||||
@ -596,7 +598,7 @@ static void kdebug_num (unsigned n, unsigned digits = 8):
|
||||
for i = 0; i < digits; ++i:
|
||||
kdebug_char (encode[(n >> (4 * ((digits - 1) - i))) & 0xf])
|
||||
|
||||
namespace Kernel:
|
||||
namespace Iris:
|
||||
inline void panic (unsigned code, char const *message = NULL):
|
||||
if message:
|
||||
kdebug (message)
|
||||
|
32
kernel.hhp
32
kernel.hhp
@ -75,7 +75,7 @@ struct kCapRef:
|
||||
kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
|
||||
kCapRef () : caps (NULL), index (~0):
|
||||
inline void clone (kCapRef source, bool copy)
|
||||
inline void set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
inline void set (kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
|
||||
struct kObject:
|
||||
kCapRef refs
|
||||
@ -97,7 +97,7 @@ bool kObject::is_free ():
|
||||
|
||||
struct kCapability : public kObject:
|
||||
struct Context:
|
||||
Kernel::Num data[2]
|
||||
Iris::Num data[2]
|
||||
kCapRef reply
|
||||
kCapRef arg
|
||||
bool copy[2]
|
||||
@ -105,7 +105,7 @@ struct kCapability : public kObject:
|
||||
kCapRef parent
|
||||
kCapRef children
|
||||
kCapRef sibling_prev, sibling_next
|
||||
Kernel::Num protected_data
|
||||
Iris::Num protected_data
|
||||
inline void invoke (kCapability::Context *c)
|
||||
void invalidate ()
|
||||
|
||||
@ -138,7 +138,7 @@ struct kThread : public kObject:
|
||||
void wait ()
|
||||
void unwait ()
|
||||
bool is_waiting ():
|
||||
return flags & Kernel::Thread::WAITING
|
||||
return flags & Iris::Thread::WAITING
|
||||
kCapRef find_capability (unsigned code, bool *copy)
|
||||
|
||||
struct kReceiver : public kObject:
|
||||
@ -154,14 +154,14 @@ struct kReceiver : public kObject:
|
||||
// The message queue. kMessages are added at the tail, and removed at the front.
|
||||
kMessageP messages
|
||||
kMessageP last_message
|
||||
Kernel::Num reply_protected_data
|
||||
Iris::Num reply_protected_data
|
||||
bool protected_only
|
||||
// This limit is for messages stored in its address space. There is unlimited space if senders provide it.
|
||||
unsigned queue_limit, queue_use
|
||||
void own (kThreadP o)
|
||||
void orphan ()
|
||||
bool try_deliver ()
|
||||
bool send_message (Kernel::Num protected_data, kCapability::Context *c)
|
||||
bool send_message (Iris::Num protected_data, kCapability::Context *c)
|
||||
void check (unsigned line)
|
||||
|
||||
struct kPage : public kObject:
|
||||
@ -177,7 +177,7 @@ struct kCaps : public kObject:
|
||||
unsigned size
|
||||
kCapability caps[1]
|
||||
inline kCapability *cap (unsigned idx)
|
||||
void set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
void set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
void clone (unsigned index, kCapRef source, bool copy)
|
||||
void init (unsigned size)
|
||||
|
||||
@ -185,8 +185,8 @@ struct kCaps : public kObject:
|
||||
#define MAX_NUM_CAPS ((PAGE_SIZE - 8 - sizeof (kCaps)) / sizeof (kCapability) + 1)
|
||||
|
||||
struct kMessage : public kObject:
|
||||
Kernel::Num protected_data
|
||||
Kernel::Num data[2]
|
||||
Iris::Num protected_data
|
||||
Iris::Num data[2]
|
||||
// This is a real Caps of two elements, not a link.
|
||||
kCaps caps
|
||||
|
||||
@ -198,7 +198,7 @@ struct kList : public kObject:
|
||||
struct kListitem : public kObject:
|
||||
kListP list
|
||||
kListitemP prev_item, next_item
|
||||
Kernel::Num info
|
||||
Iris::Num info
|
||||
// This is a real Caps of one element, not a link.
|
||||
kCaps target
|
||||
void add (kList *l)
|
||||
@ -257,7 +257,7 @@ extern "C":
|
||||
#define panic(n, m) panic_impl ((n), __stringify (__LINE__), __PRETTY_FUNCTION__, (m))
|
||||
void panic_impl (unsigned n, char const *line, char const *name, char const *message = "")
|
||||
#ifndef NDEBUG
|
||||
EXTERN Kernel::Num dbg_code
|
||||
EXTERN Iris::Num dbg_code
|
||||
EXTERN unsigned dbg_buffer[32]
|
||||
EXTERN unsigned dbg_buffer_head
|
||||
static void dbg_push (unsigned n):
|
||||
@ -293,7 +293,11 @@ EXTERN kThreadP current, old_current
|
||||
EXTERN bool do_schedule, must_wait
|
||||
// reply_caps is the source of a receiver-generated reply capability.
|
||||
// replied_caps is the source of kernel-generated capabilities which are used as arguments in a reply.
|
||||
// reply_target is the target receiver for kernel replies.
|
||||
// reply_protected is the protected data for the kernel reply.
|
||||
EXTERN kCaps reply_caps, replied_caps
|
||||
EXTERN kReceiver *reply_target
|
||||
EXTERN Iris::Num reply_protected
|
||||
|
||||
// Defined in memory.ccp
|
||||
unsigned init_memory (unsigned mem)
|
||||
@ -303,11 +307,11 @@ unsigned phys_alloc (unsigned num)
|
||||
void phys_free (unsigned page, unsigned num)
|
||||
|
||||
// Defind in invoke.ccp
|
||||
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c)
|
||||
void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c)
|
||||
|
||||
// Defined by architecture-specific files.
|
||||
void kThread_arch_init (kThread *thread)
|
||||
void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data)
|
||||
void kThread_arch_receive (kThread *thread, Iris::Num protected_data, Iris::Num *data)
|
||||
unsigned *kThread_arch_info (kThread *thread, unsigned num)
|
||||
void kMemory_arch_init (kMemory *mem)
|
||||
void kMemory_arch_free (kMemory *mem)
|
||||
@ -336,7 +340,7 @@ kCapability *kCapRef::deref ():
|
||||
return caps ? caps->cap (index) : NULL
|
||||
void kCapRef::clone (kCapRef source, bool copy):
|
||||
caps->clone (index, source, copy)
|
||||
void kCapRef::set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
void kCapRef::set (kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
if valid ():
|
||||
deref ()->invalidate ()
|
||||
caps->set (index, target, pdata, parent, parent_ptr)
|
||||
|
@ -172,6 +172,8 @@ void phys_free (unsigned page, unsigned num):
|
||||
kFreePages *p
|
||||
for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
|
||||
// Do nothing.
|
||||
if p == p->next:
|
||||
dpanic (0, "page is its own next")
|
||||
// The new block should be inserted directly after p.
|
||||
if (unsigned)p->next == page + size:
|
||||
// It can be merged with the block after it: do that.
|
||||
|
@ -38,7 +38,7 @@ void kPage_arch_init (kPage *page):
|
||||
page->arch.prev_mapped = NULL
|
||||
page->arch.next_mapped = NULL
|
||||
|
||||
void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data):
|
||||
void kThread_arch_receive (kThread *thread, Iris::Num protected_data, Iris::Num *data):
|
||||
thread->arch.a[0] = data[0].l
|
||||
thread->arch.a[1] = data[0].h
|
||||
thread->arch.a[2] = data[1].l
|
||||
@ -161,12 +161,12 @@ static unsigned make_entry_lo (kPage *page):
|
||||
//kdebug ("not mapping because there is no frame\n")
|
||||
return 0
|
||||
unsigned flags
|
||||
if page->flags & Kernel::Page::UNCACHED:
|
||||
if page->flags & Iris::Page::UNCACHED:
|
||||
flags = 0x10 | 0x2
|
||||
else:
|
||||
// 18 is write-back cache; 00 is write-through cache.
|
||||
flags = 0x18 | 0x2
|
||||
if ~page->flags & Kernel::Page::MAPPED_READONLY:
|
||||
if ~page->flags & Iris::Page::MAPPED_READONLY:
|
||||
flags |= 0x4
|
||||
return ((page->frame & ~0x80000000) >> 6) | flags
|
||||
|
||||
|
@ -33,7 +33,7 @@ static void init_idle ():
|
||||
idle.schedule_next = NULL
|
||||
idle.address_space = &idle_memory
|
||||
idle.refs.reset ()
|
||||
idle.flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV
|
||||
idle.flags = Iris::Thread::RUNNING | Iris::Thread::PRIV
|
||||
// initialize idle_memory.
|
||||
idle_memory.prev = NULL
|
||||
idle_memory.next = NULL
|
||||
@ -52,7 +52,7 @@ static void init_idle ():
|
||||
idle_page.prev = NULL
|
||||
idle_page.next = NULL
|
||||
idle_page.frame = 0x80000000
|
||||
idle_page.flags = Kernel::Page::PAYING | Kernel::Page::FRAME
|
||||
idle_page.flags = Iris::Page::PAYING | Iris::Page::FRAME
|
||||
idle_page.refs.reset ()
|
||||
idle_page.address_space = NULL
|
||||
current = &idle
|
||||
@ -147,7 +147,7 @@ static void init_threads ():
|
||||
return
|
||||
thread->pc = header->e_entry
|
||||
thread->sp = 0x80000000
|
||||
unsigned *used = (unsigned *)mem->zalloc ()
|
||||
kPage **used = (kPage **)mem->zalloc ()
|
||||
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:
|
||||
@ -168,12 +168,19 @@ static void init_threads ():
|
||||
panic (0, "different pages mapped to one address in intitial file")
|
||||
return
|
||||
continue
|
||||
used[idx] = 1
|
||||
page = mem->alloc_page ()
|
||||
page->frame = thread_start[i] + (idx << PAGE_BITS)
|
||||
page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
|
||||
page->flags = Iris::Page::PAYING | Iris::Page::FRAME
|
||||
if used[idx]:
|
||||
page->share_next = used[idx]
|
||||
used[idx]->share_prev = page
|
||||
used[idx]->flags |= Iris::Page::SHARED
|
||||
used[idx] = page
|
||||
page->flags |= Iris::Page::SHARED
|
||||
else:
|
||||
used[idx] = page
|
||||
if readonly:
|
||||
page->flags |= Kernel::Page::MAPPED_READONLY
|
||||
page->flags |= Iris::Page::MAPPED_READONLY
|
||||
if !mem->map (page, p):
|
||||
panic (0x22446688, "unable to map initial page")
|
||||
return
|
||||
@ -200,7 +207,7 @@ static void init_threads ():
|
||||
if !page->frame:
|
||||
panic (0x02220022, "out of memory");
|
||||
return
|
||||
page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
|
||||
page->flags = Iris::Page::PAYING | Iris::Page::FRAME
|
||||
if !mem->map (page, p):
|
||||
panic (0x33557799, "unable to map initial bss page")
|
||||
return
|
||||
@ -210,7 +217,7 @@ static void init_threads ():
|
||||
kdebug_num (i, 1)
|
||||
kdebug ('\n')
|
||||
else:
|
||||
if page->flags & Kernel::Page::MAPPED_READONLY:
|
||||
if page->flags & Iris::Page::MAPPED_READONLY:
|
||||
panic (0x20203030, "bss section starts on read-only page")
|
||||
return
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
@ -230,7 +237,7 @@ static void init_threads ():
|
||||
mem->pfree ((unsigned)used)
|
||||
kPage *stackpage = mem->alloc_page ()
|
||||
stackpage->frame = mem->zalloc ()
|
||||
stackpage->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
|
||||
stackpage->flags = Iris::Page::PAYING | Iris::Page::FRAME
|
||||
if !stackpage || !mem->map (stackpage, 0x7ffff000):
|
||||
panic (0x13151719, "unable to map initial stack page")
|
||||
return
|
||||
@ -242,11 +249,12 @@ static void init_threads ():
|
||||
kReceiver *recv = mem->alloc_receiver ()
|
||||
recv->owner = thread
|
||||
thread->receivers = recv
|
||||
thread->slot[0].caps->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs)
|
||||
thread->slot[0].caps->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Kernel::Num ((unsigned)thread), kCapRef (), &thread->refs)
|
||||
thread->slot[0].caps->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Kernel::Num ((unsigned)mem), kCapRef (), &mem->refs)
|
||||
thread->slot[0].caps->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Kernel::Receiver::CALL), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs)
|
||||
thread->flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV
|
||||
thread->slot[0].caps->set (__caps_num, (kReceiverP)(CAPTYPE_CAPS | CAP_MASTER), Iris::Num ((unsigned)thread->slot[0].caps), kCapRef (), &thread->slot[0].caps->refs)
|
||||
thread->slot[0].caps->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Iris::Num ((unsigned)recv), kCapRef (), &recv->refs)
|
||||
thread->slot[0].caps->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Iris::Num ((unsigned)thread), kCapRef (), &thread->refs)
|
||||
thread->slot[0].caps->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Iris::Num ((unsigned)mem), kCapRef (), &mem->refs)
|
||||
thread->slot[0].caps->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Iris::Receiver::CALL), Iris::Num ((unsigned)recv), kCapRef (), &recv->refs)
|
||||
thread->flags = Iris::Thread::RUNNING | Iris::Thread::PRIV
|
||||
if !i:
|
||||
first_scheduled = thread
|
||||
init_receiver = recv
|
||||
|
@ -33,7 +33,7 @@ static kThread *handle_exit ():
|
||||
schedule ()
|
||||
if !current:
|
||||
current = &idle
|
||||
if (current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) != Kernel::Thread::RUNNING:
|
||||
if (current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) != Iris::Thread::RUNNING:
|
||||
panic (current->flags, "non-scheduled thread running")
|
||||
if old_current == current:
|
||||
return current
|
||||
@ -54,7 +54,7 @@ static kThread *handle_exit ():
|
||||
asids[current->address_space->arch.asid] = (unsigned)current->address_space
|
||||
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
|
||||
directory = current->address_space->arch.directory
|
||||
if current->flags & Kernel::Thread::PRIV:
|
||||
if current->flags & Iris::Thread::PRIV:
|
||||
cp0_set (CP0_STATUS, 0x1000ff13)
|
||||
else:
|
||||
cp0_set (CP0_STATUS, 0x0000ff13)
|
||||
@ -69,7 +69,7 @@ kThread *tlb_refill ():
|
||||
if !directory:
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_NO_PAGE_DIRECTORY, addr)
|
||||
current->raise (Iris::ERR_NO_PAGE_DIRECTORY, addr)
|
||||
return handle_exit ()
|
||||
unsigned EntryHi
|
||||
cp0_get (CP0_ENTRY_HI, EntryHi)
|
||||
@ -77,7 +77,7 @@ kThread *tlb_refill ():
|
||||
if !t:
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_NO_PAGE_TABLE, addr)
|
||||
current->raise (Iris::ERR_NO_PAGE_TABLE, addr)
|
||||
else:
|
||||
// - 2 instead of - 1 means reset bit 0
|
||||
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
|
||||
@ -161,13 +161,22 @@ static void arch_invoke ():
|
||||
return
|
||||
msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
|
||||
msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
|
||||
msg.data[0] = Kernel::Num (old_current->arch.a[0], old_current->arch.a[1])
|
||||
msg.data[1] = Kernel::Num (old_current->arch.a[2], old_current->arch.a[3])
|
||||
msg.data[0] = Iris::Num (old_current->arch.a[0], old_current->arch.a[1])
|
||||
msg.data[1] = Iris::Num (old_current->arch.a[2], old_current->arch.a[3])
|
||||
dbg_push (old_current->arch.v[0])
|
||||
dbg_push (old_current->arch.t[0])
|
||||
dbg_push (old_current->arch.t[1])
|
||||
dbg_push (old_current->arch.a[0])
|
||||
dbg_push (old_current->arch.a[1])
|
||||
dbg_push (old_current->arch.a[2])
|
||||
dbg_push (old_current->arch.a[3])
|
||||
dbg_push (0xdeadbeef)
|
||||
target->invoke (&msg)
|
||||
dbg_push (0xfacebeef)
|
||||
if do_schedule && !must_wait:
|
||||
// If the call was to schedule without wait, it isn't done yet.
|
||||
schedule ()
|
||||
else if old_current != current && (old_current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) == Kernel::Thread::RUNNING:
|
||||
else if old_current != current && old_current && (old_current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) == Iris::Thread::RUNNING:
|
||||
// If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
|
||||
current = old_current
|
||||
|
||||
@ -186,31 +195,31 @@ kThread *exception ():
|
||||
// TLB modification.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_WRITE_DENIED, addr)
|
||||
current->raise (Iris::ERR_WRITE_DENIED, addr)
|
||||
break
|
||||
case 2:
|
||||
// TLB load or instruction fetch.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_UNMAPPED_READ, addr)
|
||||
current->raise (Iris::ERR_UNMAPPED_READ, addr)
|
||||
break
|
||||
case 3:
|
||||
// TLB store.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_UNMAPPED_WRITE, addr)
|
||||
current->raise (Iris::ERR_UNMAPPED_WRITE, addr)
|
||||
break
|
||||
case 4:
|
||||
// Address error load or instruction fetch.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_INVALID_ADDRESS_READ, addr)
|
||||
current->raise (Iris::ERR_INVALID_ADDRESS_READ, addr)
|
||||
break
|
||||
case 5:
|
||||
// Address error store.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (Kernel::ERR_INVALID_ADDRESS_WRITE, addr)
|
||||
current->raise (Iris::ERR_INVALID_ADDRESS_WRITE, addr)
|
||||
break
|
||||
case 6:
|
||||
// Bus error instruction fetch.
|
||||
@ -229,7 +238,7 @@ kThread *exception ():
|
||||
case 9:
|
||||
// Breakpoint.
|
||||
#if 0 || defined (NDEBUG)
|
||||
//current->raise (Kernel::ERR_BREAKPOINT, 0)
|
||||
//current->raise (Iris::ERR_BREAKPOINT, 0)
|
||||
#ifndef NDEBUG
|
||||
current->pc += 4
|
||||
#endif
|
||||
@ -251,19 +260,19 @@ kThread *exception ():
|
||||
break
|
||||
case 10:
|
||||
// Reserved instruction.
|
||||
current->raise (Kernel::ERR_RESERVED_INSTRUCTION, 0)
|
||||
current->raise (Iris::ERR_RESERVED_INSTRUCTION, 0)
|
||||
break
|
||||
case 11:
|
||||
// Coprocessor unusable.
|
||||
current->raise (Kernel::ERR_COPROCESSOR_UNUSABLE, 0)
|
||||
current->raise (Iris::ERR_COPROCESSOR_UNUSABLE, 0)
|
||||
break
|
||||
case 12:
|
||||
// Arithmetic overflow.
|
||||
current->raise (Kernel::ERR_OVERFLOW, 0)
|
||||
current->raise (Iris::ERR_OVERFLOW, 0)
|
||||
break
|
||||
case 13:
|
||||
// Trap.
|
||||
current->raise (Kernel::ERR_TRAP, 0)
|
||||
current->raise (Iris::ERR_TRAP, 0)
|
||||
break
|
||||
case 15:
|
||||
// Floating point exception.
|
||||
@ -272,7 +281,7 @@ kThread *exception ():
|
||||
case 23:
|
||||
// Reference to WatchHi/WatchLo address.
|
||||
cp0_set0 (CP0_WATCH_LO)
|
||||
current->raise (Kernel::ERR_WATCHPOINT, 0)
|
||||
current->raise (Iris::ERR_WATCHPOINT, 0)
|
||||
break
|
||||
case 24:
|
||||
// Machine check.
|
||||
|
@ -28,12 +28,12 @@ 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 devices.hh
|
||||
boot_threads = init udc
|
||||
programs = \#nanonote-gpio \#lcd display-emu bsquare display-emu2 ball \#buzzer metronome
|
||||
boot_threads = bootinit udc
|
||||
programs = init gpio lcd display-emu bsquare ball buzzer metronome elfrun
|
||||
|
||||
all: test
|
||||
|
||||
test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw $(addsuffix .elf,$(addprefix fs/,$(programs)))
|
||||
test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw $(addsuffix .elf,$(addprefix fs/,$(programs))) fs/init.config
|
||||
echo "reboot 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')" | nc localhost 5050
|
||||
|
||||
mips/nanonote/server/usb-server: mips/nanonote/server/usb-server.ccp mips/nanonote/server/Makefile.am mips/nanonote/server/configure.ac devices.hh
|
||||
@ -55,12 +55,15 @@ 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
|
||||
boot-programs/bootinit.o: TARGET_FLAGS = -I/usr/include
|
||||
source/elfrun.o: TARGET_FLAGS = -I/usr/include
|
||||
source/gpio.ccp: source/nanonote-gpio.ccp
|
||||
ln -s $(subst source/,,$<) $@
|
||||
$(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I.
|
||||
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
|
||||
$(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL
|
||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
|
||||
source/\#lcd.o: source/charset.data
|
||||
source/lcd.o: source/charset.data
|
||||
|
||||
source/charset.data: source/charset
|
||||
$< > $@
|
||||
|
@ -104,14 +104,14 @@
|
||||
// Default lcd framebuffer mapping space.
|
||||
#define LCD_FRAMEBUFFER_BASE ((unsigned *)0x00015000)
|
||||
|
||||
// Map IO memory (requires a priviledged Kernel::my_thread capability).
|
||||
// Map IO memory (requires a priviledged Iris::my_thread capability).
|
||||
#include <iris.hh>
|
||||
static void __map_io (unsigned physical, unsigned mapping):
|
||||
Kernel::Page p = Kernel::my_memory.create_page ()
|
||||
Iris::Page p = Iris::my_memory.create_page ()
|
||||
// false means not cachable; false means don't free when done.
|
||||
p.alloc_physical (physical, false, false)
|
||||
Kernel::my_memory.map (p, mapping)
|
||||
Kernel::free_cap (p)
|
||||
Iris::my_memory.map (p, mapping)
|
||||
Iris::free_cap (p)
|
||||
|
||||
#define map_cpm() do { __map_io (CPM_PHYSICAL, CPM_BASE); } while (0)
|
||||
#define map_intc() do { __map_io (INTC_PHYSICAL, INTC_BASE); } while (0)
|
||||
@ -135,8 +135,8 @@ static void __map_io (unsigned physical, unsigned mapping):
|
||||
|
||||
// udelay implementation
|
||||
void cdelay (unsigned cs):
|
||||
Kernel::my_receiver.set_alarm (cs + 1)
|
||||
Kernel::Cap ().call ()
|
||||
Iris::my_receiver.set_alarm (cs + 1)
|
||||
Iris::Cap ().call ()
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -105,37 +105,37 @@ void data::poll ():
|
||||
case ~1 & 0xffff:
|
||||
// No event.
|
||||
break
|
||||
case Directory::GET_SIZE:
|
||||
case Iris::Directory::GET_SIZE:
|
||||
unsigned long long size = dir.size ()
|
||||
std::cerr << "sending dir size\n"
|
||||
std::cerr << Directory::GET_SIZE << '\n'
|
||||
std::cerr << Iris::Directory::GET_SIZE << '\n'
|
||||
char *str = (char *)&size
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
std::cerr << " " << (unsigned)(str[i] & 0xff)
|
||||
std::cerr << '\n'
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Iris::Directory::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
|
||||
std::cerr << "unable to send size to device: " << usb_strerror () << std::endl
|
||||
usb_release_interface (handle, 0)
|
||||
usb_close (handle)
|
||||
handle = NULL
|
||||
return
|
||||
continue
|
||||
case Directory::GET_NAME:
|
||||
case Iris::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
|
||||
std::cerr << "sending filename\n"
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_NAME, 0, 0, dir[buffer[1]].name, 16, timeout) != 16:
|
||||
std::cerr << "sending filename " << dir[buffer[1]].full << "\n"
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Iris::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:
|
||||
case Iris::Directory::LOCK_RO:
|
||||
std::cerr << "lock\n"
|
||||
lock++
|
||||
std::cerr << "freezing file list\n"
|
||||
@ -145,7 +145,7 @@ void data::poll ():
|
||||
if !i->name.empty () && i->name[0] != '.':
|
||||
dir.push_back (Name (i->name))
|
||||
continue
|
||||
case Directory::UNLOCK_RO:
|
||||
case Iris::Directory::UNLOCK_RO:
|
||||
std::cerr << "unlock\n"
|
||||
if !lock:
|
||||
std::cerr << "unlocking without lock" << std::endl
|
||||
@ -156,7 +156,7 @@ void data::poll ():
|
||||
if !--lock:
|
||||
dir.clear ()
|
||||
continue
|
||||
case String::GET_PAGE:
|
||||
case Iris::String::GET_PAGE:
|
||||
if buffer[1] >= dir.size ():
|
||||
std::cerr << "reading invalid file" << std::endl
|
||||
usb_release_interface (handle, 0)
|
||||
@ -178,16 +178,16 @@ void data::poll ():
|
||||
handle = NULL
|
||||
return
|
||||
continue
|
||||
case String::GET_SIZE:
|
||||
case Iris::String::GET_SIZE:
|
||||
if buffer[1] >= dir.size ():
|
||||
std::cerr << "reading invalid file size" << std::endl
|
||||
std::cerr << "reading invalid file size " << buffer[1] << " >= " << dir.size () << std::endl
|
||||
usb_release_interface (handle, 0)
|
||||
usb_close (handle)
|
||||
handle = NULL
|
||||
return
|
||||
unsigned long long size = dir[buffer[1]].content.size ()
|
||||
std::cerr << "sending file size " << size << "\n"
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, String::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Iris::String::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
|
||||
std::cerr << "unable to send size to device: " << usb_strerror () << std::endl
|
||||
usb_release_interface (handle, 0)
|
||||
usb_close (handle)
|
||||
@ -312,18 +312,18 @@ void data::boot (unsigned entry):
|
||||
std::cerr << "(re)booted NanoNote\n"
|
||||
|
||||
static void dump_devices ():
|
||||
std::cerr << std::hex << "String: " << String::ID
|
||||
std::cerr << "\nWString: " << WString::ID
|
||||
std::cerr << "\nDevice: " << Device::ID
|
||||
std::cerr << "\nParent: " << Parent::ID
|
||||
std::cerr << "\nKeyboard: " << Keyboard::ID
|
||||
std::cerr << "\nBuzzer: " << Buzzer::ID
|
||||
std::cerr << "\nDisplay: " << Display::ID
|
||||
std::cerr << "\nSetting: " << Setting::ID
|
||||
std::cerr << "\nDirectory: " << Directory::ID
|
||||
std::cerr << "\nWDirectory: " << WDirectory::ID
|
||||
std::cerr << "\nFilesystem: " << Filesystem::ID
|
||||
std::cerr << "\nStream: " << Stream::ID
|
||||
std::cerr << std::hex << "String: " << Iris::String::ID
|
||||
std::cerr << "\nWString: " << Iris::WString::ID
|
||||
std::cerr << "\nDevice: " << Iris::Device::ID
|
||||
std::cerr << "\nParent: " << Iris::Parent::ID
|
||||
std::cerr << "\nKeyboard: " << Iris::Keyboard::ID
|
||||
std::cerr << "\nBuzzer: " << Iris::Buzzer::ID
|
||||
std::cerr << "\nDisplay: " << Iris::Display::ID
|
||||
std::cerr << "\nSetting: " << Iris::Setting::ID
|
||||
std::cerr << "\nDirectory: " << Iris::Directory::ID
|
||||
std::cerr << "\nWDirectory: " << Iris::WDirectory::ID
|
||||
std::cerr << "\nFilesystem: " << Iris::Filesystem::ID
|
||||
std::cerr << "\nStream: " << Iris::Stream::ID
|
||||
std::cerr << "\n"
|
||||
|
||||
int main (int argc, char **argv):
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
.balign 0x1000
|
||||
thread0:
|
||||
.incbin "init.elf"
|
||||
.incbin "bootinit.elf"
|
||||
|
||||
.balign 0x1000
|
||||
thread1:
|
||||
|
@ -137,14 +137,14 @@
|
||||
// Default lcd framebuffer mapping space.
|
||||
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
|
||||
|
||||
// Map IO memory (requires a priviledged Kernel::my_thread capability).
|
||||
// Map IO memory (requires a priviledged Iris::my_thread capability).
|
||||
#include <iris.hh>
|
||||
static void __map_io (unsigned physical, unsigned mapping):
|
||||
Kernel::Page p = Kernel::my_memory.create_page ()
|
||||
Iris::Page p = Iris::my_memory.create_page ()
|
||||
// false means not cachable; false means don't free when done.
|
||||
p.alloc_physical (physical, false, false)
|
||||
Kernel::my_memory.map (p, mapping)
|
||||
Kernel::free_cap (p)
|
||||
Iris::my_memory.map (p, mapping)
|
||||
Iris::free_cap (p)
|
||||
|
||||
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
|
||||
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
|
||||
@ -2326,8 +2326,8 @@ static __inline__ void udelay (unsigned us):
|
||||
|
||||
#ifndef __KERNEL__
|
||||
static __inline__ void cdelay (unsigned ds):
|
||||
Kernel::my_receiver.set_alarm (ds * (HZ / 100))
|
||||
Kernel::Cap ().call (~0)
|
||||
Iris::my_receiver.set_alarm (ds * (HZ / 100))
|
||||
Iris::Cap ().call (~0)
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
|
10
panic.ccp
10
panic.ccp
@ -48,7 +48,7 @@ void kdebug_num (unsigned num, unsigned digits):
|
||||
static void print_addr (char const *t, unsigned addr, bool last = false):
|
||||
kdebug (t)
|
||||
kdebug_num (addr)
|
||||
#if 1
|
||||
#if 0
|
||||
unsigned de = addr >> 21
|
||||
unsigned te = (addr >> 12) & ((1 << 9) - 1)
|
||||
if de < 0x400 && old_current && old_current->address_space->arch.directory && old_current->address_space->arch.directory[de]:
|
||||
@ -83,7 +83,7 @@ static void print_addr (char const *t, unsigned addr, bool last = false):
|
||||
kdebug_num (((unsigned *)addr)[i])
|
||||
kdebug ("\n")
|
||||
#else
|
||||
kdebug (last ? '\n' : ';')
|
||||
kdebug (last ? "\n" : "; ")
|
||||
#endif
|
||||
|
||||
static void panic_message (unsigned n, const char *line, char const *name, char const *message):
|
||||
@ -118,11 +118,11 @@ static void panic_message (unsigned n, const char *line, char const *name, char
|
||||
kdebug (':')
|
||||
kdebug_num (dbg_code.l)
|
||||
kdebug ('\n')
|
||||
kdebug ("debug buffer:")
|
||||
kdebug ("debug buffer (most recently pushed at end):")
|
||||
unsigned b = dbg_buffer_head
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
kdebug ('\n')
|
||||
for unsigned j = 0; j < 2; ++j:
|
||||
for unsigned j = 0; j < 4; ++j:
|
||||
kdebug (' ')
|
||||
kdebug_num (dbg_buffer[b])
|
||||
++b
|
||||
|
81
plan
81
plan
@ -42,3 +42,84 @@ te doen:
|
||||
- start programma van filesystem
|
||||
- nand driver
|
||||
- filesystems met backing store
|
||||
|
||||
Boot process:
|
||||
- bootinit and filesystem (and backing store) are started.
|
||||
- bootinit starts run.elf and loads init.elf.
|
||||
- run starts init.
|
||||
- init loads init.config and executes it.
|
||||
- during that process, the initial programs are killed.
|
||||
|
||||
Order:
|
||||
run.elf
|
||||
init.elf
|
||||
init.config
|
||||
load.elf
|
||||
drivers
|
||||
emulations
|
||||
programs
|
||||
|
||||
init.config is a script:
|
||||
|
||||
# load <name> = <filename> load a file into memory. Don't use this after killbootthreads.
|
||||
load session = session.config
|
||||
load driver_lcd = lcd.elf
|
||||
load driver_buzzer = buzzer.elf
|
||||
load driver_gpio = gpio.elf
|
||||
load driver_audio = audio.elf
|
||||
load driver_udc = udc.elf
|
||||
load driver_nand = nand.elf
|
||||
|
||||
load emu_lcd = emu_display.elf
|
||||
load emu_buzzer = emu_buzzer.elf
|
||||
load emu_keyboard = emu_keyboard.elf
|
||||
load emu_audio = emu_audio.elf
|
||||
load emu_udc = emu_udc.elf
|
||||
|
||||
# killbootthreads destroy bootinit, bootfs and bootstore.
|
||||
killbootthreads
|
||||
|
||||
# receive <cap> = <name> (<type> [, <index>]) prepare to accept a capability from a named program.
|
||||
receive display = driver_lcd (display)
|
||||
receive display_bright = driver_lcd (setting)
|
||||
receive buzzer = driver_buzzer (buzzer)
|
||||
receive keyboard = driver_gpio (keyboard, 0)
|
||||
receive sysreq = driver_gpio (keyboard, 1)
|
||||
receive audio = driver_audio (audio)
|
||||
receive udc = driver_udc (udc)
|
||||
receive nand = driver_nand (wstring)
|
||||
|
||||
# driver <name> run a previously loaded program priviledged.
|
||||
driver driver_lcd
|
||||
driver driver_buzzer
|
||||
driver driver_gpio
|
||||
driver driver_audio
|
||||
driver driver_udc
|
||||
driver driver_nand
|
||||
|
||||
# wait wait until all expected capabilities are received.
|
||||
wait
|
||||
|
||||
# sysreq <cap> use a capability as the system request keyboard.
|
||||
sysreq sysreq
|
||||
|
||||
# give <name> (<type> [, <index>]) = <cap> give this capability to this program when it requests it.
|
||||
give emu_display (display) = display
|
||||
give emu_display_bright (setting) = display_bright
|
||||
give emu_buzzer (buzzer) = buzzer
|
||||
give emu_keyboard (keyboard, 0) = keyboard
|
||||
give emu_audio (audio) = audio
|
||||
give emu_udc (udc) = udc
|
||||
|
||||
# run <name> run a previously loaded program (normally).
|
||||
run emu_lcd
|
||||
run emu_buzzer
|
||||
run emu_keyboard
|
||||
run emu_audio
|
||||
run emu_udc
|
||||
|
||||
# include <name> include a loaded file as another config file.
|
||||
include session
|
||||
|
||||
# loop sit and do nothing (respond to system request).
|
||||
loop
|
||||
|
16
schedule.ccp
16
schedule.ccp
@ -36,24 +36,24 @@ static void unrun_thread (kThread *thread):
|
||||
thread->schedule_next->schedule_prev = thread->schedule_prev
|
||||
|
||||
void kThread::run ():
|
||||
if flags & Kernel::Thread::RUNNING:
|
||||
if flags & Iris::Thread::RUNNING:
|
||||
return
|
||||
flags |= Kernel::Thread::RUNNING
|
||||
flags |= Iris::Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
run_thread (this)
|
||||
|
||||
void kThread::unrun ():
|
||||
if !(flags & Kernel::Thread::RUNNING):
|
||||
if !(flags & Iris::Thread::RUNNING):
|
||||
return
|
||||
flags &= ~Kernel::Thread::RUNNING
|
||||
flags &= ~Iris::Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
unrun_thread (this)
|
||||
|
||||
void kThread::unwait ():
|
||||
flags &= ~Kernel::Thread::WAITING
|
||||
if flags & Kernel::Thread::RUNNING:
|
||||
flags &= ~Iris::Thread::WAITING
|
||||
if flags & Iris::Thread::RUNNING:
|
||||
run_thread (this)
|
||||
|
||||
static void alarm_tick (kReceiver *recv):
|
||||
@ -73,9 +73,9 @@ static void alarm_tick (kReceiver *recv):
|
||||
--recv->alarm_count
|
||||
|
||||
void kThread::wait ():
|
||||
if flags & Kernel::Thread::RUNNING:
|
||||
if flags & Iris::Thread::RUNNING:
|
||||
unrun_thread (this)
|
||||
flags |= Kernel::Thread::WAITING
|
||||
flags |= Iris::Thread::WAITING
|
||||
// Try to receive a message from a kReceiver immediately.
|
||||
for kReceiver *r = receivers; r; r = r->next_owned:
|
||||
if r->try_deliver ():
|
||||
|
@ -33,16 +33,16 @@ void ball (int x, int y, unsigned colour):
|
||||
continue
|
||||
framebuffer[ty * 320 + tx] = (colour)
|
||||
|
||||
Kernel::Num start ():
|
||||
Kernel::my_parent.init_done ()
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
int colour = 0x3f30ff
|
||||
framebuffer = (unsigned *)0x15000
|
||||
Display display = Kernel::my_parent.get_device <Display> (0x10000)
|
||||
Iris::Display display = Iris::my_parent.get_device <Iris::Display> (0x10000)
|
||||
int x = r, y = r, dx = 3, dy = 0
|
||||
Kernel::Cap eof = Kernel::my_receiver.create_capability (0)
|
||||
Iris::Cap eof = Iris::my_receiver.create_capability (0)
|
||||
while true:
|
||||
display.set_eof_cb (eof)
|
||||
Kernel::wait ()
|
||||
Iris::wait ()
|
||||
ball (x, y, 0)
|
||||
x += dx
|
||||
y += dy
|
||||
|
@ -32,16 +32,16 @@ void square (int x, int y, bool print):
|
||||
continue
|
||||
framebuffer[ty * 320 + tx] = (print ? colour : 0)
|
||||
|
||||
Kernel::Num start ():
|
||||
Kernel::my_parent.init_done ()
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
colour = 0xffff00
|
||||
framebuffer = (unsigned *)0x15000
|
||||
Display display = Kernel::my_parent.get_device <Display> (0x10001)
|
||||
Iris::Display display = Iris::my_parent.get_device <Iris::Display> (0x10001)
|
||||
int x = r, y = r, dx = 3, dy = 3
|
||||
Kernel::Cap eof = Kernel::my_receiver.create_capability (0)
|
||||
Iris::Cap eof = Iris::my_receiver.create_capability (0)
|
||||
while true:
|
||||
display.set_eof_cb (eof)
|
||||
Kernel::wait ()
|
||||
Iris::wait ()
|
||||
square (x, y, false)
|
||||
x += dx
|
||||
y += dy
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
class DevBuzzer:
|
||||
static unsigned const pwm = 4
|
||||
Kernel::Cap event
|
||||
Iris::Cap event
|
||||
bool is_beeping
|
||||
public:
|
||||
DevBuzzer ():
|
||||
@ -36,9 +36,9 @@ class DevBuzzer:
|
||||
return
|
||||
tcu_stop_counter (pwm)
|
||||
event.invoke ()
|
||||
Kernel::free_cap (event)
|
||||
Iris::free_cap (event)
|
||||
is_beeping = false
|
||||
void beep (unsigned freq, unsigned ms, Kernel::Cap cb):
|
||||
void beep (unsigned freq, unsigned ms, Iris::Cap cb):
|
||||
stop ()
|
||||
event = cb
|
||||
unsigned full = JZ_EXTAL / 64 / freq
|
||||
@ -46,37 +46,37 @@ class DevBuzzer:
|
||||
tcu_set_half_data (pwm, full / 2)
|
||||
tcu_set_count (pwm, 0)
|
||||
tcu_start_counter (pwm)
|
||||
Kernel::my_receiver.set_alarm (ms * HZ / 1000)
|
||||
Iris::my_receiver.set_alarm (ms * HZ / 1000)
|
||||
is_beeping = true
|
||||
|
||||
enum codes:
|
||||
BUZZER = 32
|
||||
|
||||
Kernel::Num start ():
|
||||
Iris::Num start ():
|
||||
map_tcu ()
|
||||
|
||||
DevBuzzer buzzer
|
||||
|
||||
Device dev = Kernel::my_receiver.create_capability (BUZZER)
|
||||
Kernel::my_parent.provide_device <Buzzer> (dev.copy ())
|
||||
Kernel::free_cap (dev)
|
||||
Kernel::my_parent.init_done ()
|
||||
Iris::Device dev = Iris::my_receiver.create_capability (BUZZER)
|
||||
Iris::my_parent.provide_device <Iris::Buzzer> (dev.copy ())
|
||||
Iris::free_cap (dev)
|
||||
Iris::my_parent.init_done ()
|
||||
unsigned user (~0)
|
||||
unsigned next_user (0)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.h:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
buzzer.stop ()
|
||||
break
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
switch Iris::recv.protected_data.l:
|
||||
case BUZZER:
|
||||
// Buzzer device control request.
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Device::host (BUZZER, user, reply, arg)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Device::host (BUZZER, user, reply, arg)
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid buzzer request\n")
|
||||
@ -84,22 +84,22 @@ Kernel::Num start ():
|
||||
break
|
||||
case BUZZER:
|
||||
// Buzzer device user request.
|
||||
if Kernel::recv.protected_data.l != user:
|
||||
if Iris::recv.protected_data.l != user:
|
||||
kdebug ("invalid user requesting buzzer\n")
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Buzzer::BEEP:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Buzzer::BEEP:
|
||||
// Volume is not used by this buzzer.
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
buzzer.beep (Kernel::recv.data[1].l, Kernel::recv.data[1].h, arg)
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
buzzer.beep (Iris::recv.data[1].l, Iris::recv.data[1].h, arg)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Buzzer::STOP:
|
||||
case Iris::Buzzer::STOP:
|
||||
buzzer.stop ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("Buzzer: other\n")
|
||||
@ -107,5 +107,5 @@ Kernel::Num start ():
|
||||
break
|
||||
default:
|
||||
kdebug ("Buzzer: unknown num: ")
|
||||
kdebug_num (Kernel::recv.protected_data.h)
|
||||
kdebug_num (Iris::recv.protected_data.h)
|
||||
kdebug ("\n")
|
@ -29,7 +29,9 @@ static unsigned __slots, __caps
|
||||
static list *__slot_admin, *__cap_admin
|
||||
static list *__first_free_slot, *__first_free_cap
|
||||
|
||||
namespace Kernel:
|
||||
namespace Iris:
|
||||
bool enable_debug
|
||||
Caps my_caps
|
||||
Receiver my_receiver
|
||||
Thread my_thread
|
||||
Memory my_memory
|
||||
@ -44,6 +46,8 @@ namespace Kernel:
|
||||
used[i] = true
|
||||
unsigned num = 0
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
if used[i - __cap_admin] == false:
|
||||
panic (0, "inconsistent userspace cap db")
|
||||
used[i - __cap_admin] = false
|
||||
++num
|
||||
kdebug_num (num, 2)
|
||||
@ -54,6 +58,9 @@ namespace Kernel:
|
||||
|
||||
void free_slot (unsigned slot):
|
||||
//kdebug ("free slot\n")
|
||||
for list *i = __first_free_slot; i; i = i->next:
|
||||
if slot == i - __slot_admin:
|
||||
panic (0, "double free of userspace slot")
|
||||
__slot_admin[slot].prev = NULL
|
||||
__slot_admin[slot].next = __first_free_slot
|
||||
if __slot_admin[slot].next:
|
||||
@ -61,12 +68,16 @@ namespace Kernel:
|
||||
__first_free_slot = &__slot_admin[slot]
|
||||
|
||||
void free_cap (Cap cap):
|
||||
//kdebug ("free cap ")
|
||||
//kdebug_num (cap.idx (), 2)
|
||||
//kdebug ("\n")
|
||||
if enable_debug:
|
||||
kdebug ("free cap ")
|
||||
kdebug_num (cap.idx (), 2)
|
||||
kdebug ("\n")
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
if cap.idx () == i - __cap_admin:
|
||||
panic (0, "double free of userspace cap")
|
||||
if cap.slot () != 0:
|
||||
kdebug ("trying to free capability from non-0 slot\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
return
|
||||
list *l = &__cap_admin[cap.idx ()]
|
||||
l->prev = NULL
|
||||
@ -80,7 +91,7 @@ namespace Kernel:
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
return ~0
|
||||
list *ret = __first_free_slot
|
||||
__first_free_slot = ret->next
|
||||
@ -89,42 +100,45 @@ namespace Kernel:
|
||||
return ret - __slot_admin
|
||||
|
||||
Cap alloc_cap ():
|
||||
//kdebug ("alloc cap ")
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
Kernel::panic (0)
|
||||
Iris::panic (0)
|
||||
return Cap (0, CAP_NONE)
|
||||
list *ret = __first_free_cap
|
||||
__first_free_cap = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
//kdebug_num (ret - __cap_admin, 2)
|
||||
//kdebug ("\n")
|
||||
if enable_debug:
|
||||
kdebug ("alloc cap ")
|
||||
kdebug_num (ret - __cap_admin, 2)
|
||||
kdebug ("\n")
|
||||
return Cap (0, ret - __cap_admin)
|
||||
|
||||
extern "C":
|
||||
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
Iris::enable_debug = false
|
||||
__slots = slots
|
||||
__caps = caps
|
||||
__slot_admin = slot_admin
|
||||
__cap_admin = cap_admin
|
||||
__first_free_slot = NULL
|
||||
for unsigned i = 1; i < __slots; ++i:
|
||||
Kernel::free_slot (i)
|
||||
Iris::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)
|
||||
for unsigned i = 6; i < __caps; ++i:
|
||||
Iris::free_cap (Iris::Cap (0, i))
|
||||
Iris::my_caps = Iris::Cap (0, __caps_num)
|
||||
Iris::my_receiver = Iris::Cap (0, __receiver_num)
|
||||
Iris::my_thread = Iris::Cap (0, __thread_num)
|
||||
Iris::my_memory = Iris::Cap (0, __memory_num)
|
||||
Iris::my_call = Iris::Cap (0, __call_num)
|
||||
Iris::my_parent = Iris::Cap (0, __parent_num)
|
||||
Iris::recv.reply = Iris::alloc_cap ()
|
||||
Iris::recv.arg = Iris::alloc_cap ()
|
||||
Iris::Num ret = start ()
|
||||
Iris::my_parent.invoke (~0, ret)
|
||||
Iris::my_memory.destroy (Iris::my_thread)
|
||||
// The program no longer exists. If it somehow does, generate an address fault.
|
||||
while true:
|
||||
*(volatile unsigned *)~0
|
||||
|
@ -19,64 +19,64 @@
|
||||
#include <devices.hh>
|
||||
#include <iris.hh>
|
||||
|
||||
Kernel::Num start ():
|
||||
Device d = Kernel::my_receiver.create_capability (0)
|
||||
Kernel::my_parent.provide_device <Display> (d.copy (), 0x10000)
|
||||
Kernel::free_cap (d)
|
||||
Kernel::my_parent.init_done ()
|
||||
Display real = Kernel::my_parent.get_device <Display> (0)
|
||||
Iris::Num start ():
|
||||
Iris::Device d = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_device <Iris::Display> (d.copy (), 0x10000)
|
||||
Iris::free_cap (d)
|
||||
Iris::my_parent.init_done ()
|
||||
Iris::Display real = Iris::my_parent.get_device <Iris::Display> (0)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
Iris::wait ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
switch Iris::recv.protected_data.h:
|
||||
case 0:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
Kernel::Memory mem (arg)
|
||||
Kernel::Caps ret = mem.create_caps (3)
|
||||
Kernel::Cap target = Kernel::my_receiver.create_capability (Kernel::Num (0, 1))
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::CREATE_USER:
|
||||
Iris::Memory mem (arg)
|
||||
Iris::Caps ret = mem.create_caps (3)
|
||||
Iris::Cap target = Iris::my_receiver.create_capability (Iris::Num (0, 1))
|
||||
ret.set (0, target.copy ())
|
||||
ret.set (1, mem)
|
||||
Kernel::free_cap (target)
|
||||
Iris::free_cap (target)
|
||||
for unsigned i = 0; i < 320 * 240 * 4; i += PAGE_SIZE:
|
||||
Kernel::Page p = Kernel::my_memory.mapping ((void *)(0x15000 + i))
|
||||
Kernel::Page t = mem.create_page ()
|
||||
t.set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
|
||||
p.share (t, Kernel::Page::FORGET)
|
||||
Iris::Page p = Iris::my_memory.mapping ((void *)(0x15000 + i))
|
||||
Iris::Page t = mem.create_page ()
|
||||
t.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
|
||||
p.share (t, Iris::Page::FORGET)
|
||||
mem.map (t, 0x15000 + i)
|
||||
Kernel::my_memory.destroy (t)
|
||||
Kernel::free_cap (t)
|
||||
Kernel::free_cap (p)
|
||||
Iris::my_memory.destroy (t)
|
||||
Iris::free_cap (t)
|
||||
Iris::free_cap (p)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
Kernel::free_cap (ret)
|
||||
Iris::free_cap (ret)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
Kernel::panic (0, "destroying emulation user")
|
||||
case Device::USE:
|
||||
case Device::UNUSE:
|
||||
case Iris::Device::DESTROY_USER:
|
||||
Iris::panic (0, "destroying emulation user")
|
||||
case Iris::Device::USE:
|
||||
case Iris::Device::UNUSE:
|
||||
reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug_num (Kernel::recv.data[0].l)
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
Kernel::panic (0, "invalid emulation command")
|
||||
Iris::panic (0, "invalid emulation command")
|
||||
break
|
||||
case 1:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Display::SET_EOF_CB:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Display::SET_EOF_CB:
|
||||
real.set_eof_cb (arg.copy ())
|
||||
while Kernel::recv.data[0].l != 0:
|
||||
Kernel::my_parent.wait <Display> (0)
|
||||
while Iris::recv.data[0].l != 0:
|
||||
Iris::my_parent.wait <Iris::Display> (0)
|
||||
real.set_eof_cb (arg.copy ())
|
||||
reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug_num (Kernel::recv.data[0].l)
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug_char ('\n')
|
||||
Kernel::panic (Kernel::recv.data[0].l, "invalid operation on display emulation")
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid operation on display emulation")
|
||||
break
|
||||
default:
|
||||
Kernel::panic (0, "bug in display emulation")
|
||||
Kernel::free_cap (arg)
|
||||
Kernel::free_cap (reply)
|
||||
Iris::panic (0, "bug in display emulation")
|
||||
Iris::free_cap (arg)
|
||||
Iris::free_cap (reply)
|
||||
|
@ -1 +0,0 @@
|
||||
display-emu.ccp
|
286
source/elfrun.ccp
Normal file
286
source/elfrun.ccp
Normal file
@ -0,0 +1,286 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/elfrun.ccp: Process creation server.
|
||||
// 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"
|
||||
#include <elf.h>
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
static Iris::Memory parent_memory
|
||||
static Iris::Cap parent
|
||||
static unsigned slot
|
||||
static char *mapping
|
||||
static unsigned pages
|
||||
static Iris::Caps pages_caps
|
||||
static Iris::Memory mem
|
||||
|
||||
static Iris::Caps map_string (Iris::String data):
|
||||
// Get the size.
|
||||
Iris::Num size = data.get_size ()
|
||||
if size.value () == 0:
|
||||
Iris::panic (0, "data string is empty")
|
||||
// Allocate a caps with all the pages.
|
||||
pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
pages_caps = Iris::my_memory.create_caps (pages)
|
||||
slot = pages_caps.use ()
|
||||
// Map them into the address space as well.
|
||||
mapping = alloc_space (pages)
|
||||
// Create a memory for the program.
|
||||
mem = parent_memory.create_memory ()
|
||||
// Load the file into memory and map it.
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (pages)
|
||||
//kdebug ("\n")
|
||||
Iris::set_recv_arg (Iris::Cap (slot, p))
|
||||
data.get_page (p << PAGE_BITS)
|
||||
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
|
||||
static Iris::Caps map_caps (Iris::Caps data, unsigned p):
|
||||
// Get the size.
|
||||
if p == 0:
|
||||
Iris::panic (0, "data caps is empty")
|
||||
// Allocate a new caps with all the pages for mapping locally.
|
||||
pages = p
|
||||
pages_caps = Iris::my_memory.create_caps (pages)
|
||||
slot = pages_caps.use ()
|
||||
unsigned src_slot = data.use ()
|
||||
// Map them into the address space as well.
|
||||
mapping = alloc_space (pages)
|
||||
// Create a memory for the program.
|
||||
mem = parent_memory.create_memory ()
|
||||
// Load the file into memory and map it.
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (pages)
|
||||
//kdebug ("\n")
|
||||
Iris::Page page = Iris::Cap (slot, p)
|
||||
Iris::set_recv_arg (page)
|
||||
Iris::my_memory.create_page ()
|
||||
Iris::Page (Iris::Cap (src_slot, p)).share (page)
|
||||
Iris::my_memory.map (page, (unsigned)&mapping[p << PAGE_BITS])
|
||||
Iris::free_slot (src_slot)
|
||||
|
||||
static Iris::Caps run (Iris::Caps data, Iris::Memory parent_memory, Iris::Cap parent, unsigned num_slots, unsigned num_caps):
|
||||
Iris::Thread thread = mem.create_thread (num_slots)
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
if header->e_ident[j] != ELFMAG[j]:
|
||||
Iris::panic (header->e_ident[j], "invalid ELF magic")
|
||||
return Iris::Caps ()
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class:")
|
||||
kdebug_num (header->e_ident[EI_CLASS])
|
||||
kdebug (" != ")
|
||||
kdebug_num (ELFCLASS32)
|
||||
kdebug ("\n")
|
||||
Iris::panic (0)
|
||||
return Iris::Caps ()
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
|
||||
if header->e_type != ET_EXEC:
|
||||
Iris::panic (header->e_type, "invalid ELF type")
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
Iris::panic (header->e_machine, "invalid ELF machine")
|
||||
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 size: ")
|
||||
kdebug_num (file_offset)
|
||||
kdebug (",")
|
||||
kdebug_num (shdr->sh_size)
|
||||
kdebug ("\n")
|
||||
Iris::panic (shdr->sh_size, "thread too large")
|
||||
return Iris::Caps ()
|
||||
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
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Iris::free_cap (page)
|
||||
continue
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
unsigned f
|
||||
if readonly:
|
||||
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
|
||||
else:
|
||||
f = Iris::Page::PAYING
|
||||
page.set_flags (f, f)
|
||||
Iris::Page (slot, idx).share (page, 0)
|
||||
//kdebug ("mapping at ")
|
||||
//kdebug_num (p)
|
||||
//if readonly:
|
||||
// kdebug (" (readonly)")
|
||||
//kdebug ("\n")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map page")
|
||||
return Iris::Caps ()
|
||||
Iris::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
Iris::panic (0, "unwritable bss section")
|
||||
return Iris::Caps ()
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// No error means there is a mapping.
|
||||
Iris::free_cap (page)
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
if a >= shdr->sh_addr + shdr->sh_size:
|
||||
break
|
||||
if a < shdr->sh_addr:
|
||||
continue
|
||||
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
|
||||
else:
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR:
|
||||
Iris::panic (Iris::recv.data[0].l, "out of memory")
|
||||
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
|
||||
Iris::panic (0, "out of memory")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map bss page")
|
||||
Iris::free_cap (page)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Page (slot, p))
|
||||
Iris::my_memory.destroy (pages_caps)
|
||||
Iris::free_slot (slot)
|
||||
Iris::free_cap (pages_caps)
|
||||
Iris::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
|
||||
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
|
||||
Iris::free_cap (stackpage)
|
||||
Iris::Caps caps = mem.create_caps (num_caps)
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Iris::Thread::A0, num_slots)
|
||||
thread.set_info (Iris::Thread::A1, num_caps)
|
||||
Iris::Receiver receiver = mem.create_receiver ()
|
||||
receiver.set_owner (thread.copy ())
|
||||
Iris::Cap call = receiver.create_call_capability ()
|
||||
caps.set (__caps_num, caps.copy ())
|
||||
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 ())
|
||||
Iris::free_cap (receiver)
|
||||
Iris::free_cap (thread)
|
||||
Iris::free_cap (mem)
|
||||
Iris::free_cap (call)
|
||||
return caps
|
||||
|
||||
Iris::Num start ():
|
||||
kdebug ("elfrun started.\n")
|
||||
init_alloc ()
|
||||
Iris::Device dev = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_device <Iris::Elfrun> (dev.copy ())
|
||||
|
||||
unsigned user = ~0
|
||||
while true:
|
||||
Iris::wait ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::print_caps ()
|
||||
switch Iris::recv.protected_data.h:
|
||||
case 0:
|
||||
Iris::Device::host (1, user, reply, arg)
|
||||
break
|
||||
case 1:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Elfrun::RUN_STRING:
|
||||
unsigned num_slots = Iris::recv.data[1].l
|
||||
unsigned num_caps = Iris::recv.data[1].h
|
||||
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
|
||||
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
|
||||
Iris::String data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
|
||||
map_string (data)
|
||||
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
free_cap (ret)
|
||||
free_cap (parent_memory)
|
||||
free_cap (parent)
|
||||
free_cap (data)
|
||||
break
|
||||
case Iris::Elfrun::RUN_CAPS:
|
||||
unsigned num_slots = Iris::recv.data[1].l
|
||||
unsigned num_caps = Iris::recv.data[1].h
|
||||
unsigned p = Iris::recv.data[0].h
|
||||
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
|
||||
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
|
||||
Iris::Caps data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
|
||||
map_caps (data, p)
|
||||
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
free_cap (ret)
|
||||
free_cap (parent_memory)
|
||||
free_cap (parent)
|
||||
free_cap (data)
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "invalid operation for elfrun")
|
||||
reply.invoke (~0)
|
||||
break
|
||||
Iris::free_cap (arg)
|
||||
Iris::free_cap (reply)
|
1
source/gpio.ccp
Symbolic link
1
source/gpio.ccp
Symbolic link
@ -0,0 +1 @@
|
||||
nanonote-gpio.ccp
|
412
source/init.ccp
Normal file
412
source/init.ccp
Normal file
@ -0,0 +1,412 @@
|
||||
#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"
|
||||
#include "keys.hh"
|
||||
|
||||
#define NUM_SLOTS 8
|
||||
#define NUM_CAPS 32
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
template <typename _T> //
|
||||
struct List:
|
||||
struct Item:
|
||||
Item *prev, *next
|
||||
_T value
|
||||
_T &operator* ():
|
||||
return value
|
||||
_T *operator-> ():
|
||||
return &value
|
||||
Item *first
|
||||
Item *begin ():
|
||||
return first
|
||||
void erase (Item *i):
|
||||
if i->prev:
|
||||
i->prev->next = i->next
|
||||
else:
|
||||
first = i->next
|
||||
if i->next:
|
||||
i->next->prev = i->prev
|
||||
delete i
|
||||
Item *insert (Item *after = NULL):
|
||||
Item *ret = new Item
|
||||
if after:
|
||||
ret->prev = after->prev
|
||||
ret->next = after
|
||||
if ret->prev:
|
||||
ret->prev->next = ret
|
||||
else:
|
||||
first = ret
|
||||
after->prev = ret
|
||||
else:
|
||||
ret->prev = NULL
|
||||
ret->next = first
|
||||
first = ret
|
||||
if ret->next:
|
||||
ret->next->prev = ret
|
||||
return ret
|
||||
void init ():
|
||||
first = NULL
|
||||
List () : first (NULL):
|
||||
|
||||
struct Program
|
||||
|
||||
struct Device:
|
||||
char *name
|
||||
unsigned name_len
|
||||
unsigned type, index
|
||||
Iris::Cap cap
|
||||
Program *server
|
||||
Program *client
|
||||
|
||||
struct Program:
|
||||
char *name
|
||||
unsigned name_len
|
||||
unsigned size
|
||||
Iris::Caps pages
|
||||
Iris::Memory memory
|
||||
Iris::Thread thread
|
||||
List <Device> devices
|
||||
|
||||
static Iris::Memory top_memory
|
||||
static Iris::Directory root
|
||||
static Iris::Elfrun elfrun
|
||||
static List <Program> programs
|
||||
|
||||
static bool name_match (char const *name, unsigned name_len, Iris::String n):
|
||||
char nm[16]
|
||||
n.get_chars (0, nm)
|
||||
for unsigned t = 0; t < 16 && t < name_len; ++t:
|
||||
if nm[t] != name[t]:
|
||||
return false
|
||||
return true
|
||||
|
||||
static Iris::Caps load (char const *name, unsigned name_len, unsigned &size, Iris::Caps target = Iris::alloc_cap ()):
|
||||
kdebug ("loading ")
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
kdebug_char (name[i])
|
||||
kdebug ("\n")
|
||||
root.lock_ro ()
|
||||
Iris::Num sz = root.get_size ()
|
||||
if sz.h:
|
||||
Iris::panic (sz.h, "too many files")
|
||||
for unsigned i = 0; i < sz.l; ++i:
|
||||
Iris::String n = root.get_name (i)
|
||||
if !name_match (name, name_len, n):
|
||||
Iris::free_cap (n)
|
||||
continue
|
||||
Iris::free_cap (n)
|
||||
Iris::String file = root.get_file_ro (i)
|
||||
Iris::Num s = file.get_size ()
|
||||
if s.h:
|
||||
Iris::panic (s.h, "file is too large to load")
|
||||
size = s.l
|
||||
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
if pages > 0:
|
||||
Iris::set_recv_arg (target)
|
||||
Iris::my_memory.create_caps (pages)
|
||||
unsigned slot = target.use ()
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::set_recv_arg (Iris::Cap (slot, p))
|
||||
file.get_page (p << PAGE_BITS)
|
||||
Iris::free_slot (slot)
|
||||
Iris::free_cap (file)
|
||||
root.unlock_ro ()
|
||||
return target
|
||||
Iris::panic (0, "file not found for init")
|
||||
return target
|
||||
|
||||
static void delspace (char *&line, unsigned &maxlen):
|
||||
while maxlen && (*line == ' ' || *line == '\t'):
|
||||
++line
|
||||
--maxlen
|
||||
if maxlen && *line == '#':
|
||||
line += maxlen
|
||||
maxlen = 0
|
||||
|
||||
static bool match (char *&line, unsigned &maxlen, char const *word):
|
||||
delspace (line, maxlen)
|
||||
char const *w = word
|
||||
char *l = line
|
||||
unsigned len = 0
|
||||
while *word:
|
||||
if *l++ != *word++:
|
||||
return false
|
||||
++len
|
||||
line = l
|
||||
maxlen -= len
|
||||
delspace (line, maxlen)
|
||||
//kdebug ("match: ")
|
||||
//kdebug (w)
|
||||
//kdebug ("\n")
|
||||
return true
|
||||
|
||||
static bool isnamechar (char c):
|
||||
if c >= 'a' && c <= 'z':
|
||||
return true
|
||||
if c >= 'A' && c <= 'Z':
|
||||
return true
|
||||
if c >= '0' && c <= '9':
|
||||
return true
|
||||
if c == '_':
|
||||
return true
|
||||
return false
|
||||
|
||||
static bool get_name (char *&line, unsigned &len, char *&name, unsigned &name_len):
|
||||
delspace (line, len)
|
||||
if !len:
|
||||
return false
|
||||
name_len = 0
|
||||
while name_len < len && isnamechar (line[name_len]):
|
||||
++name_len
|
||||
name = new char[name_len]
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
name[i] = line[i]
|
||||
line += name_len
|
||||
len -= name_len
|
||||
delspace (line, len)
|
||||
return true
|
||||
|
||||
static bool string_match (char const *s1, unsigned l1, char const *s2, unsigned l2):
|
||||
if l1 != l2:
|
||||
return false
|
||||
for unsigned i = 0; i < l1; ++i:
|
||||
if s1[i] != s2[i]:
|
||||
return false
|
||||
return true
|
||||
|
||||
struct Type:
|
||||
char const *name
|
||||
unsigned len
|
||||
unsigned type
|
||||
|
||||
static unsigned read_num (char *&line, unsigned &len):
|
||||
delspace (line, len)
|
||||
unsigned num = 0
|
||||
while len && *line >= '0' && *line <= '9':
|
||||
num *= 10
|
||||
num += *line - '0'
|
||||
++line
|
||||
--len
|
||||
delspace (line, len)
|
||||
return num
|
||||
|
||||
static Type types[] = {
|
||||
{ "String", 6, Iris::String::ID },
|
||||
{ "WString", 7, Iris::WString::ID },
|
||||
{ "Device", 6, Iris::Device::ID },
|
||||
{ "Parent", 6, Iris::Parent::ID },
|
||||
{ "Keyboard", 8, Iris::Keyboard::ID },
|
||||
{ "Buzzer", 6, Iris::Buzzer::ID },
|
||||
{ "Display", 7, Iris::Display::ID },
|
||||
{ "Setting", 7, Iris::Setting::ID },
|
||||
{ "Directory", 9, Iris::Directory::ID },
|
||||
{ "WDirectory", 10, Iris::WDirectory::ID },
|
||||
{ "Filesystem", 10, Iris::Filesystem::ID },
|
||||
{ "Stream", 6, Iris::Stream::ID },
|
||||
{ NULL, 0, 0 }
|
||||
}
|
||||
|
||||
static void find_type (char *&line, unsigned &len, unsigned &type, unsigned &index):
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (line, len, n, l) || !len:
|
||||
Iris::panic (0, "no name for type")
|
||||
for unsigned t = 0; types[t].len != 0; ++t:
|
||||
if string_match (types[t].name, types[t].len, n, l):
|
||||
type = types[t].type
|
||||
if len && *line == ',':
|
||||
++line
|
||||
--len
|
||||
index = read_num (line, len)
|
||||
else:
|
||||
index = 0
|
||||
return
|
||||
Iris::panic (0, "no valid type found")
|
||||
|
||||
static void parse_line (char *&line, unsigned maxlen):
|
||||
char *start = line
|
||||
while maxlen && *line != '\n':
|
||||
++line
|
||||
--maxlen
|
||||
// The line to execute is from start to line.
|
||||
maxlen = line - start
|
||||
if *line == '\n':
|
||||
++line
|
||||
delspace (start, maxlen)
|
||||
if !maxlen:
|
||||
return
|
||||
if match (start, maxlen, "load"):
|
||||
Program *p = &**programs.insert ()
|
||||
if !get_name (start, maxlen, p->name, p->name_len) || !match (start, maxlen, "=") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (load)")
|
||||
char q = *start++
|
||||
--maxlen
|
||||
unsigned len = 0
|
||||
while maxlen && *start != q:
|
||||
++start
|
||||
--maxlen
|
||||
++len
|
||||
if !maxlen:
|
||||
Iris::panic (0, "no closing quote in init.config")
|
||||
p->pages = load (start - len, len, p->size)
|
||||
++start
|
||||
--maxlen
|
||||
else if match (start, maxlen, "killbootthreads"):
|
||||
Iris::my_parent.init_done ()
|
||||
else if match (start, maxlen, "receive"):
|
||||
// receive <name> / <type> [, <index>] = <cap>
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (receive)")
|
||||
List <Program>::Item *p
|
||||
for p = programs.begin (); p; p = p->next:
|
||||
if string_match ((*p)->name, (*p)->name_len, n, l):
|
||||
break
|
||||
if !p:
|
||||
Iris::panic (0, "program not found for receive")
|
||||
List <Device>::Item *dev = (*p)->devices.insert ()
|
||||
find_type (start, maxlen, (*dev)->type, (*dev)->index)
|
||||
if !match (start, maxlen, "=") || !get_name (start, maxlen, (*dev)->name, (*dev)->name_len):
|
||||
Iris::panic (1, "syntax error in init.config (receive)")
|
||||
else if match (start, maxlen, "driver"):
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (start, maxlen, n, l):
|
||||
Iris::panic (0, "syntax error in init.config (driver)")
|
||||
List <Program>::Item *p
|
||||
for p = programs.begin (); p; p = p->next:
|
||||
if string_match ((*p)->name, (*p)->name_len, n, l):
|
||||
break
|
||||
if !p:
|
||||
Iris::panic (0, "program not found for driver")
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability ((unsigned)&**p)
|
||||
kdebug ("running ")
|
||||
for unsigned i = 0; i < (*p)->name_len; ++i:
|
||||
kdebug_char ((*p)->name[i])
|
||||
kdebug ("\n")
|
||||
Iris::Caps caps = elfrun.run_caps (top_memory, (*p)->pages, cap.copy (), ((*p)->size + PAGE_SIZE - 1) >> PAGE_BITS)
|
||||
Iris::free_cap (cap)
|
||||
(*p)->thread = caps.get (__thread_num)
|
||||
(*p)->memory = caps.get (__memory_num)
|
||||
(*p)->thread.make_priv ()
|
||||
(*p)->thread.run ()
|
||||
// TODO: pass arguments.
|
||||
start += maxlen
|
||||
maxlen = 0
|
||||
else if match (start, maxlen, "wait"):
|
||||
// TODO
|
||||
start += maxlen
|
||||
maxlen = 0
|
||||
else if match (start, maxlen, "sysreq"):
|
||||
// TODO
|
||||
start += maxlen
|
||||
maxlen = 0
|
||||
else if match (start, maxlen, "give"):
|
||||
// TODO
|
||||
start += maxlen
|
||||
maxlen = 0
|
||||
else if match (start, maxlen, "run"):
|
||||
// TODO
|
||||
start += maxlen
|
||||
maxlen = 0
|
||||
else if match (start, maxlen, "include"):
|
||||
// TODO
|
||||
start += maxlen
|
||||
maxlen = 0
|
||||
else:
|
||||
Iris::panic (0, "invalid line in init.config")
|
||||
delspace (start, maxlen)
|
||||
if maxlen:
|
||||
kdebug ("Junk: ")
|
||||
for unsigned i = 0; i < maxlen; ++i:
|
||||
kdebug_char (start[i])
|
||||
kdebug_char ('\n')
|
||||
Iris::panic (0, "junk at end of line in init.config")
|
||||
|
||||
Iris::Num start ():
|
||||
init_alloc ()
|
||||
programs.init ()
|
||||
root = Iris::my_parent.get_device <Iris::Directory> ()
|
||||
elfrun = Iris::my_parent.get_device <Iris::Elfrun> ()
|
||||
top_memory = Iris::get_top_memory ()
|
||||
unsigned config_size
|
||||
Iris::Caps config_pages = load ("init.config", 12, config_size)
|
||||
unsigned pages = (config_size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
char *config = alloc_space (pages)
|
||||
unsigned pages_slot = config_pages.use ()
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page (pages_slot, p)
|
||||
Iris::my_memory.map (page, (unsigned)&config[p << PAGE_BITS])
|
||||
char *ptr = config
|
||||
kdebug ("parsing config\n")
|
||||
while ptr - config < config_size:
|
||||
parse_line (ptr, config + config_size - ptr)
|
||||
kdebug ("destroying pages\n")
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Cap (pages_slot, p))
|
||||
Iris::my_memory.destroy (config_pages)
|
||||
Iris::free_cap (config_pages)
|
||||
Iris::free_slot (pages_slot)
|
||||
kdebug ("waiting for events.\n")
|
||||
while true:
|
||||
Iris::wait ()
|
||||
Program *caller = (Program *)Iris::recv.protected_data.l
|
||||
if !caller:
|
||||
// System request.
|
||||
// TODO.
|
||||
kdebug ("system request\n")
|
||||
continue
|
||||
switch Iris::recv.data[0].l:
|
||||
default:
|
||||
// TODO.
|
||||
kdebug ("child request\n")
|
@ -225,7 +225,7 @@ static void log_str (char const *str):
|
||||
while *str:
|
||||
log_char (*str++)
|
||||
|
||||
static void log_num (Kernel::Num n):
|
||||
static void log_num (Iris::Num n):
|
||||
char const *encode = "0123456789abcdef"
|
||||
log_char ('[')
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
@ -237,10 +237,10 @@ static void log_num (Kernel::Num n):
|
||||
|
||||
static void log_msg ():
|
||||
log_str ("prot:")
|
||||
log_num (Kernel::recv.protected_data)
|
||||
log_num (Iris::recv.protected_data)
|
||||
log_str ("data:")
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
log_num (Kernel::recv.data[i])
|
||||
log_num (Iris::recv.data[i])
|
||||
log_char ('\n')
|
||||
|
||||
enum captype:
|
||||
@ -261,25 +261,25 @@ static unsigned pages
|
||||
static Descriptor descriptor __attribute__ ((aligned (16)))
|
||||
static bool is_on
|
||||
|
||||
static unsigned create (Kernel::Memory mem, Kernel::Caps caps):
|
||||
static unsigned create (Iris::Memory mem, Iris::Caps caps):
|
||||
unsigned physical = mem.alloc_range (pages)
|
||||
unsigned address = 0x15000
|
||||
if physical & ~PAGE_MASK:
|
||||
Kernel::panic (0, "can't allocate framebuffer")
|
||||
Iris::panic (0, "can't allocate framebuffer")
|
||||
assert (physical & PAGE_MASK && ~physical)
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Kernel::Page p = mem.create_page ()
|
||||
Iris::Page p = mem.create_page ()
|
||||
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
|
||||
if address != ~0:
|
||||
mem.map (p, address + (i << PAGE_BITS))
|
||||
Kernel::free_cap (p)
|
||||
Iris::free_cap (p)
|
||||
return physical
|
||||
|
||||
static void destroy (unsigned physical, Kernel::Caps caps):
|
||||
static void destroy (unsigned physical, Iris::Caps caps):
|
||||
unsigned address = 0x15000
|
||||
Kernel::Memory mem = caps.get (1)
|
||||
Iris::Memory mem = caps.get (1)
|
||||
if physical == ~0:
|
||||
Kernel::panic (0, "unable to destroy framebuffer with wrong cap0")
|
||||
Iris::panic (0, "unable to destroy framebuffer with wrong cap0")
|
||||
if descriptor.frame == physical && is_on:
|
||||
lcd_clr_ena ()
|
||||
#ifdef NANONOTE
|
||||
@ -287,13 +287,13 @@ static void destroy (unsigned physical, Kernel::Caps caps):
|
||||
#endif
|
||||
if address != ~0:
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Kernel::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
|
||||
Iris::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
|
||||
mem.destroy (p)
|
||||
Kernel::free_cap (p)
|
||||
Iris::free_cap (p)
|
||||
|
||||
static void use (unsigned physical, Kernel::Caps caps):
|
||||
static void use (unsigned physical, Iris::Caps caps):
|
||||
if physical == ~0:
|
||||
Kernel::panic (0, "unable to use framebuffer with wrong cap0")
|
||||
Iris::panic (0, "unable to use framebuffer with wrong cap0")
|
||||
bool was_unused = descriptor.frame == 0
|
||||
descriptor.frame = physical
|
||||
unsigned dptr = (unsigned)&descriptor
|
||||
@ -304,9 +304,9 @@ static void use (unsigned physical, Kernel::Caps caps):
|
||||
write_reg (BACKLIGHT1, 0x5f)
|
||||
#endif
|
||||
|
||||
static void unuse (unsigned physical, Kernel::Caps caps):
|
||||
static void unuse (unsigned physical, Iris::Caps caps):
|
||||
if physical == ~0:
|
||||
Kernel::panic (0, "unable to unuse framebuffer with wrong cap0")
|
||||
Iris::panic (0, "unable to unuse framebuffer with wrong cap0")
|
||||
if descriptor.frame == physical:
|
||||
lcd_clr_ena ()
|
||||
#ifdef NANONOTE
|
||||
@ -314,8 +314,8 @@ static void unuse (unsigned physical, Kernel::Caps caps):
|
||||
#endif
|
||||
descriptor.frame = 0
|
||||
|
||||
Kernel::Num start ():
|
||||
Kernel::schedule ()
|
||||
Iris::Num start ():
|
||||
Iris::schedule ()
|
||||
map_lcd ()
|
||||
map_cpm ()
|
||||
#ifdef NANONOTE
|
||||
@ -324,13 +324,13 @@ Kernel::Num start ():
|
||||
|
||||
pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
|
||||
#if 0
|
||||
unsigned physical = Kernel::my_memory.alloc_range (pages)
|
||||
unsigned physical = Iris::my_memory.alloc_range (pages)
|
||||
assert (physical & PAGE_MASK && ~physical)
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Kernel::Page p = Kernel::my_memory.create_page ()
|
||||
Iris::Page p = Iris::my_memory.create_page ()
|
||||
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
|
||||
Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + (i << PAGE_BITS))
|
||||
Kernel::free_cap (p)
|
||||
Iris::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + (i << PAGE_BITS))
|
||||
Iris::free_cap (p)
|
||||
for unsigned y = 0; y < v; ++y:
|
||||
for unsigned x = 0; x < h; ++x:
|
||||
unsigned r = spot (x, y, 100, 160)
|
||||
@ -346,10 +346,10 @@ Kernel::Num start ():
|
||||
#else
|
||||
unsigned physical = 0
|
||||
#endif
|
||||
Kernel::Page p = Kernel::my_memory.mapping (&descriptor)
|
||||
Iris::Page p = Iris::my_memory.mapping (&descriptor)
|
||||
unsigned paddr = p.physical_address ()
|
||||
physical_descriptor = paddr + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
Kernel::free_cap (p)
|
||||
Iris::free_cap (p)
|
||||
descriptor.next = physical_descriptor
|
||||
descriptor.frame = physical
|
||||
descriptor.id = 0xdeadbeef
|
||||
@ -359,67 +359,67 @@ Kernel::Num start ():
|
||||
reset ()
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
|
||||
Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
#endif
|
||||
|
||||
// Register the backlight device.
|
||||
Kernel::Cap backlight = Kernel::my_receiver.create_capability (BACKLIGHT)
|
||||
Kernel::my_parent.provide_device <Setting> (backlight.copy ())
|
||||
Kernel::free_cap (backlight)
|
||||
Iris::Cap backlight = Iris::my_receiver.create_capability (BACKLIGHT)
|
||||
Iris::my_parent.provide_device <Iris::Setting> (backlight.copy ())
|
||||
Iris::free_cap (backlight)
|
||||
|
||||
// Register the display device.
|
||||
Kernel::Cap display = Kernel::my_receiver.create_capability (LCD)
|
||||
Kernel::my_parent.provide_device <Display> (display.copy ())
|
||||
Kernel::free_cap (display)
|
||||
Kernel::my_parent.init_done ()
|
||||
Iris::Cap display = Iris::my_receiver.create_capability (LCD)
|
||||
Iris::my_parent.provide_device <Iris::Display> (display.copy ())
|
||||
Iris::free_cap (display)
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
Kernel::Cap eof_cb
|
||||
Iris::Cap eof_cb
|
||||
bool have_eof = false
|
||||
is_on = true
|
||||
unsigned lcd_user = 0
|
||||
unsigned current_backlight = 0
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
Iris::wait ()
|
||||
//log_msg ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
switch Iris::recv.protected_data.h:
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
switch Iris::recv.protected_data.l:
|
||||
case IRQ_LCD:
|
||||
have_eof = false
|
||||
eof_cb.invoke ()
|
||||
Kernel::free_cap (eof_cb)
|
||||
Iris::free_cap (eof_cb)
|
||||
break
|
||||
#if defined (TRENDTAC)
|
||||
case LOG:
|
||||
log_char (Kernel::recv.data[0].l)
|
||||
log_char (Iris::recv.data[0].l)
|
||||
break
|
||||
#endif
|
||||
case BACKLIGHT:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Device::host (BACKLIGHT, current_backlight, reply, arg)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Device::host (BACKLIGHT, current_backlight, reply, arg)
|
||||
break
|
||||
case LCD:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Device::host (LCD, lcd_user, reply, arg, 3, create, destroy, use, unuse)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Device::host (LCD, lcd_user, reply, arg, 3, create, destroy, use, unuse)
|
||||
break
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.protected_data.l, "invalid operation for master lcd")
|
||||
Iris::panic (Iris::recv.protected_data.l, "invalid operation for master lcd")
|
||||
break
|
||||
break
|
||||
case BACKLIGHT:
|
||||
if current_backlight != Kernel::recv.protected_data.l:
|
||||
if current_backlight != Iris::recv.protected_data.l:
|
||||
log_char ('&')
|
||||
log_num (current_backlight)
|
||||
log_num (Kernel::recv.protected_data)
|
||||
log_num (Iris::recv.protected_data)
|
||||
log_char ('\n')
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Setting::SET:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Setting::SET:
|
||||
// TODO
|
||||
unsigned state = Kernel::recv.data[1].l
|
||||
unsigned state = Iris::recv.data[1].l
|
||||
if !state:
|
||||
#if defined (NANONOTE)
|
||||
if is_on:
|
||||
@ -434,40 +434,40 @@ Kernel::Num start ():
|
||||
is_on = true
|
||||
#else
|
||||
#endif
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Setting::GET_RANGE:
|
||||
Kernel::recv.reply.invoke (~0)
|
||||
case Iris::Setting::GET_RANGE:
|
||||
Iris::recv.reply.invoke (~0)
|
||||
break
|
||||
default:
|
||||
Kernel::panic (0, "invalid operation for backlight")
|
||||
Iris::panic (0, "invalid operation for backlight")
|
||||
break
|
||||
break
|
||||
case LCD:
|
||||
if descriptor.frame != Kernel::recv.protected_data.l:
|
||||
//Kernel::panic (0, "invalid user requesting lcd")
|
||||
Kernel::recv.reply.invoke (~0)
|
||||
if descriptor.frame != Iris::recv.protected_data.l:
|
||||
//Iris::panic (0, "invalid user requesting lcd")
|
||||
Iris::recv.reply.invoke (~0)
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Display::SET_EOF_CB:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Display::SET_EOF_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
if have_eof:
|
||||
Kernel::free_cap (eof_cb)
|
||||
Kernel::panic (0, "replacing eof_cb")
|
||||
Iris::free_cap (eof_cb)
|
||||
Iris::panic (0, "replacing eof_cb")
|
||||
else:
|
||||
lcd_clr_eof ()
|
||||
Kernel::register_interrupt (IRQ_LCD)
|
||||
Iris::register_interrupt (IRQ_LCD)
|
||||
have_eof = true
|
||||
eof_cb = arg
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Display::GET_INFO:
|
||||
Kernel::panic (0, "get_info isn't defined yet.")
|
||||
case Iris::Display::GET_INFO:
|
||||
Iris::panic (0, "get_info isn't defined yet.")
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.data[0].l, "invalid operation for lcd")
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid operation for lcd")
|
||||
break
|
||||
default:
|
||||
Kernel::panic (0, "invalid master operation type for lcd")
|
||||
Iris::panic (0, "invalid master operation type for lcd")
|
||||
break
|
@ -19,11 +19,11 @@
|
||||
#include "devices.hh"
|
||||
#include "keys.hh"
|
||||
|
||||
Kernel::Num start ():
|
||||
Kernel::my_parent.init_done ()
|
||||
Buzzer buzzer = Kernel::my_parent.get_device <Buzzer> ()
|
||||
Keyboard kbd = Kernel::my_parent.get_device <Keyboard> ()
|
||||
Kernel::Cap key = Kernel::my_receiver.create_capability (0)
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
Iris::Buzzer buzzer = Iris::my_parent.get_device <Iris::Buzzer> ()
|
||||
Iris::Keyboard kbd = Iris::my_parent.get_device <Iris::Keyboard> ()
|
||||
Iris::Cap key = Iris::my_receiver.create_capability (0)
|
||||
kbd.set_cb (key)
|
||||
// Frequency of the pulse train in millihertz.
|
||||
unsigned mHz = 1000
|
||||
@ -31,17 +31,17 @@ Kernel::Num start ():
|
||||
unsigned freq = 1000
|
||||
bool running (false)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.l:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
if running:
|
||||
buzzer.beep (freq, 10, ~0)
|
||||
Kernel::my_receiver.set_alarm (HZ * 1000 / mHz)
|
||||
Iris::my_receiver.set_alarm (HZ * 1000 / mHz)
|
||||
break
|
||||
case 0:
|
||||
if Kernel::recv.data[0].l & Keyboard::RELEASE:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Key::VOLUME_UP:
|
||||
freq = freq * 11 / 10
|
||||
break
|
||||
@ -63,7 +63,7 @@ Kernel::Num start ():
|
||||
case Key::P:
|
||||
running = !running
|
||||
if running:
|
||||
Kernel::my_receiver.set_alarm (0)
|
||||
Iris::my_receiver.set_alarm (0)
|
||||
break
|
||||
break
|
||||
default:
|
||||
|
@ -37,25 +37,25 @@ class DevKbd:
|
||||
static unsigned const NUM_KEYS = 58
|
||||
static unsigned const keys[NUM_KEYS]
|
||||
unsigned state[NUM_COLS]
|
||||
Kernel::Cap event
|
||||
Iris::Cap event
|
||||
bool is_active
|
||||
bool is_scanning
|
||||
public:
|
||||
unsigned size ():
|
||||
return NUM_KEYS
|
||||
void send_keys (unsigned first, Kernel::Cap target):
|
||||
void send_keys (unsigned first, Iris::Cap target):
|
||||
unsigned d[4]
|
||||
unsigned i
|
||||
for i = 0; first + i < NUM_KEYS && i < 4; ++i:
|
||||
d[i] = keys[first + i]
|
||||
for ; i < 4; ++i:
|
||||
d[i] = ~0
|
||||
target.invoke (Kernel::Num (d[0], d[1]), Kernel::Num (d[2], d[3]))
|
||||
target.invoke (Iris::Num (d[0], d[1]), Iris::Num (d[2], d[3]))
|
||||
bool scanning ():
|
||||
return is_scanning
|
||||
void inactive ():
|
||||
if is_active:
|
||||
Kernel::free_cap (event)
|
||||
Iris::free_cap (event)
|
||||
is_active = false
|
||||
void check (unsigned col, unsigned rowdata):
|
||||
for unsigned r = 0; r < NUM_ROWS; ++r:
|
||||
@ -63,7 +63,7 @@ class DevKbd:
|
||||
continue
|
||||
unsigned code = encode[r][col]
|
||||
if rowdata & (1 << ROWS[r]):
|
||||
code |= Keyboard::RELEASE
|
||||
code |= Iris::Keyboard::RELEASE
|
||||
if is_active:
|
||||
event.invoke (code)
|
||||
state[col] = rowdata
|
||||
@ -101,7 +101,7 @@ class DevKbd:
|
||||
gpio_as_interrupt (ROWS_PORT, high, true, true)
|
||||
gpio_as_interrupt (ROWS_PORT, low, false, true)
|
||||
gpio_unmask_irq (ROWS_PORT, ALL_ROWS)
|
||||
void active (Kernel::Cap cb):
|
||||
void active (Iris::Cap cb):
|
||||
inactive ()
|
||||
event = cb
|
||||
is_active = true
|
||||
@ -167,7 +167,7 @@ unsigned const DevKbd::keys[NUM_KEYS] = {
|
||||
|
||||
class PowerButton:
|
||||
bool state, started
|
||||
Kernel::Cap cb
|
||||
Iris::Cap cb
|
||||
public:
|
||||
void scan ():
|
||||
if !started:
|
||||
@ -176,16 +176,16 @@ class PowerButton:
|
||||
bool s = gpio_get_port (3) & (1 << 29)
|
||||
if s != state:
|
||||
state = s
|
||||
cb.invoke (state ? Keyboard::RELEASE : 0)
|
||||
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
|
||||
gpio_as_interrupt (3, 1 << 29, !state, true)
|
||||
gpio_unmask_irq (3, 1 << 29)
|
||||
PowerButton ():
|
||||
gpio_as_gpio (3, 29)
|
||||
state = true
|
||||
started = false
|
||||
void set_cb (Kernel::Cap c):
|
||||
void set_cb (Iris::Cap c):
|
||||
if started:
|
||||
Kernel::free_cap (cb)
|
||||
Iris::free_cap (cb)
|
||||
else:
|
||||
started = true
|
||||
cb = c
|
||||
@ -196,100 +196,100 @@ enum codes:
|
||||
KBD_DEV = 32
|
||||
PWR
|
||||
|
||||
Kernel::Num start ():
|
||||
Iris::Num start ():
|
||||
map_gpio ()
|
||||
|
||||
DevKbd kbd
|
||||
PowerButton pwr
|
||||
|
||||
Device dev = Kernel::my_receiver.create_capability (KBD_DEV)
|
||||
Keyboard pw = Kernel::my_receiver.create_capability (PWR)
|
||||
Kernel::my_parent.provide_device <Keyboard> (dev.copy (), 0)
|
||||
Kernel::my_parent.provide_device <Keyboard> (pw.copy (), 1)
|
||||
Kernel::free_cap (dev)
|
||||
Kernel::free_cap (pw)
|
||||
Kernel::my_parent.init_done ()
|
||||
Iris::Device dev = Iris::my_receiver.create_capability (KBD_DEV)
|
||||
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
|
||||
Iris::my_parent.provide_device <Iris::Keyboard> (dev.copy (), 0)
|
||||
Iris::my_parent.provide_device <Iris::Keyboard> (pw.copy (), 1)
|
||||
Iris::free_cap (dev)
|
||||
Iris::free_cap (pw)
|
||||
Iris::my_parent.init_done ()
|
||||
if kbd.scanning ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
unsigned user (0), power_user (0)
|
||||
unsigned next_user (0)
|
||||
Kernel::register_interrupt (IRQ_GPIO3)
|
||||
Iris::register_interrupt (IRQ_GPIO3)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.h:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
kbd.scan ()
|
||||
if kbd.scanning ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
break
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
switch Iris::recv.protected_data.l:
|
||||
case IRQ_GPIO3:
|
||||
// Interrupt.
|
||||
pwr.scan ()
|
||||
kbd.scan ()
|
||||
if kbd.scanning ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Kernel::register_interrupt (IRQ_GPIO3)
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Iris::register_interrupt (IRQ_GPIO3)
|
||||
break
|
||||
case PWR:
|
||||
// Power button request.
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Device::host (PWR, power_user, reply, arg)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Device::host (PWR, power_user, reply, arg)
|
||||
break
|
||||
case KBD_DEV:
|
||||
// Keyboard device control request.
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Device::host (KBD_DEV, user, reply, arg)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Device::host (KBD_DEV, user, reply, arg)
|
||||
break
|
||||
default:
|
||||
break
|
||||
break
|
||||
case KBD_DEV:
|
||||
// Keyboard device user request.
|
||||
if Kernel::recv.protected_data.l != user:
|
||||
if Iris::recv.protected_data.l != user:
|
||||
kdebug ("invalid user requesting keyboard\n")
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Keyboard::SET_CB:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
kbd.active (Kernel::get_arg ())
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Keyboard::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
kbd.active (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Keyboard::GET_NUM_KEYS:
|
||||
Kernel::recv.reply.invoke (kbd.size ())
|
||||
case Iris::Keyboard::GET_NUM_KEYS:
|
||||
Iris::recv.reply.invoke (kbd.size ())
|
||||
break
|
||||
case Keyboard::GET_KEYS:
|
||||
kbd.send_keys (Kernel::recv.data[0].l, Kernel::recv.reply)
|
||||
case Iris::Keyboard::GET_KEYS:
|
||||
kbd.send_keys (Iris::recv.data[0].l, Iris::recv.reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("keyboard other\n")
|
||||
break
|
||||
break
|
||||
case PWR:
|
||||
if Kernel::recv.protected_data.l != power_user:
|
||||
if Iris::recv.protected_data.l != power_user:
|
||||
kdebug ("invalid user requesting power\n")
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Keyboard::SET_CB:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
pwr.set_cb (Kernel::get_arg ())
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Keyboard::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
pwr.set_cb (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("Power button invalid request\n")
|
||||
kdebug_num (Kernel::recv.data[0].l)
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("keyboard unknown num: ")
|
||||
kdebug_num (Kernel::recv.protected_data.h)
|
||||
kdebug_num (Iris::recv.protected_data.h)
|
||||
kdebug ("\n")
|
@ -53,14 +53,14 @@ enum event_type:
|
||||
TOUCHPAD_EVENT
|
||||
NUM_EVENTS
|
||||
|
||||
static Kernel::Cap events[NUM_EVENTS]
|
||||
static Iris::Cap events[NUM_EVENTS]
|
||||
|
||||
static void event (event_type type, unsigned data):
|
||||
events[type].invoke (data)
|
||||
|
||||
static void set_cb (event_type type):
|
||||
Kernel::free_cap (events[type])
|
||||
events[type] = Kernel::get_arg ()
|
||||
Iris::free_cap (events[type])
|
||||
events[type] = Iris::get_arg ()
|
||||
|
||||
class DevKeyboard:
|
||||
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
|
||||
@ -252,72 +252,72 @@ enum codes:
|
||||
LOCKLEDS
|
||||
PWM
|
||||
|
||||
Kernel::Num start ():
|
||||
Iris::Num start ():
|
||||
map_gpio ()
|
||||
map_pwm0 ()
|
||||
|
||||
for unsigned i = 0; i < NUM_EVENTS; ++i:
|
||||
events[i] = Kernel::alloc_cap ()
|
||||
events[i] = Iris::alloc_cap ()
|
||||
|
||||
DevKeyboard kbd
|
||||
Touchpad tp
|
||||
Lockleds leds
|
||||
Pwm pwm
|
||||
|
||||
Kernel::Cap c = Kernel::my_receiver.create_capability (KEYBOARD)
|
||||
Kernel::my_parent.provide_device <Keyboard> (c.copy (), 0)
|
||||
Kernel::free_cap (c)
|
||||
c = Kernel::my_receiver.create_capability (TOUCHPAD)
|
||||
Kernel::my_parent.provide_device <Keyboard> (c.copy (), 1)
|
||||
Kernel::free_cap (c)
|
||||
Kernel::my_parent.init_done ()
|
||||
Iris::Cap c = Iris::my_receiver.create_capability (KEYBOARD)
|
||||
Iris::my_parent.provide_device <Keyboard> (c.copy (), 0)
|
||||
Iris::free_cap (c)
|
||||
c = Iris::my_receiver.create_capability (TOUCHPAD)
|
||||
Iris::my_parent.provide_device <Keyboard> (c.copy (), 1)
|
||||
Iris::free_cap (c)
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
if kbd.is_scanning ():
|
||||
Kernel::my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
|
||||
// Enable interrupts. All are in port 0.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
|
||||
Kernel::register_interrupt (IRQ_GPIO0)
|
||||
Iris::register_interrupt (IRQ_GPIO0)
|
||||
|
||||
while true:
|
||||
Kernel::schedule ()
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.l:
|
||||
Iris::schedule ()
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
kbd.scan ()
|
||||
if kbd.is_scanning ():
|
||||
Kernel::my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
break
|
||||
case IRQ_GPIO0:
|
||||
// Always scan keyboard and touchpad on any interrupt.
|
||||
kbd.scan ()
|
||||
tp.check_events ()
|
||||
// Reregister the interrupt.
|
||||
Kernel::register_interrupt (IRQ_GPIO0)
|
||||
Iris::register_interrupt (IRQ_GPIO0)
|
||||
break
|
||||
case KEYBOARD:
|
||||
set_cb (KEYBOARD_EVENT)
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
kbd.send_initial ()
|
||||
event (KEYBOARD_EVENT, ~0)
|
||||
break
|
||||
case TOUCHPAD:
|
||||
set_cb (TOUCHPAD_EVENT)
|
||||
Kernel::recv.reply.invoke ()
|
||||
Iris::recv.reply.invoke ()
|
||||
tp.send_initial ()
|
||||
event (TOUCHPAD_EVENT, ~0)
|
||||
break
|
||||
case LOCKLEDS:
|
||||
leds.set (Kernel::recv.data[0].l)
|
||||
Kernel::recv.reply.invoke ()
|
||||
leds.set (Iris::recv.data[0].l)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case PWM:
|
||||
pwm.set_backlight (Kernel::recv.data[0].l)
|
||||
Kernel::recv.reply.invoke ()
|
||||
pwm.set_backlight (Iris::recv.data[0].l)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid gpio operation ")
|
||||
kdebug_num (Kernel::recv.protected_data.l)
|
||||
kdebug_num (Iris::recv.protected_data.l)
|
||||
kdebug ("\n")
|
||||
break
|
Loading…
Reference in New Issue
Block a user