1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-10-01 13:10:44 +03:00
iris/boot-programs/init.ccp

433 lines
13 KiB
Plaintext
Raw Normal View History

2009-07-21 13:17:52 +03:00
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
2010-01-14 19:14:37 +02:00
// bootstrap/init.ccp: Bootstrapping code.
2009-07-21 13:17:52 +03:00
// 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"
2010-01-14 19:14:37 +02:00
#include <elf.h>
2009-07-21 13:17:52 +03:00
2010-01-14 19:14:37 +02:00
#define NUM_SLOTS 4
2010-01-16 17:13:54 +02:00
#define NUM_CAPS 32
2009-07-21 13:17:52 +03:00
2010-01-14 19:14:37 +02:00
static unsigned _free
extern unsigned _end
2009-10-10 02:31:10 +03:00
2010-01-14 19:14:37 +02:00
void init_alloc ():
2010-01-17 11:01:42 +02:00
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
2009-07-21 13:17:52 +03:00
2010-01-14 19:14:37 +02:00
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
2010-01-17 11:01:42 +02:00
_free = ret + (pages << PAGE_BITS)
2010-01-14 19:14:37 +02:00
return (char *)ret
void *operator new[] (unsigned size):
2010-01-17 11:01:42 +02:00
//kdebug ("new ")
2010-01-14 19:14:37 +02:00
void *ret = (void *)_free
size = (size + 3) & ~3
2010-01-16 17:13:54 +02:00
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Kernel::Page page = Kernel::my_memory.create_page ()
page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
2010-01-17 11:01:42 +02:00
Kernel::my_memory.map (page, _free + rest + (p << PAGE_BITS))
2010-01-16 17:13:54 +02:00
Kernel::free_cap (page)
2010-01-14 19:14:37 +02:00
_free += size
2010-01-16 17:13:54 +02:00
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
2010-01-14 19:14:37 +02:00
return ret
2010-01-18 07:45:52 +02:00
void *operator new (unsigned size):
return new char[size]
2010-01-14 19:14:37 +02:00
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 data
Filesystem fs
bool have_data = false, have_fs = false
2010-01-16 17:13:54 +02:00
Device fs_dev, data_dev
2010-01-14 19:14:37 +02:00
for unsigned i = 0; i < 2; ++i:
2009-09-06 12:04:09 +03:00
Kernel::wait ()
2010-01-14 19:14:37 +02:00
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)
2010-01-16 17:13:54 +02:00
data_dev = Kernel::get_arg ()
2010-01-14 19:14:37 +02:00
Kernel::recv.reply.invoke ()
2010-01-16 17:13:54 +02:00
have_data = true
2009-10-10 02:31:10 +03:00
break
2010-01-14 19:14:37 +02:00
case Filesystem::ID:
if have_fs:
kdebug ("duplicate filesystem.\n")
Kernel::panic (0)
2010-01-16 17:13:54 +02:00
fs_dev = Kernel::get_arg ()
2010-01-14 19:14:37 +02:00
Kernel::recv.reply.invoke ()
2010-01-16 17:13:54 +02:00
have_fs = true
2009-07-21 13:17:52 +03:00
break
2009-09-07 00:34:50 +03:00
default:
2010-01-14 19:14:37 +02:00
kdebug ("unexpected device: ")
kdebug_num (Kernel::recv.data[1].l)
kdebug_char ('\n')
Kernel::panic (0)
// Initialize the root file system.
2010-01-16 17:13:54 +02:00
data = data_dev.create_user (Kernel::my_memory)
data_dev.use (data)
fs = fs_dev.create_user (Kernel::my_memory)
fs_dev.use (fs)
2010-01-14 19:14:37 +02:00
Directory root = fs.use_device_ro (data.copy ())
Kernel::free_cap (data)
Kernel::free_cap (fs)
2010-01-16 17:13:54 +02:00
Kernel::free_cap (data_dev)
Kernel::free_cap (fs_dev)
2010-01-14 19:14:37 +02:00
return root
// Make a list of all files.
static void list_files (Directory root):
Kernel::Num fullsize = root.get_size ()
if fullsize.h != 0:
2010-01-16 17:13:54 +02:00
kdebug ("Too many files in bootstrap directory:")
kdebug_num (fullsize.h)
kdebug (":")
kdebug_num (fullsize.l)
kdebug ("\n")
2010-01-14 19:14:37 +02:00
Kernel::panic (0)
num_files = fullsize.l
files = new file[num_files]
2010-01-16 17:13:54 +02:00
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files)
2010-01-14 19:14:37 +02:00
unsigned slot = Kernel::alloc_slot ()
caps.use (slot)
2010-01-16 17:13:54 +02:00
Kernel::free_cap (caps)
2010-01-14 19:14:37 +02:00
for unsigned i = 0; i < num_files; ++i:
String n = root.get_name (i)
n.get_chars (0, files[i].name)
2010-01-16 17:13:54 +02:00
Kernel::free_cap (n)
Kernel::set_recv_arg (Kernel::Cap (slot, i))
2010-01-14 19:14:37 +02:00
files[i].string = root.get_file_ro (i)
Kernel::Num fullsize = files[i].string.get_size ()
if fullsize.h != 0:
2010-01-16 17:13:54 +02:00
kdebug ("initial file size too large: ")
kdebug_num (fullsize.h)
kdebug (":")
kdebug_num (fullsize.l)
kdebug (".\n")
2010-01-14 19:14:37 +02:00
Kernel::panic (0)
files[i].size = fullsize.l
2010-01-16 17:13:54 +02:00
if max_pages < (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS:
max_pages = (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS
2010-01-14 19:14:37 +02:00
// 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 ()
2010-01-16 17:13:54 +02:00
unsigned num_pages = (f->size + PAGE_SIZE - 1) >> PAGE_BITS
2010-01-14 19:14:37 +02:00
for unsigned p = 0; p < num_pages; ++p:
2010-01-17 11:01:42 +02:00
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (num_pages)
//kdebug ("\n")
2010-01-14 19:14:37 +02:00
Kernel::set_recv_arg (Kernel::Cap (slot, p))
2010-01-16 17:13:54 +02:00
Kernel::my_memory.create_page ()
Kernel::Page (slot, p).set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
2010-01-14 19:14:37 +02:00
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:
2010-01-16 17:13:54 +02:00
kdebug ("invalid ELF class:")
kdebug_num (header->e_ident[EI_CLASS])
kdebug (" != ")
kdebug_num (ELFCLASS32)
kdebug ("\n")
2010-01-14 19:14:37 +02:00
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
2010-01-16 17:13:54 +02:00
Kernel::free_cap (page)
2010-01-14 19:14:37 +02:00
page = mem.create_page ()
2010-01-17 11:01:42 +02:00
unsigned f
if readonly:
f = Kernel::Page::PAYING | Kernel::Page::MAPPED_READONLY
else:
f = Kernel::Page::PAYING
page.set_flags (f, f)
2010-01-14 19:14:37 +02:00
Kernel::Page (slot, idx).share (page, 0)
2010-01-17 11:01:42 +02:00
//kdebug ("mapping at ")
//kdebug_num (p)
//if readonly:
// kdebug (" (readonly)")
//kdebug ("\n")
if !mem.map (page, p):
2010-01-14 19:14:37 +02:00
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:
2010-01-16 17:13:54 +02:00
// No error means there is a mapping.
Kernel::free_cap (page)
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
else:
Kernel::free_cap (page)
2010-01-14 19:14:37 +02:00
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)
2010-01-17 11:01:42 +02:00
for unsigned p = 0; p < num_pages; ++p:
2010-01-16 17:13:54 +02:00
Kernel::my_memory.destroy (Kernel::Page (slot, p))
2010-01-14 19:14:37 +02:00
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)
2010-01-17 11:01:42 +02:00
Kernel::free_cap (caps)
2010-01-18 06:01:59 +02:00
static void kdebug_name (char const *t, file *f):
kdebug (t)
for unsigned j = 0; j < 16; ++j:
if f->name[j] != 0:
kdebug_char (f->name[j])
kdebug ("...")
2010-01-18 07:45:52 +02:00
struct Dev:
static Dev *devs
Dev *next
unsigned code, idx
Device dev
static Dev *find (unsigned c, unsigned i):
for Dev *d = devs; d; d = d->next:
if d->code == c && d->idx == i:
return d
return NULL
static void add (unsigned c, unsigned i, Kernel::Cap cap):
while find (c, i):
++i
Dev *d = new Dev ()
d->next = devs
d->code = c
d->idx = i
d->dev = cap
devs = d
static void kdebug_list ():
for Dev *d = devs; d; d = d->next:
kdebug (">")
kdebug_num (d->code)
kdebug (":")
kdebug_num (d->idx)
Dev *Dev::devs
void handle_init ():
while true:
Kernel::wait ()
switch Kernel::recv.data[0].l:
case Parent::PROVIDE_DEVICE:
2010-01-18 08:31:19 +02:00
kdebug ("adding dev ")
2010-01-18 07:45:52 +02:00
kdebug_num (Kernel::recv.data[1].l)
kdebug (":")
kdebug_num (Kernel::recv.data[0].h)
kdebug ("\n")
2010-01-18 08:31:19 +02:00
Kernel::Cap reply = Kernel::get_reply ()
Dev::add (Kernel::recv.data[1].l, Kernel::recv.data[0].h, Kernel::get_arg ())
reply.invoke ()
Kernel::free_cap (reply)
2010-01-18 07:45:52 +02:00
break
case Parent::GET_DEVICE:
2010-01-18 08:31:19 +02:00
Kernel::Cap reply = Kernel::get_reply ()
2010-01-18 07:45:52 +02:00
Dev *d = Dev::find (Kernel::recv.data[1].l, Kernel::recv.data[0].h)
if d:
2010-01-18 08:31:19 +02:00
kdebug ("giving dev ")
2010-01-18 07:45:52 +02:00
kdebug_num (Kernel::recv.data[1].l)
kdebug (":")
kdebug_num (Kernel::recv.data[0].h)
kdebug ("\n")
Kernel::Cap cap = d->dev.create_user (Kernel::my_memory)
d->dev.use (cap)
2010-01-18 08:31:19 +02:00
reply.invoke (0, 0, cap.copy ())
2010-01-18 07:45:52 +02:00
Kernel::free_cap (cap)
else:
kdebug ("device not found: ")
kdebug_num (Kernel::recv.data[1].l)
kdebug (":")
kdebug_num (Kernel::recv.data[0].h)
Dev::kdebug_list ()
kdebug ("\n")
2010-01-18 08:31:19 +02:00
reply.invoke (~0, ~0)
2010-01-18 07:45:52 +02:00
Kernel::panic (0)
2010-01-18 08:31:19 +02:00
Kernel::free_cap (reply)
2010-01-18 07:45:52 +02:00
break
case Parent::INIT_DONE:
return
default:
kdebug ("unknown init request\n")
Kernel::panic (0)
2009-09-06 12:04:09 +03:00
Kernel::Num start ():
2010-01-14 19:14:37 +02:00
// Wait for the debugging device to be active, in case there is one.
2009-12-26 15:17:06 +02:00
Kernel::schedule ()
2010-01-18 08:31:19 +02:00
Dev::devs = NULL
2010-01-16 17:13:54 +02:00
init_alloc ()
2010-01-14 19:14:37 +02:00
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:
2010-01-18 06:01:59 +02:00
kdebug_name ("loading ", &files[index[i]])
2010-01-14 19:14:37 +02:00
run (&files[index[i]], files[index[i]].name[0] == '#')
2010-01-18 06:01:59 +02:00
kdebug ("running\n")
2010-01-18 07:45:52 +02:00
handle_init ()
2010-01-18 08:31:19 +02:00
kdebug ("init done\n")
2010-01-14 19:14:37 +02:00
root.unlock_ro ()
Kernel::free_slot (slot)
Kernel::my_memory.destroy (caps)
2010-01-17 11:01:42 +02:00
while true:
2010-01-18 07:45:52 +02:00
handle_init ()
//Kernel::wait ()
//kdebug ("request!\n")