mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
work on device swapping
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "devices.hh"
|
||||
#include "iris.hh"
|
||||
#include "keys.hh"
|
||||
#include <elf.h>
|
||||
|
||||
#define NUM_SLOTS 8
|
||||
@@ -26,6 +27,7 @@
|
||||
enum Cap_codes:
|
||||
SYSREQ = 1 << 16
|
||||
THREAD
|
||||
KEYBOARD
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
@@ -79,6 +81,7 @@ static Kernel::Caps terminals
|
||||
static unsigned terminal_slot
|
||||
static Kernel::Caps memories
|
||||
static unsigned memory_slot
|
||||
static unsigned *inuse
|
||||
|
||||
// Get the initial block device and filesystem.
|
||||
static Directory receive_devices ():
|
||||
@@ -89,30 +92,24 @@ static Directory receive_devices ():
|
||||
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)
|
||||
Kernel::panic (Kernel::recv.data[0].l, "Invalid bootstrap request.")
|
||||
switch Kernel::recv.data[1].l:
|
||||
case String::ID:
|
||||
if have_data:
|
||||
kdebug ("duplicate device.\n")
|
||||
Kernel::panic (0)
|
||||
Kernel::panic (0, "duplicate device.")
|
||||
data_dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
have_data = true
|
||||
break
|
||||
case Filesystem::ID:
|
||||
if have_fs:
|
||||
kdebug ("duplicate filesystem.\n")
|
||||
Kernel::panic (0)
|
||||
Kernel::panic (0, "duplicate filesystem.")
|
||||
fs_dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
have_fs = true
|
||||
break
|
||||
default:
|
||||
kdebug ("unexpected device: ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug_char ('\n')
|
||||
Kernel::panic (0)
|
||||
Kernel::panic (Kernel::recv.data[1].l, "unexpected device")
|
||||
// Initialize the root file system.
|
||||
data = data_dev.create_user (Kernel::my_memory)
|
||||
data_dev.use (data)
|
||||
@@ -204,8 +201,7 @@ static void run (file *f, bool priv, int id):
|
||||
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)
|
||||
Kernel::panic (header->e_ident[j], "invalid ELF magic")
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class:")
|
||||
@@ -216,21 +212,13 @@ static void run (file *f, bool priv, int id):
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
kdebug ("invalid ELF data\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (header->e_ident[EI_DATA], "invalid ELF data")
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
kdebug ("invalid ELF version\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (header->e_ident[EI_VERSION], "invalid ELF version")
|
||||
if header->e_type != ET_EXEC:
|
||||
kdebug ("invalid ELF type\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (header->e_type, "invalid ELF type")
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
kdebug ("invalid ELF machine\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (header->e_machine, "invalid ELF machine")
|
||||
thread.set_pc (header->e_entry)
|
||||
thread.set_sp (0x80000000)
|
||||
for unsigned section = 0; section < header->e_shnum; ++section:
|
||||
@@ -242,8 +230,7 @@ static void run (file *f, bool priv, int id):
|
||||
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)
|
||||
Kernel::panic (shdr->sh_size, "thread too large")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
@@ -268,14 +255,12 @@ static void run (file *f, bool priv, int id):
|
||||
// kdebug (" (readonly)")
|
||||
//kdebug ("\n")
|
||||
if !mem.map (page, p):
|
||||
kdebug ("unable to map page\n")
|
||||
Kernel::panic (0)
|
||||
Kernel::panic (0, "unable to map page")
|
||||
return
|
||||
Kernel::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
kdebug ("unwritable bss section\n")
|
||||
Kernel::panic (0)
|
||||
Kernel::panic (0, "unwritable bss section")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
Kernel::Page page = mem.mapping ((void *)p)
|
||||
@@ -292,26 +277,18 @@ static void run (file *f, bool priv, int id):
|
||||
Kernel::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Kernel::recv.data[0].l != Kernel::NO_ERROR:
|
||||
kdebug ("out of memory\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (Kernel::recv.data[0].l, "out of memory")
|
||||
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
|
||||
kdebug ("out of memory\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (0, "out of memory")
|
||||
if !mem.map (page, p):
|
||||
kdebug ("unable to map bss page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (0, "unable to map bss page")
|
||||
Kernel::free_cap (page)
|
||||
for unsigned p = 0; p < num_pages; ++p:
|
||||
Kernel::my_memory.destroy (Kernel::Page (slot, p))
|
||||
Kernel::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
if Kernel::recv.data[0].l != Kernel::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
|
||||
kdebug ("unable to map initial stack page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::panic (Kernel::recv.data[0].l, "unable to map initial stack page")
|
||||
Kernel::free_cap (stackpage)
|
||||
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
|
||||
thread.use (caps, 0)
|
||||
@@ -405,6 +382,8 @@ static void get_device ():
|
||||
unsigned id = Kernel::recv.protected_data.l
|
||||
Dev *d = Dev::find (Kernel::recv.data[1].l, Kernel::recv.data[0].h)
|
||||
if d:
|
||||
if inuse[id * Dev::num_devs + d->id] > 0:
|
||||
Kernel::panic (id, "requesting device twice")
|
||||
kdebug ("giving dev ")
|
||||
kdebug_num (Kernel::recv.data[1].l)
|
||||
kdebug (":")
|
||||
@@ -414,7 +393,12 @@ static void get_device ():
|
||||
kdebug (" to ")
|
||||
kdebug_num (id)
|
||||
kdebug ("\n")
|
||||
Kernel::Cap cap = Kernel::Caps (terminal_slot, id).get (d->id)
|
||||
Kernel::Cap cap = d->dev.create_user (Kernel::Memory (memory_slot, id), 0, 0x15000)
|
||||
Kernel::Caps (terminal_slot, id).set (d->id, cap.copy ())
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
if inuse[i * Dev::num_devs + d->id] == 2:
|
||||
inuse[i * Dev::num_devs + d->id] = 1
|
||||
inuse[id * Dev::num_devs + d->id] = 2
|
||||
d->dev.use (cap)
|
||||
reply.invoke (0, 0, cap.copy ())
|
||||
Kernel::free_cap (cap)
|
||||
@@ -453,6 +437,10 @@ Kernel::Num start ():
|
||||
run (&files[index[i]], files[index[i]].name[0] == '#', i)
|
||||
kdebug ("running\n")
|
||||
handle_init (i)
|
||||
inuse = new unsigned[num_files * Dev::num_devs]
|
||||
for unsigned f = 0; f < num_files; ++f:
|
||||
for unsigned d = 0; d < Dev::num_devs; ++d:
|
||||
inuse[f * Dev::num_devs + d] = 0
|
||||
// Notify all programs that they may start.
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
Kernel::Cap (memory_slot, i + num_files).invoke ()
|
||||
@@ -462,12 +450,6 @@ Kernel::Num start ():
|
||||
Kernel::Memory mem (memory_slot, i)
|
||||
Kernel::set_recv_arg (term)
|
||||
mem.create_caps (Dev::num_devs)
|
||||
unsigned termslot = term.use ()
|
||||
for Dev *d = Dev::devs; d; d = d->next:
|
||||
Kernel::set_recv_arg (Kernel::Cap (termslot, d->id))
|
||||
// The 0x15000 is for the Display; the others don't care about it.
|
||||
d->dev.create_user (mem, 0, 0x15000)
|
||||
Kernel::free_slot (termslot)
|
||||
// set up system request.
|
||||
Keyboard sysreq = sysreq_dev.create_user (Kernel::my_memory)
|
||||
sysreq_dev.use (sysreq)
|
||||
@@ -476,10 +458,22 @@ Kernel::Num start ():
|
||||
sysreq.set_cb (cap.copy ())
|
||||
Kernel::free_cap (sysreq)
|
||||
Kernel::free_cap (cap)
|
||||
// set up own capabilities.
|
||||
Dev *display_dev = Dev::find (Display::ID, 0)
|
||||
if !display_dev:
|
||||
Kernel::panic (0, "no display")
|
||||
Display display = display_dev->dev.create_user (Kernel::my_memory, 0, 0x15000)
|
||||
Dev *keyboard_dev = Dev::find (Keyboard::ID, 0)
|
||||
if !keyboard_dev:
|
||||
Kernel::panic (0, "no keyboard")
|
||||
Keyboard keyboard = keyboard_dev->dev.create_user (Kernel::my_memory, 0, 0x15000)
|
||||
kdebug ("init done\n")
|
||||
root.unlock_ro ()
|
||||
Kernel::free_slot (slot)
|
||||
Kernel::my_memory.destroy (caps)
|
||||
Dev **waiter = new Dev *[num_files]
|
||||
Kernel::Cap keyboard_cb = Kernel::my_receiver.create_capability (Kernel::Num (0, KEYBOARD))
|
||||
bool in_system = false
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
@@ -487,7 +481,10 @@ Kernel::Num start ():
|
||||
// System request.
|
||||
if Kernel::recv.data[0].l & Keyboard::RELEASE:
|
||||
continue
|
||||
kdebug ("system request...\n")
|
||||
keyboard_dev->dev.use (keyboard)
|
||||
display_dev->dev.use (display)
|
||||
keyboard.set_cb (keyboard_cb)
|
||||
in_system = true
|
||||
continue
|
||||
case THREAD:
|
||||
// Request for something from a child thread.
|
||||
@@ -499,10 +496,59 @@ Kernel::Num start ():
|
||||
case Parent::GET_DEVICE:
|
||||
get_device ()
|
||||
break
|
||||
case Parent::WAIT:
|
||||
unsigned id = Kernel::recv.protected_data.l
|
||||
Dev *dev = Dev::find (Kernel::recv.data[1].l, 0)
|
||||
if id >= num_files:
|
||||
Kernel::panic (0, "invalid id")
|
||||
if !dev:
|
||||
Kernel::panic (0, "invalid dev")
|
||||
switch inuse[id * Dev::num_devs + dev->id]:
|
||||
case 0:
|
||||
Kernel::panic (0, "waiting for non-owned device")
|
||||
case 2:
|
||||
if !in_system:
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
// fall through.
|
||||
case 1:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
memories.set (id + num_files, reply.copy ())
|
||||
Kernel::free_cap (reply)
|
||||
waiter[id] = dev
|
||||
break
|
||||
break
|
||||
case Parent::EXIT:
|
||||
Kernel::panic (Kernel::recv.protected_data.l, "exit is not supported")
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.data[0].l, "invalid operation from child")
|
||||
break
|
||||
case KEYBOARD:
|
||||
if in_system && Kernel::recv.data[0].l == (Key::ENTER | Keyboard::RELEASE):
|
||||
for Dev *d = Dev::devs; d; d = d->next:
|
||||
if d->idx != 0:
|
||||
continue
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
if inuse[i * Dev::num_devs + d->id] == 2:
|
||||
Kernel::Cap c = Kernel::Caps (terminal_slot, i).get (d->id)
|
||||
d->dev.use (c)
|
||||
Kernel::free_cap (c)
|
||||
if waiter[i] == d:
|
||||
Kernel::Cap (memory_slot, i + num_files).invoke ()
|
||||
waiter[i] = NULL
|
||||
in_system = false
|
||||
break
|
||||
if Kernel::recv.data[0].l & Keyboard::RELEASE:
|
||||
continue
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Key::UP:
|
||||
case Key::DOWN:
|
||||
case Key::LEFT:
|
||||
case Key::RIGHT:
|
||||
case Key::VOLUME_UP:
|
||||
case Key::VOLUME_DOWN:
|
||||
kdebug ("key pressed.\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
Kernel::panic (Kernel::recv.protected_data.h, "unknown source of request")
|
||||
|
||||
Reference in New Issue
Block a user