1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-05 06:43:44 +02:00
iris/source/elfrun.ccp
2010-06-06 23:03:25 +02:00

305 lines
11 KiB
COBOL

#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/elfrun.ccp: Process creation server.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "devices.hh"
#include "iris.hh"
#include <elf.h>
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + (pages << PAGE_BITS)
return (char *)ret
void *operator new[] (unsigned size):
//kdebug ("new ")
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
Iris::free_cap (page)
_free += size
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
return ret
void *operator new (unsigned size):
return new char[size]
static Iris::Memory parent_memory
static Iris::Cap parent
static unsigned slot
static char *mapping
static unsigned pages
static Iris::Caps pages_caps
static Iris::Memory mem
static unsigned *bss_mapping
static Iris::Page bss_page
static Iris::Caps map_string (Iris::String data):
// Get the size.
Iris::Num size = data.get_size ()
if size.value () == 0:
Iris::panic (0, "data string is empty")
// Allocate a caps with all the pages.
pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
pages_caps = Iris::my_memory.create_caps (pages)
slot = pages_caps.use ()
// Map them into the address space as well.
mapping = alloc_space (pages)
// Create a memory for the program.
mem = parent_memory.create_memory ()
// Load the file into memory and map it.
for unsigned p = 0; p < pages; ++p:
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (pages)
//kdebug ("\n")
Iris::set_recv_arg (Iris::Cap (slot, p))
data.get_block (p << PAGE_BITS)
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
static Iris::Caps map_caps (Iris::Caps data, unsigned p):
// Get the size.
if p == 0:
Iris::panic (0, "data caps is empty")
// Allocate a new caps with all the pages for mapping locally.
pages = p
pages_caps = Iris::my_memory.create_caps (pages)
slot = pages_caps.use ()
unsigned src_slot = data.use ()
// Map them into the address space as well.
mapping = alloc_space (pages)
// Create a memory for the program.
mem = parent_memory.create_memory ()
// Load the file into memory and map it.
for unsigned p = 0; p < pages; ++p:
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (pages)
//kdebug ("\n")
Iris::Page page = Iris::Cap (slot, p)
Iris::set_recv_arg (page)
Iris::my_memory.create_page ()
Iris::Page (Iris::Cap (src_slot, p)).share (page)
Iris::my_memory.map (page, (unsigned)&mapping[p << PAGE_BITS])
Iris::free_slot (src_slot)
static Iris::Caps run (Iris::Caps data, Iris::Memory parent_memory, Iris::Cap parent, unsigned num_slots, unsigned num_caps):
Iris::Thread thread = mem.create_thread (num_slots)
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
Iris::panic (header->e_ident[j], "invalid ELF magic")
return Iris::Caps ()
if header->e_ident[EI_CLASS] != ELFCLASS32:
kdebug ("invalid ELF class:")
kdebug_num (header->e_ident[EI_CLASS])
kdebug (" != ")
kdebug_num (ELFCLASS32)
kdebug ("\n")
Iris::panic (0)
return Iris::Caps ()
if header->e_ident[EI_DATA] != ELFDATA2LSB:
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
if header->e_ident[EI_VERSION] != EV_CURRENT:
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
if header->e_type != ET_EXEC:
Iris::panic (header->e_type, "invalid ELF type")
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
Iris::panic (header->e_machine, "invalid ELF machine")
thread.set_pc (header->e_entry)
thread.set_sp (0x80000000)
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
bool readonly = !(shdr->sh_flags & SHF_WRITE)
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS:
//kdebug ("loading ")
//kdebug_num (shdr->sh_addr)
//kdebug ("+")
//kdebug_num (shdr->sh_size)
//kdebug ("\n")
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
kdebug ("thread size: ")
kdebug_num (file_offset)
kdebug (",")
kdebug_num (shdr->sh_size)
kdebug ("\n")
Iris::panic (shdr->sh_size, "thread too large")
return Iris::Caps ()
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
Iris::Page page = mem.mapping ((void *)p)
if Iris::recv.data[0].l == Iris::NO_ERROR:
// The address already has a mapping; assume that it is correct.
Iris::free_cap (page)
continue
Iris::free_cap (page)
page = mem.create_page ()
unsigned f
if readonly:
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
else:
f = Iris::Page::PAYING
page.set_flags (f, f)
Iris::Page (slot, idx).share (page, 0)
//kdebug ("mapping at ")
//kdebug_num (p)
//if readonly:
// kdebug (" (readonly)")
//kdebug ("\n")
if !mem.map (page, p):
Iris::panic (0, "unable to map page")
return Iris::Caps ()
Iris::free_cap (page)
else:
if readonly:
Iris::panic (0, "unwritable bss section")
return Iris::Caps ()
//kdebug ("clearing ")
//kdebug_num (shdr->sh_addr)
//kdebug ("+")
//kdebug_num (shdr->sh_size)
//kdebug ("\n")
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Iris::Page page = mem.mapping ((void *)p)
if Iris::recv.data[0].l == Iris::NO_ERROR:
// No error means there is a mapping.
page.share (bss_page, 0)
Iris::free_cap (page)
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
else:
Iris::free_cap (page)
page = mem.create_page ()
if Iris::recv.data[0].l != Iris::NO_ERROR:
Iris::panic (Iris::recv.data[0].l, "out of memory")
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
Iris::panic (0, "out of memory")
if !mem.map (page, p):
Iris::panic (0, "unable to map bss page")
Iris::free_cap (page)
//kdebug ("start of program:\n")
//for unsigned i = 0; i < 0x40; i += 4:
// kdebug_num ((unsigned)mapping + 4 * i, 3)
// kdebug (" ==>")
// for unsigned j = 0; j < 4; j += 1:
// kdebug (" ")
// kdebug_num (((unsigned *)mapping)[i + j])
// kdebug ("\n")
for unsigned p = 0; p < pages; ++p:
Iris::my_memory.destroy (Iris::Page (slot, p))
Iris::my_memory.destroy (pages_caps)
Iris::free_slot (slot)
Iris::free_cap (pages_caps)
Iris::Page stackpage = mem.create_page ()
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
Iris::free_cap (stackpage)
Iris::Caps caps = mem.create_caps (num_caps)
thread.use (caps, 0)
thread.set_info (Iris::Thread::A0, num_slots)
thread.set_info (Iris::Thread::A1, num_caps)
Iris::Receiver receiver = mem.create_receiver ()
receiver.set_owner (thread.copy ())
Iris::Cap call = receiver.create_call_capability ()
caps.set (__caps_num, caps.copy ())
caps.set (__receiver_num, receiver.copy ())
caps.set (__thread_num, thread.copy ())
caps.set (__memory_num, mem.copy ())
caps.set (__call_num, call.copy ())
caps.set (__parent_num, parent.copy ())
Iris::free_cap (receiver)
Iris::free_cap (thread)
Iris::free_cap (mem)
Iris::free_cap (call)
return caps
Iris::Num start ():
kdebug ("elfrun started.\n")
init_alloc ()
Iris::Elfrun dev = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_capability <Iris::Elfrun> (dev.copy ())
Iris::free_cap (dev)
bss_mapping = (unsigned *)alloc_space (1)
bss_page = Iris::my_memory.create_page ()
Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
while true:
Iris::wait ()
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
switch Iris::recv.data[0].l:
case Iris::Elfrun::RUN_STRING:
unsigned num_slots = Iris::recv.data[1].l
unsigned num_caps = Iris::recv.data[1].h
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
Iris::String data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
map_string (data)
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
reply.invoke (0, 0, ret.copy ())
free_cap (ret)
free_cap (parent_memory)
free_cap (parent)
free_cap (data)
break
case Iris::Elfrun::RUN_CAPS:
unsigned num_slots = Iris::recv.data[1].l
unsigned num_caps = Iris::recv.data[1].h
unsigned p = Iris::recv.data[0].h
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
Iris::Caps data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
map_caps (data, p)
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
reply.invoke (0, 0, ret.copy ())
free_cap (ret)
free_cap (parent_memory)
free_cap (parent)
free_cap (data)
break
default:
Iris::panic (0, "invalid operation for elfrun")
reply.invoke (~0)
break
Iris::free_cap (arg)
Iris::free_cap (reply)