1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-04-21 12:27:27 +03:00

new directory organization

This commit is contained in:
Bas Wijnen
2013-05-14 18:30:50 -04:00
parent b06e011a07
commit fa021a80f0
62 changed files with 133 additions and 2572 deletions

View File

@@ -0,0 +1,54 @@
#pypp 0
// vim: set filetype=cpp : //
#include <iris.hh>
#include <devices.hh>
enum captypes:
CONTROL = 1
KBD
INTERRUPT
Iris::Num start ():
unsigned *screen = (unsigned *)0x40000000
Iris::RTC rtc = Iris::my_parent.get_capability <Iris::RTC> ()
Iris::Display display = Iris::my_parent.get_capability <Iris::Display> ()
display.map_fb ((unsigned)screen)
Iris::Font font = Iris::my_parent.get_capability <Iris::Font> ()
font.set_display (display)
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
Iris::Cap cap = Iris::my_receiver.create_capability (KBD)
keyboard.set_cb (cap.copy ())
Iris::free_cap (cap)
Iris::Buzzer buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
Iris::Event self = Iris::my_receiver.create_capability (CONTROL)
Iris::my_parent.provide_capability <Iris::Event> (self)
cap = Iris::my_receiver.create_capability (INTERRUPT)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case INTERRUPT:
// RTC alarm interrupt.
if Iris::recv.data[0].l == ~0:
// Not a real interrupt, just an abort notification.
continue
font.printf ("alarm: RTC alarm interrupt\n")
break
case CONTROL:
// Store callback
font.printf ("alarm: control event\n")
break
case KBD:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
// Key release.
Iris::poweroff ()
else:
// Key press.
unsigned time = rtc.get_time ()
rtc.set_alarm (time + 5, cap)
unsigned alarm = rtc.get_alarm ()
unsigned enabled = Iris::recv.data[1].l
font.printf ("Debug: %d %d %d\n", time, alarm, enabled)
break
default:
Iris::panic (Iris::recv.protected_data.l, "invalid request for alarm")

View File

@@ -0,0 +1,62 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/ball.ccp: Bouncing ball demo.
// 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>
static unsigned *framebuffer
static int const r = 10
void ball (int x, int y, unsigned colour):
for int ty = y - r; ty < y + r; ++ty:
if ty < 0 || ty >= 240:
continue
for int tx = x - r; tx < x + r; ++tx:
if tx < 0 || tx >= 320:
continue
if (x - tx) * (x - tx) + (y - ty) * (y - ty) > r * r:
continue
framebuffer[ty * 320 + tx] = (colour)
Iris::Num start ():
Iris::my_parent.init_done ()
int colour = 0x3f30ff
framebuffer = (unsigned *)0x15000
Iris::Display display = Iris::my_parent.get_capability <Iris::Display> ()
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
int x = r, y = r, dx = 3, dy = 0
Iris::Cap eof = Iris::my_receiver.create_capability (0)
while true:
display.set_eof_cb (eof)
Iris::wait ()
ball (x, y, 0)
x += dx
y += dy
if y + r >= 240:
dy = -dy
y = 240 - r
if x - r < 0:
x = r
dx = -dx
if x + r >= 320:
x = 320 - r
dx = -dx
if y == 240 - r && dy == 0:
dy = -21
++dy
ball (x, y, colour)

View File

@@ -0,0 +1,28 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/booter.ccp: Boot into another kernel.
// Copyright 2010 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>
Iris::Num start ():
Iris::String data = Iris::my_parent.get_capability <Iris::String> ()
Iris::Boot boot = Iris::my_parent.get_capability <Iris::Boot> ()
//boot.boot (data, 0x81fff000, 0x81fff000)
boot.boot (data, 0xa1fff000, 0xa1fff000)
Iris::panic (0, "boot returns")
return 0

View File

@@ -0,0 +1,60 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/bsquare.ccp: Floating square demo.
// 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>
static unsigned *framebuffer
static int const r = 10
static int colour
void square (int x, int y, bool print):
for int ty = y - r; ty < y + r; ++ty:
if ty < 0 || ty >= 240:
continue
for int tx = x - r; tx < x + r; ++tx:
if tx < 0 || tx >= 320:
continue
framebuffer[ty * 320 + tx] = (print ? colour : 0)
Iris::Num start ():
Iris::my_parent.init_done ()
colour = 0xffff00
framebuffer = (unsigned *)0x15000
Iris::Display display = Iris::my_parent.get_capability <Iris::Display> (0x10001)
int x = r, y = r, dx = 3, dy = 3
Iris::Cap eof = Iris::my_receiver.create_capability (0)
while true:
display.set_eof_cb (eof)
Iris::wait ()
square (x, y, false)
x += dx
y += dy
if y + r >= 240:
dy = -dy
y = 240 - r
if x - r < 0:
x = r
dx = -dx
if x + r >= 320:
x = 320 - r
dx = -dx
if y - r < 0:
y = r
dy = -dy
square (x, y, true)

View File

@@ -0,0 +1,71 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/metronome.ccp: Userspace program.
// 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 "keys.hh"
Iris::Num start ():
Iris::my_parent.init_done ()
Iris::Buzzer buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
Iris::Keyboard kbd = Iris::my_parent.get_capability <Iris::Keyboard> ()
Iris::Cap key = Iris::my_receiver.create_capability (0)
kbd.set_cb (key)
// Frequency of the pulse train in millihertz.
unsigned mHz = 1000
// Frequency of single pulses in hertz.
unsigned freq = 1000
bool running (false)
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case ~0:
if running:
buzzer.beep (freq, 10, ~0)
Iris::my_receiver.set_alarm (HZ * 1000 / mHz)
break
case 0:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
break
switch Iris::recv.data[0].l:
case Key::VOLUME_UP:
freq = freq * 11 / 10
break
case Key::VOLUME_DOWN:
freq = freq * 9 / 10
break
case Key::LEFT:
mHz = mHz * 99 / 100
break
case Key::RIGHT:
mHz = mHz * 101 / 100
break
case Key::UP:
mHz = mHz * 11 / 10
break
case Key::DOWN:
mHz = mHz * 9 / 10
break
case Key::P:
running = !running
if running:
Iris::my_receiver.set_alarm (0)
break
break
default:
kdebug ("metronome: huh?\n")
break

View File

@@ -0,0 +1,58 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/test.ccp: Testing program.
// 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>
bool match (char const *a, char const *b, unsigned l1, unsigned l2):
if l1 != l2:
return false
for unsigned i = 0; i < l1; ++i:
if a[i] != b[i]:
return false
return true
static bool print_name (Iris::String name, unsigned indent):
unsigned l = name.get_size ().l
for unsigned i = 0; i < indent; ++i:
kdebug_char (' ')
char part[16]
for unsigned i = 0; i < l; i += 16:
name.get_chars (i, part)
for unsigned k = 0; k < 16 && i * 16 + k < l; ++k:
kdebug_char (part[k])
kdebug_char ('\n')
return match (part, ".", l, 1) || match (part, "..", l, 2)
static void print_dir (Iris::Directory dir, unsigned indent):
dir.lock_ro ()
Iris::Num files = dir.get_size ()
for Iris::Num i = 0; i.value () < files.value (); i = i.value () + 1:
Iris::String f = dir.get_name (i)
bool ignore = print_name (f, indent)
if !ignore && dir.get_file_info (i, 0).l & 1:
Iris::Directory d = dir.get_file_ro (i)
print_dir (d, indent + 4)
Iris::free_cap (d)
Iris::free_cap (f)
dir.unlock_ro ()
Iris::Num start ():
Iris::Directory dir = Iris::my_parent.get_capability <Iris::Directory> ()
print_dir (dir, 0)
return 0

380
userspace/boot/bootinit.ccp Normal file
View File

@@ -0,0 +1,380 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/bootinit.ccp: Bootstrapping code.
// Copyright 2009-2010 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>
#define ELFRUN_NAME "elfrun.elf"
#define INIT_NAME "init.elf"
// These numbers are only used for elfrun.
#define NUM_SLOTS 8
#define NUM_CAPS 32
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::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 unsigned *bss_mapping
static Iris::Page bss_page
// Get the initial block device and filesystem.
static Iris::Directory receive_devices ():
Iris::Block device
bool have_device = false
Iris::Cap reply[2]
bool have_reply[2]
have_reply[0] = false
have_reply[1] = false
unsigned next = 2
while true:
Iris::wait ()
kdebug_num (Iris::recv.protected_data.l, 1)
kdebug (": ")
if Iris::recv.protected_data.l == 0:
kdebug ("sd detect event device request\n")
// SD detection event device request.
// Ignore all; that will result in the driver thinking there is a card.
Iris::recv.reply.invoke ()
continue
switch Iris::recv.data[0].l:
case Iris::Parent::PROVIDE_CAPABILITY:
switch Iris::recv.data[1].l:
case Iris::Block::ID:
case Iris::WBlock::ID:
// Ignore other partitions.
Iris::Cap r = Iris::get_reply ()
if Iris::recv.data[0].h != 0:
kdebug ("ignoring non-0 partition\n")
else:
if have_device:
Iris::panic (0, "double device provided")
device = Iris::get_arg ()
if have_reply[next - 2]:
kdebug ("block provided (used)\n")
reply[next++ - 2].invoke (0, 0, device.copy ())
Iris::free_cap (device)
else:
kdebug ("block provided (stored)\n")
have_device = true
r.invoke ()
Iris::free_cap (r)
break
case Iris::Directory::ID:
kdebug ("directory provided\n")
Iris::Directory ret = Iris::get_arg ()
Iris::recv.reply.invoke ()
return ret
default:
Iris::panic (Iris::recv.data[1].l, "invalid capability type provided by boot thread")
break
case Iris::Parent::GET_CAPABILITY:
if Iris::recv.data[1].l == Iris::Event::ID:
kdebug ("event requested\n")
// Detection of sd card.
Iris::Cap reply = Iris::get_reply ()
Iris::Cap event = Iris::my_receiver.create_capability (0)
reply.invoke (0, 0, event.copy ())
Iris::free_cap (event)
Iris::free_cap (reply)
break
if Iris::recv.data[1].l != Iris::Block::ID && Iris::recv.data[1].l != Iris::WBlock::ID:
Iris::panic (Iris::recv.data[1].l, "invalid capability type requested by boot thread")
if next == Iris::recv.protected_data.l && have_device:
kdebug ("block requested (sent)\n")
Iris::recv.reply.invoke (0, 0, device.copy ())
Iris::free_cap (device)
have_device = false
++next
else:
kdebug ("block requested (not sent)\n")
reply[Iris::recv.protected_data.l - 2] = Iris::get_reply ()
have_reply[Iris::recv.protected_data.l - 2] = true
break
case Iris::Parent::INIT_DONE:
kdebug ("init done\n")
// Ignore.
Iris::recv.reply.invoke ()
break
case Iris::Parent::EXIT:
Iris::panic (Iris::recv.protected_data.l, "boot thread exits")
default:
Iris::panic (Iris::recv.protected_data.l, "invalid boot request")
static bool stringcmp (char const *s1, char const *s2, unsigned size):
for unsigned t = 0; t < size; ++t:
if s1[t] != s2[t]:
return false
return true
static Iris::Block find (Iris::Directory root, char const *name):
unsigned size = 0
while name[size]:
++size
Iris::Num num_files = root.get_size ()
for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
Iris::String n = root.get_name (i)
char current_name[16]
n.get_chars (0, current_name)
Iris::free_cap (n)
if !stringcmp (current_name, name, size):
continue
// Found elfrun.
Iris::Block ret = root.get_file_ro (i)
return ret
Iris::panic (0, "bootfile not found")
static void run (Iris::Block data, Iris::Memory parent_memory, Iris::Cap parent):
// Get the size.
Iris::Num size = data.get_size ()
if size.value () == 0:
Iris::panic (0, "elfrun is empty")
// Allocate a caps with all the pages.
unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
unsigned slot = pages_caps.use ()
// Map them into the address space as well.
char *mapping = alloc_space (pages)
// Create a memory for the program.
Iris::Memory 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))
Iris::my_memory.create_page ()
Iris::Page (slot, p).set_flags (Iris::Page::PAYING)
data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, Iris::Cap (slot, p))
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
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
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
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:
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
Iris::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
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)
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::free_cap (page)
else:
if readonly:
Iris::panic (0, "unwritable bss section")
return
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::panic (0, "out of memory")
if !mem.map (page, p):
Iris::panic (0, "unable to map bss page")
Iris::free_cap (page)
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::Page stackpage = mem.create_page ()
stackpage.set_flags (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)
thread.run ()
Iris::free_cap (receiver)
Iris::free_cap (thread)
Iris::free_cap (call)
Iris::free_cap (caps)
Iris::Num start ():
// Wait for the debugging device to be active, in case there is one.
Iris::schedule ()
kdebug ("Starting bootinit\n")
init_alloc ()
bss_mapping = (unsigned *)alloc_space (1)
bss_page = Iris::my_memory.create_page ()
Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
Iris::Memory top_memory = Iris::get_top_memory ()
Iris::Directory root = receive_devices ()
root.lock_ro ()
Iris::Block run_block = find (root, ELFRUN_NAME)
Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
run (run_block, top_memory, parent_cap)
Iris::wait ()
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
Iris::panic (0, "elfrun doesn't provide correct capability")
Iris::Cap reply = Iris::get_reply ()
Iris::Elfrun elfrun = Iris::get_arg ()
Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
Iris::free_cap (parent_cap)
reply.invoke ()
Iris::free_cap (reply)
parent_cap = Iris::my_receiver.create_capability (0)
Iris::Block init_block = find (root, INIT_NAME)
Iris::Caps init_caps = elfrun.run_block (top_memory.copy (), init_block.copy (), parent_cap.copy (), 8, 63)
Iris::Thread init = init_caps.get (__thread_num)
init.make_priv ()
init.run ()
Iris::free_cap (init)
Iris::free_cap (init_caps)
bool have_root = false
bool have_elfrun = false
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::Parent::GET_CAPABILITY:
switch Iris::recv.data[1].l:
case Iris::Directory::ID:
if have_root:
Iris::panic (0, "Init requests root directory twice")
Iris::recv.reply.invoke (0, 0, root.copy ())
have_root = true
break
case Iris::Elfrun::ID:
if have_elfrun:
Iris::panic (0, "Init requests elfrun twice")
Iris::recv.reply.invoke (0, 0, elfrun.copy ())
have_elfrun = true
break
default:
Iris::panic (0, "Invalid device requested by init")
break
case Iris::Parent::INIT_DONE:
if Iris::recv.data[1].value () != 0:
Iris::recv.reply.invoke ()
break
// Special response: kill boot threads.
Iris::Cap reply = Iris::get_reply ()
root.unlock_ro ()
reply.invoke ()
Iris::free_cap (reply)
top_memory.destroy (Iris::my_memory)
Iris::panic (0, "bootinit should be destroyed")
default:
Iris::panic (Iris::recv.data[0].l, "invalid operation from init")

166
userspace/boot/crt0.ccp Normal file
View File

@@ -0,0 +1,166 @@
#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 Iris:
bool enable_debug
Caps my_caps
Receiver my_receiver
Thread my_thread
Memory my_memory
Cap my_call
Parent my_parent
__recv_data_t recv
void print_caps ():
// __caps cannot be larger than 63.
bool used[63]
for unsigned i = 0; i < __caps; ++i:
used[i] = true
unsigned num = 0
for list *i = __first_free_cap; i; i = i->next:
if used[i - __cap_admin] == false:
panic (0, "inconsistent userspace cap db")
used[i - __cap_admin] = false
++num
kdebug_num (num, 2)
kdebug (":")
for unsigned i = 0; i < __caps; ++i:
kdebug_char (used[i] ? '#' : '.')
kdebug_char ('\n')
void free_slot (unsigned slot):
//kdebug ("free slot\n")
for list *i = __first_free_slot; i; i = i->next:
if slot == i - __slot_admin:
panic (0, "double free of userspace slot")
__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):
if enable_debug:
kdebug ("free cap ")
kdebug_num (cap.idx (), 2)
kdebug ("\n")
for list *i = __first_free_cap; i; i = i->next:
if cap.idx () == i - __cap_admin:
panic (0, "double free of userspace cap")
if cap.slot () != 0:
kdebug ("trying to free capability from non-0 slot\n")
Iris::panic (0)
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")
Iris::panic (0)
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 ():
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n")
Iris::panic (0)
return Cap (0, CAP_NONE)
list *ret = __first_free_cap
__first_free_cap = ret->next
if ret->next:
ret->next->prev = NULL
if enable_debug:
kdebug ("alloc cap ")
kdebug_num (ret - __cap_admin, 2)
kdebug ("\n")
return Cap (0, ret - __cap_admin)
extern "C":
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
Iris::enable_debug = false
__slots = slots
__caps = caps
__slot_admin = slot_admin
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i:
Iris::free_slot (i)
__first_free_cap = NULL
for unsigned i = 6; i < __caps; ++i:
Iris::free_cap (Iris::Cap (0, i))
Iris::my_caps = Iris::Cap (0, __caps_num)
Iris::my_receiver = Iris::Cap (0, __receiver_num)
Iris::my_thread = Iris::Cap (0, __thread_num)
Iris::my_memory = Iris::Cap (0, __memory_num)
Iris::my_call = Iris::Cap (0, __call_num)
Iris::my_parent = Iris::Cap (0, __parent_num)
Iris::recv.reply = Iris::alloc_cap ()
Iris::recv.arg = Iris::alloc_cap ()
Iris::Num ret = start ()
Iris::my_parent.exit (ret)
Iris::my_memory.destroy (Iris::my_thread)
// The program no longer exists. If it somehow does, die again.
while true:
Iris::panic (0, "this program should no longer exist.")
*(volatile unsigned *)~0
__asm__ volatile ("\t.text\n"
"\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")

628
userspace/boot/init.ccp Normal file
View File

@@ -0,0 +1,628 @@
#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"
#include "keys.hh"
#define INIT_CONFIG "init.config"
#define INIT_CONFIG_SIZE 12
#define NUM_SLOTS 8
#define NUM_CAPS 32
enum Captype:
SYSREQ
PROGRAM
FILE
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::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]
template <typename _T> //
struct List:
struct Item:
Item *prev, *next
_T value
_T &operator* ():
return value
_T *operator-> ():
return &value
Item *first
Item *begin ():
return first
void erase (Item *i):
if i->prev:
i->prev->next = i->next
else:
first = i->next
if i->next:
i->next->prev = i->prev
delete i
Item *insert (Item *after = NULL):
Item *ret = new Item
if after:
ret->prev = after->prev
ret->next = after
if ret->prev:
ret->prev->next = ret
else:
first = ret
after->prev = ret
else:
ret->prev = NULL
ret->next = first
first = ret
if ret->next:
ret->next->prev = ret
return ret
void init ():
first = NULL
List () : first (NULL):
struct Program
struct Devbase:
char *name
unsigned name_len
unsigned type
Program *client
Iris::Cap cap
struct Serverdevice : public Devbase:
unsigned index
Program *server
struct Clientdevice:
unsigned type, index
Devbase *dev
static Iris::Memory top_memory
static Iris::Directory root
static Iris::Elfrun elfrun
struct Program:
char *name
unsigned name_len
unsigned size
Iris::Caps pages
Iris::Memory memory
Iris::Thread thread
List <Serverdevice> server_devices
List <Clientdevice> client_devices
unsigned num_waiting
bool priv
void run ():
Iris::Cap cap = Iris::my_receiver.create_capability (Iris::Num (PROGRAM, (unsigned)this))
if priv:
kdebug ("priv ")
kdebug ("running ")
for unsigned i = 0; i < name_len; ++i:
kdebug_char (name[i])
kdebug ("\n")
Iris::Caps caps = elfrun.run_caps (top_memory, pages, cap.copy (), (size + PAGE_SIZE - 1) >> PAGE_BITS)
Iris::free_cap (cap)
thread = caps.get (__thread_num)
memory = caps.get (__memory_num)
Iris::free_cap (caps)
if priv:
thread.make_priv ()
thread.run ()
struct File : public Devbase:
unsigned size
Iris::Caps pages
static List <Program> programs
static List <File> files
static Serverdevice *sysreq
static bool name_match (char const *name, unsigned name_len, Iris::String n):
char nm[16]
n.get_chars (0, nm)
for unsigned t = 0; t < 16 && t < name_len; ++t:
if nm[t] != name[t]:
return false
return true
static Iris::Caps load (char const *name, unsigned name_len, unsigned &size, Iris::Caps target = Iris::alloc_cap ()):
kdebug ("loading ")
for unsigned i = 0; i < name_len; ++i:
kdebug_char (name[i])
kdebug ("\n")
root.lock_ro ()
Iris::Num sz = root.get_size ()
if sz.h:
Iris::panic (sz.h, "too many files")
for unsigned i = 0; i < sz.l; ++i:
Iris::String n = root.get_name (i)
if !name_match (name, name_len, n):
Iris::free_cap (n)
continue
Iris::free_cap (n)
Iris::Block file = root.get_file_ro (i)
Iris::Num s = file.get_size ()
if s.h:
Iris::panic (s.h, "file is too large to load")
size = s.l
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
if pages > 0:
Iris::set_recv_arg (target)
Iris::my_memory.create_caps (pages)
unsigned slot = target.use ()
for unsigned p = 0; p < pages; ++p:
Iris::set_recv_arg (Iris::Cap (slot, p))
file.get_block (p << PAGE_BITS)
Iris::free_slot (slot)
Iris::free_cap (file)
root.unlock_ro ()
return target
Iris::panic (0, "file not found for init")
return target
static void delspace (char *&line, unsigned &maxlen):
while maxlen && (*line == ' ' || *line == '\t'):
++line
--maxlen
if maxlen && *line == '#':
line += maxlen
maxlen = 0
static bool match (char *&line, unsigned &maxlen, char const *word):
delspace (line, maxlen)
char const *w = word
char *l = line
unsigned len = 0
while *word:
if *l++ != *word++:
return false
++len
line = l
maxlen -= len
delspace (line, maxlen)
//kdebug ("match: ")
//kdebug (w)
//kdebug ("\n")
return true
static bool isnamechar (char c):
if c >= 'a' && c <= 'z':
return true
if c >= 'A' && c <= 'Z':
return true
if c >= '0' && c <= '9':
return true
if c == '_':
return true
return false
static bool get_name (char *&line, unsigned &len, char *&name, unsigned &name_len):
delspace (line, len)
if !len:
return false
name_len = 0
while name_len < len && isnamechar (line[name_len]):
++name_len
name = new char[name_len]
//kdebug ("name: ")
for unsigned i = 0; i < name_len; ++i:
name[i] = line[i]
//kdebug_char (name[i])
//kdebug_char ('\n')
line += name_len
len -= name_len
delspace (line, len)
return true
static bool string_match (char const *s1, unsigned l1, char const *s2, unsigned l2):
if l1 != l2:
return false
for unsigned i = 0; i < l1; ++i:
if s1[i] != s2[i]:
return false
return true
struct Type:
char const *name
unsigned len
unsigned type
static unsigned read_num (char *&line, unsigned &len):
delspace (line, len)
unsigned num = 0
while len && *line >= '0' && *line <= '9':
num *= 10
num += *line - '0'
++line
--len
delspace (line, len)
return num
static Type types[] = {
{ "String", 6, Iris::String::ID },
{ "WString", 7, Iris::WString::ID },
{ "Block", 5, Iris::Block::ID },
{ "WBlock", 6, Iris::WBlock::ID },
{ "Boot", 4, Iris::Boot::ID },
{ "Device", 6, Iris::Device::ID },
{ "Event", 5, Iris::Event::ID },
{ "Parent", 6, Iris::Parent::ID },
{ "Keyboard", 8, Iris::Keyboard::ID },
{ "Buzzer", 6, Iris::Buzzer::ID },
{ "Display", 7, Iris::Display::ID },
{ "Font", 4, Iris::Font::ID },
{ "Setting", 7, Iris::Setting::ID },
{ "Directory", 9, Iris::Directory::ID },
{ "WDirectory", 10, Iris::WDirectory::ID },
{ "Stream", 6, Iris::Stream::ID },
{ "UI", 2, Iris::UI::ID },
{ "RTC", 3, Iris::RTC::ID },
{ NULL, 0, 0 }
}
static void find_type (char *&line, unsigned &len, unsigned &type, unsigned &index):
char *n
unsigned l
if !get_name (line, len, n, l) || !len:
Iris::panic (0, "no name for type")
for unsigned t = 0; types[t].len != 0; ++t:
if string_match (types[t].name, types[t].len, n, l):
type = types[t].type
if len && *line == ',':
++line
--len
index = read_num (line, len)
else:
index = 0
return
Iris::panic (0, "no valid type found")
static bool find_cap (char *&line, unsigned &len, Program **server, Devbase *&dev, bool &present):
char *n
unsigned l
if !get_name (line, len, n, l):
Iris::panic (0, "no capability name found in init.config")
for List <Program>::Item *p = programs.begin (); p; p = p->next:
List <Serverdevice>::Item *d
for d = (*p)->server_devices.begin (); d; d = d->next:
if string_match (n, l, (*d)->name, (*d)->name_len):
if server:
*server = &**p
dev = &**d
present = false
return true
if server:
return false
for List <File>::Item *f = files.begin (); f; f = f->next:
if string_match (n, l, (*f)->name, (*f)->name_len):
dev = &**f
present = true
return true
return false
static void parse_line (char *&line, unsigned maxlen)
static void include (char const *name, unsigned name_len):
unsigned size
Iris::Caps caps = load (name, name_len, size)
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
char *config = alloc_space (pages)
unsigned pages_slot = caps.use ()
for unsigned p = 0; p < pages; ++p:
Iris::Page page (pages_slot, p)
Iris::my_memory.map (page, (unsigned)&config[p << PAGE_BITS])
char *ptr = config
while ptr - config < size:
parse_line (ptr, config + size - ptr)
for unsigned p = 0; p < pages; ++p:
Iris::my_memory.destroy (Iris::Cap (pages_slot, p))
Iris::my_memory.destroy (caps)
Iris::free_cap (caps)
Iris::free_slot (pages_slot)
static char *get_filename (char *&line, unsigned &maxlen, unsigned &len):
char q = *line++
--maxlen
len = 0
while maxlen && *line != q:
++line
--maxlen
++len
if !maxlen:
Iris::panic (0, "no closing quote in init.config")
return line - len
static void do_load (char *&line, unsigned &maxlen, bool priv):
Program *p = &**programs.insert ()
if !get_name (line, maxlen, p->name, p->name_len) || !match (line, maxlen, "=") || !maxlen:
Iris::panic (0, "syntax error in init.config (load)")
unsigned l
char *n = get_filename (line, maxlen, l)
p->pages = load (n, l, p->size)
p->priv = priv
p->num_waiting = 0
++line
--maxlen
static void parse_line (char *&line, unsigned maxlen):
char *start = line
while maxlen && *line != '\n':
++line
--maxlen
// The line to execute is from start to line.
maxlen = line - start
if *line == '\n':
++line
delspace (start, maxlen)
if !maxlen:
return
if match (start, maxlen, "program"):
// program <name> = "<filename>"
do_load (start, maxlen, false)
else if match (start, maxlen, "driver"):
// driver <name> = "<filename>"
do_load (start, maxlen, true)
else if match (start, maxlen, "file"):
// file <name> = "<filename>"
File *f = &**files.insert ()
f->type = Iris::Block::ID
if !get_name (start, maxlen, f->name, f->name_len) || !match (start, maxlen, "=") || !maxlen:
Iris::panic (0, "syntax error in init.config (file name)")
unsigned l
char *n = get_filename (start, maxlen, l)
f->pages = load (n, l, f->size)
f->cap = Iris::my_receiver.create_capability (Iris::Num (FILE, (unsigned)f))
++line
--maxlen
else if match (start, maxlen, "receive"):
// receive <name> / <type> [, <index>] = <cap>
char *n
unsigned l
if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
Iris::panic (0, "syntax error in init.config (receive)")
List <Program>::Item *p
for p = programs.begin (); p; p = p->next:
if string_match ((*p)->name, (*p)->name_len, n, l):
break
if !p:
Iris::panic (0, "program not found for receive")
List <Serverdevice>::Item *dev = (*p)->server_devices.insert ()
find_type (start, maxlen, (*dev)->type, (*dev)->index)
if !match (start, maxlen, "=") || !get_name (start, maxlen, (*dev)->name, (*dev)->name_len):
Iris::panic (1, "syntax error in init.config (receive)")
(*dev)->server = &**p
(*dev)->client = NULL
(*dev)->cap = Iris::Cap ()
else if match (start, maxlen, "sysreq"):
Program *server
if sysreq:
Iris::panic (0, "double registration of sysreq")
bool dummy
if !find_cap (start, maxlen, &server, *(Devbase **)&sysreq, dummy):
Iris::panic (0, "capability not found for sysreq")
if sysreq->type != Iris::Keyboard::ID:
kdebug ("capability for sysreq is not a keyboard\n")
else if match (start, maxlen, "give"):
// give <name> / <type> [, <index>] = <cap>
char *n
unsigned l
if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
Iris::panic (0, "syntax error in init.config (give)")
List <Program>::Item *p
for p = programs.begin (); p; p = p->next:
if string_match ((*p)->name, (*p)->name_len, n, l):
break
if !p:
Iris::panic (0, "program not found for give")
List <Clientdevice>::Item *d = (*p)->client_devices.insert ()
find_type (start, maxlen, (*d)->type, (*d)->index)
if !match (start, maxlen, "="):
Iris::panic (1, "syntax error in init.config (give)")
bool present
if !find_cap (start, maxlen, NULL, (*d)->dev, present):
Iris::panic (0, "capability not found for give")
if (*d)->dev->type != (*d)->type:
kdebug ("capability type mismatch for give\n")
if (*d)->dev->client:
Iris::panic (0, "capability given out twice")
(*d)->dev->client = &**p
if !present:
++(*p)->num_waiting
//kdebug ("registered give device: ")
//kdebug_num ((*d)->type)
//kdebug ("\n")
else if match (start, maxlen, "include"):
unsigned name_len
char *name = get_filename (line, maxlen, name_len)
include (name, name_len)
else:
for unsigned i = 0; i < maxlen; ++i:
kdebug_char (start[i])
kdebug_char ('\n')
Iris::panic (0, "invalid line in init.config")
delspace (start, maxlen)
if maxlen:
kdebug ("Junk: ")
for unsigned i = 0; i < maxlen; ++i:
kdebug_char (start[i])
kdebug_char ('\n')
Iris::panic (0, "junk at end of line in init.config")
Iris::Num start ():
init_alloc ()
programs.init ()
files.init ()
root = Iris::my_parent.get_capability <Iris::Directory> ()
elfrun = Iris::my_parent.get_capability <Iris::Elfrun> ()
sysreq = NULL
top_memory = Iris::get_top_memory ()
include (INIT_CONFIG, INIT_CONFIG_SIZE)
kdebug ("killing boot threads\n")
Iris::my_parent.init_done ()
for List <Program>::Item *p = programs.begin (); p; p = p->next:
if !(*p)->num_waiting:
(*p)->run ()
if !sysreq:
Iris::panic (0, "sysreq not registered")
if sysreq->client:
Iris::panic (0, "sysreq set to reserved capability")
kdebug ("waiting for events.\n")
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case SYSREQ:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
Iris::reboot ()
continue
kdebug ("sysreq event: rebooting device at release\n")
continue
case FILE:
File *file = (File *)Iris::recv.protected_data.h
switch Iris::recv.data[0].l:
case Iris::Block::GET_SIZE:
Iris::recv.reply.invoke (file->size)
break
case Iris::Block::GET_ALIGN_BITS:
Iris::recv.reply.invoke (PAGE_BITS)
break
case Iris::Block::GET_BLOCK:
Iris::Cap reply = Iris::get_reply ()
Iris::Page target = Iris::get_arg ()
Iris::Page source = file->pages.get (Iris::recv.data[1].l >> PAGE_BITS)
source.share (target, Iris::Page::READONLY)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (source)
Iris::free_cap (target)
break
default:
Iris::panic (Iris::recv.data[0].l, "unknown request for init string")
break
case PROGRAM:
Program *caller = (Program *)Iris::recv.protected_data.h
switch Iris::recv.data[0].l:
case Iris::Parent::GET_CAPABILITY:
unsigned index = Iris::recv.data[0].h
unsigned type = Iris::recv.data[1].l
if Iris::recv.data[1].h:
Iris::panic (Iris::recv.data[1].h, "high device requested")
//kdebug ("requested device ")
//kdebug_num (type)
//kdebug (":")
//kdebug_num (index)
//kdebug ("\n")
List <Clientdevice>::Item *d
for d = caller->client_devices.begin (); d; d = d->next:
//kdebug ("checking ")
//kdebug_num ((*d)->type)
//kdebug (":")
//kdebug_num ((*d)->index)
//kdebug ("\n")
if (*d)->type == type && (*d)->index == index:
break
if !d:
Iris::debug ("requested %x by %s\n", type, caller->name)
Iris::panic (type, "unregistered device requested")
Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
//kdebug ("given device ")
//kdebug_num (type)
//kdebug (":")
//kdebug_num (index)
//kdebug ("\n")
break
case Iris::Parent::PROVIDE_CAPABILITY:
if Iris::recv.data[1].h != 0:
kdebug ("init: too high device provided\n")
continue
unsigned type = Iris::recv.data[1].l
unsigned index = Iris::recv.data[0].h
List <Serverdevice>::Item *d
for d = caller->server_devices.begin (); d; d = d->next:
if (*d)->type == type && (*d)->index == index:
break
if !d:
Iris::debug ("caller: %s\n", caller->name)
Iris::panic (type, "unregistered device provided")
(*d)->cap = Iris::get_arg ()
Iris::recv.reply.invoke ()
if (*d)->client:
if !--(*d)->client->num_waiting:
(*d)->client->run ()
//kdebug ("provided ")
//kdebug_num ((*d)->type)
//kdebug (":")
//kdebug_num ((*d)->index)
//kdebug ("\n")
break
case Iris::Parent::INIT_DONE:
//kdebug ("init done\n")
Iris::recv.reply.invoke ()
if caller == sysreq->server:
Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ)
Iris::Keyboard (sysreq->cap).set_cb (cap.copy ())
Iris::free_cap (cap)
kdebug ("registered sysreq\n")
break
case Iris::Parent::EXIT:
kdebug ("child ")
for unsigned i = 0; i < caller->name_len; ++i:
kdebug_char (caller->name[i])
kdebug (" exits with code ")
kdebug_num (Iris::recv.data[1].h)
kdebug (":")
kdebug_num (Iris::recv.data[1].l)
kdebug ("\n")
top_memory.destroy (caller->memory)
break
default:
// TODO.
kdebug ("child request: ")
kdebug_num (Iris::recv.data[0].l)
kdebug (" from ")
for unsigned i = 0; i < caller->name_len; ++i:
kdebug_char (caller->name[i])
kdebug ("\n")

32
userspace/boot/mkthreadlist Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
cat << EOF
.globl init_start
.globl thread_start
.set noreorder
.balign 0x1000
EOF
for i in "$@" ; do
cat << EOF
${i##*/}:
.incbin "fs/${i##*/}.elf"
.balign 0x1000
EOF
done
cat << EOF
end_threads:
init_start:
thread_start:
EOF
for i in "$@" ; do
cat << EOF
.word ${i##*/}
EOF
done
cat << EOF
.word end_threads
.word 0
EOF

886
userspace/data/charset Executable file
View File

@@ -0,0 +1,886 @@
#!/usr/bin/env python
data = """
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . # .
. . . . # .
. . . # . .
. . . # . .
. . # . . .
. . . . . .
. # . . . .
. . . . . .
. # # . # #
. . # . . #
+ # . + # .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . # . # .
. # # # # #
. # . # . .
# # # # # .
# . # . . .
. . . . . .
. . . . # .
. . # # # #
. # . # . .
. . # # # .
. . # . # .
. # # # # .
. # . . . .
. . . . . .
. . . . . .
. # # . # .
. # . # . .
. . . # . .
. . # . . .
. . # . # .
. # . # # .
. . . . . .
. # # . . .
. # . # . .
. # # . . .
. . # . . .
. # # . # .
. # . # # .
. # # # # .
. . . . . .
. . # # . .
. . . # . .
. + # . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . + # #
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. . # . . .
. . # # . .
. . . . . .
. . # # . .
. . . . # .
. . . . # .
. . . . # .
. . . # . .
. . . # . .
# # + . . .
. . . . . .
. # . . # .
. . # . # .
. . # # . .
. # # # # #
. . # # . .
. . # . # .
. # . . # .
. . . . . .
. . . . . .
. . . . . .
. . . # . .
. . . # . .
# # # # # .
. . # . . .
. # . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . # # . .
. . # . . .
. + # . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. # # # # .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . # . .
. . # # . .
. . . . . .
. . . . . .
. . . . # .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. . . . . .
. . . . . .
. . + # # .
. # + . # .
. # . . # .
# . . # . .
# . + # . .
# # + . . .
. . . . . .
. . . . . .
. . . . # .
. . # # . .
. . . # . .
. . # . . .
. . # . . .
# # # . . .
. . . . . .
. . . . . .
. . + # # .
. + + . # .
. . . . # .
. + # . . .
. # . . . .
# # # # . .
. . . . . .
. . . . . .
. . # # # .
. . . . # .
. . . + # .
. + # . . .
. . . # . .
# # # . . .
. . . . . .
. . . . . .
. . # . . #
. # . . # .
. # # # # .
. . . # . .
. . . # . .
. . # . . .
. . . . . .
. . . . . .
. . # # # #
. # . . . .
. # # # . .
. . . # . .
. . . . # .
# # # # . .
. . . . . .
. . . + # .
. . . # . .
. . # . . .
. . # # # .
. # . . # .
. # . . # .
. # # # . .
. . . . . .
. . . . . .
. . # # # #
. . . . # .
. . . . # .
. . + + . .
. . + + . .
. # . . . .
. . . . . .
. . . . . .
. . + # # .
. # . . # .
. + # # + .
# . . # . .
# . . # . .
# # + . . .
. . . . . .
. . . . . .
. . + # # .
. # . . # .
. # . + # .
. # + # . .
. . . # . .
# # # . . .
. . . . . .
. . . . . .
. . . # . .
. . # # . .
. . . . . .
. . . . . .
. # # . . .
. # . . . .
. . . . . .
. . . . . .
. . . # . .
. . # # . .
. . . . . .
. . . . . .
. # # . . .
. # . . . .
+ # . . . .
. . . . . .
. . . # + .
. + + . . .
. # . . . .
. # . . . .
. . # . . .
. . # . . .
. . . . . .
. . . . . .
. . . . . .
. # # # # .
. . . . . .
. . . . . .
# # # # . .
. . . . . .
. . . . . .
. . . . . .
. . # . . .
. . # . . .
. . . # . .
. . . # . .
. . + + . .
+ # . . . .
. . . . . .
. . # # . .
. . # . # .
. . . . # .
. . . + # .
. . # . . .
. . . . . .
. # . . . .
. . . . . .
. . # # # .
. . # . . #
. # . # . #
. # . # + #
# . # # # .
. # . . . .
. # # # . .
. . . . . .
. . . + # .
. . . # . #
. . # . . #
. . # # # #
. # . . # .
. # . . # .
# . . # . .
. . . . . .
. . . # # .
. . . # . #
. . # . # .
. . # # # .
. # . . # .
. # . + # .
# # # + . .
. . . . . .
. . + # # .
. . # + . #
. # . . . .
. # . . . .
# . . . . .
+ + . + + .
# # # . . .
. . . . . .
. . . # # .
. . . # . #
. . # . . #
. . # . . #
. # . . # .
. # . + # .
# # # + . .
. . . . . .
. . . # # #
. . . # . .
. . # . . .
. . # # . .
. # . . . .
. # . . . .
# # # . . .
. . . . . .
. . . # # #
. . . # . .
. . # . . .
. . # # . .
. # . . . .
. # . . . .
# . . . . .
. . . . . .
. . + # # .
. . # + . #
. # . . . .
. # . . . .
# . # # . .
+ + . # . .
+ # # . . .
. . . . . .
. . . # . #
. . . # . #
. . # . # .
. . # # # .
. # . # . .
. # . # . .
# . # . . .
. . . . . .
. . . # # #
. . . . # .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
# # # . . .
. . . . . .
. . . # # #
. . . . # .
. . . # . .
. . . # . .
. . # . . .
# . # . . .
# # . . . .
. . . . . .
. . . # . #
. . . # . #
. . # . # .
. . # # + .
. # + . . .
. # . # . .
# . . # . .
. . . . . .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. # . . . .
# # # # . .
. . . . . .
. . # . # #
. . # + # +
. # . # . #
. # . . . #
# . . . # .
# . . . # .
+ . . # . .
. . . . . .
. . # . . #
. . # # . +
. # + + . #
. # . # . #
# . + + # .
# . . # # .
+ . . # . .
. . . . . .
. . . # # .
. . # + . #
. # . . . #
. # . . . #
# . . . # .
# . . + # .
# # # . . .
. . . . . .
. . . # # .
. . . # . #
. . # . . #
. . # . + #
. # # # + .
. # . . . .
# . . . . .
. . . . . .
. . . # # .
. . # + . #
. # . . . #
. # . . . #
# . . # # .
# . . . # .
# # # . # .
. . . . . .
. . . # # .
. . . # . #
. . # . . #
. . # . + #
. # # # + .
. # . # . .
# . . # . .
. . . . . .
. . + # # #
. . # + . .
. # . . . .
. . # # . .
. . . # . .
. . . . # .
# # # # . .
. . . . . .
. # # # # #
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. # . . . .
# . . . . .
. . . . . .
. . # . . #
. . # . . #
. # . . # .
. # . . # .
# . . # . .
# . + # . .
# # + . . .
. . . . . .
. + . . . #
. # . . . #
+ . . . # .
. # . . # .
+ . . # . .
. # + + . .
. # . . . .
. . . . . .
. . # . . +
. . # . . +
. # . . . #
. # . . . #
# . # . # .
# + # . # .
# + # # . .
. . . . . .
. # . . . #
. . # . . #
. . # # + .
. . . # . .
. + # # . .
. # . . # .
# . . . # .
. . . . . .
. # . . . #
. . # . . #
. . # # + .
. . . # . .
. + # . . .
. # . . . .
# . . . . .
. . . . . .
. . # # # #
. . . . . #
. . . # + .
. . . # . .
. + # . . .
. # . . . .
# # # # . .
. . . . . .
. . . # # #
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. # . . . .
# # # . . .
. . . . . .
. # . . . .
. . # . . .
. . # . . .
. . . # . .
. . . # . .
. . . . # .
. . . . # .
. . . . . .
. . . # # #
. . . . . #
. . . . # .
. . . . # .
. . . # . .
. . . # . .
# # # . . .
. . . . . .
. . . + # .
. . + # . #
. # . . . #
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
# # # # # .
. . . . . .
. . # # . .
. . . # . .
. . + # . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . # # + #
. # . # # .
. # . . # .
# . . # . .
. # + # . .
. # # . . .
. . . . . .
. . . # . .
. . . # . .
. . # . . .
. . # # # .
. # . . # .
. # . . # .
# # # # . .
. . . . . .
. . . . . .
. . . # # .
. # + . # .
. # . . . .
# . . . . .
. # . # . .
. # + . . .
. . . . . .
. . . . . #
. . . . . #
. . # # # .
. # + . # .
# . . # . .
# . . # . .
# # # . . .
. . . . . .
. . . . . .
. . + # # .
. # . . # .
. # # # + .
# . . . . .
. # . . . .
. # # . . .
. . . . . .
. . . # # .
. . . # . #
. . # . . .
. # # # . .
. # . . . .
. # . . . .
# . . . . .
. . . . . .
. . . . . .
. . . # # #
. . # . . #
. . . # # #
. . . . # .
. . . + # .
. # # . . .
. . . . . .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # # # . .
. # . . # .
# . . # . .
. . . . . .
. . . . # .
. . . . . .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. . . . . .
. . . . # .
. . . . . .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # . . . .
# # . . . .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # + # . .
. # # + . .
# . # + . .
. . . . . .
. . . . # .
. . . . # .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. . . . . .
. . . . . .
. . . # # #
. . # + + #
. . # + + #
. # + + # .
. # + + # .
# + + # . .
. . . . . .
. . . . . .
. . . # + #
. . # # + #
. . # . . #
. # . . # .
. # . . # .
# . . # . .
. . . # . .
. . . . . .
. . + # # .
. # + . # .
. # . . . #
# . . . # .
. # . + # .
. # # + . .
. . . . . .
. . . . . .
. . . # # #
. . # . . #
. . # . . #
. # # # + .
. # . . . .
# . . . . .
. . . . . .
. . . . . .
. . + # # #
. # . . # .
. # . . # .
. # # # . .
. . . # . .
. . # . . .
. . # . . .
. . . . . .
. . . # + #
. . # # . #
. . # . . .
. # . . . .
. # . . . .
# . . . . .
. . . . . .
. . . . . .
. . # # # #
. # . . . .
. . # # . .
. . . # . .
. . . . # .
# # # # . .
. . . . . .
. . . . . .
. . . # . .
. # # # . .
. . # . . .
. # . . . .
. # . # . .
. # + . . .
. . . . . .
. . . . . .
. . # . . #
. # . . # .
. # . . # .
# . . # . .
# . + # . .
# # + . . .
. . . . . .
. . . . . .
. + # . . +
. # . . . #
. + + . + #
. # . # + .
. # . # . .
. # . . . .
. . . . . .
. . . . . .
. . # . . +
. # . . . #
. # . # . #
# . # . # .
# . # . # .
# # # + . .
. . . . . .
. . . . . .
. . # . . #
. . # . # .
. . + # + .
. + # + . .
. # . # . .
# . . # . .
. . . . . .
. . . . . .
. . # . . #
. # . . # .
. . # # # .
. . . # . .
. . + # . .
# # + . . .
. . . . . .
. . . . . .
. . # # # #
. . . . # .
. . . # + .
. + # . . .
. # . . . .
# # # # . .
. . . . . .
. . . + # #
. . . # . .
. . # . . .
. # + . . .
. # . . . .
. # . . . .
+ # # . . .
. . . . . .
. . . . # .
. . . . # .
. . . # . .
. . . # . .
. . # . . .
. . # . . .
. # . . . .
. . . . . .
. . . # # +
. . . . . #
. . . . # .
. . . . + #
. . . # . .
. . . # . .
# # + . . .
. . . . . .
. # # . . .
. # . # . #
. . . # # .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. # + # + .
. # + # + .
. + # + # .
. + # + # .
. # + # + .
. # + # + .
. . . . . .
"""
# """ # add quotes, because vim thinks the qotes on the previous line start a string.
import sys
charsize = 25 * 4 + 1
for c in range (128 - 32):
for l in range (8):
offset = 2 + c * charsize + 25 * (l >> 1) + 12 * (l & 1)
ln = ""
for x in range (6):
char = data[offset + x * 2]
if char == '.':
sys.stdout.write (chr (0))
elif char == '+':
sys.stdout.write (chr (128))
elif char == '#':
sys.stdout.write (chr (255))
else:
raise "invalid character in " + str (c)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
userspace/data/courier.xcf Normal file

Binary file not shown.

View File

@@ -0,0 +1,80 @@
# driver <name> = '<filename>' load a file into memory to be run priviledged.
# program <name> = '<filename>' load a file into memory to be run normally.
# file <name> = '<filename>' load a file into memory as a Block.
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
# sysreq <cap> use a capability as the system request keyboard.
# give <name> / <type> [, <index>] = <cap> give this capability to this program when it requests it.
# include <file> include a file as another config file.
# at end of file, the initial threads are killed and the drivers and programs are run as soon as all their dependencies are provided.
driver driver_gpio = "gpio.elf"
receive driver_gpio / Keyboard , 0 = keyboard
receive driver_gpio / Keyboard , 1 = sysreq
receive driver_gpio / Event = sdmmc_gpio
sysreq sysreq
#driver driver_nand = "nand.elf"
#receive driver_nand / WBlock = nand
#driver driver_ums = "usb-mass-storage.elf"
#give driver_ums / WBlock = nand
#driver driver_boot = "boot.elf"
#receive driver_boot / Boot = boot
#file kernel = "kernel.raw"
#program booter = "booter.elf"
#give booter / Block = kernel
#give booter / Boot = boot
driver driver_lcd = "lcd.elf"
receive driver_lcd / Display = display
receive driver_lcd / Setting = display_bright
driver driver_buzzer = "buzzer.elf"
receive driver_buzzer / Buzzer = buzzer
#program alarm = "alarm.elf"
#receive alarm / UI = ui
#program gui = "gui.elf"
#give gui / UI = ui
#give gui / Display = display
#give gui / Setting = display_bright
#give gui / Buzzer = buzzer
#give gui / Keyboard = keyboard
#driver sdmmc = "sd+mmc.elf"
#receive sdmmc / WBlock = sdmmc
#give sdmmc / Event = sdmmc_gpio
#program partition = "partition.elf"
#receive partition / WBlock, 0 = p0
#receive partition / WBlock, 1 = p1
#receive partition / WBlock, 2 = p2
#receive partition / WBlock, 3 = p3
#give partition / WBlock = sdmmc
#program fat = "fat.elf"
#receive fat / Directory = root
#give fat / WBlock = p0
#program test = "test.elf"
#give test / Directory = root
file fontfile = "font.dat"
program font = "font.elf"
receive font / Font = font
give font / Block = fontfile
#give font / Display = display
driver driver_rtc = "rtc.elf"
receive driver_rtc / RTC = rtc
driver alarm = "alarm.elf"
give alarm / Keyboard = keyboard
give alarm / Display = display
give alarm / Buzzer = buzzer
give alarm / Font = font
give alarm / RTC = rtc
receive alarm / Event = alarm

30
userspace/data/makefont Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python
import sys
import os
from PIL import Image
def mknum (num):
return ''.join ([chr ((num >> (8 * i)) & 0xff) for i in range (4)])
im = Image.open (sys.argv[1])
height = im.size[1]
width, baseline, skip = [int (x) for x in os.path.splitext (sys.argv[1])[0].split ('-')[-1].split ('+')]
num_glyphs = im.size[0] / width
sys.stdout.write (mknum (skip + num_glyphs))
size1 = (3 + width * height) * 4
base = (num_glyphs + skip) * 4
for i in range (skip):
sys.stdout.write (mknum (base + (num_glyphs - 1) * size1))
for i in range (skip, skip + num_glyphs):
sys.stdout.write (mknum (base + (i - skip) * size1))
im = im.convert ('RGBA')
pix = im.load ()
#sys.stderr.write ('%d\n' % len (pix[0,0]))
for g in range (skip, skip + num_glyphs):
sys.stdout.write (mknum (width))
sys.stdout.write (mknum (height))
sys.stdout.write (mknum (baseline))
for y in range (height):
for x in range (width):
sys.stdout.write (''.join ([chr (x) for x in (pix[x + (g - skip) * width, y])]))

98
userspace/glue/buffer.ccp Normal file
View File

@@ -0,0 +1,98 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/buffer.ccp: block device buffer.
// Copyright 2010 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"
static unsigned align
static Iris::Page page, rpage
static unsigned mapping, rmapping
static Iris::Num size, current
static Iris::String dev
static void read_block (Iris::Num idx):
idx = idx.value () & PAGE_MASK
if idx.value () == current.value ():
return
//kdebug ("buffering block ")
//kdebug_num (idx.h)
//kdebug (":")
//kdebug_num (idx.l)
//kdebug ("\n")
dev.get_block (idx, PAGE_SIZE, 0, page)
//kdebug ("buffered\n")
current = idx
Iris::Num start ():
dev = Iris::my_parent.get_capability <Iris::WString> ()
align = dev.get_align_bits ()
size = dev.get_size ()
if align > PAGE_BITS:
Iris::panic (align, "invalid alignment value for block device")
page = Iris::my_memory.create_page ()
rpage = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING)
rpage.set_flags (Iris::Page::PAYING)
mapping = 0x15000
rmapping = 0x17000
Iris::my_memory.map (page, mapping)
Iris::my_memory.map (rpage, rmapping)
current.h = ~0
current.l = ~0
Iris::Cap cap = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_capability <Iris::WString> (cap.copy ())
Iris::free_cap (cap)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
Iris::recv.reply.invoke (size)
break
case Iris::String::GET_ALIGN_BITS:
// Use 16 byte alignment to make implementing GET_CHARS easier.
Iris::recv.reply.invoke (4)
break
case Iris::String::GET_CHARS:
Iris::Cap reply = Iris::get_reply ()
unsigned offset = Iris::recv.data[1].l & ~PAGE_MASK & ~((1 << 4) - 1)
read_block (Iris::recv.data[1])
unsigned *data = (unsigned *)((char *)mapping)[offset]
reply.invoke (Iris::Num (data[0], data[1]), Iris::Num (data[2], data[3]))
Iris::free_cap (reply)
break
case Iris::String::GET_BLOCK:
Iris::Cap reply = Iris::get_reply ()
Iris::Page arg = Iris::get_arg ()
unsigned offset = Iris::recv.data[1].l & ~PAGE_MASK & ~((1 << 4) - 1)
unsigned sz = Iris::recv.data[0].h >> 16
unsigned roffset = Iris::recv.data[0].h & 0xffff
Iris::Num idx = Iris::recv.data[1]
arg.set_flags (Iris::Page::FRAME | Iris::Page::PAYING)
arg.share (rpage)
rpage.set_flags (Iris::Page::FRAME)
read_block (idx)
for unsigned i = 0; i < sz; ++i:
((char *)rmapping)[roffset + i] = ((char *)mapping)[offset + i]
rpage.set_flags (0, Iris::Page::FRAME)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)
break
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for buffer")

304
userspace/glue/elfrun.ccp Normal file
View File

@@ -0,0 +1,304 @@
#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::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::Block 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)
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::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)
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_BLOCK:
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::Block 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)

688
userspace/glue/fat.ccp Normal file
View File

@@ -0,0 +1,688 @@
#pypp 0
#include <iris.hh>
#include <devices.hh>
#define SECTOR_BITS 9
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
#define ROOT_CLUSTER 0x7fffffff
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::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::WBlock dev
static Iris::Num device_size
static Iris::Page page
static char *data
static Iris::Num current_block
static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
if p.code == page.code:
if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS:
return
current_block = idx
//kdebug ("fat getting block: ")
//kdebug_num (idx.h)
//kdebug (":")
//kdebug_num (idx.l)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("@")
//kdebug_num (offset)
//kdebug ("\n")
dev.get_block (idx, size, offset, p)
struct Fat:
char oem[8]
unsigned sector_size_bits
unsigned sectors_per_cluster_bits
unsigned reserved_sectors
unsigned num_fats
unsigned root_entries
unsigned sectors
unsigned media
unsigned sectors_per_fat
unsigned sectors_per_track
unsigned heads
unsigned hidden_sectors
unsigned active_fat
bool write_all_fats
unsigned fs_version
unsigned root_cluster
unsigned fsinfo_sector
unsigned boot_backup_sector
unsigned drive
unsigned current_head
unsigned volume_id
char label[0xb]
unsigned bits
unsigned clusters
unsigned cluster_size_bits
unsigned root_sectors
unsigned header_sectors
unsigned bad_clusters
unsigned free_clusters
unsigned last_alloced
unsigned *fat
unsigned first_free_cluster, first_bad_cluster
void print_num (char const *pre, unsigned data):
kdebug ("\t")
kdebug (pre)
unsigned bytes = 1
while bytes < 8 && data >> (bytes * 4):
++bytes
kdebug_num (data, bytes)
kdebug ("\n")
void print_br ():
kdebug ("\tOEM: '")
for unsigned i = 0; i < 8; ++i:
kdebug_char (oem[i])
kdebug ("'\n")
print_num ("bytes per sector: ", 1 << sector_size_bits)
print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits)
print_num ("reserved sectors: ", reserved_sectors)
print_num ("number of fats: ", num_fats)
print_num ("entries in root directory: ", root_entries)
print_num ("sectors: ", sectors)
print_num ("media descriptor: ", media)
print_num ("sectors per fat: ", sectors_per_fat)
print_num ("sectors per track: ", sectors_per_track)
print_num ("heads: ", heads)
print_num ("hidden sectors: ", hidden_sectors)
print_num ("active_fat: ", active_fat)
kdebug ("\twrite all: ")
kdebug (write_all_fats ? "yes\n" : "no\n")
print_num ("fs version: ", fs_version)
print_num ("root cluster: ", root_cluster)
print_num ("fsinfo sector: ", fsinfo_sector)
print_num ("boot sector backup sector: ", boot_backup_sector)
print_num ("drive: ", drive)
print_num ("current head: ", current_head)
print_num ("volume id: ", volume_id)
kdebug ("\tlabel: '")
for unsigned i = 0; i < 0xb; ++i:
kdebug_char (label[i])
kdebug ("'\n")
print_num ("bits: ", bits)
print_num ("clusters: ", clusters)
print_num ("header sectors: ", header_sectors)
unsigned read_num (char *data, unsigned bytes):
unsigned ret = 0
for unsigned i = 0; i < bytes; ++i:
ret |= (data[i] & 0xff) << (i * 8)
return ret
void map_fat_cluster (unsigned c, unsigned offset = 0):
//unsigned b = current_block.l
read_block ((reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits)
//if b != current_block.l:
//for unsigned i = 0; i < 0x20; ++i:
//kdebug (" ")
//kdebug_num (data[i], 2)
//kdebug ("\n")
unsigned make_bits (unsigned orig):
unsigned ret
for ret = 0; ret < 32; ++ret:
if orig == 1 << ret:
return ret
//Iris::panic (orig, "non-power of 2")
kdebug ("not a power of two, using 16\n")
return 16
void reset ():
read_block (0)
if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
kdebug ("invalid boot record signature in fat device\n")
for unsigned i = 0; i < 8; ++i:
oem[i] = data[3 + i]
sector_size_bits = make_bits (read_num (data + 0xb, 2))
sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1))
cluster_size_bits = sector_size_bits + sectors_per_cluster_bits
reserved_sectors = read_num (data + 0xe, 2)
num_fats = read_num (data + 0x10, 1)
root_entries = read_num (data + 0x11, 2)
sectors = read_num (data + 0x13, 2)
media = read_num (data + 0x15, 1)
sectors_per_fat = read_num (data + 0x16, 2)
sectors_per_track = read_num (data + 0x18, 2)
heads = read_num (data + 0x1a, 2)
hidden_sectors = read_num (data + 0x1c, 4)
if !sectors:
sectors = read_num (data + 0x20, 4)
if Iris::Num (sectors).value () << sector_size_bits > device_size.value ():
sectors = device_size.value () >> sector_size_bits
kdebug ("warning: limiting sectors because of limited device size\n")
root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits
header_sectors = reserved_sectors + sectors_per_fat * num_fats + root_sectors
clusters = (sectors - header_sectors) >> sectors_per_cluster_bits
unsigned skip
if clusters >= 65525:
bits = 32
sectors_per_fat = read_num (data + 0x24, 4)
active_fat = read_num (data + 0x28, 2)
write_all_fats = active_fat & 0x80
active_fat &= 0xf
fs_version = read_num (data + 0x2a, 2)
root_cluster = read_num (data + 0x2c, 4)
fsinfo_sector = read_num (data + 0x30, 2)
boot_backup_sector = read_num (data + 0x32, 2)
skip = 0x40 - 0x24
else:
if clusters < 4085:
bits = 12
else:
bits = 16
skip = 0
active_fat = 0
write_all_fats = true
fs_version = 0
root_cluster = 0
fsinfo_sector = 0
boot_backup_sector = 0
unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits
unsigned fat_entries = sectors_per_fat * fat_entries_per_sector
if clusters + 2 > fat_entries:
clusters = fat_entries - 2
kdebug ("warning: limiting clusters because of limited sector count\n")
drive = read_num (data + skip + 0x24, 1)
current_head = read_num (data + skip + 0x25, 1)
if data[skip + 0x26] == 0x29:
volume_id = read_num (data + skip + 0x27, 4)
for unsigned i = 0; i < 0xb; ++i:
label[i] = data[skip + 0x2b + i]
char *id = data + skip + 0x36
if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ':
kdebug ("warning: file system type field was not 'FATxx '\n")
else:
switch bits:
case 12:
if id[3] != '1' || id[4] != '2':
kdebug ("warning: id for fat12 is not FAT12\n")
break
case 16:
if id[3] != '1' || id[4] != '6':
kdebug ("warning: id for fat16 is not FAT16\n")
break
case 32:
if id[3] != '3' || id[4] != '2':
kdebug ("warning: id for fat32 wat not FAT32")
break
else:
volume_id = 0
for unsigned i = 0; i < 0xb; ++i:
label[i] = 0
if fsinfo_sector:
read_block (fsinfo_sector << sector_size_bits)
if (data[0] & 0xff) != 0x52 || (data[1] & 0xff) != 0x52 || (data[2] & 0xff) != 0x6a || (data[3] & 0xff) != 0x41 || (data[0x1e4] & 0xff) != 0x72 || (data[0x1e5] & 0xff) != 0x72 || (data[0x1e6] & 0xff) != 0x4a || (data[0x1e7] & 0xff) != 0x61 || (data[0x1fe] & 0xff) != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
kdebug ("invalid signature in fsinfo structure\n")
free_clusters = read_num (data + 0x1e8, 4)
last_alloced = read_num (data + 0x1ec, 4)
else:
free_clusters = ~0
last_alloced = ~0
// Now read the FAT.
bad_clusters = 0
fat = new unsigned[clusters]
unsigned counted_free_clusters = 0
first_free_cluster = ~0
for unsigned c = 0; c < clusters; ++c:
// reduced cluster.
unsigned rc = c & (1 << sector_size_bits) - 1
// The next line does nothing most of the time.
map_fat_cluster (c)
switch bits:
case 12:
fat[c] = data[(rc + 2) * 2] & 0xff
// There may be a sector boundary in the middle of the entry, so optionally reread.
map_fat_cluster (c, 1)
fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8
if c & 1:
fat[c] >>= 4
else:
fat[c] &= 0xfff
break
case 16:
fat[c] = read_num (data + (rc + 2) * 2, 2)
break
case 32:
fat[c] = read_num (data + (rc + 2) * 4, 4)
break
// Correct for the crazy +2 offset, and keep a list of bad and free clusters.
if fat[c] == 0:
// Free cluster.
fat[c] = first_free_cluster
first_free_cluster = c
++counted_free_clusters
else if fat[c] == 1:
// Invalid value.
Iris::panic (0, "entry is '1' in fat.")
else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff:
// Last cluster in chain.
fat[c] = ~0
//kdebug ("last cluster: ")
//kdebug_num (c)
//kdebug ("\n")
else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7:
// Bad cluster.
fat[c] = first_bad_cluster
first_bad_cluster = c
++bad_clusters
else:
// Non-last cluster in chain.
fat[c] -= 2
//kdebug_num (c)
//kdebug (" -> ")
//kdebug_num (fat[c])
//kdebug ("\n")
unsigned fat_lookup (unsigned first_cluster, unsigned cluster):
//kdebug ("looking up ")
//kdebug_num (first_cluster)
//kdebug ("+")
//kdebug_num (cluster)
//kdebug (":")
while cluster--:
first_cluster = fat[first_cluster]
//kdebug ("->")
//kdebug_num (first_cluster)
if first_cluster == ~0:
//kdebug ("sector beyond end of file requested\n")
return ~0
//kdebug ("\n")
return first_cluster
struct File:
Fat *fat
unsigned size
unsigned first_cluster
char name[11]
bool archive, readonly, system, hidden, directory, volume
unsigned create_second, create_minute_hour, create_date, access_date, time, date
unsigned checksum
void load_cluster (unsigned idx, unsigned offset_in_cluster, Iris::Page p = page, unsigned offset = 0):
unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits)
//kdebug ("loading cluster ")
//kdebug_num (idx)
//kdebug ("+")
//kdebug_num (offset_in_cluster)
//kdebug ("@")
//kdebug_num (cluster)
//kdebug (" from file\n")
if cluster == ~0:
kdebug ("invalid cluster requested from file\n")
return
read_block (((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits) + offset_in_cluster, p, fat->cluster_size_bits < PAGE_BITS ? 1 << fat->cluster_size_bits : PAGE_SIZE, offset)
char *load_dir_entry (unsigned dir, unsigned idx):
unsigned sector = idx >> (sector_size_bits - 5)
unsigned num = (idx << 5) & ~BLOCK_MASK
Iris::Num hwsector
if dir == ROOT_CLUSTER:
if sector < root_sectors:
hwsector = header_sectors - root_sectors + sector
else:
return NULL
else:
unsigned entry = fat_lookup (dir, sector)
if entry == ~0:
return NULL
hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits)
read_block (hwsector.value () << sector_size_bits)
return &data[num]
char *find_idx (unsigned dir, unsigned *idx, unsigned *count = NULL):
unsigned todo = *idx + 1
char *e
if count:
*count = 0
for *idx = 0; todo; ++*idx:
e = load_dir_entry (dir, *idx)
if !e:
return NULL
if (e[0xb] & 0xff) == 0xf:
// This is part of a long filename.
continue
if (e[0] & 0xff) == 0xe5:
// This is a deleted file.
continue
if !e[0]:
// This is a free entry.
continue
if count:
++*count
--todo
--*idx
return e
unsigned get_dir_size (unsigned dir):
unsigned num = 0 - 2
unsigned ret
find_idx (dir, &num, &ret)
return ret
bool get_dir_entry (unsigned dir, unsigned idx, File *f):
char *e = load_dir_entry (dir, idx)
if !e:
kdebug ("unable to load dir entry\n")
return false
f->fat = this
//kdebug ("loading dir entry for ")
for unsigned i = 0; i < 11; ++i:
f->name[i] = e[i]
//kdebug_char (f->name[i])
//kdebug ("\n")
f->readonly = e[0xb] & 0x1
f->system = e[0xb] & 0x2
f->hidden = e[0xb] & 0x4
f->volume = e[0xb] & 0x8
f->directory = e[0xb] & 0x10
f->archive = e[0xb] & 0x20
f->create_second = read_num (e + 0xd, 1)
f->create_minute_hour = read_num (e + 0xe, 2)
f->create_date = read_num (e + 0x10, 2)
f->access_date = read_num (e + 0x12, 2)
f->time = read_num (e + 0x16, 1)
f->date = read_num (e + 0x18, 1)
f->size = read_num (e + 0x1c, 4)
f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2
f->checksum = 0
for unsigned i = 0; i < 11; ++i:
f->checksum = ((((f->checksum & 1) << 7) | ((f->checksum & 0xfe) >> 1)) + f->name[i]) & 0xff
//kdebug ("loaded dir entry, first cluster = ")
//kdebug_num (f->first_cluster)
//kdebug ("\n")
return true
struct LFN:
unsigned ordinal
unsigned name[13]
unsigned checksum
bool load_lfn (unsigned dir, unsigned idx, unsigned t, unsigned checksum, LFN *lfn):
if t >= idx:
return false
char *e = load_dir_entry (dir, idx - t - 1)
if (e[0xb] & 0xff) != 0xf:
return false
lfn->ordinal = read_num (e + 0x00, 1)
for unsigned i = 0; i < 5; ++i:
lfn->name[i] = read_num (e + 0x01 + 2 * i, 2)
lfn->checksum = read_num (e + 0xd, 1)
for unsigned i = 0; i < 6; ++i:
lfn->name[i + 5] = read_num (e + 0xe + 2 * i, 2)
for unsigned i = 0; i < 2; ++i:
lfn->name[i + 11] = read_num (e + 0x1c + 2 * i, 2)
return true
unsigned parse_shortname (File const &f, char *name):
if f.name[0] == ' ':
Iris::panic (0, "fat name starts with space")
unsigned len = 8
while f.name[len - 1] == ' ':
--len
char *ptr = name
for unsigned i = 0; i < len; ++i:
*ptr++ = f.name[i]
if f.name[8] == ' ':
return len
*ptr++ = '.'
len = 3
while f.name[8 + len - 1] == ' ':
--len
for unsigned i = 0; i < len; ++i:
*ptr++ = f.name[8 + i]
return ptr - name
unsigned get_name_size (unsigned dir, unsigned idx, File const &f):
LFN lfn
unsigned num = 0
if !load_lfn (dir, idx, 0, f.checksum, &lfn):
// Not a long filename.
char n[12]
return parse_shortname (f, n)
unsigned ordinal = 0
while true:
if !load_lfn (dir, idx, num, f.checksum, &lfn):
Iris::panic (0, "error parsing long filename")
if (lfn.ordinal & 0x3f) != ++ordinal:
Iris::panic (lfn.ordinal, "error in sequence for long filename")
if lfn.ordinal & 0x40:
break
++num
unsigned i
for i = 0; i < 13; ++i:
if !lfn.name[i]:
break
return num * 13 + i
// Capability encoding.
// 0:ROOT_CLUSTER = non fat-32 root directory.
// 0:cluster = other directory.
// cluster:index = file index from directory at cluster.
// cluster|0x80000000:index = filename for file with index from directory at cluster.
Iris::Num start ():
init_alloc ()
current_block = ~0
dev = Iris::my_parent.get_capability <Iris::WBlock> ()
if dev.get_align_bits () > SECTOR_BITS:
kdebug ("fat device doesn't support 512 byte access")
return 1
device_size = dev.get_size ()
data = (char *)0x15000; //alloc_space (1)
page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING)
Iris::my_memory.map (page, (unsigned)data)
Fat fat
fat.reset ()
fat.print_br ()
Iris::Cap root
if fat.root_cluster:
root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0))
else:
root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0))
Iris::my_parent.provide_capability <Iris::Directory> (root.copy ())
Iris::free_cap (root)
while true:
Iris::wait ()
unsigned dir = Iris::recv.protected_data.h
if dir & 0x80000000:
dir &= ~0x80000000
// File name.
unsigned idx = Iris::recv.protected_data.l
Iris::Cap reply = Iris::get_reply ()
unsigned num = Iris::recv.data[1].l
unsigned size = Iris::recv.data[0].h >> 16
unsigned cmd = Iris::recv.data[0].l
Fat::File f
if !fat.find_idx (dir, &idx):
Iris::panic (Iris::recv.protected_data.l, "invalid index")
if !fat.get_dir_entry (dir, idx, &f):
Iris::panic (Iris::recv.protected_data.l, "invalid dir entry requested for filename")
switch cmd:
case Iris::String::GET_SIZE:
//kdebug ("filename size requested\n")
reply.invoke (fat.get_name_size (dir, idx, f))
break
case Iris::String::GET_CHARS:
//kdebug ("filename chars requested\n")
//kdebug ("flags: ")
//kdebug_char (f.readonly ? 'R' : 'r')
//kdebug_char (f.system ? 'S' : 's')
//kdebug_char (f.hidden ? 'H' : 'h')
//kdebug_char (f.volume ? 'V' : 'v')
//kdebug_char (f.directory ? 'D' : 'd')
//kdebug_char (f.archive ? 'A' : 'a')
//kdebug_char ('\n')
/**/union { unsigned u[4]; char c[16]; } u
for unsigned k = 0; k < 4; ++k:
u.u[k] = 0
Fat::LFN lfn
if !fat.load_lfn (dir, idx, 0, f.checksum, &lfn):
// Not a long filename.
char n[12]
unsigned len = fat.parse_shortname (f, n)
//kdebug ("short filename: ")
for unsigned k = 0; k + num < len; ++k:
u.c[k] = n[k + num]
//kdebug_char (u.c[k])
//kdebug ("\n")
else:
// Very inefficient, but it works: reload everything for every character.
//kdebug ("filename: ")
for unsigned c = 0; c < 16; ++c:
if !fat.load_lfn (dir, idx, (num + c) / 13, f.checksum, &lfn):
// Filename isn't this long: keep the rest at 0.
break
u.c[c] = lfn.name[(num + c) % 13]
if u.c[c] == 0:
break
//kdebug_char (u.c[c])
//kdebug ("\n")
reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3]))
break
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename")
Iris::free_cap (reply)
else if dir:
// If it *has* a directory, it *is* a file.
unsigned idx = Iris::recv.protected_data.l
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Num num = Iris::recv.data[1]
unsigned size = Iris::recv.data[0].h >> 16
unsigned offset = Iris::recv.data[0].h & 0xffff
unsigned cmd = Iris::recv.data[0].l
Fat::File f
fat.get_dir_entry (dir, idx, &f)
switch cmd:
case Iris::Block::GET_SIZE:
//kdebug ("file size requested\n")
reply.invoke (f.size)
break
case Iris::Block::GET_ALIGN_BITS:
//kdebug ("file align requested\n")
reply.invoke (fat.cluster_size_bits <= PAGE_BITS ? fat.cluster_size_bits : PAGE_BITS)
break
case Iris::Block::GET_BLOCK:
//kdebug ("file block requested\n")
unsigned mask = (1 << fat.cluster_size_bits) - 1
//kdebug ("mask = ")
//kdebug_num (mask)
//kdebug ("\n")
if offset > PAGE_SIZE:
//kdebug ("invalid offset requested\n")
break
if size + offset > PAGE_SIZE:
Iris::panic (size, "invalid size requested")
size = PAGE_SIZE - offset
for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits:
f.load_cluster ((num.l & ~mask) + i, num.l & mask, arg, i + offset)
reply.invoke ()
break
case Iris::WBlock::TRUNCATE:
case Iris::WBlock::SET_BLOCK:
Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet")
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for fat file")
Iris::free_cap (reply)
Iris::free_cap (arg)
else:
// Directory.
switch Iris::recv.data[0].l:
case Iris::Directory::GET_SIZE:
//kdebug ("dir size requested\n")
Iris::Cap reply = Iris::get_reply ()
reply.invoke (fat.get_dir_size (Iris::recv.protected_data.l))
Iris::free_cap (reply)
break
case Iris::Directory::GET_NAME:
//kdebug ("dir name requested\n")
Iris::Cap reply = Iris::get_reply ()
Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000))
reply.invoke (0, 0, ret.copy ())
Iris::free_cap (reply)
Iris::free_cap (ret)
break
case Iris::Directory::GET_FILE_RO:
//kdebug ("dir file requested\n")
Iris::Cap reply = Iris::get_reply ()
dir = Iris::recv.protected_data.l
unsigned idx = Iris::recv.data[1].l
unsigned oldidx = idx
if !fat.find_idx (dir, &idx):
kdebug_num (oldidx)
kdebug ("\n")
Iris::panic (1, "file not found")
Fat::File f
fat.get_dir_entry (dir, idx, &f)
Iris::Cap ret
if f.directory:
//kdebug ("dir provided: ")
//kdebug_num (f.first_cluster)
//kdebug ("\n")
ret = Iris::my_receiver.create_capability (Iris::Num (f.first_cluster, 0))
else:
ret = Iris::my_receiver.create_capability (Iris::Num (idx, dir))
reply.invoke (0, 0, ret.copy ())
Iris::free_cap (reply)
Iris::free_cap (ret)
break
case Iris::Directory::GET_FILE_INFO:
//kdebug ("dir file info requested\n")
Iris::Cap reply = Iris::get_reply ()
dir = Iris::recv.protected_data.l
unsigned idx = Iris::recv.data[1].l
unsigned oldidx = idx
if !fat.find_idx (dir, &idx):
kdebug_num (oldidx)
kdebug ("\n")
Iris::panic (2, "file not found")
unsigned type = Iris::recv.data[0].h
Fat::File f
fat.get_dir_entry (dir, idx, &f)
reply.invoke (f.directory ? 1 : 0)
Iris::free_cap (reply)
break
case Iris::Directory::LOCK_RO:
case Iris::Directory::UNLOCK_RO:
//kdebug ("dir lock or unlock requested\n")
Iris::recv.reply.invoke ()
break
default:
//kdebug ("invalid dir operation requested\n")
Iris::recv.reply.invoke ()
break

179
userspace/glue/font.ccp Normal file
View File

@@ -0,0 +1,179 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/font.ccp: Font manager.
// Copyright 2012 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"
#define screenw 320
#define screenh 240
struct Glyph:
unsigned width, height, baseline
unsigned data[1]
static Iris::Display display
static Iris::Caps caps, display_caps
static unsigned slot, num_glyphs
static unsigned long pages, base
static Glyph **glyphs
static char *fb
static unsigned x, y
static unsigned read_int (unsigned addr):
return *reinterpret_cast <unsigned *> (addr)
static void load_font (Iris::Block font):
unsigned long long size = font.get_size ().value ()
pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
caps = Iris::my_memory.create_caps (pages)
slot = caps.use ()
for unsigned i = 0; i < size; i += PAGE_SIZE:
Iris::Page page = Iris::Cap (slot, i >> PAGE_BITS)
Iris::set_recv_arg (page)
font.get_block (i)
Iris::my_memory.map (page, base + i)
num_glyphs = read_int (base)
glyphs = reinterpret_cast <Glyph **> (base + sizeof (int))
for unsigned i = 0; i < num_glyphs; ++i:
glyphs[i] = reinterpret_cast <Glyph *> (base + sizeof (int) + read_int (base + sizeof (int) + i * sizeof (int)))
static void free_font ():
for unsigned i = 0; i < pages; ++i:
Iris::my_memory.destroy (Iris::Cap (slot, i))
Iris::my_memory.destroy (caps)
Iris::free_slot (slot)
static unsigned draw_char (char c, unsigned &w, unsigned &h):
if c >= num_glyphs:
c = num_glyphs - 1
Glyph *g = glyphs[c]
w = g->width
h = g->height
for unsigned ty = 0; ty < h; ++ty:
unsigned py = ty + y - g->baseline
if py < 0 || py >= screenh:
continue
for unsigned tx = 0; tx < g->width; ++tx:
unsigned px = tx + x
if px < 0 || px >= screenw:
continue
unsigned p = g->data[ty * g->width + tx]
unsigned red = unsigned (p) & 0xff
unsigned green = unsigned (p >> 8) & 0xff
unsigned blue = unsigned (p >> 16) & 0xff
unsigned alpha = (unsigned (p >> 24) & 0xff) + 1
if alpha == 0x100:
fb[(py * 320 + px) * 4 + 2] = red
fb[(py * 320 + px) * 4 + 1] = green
fb[(py * 320 + px) * 4 + 0] = blue
else:
unsigned unalpha = 256 - alpha
fb[(py * 320 + px) * 4 + 2] = (fb[(py * 320 + px) * 4 + 2] * unalpha + red * alpha) >> 8
fb[(py * 320 + px) * 4 + 1] = (fb[(py * 320 + px) * 4 + 1] * unalpha + green * alpha) >> 8
fb[(py * 320 + px) * 4 + 0] = (fb[(py * 320 + px) * 4 + 0] * unalpha + blue * alpha) >> 8
return g->baseline
static void get_size (char c, unsigned &w, unsigned &h, unsigned &b):
if c >= num_glyphs:
c = num_glyphs - 1
Glyph *g = glyphs[c]
w = g->width
h = g->height
b = g->baseline
Iris::Num start ():
x = 0
y = 8
// Random address which is large enough to store a huge file.
base = 0x40000000
fb = reinterpret_cast <char *> (0x20000000)
Iris::Font self = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_capability <Iris::Font> (self.copy ())
Iris::free_cap (self)
//display = Iris::my_parent.get_capability <Iris::Display> ()
Iris::Block font = Iris::my_parent.get_capability <Iris::Block> ()
load_font (font)
Iris::free_cap (font)
Iris::my_parent.init_done ()
//display_caps = display.map_fb (reinterpret_cast <unsigned> (fb))
bool have_display = false
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::Font::SET_DISPLAY:
Iris::Cap reply = Iris::get_reply ()
if have_display:
Iris::free_cap (display)
have_display = true
display = Iris::get_arg ()
display_caps = display.map_fb (reinterpret_cast <unsigned> (fb))
reply.invoke ()
Iris::free_cap (reply)
break
case Iris::Font::LOAD_FONT:
free_font ()
font = Iris::get_arg ()
load_font (font)
Iris::free_cap (font)
Iris::recv.reply.invoke ()
break
case Iris::Font::SETUP:
// TODO: interface needs to be defined.
Iris::recv.reply.invoke ()
break
case Iris::Font::AT:
if Iris::recv.data[0].h & 1:
x += Iris::recv.data[1].l
if x > screenw:
x = 0
y += 16
if y + 16 > screenh + 8:
y = 8
else:
x = Iris::recv.data[1].l
if Iris::recv.data[0].h & 2:
y += Iris::recv.data[1].h
if y + 16 > screenh + 8:
y = 8
else:
y = Iris::recv.data[1].h
Iris::recv.reply.invoke ()
break
case Iris::Font::WRITE:
Iris::Cap reply = Iris::get_reply ()
unsigned w, h
unsigned b = draw_char (Iris::recv.data[1].l, w, h)
x += w
if x + w > screenw:
x = 0
y += h
if y + h > screenh + b:
y = b
reply.invoke ()
Iris::free_cap (reply)
break
case Iris::Font::GET_POS:
Iris::recv.reply.invoke (x, y)
break
case Iris::Font::GET_SIZE:
unsigned w, h, b
get_size (Iris::recv.data[1].l, w, h, b)
Iris::recv.reply.invoke (Iris::Num (b, h), w)
break
default:
Iris::panic (0, "invalid operation type for lcd")
break

268
userspace/glue/gui.ccp Normal file
View File

@@ -0,0 +1,268 @@
#pypp 0
#include <iris.hh>
#include <devices.hh>
#include <keys.hh>
// Interface: two way, started by ui.
// From ui to application.
// ~0: request reset.
// ~1: set reply cap; send current state.
// inum: event (with optional value) for input number num.
// From application to ui.
// onum: event (with optional value) for output number num.
// For now, the code is hardwired to the alarm clock interface.
enum outs:
CURRENT_TIME
ALARM
enum ins:
TOTAL_TIME
START
static Iris::Display display
static Iris::Buzzer buzzer
static unsigned *framebuffer
static unsigned alarming
enum PD:
UI
KBD
static char const *chardef =
".###.."
"#...#."
"#...#."
"#...#."
"#...#."
"#...#."
".###.."
"......"
"..#..."
"..#..."
"..#..."
"..#..."
"..#..."
"..#..."
"..#..."
"......"
".###.."
"#...#."
"....#."
"...#.."
"..#..."
".#...."
"#####."
"......"
".###.."
"#...#."
"....#."
"..##.."
"....#."
"#...#."
".###.."
"......"
"#...#."
"#...#."
"#...#."
"#####."
"....#."
"....#."
"....#."
"......"
"#####."
"#....."
"####.."
"....#."
"....#."
"....#."
"####.."
"......"
"....#."
"...#.."
"..#..."
".###.."
"#...#."
"#...#."
".###.."
"......"
"#####."
"....#."
"...#.."
"..#..."
".#...."
"#....."
"#....."
"......"
".###.."
"#...#."
"#...#."
".###.."
"#...#."
"#...#."
".###.."
"......"
".###.."
"#...#."
"#...#."
".###.."
"..#..."
".#...."
"#....."
"......"
"......"
"......"
"..#..."
"......"
"......"
"..#..."
"......"
"......"
static void draw_pixel (unsigned x, unsigned y, bool set):
for unsigned ty = 0; ty < 8; ++ty:
for unsigned tx = 0; tx < 8; ++tx:
framebuffer[320 * (y + ty) + x + tx] = (set ? 0xffffff : 0x000000)
static void draw_num (bool upper, unsigned x0, unsigned d):
for unsigned y = 0; y < 8; ++y:
for unsigned x = 0; x < 6; ++x:
draw_pixel (x * 10 + 10 + x0 * 60, y * 10 + (upper ? 30 : 50 + 80), chardef[(d * 8 + y) * 6 + x] == '#')
static void draw_time (bool upper, unsigned time):
unsigned min = time / 60
time %= 60
if min >= 100:
min = 99
time = 99
draw_num (upper, 0, min / 10)
draw_num (upper, 1, min % 10)
draw_num (upper, 3, time / 10)
draw_num (upper, 4, time % 10)
static void do_alarm ():
static unsigned tune[] = { 4, 6, 6, 5, 7, 7 }
if ++alarming > sizeof (tune) / sizeof (*tune):
alarming = 1
buzzer.beep (tune[alarming - 1] * 220, 300, ~0)
Iris::my_receiver.set_alarm (HZ / 3)
Iris::Num start ():
display = Iris::my_parent.get_capability <Iris::Display> ()
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
framebuffer = (unsigned *)0x15000
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
unsigned screen_max = bright.get_range ()
bright.set (0)
bool screen_on = false
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
app.get_state (cb.copy ())
Iris::free_cap (cb)
cb = Iris::my_receiver.create_capability (KBD)
keyboard.set_cb (cb.copy ())
Iris::free_cap (cb)
draw_num (false, 2, 10)
draw_num (true, 2, 10)
unsigned total_time = 0
alarming = 0
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case ~0:
// Alarm.
if alarming:
do_alarm ()
break
case UI:
switch Iris::recv.data[0].l:
case CURRENT_TIME:
draw_time (false, Iris::recv.data[1].l)
break
case ALARM:
do_alarm ()
break
case TOTAL_TIME | Iris::UI::INPUT:
total_time = Iris::recv.data[1].l
draw_time (true, total_time)
break
case START | Iris::UI::INPUT:
break
break
case KBD:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
break
alarming = 0
switch Iris::recv.data[0].l:
case Key::VOLUME_UP:
total_time += 60
draw_time (true, total_time)
app.event (TOTAL_TIME, total_time)
break
case Key::VOLUME_DOWN:
if total_time < 60:
total_time = 0
else:
total_time -= 60
draw_time (true, total_time)
app.event (TOTAL_TIME, total_time)
break
case Key::UP:
total_time += 10
draw_time (true, total_time)
app.event (TOTAL_TIME, total_time)
break
case Key::DOWN:
if total_time < 10:
total_time = 0
else:
total_time -= 10
draw_time (true, total_time)
app.event (TOTAL_TIME, total_time)
break
case Key::LEFT:
if total_time < 1:
total_time = 0
else:
total_time -= 1
draw_time (true, total_time)
app.event (TOTAL_TIME, total_time)
break
case Key::RIGHT:
total_time += 1
draw_time (true, total_time)
app.event (TOTAL_TIME, total_time)
break
case Key::ENTER:
app.event (START)
break
case Key::BACKSPACE:
screen_on = !screen_on
if screen_on:
bright.set (screen_max)
else:
bright.set (0)
break

View File

@@ -0,0 +1,122 @@
#pypp 0
#include <iris.hh>
#include <devices.hh>
#define NUM_PARTITIONS 4
#define SECTOR_BITS 9
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
unsigned bits
struct Partition:
static Iris::Num device_size
unsigned lba_start, lba_size
unsigned type
bool active
Iris::Num start, size
static unsigned read_num (char *data):
return data[0] & 0xff | (data[1] & 0xff) << 8 | (data[2] & 0xff) << 16 | (data[3] & 0xff) << 24
void read (char *data):
if data[0] == 0:
active = false
else:
active = true
if (data[0] & 0xff) != 0x80:
kdebug ("Warning: invalid active code ")
kdebug_num (data[0], 2)
kdebug ("\n")
type = data[4] & 0xff
lba_start = read_num (data + 8)
lba_size = read_num (data + 12)
start = Iris::Num (lba_start).value () << SECTOR_BITS
size = Iris::Num (lba_size).value () << SECTOR_BITS
kdebug ("Partition read: ")
kdebug_num (lba_start)
kdebug ("+")
kdebug_num (lba_size)
kdebug ("\n")
Iris::Num Partition::device_size
static Iris::WBlock dev
static void read_sector (Iris::Num idx, Iris::Page page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
offset &= ~PAGE_MASK
if size + offset > PAGE_SIZE:
size = PAGE_SIZE - offset
size >>= SECTOR_BITS
idx = idx.value () >> SECTOR_BITS
for unsigned i = 0; i < size; ++i:
dev.get_block ((idx.value () + i) << SECTOR_BITS, 1 << SECTOR_BITS, (i << SECTOR_BITS) + offset, page)
Iris::Num start ():
Partition::device_size = 0
dev = Iris::my_parent.get_capability <Iris::WBlock> ()
bits = dev.get_align_bits ()
if bits > SECTOR_BITS:
Iris::panic (bits, "partitioned device doesn't support 512 byte access\n")
Partition::device_size = dev.get_size ()
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING)
char *buffer = (char *)0x15000
unsigned *ubuffer = (unsigned *)buffer
Iris::my_memory.map (page, (unsigned)buffer)
read_sector (0, page)
if buffer[0x1fe] != 0x55 || (buffer[0x1ff] & 0xff) != 0xaa:
kdebug ("invalid mbr signature\n")
Partition partition[NUM_PARTITIONS]
Iris::Cap cap
for unsigned i = 0; i < NUM_PARTITIONS; ++i:
partition[i].read (buffer + 0x1be + 0x10 * i)
cap = Iris::my_receiver.create_capability (i)
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy (), i)
Iris::free_cap (cap)
page.set_flags (0, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
//kdebug ("partition received: ")
//kdebug_num (Iris::recv.data[0].l)
//kdebug ("\n")
switch Iris::recv.data[0].l:
case Iris::Block::GET_SIZE:
Iris::recv.reply.invoke (partition[Iris::recv.protected_data.l].size)
break
case Iris::Block::GET_ALIGN_BITS:
Iris::recv.reply.invoke (SECTOR_BITS)
break
case Iris::Block::GET_BLOCK:
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Num p = Iris::recv.data[1].value () & BLOCK_MASK
Iris::Num offset = partition[Iris::recv.protected_data.l].start.value ()
unsigned size = Iris::recv.data[0].h >> 16
unsigned out_offset = Iris::recv.data[0].h & 0xffff
//kdebug ("partition sending sector ")
//kdebug_num (offset.h)
//kdebug (":")
//kdebug_num (offset.l)
//kdebug (" + ")
//kdebug_num (p.h)
//kdebug (":")
//kdebug_num (p.l)
//kdebug (" = ")
//kdebug_num (Iris::Num (offset.value () + p.value ()).h)
//kdebug (":")
//kdebug_num (Iris::Num (offset.value () + p.value ()).l)
//kdebug ("\n")
read_sector (offset.value () + p.value (), arg, size, out_offset)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)
break
case Iris::WBlock::SET_BLOCK:
Iris::panic (Iris::recv.data[0].l, "writing to partitions not supported yet")
case Iris::WBlock::TRUNCATE:
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for partition handler")

View File

@@ -0,0 +1,762 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/usb-mass-storage.ccp: USB mass storage device driver.
// Copyright 2009-2010 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"
#define ARCH
#include "arch.hh"
#if 0
States and expected interrupts:
IDLE: after reset or csw.
IN interrupt: csw received, do nothing.
OUT interrupt: cbw; handle
-> IDLE (no data; csw sent)
-> TX (send)
-> RX (receive packets)
TX: transmitting data.
IN interrupt: host received data; send more.
-> TX (more to send)
RX: receiving data.
OUT interrupt: host sent data; handle.
-> RX (more to receive)
-> IDLE (done receiving; send csw)
#endif
extern "C":
void *memset (char *s, int c, unsigned long n):
Iris::debug ("memset called: %x %x->%x\n", s, n, c)
for unsigned i = 0; i < n; ++i:
s[i] = c
return s
class Udc:
typedef unsigned char u8
typedef unsigned short u16
typedef unsigned int u32
typedef u8 string
// The ugly stuff is because pypp doesn't support __attribute__.
/**/struct Setup {
u8 request_type;
u8 request;
u16 value;
u16 index;
u16 length;
} __attribute__ ((packed))
/**/struct Device {
static u8 const Type = 1;
u8 length;
u8 type;
u16 usb_version;
u8 dev_class;
u8 subclass;
u8 protocol;
u8 max_packet_size0;
u16 vendor;
u16 product;
u16 dev_version;
string s_manufacturer;
string s_product;
string s_serial;
u8 num_configurations;
} __attribute__ ((packed))
/**/struct Configuration {
static u8 const Type = 2;
u8 length;
u8 type;
u16 total_length;
u8 num_interfaces;
u8 configuration_value;
u8 configuration;
u8 attributes;
u8 max_power;
} __attribute__ ((packed))
/**/struct Interface {
static u8 const Type = 4;
u8 length;
u8 type;
u8 interface;
u8 alternate;
u8 num_endpoints;
u8 iface_class;
u8 subclass;
u8 protocol;
string name;
} __attribute__ ((packed))
/**/struct Endpoint {
static u8 const Type = 5;
u8 length;
u8 type;
u8 address;
u8 attributes;
u16 max_packet_size;
u8 interval;
} __attribute__ ((packed))
/**/struct Device_Qualifier {
static u8 const Type = 6;
u8 length;
u8 type;
u16 version;
u8 dev_class;
u8 subclass;
u8 protocol;
u8 max_packet_size0;
u8 num_configurations;
u8 reserved;
} __attribute__ ((packed))
/**/struct Langs {
static u8 const Type = 3;
u8 length;
u8 type;
u8 lang;
} __attribute__ ((packed))
template <unsigned size> struct String {
static u8 const Type = 3;
u8 length;
u8 type;
u16 data[size];
} __attribute__ ((packed))
/**/struct CBW {
u32 sig;
u32 tag;
u32 length;
u8 flags;
u8 lun;
u8 size;
u8 data[16];
enum Code {
TEST_UNIT_READY = 0x00,
REQUEST_SENSE = 0x03,
FORMAT_UNIT = 0x04,
INQUIRY = 0x12,
RESERVE6 = 0x16,
RELEASE6 = 0x17,
SEND_DIAGNOSTIC = 0x1d,
READ_CAPACITY = 0x25,
READ10 = 0x28,
WRITE10 = 0x2a,
RESERVE10 = 0x56,
RELEASE10 = 0x57
};
} __attribute__ ((packed))
static unsigned const max_packet_size0 = 64
static unsigned const max_packet_size_bulk = 64
enum Requests:
GET_STATUS = 0
CLEAR_FEATURE = 1
SET_FEATURE = 3
SET_ADDRESS = 5
GET_DESCRIPTOR = 6
SET_DESCRIPTOR = 7
GET_CONFIGURATION = 8
SET_CONFIGURATION = 9
GET_INTERFACE = 10
SET_INTERFACE = 11
SYNCH_FRAME = 12
enum Storage_requests:
BULK_ONLY_RESET = 0xff
GET_MAX_LUN = 0xfe
enum Request_types:
STANDARD_TO_DEVICE = 0
CLASS_TO_DEVICE = 0x20
VENDOR_TO_DEVICE = 0x40
STANDARD_TO_INTERFACE = 1
CLASS_TO_INTERFACE = 0x21
VENDOR_TO_INTERFACE = 0x41
STANDARD_TO_ENDPOINT = 2
CLASS_TO_ENDPOINT = 0x22
VENDOR_TO_ENDPOINT = 0x42
STANDARD_FROM_DEVICE = 0x80
CLASS_FROM_DEVICE = 0xa0
VENDOR_FROM_DEVICE = 0xc0
STANDARD_FROM_INTERFACE = 0x81
CLASS_FROM_INTERFACE = 0xa1
VENDOR_FROM_INTERFACE = 0xc1
STANDARD_FROM_ENDPOINT = 0x82
CLASS_FROM_ENDPOINT = 0xa2
VENDOR_FROM_ENDPOINT = 0xc2
enum Endpoint_types:
CONTROL = 0
ISOCHRONOUS = 1
BULK = 2
INTERRUPT = 3
enum Endpoint_features:
ENDPOINT_HALT = 0
/**/struct my_config {
Configuration config;
Interface interface;
Endpoint endpoint[2];
} __attribute__ ((packed))
static Device device_descriptor
//static Device_Qualifier device_qualifier_descriptor
static my_config config_descriptor; //, other_config_descriptor
static String <1> s_langs
static String <6> s_manufacturer
static String <16> s_product
static String <12> s_serial
char configuration
unsigned get_descriptor (unsigned type, unsigned idx, unsigned len)
unsigned handle_setup (Setup *s)
void reset ()
void irq_in0 ()
void handle_rx ()
void handle_tx ()
void handle_cbw ()
void send_csw ()
unsigned big_endian (unsigned src)
bool handle_interrupt (bool usb, bool in)
void stall (unsigned error)
bool stalling
enum State:
IDLE
TX
RX
SENT_CSW
STALL
State state
unsigned residue
unsigned status
unsigned tag
unsigned data_done, lba, blocks
unsigned block_bits
Iris::WBlock block
Iris::Page buffer_page
// A random address to map the buffer.
static unsigned const buffer = 0x15000
public:
void init (Iris::WBlock b)
void log (unsigned c)
void interrupt ()
void send (unsigned ep, char const *data, unsigned length, unsigned maxlength)
void send_padded (char const *data, unsigned length, unsigned maxlength)
Udc::Device Udc::device_descriptor
Udc::my_config Udc::config_descriptor
Udc::String <1> Udc::s_langs
Udc::String <6> Udc::s_manufacturer
Udc::String <16> Udc::s_product
Udc::String <12> Udc::s_serial
void Udc::reset ():
// Reset.
UDC_TESTMODE = 0
configuration = 0
state = IDLE
status = 0
residue = 0
// enable interrupt on bus reset.
UDC_INTRUSBE = UDC_INTR_RESET
// enable interrupts on endpoint 0 and in endpoint 2
UDC_INTRINE = 1 << 0 | 1 << 2
// and on out endpoint 1.
UDC_INTROUTE = 1 << 1
// exit suspend mode by reading the interrupt register.
unsigned i = UDC_INTRUSB
// reset all pending endpoint interrupts.
i = UDC_INTRIN
i = UDC_INTROUT
UDC_INDEX = 1
UDC_OUTMAXP = max_packet_size_bulk
// Do this twice to flush a double-buffered fifo completely.
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
UDC_INDEX = 2
UDC_INMAXP = max_packet_size_bulk
UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
//Iris::debug ("usb reset\n")
void Udc::init (Iris::WBlock b):
block = b
block_bits = block.get_align_bits ()
// Set up the buffer page.
buffer_page = Iris::my_memory.create_page ()
buffer_page.set_flags (Iris::Page::PAYING)
Iris::my_memory.map (buffer_page, buffer)
// Initialize the globals. My method of compiling doesn't handle global constructors.
device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 3, 1 }
config_descriptor = (my_config){
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 30 },
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0x8, 0x6, 0x50, 0 }, {
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x82, BULK, max_packet_size_bulk, 0 }
}
}
s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
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_serial = (String <12>){ sizeof (String <12>), String <12>::Type, { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B' } }
cpm_start_udc ()
// Disconnect from the bus and don't try to get high-speed.
UDC_POWER = 0
reset ()
// Wait a while.
Iris::sleep (HZ / 10)
// Connect to the host.
UDC_POWER = UDC_POWER_SOFTCONN
void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
if maxlength < length:
length = maxlength
unsigned i
for i = 0; (length - i & ~3) > 0 && i < length; i += 4:
UDC_FIFO (ep) = ((unsigned *)data)[i / 4]
//kdebug_num (((unsigned *)data)[i / 4], 8)
//kdebug (" ")
for ; i < length; ++i:
UDC_FIFO8 (ep) = data[i]
//kdebug_num (data[i], 2)
//kdebug (" ")
void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
UDC_INDEX = 2
unsigned len = length < maxlength ? length : maxlength
residue = maxlength - len
len = (len + 3) & ~3
send (2, data, len, maxlength)
//Iris::debug ("sending %x, valid %x\n", maxlength, len)
while len + 3 < maxlength:
UDC_FIFO (2) = 0
len += 4
//kdebug_char ('-')
while len < maxlength:
UDC_FIFO8 (2) = 0
++len
//kdebug_char ('.')
UDC_INCSR |= UDC_INCSR_INPKTRDY
blocks = 0
state = TX
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
switch type:
case Configuration::Type:
if idx != 0:
return false
//Iris::debug ("get config descriptor\n")
send (0, reinterpret_cast <char const *> (&config_descriptor), sizeof (config_descriptor), len)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case Device::Type:
if idx != 0:
return false
//Iris::debug ("get device descriptor\n")
send (0, reinterpret_cast <char const *> (&device_descriptor), sizeof (device_descriptor), len)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case Device_Qualifier::Type:
//if idx != 0:
// return false
//send (0, reinterpret_cast <char const *> (&device_qualifier_descriptor), sizeof (device_qualifier_descriptor), len)
//return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
//break
return ~0
// The 6 is an arbitrary number, except that String <6> is instantiated already.
case String <6>::Type:
switch idx:
case 0:
//Iris::debug ("get language descriptor\n")
send (0, reinterpret_cast <char const *> (&s_langs), sizeof (s_langs), len)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case 1:
//Iris::debug ("get manufacturer descriptor\n")
send (0, reinterpret_cast <char const *> (&s_manufacturer), sizeof (s_manufacturer), len)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case 2:
//Iris::debug ("get product descriptor\n")
send (0, reinterpret_cast <char const *> (&s_product), sizeof (s_product), len)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case 3:
//Iris::debug ("get serial descriptor\n")
send (0, reinterpret_cast <char const *> (&s_serial), sizeof (s_serial), len)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
default:
return ~0
default:
return ~0
unsigned Udc::handle_setup (Setup *s):
switch s->request_type:
case STANDARD_TO_DEVICE:
UDC_INDEX = 0
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
switch s->request:
case SET_ADDRESS:
UDC_FADDR = s->value
Iris::debug ("set address %x\n", s->value)
return 0
case SET_CONFIGURATION:
if s->value >= 2:
return ~0
configuration = s->value
Iris::debug ("set configuration %x\n", s->value)
return 0
case SET_INTERFACE:
if s->value != 0:
return ~0
Iris::debug ("set interface %x\n", s->value)
return 0
default:
return ~0
case STANDARD_FROM_DEVICE:
UDC_INDEX = 0
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
switch s->request:
case GET_STATUS:
Iris::debug ("get status\t")
send (0, "\0\0", 2, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case GET_DESCRIPTOR:
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
case GET_CONFIGURATION:
Iris::debug ("get configuration\t")
send (0, &configuration, 1, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case GET_INTERFACE:
Iris::debug ("get interface\t")
send (0, "\0", 1, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
default:
return ~0
case STANDARD_TO_ENDPOINT:
switch s->request:
case CLEAR_FEATURE:
switch s->value:
case ENDPOINT_HALT:
switch s->index:
case 0x82:
//Iris::debug ("in ep halt reset\n")
UDC_INDEX = 2
UDC_INCSR = (UDC_INCSR & ~UDC_INCSR_SENDSTALL) | UDC_INCSR_CDT
stalling = false
send_csw ()
break
case 1:
//Iris::panic (0, "halt reset on out endpoint")
UDC_INDEX = 1
UDC_OUTCSR |= UDC_OUTCSR_CDT
break
default:
return ~0
return UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
default:
return ~0
default:
return ~0
case CLASS_FROM_INTERFACE:
UDC_INDEX = 0
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
switch s->request:
case GET_MAX_LUN:
//Iris::debug ("get max lun\t")
send (0, "\0", 1, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
default:
return ~0
case CLASS_TO_INTERFACE:
UDC_INDEX = 0
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
switch s->request:
case BULK_ONLY_RESET:
Iris::debug ("bulk reset\n")
state = IDLE
return 0
default:
return ~0
default:
Iris::debug ("request: %x %x %x %x %x\n", s->request_type, s->request, s->index, s->length, s->value)
return ~0
void Udc::irq_in0 ():
// Interrupt on endpoint 0.
UDC_INDEX = 0
unsigned csr = UDC_CSR0
if csr & UDC_CSR0_SENTSTALL:
UDC_CSR0 = 0
//Iris::debug ("stall 0 done\t")
if csr & UDC_CSR0_SETUPEND:
UDC_CSR0 = UDC_CSR0_SVDSETUPEND
Iris::debug ("setup aborted\t")
if !(csr & UDC_CSR0_OUTPKTRDY):
//Iris::debug ("no packet 0: %x\n", csr)
return
UDC_INDEX = 0
union { unsigned d[2]; Setup s; } packet
packet.d[0] = UDC_FIFO (0)
packet.d[1] = UDC_FIFO (0)
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
// More data will follow; unsupported.
Iris::debug ("packet on ep0 too long\n")
UDC_CSR0 = UDC_CSR0_SENDSTALL
return
unsigned ret = handle_setup (&packet.s)
UDC_INDEX = 0
if ret == ~0:
//Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
UDC_CSR0 = UDC_CSR0_SENDSTALL
return
if ret:
UDC_CSR0 = ret
//kdebug ("done in0\n")
void Udc::send_csw ():
UDC_INDEX = 2
UDC_FIFO (2) = 0x53425355
UDC_FIFO (2) = tag
UDC_FIFO (2) = residue
UDC_FIFO8 (2) = status
UDC_INCSR |= UDC_INCSR_INPKTRDY
state = SENT_CSW
status = 0
residue = 0
//kdebug ("sent csw\n")
void Udc::stall (unsigned error):
if stalling:
Iris::debug ("already stalling!\n")
UDC_INCSR |= UDC_INCSR_SENDSTALL
stalling = true
state = STALL
unsigned Udc::big_endian (unsigned src):
return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
void Udc::handle_rx ():
buffer_page.set_flags (Iris::Page::FRAME)
UDC_INDEX = 1
if !(UDC_OUTCSR & UDC_OUTCSR_OUTPKTRDY):
Iris::panic (0, "no packet ready after out interrupt during rx")
if UDC_OUTCOUNT != max_packet_size_bulk:
Iris::panic (UDC_OUTCOUNT, "invalid packet size during rx")
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
((unsigned *)buffer)[(t + data_done) >> 2] = UDC_FIFO (1)
UDC_OUTCSR &= ~UDC_OUTCSR_OUTPKTRDY
data_done += max_packet_size_bulk
if data_done == 1 << block_bits:
//Iris::debug ("writing block %x\n", lba)
block.set_block (lba << block_bits, buffer_page, 1 << block_bits)
data_done = 0
--blocks
++lba
if blocks == 0:
send_csw ()
return
void Udc::handle_tx ():
if blocks == 0:
send_csw ()
return
if data_done == 0:
// read block lba.
buffer_page.set_flags (Iris::Page::FRAME)
block.get_block (lba << block_bits, 1 << block_bits, 0, buffer_page)
UDC_INDEX = 2
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
UDC_FIFO (2) = ((unsigned *)buffer)[(data_done + t) >> 2]
data_done += max_packet_size_bulk
if data_done == 1 << block_bits:
data_done = 0
++lba
--blocks
UDC_INCSR |= UDC_INCSR_INPKTRDY
void Udc::handle_cbw ():
UDC_INDEX = 1
unsigned csr = UDC_OUTCSR
unsigned size = UDC_OUTCOUNT
if csr & UDC_OUTCSR_SENDSTALL:
// When stalling, do nothing else.
//kdebug ("not responding to out during stall\n")
UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
return
if !(csr & UDC_OUTCSR_OUTPKTRDY):
// No packet; this shouldn't happen.
Iris::panic (0, "no packet")
return
// expect a new cbw.
if size != 31:
Iris::debug ("count %d != 31\n", size)
stall (2)
return
union Cbw:
unsigned u[8]
char b[32]
CBW cbw
Cbw cbw
for unsigned i = 0; i < 7; ++i:
cbw.u[i] = UDC_FIFO (1)
for unsigned i = 28; i < 31; ++i:
cbw.b[i] = UDC_FIFO8 (1)
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
tag = cbw.cbw.tag
if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
Iris::debug ("wrong cbw: sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
stall (2)
return
//kdebug ("bulk cbw\t")
#if 0
Iris::debug ("cbw:")
for unsigned i = 0; i < cbw.cbw.size; ++i:
kdebug_char (' ')
kdebug_num (cbw.cbw.data[i], 2)
Iris::debug ("\n")
#endif
UDC_INDEX = 2
bool to_host = cbw.cbw.flags & 0x80
switch cbw.cbw.data[0]:
case CBW::TEST_UNIT_READY:
if to_host || cbw.cbw.length != 0:
stall (2)
return
//Iris::debug ("sending ready response\t")
send_csw ()
break
case CBW::REQUEST_SENSE:
//Iris::debug ("sense requested\n")
send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
break
case CBW::FORMAT_UNIT:
Iris::panic (0, "FORMAT_UNIT isn't implemented")
case CBW::INQUIRY:
if !to_host:
stall (2)
return
//Iris::debug ("sending inquiry response\t")
// TODO: find out why these bytes are messed up.
send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
break
case CBW::RESERVE6:
Iris::panic (0, "RESERVE6 isn't implemented")
case CBW::RELEASE6:
Iris::panic (0, "RELEASE6 isn't implemented")
case CBW::SEND_DIAGNOSTIC:
Iris::panic (0, "SEND_DIAGNOSTIC isn't implemented")
case CBW::READ_CAPACITY:
if !to_host:
stall (2)
return
unsigned capacity[2]
capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
capacity[1] = big_endian (1 << block_bits)
//Iris::debug ("sending capacity: %x * %x\t", capacity[0], capacity[1])
send_padded ((char *)capacity, 8, cbw.cbw.length)
break
case CBW::READ10:
if !to_host:
stall (2)
return
lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
data_done = 0
state = TX
handle_tx ()
break
case CBW::WRITE10:
if to_host:
stall (2)
return
lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
if blocks == 0:
send_csw ()
break
state = RX
data_done = 0
buffer_page.set_flags (Iris::Page::FRAME)
break
case CBW::RESERVE10:
Iris::panic (0, "RESERVE10 isn't implemented")
case CBW::RELEASE10:
Iris::panic (0, "RELEASE10 isn't implemented")
default:
#if 0
Iris::debug ("unknown cbw:")
for unsigned i = 0; i < cbw.cbw.size; ++i:
kdebug_char (' ')
kdebug_num (cbw.cbw.data[i], 2)
Iris::debug ("\n")
#endif
residue = cbw.cbw.length
stall (1)
return
void Udc::interrupt ():
//Iris::debug ("interrupt, state = %d\n", state)
while true:
bool action = false
unsigned usb = UDC_INTRUSB
unsigned in = UDC_INTRIN
unsigned out = UDC_INTROUT
if usb & 4:
//Iris::debug ("reset\n")
reset ()
action = true
if state == STALL && in & 4:
// This must be handled here, because the state can be changed by the control request.
//Iris::debug ("stalling\n")
in &= ~4
if in & 1:
//Iris::debug ("control request\n")
irq_in0 ()
action = true
if in & 4:
//Iris::debug ("in request\n")
// Notification of sent packet (or stall, but we don't do that on the in endpoint).
switch state:
case SENT_CSW:
// csw received.
state = IDLE
break
case TX:
handle_tx ()
break
default:
Iris::panic (state, "invalid state for data send")
stall (2)
break
action = true
if out & 2:
//Iris::debug ("out request\n")
switch state:
case IDLE:
handle_cbw ()
break
case RX:
handle_rx ()
break
default:
stall (2)
Iris::panic (0, "invalid state for data receive")
break
action = true
if !action:
// No more interrupts to handle; this is normal, because we're looping until this happens.
//Iris::debug ("irq done\n")
return
Iris::Num start ():
map_udc ()
map_gpio ()
map_cpm ()
Udc udc
Iris::WBlock nand = Iris::my_parent.get_capability <Iris::WBlock> ()
udc.init (nand)
while true:
Iris::register_interrupt (IRQ_UDC)
Iris::wait ()
udc.interrupt ()

1
userspace/hardware Symbolic link
View File

@@ -0,0 +1 @@
nanonote

136
userspace/nanonote/boot.ccp Normal file
View File

@@ -0,0 +1,136 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/boot.ccp: Boot into another kernel.
// Copyright 2010 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>
extern "C":
extern unsigned pre_code, pre_end, post_code, post_end
struct args_t:
unsigned load
unsigned size
unsigned entry
unsigned source
Iris::Num start ():
unsigned *loader_addr = (unsigned *)0x15000
unsigned *page_addr = (unsigned *)0x16000
unsigned *tmp_addr = (unsigned *)0x17000
Iris::Boot cap = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_capability <Iris::Boot> (cap.copy ())
Iris::free_cap (cap)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::Boot::BOOT:
Iris::Block code = Iris::get_arg ()
unsigned load = Iris::recv.data[1].l
unsigned entry = Iris::recv.data[1].h
Iris::Num lsize = code.get_size ()
if lsize.h != 0:
Iris::panic (lsize.h, "string to boot is too large to be loaded")
unsigned size = lsize.l
unsigned pages = ((size + ~PAGE_MASK) >> PAGE_BITS) + 1
unsigned phys = Iris::my_memory.alloc_range (pages)
if phys & ~PAGE_MASK:
Iris::panic (size, "unable to allocate space for string to load")
unsigned target, offset
if phys < (load & ~0xa0000000):
Iris::debug ("pre-loading\n")
Iris::Page pre = Iris::my_memory.create_page ()
pre.alloc_physical (phys, true, true)
Iris::my_memory.map (pre, (unsigned)loader_addr)
for unsigned i = 0; i < &pre_end - &pre_code; ++i:
loader_addr[i] = (&pre_code)[i]
target = phys
offset = 1
else:
Iris::debug ("post-loading\n")
Iris::Page post = Iris::my_memory.create_page ()
post.alloc_physical (phys + ((pages - 1) << PAGE_BITS), true, true)
Iris::my_memory.map (post, (unsigned)loader_addr)
for unsigned i = 0; i < &post_end - &post_code; ++i:
loader_addr[i] = (&post_code)[i]
target = phys + ((pages - 1) << PAGE_BITS)
offset = 0
Iris::Page tmp = Iris::my_memory.create_page ()
tmp.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (tmp, (unsigned)tmp_addr)
for unsigned i = 0; i < pages - 1; ++i:
Iris::Page page = Iris::my_memory.create_page ()
page.alloc_physical (phys + ((i + offset) << PAGE_BITS), true, true)
Iris::my_memory.map (page, (unsigned)page_addr)
code.get_block (i << PAGE_BITS, PAGE_SIZE, 0, tmp)
for unsigned t = 0; t < PAGE_SIZE / 4; ++t:
page_addr[t] = tmp_addr[t]
args_t *args = (args_t *)((unsigned)loader_addr + PAGE_SIZE - sizeof (args_t))
unsigned phys_args = target + PAGE_SIZE - sizeof (args_t)
args->load = load
args->entry = entry
args->size = size
args->source = phys + (offset << PAGE_BITS) | 0x80000000
Iris::debug ("booting into: %x+%x->%x@%x (%x, %x)\n", args->source, args->size, args->load, args->entry, args, phys_args)
// Everything is set up; jump to the loader.
Iris::boot (target | 0x80000000, phys_args | 0x80000000)
Iris::panic (0, "Iris::boot should not return, but it does")
default:
Iris::panic (Iris::recv.data[0].l, "invalid commend received on boot capability")
asm volatile ("\t.set noreorder\n"
"\t.globl pre_code, pre_end, post_code, post_end\n"
"\t.text\n"
"pre_code:\n"
"\tlw $t0, 0($a0)\n" // t0 is the load address
"\tlw $t1, 4($a0)\n" // t1 is the size
"\tlw $t9, 8($a0)\n" // t9 is the entry point
"\tlw $t2, 12($a0)\n" // t2 is the source of the loaded image
"\tadd $t0, $t0, $t1\n" // t0 is the end of the load region
"\tadd $t2, $t2, $t1\n" // t2 is the end of the source
"1:\n"
"\tlw $t3, -4($t2)\n"
"\tsw $t3, -4($t0)\n"
"\taddiu $t2, $t2, -4\n"
"\taddiu $t1, $t1, -4\n"
"\tbnez $t1, 1b\n"
"\taddiu $t0, $t0, -4\n"
// Done copying
"\tjr $t9\n"
"\tnop\n"
"pre_end:\n"
"\n"
"post_code:\n"
"\tlw $t0, 0($a0)\n" // t0 is the load address
"\tlw $t1, 4($a0)\n" // t1 is the size
"\tlw $t9, 8($a0)\n" // t9 is the entry point
"\tlw $t2, 12($a0)\n" // t2 is the source of the loaded image
"1:\n"
"\tlw $t3, 0($t2)\n"
"\tsw $t3, 0($t0)\n"
"\taddiu $t2, $t2, 4\n"
"\taddiu $t1, $t1, -4\n"
"\tbnez $t1, 1b\n"
"\taddiu $t0, $t0, 4\n"
// Done copying
"\tjr $t9\n"
"\tnop\n"
"post_end:\n"
"\n"
"\t.set reorder\n")

View File

@@ -0,0 +1,97 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/buzzer.ccp: Piezo buzzer driver.
// 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"
#define ARCH
#include "arch.hh"
class DevBuzzer:
static unsigned const pwm = 4
Iris::Cap event
bool is_beeping
public:
DevBuzzer ():
is_beeping = false
tcu_stop_counter (pwm)
tcu_select_extalclk (pwm)
tcu_select_clk_div64 (pwm)
tcu_enable_pwm_output (pwm)
void stop ():
if !is_beeping:
return
tcu_stop_counter (pwm)
event.invoke ()
Iris::free_cap (event)
is_beeping = false
void beep (unsigned freq, unsigned ms, Iris::Cap cb):
stop ()
event = cb
unsigned full = JZ_EXTAL / 64 / freq
tcu_set_full_data (pwm, full)
tcu_set_half_data (pwm, full / 2)
tcu_set_count (pwm, 0)
tcu_start_counter (pwm)
Iris::my_receiver.set_alarm (ms * HZ / 1000)
is_beeping = true
enum codes:
BUZZER = 32
Iris::Num start ():
map_tcu ()
DevBuzzer buzzer
Iris::Buzzer dev = Iris::my_receiver.create_capability (BUZZER)
Iris::my_parent.provide_capability <Iris::Buzzer> (dev.copy ())
Iris::free_cap (dev)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
if Iris::recv.protected_data.h == ~0:
// Alarm.
buzzer.stop ()
continue
switch Iris::recv.protected_data.l:
case BUZZER:
// Buzzer device user request.
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
buzzer.stop ()
Iris::recv.reply.invoke ()
break
case Iris::Buzzer::BEEP:
// Volume is not used by this buzzer.
Iris::Cap arg = Iris::get_arg ()
Iris::Cap reply = Iris::get_reply ()
buzzer.beep (Iris::recv.data[1].l, Iris::recv.data[1].h, arg)
reply.invoke ()
Iris::free_cap (reply)
break
case Iris::Buzzer::STOP:
buzzer.stop ()
Iris::recv.reply.invoke ()
break
default:
kdebug ("Buzzer: other\n")
break
break
default:
kdebug ("Buzzer: unknown num: ")
kdebug_num (Iris::recv.protected_data.l)
kdebug ("\n")

299
userspace/nanonote/gpio.ccp Normal file
View File

@@ -0,0 +1,299 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/nanonote-gpio.ccp: gpio devices on the nanonote.
// 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"
#define ARCH
#include "arch.hh"
#include "keys.hh"
#define QI
#define SCAN_INTERVAL HZ / 50
class DevKbd:
static unsigned const NUM_COLS = 8
static unsigned const NUM_ROWS = 8
static unsigned const COLS_PORT = 2
static unsigned const ROWS_PORT = 3
static unsigned const ALL_COLS = 0x0003fc00
static unsigned const ALL_ROWS = 0x05fc0000
static unsigned const COLS[NUM_COLS]
static unsigned const ROWS[NUM_ROWS]
static unsigned const encode[NUM_ROWS][NUM_COLS]
static unsigned const NUM_KEYS = 58
static unsigned const keys[NUM_KEYS]
unsigned state[NUM_COLS]
Iris::Cap event
bool is_active
bool is_scanning
public:
unsigned size ():
return NUM_KEYS
void send_keys (unsigned first, Iris::Cap target):
unsigned d[4]
unsigned i
for i = 0; first + i < NUM_KEYS && i < 4; ++i:
d[i] = keys[first + i]
for ; i < 4; ++i:
d[i] = ~0
target.invoke (Iris::Num (d[0], d[1]), Iris::Num (d[2], d[3]))
bool scanning ():
return is_scanning
void inactive ():
if is_active:
Iris::free_cap (event)
is_active = false
void check (unsigned col, unsigned rowdata):
for unsigned r = 0; r < NUM_ROWS; ++r:
if !((rowdata ^ state[col]) & (1 << ROWS[r])):
continue
unsigned code = encode[r][col]
if rowdata & (1 << ROWS[r]):
code |= Iris::Keyboard::RELEASE
if is_active:
event.invoke (code)
state[col] = rowdata
void delay ():
for unsigned i = 0; i < 10000; ++i:
gpio_set (0, 0)
void scan ():
unsigned r
gpio_mask_irq (ROWS_PORT, ALL_ROWS)
is_scanning = false
if !is_active:
return
for unsigned c = 0; c < NUM_COLS; ++c:
gpio_as_input (COLS_PORT, ALL_COLS & ~(1 << COLS[c]))
gpio_as_output (COLS_PORT, 1 << COLS[c])
if c > 0:
check (c - 1, r)
delay ()
else:
check (0, state[0])
delay ()
r = gpio_get_port (ROWS_PORT) & ALL_ROWS
if r != ALL_ROWS:
is_scanning = true
gpio_as_output (COLS_PORT, ALL_COLS)
check (NUM_COLS - 1, r)
delay ()
r = gpio_get_port (ROWS_PORT) & ALL_ROWS
unsigned high = 0, low = 0
for unsigned i = 0; i < NUM_ROWS; ++i:
if r & (1 << ROWS[i]):
low |= 1 << ROWS[i]
else:
high |= 1 << ROWS[i]
gpio_as_interrupt (ROWS_PORT, high, true, true)
gpio_as_interrupt (ROWS_PORT, low, false, true)
gpio_unmask_irq (ROWS_PORT, ALL_ROWS)
void active (Iris::Cap cb):
inactive ()
event = cb
is_active = true
for unsigned c = 0; c < NUM_COLS; ++c:
state[c] = ALL_ROWS
scan ()
DevKbd ():
is_active = false
gpio_as_gpio (COLS_PORT, ALL_COLS)
gpio_as_gpio (ROWS_PORT, ALL_ROWS)
gpio_clear (COLS_PORT, ALL_COLS)
gpio_as_output (COLS_PORT, ALL_COLS)
gpio_as_input (ROWS_PORT, ALL_ROWS)
gpio_enable_pull (ROWS_PORT, ALL_ROWS)
for unsigned i = 0; i < NUM_COLS; ++i:
state[i] = ALL_ROWS
scan ()
unsigned const DevKbd::COLS[NUM_COLS] = { 10, 11, 12, 13, 14, 15, 16, 17 }
unsigned const DevKbd::ROWS[NUM_ROWS] = { 18, 19, 20, 21, 22, 23, 24, 26 }
unsigned const DevKbd::encode[NUM_ROWS][NUM_COLS] = {
#ifdef QI
{ Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7, ~0 },
{ Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I },
{ Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K },
{ Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M },
{ Key::TAB, Key::CAPS_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP },
{ Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT },
{ Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT },
{ Key::LEFT_SHIFT, Key::LEFT_ALT, Key::FN, ~0, ~0, ~0, ~0, ~0 }
#else
{ Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0, ~0 },
{ Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8 },
{ Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I },
{ Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K },
{ Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::UP },
{ Key::N9, Key::O, Key::L, Key::LEFT_ALT, Key::CAPS_LOCK, Key::SPACE, Key::EQUALS, Key::LEFT },
{ Key::BACKSPACE, Key::N0, Key::P, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT },
{ Key::FN, Key::LEFT_SHIFT, Key::LEFT_CONTROL, ~0, ~0, ~0, ~0, ~0 }
#endif
}
unsigned const DevKbd::keys[NUM_KEYS] = {
#ifdef QI
Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7,
Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I,
Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K,
Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M,
Key::TAB, Key::CAPS_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP,
Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT,
Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT,
Key::LEFT_SHIFT, Key::LEFT_ALT, Key::FN
#else
Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0,
Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8,
Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I,
Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K,
Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::UP,
Key::N9, Key::O, Key::L, Key::LEFT_ALT, Key::CAPS_LOCK, Key::SPACE, Key::EQUALS, Key::LEFT,
Key::BACKSPACE, Key::N0, Key::P, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT,
Key::FN, Key::LEFT_SHIFT, Key::LEFT_CONTROL
#endif
}
class Event:
bool state, started
unsigned pin
Iris::Cap cb
public:
void scan ():
if !started:
return
gpio_mask_irq (3, 1 << pin)
bool s = gpio_get_port (3) & (1 << pin)
if s != state:
state = s
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
gpio_as_interrupt (3, 1 << pin, !state, true)
gpio_unmask_irq (3, 1 << pin)
Event (unsigned p):
pin = p
gpio_as_gpio (3, pin)
state = true
started = false
void set_cb (Iris::Cap c):
if started:
Iris::free_cap (cb)
else:
started = true
cb = c
state = true
scan ()
enum codes:
KBD_DEV = 1
PWR
SDMMC
Iris::Num start ():
map_gpio ()
DevKbd kbd
Event pwr (29)
Event sdmmc (0)
Iris::Keyboard dev = Iris::my_receiver.create_capability (KBD_DEV)
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
Iris::Event sm = Iris::my_receiver.create_capability (SDMMC)
Iris::my_parent.provide_capability <Iris::Keyboard> (dev.copy (), 0)
Iris::my_parent.provide_capability <Iris::Keyboard> (pw.copy (), 1)
Iris::my_parent.provide_capability <Iris::Event> (sm.copy ())
Iris::free_cap (dev)
Iris::free_cap (pw)
Iris::free_cap (sm)
Iris::my_parent.init_done ()
if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::register_interrupt (IRQ_GPIO3)
while true:
Iris::wait ()
if Iris::recv.protected_data.h == ~0:
// Alarm.
kbd.scan ()
if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
continue
switch Iris::recv.protected_data.l:
case 0:
// Interrupt.
pwr.scan ()
kbd.scan ()
sdmmc.scan ()
if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::register_interrupt (IRQ_GPIO3)
break
case KBD_DEV:
// Keyboard device user request.
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply ()
kbd.active (Iris::get_arg ())
reply.invoke ()
Iris::free_cap (reply)
break
case Iris::Keyboard::GET_NUM_KEYS:
Iris::recv.reply.invoke (kbd.size ())
break
case Iris::Keyboard::GET_KEYS:
kbd.send_keys (Iris::recv.data[0].l, Iris::recv.reply)
break
default:
kdebug ("keyboard other\n")
break
break
case PWR:
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply ()
pwr.set_cb (Iris::get_arg ())
reply.invoke ()
Iris::free_cap (reply)
break
default:
kdebug ("Power button invalid request\n")
kdebug_num (Iris::recv.data[0].l)
kdebug ("\n")
break
break
case SDMMC:
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply ()
sdmmc.set_cb (Iris::get_arg ())
reply.invoke ()
Iris::free_cap (reply)
break
default:
kdebug ("SdMmc gpio invalid request\n")
kdebug_num (Iris::recv.data[0].l)
kdebug ("\n")
break
break
default:
kdebug ("keyboard unknown num: ")
kdebug_num (Iris::recv.protected_data.h)
kdebug ("\n")

470
userspace/nanonote/lcd.ccp Normal file
View File

@@ -0,0 +1,470 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/lcd.ccp: Display driver.
// 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"
#define ARCH
#include "arch.hh"
__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"source/data/charset.data\"\n.section .text")
extern unsigned char const charset[127-32][8][6]
#define assert(x) do { if (!(x)) { kdebug ("assertion failed " #x); while (true) {} } } while (0)
#if defined (TRENDTAC)
static unsigned h = 800, v = 480, fps = 60, Bpp = 2
#define LOG_X_BASE 1
#define LOG_Y_BASE 1
#elif defined (NANONOTE)
static unsigned h = 320, v = 240, fps = 60, Bpp = 4
#define LOG_X_BASE 0
#define LOG_Y_BASE 0
#else
#error unknown board
#endif
#define frame_size (v * h * Bpp)
static unsigned physical_descriptor
/**/struct Descriptor {
unsigned next;
unsigned frame;
unsigned id;
unsigned cmd;
} __attribute__ ((packed))
#if defined (NANONOTE)
#define SP_PORT 2
#define SPEN 21
#define SPDA 22
#define SPCK 23
static void udelay (unsigned num):
for unsigned i = 0; i < num * (JZ_EXTAL / 1000000); ++i:
// set 0 does nothing, but costs at least one clock pulse.
gpio_set (SP_PORT, 0)
// Register names. The registers are not named in the datasheet, and in some cases the name only describes a part of the bits in it.
// The registers with bit 6 set have bit 7 set instead, because of the transfer method.
enum spi_reg:
AC = 0x00
DC = 0x01
BRIGHTNESS = 0x03
FORMAT = 0x04
BACKLIGHT1 = 0x05
VBLANK = 0x06
HBLANK = 0x07
BACKLIGHT2 = 0x08
SYNC = 0x0b
POLARITY = 0x0c
CONTRAST_RGB = 0x0d
SUB_CONTRAST_R = 0x0e
SUB_BRIGHTNESS_R= 0x0f
SUB_CONTRAST_B = 0x10
SUB_BRIGHTNESS_B= 0x11
TRIM = 0x12
COLOR = 0x13
GAMMA = 0x16
GAMMA1 = 0x17
GAMMA2 = 0x18
GAMMA3 = 0x19
GAMMA4 = 0x1a
INVERSION = 0xa5
HLEVEL = 0xa6
LLEVEL = 0xa7
FB = 0xb1
static void write_reg (unsigned reg, unsigned val):
unsigned value = (reg << 8) | (val & 0xff)
gpio_clear (SP_PORT, 1 << SPEN)
udelay (1)
for unsigned i = 0; i < 16; ++i, value <<= 1:
gpio_clear (SP_PORT, 1 << SPCK)
if value & 0x8000:
gpio_set (SP_PORT, 1 << SPDA)
else:
gpio_clear (SP_PORT, 1 << SPDA)
udelay (4)
gpio_set (SP_PORT, 1 << SPCK)
udelay (4)
gpio_set (SP_PORT, 1 << SPEN)
udelay(4)
#endif
static void reset ():
#if defined (TRENDTAC)
// Note that the sync pulse is part of the pre-display region.
// Vertical timings.
unsigned vsync = 20, vpre = 20, vpost = 0
// Horizontal timings.
unsigned hsync = 80, hpre = 80, hpost = 0
// One clock pulse per pixel.
unsigned cpp = 1
// Bits per pixel.
unsigned bpp = LCD_CTRL_BPP_16
// Configuration.
#define MODE_TFT_GEN 0
#define VSYNC_N (1 << 8)
unsigned cfg = MODE_TFT_GEN | VSYNC_N
#elif defined (NANONOTE)
// Note that the sync pulse is part of the pre-display region.
// Horizontal timings.
unsigned hsync = 1, hpre = 70, hpost = 273
// Vertical timings.
unsigned vsync = 1, vpre = 21, vpost = 2
// 3 clocks per pixel.
unsigned cpp = 3
// Bits per pixel.
unsigned bpp = LCD_CTRL_BPP_18_24
// Configuration.
unsigned cfg = LCD_CFG_MODE_SERIAL_TFT | LCD_CFG_HSP | LCD_CFG_VSP | LCD_CFG_PCP
// Set up SPI pins.
gpio_as_output (SP_PORT, (1 << SPEN) | (1 << SPCK) | (1 << SPDA))
gpio_set (SP_PORT, (1 << SPEN) | (1 << SPCK))
#else
#error unknown board
#endif
// Note that the sync pulse is part of the pre-display region.
unsigned vpe = vsync, vds = vpre, vde = vds + v, vt = vde + vpost
unsigned hpe = hsync, hds = hpre, hde = hds + h, ht = hde + hpost
cpm_stop_lcd ()
unsigned pixclock = fps * ht * vt
#if defined (TRENDTAC)
unsigned pllout = cpm_get_pllout ()
CPM_CFCR2 = pllout / pixclock - 1
unsigned val = pllout / (pixclock * 4) - 1
assert (pllout / (val + 1) <= 150000000)
assert (val <= 0xf)
cpm_set_lcdclk_div (val)
CPM_CFCR |= CPM_CFCR_UPE
#elif defined (NANONOTE)
unsigned val = cpm_get_pllout2 () / pixclock - 1
//assert (val < 0x400)
//cpm_set_pixdiv (val)
//cpm_set_pixdiv (12)
val = cpm_get_pllout2 () / (pixclock * 3) - 1
assert (val < 0x20)
//cpm_set_ldiv (val)
// Update dividers.
//CPM_CPCCR |= CPM_CPCCR_CE
#else
#error "Unknown board"
#endif
cpm_start_lcd ()
#ifdef NANONOTE
// Reset the controller.
write_reg (BACKLIGHT1, 0x1e)
// Enable display.
write_reg (BACKLIGHT1, 0x5e)
// Set data to rgbrgbrgb input, with a delta color filter.
write_reg (COLOR, 0x01)
#endif
LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM
LCD_CFG = cfg
LCD_HSYNC = hpe
LCD_VSYNC = vpe
LCD_VAT = (ht << 16) | vt
LCD_DAH = (hds << 16) | hde
LCD_DAV = (vds << 16) | vde
LCD_DA0 = physical_descriptor
LCD_STATE = 0
LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM | LCD_CTRL_ENA
static void putchar (unsigned x, unsigned y, unsigned ch):
if ch < 32 || ch > 126:
ch = 127
ch -= 32
for unsigned k = 0; k < 6; ++k:
for unsigned r = 0; r < 8; ++r:
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = charset[ch][r][k] * 0x00010101
static unsigned log_x = LOG_X_BASE, log_y = LOG_Y_BASE
static void inc_logx ():
if ++log_x >= h / 6:
log_x = LOG_X_BASE
if ++log_y >= v / 8:
log_y = LOG_Y_BASE
static void log_char (unsigned ch):
switch ch:
case '\n':
while log_x < h / 6:
putchar (log_x++, log_y, ' ')
inc_logx ()
break
default:
putchar (log_x, log_y, ch)
inc_logx ()
static void log_str (char const *str):
while *str:
log_char (*str++)
static void log_num (Iris::Num n):
char const *encode = "0123456789abcdef"
log_char ('[')
for unsigned i = 0; i < 8; ++i:
log_char (encode[(n.h >> (4 * (7 - i))) & 0xf])
log_char (' ')
for unsigned i = 0; i < 8; ++i:
log_char (encode[(n.l >> (4 * (7 - i))) & 0xf])
log_char (']')
static void log_msg ():
log_str ("prot:")
log_num (Iris::recv.protected_data)
log_str ("data:")
for unsigned i = 0; i < 2; ++i:
log_num (Iris::recv.data[i])
log_char ('\n')
enum captype:
LOG = 1
BACKLIGHT
LCD
static unsigned spot (unsigned x, unsigned y, unsigned cx, unsigned cy):
unsigned dx2 = (x - cx) * (x - cx)
unsigned dy2 = (y - cy) * (y - cy)
unsigned d2 = dx2 + dy2
unsigned l = 120
if d2 >= l * l:
return 0
return ((l * l - d2 - 1) << 8) / (l * l)
static unsigned pages
static Descriptor descriptor __attribute__ ((aligned (16)))
static bool is_on
static unsigned create (Iris::Memory mem):
unsigned physical = mem.alloc_range (pages)
unsigned address = 0x15000
if physical & ~PAGE_MASK:
Iris::panic (0, "can't allocate framebuffer")
assert (physical & PAGE_MASK && ~physical)
for unsigned i = 0; i < pages; ++i:
Iris::Page p = mem.create_page ()
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
if address != ~0:
mem.map (p, address + (i << PAGE_BITS))
Iris::free_cap (p)
return physical
static void destroy (unsigned physical, Iris::Memory mem):
unsigned address = 0x15000
if physical == ~0:
Iris::panic (0, "unable to destroy framebuffer with wrong cap0")
if descriptor.frame == physical && is_on:
lcd_clr_ena ()
#ifdef NANONOTE
write_reg (BACKLIGHT1, 0x5e)
#endif
if address != ~0:
for unsigned i = 0; i < pages; ++i:
Iris::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
mem.destroy (p)
Iris::free_cap (p)
static void use (unsigned physical):
if physical == ~0:
Iris::panic (0, "unable to use framebuffer with wrong cap0")
bool was_unused = descriptor.frame == 0
descriptor.frame = physical
unsigned dptr = (unsigned)&descriptor
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
if was_unused && is_on:
lcd_set_ena ()
#ifdef NANONOTE:
write_reg (BACKLIGHT1, 0x5f)
#endif
static void unuse (unsigned physical):
if physical == ~0:
Iris::panic (0, "unable to unuse framebuffer with wrong cap0")
if descriptor.frame == physical:
lcd_clr_ena ()
#ifdef NANONOTE
write_reg (BACKLIGHT1, 0x5e)
#endif
descriptor.frame = 0
Iris::Num start ():
Iris::schedule ()
map_lcd ()
map_cpm ()
#ifdef NANONOTE
map_gpio ()
#endif
pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
unsigned physical = 0
Iris::Page p = Iris::my_memory.mapping (&descriptor)
unsigned paddr = p.physical_address ()
physical_descriptor = paddr + ((unsigned)&descriptor & ~PAGE_MASK)
Iris::free_cap (p)
descriptor.next = physical_descriptor
descriptor.frame = physical
descriptor.id = 0xdeadbeef
descriptor.cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT)
unsigned dptr = (unsigned)&descriptor
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
reset ()
#if defined (TRENDTAC)
Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
#endif
// Register the backlight device.
Iris::Setting backlight = Iris::my_receiver.create_capability (BACKLIGHT)
Iris::my_parent.provide_capability <Iris::Setting> (backlight.copy ())
Iris::free_cap (backlight)
// Register the display device.
Iris::Display display = Iris::my_receiver.create_capability (LCD)
Iris::my_parent.provide_capability <Iris::Display> (display.copy ())
Iris::free_cap (display)
Iris::my_parent.init_done ()
Iris::Cap eof_cb
bool have_eof = false
is_on = true
while true:
Iris::wait ()
//log_msg ()
switch Iris::recv.protected_data.l:
case 0:
have_eof = false
eof_cb.invoke ()
Iris::free_cap (eof_cb)
break
#if defined (TRENDTAC)
case LOG:
log_char (Iris::recv.data[0].l)
break
#endif
case BACKLIGHT:
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Setting::SET:
// TODO
unsigned state = Iris::recv.data[1].l
if !state:
#if defined (NANONOTE)
if is_on:
write_reg (BACKLIGHT1, 0x5e)
is_on = false
#else
#endif
else:
#if defined (NANONOTE)
if !is_on:
write_reg (BACKLIGHT1, 0x5f)
is_on = true
#else
#endif
Iris::recv.reply.invoke ()
break
case Iris::Setting::GET_RANGE:
Iris::recv.reply.invoke (~0)
break
default:
Iris::panic (0, "invalid operation for backlight")
break
break
case LCD:
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Display::SET_EOF_CB:
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
if have_eof:
Iris::free_cap (eof_cb)
Iris::panic (0, "replacing eof_cb")
else:
lcd_clr_eof ()
Iris::register_interrupt (IRQ_LCD)
have_eof = true
eof_cb = arg
reply.invoke ()
Iris::free_cap (reply)
break
case Iris::Display::MAP_FB:
unsigned addr = Iris::recv.data[1].l
unsigned use = Iris::recv.data[0].h
Iris::Cap reply = Iris::get_reply ()
Iris::Memory mem = Iris::get_arg ()
unsigned physical = mem.alloc_range (pages)
assert (physical & PAGE_MASK && ~physical)
Iris::Caps ret = mem.create_caps (pages / 63 + 1)
unsigned slot = ret.use ()
for unsigned c = 0; c < pages / 63 + 1; ++c:
Iris::Caps caps (Iris::Cap (slot, c))
unsigned num = pages - 63 * c >= 63 ? 63 : pages - 63 * c
Iris::set_recv_arg (caps)
mem.create_caps (num)
unsigned slot2 = caps.use ()
for unsigned i = 0; i < num; ++i:
Iris::Page p = Iris::Cap (slot2, i)
Iris::set_recv_arg (p)
mem.create_page ()
p.alloc_physical (physical + ((63 * c + i) << PAGE_BITS), false, true)
mem.map (p, addr + ((63 * c + i) << PAGE_BITS))
Iris::free_slot (slot2)
Iris::free_slot (slot)
reply.invoke (0, 0, ret.copy ())
Iris::free_cap (ret)
Iris::free_cap (mem)
Iris::free_cap (reply)
if !use:
break
bool was_unused = descriptor.frame == 0
descriptor.frame = physical
unsigned dptr = (unsigned)&descriptor
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
if was_unused && is_on:
lcd_set_ena ()
#ifdef NANONOTE:
write_reg (BACKLIGHT1, 0x5f)
#endif
break
case Iris::Display::UNMAP_FB:
Iris::panic (0, "unmap_fb isn't implemented yet")
case Iris::Display::GET_INFO:
Iris::panic (0, "get_info isn't implemented yet.")
default:
Iris::panic (Iris::recv.data[0].l, "invalid operation for lcd")
break
default:
Iris::panic (0, "invalid operation type for lcd")
break

180
userspace/nanonote/nand.ccp Normal file
View File

@@ -0,0 +1,180 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/nand.ccp: NAND driver.
// 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"
#define ARCH
#include "arch.hh"
#define debug Iris::debug
#define DELAY Iris::schedule
#include "nand.hh"
#undef debug
static unsigned *cache
static bool dirty
static unsigned current_block
static void sync ():
//Iris::debug ("erasing %x\n", current_block << block_bits)
erase (current_block << block_bits)
for unsigned p = 0; p < 1 << (block_bits - page_bits); ++p:
write ((current_block << block_bits) + (p << page_bits), (char *)&cache[p << (page_bits - 2)])
static void read_block (unsigned b):
if b == current_block:
return
if current_block != ~0 && dirty:
sync ()
current_block = b
//kdebug ("setting current block to ")
//kdebug_num (b)
//kdebug ("\n")
for unsigned p = 0; p < 1 << (block_bits - 9); ++p:
read ((b << block_bits) + (p << 9), (char *)&cache[p << (9 - 2)])
dirty = false
Iris::Num start ():
map_emc ()
map_gpio ()
// Arbitrary addresses where the pages are mapped.
command = (volatile char *)0x15000
address = (volatile char *)0x16000
data = (volatile char *)0x17000
Iris::Page data_page = Iris::my_memory.create_page ()
Iris::Page command_page = Iris::my_memory.create_page ()
Iris::Page address_page = Iris::my_memory.create_page ()
unsigned base = 0x18000000
data_page.alloc_physical (base, false, false)
command_page.alloc_physical (base + 0x8000, false, false)
address_page.alloc_physical (base + 0x10000, false, false)
Iris::my_memory.map (data_page, (unsigned)data)
Iris::my_memory.map (command_page, (unsigned)command)
Iris::my_memory.map (address_page, (unsigned)address)
Iris::free_cap (data_page)
Iris::free_cap (command_page)
Iris::free_cap (address_page)
reset ()
current_block = ~0
dirty = false
cache = (unsigned *)0x40000000
for unsigned p = 0; p < 1 << (block_bits - PAGE_BITS); ++p:
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (page, (unsigned)cache + (p << PAGE_BITS))
Iris::free_cap (page)
Iris::Page tmp = Iris::my_memory.create_page ()
tmp.set_flags (Iris::Page::PAYING)
unsigned *tmp_addr = (unsigned *)0x3ffff000
Iris::my_memory.map (tmp, (unsigned)tmp_addr)
Iris::Cap cap = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
Iris::free_cap (cap)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::Block::GET_SIZE:
if size_bits > 32:
Iris::recv.reply.invoke (Iris::Num (0, 1 << (size_bits - 32)))
else:
Iris::recv.reply.invoke (1 << size_bits)
break
case Iris::Block::GET_ALIGN_BITS:
Iris::recv.reply.invoke (9)
break
case Iris::Block::GET_BLOCK:
unsigned row = Iris::recv.data[1].value () >> 9
unsigned block = row >> (block_bits - 9)
row &= (1 << (block_bits - 9)) - 1
unsigned offset = Iris::recv.data[0].h & 0xe00
unsigned size = Iris::recv.data[0].h >> 16
if size + offset >= 0x1000:
size = 0x1000 - offset
#if 0
kdebug ("get ")
kdebug_num (block)
kdebug (":")
kdebug_num (row)
kdebug ("+")
kdebug_num (size)
kdebug ("@")
kdebug_num (offset)
kdebug ("\n")
#endif
read_block (block)
Iris::Cap reply = Iris::get_reply ()
Iris::Page page = Iris::get_arg ()
page.share (tmp)
tmp.set_flags (Iris::Page::FRAME)
for unsigned t = 0; t < size >> 2; ++t:
tmp_addr[(offset >> 2) + t] = cache[t + (row << (9 - 2))]
tmp.set_flags (0, Iris::Page::FRAME)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (page)
break
case Iris::WBlock::SET_BLOCK:
unsigned row = Iris::recv.data[1].value () >> 9
unsigned block = row >> (block_bits - 9)
row &= (1 << (block_bits - 9)) - 1
unsigned offset = Iris::recv.data[0].h & 0xe00
unsigned size = Iris::recv.data[0].h >> 16
if size + offset >= 0x1000:
size = 0x1000 - offset
#if 0
kdebug ("set ")
kdebug_num (block)
kdebug (":")
kdebug_num (row)
kdebug ("+")
kdebug_num (size)
kdebug ("@")
kdebug_num (offset)
kdebug ("\n")
#endif
//kdebug_num (current_block)
//kdebug ("/")
read_block (block)
Iris::Cap reply = Iris::get_reply ()
Iris::Page page = Iris::get_arg ()
page.share (tmp)
tmp.set_flags (Iris::Page::FRAME)
for unsigned t = 0; t < size; t += 4:
cache[(offset + t + (row << 9)) >> 2] = tmp_addr[(offset + t) >> 2]
tmp.set_flags (0, Iris::Page::FRAME)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (page)
dirty = true
//kdebug_num (current_block)
//kdebug ("!")
break
case Iris::WBlock::TRUNCATE:
default:
Iris::recv.reply.invoke (Iris::ERR_INVALID_OPERATION)
break

153
userspace/nanonote/rtc.ccp Normal file
View File

@@ -0,0 +1,153 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/rtc.ccp: real-time clock driver.
// Copyright 2010 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"
#define ARCH
#include "arch.hh"
static Iris::Font font
static void ready ():
while !rtc_write_ready ():
Iris::schedule ()
static unsigned get_second ():
ready ()
unsigned ret = rtc_get_second ()
unsigned r2
while true:
ready ()
r2 = rtc_get_second ()
if ret == r2:
return ret
kdebug ("ret != r2\n")
ret = r2
Iris::Num start ():
map_cpm ()
map_rtc ()
cpm_start_rtc ()
ready ()
rtc_enabled ()
if rtc_get_scratch_pattern () != 0xbeefface:
ready ()
rtc_set_nc1Hz_val (RTC_CLOCK)
ready ()
rtc_set_adjc_val (0)
ready ()
rtc_set_second (0)
ready ()
rtc_set_alarm_second (0)
ready ()
rtc_set_scratch_pattern (0xbeefface)
ready ()
rtc_disable_alarm ()
ready ()
rtc_clear_alarm_flag ()
ready ()
rtc_enable_alarm_irq ()
ready ()
rtc_disable_1Hz_irq ()
ready ()
rtc_set_hwfcr_val (0x1e0)
ready ()
rtc_set_hrcr_val (0xfe0)
ready ()
rtc_disable_alarm_wakeup ()
Iris::RTC self = Iris::my_receiver.create_capability (1)
Iris::my_parent.provide_capability <Iris::RTC> (self.copy ())
Iris::free_cap (self)
Iris::my_parent.init_done ()
bool have_interrupt = false
Iris::Cap interrupt
while true:
Iris::wait ()
if Iris::recv.protected_data.l == 0:
// Interrupt.
ready ()
rtc_disable_alarm ()
ready ()
rtc_disable_alarm_wakeup ()
if have_interrupt:
interrupt.invoke (0)
Iris::free_cap (interrupt)
have_interrupt = false
continue
switch Iris::recv.data[0].l:
case Iris::RTC::SETUP:
ready ()
rtc_set_nc1Hz_val (Iris::recv.data[1].l)
ready ()
rtc_set_adjc_val (Iris::recv.data[1].h)
Iris::recv.reply.invoke ()
break
case Iris::RTC::GET_TIME:
ready ()
Iris::recv.reply.invoke (rtc_get_second ())
Iris::recv.reply.invoke (0)
break
case Iris::RTC::SET_TIME:
ready ()
rtc_set_second (Iris::recv.data[1].l)
Iris::recv.reply.invoke ()
break
case Iris::RTC::GET_ALARM:
ready ()
Iris::recv.reply.invoke (rtc_get_alarm_second (), rtc_alarm_is_enabled ())
Iris::recv.reply.invoke (0)
break
case Iris::RTC::UNSET_ALARM:
Iris::Cap reply = Iris::get_reply ()
if have_interrupt:
have_interrupt = false
interrupt.invoke (~0)
Iris::free_cap (interrupt)
Iris::unregister_interrupt (IRQ_RTC)
ready ()
rtc_disable_alarm ()
ready ()
rtc_disable_alarm_wakeup ()
reply.invoke ()
Iris::free_cap (reply)
case Iris::RTC::SET_ALARM:
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
unsigned alarm = Iris::recv.data[1].l
if have_interrupt:
Iris::debug ("not registering irq\n")
interrupt.invoke (~0)
Iris::free_cap (interrupt)
else:
Iris::debug ("registering irq\n")
Iris::register_interrupt (IRQ_RTC)
interrupt = arg
have_interrupt = true
ready ()
rtc_set_alarm_second (alarm)
ready ()
rtc_clear_alarm_flag ()
ready ()
rtc_enable_alarm ()
ready ()
rtc_enable_alarm_wakeup ()
reply.invoke ()
Iris::free_cap (reply)
break
default:
Iris::panic (Iris::recv.data[0].l, "invalid rtc request")
return 0

View File

@@ -0,0 +1,590 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/sd+mmc.ccp: sd+mmc driver.
// 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"
#define ARCH
#include "arch.hh"
class Mmc:
public:
enum Response_type:
NONE = MSC_CMDAT_RESPONSE_NONE
RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ
WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE
R1 = MSC_CMDAT_RESPONSE_R1
R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
R2 = MSC_CMDAT_RESPONSE_R2
R3 = MSC_CMDAT_RESPONSE_R3
R4 = MSC_CMDAT_RESPONSE_R4
R5 = MSC_CMDAT_RESPONSE_R5
R6 = MSC_CMDAT_RESPONSE_R6
R7 = MSC_CMDAT_RESPONSE_R7
static unsigned const POWER_PORT = 3
static unsigned const POWER_PIN = 2
struct CID:
unsigned mid
char oid[2]
char pnm[5]
unsigned prv
unsigned psn
unsigned year
unsigned month
struct CSD:
unsigned c_size
unsigned c_size_mult
unsigned read_bl_len, write_bl_len
bool copy
bool perm_write_protect
bool tmp_write_protect
bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
void check_sd ()
void check_sdmem ()
void check_mmc ()
public:
void reset ()
void detect ()
void release ()
void interrupt ()
CID const &get_cid ():
return cid
unsigned get_num_blocks ():
return num_blocks
unsigned get_read_block_size ():
return read_block_size
unsigned get_block_bits ():
return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
void read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
void wait_write ()
void add_cb (Iris::Listitem item):
cb_list.add_item (item)
private:
void set_block (unsigned block)
unsigned current_block_num
bool dirty
unsigned *current_block
unsigned rca
bool have_sdmem, have_io
bool hc
CID cid
CSD csd
unsigned num_blocks, read_block_size
Iris::Page buffer_page
Iris::List cb_list
static unsigned const buffer = 0x15000
bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
MSC_CMD = cmd
MSC_ARG = arg
MSC_CMDAT = response_type
MSC_IMASK = ~MSC_IMASK_END_CMD_RES
Iris::register_interrupt (IRQ_MSC)
msc_start_op ()
Iris::wait_for_interrupt ()
MSC_IMASK = ~0
//kdebug ("cmd: ")
//kdebug_num (cmd)
unsigned stat = MSC_STAT
//kdebug (", stat: ")
//kdebug_num (stat)
//kdebug ("\n")
if stat & MSC_STAT_CRC_RES_ERR:
Iris::panic (0, "crc error in mmc response")
return false
if stat & MSC_STAT_TIME_OUT_RES:
kdebug ("time out waiting for mmc response\n")
MSC_IREG = MSC_IREG_END_CMD_RES
return false
if response_type == R2:
unsigned d = MSC_RES
if d >> 8 != 0x3f:
Iris::panic (d, "invalid r2 response")
if cmd == 3:
// Read out result.
cid.mid = d & 0xff
d = MSC_RES
cid.oid[0] = d >> 8
cid.oid[1] = d & 0xff
d = MSC_RES
cid.pnm[0] = d >> 8
cid.pnm[1] = d & 0xff
d = MSC_RES
cid.pnm[2] = d >> 8
cid.pnm[3] = d & 0xff
d = MSC_RES
cid.pnm[4] = d >> 8
cid.prv = d & 0xff
d = MSC_RES
cid.psn = d << 16
d = MSC_RES
cid.psn |= d
d = MSC_RES
cid.year = 2000 + (d >> 4 & 0xff)
cid.month = d & 0xf
#if 1
Iris::debug ("CID: mid=%x, oid=%x %x, pnm=%x %x %x %x %x, prv=%x, psn=%x, year=%x, month=%x\n", cid.mid, cid.oid[0], cid.oid[1], cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cid.prv, cid.psn, cid.year, cid.month)
#endif
else:
// Header (8) 1.0 1.0
// Read out csd.
// Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
d = MSC_RES
// Ignore taac and nsac. 8 + 8 2.0 4.0 ***
d = MSC_RES
// Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
d = MSC_RES
// Ignore rest of ccc. 4/12 0.4 6.4
// 4 0.4 7.0
csd.read_bl_len = (d >> 8) & 0xf
// Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
// 2/12 0.2 8.0 ***
csd.c_size = (d & 0x0003) << 10
d = MSC_RES
// 10/12 1.2 9.2
csd.c_size |= d >> 6
// Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
d = MSC_RES
// Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
// 3 0.3 11.1
csd.c_size_mult = (d >> 7) & 0x7
// Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
d = MSC_RES
// Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
// 2/4 0.4 14.0 ***
csd.write_bl_len = (d << 2) & 0xc
d = MSC_RES
// 2/4 0.2 14.2
csd.write_bl_len |= (d >> 14) & 0x3
// Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
// 1 0.1 15.2
csd.copy = d & 0x40
// 1 0.1 15.3
csd.perm_write_protect = d & 0x20
// 1 0.1 15.4
csd.tmp_write_protect = d & 0x10
// Ignore file_format. 2 (+ 2) 0.4 16.0 ***
read_block_size = hc ? 512 : 1 << csd.read_bl_len
num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
if hc:
if csd.read_bl_len < 9:
num_blocks >>= 9 - csd.read_bl_len
else:
num_blocks <<= csd.read_bl_len - 9
#if 1
Iris::debug ("CSD: size=%x<<%x, r/w len=%x/%x, %s, %s, %s\n", csd.c_size, csd.c_size_mult, csd.read_bl_len, csd.write_bl_len, csd.copy ? "copy" : "no copy", csd.perm_write_protect ? "fixed write protect" : "no fixed write protect", csd.tmp_write_protect ? "write protect" : "no write protect")
#endif
unsigned c_size
unsigned c_size_mult
unsigned read_bl_len, write_bl_len
bool copy
bool perm_write_protect
bool tmp_write_protect
else if response_type != NONE:
unsigned r = MSC_RES
if response_type == R3:
if r >> 8 != 0x3f:
Iris::panic (r, "r3 response was not 3f")
else if r >> 8 != cmd:
kdebug ("stat: ")
kdebug_num (MSC_STAT)
kdebug ("; response: ")
kdebug_num (r)
kdebug ("; cmd: ")
kdebug_num (cmd)
Iris::panic (r, "response doesn't match command")
r <<= 24
r |= MSC_RES << 8
r |= MSC_RES & 0xff
if response:
*response = r
else:
//kdebug ("extra response fifo read: ")
//for unsigned i = 0; i < 9; ++i:
//kdebug (" ")
//kdebug_num (MSC_RES, 4)
//kdebug ("\n")
MSC_IREG = MSC_IREG_END_CMD_RES
return true
void Mmc::reset ():
current_block_num = ~0
dirty = false
cb_list = Iris::my_memory.create_list ()
current_block = (unsigned *)(buffer + PAGE_SIZE)
// Create a buffer to use for data transfer.
buffer_page = Iris::my_memory.create_page ()
Iris::my_memory.map (buffer_page, buffer)
// Reset all state, by faking a release event.
release ()
// Enable 25 MHz clock to msc.
CPM_MSCCDR = 13
cpm_start_msc ()
// Enable msc pins.
gpio_as_msc ()
// Disable power to card.
gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
gpio_as_output (POWER_PORT, 1 << POWER_PIN)
gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
gpio_set (POWER_PORT, 1 << POWER_PIN)
// Stop the clock.
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
while MSC_STAT & MSC_STAT_CLK_EN:
//kdebug (",")
Iris::sleep (1)
// Reset controller and inserted devices.
MSC_STRPCL = MSC_STRPCL_RESET
while MSC_STAT & MSC_STAT_IS_RESETTING:
//kdebug (":")
Iris::sleep (1)
// Initialize registers.
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1
MSC_RESTO = 64
MSC_RDTO = ~0
MSC_BLKLEN = 0x200
MSC_NOB = 0
MSC_IREG = ~0
MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ)
MSC_ARG = 0
// Start the clock.
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
// Set cards, if any, to idle.
send (0, 0, NONE)
// Reset SDIO device, if any. Don't do this, because it breaks for some reason.
//send (52, 0x88000c08, R5)
void Mmc::check_mmc ():
//kdebug ("checking mmc\n")
// 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
// 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
// 6. If the response timeout occurs, goto 9.
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
void Mmc::check_sdmem ():
kdebug ("checking sdmem\n")
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
unsigned code
hc = false
if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
kdebug ("hc\n")
hc = true
if !send (55, 0, R1, &code):
check_mmc ()
return
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
check_mmc ()
return
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
unsigned retries = 100
while !(code & (1 << 31)) && --retries:
if !send (55, 0, R1, &code):
return
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
return
Iris::sleep (1)
if !(code & (1 << 31)):
Iris::panic (code, "card fails to finish setting up")
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
if !send (2, 0, R2):
Iris::panic (0, "card failed to send CID")
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
rca = 0
while !rca:
if !send (3, 0, R6, &rca):
Iris::panic (0, "card failed to provide rca")
rca &= 0xffff0000
kdebug ("received rca ")
kdebug_num (rca >> 16, 4)
kdebug ("\n")
have_sdmem = true
void Mmc::check_sd ():
//kdebug ("checking sdio\n")
if !send (0, 0, NONE):
Iris::panic (0, "unable to reset cards?")
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
unsigned code
if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
check_sdmem ()
return
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
while !(code & (1 << 31)):
if !send (5, 1 << 20, R4, &code):
Iris::panic (0, "invalid response to cmd 5")
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card.
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
have_io = true
if code & (1 << 27):
check_sdmem ()
return
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
rca = 0
while rca == 0:
if !send (3, 0, R6, &rca):
Iris::panic (0, "unable to set rca")
rca &= 0xffff0000
check_mmc ()
void Mmc::detect ():
kdebug ("mmc detect\n")
gpio_clear (POWER_PORT, 1 << POWER_PIN)
check_sd ()
check_mmc ()
if have_sdmem:
if !send (9, rca, R2):
Iris::panic (0, "unable to request csd")
if !send (7, rca, R1B):
Iris::panic (0, "unable to select sdmem")
kdebug ("found device; size = ")
kdebug_num (num_blocks)
kdebug (" * ")
kdebug_num (read_block_size)
kdebug (" = ")
kdebug_num (num_blocks * read_block_size)
kdebug ("\n")
// Set up buffer memory.
for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
Iris::Page p = Iris::my_memory.create_page ()
p.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (p, (unsigned)current_block + i)
Iris::free_cap (p)
Iris::Listitem item = cb_list.get_next ()
while item.code != Iris::Cap ().code:
Iris::Cap c = cb_list.get_cap (item)
c.invoke (0, ~0)
Iris::free_cap (c)
Iris::Listitem nextitem = cb_list.get_next (item);
Iris::free_cap (item)
item = nextitem
void Mmc::release ():
kdebug ("mmc release\n")
gpio_set (POWER_PORT, 1 << POWER_PIN)
have_sdmem = false
have_io = false
read_block_size = 0
if num_blocks != 0:
for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
Iris::Page p = Iris::my_memory.mapping ((void *)((unsigned)current_block + i))
Iris::my_memory.destroy (p)
Iris::free_cap (p)
if dirty:
Iris::debug ("Warning: sd/mmc card removed before data was written to it")
current_block_num = ~0
dirty = false
num_blocks = 0
Iris::Listitem item = cb_list.get_next ()
while item.code != Iris::Cap ().code:
Iris::Cap c = cb_list.get_cap (item)
c.invoke (0, ~0)
Iris::free_cap (c)
Iris::Listitem nextitem = cb_list.get_next (item);
Iris::free_cap (item)
item = nextitem
void Mmc::interrupt ():
kdebug ("mmc interrupt\n")
void Mmc::set_block (unsigned block):
if current_block_num == block:
return
if dirty && current_block_num != ~0:
MSC_NOB = 1
MSC_BLKLEN = 1 << csd.write_bl_len
if !send (24, (current_block_num << csd.write_bl_len), WR_DATA):
Iris::panic (0, "unable to send data")
MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ
for unsigned a = 0; a < 1 << csd.write_bl_len; a += 4:
while MSC_STAT & MSC_STAT_DATA_FIFO_FULL:
Iris::register_interrupt (IRQ_MSC)
Iris::wait_for_interrupt ()
MSC_TXFIFO = current_block[a >> 2]
MSC_IMASK = ~0
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
//kdebug ("done writing page\n")
current_block_num = block
dirty = false
MSC_NOB = 1
MSC_BLKLEN = 1 << 9
for unsigned a = 0; a < 1 << csd.write_bl_len; a += 1 << 9:
if !send (17, (block << csd.write_bl_len) + a, RD_DATA):
Iris::panic (0, "unable to request data")
MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ
for unsigned aa = 0; aa < 1 << 9; aa += 4:
while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY:
Iris::register_interrupt (IRQ_MSC)
Iris::wait_for_interrupt ()
current_block[(a + aa) >> 2] = MSC_RXFIFO
MSC_IMASK = ~0
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
//kdebug ("done filling page\n")
void Mmc::read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
if address.value () >> (csd.write_bl_len + 32):
Iris::panic (address.h, "page too high: not supported")
unsigned block = address.value () >> csd.write_bl_len
unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
set_block (block)
unsigned blockmask = ~((1 << 9) - 1)
size &= blockmask
offset &= ~PAGE_MASK & ~3
if size + offset > PAGE_SIZE:
size = PAGE_SIZE - offset
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
page.share (buffer_page)
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
page.set_flags (0, Iris::Page::PAYING)
for unsigned i = 0; i < size; i += 4:
((unsigned *)buffer)[(offset + i) >> 2] = current_block[(start_pos + i) >> 2]
void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
if address.value () >> (csd.write_bl_len + 32):
Iris::panic (address.h, "page too high: not supported")
unsigned block = address.value () >> csd.write_bl_len
unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
set_block (block)
unsigned blockmask = ~((1 << 9) - 1)
size &= blockmask
offset &= ~PAGE_MASK & ~3
if size + offset > PAGE_SIZE:
size = PAGE_SIZE - offset
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
page.share (buffer_page)
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
page.set_flags (0, Iris::Page::PAYING)
for unsigned i = 0; i < size; i += 4:
current_block[(start_pos + i) >> 2] = ((unsigned *)buffer)[(offset + i) >> 2]
dirty = true
void Mmc::wait_write ():
MSC_IMASK = ~MSC_IMASK_PRG_DONE
while !MSC_STAT & MSC_STAT_PRG_DONE:
Iris::register_interrupt (IRQ_MSC)
Iris::wait_for_interrupt ()
MSC_IREG = MSC_IREG_PRG_DONE
static Mmc mmc
enum types:
DETECT = 1
REQUEST
Iris::Num start ():
map_msc ()
map_gpio ()
map_cpm ()
mmc.reset ()
Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
detect.set_cb (cap.copy ())
cap.invoke (~0)
Iris::free_cap (cap)
// Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
Iris::wait ()
if Iris::recv.data[0].l != ~0:
// If it was "there is no card", the message we sent is still in the queue.
Iris::wait ()
else:
// Otherwise, there is a card.
mmc.detect ()
cap = Iris::my_receiver.create_capability (REQUEST)
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
Iris::free_cap (cap)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case 0:
mmc.interrupt ()
break
case DETECT:
if Iris::recv.data[0].l:
mmc.detect ()
else:
mmc.release ()
break
case REQUEST:
//kdebug ("sd+mmc request ")
//kdebug_num (Iris::recv.data[0].l)
//kdebug ("\n")
switch Iris::recv.data[0].l:
case Iris::Block::GET_SIZE:
Iris::debug ("get size\n")
unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
Iris::recv.reply.invoke (size)
break
case Iris::Block::GET_ALIGN_BITS:
Iris::debug ("get align bits\n")
Iris::recv.reply.invoke (9)
break
case Iris::Block::GET_BLOCK:
//Iris::debug ("get block\n")
Iris::Cap reply = Iris::get_reply ()
Iris::Page page = Iris::get_arg ()
mmc.read_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
reply.invoke ()
Iris::free_cap (page)
Iris::free_cap (reply)
break
case Iris::WBlock::SET_BLOCK:
Iris::debug ("set block\n")
Iris::Cap reply = Iris::get_reply ()
Iris::Page page = Iris::get_arg ()
mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
reply.invoke ()
Iris::free_cap (page)
Iris::free_cap (reply)
mmc.wait_write ()
break
case Iris::Block::SET_CHANGE_CB:
Iris::debug ("set change cb\n")
Iris::Listitem item = Iris::get_arg ()
Iris::Cap reply = Iris::get_reply ()
mmc.add_cb (item)
reply.invoke ()
Iris::free_cap (item)
Iris::free_cap (reply)
break
case Iris::WBlock::TRUNCATE:
Iris::debug ("truncate\n")
// Fall through: don't support resizing.
default:
Iris::panic (0, "unexpected event for sd+mmc")
break
default:
Iris::panic (0, "unexpected request source for sd+mmc")

664
userspace/nanonote/udc.ccp Normal file
View File

@@ -0,0 +1,664 @@
#pypp 0
// vim: set filetype=cpp : //
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/udc.ccp: USB device controller driver.
// 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"
#define ARCH
#include "arch.hh"
class Udc:
typedef unsigned char u8
typedef unsigned short u16
typedef unsigned int u32
typedef u8 string
// The ugly stuff is because pypp doesn't support __attribute__.
/**/struct Setup {
u8 request_type;
u8 request;
u16 value;
u16 index;
u16 length;
} __attribute__ ((packed))
/**/struct Device {
static u8 const Type = 1;
u8 length;
u8 type;
u16 usb_version;
u8 dev_class;
u8 subclass;
u8 protocol;
u8 max_packet_size0;
u16 vendor;
u16 product;
u16 dev_version;
string s_manufacturer;
string s_product;
string s_serial;
u8 num_configurations;
} __attribute__ ((packed))
/**/struct Configuration {
static u8 const Type = 2;
u8 length;
u8 type;
u16 total_length;
u8 num_interfaces;
u8 configuration_value;
u8 configuration;
u8 attributes;
u8 max_power;
} __attribute__ ((packed))
/**/struct Interface {
static u8 const Type = 4;
u8 length;
u8 type;
u8 interface;
u8 alternate;
u8 num_endpoints;
u8 iface_class;
u8 subclass;
u8 protocol;
string name;
} __attribute__ ((packed))
/**/struct Endpoint {
static u8 const Type = 5;
u8 length;
u8 type;
u8 address;
u8 attributes;
u16 max_packet_size;
u8 interval;
} __attribute__ ((packed))
/**/struct Device_Qualifier {
static u8 const Type = 6;
u8 length;
u8 type;
u16 version;
u8 dev_class;
u8 subclass;
u8 protocol;
u8 max_packet_size0;
u8 num_configurations;
u8 reserved;
} __attribute__ ((packed))
/**/struct Langs {
static u8 const Type = 3;
u8 length;
u8 type;
u8 lang;
} __attribute__ ((packed))
template <unsigned size> struct String {
static u8 const Type = 3;
u8 length;
u8 type;
u16 data[size];
} __attribute__ ((packed))
static unsigned const max_packet_size0 = 64
static unsigned const max_packet_size_bulk = 64
enum Requests:
GET_STATUS = 0
CLEAR_FEATURE = 1
SET_FEATURE = 3
SET_ADDRESS = 5
GET_DESCRIPTOR = 6
SET_DESCRIPTOR = 7
GET_CONFIGURATION = 8
SET_CONFIGURATION = 9
GET_INTERFACE = 10
SET_INTERFACE = 11
SYNCH_FRAME = 12
enum Request_types:
STANDARD_TO_DEVICE = 0
VENDOR_TO_DEVICE = 0x40
STANDARD_FROM_DEVICE = 0x80
VENDOR_FROM_DEVICE = 0xc0
enum Endpoint_types:
CONTROL = 0
ISOCHRONOUS = 1
BULK = 2
INTERRUPT = 3
/**/struct my_config {
Configuration config;
Interface interface;
Endpoint endpoint[2];
} __attribute__ ((packed))
static Device device_descriptor
//static Device_Qualifier device_qualifier_descriptor
static my_config config_descriptor; //, other_config_descriptor
static String <1> s_langs
static String <6> s_manufacturer
static String <16> s_product
enum State:
IDLE
TX
RX
State state
char configuration
unsigned size
unsigned rx_request
char const *ptr
unsigned cmd_code, cmd_arg
bool rebooting
bool vendor (Setup *s, unsigned cmd)
bool get_descriptor (unsigned type, unsigned idx, unsigned len)
bool handle_setup (Setup *s, unsigned cmd)
void irq_usb (unsigned cmd)
void irq_in (unsigned cmd)
void irq_out (unsigned cmd)
char log_buffer[1000]
unsigned log_buffer_size
unsigned log_buffer_start
Iris::Cap caller, caller_arg
bool have_caller
unsigned *page
unsigned *p
Iris::Page buffer_page
public:
void init ()
void log (unsigned c)
void interrupt (unsigned cmd)
void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap 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 = {
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
}
}
Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } }
Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
Udc::String <16> Udc::s_product = { sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
//Udc::Device_Qualifier const Udc::device_qualifier_descriptor = { sizeof (Device_Qualifier), Device_Qualifier::Type, 0x200, 0, 0, 0, max_packet_size0, 1, 0 }
//Udc::my_config const Udc::other_config_descriptor = {
// (Configuration){ sizeof (Configuration), 7, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
// (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
// }
// }
void Udc::init ():
// Initialize the globals. My method of compiling doesn't do that properly.
device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
config_descriptor = (my_config){
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
}
}
s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
have_caller = false
log_buffer_size = 0
log_buffer_start = 0
cmd_code = ~0
cmd_arg = 0
// Use the space which is reserved for the framebuffer, because it will not be in use.
// Normally a normal new page should be allocated here, but new isn't implemented at this point.
page = (unsigned *)LCD_FRAMEBUFFER_BASE
p = page
buffer_page = Iris::my_memory.create_page ()
buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING)
Iris::my_memory.map (buffer_page, (unsigned)page)
// Disconnect from the bus and don't try to get high-speed.
UDC_POWER = 0
UDC_TESTMODE = 0
UDC_INDEX = 0
state = IDLE
configuration = 0
size = 0
// exit suspend mode by reading the interrupt register.
cpm_start_udc ()
// reset all pending endpoint interrupts.
unsigned i = UDC_INTRUSB
i = UDC_INTRIN
i = UDC_INTROUT
// enable interrupt on bus reset.
UDC_INTRUSBE = UDC_INTR_RESET
// enable interrupts on endpoint 0.
UDC_INTRINE = 1 << 0
// and on out endpoint 1.
UDC_INTROUTE = 1 << 1
// Wait a while.
for unsigned w = 0; w < 10000; ++w:
Iris::schedule ()
// Connect to the host.
UDC_POWER = UDC_POWER_SOFTCONN
bool Udc::vendor (Setup *s, unsigned cmd):
if !(s->request_type & 0x80):
kdebug ("data to device without size\n")
Iris::panic (0)
return true
if s->request == 10:
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
if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO:
caller.invoke ()
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("(un)lock response\n")
cmd_code = ~0
else:
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
size = s->length < 6 ? s->length : 6
rebooting = true
state = TX
return true
void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg):
if cmd_code != ~0:
kdebug ("new code sent while old one wasn't finished.\n")
Iris::panic (0)
cmd_code = code
cmd_arg = narg
caller = reply
caller_arg = arg
have_caller = true
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
switch type:
case Configuration::Type:
if idx != 0:
return false
ptr = reinterpret_cast <char const *> (&config_descriptor)
size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor))
break
case Device::Type:
if idx != 0:
return false
ptr = reinterpret_cast <char const *> (&device_descriptor)
size = (len < sizeof (device_descriptor) ? len : sizeof (device_descriptor))
break
case Device_Qualifier::Type:
//if idx != 0:
// return false
//ptr = reinterpret_cast <char const *> (&device_qualifier_descriptor)
//size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
//break
return false
// The 6 is an arbitrary number, except that String <6> is instantiated already.
case String <6>::Type:
switch idx:
case 0:
ptr = reinterpret_cast <char const *> (&s_langs)
size = (len < sizeof (s_langs) ? len : sizeof (s_langs))
break
case 1:
ptr = reinterpret_cast <char const *> (&s_manufacturer)
size = (len < sizeof (s_manufacturer) ? len : sizeof (s_manufacturer))
break
case 2:
ptr = reinterpret_cast <char const *> (&s_product)
size = (len < sizeof (s_product) ? len : sizeof (s_product))
break
default:
return false
break
default:
return false
state = TX
return true
bool Udc::handle_setup (Setup *s, unsigned cmd):
switch s->request_type:
case STANDARD_TO_DEVICE:
switch s->request:
case SET_ADDRESS:
UDC_FADDR = s->value
break
case SET_CONFIGURATION:
if s->value >= 2:
return false
configuration = s->value
break
case SET_INTERFACE:
if s->value != 0:
return false
break
default:
return false
UDC_OUTMAXP = 64
UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
break
case STANDARD_FROM_DEVICE:
switch s->request:
case GET_STATUS:
ptr = "\0\0"
size = (s->length < 2 ? s->length : 2)
state = TX
break
case GET_DESCRIPTOR:
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
case GET_CONFIGURATION:
ptr = &configuration
size = (s->length < 1 ? s->length : 1)
state = TX
break
case GET_INTERFACE:
ptr = "\0"
size = (s->length < 1 ? s->length : 1)
state = TX
break
default:
return false
break
case VENDOR_TO_DEVICE:
case VENDOR_FROM_DEVICE:
return vendor (s, cmd)
default:
return false
return true
void Udc::irq_usb (unsigned cmd):
// Reset.
//Iris::debug ("usb reset\n")
state = IDLE
void Udc::irq_in (unsigned cmd):
// Interrupt on endpoint 0.
unsigned csr = UDC_CSR0
if csr & UDC_CSR0_SENTSTALL:
csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL)
state = IDLE
if csr & UDC_CSR0_SETUPEND:
csr |= UDC_CSR0_SVDSETUPEND
state = IDLE
switch state:
case IDLE:
if rebooting:
Iris::reboot ()
if !(csr & UDC_CSR0_OUTPKTRDY):
return
union { unsigned d[2]; Setup s; } packet
packet.d[0] = UDC_FIFO (0)
packet.d[1] = UDC_FIFO (0)
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
// More data will follow; delay handling of packet.
state = RX
UDC_CSR0 = csr | UDC_CSR0_SVDOUTPKTRDY
rx_request = packet.s.request
return
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
if !handle_setup (&packet.s, cmd):
csr |= UDC_CSR0_SENDSTALL
break
if size == 0:
return
// Fall through.
case TX:
unsigned i
for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4:
UDC_FIFO (0) = *(unsigned *)ptr
ptr += 4
for ; size > 0 && i < max_packet_size0; ++i, --size:
UDC_FIFO8 (0) = *ptr++
if i == max_packet_size0:
csr |= UDC_CSR0_INPKTRDY
else:
state = IDLE
csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
break
case RX:
// The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
switch rx_request & 0xff:
case Iris::Directory::GET_SIZE & 0xff:
if !have_caller:
kdebug ("received dir size from server without a caller waiting\n")
Iris::panic (0)
unsigned size_l = UDC_FIFO (0)
unsigned size_h = UDC_FIFO (0)
caller.invoke (Iris::Num (size_l, size_h))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("get_size response\n")
break
case Iris::Directory::GET_NAME & 0xff:
if !have_caller:
kdebug ("received filename from server without a caller waiting\n")
Iris::panic (0)
unsigned n[4]
for unsigned i = 0; i < 4; ++i:
n[i] = UDC_FIFO (0)
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
//kdebug ("get_name response\n")
have_caller = false
break
case Iris::String::GET_SIZE & 0xff:
if !have_caller:
kdebug ("received string size from server without a caller waiting\n")
Iris::panic (0)
unsigned size_l = UDC_FIFO (0)
unsigned size_h = UDC_FIFO (0)
caller.invoke (Iris::Num (size_l, size_h))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("get_filesize response\n")
break
case Iris::String::GET_CHARS & 0xff:
if !have_caller:
kdebug ("received string char data from server without a caller waiting\n")
Iris::panic (0)
unsigned n[4]
for unsigned i = 0; i < 4; ++i:
n[i] = UDC_FIFO (0)
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("get_chars response\n")
break
default:
kdebug ("invalid vendor request: ")
kdebug_num (rx_request)
kdebug ("\n")
Iris::panic (0)
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
state = IDLE
break
UDC_CSR0 = csr
void Udc::irq_out (unsigned cmd):
// Interrupt on OUT endpoint 1.
UDC_INDEX = 1
if !have_caller:
kdebug ("received bulk data from server without a caller waiting\n")
Iris::panic (0)
unsigned size = UDC_OUTCOUNT
unsigned csr = UDC_OUTCSR
//Iris::debug ("handling bulk interrupt for %x with %d bytes.\n", csr, size)
csr &= ~UDC_OUTCSR_OUTPKTRDY
for unsigned i = 0; i < size; i += 4:
*p++ = UDC_FIFO (1)
if p - page == PAGE_SIZE >> 2:
buffer_page.share (caller_arg, Iris::Page::FORGET)
buffer_page.set_flags (Iris::Page::FRAME)
caller.invoke ()
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("bulk response\n")
p = page
UDC_OUTCSR = csr
UDC_INDEX = 0
void Udc::interrupt (unsigned cmd):
while true:
unsigned usb = UDC_INTRUSB
unsigned in = UDC_INTRIN
unsigned out = UDC_INTROUT
if !(usb & 4) && !(in & 1) && !(out & 2):
break
//Iris::debug ("interrupt: %d/%d/%d\n", usb, in, out)
if usb & 4:
irq_usb (cmd)
if in & 1:
irq_in (cmd)
if out & 2:
irq_out (cmd)
void Udc::log (unsigned c):
if log_buffer_size >= sizeof (log_buffer):
return
log_buffer[log_buffer_size++] = c
enum pdata:
LOG = 1
DIRECTORY
FILE
NAME
Iris::Num start ():
map_udc ()
map_gpio ()
map_cpm ()
Udc udc
//Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
//__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1")
Iris::Directory dir = Iris::my_receiver.create_capability (DIRECTORY)
Iris::my_parent.provide_capability <Iris::Directory> (dir.copy ())
Iris::free_cap (dir)
udc.init ()
Iris::register_interrupt (IRQ_UDC)
// Don't call init_done, because this can be used as bootthread and without a parent this call will not be answered.
//Iris::my_parent.init_done ()
unsigned state = 0
while true:
Iris::wait ()
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
//Iris::debug ("udc event, protected: %x\n", Iris::recv.protected_data.l)
switch Iris::recv.protected_data.l:
case 0:
udc.interrupt (state)
Iris::register_interrupt (IRQ_UDC)
break
case LOG:
udc.log (Iris::recv.data[0].l)
break
case DIRECTORY:
//Iris::debug ("dir request %d\n", Iris::recv.data[0].l)
switch Iris::recv.data[0].l:
case Iris::Directory::GET_NAME:
Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (NAME, Iris::recv.data[1].l))
reply.invoke (0, 0, name.copy ())
Iris::free_cap (name)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case Iris::Directory::GET_SIZE:
case Iris::Directory::LOCK_RO:
case Iris::Directory::UNLOCK_RO:
state = Iris::recv.data[0].l
if Iris::recv.data[1].h != 0:
Iris::panic (0, "index out of supported range")
udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
continue
case Iris::Directory::GET_FILE_RO:
if Iris::recv.data[1].h != 0:
kdebug ("index out of supported range\n")
Iris::panic (0)
//kdebug ("sending file\n")
Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (FILE, Iris::recv.data[1].l))
reply.invoke (0, 0, file.copy ())
Iris::free_cap (file)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case Iris::Directory::GET_FILE_INFO:
default:
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
break
case FILE:
//Iris::debug ("file request %d\n", Iris::recv.data[0].l)
switch Iris::recv.data[0].l:
case Iris::Block::GET_BLOCK:
if Iris::recv.data[0].h != PAGE_SIZE << 16:
Iris::panic (0, "unsupported get_block arguments for boot usb device driver")
// Fall through.
case Iris::Block::GET_SIZE:
udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.h, reply, arg)
continue
default:
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
break
case NAME:
//Iris::debug ("name request %d\n", Iris::recv.data[0].l)
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
reply.invoke (16)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case Iris::String::GET_CHARS:
state = Iris::recv.data[0].l
udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.h, reply, arg)
continue
default:
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
default:
kdebug ("other request:")
kdebug_num (Iris::recv.protected_data.l)
kdebug ("\n")
udc.log ('~')
char digit[] = "0123456789abcdef"
for unsigned i = 0; i < 8; ++i:
udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
udc.log ('\n')
break
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)

View File

@@ -0,0 +1,323 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/gpio.ccp: GPIO driver, controlling all devices without special hardware.
// 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"
#define ARCH
#include "arch.hh"
// Interval between polls for keyboard events (when keys are pressed)
#define ALARM_INTERVAL (HZ / 50)
// GPIO pins for the devices (port.pin)
// keyboard
// Cols = 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14, 3.15, 3.29
// Rows = 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7
// For some reason, it only works if the rows are input and the columns are output.
// interrupts: yes, with all columns set to output 0, the first key press can be detected as an interrupt; some other events also trigger interrupts.
// touchpad buttons
// Left: 0.16
// Right: 0.13
// interrupts: yes, for any change.
// Lock leds
// Num lock: 2.22
// Caps lock: 0.27
// Scroll lock: 0.9
// interrupts: no, output only.
// interrupt summary
// Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad
// Port 1: None.
// Port 2: None.
// Port 3: None.
enum event_type:
KEYBOARD_EVENT
TOUCHPAD_EVENT
NUM_EVENTS
static Iris::Cap events[NUM_EVENTS]
static void event (event_type type, unsigned data):
events[type].invoke (data)
static void set_cb (event_type type):
Iris::free_cap (events[type])
events[type] = Iris::get_arg ()
class DevKeyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
unsigned keys[GPIO_KBD_NUM_COLS]
bool scanning
void parse (unsigned col, unsigned data):
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
if (data ^ keys[col]) & (1 << row):
unsigned code = encode[col][row]
if data & (1 << row):
code |= Keyboard::RELEASE
event (KEYBOARD_EVENT, code)
keys[col] = data
// If any keys are pressed, scanning is required.
if data != GPIO_KBD_ROW_MASK:
scanning = true
public:
bool is_scanning ():
return scanning
void scan ():
// Disable interrupts during scan.
GPIO_GPIER (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// All columns are input.
GPIO_GPDIR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
int const cols[GPIO_KBD_NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
unsigned dir = GPIO_GPDIR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
// Set scanning to false before first parse.
scanning = false
// Clear all pins. This is only required once, because it's done at the end of the loop as well.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
// Set pin to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Delay for stabalization.
for unsigned i = 0; i < 100; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Read the result.
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
// Generate events.
parse (col, data)
// Set pin to get rid of capacitance effects.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
// Delay to make the above trick work.
for unsigned i = 0; i < 100; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Pin is set to input at the start of the loop.
// set all to 0.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// set all to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
// Delay for stabalization.
for unsigned i = 0; i < 100; ++i:
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
// Set interrupts.
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
for unsigned i = 0; i < 8; ++i:
if data & (1 << i):
gpio_irq_low (GPIO_KBD_ROW_PORT, i)
else:
gpio_irq_high (GPIO_KBD_ROW_PORT, i)
// Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
DevKeyboard ():
// Set all columns to output without pull-ups when set as input.
GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
// Set all rows to input and enable the pull-ups.
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// Initialize things in the same way as when a new callback is set up.
send_initial ()
void send_initial ():
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
keys[col] = 0xff
scan ()
enum Keys:
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10
SPACE, TAB, ENTER, LBRACE, RBRACE, COMMA, PERIOD, MINUS, EQUAL, SLASH, BACKSLASH, SEMICOLON, EXTRA, BACKQUOTE, QUOTE
UP, DOWN, LEFT, RIGHT
ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
LSHIFT, RSHIFT, CTRL, ALT
CAPS, NUM
NONE = ~Keyboard::RELEASE
unsigned const DevKeyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
{ PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
{ E, F3, D, F4, C, NONE, NONE, N3 },
{ R, T, F, G, V, B, N5, N4 },
{ U, Y, J, H, M, N, N6, N7 },
{ I, RBRACE, K, F6, COMMA, NONE, EQUAL, N8 },
{ O, F7, L, NONE, PERIOD, MENU, F8, N9 },
{ NONE, NONE, NONE, SPACE, NUM, NONE, DELETE, NONE },
{ NONE, BACKSPACE, NONE, NONE, ENTER, NONE, F9, NONE },
{ NONE, NONE, NONE, ALT, NONE, NONE, NONE, SYSRQ },
{ P, LBRACE, SEMICOLON, QUOTE, BACKSLASH, SLASH, MINUS, N0 },
{ NONE, ZZZ, NONE, NONE, NONE, NONE, NONE, F10 },
{ NONE, NONE, NONE, NONE, NONE, NONE, F2, NONE },
{ NONE, NONE, NONE, NONE, NONE, NONE, INSERT, NONE },
{ NONE, NONE, UP, DOWN, LEFT, RIGHT, NONE, NONE },
{ NONE, LSHIFT, RSHIFT, NONE, NONE, NONE, F1, FN }}
class Touchpad:
unsigned old_state
public:
void check_events ():
unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
if state & (1 << GPIO_TP_LEFT):
gpio_irq_low (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0)
else:
gpio_irq_high (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0 | Keyboard::RELEASE)
if state & (1 << GPIO_TP_RIGHT):
gpio_irq_low (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 1)
else:
gpio_irq_high (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 1 | Keyboard::RELEASE)
old_state = state
// Ack interrupts.
//GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
Touchpad ():
// Set pins to input with pull-ups.
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
// See if they are already pressed. Also set up interrupts. This is done like when a new callback is registered.
send_initial ()
void send_initial ():
old_state = 0
check_events ()
class Lockleds:
// Note that num lock is in port 2. The others are in port 0.
public:
Lockleds ():
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
gpio_as_output (GPIO_SCROLL_PORT, GPIO_SCROLL)
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
void set (unsigned state):
if state & 4:
GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
else:
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
if state & 2:
GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
else:
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
if state & 1:
GPIO_GPDR (GPIO_SCROLL_PORT) &= ~(1 << GPIO_SCROLL)
else:
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
class Pwm:
public:
Pwm ():
GPIO_GPDIR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
PWM_PER (0) = 300
void set_backlight (unsigned level):
if level > 300:
level = 300
PWM_DUT (0) = level
if level:
PWM_CTR (0) = 0x80
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
else:
PWM_CTR (0) = 0x00
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
enum codes:
KEYBOARD = 1
TOUCHPAD
LOCKLEDS
PWM
Iris::Num start ():
map_gpio ()
map_pwm0 ()
for unsigned i = 0; i < NUM_EVENTS; ++i:
events[i] = Iris::alloc_cap ()
DevKeyboard kbd
Touchpad tp
Lockleds leds
Pwm pwm
Iris::Cap c = Iris::my_receiver.create_capability (KEYBOARD)
Iris::my_parent.provide_capability <Keyboard> (c.copy (), 0)
Iris::free_cap (c)
c = Iris::my_receiver.create_capability (TOUCHPAD)
Iris::my_parent.provide_capability <Keyboard> (c.copy (), 1)
Iris::free_cap (c)
Iris::my_parent.init_done ()
if kbd.is_scanning ():
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
// Enable interrupts. All are in port 0.
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
Iris::register_interrupt (IRQ_GPIO0)
while true:
Iris::schedule ()
Iris::wait ()
switch Iris::recv.protected_data.l:
case ~0:
// Alarm.
kbd.scan ()
if kbd.is_scanning ():
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
break
case 0:
// Always scan keyboard and touchpad on any interrupt.
kbd.scan ()
tp.check_events ()
// Reregister the interrupt.
Iris::register_interrupt (IRQ_GPIO0)
break
case KEYBOARD:
set_cb (KEYBOARD_EVENT)
Iris::recv.reply.invoke ()
kbd.send_initial ()
event (KEYBOARD_EVENT, ~0)
break
case TOUCHPAD:
set_cb (TOUCHPAD_EVENT)
Iris::recv.reply.invoke ()
tp.send_initial ()
event (TOUCHPAD_EVENT, ~0)
break
case LOCKLEDS:
leds.set (Iris::recv.data[0].l)
Iris::recv.reply.invoke ()
break
case PWM:
pwm.set_backlight (Iris::recv.data[0].l)
Iris::recv.reply.invoke ()
break
default:
kdebug ("invalid gpio operation ")
kdebug_num (Iris::recv.protected_data.l)
kdebug ("\n")
break