mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
make things work with unfinished new startup procedure
This commit is contained in:
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)
|
||||
|
||||
Reference in New Issue
Block a user