1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-28 12:32:05 +02:00

towards a usb file system

This commit is contained in:
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
*.cc
*.hh
gpio
lcd
init
udc
buzzer
metronome
nanonote-gpio
boot-programs/charset.data
mips/nanonote/sdram-setup.raw
nanonote-boot

View File

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

View File

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

View File

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

View File

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

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.
void use (Kernel::Cap user):
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.
struct Parent : public Kernel::Cap:
@ -270,11 +304,25 @@ struct WDirectory : public Directory:
void unlock ():
call (CAP_MASTER_DIRECT | UNLOCK)
// A filesystem turns a String into a Directory.
struct Filesystem : public Device:
Filesystem (Kernel::Cap c = Kernel::Cap ()) : Device (c):
enum request:
USE_DEVICE = WDirectory::ID
USE_DEVICE_RO
ID
WDirectory use_device (WString dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return Kernel::get_arg ()
Directory use_device_ro (String dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return Kernel::get_arg ()
// Stream interface.
struct Stream : public Kernel::Cap:
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
READ = WDirectory::ID
READ = Filesystem::ID
WRITE
ID
// Try to read size bytes. Returns the number of bytes successfully read.

View File

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

View File

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

View File

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

View File

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

View File

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

143
source/crt0.ccp Normal file
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")