1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-29 19:44:16 +02:00

towards a usb file system

This commit is contained in:
Bas Wijnen 2010-01-14 18:14:37 +01:00
parent 3debf99082
commit 0c1dfe719b
20 changed files with 690 additions and 507 deletions

7
.gitignore vendored
View File

@ -6,13 +6,6 @@ uimage
*.elf *.elf
*.cc *.cc
*.hh *.hh
gpio
lcd
init
udc
buzzer
metronome
nanonote-gpio
boot-programs/charset.data boot-programs/charset.data
mips/nanonote/sdram-setup.raw mips/nanonote/sdram-setup.raw
nanonote-boot nanonote-boot

View File

@ -46,6 +46,10 @@ PYPP = /usr/bin/pypp
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@ $(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@ #$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
fs/%.elf: source/crt0.o source/%.o
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
#$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
clean: clean:
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES) rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)

View File

@ -97,7 +97,7 @@ namespace Kernel:
return Cap (0, ret - __cap_admin) return Cap (0, ret - __cap_admin)
extern "C": extern "C":
void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin): void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
__slots = slots __slots = slots
__caps = caps __caps = caps
__slot_admin = slot_admin __slot_admin = slot_admin
@ -137,7 +137,7 @@ __asm__ volatile ("\t.globl __start\n"
"\tmove $a2, $sp\n" "\tmove $a2, $sp\n"
"\tsubu $sp, $sp, $v1\n" "\tsubu $sp, $sp, $v1\n"
"\tmove $a3, $sp\n" "\tmove $a3, $sp\n"
"\tla $t9, __main\n" "\tla $t9, run__main\n"
"\tjr $t9\n" "\tjr $t9\n"
"\tnop\n" "\tnop\n"
"\t.set reorder") "\t.set reorder")

View File

@ -1,6 +1,6 @@
#pypp 0 #pypp 0
// Iris: micro-kernel for a capability-based operating system. // Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.ccp: System boot manager. // bootstrap/init.ccp: Bootstrapping code.
// Copyright 2009 Bas Wijnen <wijnen@debian.org> // Copyright 2009 Bas Wijnen <wijnen@debian.org>
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
@ -18,136 +18,288 @@
#include "devices.hh" #include "devices.hh"
#include "iris.hh" #include "iris.hh"
#include <elf.h>
static Keyboard sysreq #define NUM_SLOTS 4
static Device kbd_dev, buz_dev, backlight_dev, rootfs_dev #define NUM_CAPS 16
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = _end
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + pages * PAGE_SIZE
return (char *)ret
void *operator new[] (unsigned size):
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (size & ~PAGE_MASK)
if rest <= size:
_free += size
return ret
unsigned pages = ((size - rest) + PAGE_SIZE - 1) & PAGE_MASK
char *space = alloc_space (pages)
for unsigned p = 0; p < pages; ++p:
Kernel::Page page = Kernel::my_memory.create_page ()
page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
Kernel::my_memory.map (page, (unsigned)&space[p << PAGE_BITS])
Kernel::free_cap (page)
_free += size
return ret
struct file:
unsigned size
// Only the first 16 characters of the name are used, because that's much easier.
// This means that file names must be different in the first 16 characters if sort order matters.
char name[16]
String string
static unsigned num_files
static file *files
static unsigned *index
static Kernel::Memory top_memory
static unsigned slot static unsigned slot
static unsigned max_pages
static char *mapping
static unsigned current_thread
// Event types. // Get the initial block device and filesystem.
enum type: static Directory receive_devices ():
SYSREQ String data
KBDDEV Filesystem fs
BUZDEV bool have_data = false, have_fs = false
BACKLIGHTDEV for unsigned i = 0; i < 2; ++i:
ROOTFSDEV Device dev
static void user_reply (Kernel::Cap target, unsigned dev):
switch dev:
case Keyboard::ID:
// keyboard user
Kernel::Cap kbd = kbd_dev.create_user (Kernel::Cap ())
kbd_dev.use (kbd)
target.invoke (0, 0, kbd.copy ())
Kernel::free_cap (kbd)
break
case Buzzer::ID:
// buzzer user
Kernel::Cap buzzer = buz_dev.create_user (Kernel::Cap ())
buz_dev.use (buzzer)
target.invoke (0, 0, buzzer.copy ())
Kernel::free_cap (buzzer)
break
default:
kdebug ("invalid id requested:")
kdebug_num (dev)
kdebug_char ('\n')
break
static void setup ():
unsigned state = 0
Kernel::Caps caps = Kernel::my_memory.create_caps (32)
slot = caps.use ()
Kernel::Cap user
unsigned device
while true:
Kernel::wait () Kernel::wait ()
Kernel::Cap reply = Kernel::get_reply () if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
Kernel::Cap arg = Kernel::get_arg () kdebug ("Invalid bootstrap request.\n")
switch Kernel::recv.data[0].l: Kernel::panic (0)
case Parent::PROVIDE_DEVICE: switch Kernel::recv.data[1].l:
switch Kernel::recv.data[1].l: case String::ID:
case Keyboard::ID: if have_data:
switch Kernel::recv.data[0].h: kdebug ("duplicate device.\n")
case 0: Kernel::panic (0)
caps.set (KBDDEV, arg.copy ()) dev = Kernel::get_arg ()
kbd_dev = Kernel::Cap (slot, KBDDEV) have_data = true
break Kernel::recv.reply.invoke ()
case 1: data = dev.create_user (Kernel::my_memory)
caps.set (SYSREQ, arg.copy ()) dev.use (data)
sysreq = Kernel::Cap (slot, SYSREQ) Kernel::free_cap (dev)
break
default:
kdebug ("unexpected keyboard\n")
break
reply.invoke ()
Kernel::free_cap (reply)
break
case Buzzer::ID:
caps.set (BUZDEV, arg.copy ())
buz_dev = Kernel::Cap (slot, BUZDEV)
reply.invoke ()
Kernel::free_cap (reply)
break
case Setting::ID:
caps.set (BACKLIGHTDEV, arg.copy ())
backlight_dev = Kernel::Cap (slot, BACKLIGHTDEV)
reply.invoke ()
Kernel::free_cap (reply)
break
case Directory::ID:
caps.set (ROOTFSDEV, arg.copy ())
rootfs_dev = Kernel::Cap (slot, ROOTFSDEV)
reply.invoke ()
Kernel::free_cap (reply)
break
default:
kdebug ("unexpected device: ")
kdebug_num (Kernel::recv.data[1].l)
kdebug_char ('\n')
break
break break
case Parent::GET_DEVICE: case Filesystem::ID:
user = reply if have_fs:
device = Kernel::recv.data[1].l kdebug ("duplicate filesystem.\n")
Kernel::panic (0)
dev = Kernel::get_arg ()
have_fs = true
fs = dev.create_user (Kernel::my_memory)
dev.use (fs)
Kernel::free_cap (dev)
Kernel::recv.reply.invoke ()
break break
default: default:
kdebug ("unknown setup request for init\n") kdebug ("unexpected device: ")
reply.invoke () kdebug_num (Kernel::recv.data[1].l)
Kernel::free_cap (reply) kdebug_char ('\n')
Kernel::free_cap (arg) Kernel::panic (0)
continue // Initialize the root file system.
Kernel::free_cap (arg) Directory root = fs.use_device_ro (data.copy ())
if ++state == 6: Kernel::free_cap (data)
break Kernel::free_cap (fs)
// sysreq return root
Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
sysreq.set_cb (cb.copy ()) // Make a list of all files.
Kernel::free_cap (cb) static void list_files (Directory root):
// First user reply. Kernel::Num fullsize = root.get_size ()
user_reply (user, device) if fullsize.h != 0:
Kernel::free_cap (user) kdebug ("Too many files in bootstrap directory.\n")
Kernel::panic (0)
num_files = fullsize.l
files = new file[num_files]
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2)
unsigned slot = Kernel::alloc_slot ()
caps.use (slot)
for unsigned i = 0; i < num_files; ++i:
Kernel::set_recv_arg (Kernel::Cap (slot, i * 2))
String n = root.get_name (i)
n.get_chars (0, files[i].name)
Kernel::set_recv_arg (Kernel::Cap (slot, i * 2 + 1))
files[i].string = root.get_file_ro (i)
Kernel::Num fullsize = files[i].string.get_size ()
if fullsize.h != 0:
kdebug ("initial file size too large.\n")
Kernel::panic (0)
files[i].size = fullsize.l
if max_pages < (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK:
max_pages = (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK
// Sort the list of files.
static bool is_less (file *f1, file *f2):
for unsigned i = 0; i < 16; ++i:
if f1->name[i] < f2->name[i]:
return true
if f1->name[i] > f2->name[i]:
return false
return false
// Bubble sort.
static void sort ():
index = new unsigned[num_files]
index[0] = 0
// Invariant: index[0...f-1] is sorted.
for unsigned f = 1; f < num_files; ++f:
// Bubble up until top. Test for less-than, because it wraps to maxunsigned.
unsigned i
// Invariant: index[0...f] \ index[i+1] is sorted and index[i+1...f] is sorted.
for i = f - 1; i < f; --i:
if is_less (&files[index[i]], &files[f]):
break
index[i + 1] = index[i]
index[i + 1] = f
static void run (file *f, bool priv):
Kernel::Memory mem = top_memory.create_memory ()
unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK
for unsigned p = 0; p < num_pages; ++p:
Kernel::set_recv_arg (Kernel::Cap (slot, p))
mem.create_page ()
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
Kernel::Thread thread = mem.create_thread (NUM_SLOTS)
if priv:
thread.make_priv ()
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
kdebug ("invalid ELF magic\n")
Kernel::panic (0)
return
if header->e_ident[EI_CLASS] != ELFCLASS32:
kdebug ("invalid ELF class\n")
Kernel::panic (0)
return
if header->e_ident[EI_DATA] != ELFDATA2LSB:
kdebug ("invalid ELF data\n")
Kernel::panic (0)
return
if header->e_ident[EI_VERSION] != EV_CURRENT:
kdebug ("invalid ELF version\n")
Kernel::panic (0)
return
if header->e_type != ET_EXEC:
kdebug ("invalid ELF type\n")
Kernel::panic (0)
return
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
kdebug ("invalid ELF machine\n")
Kernel::panic (0)
return
thread.set_pc (header->e_entry)
thread.set_sp (0x80000000)
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
bool readonly = !(shdr->sh_flags & SHF_WRITE)
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS:
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
kdebug ("thread too large\n")
Kernel::panic (0)
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
Kernel::Page page = mem.mapping ((void *)p)
if Kernel::recv.data[0].l == Kernel::NO_ERROR:
// The address already has a mapping; assume that it is correct.
Kernel::free_cap (page)
continue
page = mem.create_page ()
Kernel::Page (slot, idx).share (page, 0)
if !mem.map (page, p, readonly):
kdebug ("unable to map page\n")
Kernel::panic (0)
return
Kernel::free_cap (page)
else:
if readonly:
kdebug ("unwritable bss section\n")
Kernel::panic (0)
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Kernel::Page page = mem.mapping ((void *)p)
if Kernel::recv.data[0].l == Kernel::NO_ERROR:
// No error means there is no mapping.
page = mem.create_page ()
if Kernel::recv.data[0].l != Kernel::NO_ERROR:
kdebug ("out of memory\n")
Kernel::panic (0)
return
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
kdebug ("out of memory\n")
Kernel::panic (0)
return
if !mem.map (page, p):
kdebug ("unable to map bss page\n")
Kernel::panic (0)
return
Kernel::free_cap (page)
else:
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
((unsigned *)&mapping[p])[(a & ~PAGE_MASK) >> 2] = 0
for unsigned p = 0; p <= num_pages; ++p:
mem.destroy (Kernel::Page (slot, p))
Kernel::Page stackpage = mem.create_page ()
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
if Kernel::recv.data[0].l != Kernel::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
kdebug ("unable to map initial stack page\n")
Kernel::panic (0)
return
Kernel::free_cap (stackpage)
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
thread.use (caps, 0)
thread.set_info (Kernel::Thread::A0, NUM_SLOTS)
thread.set_info (Kernel::Thread::A1, NUM_CAPS)
Kernel::Receiver receiver = mem.create_receiver ()
receiver.set_owner (thread.copy ())
Kernel::Cap call = receiver.create_call_capability ()
Kernel::Cap parent = Kernel::my_receiver.create_capability (++current_thread)
caps.set (__receiver_num, receiver.copy ())
caps.set (__thread_num, thread.copy ())
caps.set (__memory_num, mem.copy ())
caps.set (__call_num, call.copy ())
caps.set (__parent_num, parent.copy ())
thread.run ()
Kernel::free_cap (receiver)
Kernel::free_cap (thread)
Kernel::free_cap (mem)
Kernel::free_cap (call)
Kernel::free_cap (parent)
Kernel::Num start (): Kernel::Num start ():
// Wait for the debugging device to be active, in case there is one.
Kernel::schedule () Kernel::schedule ()
setup () top_memory = Kernel::get_top_memory ()
// claim backlight Directory root = receive_devices ()
Setting backlight = backlight_dev.create_user (Kernel::Cap ()) root.lock_ro ()
backlight_dev.use (backlight) list_files (root)
bool backlight_state = true sort ()
while true: Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
Kernel::wait () slot = caps.use ()
switch Kernel::recv.protected_data.value (): mapping = alloc_space (max_pages)
case SYSREQ: for unsigned i = 0; i < num_files; ++i:
unsigned code = Kernel::recv.data[0].l run (&files[index[i]], files[index[i]].name[0] == '#')
if !(code & Keyboard::RELEASE): root.unlock_ro ()
backlight_state = !backlight_state Kernel::free_slot (slot)
backlight.set (backlight_state ? ~0 : 0) Kernel::my_memory.destroy (caps)
break return 0
default:
if Kernel::recv.data[0].l != Parent::GET_DEVICE:
kdebug ("invalid call from user\n")
break
Kernel::Cap reply = Kernel::get_reply ()
user_reply (reply, Kernel::recv.data[1].l)
Kernel::free_cap (reply)
break

View File

@ -150,17 +150,19 @@ class Udc:
char configuration char configuration
unsigned size unsigned size
char const *ptr char const *ptr
unsigned cmd_code, cmd_arg
bool rebooting bool rebooting
bool vendor (Setup *s) bool vendor (Setup *s, unsigned cmd)
bool get_descriptor (unsigned type, unsigned idx, unsigned len) bool get_descriptor (unsigned type, unsigned idx, unsigned len)
bool handle_setup (Setup *s) bool handle_setup (Setup *s, unsigned cmd)
char log_buffer[1000] char log_buffer[1000]
unsigned log_buffer_size unsigned log_buffer_size
unsigned log_buffer_start unsigned log_buffer_start
public: public:
void init () void init ()
void log (unsigned c) void log (unsigned c)
void interrupt () void interrupt (unsigned cmd)
void send (unsigned code, unsigned arg)
Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 } Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
Udc::my_config Udc::config_descriptor = { Udc::my_config Udc::config_descriptor = {
@ -198,6 +200,8 @@ void Udc::init ():
s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } } s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
log_buffer_size = 0 log_buffer_size = 0
log_buffer_start = 0 log_buffer_start = 0
cmd_code = ~0
cmd_arg = 0
// Disconnect from the bus and don't try to get high-speed. // Disconnect from the bus and don't try to get high-speed.
UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB) UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB)
@ -221,21 +225,35 @@ void Udc::init ():
// Connect to the host. // Connect to the host.
UDC_POWER |= UDC_POWER_SOFTCONN UDC_POWER |= UDC_POWER_SOFTCONN
bool Udc::vendor (Setup *s): bool Udc::vendor (Setup *s, unsigned cmd):
if !(s->request_type & 0x80): if !(s->request_type & 0x80):
switch s->request:
case Directory::GET_SIZE:
//TODO
case Directory::GET_NAME:
//TODO
default:
kdebug ("invalid vendor request\n")
Kernel::panic (0)
return true return true
if s->request == 10: if s->request == 10:
static char b[2] static unsigned b[2]
ptr = b ptr = (char *)b
size = s->length < 2 ? s->length : 2 size = s->length < 8 ? s->length : 8
b[0] = '#' if cmd_code != ~0:
if log_buffer_start == log_buffer_size: b[0] = cmd_code
size = 1 b[1] = cmd_arg
cmd_code = ~0
else: else:
b[1] = log_buffer[log_buffer_start++] if log_buffer_start == log_buffer_size:
if log_buffer_start == log_buffer_size: b[0] = ~1
log_buffer_start = 0 b[1] = 0
log_buffer_size = 0 else:
b[0] = ~0
b[1] = (log_buffer[log_buffer_start++] & 0xff) * 0x01010101
if log_buffer_start == log_buffer_size:
log_buffer_start = 0
log_buffer_size = 0
else: else:
static char const *name = "Reboot" static char const *name = "Reboot"
ptr = name ptr = name
@ -244,6 +262,13 @@ bool Udc::vendor (Setup *s):
state = TX state = TX
return true return true
void Udc::send (unsigned code, unsigned arg):
if code != ~0:
kdebug ("new code sent while old one wasn't finished.\n")
Kernel::panic (0)
cmd_code = code
cmd_arg = arg
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
switch type: switch type:
case Configuration::Type: case Configuration::Type:
@ -265,7 +290,7 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
//size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor)) //size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
//break //break
return false return false
// The 6 is an arbitrary number, except that String <6> in instantiated already. // The 6 is an arbitrary number, except that String <6> is instantiated already.
case String <6>::Type: case String <6>::Type:
switch idx: switch idx:
case 0: case 0:
@ -288,7 +313,7 @@ bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
state = TX state = TX
return true return true
bool Udc::handle_setup (Setup *s): bool Udc::handle_setup (Setup *s, unsigned cmd):
switch s->request_type: switch s->request_type:
case STANDARD_TO_DEVICE: case STANDARD_TO_DEVICE:
switch s->request: switch s->request:
@ -331,12 +356,12 @@ bool Udc::handle_setup (Setup *s):
break break
case VENDOR_TO_DEVICE: case VENDOR_TO_DEVICE:
case VENDOR_FROM_DEVICE: case VENDOR_FROM_DEVICE:
return vendor (s) return vendor (s, cmd)
default: default:
return false return false
return true return true
void Udc::interrupt (): void Udc::interrupt (unsigned cmd):
unsigned i = UDC_INTRUSB unsigned i = UDC_INTRUSB
if i & UDC_INTR_RESET: if i & UDC_INTR_RESET:
state = IDLE state = IDLE
@ -361,7 +386,7 @@ void Udc::interrupt ():
packet.d[0] = UDC_FIFO (0) packet.d[0] = UDC_FIFO (0)
packet.d[1] = UDC_FIFO (0) packet.d[1] = UDC_FIFO (0)
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
if !handle_setup (&packet.s): if !handle_setup (&packet.s, cmd):
csr |= UDC_CSR0_SENDSTALL csr |= UDC_CSR0_SENDSTALL
break break
if size == 0: if size == 0:
@ -395,6 +420,8 @@ void Udc::log (unsigned c):
enum pdata: enum pdata:
LOG = 32 LOG = 32
FS FS
DATA
DIRECTORY
Kernel::Num start (): Kernel::Num start ():
map_udc () map_udc ()
@ -408,52 +435,28 @@ Kernel::Num start ():
Kernel::register_interrupt (IRQ_UDC) Kernel::register_interrupt (IRQ_UDC)
Device fs_dev = Kernel::my_receiver.create_capability (FS) Device fs_dev = Kernel::my_receiver.create_capability (FS)
Kernel::my_parent.provide_device <Directory> (fs_dev) Kernel::my_parent.provide_device <Directory> (fs_dev)
Kernel::Num current_user = 0 unsigned data_current_user = 0, fs_current_user = 0
unsigned next_user unsigned next_user
unsigned state = 0
while true: while true:
Kernel::wait () Kernel::wait ()
Kernel::Cap reply = Kernel::get_reply ()
switch Kernel::recv.protected_data.h: switch Kernel::recv.protected_data.h:
case 0: case 0:
switch Kernel::recv.protected_data.l: switch Kernel::recv.protected_data.l:
case IRQ_UDC: case IRQ_UDC:
udc.interrupt () udc.interrupt (state)
Kernel::register_interrupt (IRQ_UDC) Kernel::register_interrupt (IRQ_UDC)
break break
case LOG: case LOG:
udc.log (Kernel::recv.data[0].l) udc.log (Kernel::recv.data[0].l)
break break
case FS: case FS:
switch Kernel::recv.data[0].l: Device::host (FS, fs_current_user, reply)
case Device::CREATE_USER: continue
Kernel::Cap reply = Kernel::get_reply () case DATA:
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, FS)) Device::host (DATA, data_current_user, reply)
reply.invoke (0, 0, c.copy ()) continue
Kernel::free_cap (c)
Kernel::free_cap (reply)
break
case Device::DESTROY_USER:
Kernel::Cap reply = Kernel::get_reply ()
reply.invoke ()
Kernel::free_cap (reply)
break
case Device::USE:
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
current_user = Kernel::my_receiver.get_protected (arg)
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
case Device::UNUSE:
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
if current_user.value () == Kernel::my_receiver.get_protected (arg).value ():
current_user = 0
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
break
default: default:
udc.log ('~') udc.log ('~')
char digit[] = "0123456789abcdef" char digit[] = "0123456789abcdef"
@ -461,18 +464,55 @@ Kernel::Num start ():
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf]) udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
udc.log ('\n') udc.log ('\n')
break break
case FS: case DATA:
if current_user.value () != Kernel::recv.protected_data.value (): if data_current_user != Kernel::recv.protected_data.l:
break break
switch Kernel::recv.data[0].l:
case String::GET_SIZE:
case String::GET_CHARS:
reply.invoke (0)
Kernel::free_cap (reply)
continue
case String::GET_PAGE:
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
continue
break
case FS:
if fs_current_user != Kernel::recv.protected_data.l:
break
switch Kernel::recv.data[0].l:
case Filesystem::USE_DEVICE:
case Filesystem::USE_DEVICE_RO:
Directory dir = Kernel::my_receiver.create_capability (Kernel::Num (0, DIRECTORY))
reply.invoke (0, 0, dir.copy ())
Kernel::free_cap (dir)
Kernel::free_cap (reply)
continue
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
continue
case DIRECTORY:
switch Kernel::recv.data[0].l: switch Kernel::recv.data[0].l:
case Directory::GET_SIZE: case Directory::GET_SIZE:
case Directory::GET_NAME: case Directory::GET_NAME:
case Directory::GET_FILE_RO:
case Directory::LOCK_RO: case Directory::LOCK_RO:
case Directory::UNLOCK_RO: case Directory::UNLOCK_RO:
Kernel::recv.reply.invoke () state = Kernel::recv.data[0].l
break if Kernel::recv.data[1].h != 0:
kdebug ("index out of supported range\n")
Kernel::panic (0)
udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l)
Kernel::free_cap (reply)
continue
case Directory::GET_FILE_RO:
//TODO
case Directory::GET_FILE_INFO: case Directory::GET_FILE_INFO:
default: default:
Kernel::recv.reply.invoke (~0) reply.invoke (Kernel::ERR_INVALID_OPERATION)
break Kernel::free_cap (reply)
continue
reply.invoke ()
Kernel::free_cap (reply)

View File

@ -1,257 +0,0 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// bootstrap/init.ccp: Bootstrapping code.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "devices.hh"
#include "iris.hh"
struct file:
unsigned size
// Only the first 16 characters of the name are used, because that's much easier.
// This means that file names must be different in the first 16 characters if sort order matters.
char name[16]
String string
static unsigned num_files
static file *files
static unsigned index
static Kernel::Memory top_memory
static unsigned slot
static unsigned max_pages
static char *mapping
static unsigned current_thread
// Get the initial block device and filesystem.
static Directory receive_devices ():
String dev
Filesystem fs
for unsigned i = 0; i < 2; ++i:
Kernel::wait ()
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
kdebug ("Invalid bootstrap request.\n")
Kernel::panic (0)
switch Kernel::recv.data[1].l:
case String::ID:
if dev:
kdebug ("duplicate device.\n")
Kernel::panic (0)
dev = Kernel::get_arg ()
Kernel::recv.reply.invoke ()
break
case Filesystem::ID:
if fs:
kdebug ("duplicate filesystem.\n")
Kernel::panic (0)
fs = Kernel::get_arg ()
Kernel::recv.reply.invoke ()
break
default:
kdebug ("unexpected device: ")
kdebug_num (Kernel::recv.data[1].l)
kdebug_char ('\n')
Kernel::panic (0)
// Initialize the root file system.
Directory root = fs.use_device (dev.copy ())
Kernel::free_cap (dev)
Kernel::free_cap (fs)
return root
// Make a list of all files.
static void list_files (Directory root):
Kernel::Num fullsize = root.get_size ()
if fullsize.h != 0:
kdebug ("Too many files in bootstrap directory.\n")
Kernel::panic (0)
num_files = fullsize.l
files = new file[num_files]
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2)
unsigned slot = Kernel::alloc_slot ()
caps.use (slot)
for unsigned i = 0; i < num_files; ++i:
Kernel::set_recv_arg (Kernel::Cap (slot, i * 2))
String n = root.get_name (i)
n.get_chars (0, files[i].name)
Kernel::set_recv_arg (Kernel::Cap (slot, i * 2 + 1))
files[i].string = root.get_file_ro (i)
Kernel::Num fullsize = files[i].string.get_size ()
if fullsize.h != 0:
kdebug ("initial file size too large.\n")
Kernel::panic (0)
files[i].size = fullsize.l
if max_pages < (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK:
max_pages = (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK
// Sort the list of files.
static bool is_less (file *f1, file *f2):
return
// Bubble sort.
static void sort ():
index = new unsigned[num_files]
index[0] = 0
// Invariant: index[0...f-1] is sorted.
for unsigned f = 1; f < num_files; ++f:
// Bubble up until top. Test for less-than, because it wraps to maxunsigned.
unsigned i
// Invariant: index[0...f] \ index[i+1] is sorted and index[i+1...f] is sorted.
for i = f - 1; i < f; --i:
if is_less (&files[index[i]], &files[f]):
break
index[i + 1] = index[i]
index[i + 1] = f
static void run (file *f, bool priv):
Kernel::Memory mem = top_memory.create_memory ()
unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK
for unsigned p = 0; p < num_pages; ++p:
Kernel::set_recv_arg (Kernel::Cap (slot, p))
mem.create_page ()
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
Kernel::Thread *thread = mem.create_thread (NUM_SLOTS)
if priv:
thread.make_priv ()
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
kdebug ("invalid ELF magic\n")
Kernel::panic (0)
return
if header->e_ident[EI_CLASS] != ELFCLASS32:
kdebug ("invalid ELF class\n")
Kernel::panic (0)
return
if header->e_ident[EI_DATA] != ELFDATA2LSB:
kdebug ("invalid ELF data\n")
Kernel::panic (0)
return
if header->e_ident[EI_VERSION] != EV_CURRENT:
kdebug ("invalid ELF version\n")
Kernel::panic (0)
return
if header->e_type != ET_EXEC:
kdebug ("invalid ELF type\n")
Kernel::panic (0)
return
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
kdebug ("invalid ELF machine\n")
Kernel::panic (0)
return
thread.set_pc (header->e_entry)
thread.set_sp (0x80000000)
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
bool readonly = !(shdr->sh_flags & SHF_WRITE)
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS:
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
kdebug ("thread too large\n")
Kernel::panic (0)
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
Kernel::Page page = mem.mapping (p)
if page:
// The address already has a mapping; assume that it is correct.
Kernel::free_cap (page)
continue
page = mem.create_page ()
Kernel::Cap (slot, idx).share (page, 0)
if !mem.map (page, p, readonly):
kdebug ("unable to map page\n")
Kernel::panic (0)
return
Kernel::free_cap (page)
else:
if readonly:
kdebug ("unwritable bss section\n")
Kernel::panic (0)
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
kPage *page = mem->get_mapping (p)
if !page:
page = mem.create_page ()
if !page:
kdebug ("out of memory\n")
Kernel::panic (0)
return
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
kdebug ("out of memory\n")
Kernel::panic (0)
return
if !mem.map (page, p):
kdebug ("unable to map bss page\n")
Kernel::panic (0)
return
Kernel::free_cap (page)
else:
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
((unsigned *)&mapping[idx << PAGE_BITS])[(a & ~PAGE_MASK) >> 2] = 0
for unsigned p = 0; p <= num_pages; ++p:
mem.destroy (Kernel::Cap (slot, p))
Kernel::Page stackpage = mem.create_page ()
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
if !stackpage || !mem.map (stackpage, 0x7ffff000):
kdebug ("unable to map initial stack page\n")
Kernel::panic (0)
return
Kernel::free_cap (stackpage)
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
thread.use (caps, 0)
thread.set_info (Kernel::Thread::A0, NUM_SLOTS)
thread.set_info (Kernel::Thread::A1, NUM_CAPS)
Kernel::Receiver receiver = mem.create_receiver ()
receiver.set_owner (thread.copy ())
Kernel::Cap call = receiver.create_call_capability ()
Kernel::Cap parent = Kernel::my_receiver.create_capability (++current_thread)
caps.set (__receiver_num, receiver.copy ())
caps.set (__thread_num, thread.copy ())
caps.set (__memory_num, mem.copy ())
caps.set (__call_num, call.copy ())
caps.set (__parent_num, parent.copy ())
thread.run ()
Kernel::free_cap (receiver)
Kernel::free_cap (thread)
Kernel::free_cap (mem)
Kernel::free_cap (call)
Kernel::free_cap (parent)
Kernel::Num start ():
// Wait for the debugging device to be active, in case there is one.
Kernel::schedule ()
top_memory = Kernel::get_top_memory ()
Directory root = receive_devices ()
root.lock_ro ()
list_files (root)
sort ()
Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
slot = caps.use ()
mapping = alloc_space (max_pages)
for unsigned i = 0; i < num_files; ++i:
run (files[i], files[i].name[0] == '#')
root.unlock_ro ()
Kernel::free_slot (slot)
Kernel::my_memory.destroy (caps)
return 0

View File

@ -98,6 +98,40 @@ struct Device : public Kernel::Cap:
// Make user active. It makes the previous active user inactive. // Make user active. It makes the previous active user inactive.
void use (Kernel::Cap user): void use (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | USE) ocall (user, CAP_MASTER_DIRECT | USE)
// Convenience function for threads implementing a device.
static void host (unsigned id, unsigned &current_user, Kernel::Cap &reply):
static unsigned last_user
switch Kernel::recv.data[0].l:
case Device::CREATE_USER:
// Increment last_user; skip 0.
// FIXME: if this really wraps, it is possible that two users share their id.
if !++last_user:
++last_user
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (last_user, id))
reply.invoke (0, 0, c.copy ())
Kernel::free_cap (c)
Kernel::free_cap (reply)
break
case Device::DESTROY_USER:
reply.invoke ()
Kernel::free_cap (reply)
break
case Device::USE:
Kernel::Cap arg = Kernel::get_arg ()
current_user = Kernel::my_receiver.get_protected (arg).l
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
case Device::UNUSE:
Kernel::Cap arg = Kernel::get_arg ()
Kernel::Num p = Kernel::my_receiver.get_protected (arg)
if p.h == id && current_user == p.l:
current_user = 0
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
// Interface for talking to the parent process. // Interface for talking to the parent process.
struct Parent : public Kernel::Cap: struct Parent : public Kernel::Cap:
@ -270,11 +304,25 @@ struct WDirectory : public Directory:
void unlock (): void unlock ():
call (CAP_MASTER_DIRECT | UNLOCK) call (CAP_MASTER_DIRECT | UNLOCK)
// A filesystem turns a String into a Directory.
struct Filesystem : public Device:
Filesystem (Kernel::Cap c = Kernel::Cap ()) : Device (c):
enum request:
USE_DEVICE = WDirectory::ID
USE_DEVICE_RO
ID
WDirectory use_device (WString dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return Kernel::get_arg ()
Directory use_device_ro (String dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return Kernel::get_arg ()
// Stream interface. // Stream interface.
struct Stream : public Kernel::Cap: struct Stream : public Kernel::Cap:
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
READ = WDirectory::ID READ = Filesystem::ID
WRITE WRITE
ID ID
// Try to read size bytes. Returns the number of bytes successfully read. // Try to read size bytes. Returns the number of bytes successfully read.

View File

@ -194,7 +194,7 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
switch cmd: switch cmd:
case Kernel::Receiver::SET_OWNER & REQUEST_MASK: case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
if !c->arg.valid (): if !c->arg.valid ():
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
unsigned cap = (unsigned)c->arg->target unsigned cap = (unsigned)c->arg->target
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER): if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
@ -211,7 +211,7 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK: case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
if !c->arg.valid () || c->arg->target != receiver: if !c->arg.valid () || c->arg->target != receiver:
dpanic (0, "wrong argument for get_protected") dpanic (0, "wrong argument for get_protected")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
reply_num (c->arg->protected_data) reply_num (c->arg->protected_data)
return return
@ -303,12 +303,12 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
return return
default: default:
dpanic (0, "invalid create type") dpanic (0, "invalid create type")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
break break
case Kernel::Memory::DESTROY & REQUEST_MASK: case Kernel::Memory::DESTROY & REQUEST_MASK:
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem: if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem:
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
switch (unsigned)c->arg->target & CAPTYPE_MASK: switch (unsigned)c->arg->target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
@ -337,12 +337,12 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
// FIXME: this should work for fake pages as well. // FIXME: this should work for fake pages as well.
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE: if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
dpanic (0x22993341, "Trying to map non-page") dpanic (0x22993341, "Trying to map non-page")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
if page->address_space != mem: if page->address_space != mem:
dpanic (0x52993341, "Trying to map foreign page") dpanic (0x52993341, "Trying to map foreign page")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY
mem->map (page, c->data[1].l & PAGE_MASK, readonly) mem->map (page, c->data[1].l & PAGE_MASK, readonly)
@ -350,6 +350,9 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
case Kernel::Memory::MAPPING & REQUEST_MASK: case Kernel::Memory::MAPPING & REQUEST_MASK:
bool readonly bool readonly
kPage *page = mem->get_mapping (c->data[1].l, &readonly) kPage *page = mem->get_mapping (c->data[1].l, &readonly)
if !page:
reply_num (Kernel::ERR_UNMAPPED_READ)
return
unsigned t = CAPTYPE_PAGE | CAP_MASTER unsigned t = CAPTYPE_PAGE | CAP_MASTER
if readonly: if readonly:
t |= Kernel::Page::READONLY t |= Kernel::Page::READONLY
@ -421,12 +424,12 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
if c->data[1].l >= thread->slots || !c->arg.valid (): if c->data[1].l >= thread->slots || !c->arg.valid ():
dbg_send (5, 3) dbg_send (5, 3)
dpanic (c->data[1].l, "no argument given for USE_SLOT") dpanic (c->data[1].l, "no argument given for USE_SLOT")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
// FIXME: This doesn't allow using a fake caps. // FIXME: This doesn't allow using a fake caps.
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE): if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE):
dpanic (0, "argument for USE_SLOT is not a caps") dpanic (0, "argument for USE_SLOT is not a caps")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
unsigned slot = c->data[1].l unsigned slot = c->data[1].l
kCaps *new_caps = (kCaps *)c->arg->protected_data.l kCaps *new_caps = (kCaps *)c->arg->protected_data.l
@ -465,14 +468,14 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
return return
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK: case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV ((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
break break
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK: case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
panic (0x54365435, "non-memory argument to alloc_range") panic (0x54365435, "non-memory argument to alloc_range")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
kMemory *mem = (kMemory *)c->arg->protected_data.l kMemory *mem = (kMemory *)c->arg->protected_data.l
if !mem->use (c->data[1].l): if !mem->use (c->data[1].l):
@ -490,11 +493,11 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK: case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
if !c->arg.valid (): if !c->arg.valid ():
panic (0x71342134, "no argument provided for alloc physical") panic (0x71342134, "no argument provided for alloc physical")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
panic (0x21342134, "no page provided for alloc physical") panic (0x21342134, "no page provided for alloc physical")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
page->forget () page->forget ()
@ -519,7 +522,7 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK: case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
dpanic (0x99049380, "invalid page for physical address") dpanic (0x99049380, "invalid page for physical address")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
reply_num (page->frame & ~0xc0000000) reply_num (page->frame & ~0xc0000000)
@ -571,11 +574,11 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
case Kernel::Page::SHARE & REQUEST_MASK: case Kernel::Page::SHARE & REQUEST_MASK:
if !c->arg.valid (): if !c->arg.valid ():
// Cannot share without a target page. // Cannot share without a target page.
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
// FIXME: This makes it impossible to use a fake kPage capability. // FIXME: This makes it impossible to use a fake kPage capability.
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
kPage *t = (kPage *)c->arg->protected_data.l kPage *t = (kPage *)c->arg->protected_data.l
t->forget () t->forget ()
@ -645,7 +648,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
break break
case Kernel::Page::SET_FLAGS & REQUEST_MASK: case Kernel::Page::SET_FLAGS & REQUEST_MASK:
if cmd & Kernel::Page::READONLY: if cmd & Kernel::Page::READONLY:
reply_num (~0) reply_num (Kernel::ERR_WRITE_DENIED)
return return
// Always refuse to set reserved flags. // Always refuse to set reserved flags.
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED) c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
@ -785,12 +788,12 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
else: else:
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM: if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
dpanic (0, "invalid request for list: arg is no listitem") dpanic (0, "invalid request for list: arg is no listitem")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
item = (kListitem *)c->arg->protected_data.l item = (kListitem *)c->arg->protected_data.l
if item->list != list: if item->list != list:
dpanic (0, "item list is not equal to called object") dpanic (0, "item list is not equal to called object")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
switch cmd: switch cmd:
case Kernel::List::GET_NEXT & REQUEST_MASK: case Kernel::List::GET_NEXT & REQUEST_MASK:
@ -799,7 +802,7 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
else: else:
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::LIST: if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::LIST:
dpanic (0, "trying to get next listitem with insufficient rights") dpanic (0, "trying to get next listitem with insufficient rights")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
item = item->next_item item = item->next_item
if !item: if !item:
@ -810,32 +813,32 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
case Kernel::List::ADD_ITEM & REQUEST_MASK: case Kernel::List::ADD_ITEM & REQUEST_MASK:
if !item: if !item:
dpanic (0, "invalid request: no listitem for List::ADD_ITEM") dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::ADD: if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::ADD:
dpanic (0, "trying to add listitem with insufficient rights") dpanic (0, "trying to add listitem with insufficient rights")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
((kListitem *)c->arg->protected_data.l)->add (list) ((kListitem *)c->arg->protected_data.l)->add (list)
break break
case Kernel::List::GET_INFO & REQUEST_MASK: case Kernel::List::GET_INFO & REQUEST_MASK:
if !item: if !item:
dpanic (0, "no item for List::GET_INFO") dpanic (0, "no item for List::GET_INFO")
reply_num (~0, ~0, ~0) reply_num (Kernel::ERR_INVALID_ARGUMENT, ~0, ~0)
return return
reply_num (item->info) reply_num (item->info)
return return
case Kernel::List::SET_INFO & REQUEST_MASK: case Kernel::List::SET_INFO & REQUEST_MASK:
if !item: if !item:
dpanic (0, "no item for List::SET_INFO") dpanic (0, "no item for List::SET_INFO")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
item->info = c->data[1] item->info = c->data[1]
break break
case Kernel::List::GET_CAP & REQUEST_MASK: case Kernel::List::GET_CAP & REQUEST_MASK:
if !item: if !item:
dpanic (0, "no item for List::GET_CAP") dpanic (0, "no item for List::GET_CAP")
reply_num (~0) reply_num (Kernel::ERR_INVALID_ARGUMENT)
return return
kCapability *cap = item->target.cap (0) kCapability *cap = item->target.cap (0)
reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities) reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities)

View File

@ -86,6 +86,7 @@ namespace Kernel:
ERR_OUT_OF_MEMORY ERR_OUT_OF_MEMORY
// The following are not raised, but returned. // The following are not raised, but returned.
ERR_INVALID_OPERATION ERR_INVALID_OPERATION
ERR_INVALID_ARGUMENT
NUM_EXCEPTION_CODES NUM_EXCEPTION_CODES
#ifndef NDEBUG #ifndef NDEBUG
@ -378,7 +379,7 @@ namespace Kernel:
return get_info (SP) return get_info (SP)
unsigned get_flags (): unsigned get_flags ():
return get_info (FLAGS) return get_info (FLAGS)
void run (bool run): void run (bool run = true):
set_flags (run ? RUNNING : 0, RUNNING) set_flags (run ? RUNNING : 0, RUNNING)
void wait (bool wait): void wait (bool wait):
set_flags (wait ? WAITING : 0, WAITING) set_flags (wait ? WAITING : 0, WAITING)
@ -454,8 +455,9 @@ namespace Kernel:
ocall (target, CAP_MASTER_DIRECT | SHARE, flags) ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
unsigned get_flags (): unsigned get_flags ():
return call (CAP_MASTER_DIRECT | GET_FLAGS).l return call (CAP_MASTER_DIRECT | GET_FLAGS).l
void set_flags (unsigned new_flags, unsigned mask): bool set_flags (unsigned new_flags, unsigned mask):
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask)) call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
return recv.data[0].l == NO_ERROR
unsigned physical_address (): unsigned physical_address ():
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
void alloc_physical (unsigned address, bool cachable, bool freeable): void alloc_physical (unsigned address, bool cachable, bool freeable):
@ -536,10 +538,10 @@ namespace Kernel:
void destroy (Cap target): void destroy (Cap target):
ocall (target, CAP_MASTER_DIRECT | DESTROY) ocall (target, CAP_MASTER_DIRECT | DESTROY)
// TODO: LIST // TODO: LIST
void map (Cap page, unsigned address, bool readonly = false): bool map (Cap page, unsigned address, bool readonly = false):
if readonly: if readonly:
address |= Page::READONLY address |= Page::READONLY
ocall (page, CAP_MASTER_DIRECT | MAP, address) return ocall (page, CAP_MASTER_DIRECT | MAP, address).l != ~0
Page mapping (void *address): Page mapping (void *address):
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address)) icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
return get_arg () return get_arg ()

View File

@ -17,7 +17,7 @@
load = 0x80000000 load = 0x80000000
ARCH_CXXFLAGS = -DNUM_THREADS=6 ARCH_CXXFLAGS = -DNUM_THREADS=2
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
CROSS = mipsel-linux-gnu- CROSS = mipsel-linux-gnu-
OBJDUMP = $(CROSS)objdump OBJDUMP = $(CROSS)objdump
@ -28,7 +28,10 @@ LDFLAGS = --omagic -Ttext $(load)
arch_iris_sources = mips/interrupts.cc mips/arch.cc arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.cc boot_sources = mips/init.cc mips/nanonote/board.cc
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
boot_threads = init udc nanonote-gpio buzzer metronome lcd boot_threads = init udc
programs = nanonote-gpio buzzer metronome lcd
all: test $(addsuffix .elf,$(addprefix fs/,$(programs)))
test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw
echo "reboot 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')" | nc localhost 5050 echo "reboot 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')" | nc localhost 5050
@ -53,6 +56,7 @@ mips/nanonote/sdram-setup.elf: LDFLAGS = --omagic -T mips/nanonote/sdram-setup.l
mips/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads)) mips/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20" mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
mips/init.o: TARGET_FLAGS = -I/usr/include mips/init.o: TARGET_FLAGS = -I/usr/include
boot-programs/init.o: TARGET_FLAGS = -I/usr/include
$(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I. $(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I.
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL $(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh $(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh

View File

@ -22,9 +22,11 @@
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <cstring>
#include <shevek/mainloop.hh> #include <shevek/mainloop.hh>
#include <shevek/server.hh> #include <shevek/server.hh>
#include <shevek/args.hh> #include <shevek/args.hh>
#include "devices.hh"
struct client struct client
@ -69,18 +71,87 @@ struct data:
void data::poll (): void data::poll ():
while true: while true:
char buffer[2] unsigned buffer[2]
int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, buffer, 8, timeout) int s = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, POLL, 0, 0, (char *)buffer, 8, timeout)
if s < 1 || s > 2 || buffer[0] != '#': if s != 8:
std::cerr << "unable to send poll message to device: " << usb_strerror () << std::endl std::cerr << "unable to send poll message to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0) usb_release_interface (handle, 0)
usb_close (handle) usb_close (handle)
handle = NULL handle = NULL
return return
if s != 1: switch buffer[0] & 0xffff:
std::cout << buffer[1] << std::flush case ~0 & 0xffff:
else: // Log character.
break std::cout << (char)buffer[1] << std::flush
continue
case ~1 & 0xffff:
// No event.
break
case Directory::GET_SIZE:
unsigned long long size = dir.size ()
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_SIZE, 0, 0, (char const *)&size, 8, timeout) != 8:
std::cerr << "unable to send size to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
continue
case Directory::GET_NAME:
if buffer[1] >= dir.size ():
std::cerr << "invalid file name requested" << std::endl;
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_NAME, 0, 0, dir[buffer[1]].name, 16, timeout) != 16:
std::cerr << "unable to send name to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
continue
case Directory::LOCK_RO:
if !lock++:
dir.load (files)
continue
case Directory::UNLOCK_RO:
if !lock:
std::cerr << "unlocking without lock" << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
--lock
continue
case Directory::GET_FILE_RO:
unsigned f = buffer[0] >> 16
if f >= dir.size ():
std::cerr << "reading invalid file" << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
std::ifstream file (dir[f])
file.seek (buffer[1] << 12)
char page[1 << 12]
memset (page, 0, 1 << 12)
file.read (page, 1 << 12)
for unsigned i = 0; i < (1 << 12); i += 64:
if usb_bulk_write (handle, 1 | USB_ENDPOINT_OUT, p, 64) != 64:
std::cerr << "unable to send file to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
continue
default:
std::cerr << "invalid request" << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
// If the code reaches this point, break out of the loop. The loop continues if a continue statement is reached.
break
(shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll)) (shevek::absolute_time () + shevek::relative_time (1, 0)).schedule (sigc::mem_fun (*this, &data::poll))
struct client : public shevek::server <client, data *>::connection: struct client : public shevek::server <client, data *>::connection:

View File

@ -29,22 +29,6 @@ thread1:
.balign 0x1000 .balign 0x1000
thread2: thread2:
.incbin "nanonote-gpio.elf"
.balign 0x1000
thread3:
.incbin "buzzer.elf"
.balign 0x1000
thread4:
.incbin "metronome.elf"
.balign 0x1000
thread5:
.incbin "lcd.elf"
.balign 0x1000
thread6:
// Everything from here may be freed after kernel initialization. // Everything from here may be freed after kernel initialization.
init_start: init_start:
@ -53,7 +37,3 @@ thread_start:
.word thread0 .word thread0
.word thread1 .word thread1
.word thread2 .word thread2
.word thread3
.word thread4
.word thread5
.word thread6

143
source/crt0.ccp Normal file
View File

@ -0,0 +1,143 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.S: Startup code for initial Threads.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "iris.hh"
#include "devices.hh"
// For some unknown reason, gcc needs this to be defined.
unsigned __gxx_personality_v0
struct list:
list *prev, *next
static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap
namespace Kernel:
Receiver my_receiver
Thread my_thread
Memory my_memory
Cap my_call
Parent my_parent
__recv_data_t recv
void print_caps ():
// Assume __caps to be 16.
bool used[16]
for unsigned i = 0; i < 16; ++i:
used[i] = true
unsigned num = 0
for list *i = __first_free_cap; i; i = i->next:
used[i - __cap_admin] = false
++num
kdebug_num (num, 1)
kdebug (":")
for unsigned i = 0; i < 16; ++i:
kdebug_char (used[i] ? '#' : '.')
kdebug_char ('\n')
void free_slot (unsigned slot):
//kdebug ("free slot\n")
__slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next:
__slot_admin[slot].next->prev = &__slot_admin[slot]
__first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap):
//kdebug ("free cap\n")
if cap.slot () != 0:
kdebug ("trying to free capability from non-0 slot\n")
return
list *l = &__cap_admin[cap.idx ()]
l->prev = NULL
l->next = __first_free_cap
if l->next:
l->next->prev = l
__first_free_cap = l
unsigned alloc_slot ():
//kdebug ("alloc slot\n")
if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
kdebug ("out of slots!\n")
return ~0
list *ret = __first_free_slot
__first_free_slot = ret->next
if ret->next:
ret->next->prev = NULL
return ret - __slot_admin
Cap alloc_cap ():
//kdebug ("alloc cap\n")
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n")
return Cap (0, CAP_NONE)
list *ret = __first_free_cap
__first_free_cap = ret->next
if ret->next:
ret->next->prev = NULL
return Cap (0, ret - __cap_admin)
extern "C":
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
__slots = slots
__caps = caps
__slot_admin = slot_admin
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 2; i < __slots; ++i:
Kernel::free_slot (i)
__first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i:
Kernel::free_cap (Kernel::Cap (0, i))
Kernel::my_receiver = Kernel::Cap (0, __receiver_num)
Kernel::my_thread = Kernel::Cap (0, __thread_num)
Kernel::my_memory = Kernel::Cap (0, __memory_num)
Kernel::my_call = Kernel::Cap (0, __call_num)
Kernel::my_parent = Kernel::Cap (0, __parent_num)
Kernel::recv.reply = Kernel::alloc_cap ()
Kernel::recv.arg = Kernel::alloc_cap ()
Kernel::Num ret = start ()
Kernel::my_parent.invoke (~0, ret)
Kernel::my_memory.destroy (Kernel::my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:
*(volatile unsigned *)~0
__asm__ volatile ("\t.globl __start\n"
"\t.set noreorder\n"
"__start:\n"
"\tbal 1f\n"
"__hack_label:\n"
"\tnop\n"
"\t.word _gp\n"
"1:\n"
"\tlw $gp, 0($ra)\n"
"\tsll $v0, $a0, 3\n"
"\tsll $v1, $a1, 3\n"
"\tsubu $sp, $sp, $v0\n"
"\tmove $a2, $sp\n"
"\tsubu $sp, $sp, $v1\n"
"\tmove $a3, $sp\n"
"\tla $t9, run__main\n"
"\tjr $t9\n"
"\tnop\n"
"\t.set reorder")