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

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 ()