Date:2010-06-06 23:03:25 (13 years 9 months ago)
Author:Bas Wijnen
Commit:89680305512edd1efac9595d39807f4ba4ffd708
Message:working fat system on sd card

Files: Makefile (1 diff)
boot-programs/bootinit.ccp (1 diff)
boot-programs/crt0.ccp (1 diff)
boot-programs/udc.ccp (1 diff)
devices.hhp (4 diffs)
init.config (1 diff)
invoke.ccp (3 diffs)
iris.hhp (3 diffs)
kernel.hhp (1 diff)
mbr+fat.txt (1 diff)
mips/arch.ccp (1 diff)
mips/init.ccp (2 diffs)
mips/interrupts.ccp (2 diffs)
mips/nanonote/Makefile.arch (4 diffs)
mips/nanonote/jz4740.hhp (3 diffs)
mips/nanonote/server/usb-server.ccp (1 diff)
mips/nanonote/threadlist-sd.S (1 diff)
mips/nanonote/threadlist-udc.S (1 diff)
mips/nanonote/threadlist.S (1 diff)
screen.png (0 diffs)
source/bootinit.ccp (1 diff)
source/crt0.ccp (1 diff)
source/elfrun.ccp (1 diff)
source/fat.ccp (1 diff)
source/init.ccp (5 diffs)
source/partition.ccp (1 diff)
source/sd+mmc.ccp (5 diffs)
source/test.ccp (1 diff)
source/udc.ccp (1 diff)

Change Details

Makefile
2323LD = $(CROSS)ld
2424OBJCOPY = $(CROSS)objcopy
2525
26headers = kernel.hh iris.hh devices.hh ui.hh $(arch_headers)
26headers = kernel.hh iris.hh devices.hh ui.hh keys.hh $(arch_headers)
2727iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
2828BUILT_SOURCES = $(iris_sources) $(boot_sources)
2929
boot-programs/bootinit.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/bootinit.ccp: Bootstrapping code.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "devices.hh"
20#include "iris.hh"
21#include <elf.h>
22
23#define ELFRUN_NAME "elfrun.elf"
24#define INIT_NAME "init.elf"
25#define NUM_SLOTS 8
26#define NUM_CAPS 32
27
28static unsigned _free
29extern unsigned _end
30
31void init_alloc ():
32    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
33
34char *alloc_space (unsigned pages):
35    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
36    _free = ret + (pages << PAGE_BITS)
37    return (char *)ret
38
39void *operator new[] (unsigned size):
40    //kdebug ("new ")
41    void *ret = (void *)_free
42    size = (size + 3) & ~3
43    unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
44    if rest < size:
45        unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
46        for unsigned p = 0; p < pages; ++p:
47            Iris::Page page = Iris::my_memory.create_page ()
48            page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
49            Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
50            Iris::free_cap (page)
51    _free += size
52    //kdebug_num ((unsigned)ret)
53    //kdebug ("+")
54    //kdebug_num (size)
55    //kdebug ("\n")
56    return ret
57
58void *operator new (unsigned size):
59    return new char[size]
60
61static unsigned *bss_mapping
62static Iris::Page bss_page
63
64// Get the initial block device and filesystem.
65static Iris::Directory receive_devices ():
66    Iris::String data
67    Iris::Filesystem fs
68    bool have_data = false, have_fs = false
69    for unsigned i = 0; i < 2; ++i:
70        Iris::wait ()
71        if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY:
72            Iris::panic (Iris::recv.data[0].l, "Invalid bootstrap request.")
73        switch Iris::recv.data[1].l:
74            case Iris::String::ID:
75                if have_data:
76                    Iris::panic (0, "duplicate device.")
77                data = Iris::get_arg ()
78                Iris::recv.reply.invoke ()
79                have_data = true
80                break
81            case Iris::Filesystem::ID:
82                if have_fs:
83                    Iris::panic (0, "duplicate filesystem.")
84                fs = Iris::get_arg ()
85                Iris::recv.reply.invoke ()
86                have_fs = true
87                break
88            default:
89                Iris::panic (Iris::recv.data[1].l, "unexpected device")
90    // Initialize the root file system.
91    Iris::Directory root = fs.use_device_ro (data.copy ())
92    Iris::free_cap (data)
93    Iris::free_cap (fs)
94    return root
95
96static bool stringcmp (char const *s1, char const *s2, unsigned size):
97    for unsigned t = 0; t < size; ++t:
98        if s1[t] != s2[t]:
99            return false
100    return true
101
102static Iris::String find (Iris::Directory root, char const *name):
103    unsigned size = 0
104    while name[size]:
105        ++size
106    Iris::Num num_files = root.get_size ()
107    for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
108        Iris::String n = root.get_name (i)
109        char current_name[16]
110        n.get_chars (0, current_name)
111        Iris::free_cap (n)
112        if !stringcmp (current_name, name, size):
113            continue
114        // Found elfrun.
115        Iris::String ret = root.get_file_ro (i)
116        return ret
117    Iris::panic (0, "bootfile not found")
118
119static void run (Iris::String data, Iris::Memory parent_memory, Iris::Cap parent):
120    // Get the size.
121    Iris::Num size = data.get_size ()
122    if size.value () == 0:
123        Iris::panic (0, "elfrun is empty")
124    // Allocate a caps with all the pages.
125    unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
126    Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
127    unsigned slot = pages_caps.use ()
128    // Map them into the address space as well.
129    char *mapping = alloc_space (pages)
130    // Create a memory for the program.
131    Iris::Memory mem = parent_memory.create_memory ()
132    // Load the file into memory and map it.
133    for unsigned p = 0; p < pages; ++p:
134        //kdebug_num (p)
135        //kdebug ("/")
136        //kdebug_num (pages)
137        //kdebug ("\n")
138        Iris::set_recv_arg (Iris::Cap (slot, p))
139        Iris::my_memory.create_page ()
140        Iris::Page (slot, p).set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
141        data.get_page (p << PAGE_BITS, Iris::Cap (slot, p))
142        Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
143    Iris::Thread thread = mem.create_thread (NUM_SLOTS)
144    Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
145    for unsigned j = 0; j < SELFMAG; ++j:
146        if header->e_ident[j] != ELFMAG[j]:
147            Iris::panic (header->e_ident[j], "invalid ELF magic")
148            return
149    if header->e_ident[EI_CLASS] != ELFCLASS32:
150        kdebug ("invalid ELF class:")
151        kdebug_num (header->e_ident[EI_CLASS])
152        kdebug (" != ")
153        kdebug_num (ELFCLASS32)
154        kdebug ("\n")
155        Iris::panic (0)
156        return
157    if header->e_ident[EI_DATA] != ELFDATA2LSB:
158        Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
159    if header->e_ident[EI_VERSION] != EV_CURRENT:
160        Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
161    if header->e_type != ET_EXEC:
162        Iris::panic (header->e_type, "invalid ELF type")
163    if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
164        Iris::panic (header->e_machine, "invalid ELF machine")
165    thread.set_pc (header->e_entry)
166    thread.set_sp (0x80000000)
167    for unsigned section = 0; section < header->e_shnum; ++section:
168        Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
169        if ~shdr->sh_flags & SHF_ALLOC:
170            continue
171        bool readonly = !(shdr->sh_flags & SHF_WRITE)
172        //bool executable = shdr->sh_flags & SHF_EXEC_INSTR
173        if shdr->sh_type != SHT_NOBITS:
174            unsigned file_offset = shdr->sh_offset >> PAGE_BITS
175            if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
176                Iris::panic (shdr->sh_size, "thread too large")
177                return
178            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
179                unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
180                unsigned idx = file_offset + section_offset
181                Iris::Page page = mem.mapping ((void *)p)
182                if Iris::recv.data[0].l == Iris::NO_ERROR:
183                    // The address already has a mapping; assume that it is correct.
184                    Iris::free_cap (page)
185                    continue
186                Iris::free_cap (page)
187                page = mem.create_page ()
188                unsigned f
189                if readonly:
190                    f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
191                else:
192                    f = Iris::Page::PAYING
193                page.set_flags (f, f)
194                Iris::Page (slot, idx).share (page, 0)
195                //kdebug ("mapping at ")
196                //kdebug_num (p)
197                //if readonly:
198                // kdebug (" (readonly)")
199                //kdebug ("\n")
200                if !mem.map (page, p):
201                    Iris::panic (0, "unable to map page")
202                    return
203                Iris::free_cap (page)
204        else:
205            if readonly:
206                Iris::panic (0, "unwritable bss section")
207                return
208            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
209                Iris::Page page = mem.mapping ((void *)p)
210                if Iris::recv.data[0].l == Iris::NO_ERROR:
211                    // No error means there is a mapping.
212                    page.share (bss_page, 0)
213                    Iris::free_cap (page)
214                    for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
215                        if a >= shdr->sh_addr + shdr->sh_size:
216                            break
217                        if a < shdr->sh_addr:
218                            continue
219                        bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
220                else:
221                    Iris::free_cap (page)
222                    page = mem.create_page ()
223                    if Iris::recv.data[0].l != Iris::NO_ERROR:
224                        Iris::panic (Iris::recv.data[0].l, "out of memory")
225                    if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
226                        Iris::panic (0, "out of memory")
227                    if !mem.map (page, p):
228                        Iris::panic (0, "unable to map bss page")
229                    Iris::free_cap (page)
230    for unsigned p = 0; p < pages; ++p:
231        Iris::my_memory.destroy (Iris::Page (slot, p))
232    Iris::my_memory.destroy (pages_caps)
233    Iris::free_slot (slot)
234    Iris::Page stackpage = mem.create_page ()
235    stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
236    if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
237        Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
238    Iris::free_cap (stackpage)
239    Iris::Caps caps = mem.create_caps (NUM_CAPS)
240    thread.use (caps, 0)
241    thread.set_info (Iris::Thread::A0, NUM_SLOTS)
242    thread.set_info (Iris::Thread::A1, NUM_CAPS)
243    Iris::Receiver receiver = mem.create_receiver ()
244    receiver.set_owner (thread.copy ())
245    Iris::Cap call = receiver.create_call_capability ()
246    caps.set (__caps_num, caps.copy ())
247    caps.set (__receiver_num, receiver.copy ())
248    caps.set (__thread_num, thread.copy ())
249    caps.set (__memory_num, mem.copy ())
250    caps.set (__call_num, call.copy ())
251    caps.set (__parent_num, parent)
252    thread.run ()
253    Iris::free_cap (receiver)
254    Iris::free_cap (thread)
255    Iris::free_cap (call)
256    Iris::free_cap (caps)
257
258Iris::Num start ():
259    // Wait for the debugging device to be active, in case there is one.
260    Iris::schedule ()
261    kdebug ("Starting bootinit\n")
262    init_alloc ()
263    bss_mapping = (unsigned *)alloc_space (1)
264    bss_page = Iris::my_memory.create_page ()
265    Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
266
267    Iris::Memory top_memory = Iris::get_top_memory ()
268    Iris::Directory root = receive_devices ()
269    root.lock_ro ()
270    Iris::String run_string = find (root, ELFRUN_NAME)
271    Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
272    run (run_string, top_memory, parent_cap)
273    Iris::wait ()
274    if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
275        Iris::panic (0, "elfrun doesn't provide correct capability")
276    Iris::Cap reply = Iris::get_reply ()
277    Iris::Elfrun elfrun = Iris::get_arg ()
278    Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
279    Iris::free_cap (parent_cap)
280    reply.invoke ()
281    Iris::free_cap (reply)
282
283    parent_cap = Iris::my_receiver.create_capability (0)
284    Iris::String init_string = find (root, INIT_NAME)
285    Iris::Caps init_caps = elfrun.run_string (top_memory.copy (), init_string.copy (), parent_cap.copy (), 8, 63)
286
287    Iris::Thread init = init_caps.get (__thread_num)
288    init.make_priv ()
289    init.run ()
290    Iris::free_cap (init)
291    Iris::free_cap (init_caps)
292
293    bool have_root = false
294    bool have_elfrun = false
295    while true:
296        Iris::wait ()
297        switch Iris::recv.data[0].l:
298            case Iris::Parent::GET_CAPABILITY:
299                switch Iris::recv.data[1].l:
300                    case Iris::Directory::ID:
301                        if have_root:
302                            Iris::panic (0, "Init requests root directory twice")
303                        Iris::recv.reply.invoke (0, 0, root.copy ())
304                        have_root = true
305                        break
306                    case Iris::Elfrun::ID:
307                        if have_elfrun:
308                            Iris::panic (0, "Init requests elfrun twice")
309                        Iris::recv.reply.invoke (0, 0, elfrun.copy ())
310                        have_elfrun = true
311                        break
312                    default:
313                        Iris::panic (0, "Invalid device requested by init")
314                break
315            case Iris::Parent::INIT_DONE:
316                if Iris::recv.data[1].value () != 0:
317                    Iris::recv.reply.invoke ()
318                    break
319                // Special response: kill boot threads.
320                Iris::Cap reply = Iris::get_reply ()
321                root.unlock_ro ()
322                reply.invoke ()
323                Iris::free_cap (reply)
324                top_memory.destroy (Iris::my_memory)
325                Iris::panic (0, "bootinit should be destroyed")
326            default:
327                Iris::panic (Iris::recv.data[0].l, "invalid operation from init")
boot-programs/crt0.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/init.S: Startup code for initial Threads.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "iris.hh"
20#include "devices.hh"
21
22// For some unknown reason, gcc needs this to be defined.
23unsigned __gxx_personality_v0
24
25struct list:
26    list *prev, *next
27
28static unsigned __slots, __caps
29static list *__slot_admin, *__cap_admin
30static list *__first_free_slot, *__first_free_cap
31
32namespace Iris:
33    Caps my_caps
34    Receiver my_receiver
35    Thread my_thread
36    Memory my_memory
37    Cap my_call
38    Parent my_parent
39    __recv_data_t recv
40
41    void print_caps ():
42        // Assume __caps to be 32.
43        bool used[32]
44        for unsigned i = 0; i < 32; ++i:
45            used[i] = true
46        unsigned num = 0
47        for list *i = __first_free_cap; i; i = i->next:
48            used[i - __cap_admin] = false
49            ++num
50        kdebug_num (num, 2)
51        kdebug (":")
52        for unsigned i = 0; i < 32; ++i:
53            kdebug_char (used[i] ? '#' : '.')
54        kdebug_char ('\n')
55
56    void free_slot (unsigned slot):
57        //kdebug ("free slot\n")
58        __slot_admin[slot].prev = NULL
59        __slot_admin[slot].next = __first_free_slot
60        if __slot_admin[slot].next:
61            __slot_admin[slot].next->prev = &__slot_admin[slot]
62        __first_free_slot = &__slot_admin[slot]
63
64    void free_cap (Cap cap):
65        //kdebug ("free cap\n")
66        if cap.slot () != 0:
67            kdebug ("trying to free capability from non-0 slot\n")
68            return
69        list *l = &__cap_admin[cap.idx ()]
70        l->prev = NULL
71        l->next = __first_free_cap
72        if l->next:
73            l->next->prev = l
74        __first_free_cap = l
75
76    unsigned alloc_slot ():
77        //kdebug ("alloc slot\n")
78        if !__first_free_slot:
79            // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
80            kdebug ("out of slots!\n")
81            Iris::panic (0)
82            return ~0
83        list *ret = __first_free_slot
84        __first_free_slot = ret->next
85        if ret->next:
86            ret->next->prev = NULL
87        return ret - __slot_admin
88
89    Cap alloc_cap ():
90        //kdebug ("alloc cap\n")
91        if !__first_free_cap:
92            // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
93            kdebug ("out of capabilities!\n")
94            Iris::panic (0)
95            return Cap (0, CAP_NONE)
96        list *ret = __first_free_cap
97        __first_free_cap = ret->next
98        if ret->next:
99            ret->next->prev = NULL
100        return Cap (0, ret - __cap_admin)
101
102extern "C":
103    void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
104        __slots = slots
105        __caps = caps
106        __slot_admin = slot_admin
107        __cap_admin = cap_admin
108        __first_free_slot = NULL
109        for unsigned i = 1; i < __slots; ++i:
110            Iris::free_slot (i)
111        __first_free_cap = NULL
112        for unsigned i = 6; i < __caps; ++i:
113            Iris::free_cap (Iris::Cap (0, i))
114        Iris::my_caps = Iris::Cap (0, __caps_num)
115        Iris::my_receiver = Iris::Cap (0, __receiver_num)
116        Iris::my_thread = Iris::Cap (0, __thread_num)
117        Iris::my_memory = Iris::Cap (0, __memory_num)
118        Iris::my_call = Iris::Cap (0, __call_num)
119        Iris::my_parent = Iris::Cap (0, __parent_num)
120        Iris::recv.reply = Iris::alloc_cap ()
121        Iris::recv.arg = Iris::alloc_cap ()
122        Iris::Num ret = start ()
123        Iris::my_parent.exit (ret)
124        Iris::my_memory.destroy (Iris::my_thread)
125        // The program no longer exists. If it somehow does, generate an address fault.
126        while true:
127            *(volatile unsigned *)~0
128
129__asm__ volatile ("\t.globl __start\n"
130    "\t.set noreorder\n"
131    "__start:\n"
132    "\tbal 1f\n"
133    "__hack_label:\n"
134    "\tnop\n"
135    "\t.word _gp\n"
136    "1:\n"
137    "\tlw $gp, 0($ra)\n"
138    "\tsll $v0, $a0, 3\n"
139    "\tsll $v1, $a1, 3\n"
140    "\tsubu $sp, $sp, $v0\n"
141    "\tmove $a2, $sp\n"
142    "\tsubu $sp, $sp, $v1\n"
143    "\tmove $a3, $sp\n"
144    "\tla $t9, run__main\n"
145    "\tjr $t9\n"
146    "\tnop\n"
147    "\t.set reorder")
boot-programs/udc.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/udc.ccp: USB device controller driver.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "iris.hh"
20#include "devices.hh"
21#define ARCH
22#include "arch.hh"
23
24class Udc:
25    typedef unsigned char u8
26    typedef unsigned short u16
27    typedef unsigned int u32
28    typedef u8 string
29    // The ugly stuff is because pypp doesn't support __attribute__.
30    /**/struct Setup {
31        u8 request_type;
32        u8 request;
33        u16 value;
34        u16 index;
35        u16 length;
36     } __attribute__ ((packed))
37    /**/struct Device {
38        static u8 const Type = 1;
39        u8 length;
40        u8 type;
41        u16 usb_version;
42        u8 dev_class;
43        u8 subclass;
44        u8 protocol;
45        u8 max_packet_size0;
46        u16 vendor;
47        u16 product;
48        u16 dev_version;
49        string s_manufacturer;
50        string s_product;
51        string s_serial;
52        u8 num_configurations;
53     } __attribute__ ((packed))
54    /**/struct Configuration {
55        static u8 const Type = 2;
56        u8 length;
57        u8 type;
58        u16 total_length;
59        u8 num_interfaces;
60        u8 configuration_value;
61        u8 configuration;
62        u8 attributes;
63        u8 max_power;
64     } __attribute__ ((packed))
65    /**/struct Interface {
66        static u8 const Type = 4;
67        u8 length;
68        u8 type;
69        u8 interface;
70        u8 alternate;
71        u8 num_endpoints;
72        u8 iface_class;
73        u8 subclass;
74        u8 protocol;
75        string name;
76     } __attribute__ ((packed))
77    /**/struct Endpoint {
78        static u8 const Type = 5;
79        u8 length;
80        u8 type;
81        u8 address;
82        u8 attributes;
83        u16 max_packet_size;
84        u8 interval;
85     } __attribute__ ((packed))
86    /**/struct Device_Qualifier {
87        static u8 const Type = 6;
88        u8 length;
89        u8 type;
90        u16 version;
91        u8 dev_class;
92        u8 subclass;
93        u8 protocol;
94        u8 max_packet_size0;
95        u8 num_configurations;
96        u8 reserved;
97     } __attribute__ ((packed))
98    /**/struct Langs {
99        static u8 const Type = 3;
100        u8 length;
101        u8 type;
102        u8 lang;
103     } __attribute__ ((packed))
104    template <unsigned size> struct String {
105        static u8 const Type = 3;
106        u8 length;
107        u8 type;
108        u16 data[size];
109     } __attribute__ ((packed))
110    static unsigned const max_packet_size0 = 64
111    static unsigned const max_packet_size_bulk = 64
112    enum Requests:
113        GET_STATUS = 0
114        CLEAR_FEATURE = 1
115        SET_FEATURE = 3
116        SET_ADDRESS = 5
117        GET_DESCRIPTOR = 6
118        SET_DESCRIPTOR = 7
119        GET_CONFIGURATION = 8
120        SET_CONFIGURATION = 9
121        GET_INTERFACE = 10
122        SET_INTERFACE = 11
123        SYNCH_FRAME = 12
124    enum Request_types:
125        STANDARD_TO_DEVICE = 0
126        VENDOR_TO_DEVICE = 0x40
127        STANDARD_FROM_DEVICE = 0x80
128        VENDOR_FROM_DEVICE = 0xc0
129    enum Endpoint_types:
130        CONTROL = 0
131        ISOCHRONOUS = 1
132        BULK = 2
133        INTERRUPT = 3
134    /**/struct my_config {
135        Configuration config;
136        Interface interface;
137        Endpoint endpoint[2];
138     } __attribute__ ((packed))
139    static Device device_descriptor
140    //static Device_Qualifier device_qualifier_descriptor
141    static my_config config_descriptor; //, other_config_descriptor
142    static String <1> s_langs
143    static String <6> s_manufacturer
144    static String <16> s_product
145    enum State:
146        IDLE
147        TX
148        RX
149    State state
150    char configuration
151    unsigned size
152    unsigned rx_request
153    char const *ptr
154    unsigned cmd_code, cmd_arg
155    bool rebooting
156    bool vendor (Setup *s, unsigned cmd)
157    bool get_descriptor (unsigned type, unsigned idx, unsigned len)
158    bool handle_setup (Setup *s, unsigned cmd)
159    void irq_usb (unsigned cmd)
160    void irq_in (unsigned cmd)
161    void irq_out (unsigned cmd)
162    char log_buffer[1000]
163    unsigned log_buffer_size
164    unsigned log_buffer_start
165    Iris::Cap caller, caller_arg
166    bool have_caller
167    unsigned *page
168    unsigned *p
169    Iris::Page buffer_page
170    public:
171    void init ()
172    void log (unsigned c)
173    void interrupt (unsigned cmd)
174    void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg)
175
176Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
177Udc::my_config Udc::config_descriptor = {
178    (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
179    (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
180        (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
181        (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
182    }
183 }
184Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } }
185Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
186Udc::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' } }
187
188//Udc::Device_Qualifier const Udc::device_qualifier_descriptor = { sizeof (Device_Qualifier), Device_Qualifier::Type, 0x200, 0, 0, 0, max_packet_size0, 1, 0 }
189//Udc::my_config const Udc::other_config_descriptor = {
190// (Configuration){ sizeof (Configuration), 7, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
191// (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
192// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
193// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
194// }
195// }
196
197void Udc::init ():
198    // Initialize the globals. My method of compiling doesn't do that properly.
199    device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
200    config_descriptor = (my_config){
201        (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
202        (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
203            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
204            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
205        }
206     }
207    s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
208    s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
209    s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
210    have_caller = false
211    log_buffer_size = 0
212    log_buffer_start = 0
213    cmd_code = ~0
214    cmd_arg = 0
215
216    // Use the space which is reserved for the framebuffer, because it will not be in use.
217    // Normally a normal new page should be allocated here, but new isn't implemented at this point.
218    page = (unsigned *)LCD_FRAMEBUFFER_BASE
219    p = page
220    buffer_page = Iris::my_memory.create_page ()
221    buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING, Iris::Page::FRAME | Iris::Page::PAYING)
222    Iris::my_memory.map (buffer_page, (unsigned)page)
223
224    // Disconnect from the bus and don't try to get high-speed.
225    UDC_POWER = 0
226    UDC_TESTMODE = 0
227    UDC_INDEX = 0
228    state = IDLE
229    configuration = 0
230    size = 0
231    // exit suspend mode by reading the interrupt register.
232    cpm_start_udc ()
233    // reset all pending endpoint interrupts.
234    unsigned i = UDC_INTRUSB
235    i = UDC_INTRIN
236    i = UDC_INTROUT
237    // enable interrupt on bus reset.
238    UDC_INTRUSBE = UDC_INTR_RESET
239    // enable interrupts on endpoint 0.
240    UDC_INTRINE = 1 << 0
241    // and on out endpoint 1.
242    UDC_INTROUTE = 1 << 1
243    // Wait a while.
244    for unsigned w = 0; w < 10000; ++w:
245        Iris::schedule ()
246    // Connect to the host.
247    UDC_POWER = UDC_POWER_SOFTCONN
248
249bool Udc::vendor (Setup *s, unsigned cmd):
250    if !(s->request_type & 0x80):
251        kdebug ("data to device without size\n")
252        Iris::panic (0)
253        return true
254    if s->request == 10:
255        static unsigned b[2]
256        ptr = (char *)b
257        size = s->length < 8 ? s->length : 8
258        if cmd_code != ~0:
259            b[0] = cmd_code
260            b[1] = cmd_arg
261            if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO:
262                caller.invoke ()
263                Iris::free_cap (caller)
264                Iris::free_cap (caller_arg)
265                have_caller = false
266                //kdebug ("(un)lock response\n")
267            cmd_code = ~0
268        else:
269            if log_buffer_start == log_buffer_size:
270                b[0] = ~1
271                b[1] = 0
272            else:
273                b[0] = ~0
274                b[1] = (log_buffer[log_buffer_start++] & 0xff) * 0x01010101
275            if log_buffer_start == log_buffer_size:
276                log_buffer_start = 0
277                log_buffer_size = 0
278    else:
279        static char const *name = "Reboot"
280        ptr = name
281        size = s->length < 6 ? s->length : 6
282        rebooting = true
283    state = TX
284    return true
285
286void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg):
287    if cmd_code != ~0:
288        kdebug ("new code sent while old one wasn't finished.\n")
289        Iris::panic (0)
290    cmd_code = code
291    cmd_arg = narg
292    caller = reply
293    caller_arg = arg
294    have_caller = true
295
296bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
297    switch type:
298        case Configuration::Type:
299            if idx != 0:
300                return false
301            ptr = reinterpret_cast <char const *> (&config_descriptor)
302            size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor))
303            break
304        case Device::Type:
305            if idx != 0:
306                return false
307            ptr = reinterpret_cast <char const *> (&device_descriptor)
308            size = (len < sizeof (device_descriptor) ? len : sizeof (device_descriptor))
309            break
310        case Device_Qualifier::Type:
311            //if idx != 0:
312            // return false
313            //ptr = reinterpret_cast <char const *> (&device_qualifier_descriptor)
314            //size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
315            //break
316            return false
317        // The 6 is an arbitrary number, except that String <6> is instantiated already.
318        case String <6>::Type:
319            switch idx:
320                case 0:
321                    ptr = reinterpret_cast <char const *> (&s_langs)
322                    size = (len < sizeof (s_langs) ? len : sizeof (s_langs))
323                    break
324                case 1:
325                    ptr = reinterpret_cast <char const *> (&s_manufacturer)
326                    size = (len < sizeof (s_manufacturer) ? len : sizeof (s_manufacturer))
327                    break
328                case 2:
329                    ptr = reinterpret_cast <char const *> (&s_product)
330                    size = (len < sizeof (s_product) ? len : sizeof (s_product))
331                    break
332                default:
333                    return false
334            break
335        default:
336            return false
337    state = TX
338    return true
339
340bool Udc::handle_setup (Setup *s, unsigned cmd):
341    switch s->request_type:
342        case STANDARD_TO_DEVICE:
343            switch s->request:
344                case SET_ADDRESS:
345                    UDC_FADDR = s->value
346                    break
347                case SET_CONFIGURATION:
348                    if s->value >= 2:
349                        return false
350                    configuration = s->value
351                    break
352                case SET_INTERFACE:
353                    if s->value != 0:
354                        return false
355                    break
356                default:
357                    return false
358            UDC_OUTMAXP = 64
359            UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
360            UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
361            break
362        case STANDARD_FROM_DEVICE:
363            switch s->request:
364                case GET_STATUS:
365                    ptr = "\0\0"
366                    size = (s->length < 2 ? s->length : 2)
367                    state = TX
368                    break
369                case GET_DESCRIPTOR:
370                    return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
371                case GET_CONFIGURATION:
372                    ptr = &configuration
373                    size = (s->length < 1 ? s->length : 1)
374                    state = TX
375                    break
376                case GET_INTERFACE:
377                    ptr = "\0"
378                    size = (s->length < 1 ? s->length : 1)
379                    state = TX
380                    break
381                default:
382                    return false
383            break
384        case VENDOR_TO_DEVICE:
385        case VENDOR_FROM_DEVICE:
386            return vendor (s, cmd)
387        default:
388            return false
389    return true
390
391void Udc::irq_usb (unsigned cmd):
392    // Reset.
393    state = IDLE
394
395void Udc::irq_in (unsigned cmd):
396    // Interrupt on endpoint 0.
397    unsigned csr = UDC_CSR0
398    if csr & UDC_CSR0_SENTSTALL:
399        csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL)
400        state = IDLE
401    if csr & UDC_CSR0_SETUPEND:
402        csr |= UDC_CSR0_SVDSETUPEND
403        state = IDLE
404    switch state:
405        case IDLE:
406            if rebooting:
407                Iris::reboot ()
408            if !(csr & UDC_CSR0_OUTPKTRDY):
409                return
410            union { unsigned d[2]; Setup s; } packet
411            packet.d[0] = UDC_FIFO (0)
412            packet.d[1] = UDC_FIFO (0)
413            if !(packet.s.request_type & 0x80) && packet.s.length > 0:
414                // More data will follow; delay handling of packet.
415                state = RX
416                UDC_CSR0 = csr | UDC_CSR0_SVDOUTPKTRDY
417                rx_request = packet.s.request
418                return
419            UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
420            if !handle_setup (&packet.s, cmd):
421                csr |= UDC_CSR0_SENDSTALL
422                break
423            if size == 0:
424                return
425            // Fall through.
426        case TX:
427            unsigned i
428            for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4:
429                UDC_FIFO (0) = *(unsigned *)ptr
430                ptr += 4
431            for ; size > 0 && i < max_packet_size0; ++i, --size:
432                UDC_FIFO8 (0) = *ptr++
433            if i == max_packet_size0:
434                csr |= UDC_CSR0_INPKTRDY
435            else:
436                state = IDLE
437                csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
438            break
439        case RX:
440            // The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
441            switch rx_request & 0xff:
442                case Iris::Directory::GET_SIZE & 0xff:
443                    if !have_caller:
444                        kdebug ("received dir size from server without a caller waiting\n")
445                        Iris::panic (0)
446                    unsigned size_l = UDC_FIFO (0)
447                    unsigned size_h = UDC_FIFO (0)
448                    caller.invoke (Iris::Num (size_l, size_h))
449                    Iris::free_cap (caller)
450                    Iris::free_cap (caller_arg)
451                    have_caller = false
452                    //kdebug ("get_size response\n")
453                    break
454                case Iris::Directory::GET_NAME & 0xff:
455                    if !have_caller:
456                        kdebug ("received filename from server without a caller waiting\n")
457                        Iris::panic (0)
458                    unsigned n[4]
459                    for unsigned i = 0; i < 4; ++i:
460                        n[i] = UDC_FIFO (0)
461                    caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
462                    Iris::free_cap (caller)
463                    Iris::free_cap (caller_arg)
464                    //kdebug ("get_name response\n")
465                    have_caller = false
466                    break
467                case Iris::String::GET_SIZE & 0xff:
468                    if !have_caller:
469                        kdebug ("received string size from server without a caller waiting\n")
470                        Iris::panic (0)
471                    unsigned size_l = UDC_FIFO (0)
472                    unsigned size_h = UDC_FIFO (0)
473                    caller.invoke (Iris::Num (size_l, size_h))
474                    Iris::free_cap (caller)
475                    Iris::free_cap (caller_arg)
476                    have_caller = false
477                    //kdebug ("get_filesize response\n")
478                    break
479                case Iris::String::GET_CHARS & 0xff:
480                    if !have_caller:
481                        kdebug ("received string char data from server without a caller waiting\n")
482                        Iris::panic (0)
483                    unsigned n[4]
484                    for unsigned i = 0; i < 4; ++i:
485                        n[i] = UDC_FIFO (0)
486                    caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
487                    Iris::free_cap (caller)
488                    Iris::free_cap (caller_arg)
489                    have_caller = false
490                    //kdebug ("get_chars response\n")
491                    break
492                default:
493                    kdebug ("invalid vendor request: ")
494                    kdebug_num (rx_request)
495                    kdebug ("\n")
496                    Iris::panic (0)
497            UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
498            state = IDLE
499            break
500    UDC_CSR0 = csr
501
502void Udc::irq_out (unsigned cmd):
503    // Interrupt on OUT endpoint 1.
504    UDC_INDEX = 1
505    if !have_caller:
506        kdebug ("received bulk data from server without a caller waiting\n")
507        Iris::panic (0)
508    unsigned size = UDC_OUTCOUNT
509    unsigned csr = UDC_OUTCSR
510    //kdebug ("handling bulk interrupt for ")
511    //kdebug_num (csr)
512    //kdebug (" with ")
513    //kdebug_num (size)
514    //kdebug (" bytes.\n")
515    csr &= ~UDC_OUTCSR_OUTPKTRDY
516    for unsigned i = 0; i < size; i += 4:
517        *p++ = UDC_FIFO (1)
518    if p - page == PAGE_SIZE >> 2:
519        buffer_page.share (caller_arg, Iris::Page::FORGET)
520        buffer_page.set_flags (Iris::Page::FRAME, Iris::Page::FRAME)
521        caller.invoke ()
522        Iris::free_cap (caller)
523        Iris::free_cap (caller_arg)
524        have_caller = false
525        //kdebug ("bulk response\n")
526        p = page
527    UDC_OUTCSR = csr
528    UDC_INDEX = 0
529
530void Udc::interrupt (unsigned cmd):
531    while true:
532        unsigned usb = UDC_INTRUSB
533        unsigned in = UDC_INTRIN
534        unsigned out = UDC_INTROUT
535        if !(usb & 4) && !(in & 1) && !(out & 2):
536            break
537        //kdebug ("interrupt: ")
538        //kdebug_num (usb, 1)
539        //kdebug ("/")
540        //kdebug_num (in, 1)
541        //kdebug ("/")
542        //kdebug_num (out, 1)
543        //kdebug ("\n")
544        if usb & 4:
545            irq_usb (cmd)
546        if in & 1:
547            irq_in (cmd)
548        if out & 2:
549            irq_out (cmd)
550
551void Udc::log (unsigned c):
552    if log_buffer_size >= sizeof (log_buffer):
553        return
554    log_buffer[log_buffer_size++] = c
555
556enum pdata:
557    LOG = 32
558    FS
559    DATA
560    DIRECTORY
561    FILE
562    NAME
563
564Iris::Num start ():
565    map_udc ()
566    map_gpio ()
567    map_cpm ()
568    Udc udc
569
570    Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
571    __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
572    udc.init ()
573    Iris::register_interrupt (IRQ_UDC)
574    Iris::Filesystem fs = Iris::my_receiver.create_capability (FS)
575    Iris::String data = Iris::my_receiver.create_capability (DATA)
576    Iris::my_parent.provide_capability <Iris::Filesystem> (fs.copy ())
577    Iris::my_parent.provide_capability <Iris::String> (data.copy ())
578    Iris::free_cap (fs)
579    Iris::free_cap (data)
580    unsigned state = 0
581    while true:
582        Iris::wait ()
583        Iris::Cap reply = Iris::get_reply ()
584        Iris::Cap arg = Iris::get_arg ()
585        switch Iris::recv.protected_data.l:
586            case IRQ_UDC:
587                udc.interrupt (state)
588                Iris::register_interrupt (IRQ_UDC)
589                break
590            case LOG:
591                udc.log (Iris::recv.data[0].l)
592                break
593            case DATA:
594                //kdebug ("data request\n")
595                switch Iris::recv.data[0].l:
596                    case Iris::Device::RESET:
597                    case Iris::String::GET_SIZE:
598                    case Iris::String::GET_CHARS:
599                        reply.invoke (0)
600                        Iris::free_cap (reply)
601                        Iris::free_cap (arg)
602                        continue
603                    case Iris::String::GET_PAGE:
604                    default:
605                        reply.invoke (Iris::ERR_INVALID_OPERATION)
606                        Iris::free_cap (reply)
607                        Iris::free_cap (arg)
608                        continue
609                break
610            case FS:
611                //kdebug ("fs request\n")
612                switch Iris::recv.data[0].l:
613                    case Iris::Device::RESET:
614                        reply.invoke (0)
615                        Iris::free_cap (reply)
616                        Iris::free_cap (arg)
617                        continue
618                    case Iris::Filesystem::USE_DEVICE:
619                    case Iris::Filesystem::USE_DEVICE_RO:
620                        Iris::Directory dir = Iris::my_receiver.create_capability (DIRECTORY)
621                        reply.invoke (0, 0, dir.copy ())
622                        Iris::free_cap (dir)
623                        Iris::free_cap (reply)
624                        Iris::free_cap (arg)
625                        continue
626                    default:
627                        reply.invoke (Iris::ERR_INVALID_OPERATION)
628                        Iris::free_cap (reply)
629                        Iris::free_cap (arg)
630                        continue
631                break
632            case DIRECTORY:
633                //kdebug ("dir request\n")
634                switch Iris::recv.data[0].l:
635                    case Iris::Directory::GET_NAME:
636                        Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (NAME, Iris::recv.data[1].l))
637                        reply.invoke (0, 0, name.copy ())
638                        Iris::free_cap (name)
639                        Iris::free_cap (reply)
640                        Iris::free_cap (arg)
641                        continue
642                    case Iris::Directory::GET_SIZE:
643                    case Iris::Directory::LOCK_RO:
644                    case Iris::Directory::UNLOCK_RO:
645                        state = Iris::recv.data[0].l
646                        if Iris::recv.data[1].h != 0:
647                            kdebug ("index out of supported range\n")
648                            Iris::panic (0)
649                        udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
650                        continue
651                    case Iris::Directory::GET_FILE_RO:
652                        if Iris::recv.data[1].h != 0:
653                            kdebug ("index out of supported range\n")
654                            Iris::panic (0)
655                        //kdebug ("sending file\n")
656                        Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (FILE, Iris::recv.data[1].l))
657                        reply.invoke (0, 0, file.copy ())
658                        Iris::free_cap (file)
659                        Iris::free_cap (reply)
660                        Iris::free_cap (arg)
661                        continue
662                    case Iris::Directory::GET_FILE_INFO:
663                    default:
664                        reply.invoke (Iris::ERR_INVALID_OPERATION)
665                        Iris::free_cap (reply)
666                        Iris::free_cap (arg)
667                        continue
668                break
669            case FILE:
670                //kdebug ("file request\n")
671                switch Iris::recv.data[0].l:
672                    case Iris::String::GET_SIZE:
673                    case Iris::String::GET_CHARS:
674                    case Iris::String::GET_PAGE:
675                        udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.h, reply, arg)
676                        continue
677                    default:
678                        reply.invoke (Iris::ERR_INVALID_OPERATION)
679                        Iris::free_cap (reply)
680                        Iris::free_cap (arg)
681                        continue
682                break
683            case NAME:
684                //kdebug ("name request\n")
685                switch Iris::recv.data[0].l:
686                    case Iris::String::GET_SIZE:
687                        reply.invoke (16)
688                        Iris::free_cap (reply)
689                        Iris::free_cap (arg)
690                        continue
691                    case Iris::String::GET_CHARS:
692                        state = Iris::recv.data[0].l
693                        udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.h, reply, arg)
694                        continue
695                    default:
696                        reply.invoke (Iris::ERR_INVALID_OPERATION)
697                        Iris::free_cap (reply)
698                        Iris::free_cap (arg)
699                        continue
700            default:
701                kdebug ("other request:")
702                kdebug_num (Iris::recv.protected_data.l)
703                kdebug ("\n")
704                udc.log ('~')
705                char digit[] = "0123456789abcdef"
706                for unsigned i = 0; i < 8; ++i:
707                    udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
708                udc.log ('\n')
709                break
710        reply.invoke ()
711        Iris::free_cap (reply)
712        Iris::free_cap (arg)
devices.hhp
3939        enum request:
4040            GET_SIZE = 0x2001
4141            GET_CHARS
42            GET_PAGE
42            GET_ALIGN_BITS
43            GET_BLOCK
4344            ID
4445        /// Get the size of the string.
4546        Num get_size ():
4647            return call (CAP_MASTER_DIRECT | GET_SIZE)
47        /// Get exactly 16 characters. The index must be word-aligned.
48        /// Get exactly 16 characters. The index must be aligned to 16 bytes or align_bits, whichever is smaller.
4849        char *get_chars (Num idx, char buffer[16]):
4950            call (CAP_MASTER_DIRECT | GET_CHARS, idx)
5051            unsigned *b = (unsigned *)buffer
...... 
5354            b[2] = recv.data[1].l
5455            b[3] = recv.data[1].h
5556            return buffer
56        /// Helper function for get_page.
57        /// Get the number of bits that page accesses must be aligned to. Cannot be more than PAGE_BITS.
58        unsigned get_align_bits ():
59            return call (CAP_MASTER_DIRECT | GET_ALIGN_BITS).l
60        /// Helper function for get_block.
5761        static Page _create_paying_page ():
5862            Page ret = my_memory.create_page ()
5963            ret.set_flags (Page::PAYING, Page::PAYING)
6064            return ret
61        /// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
62        Cap get_page (Num idx, Page ret = _create_paying_page ()):
63            ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
65        /// Get a block from the string; place it at offset on page. This need not be implemented for strings smaller than PAGE_SIZE. All arguments must be aligned.
66        Cap get_block (Num idx, unsigned size = PAGE_SIZE, unsigned offset = 0, Page ret = _create_paying_page ()):
67            ocall (ret, Iris::Num (CAP_MASTER_DIRECT | GET_BLOCK, size << 16 | offset), idx)
6468            return ret
6569
6670    /// A writable String.
...... 
6973        enum request:
7074            TRUNCATE = String::ID
7175            SET_CHARS
72            SET_PAGE
76            SET_BLOCK
7377            ID
7478        /// Set the size of the string. Strings may have a limit to this setting.
7579        void truncate (Num size):
...... 
7781        /// Set exactly 4 characters. The index must be word-aligned.
7882        void set_chars (Num idx, char buffer[4]):
7983            call (Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
80        /// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
81        void set_page (Num idx, Page page):
82            ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
84        /// Overwrite a block from the string with data at offset on the page. This need not be implemented for strings smaller than PAGE_SIZE. The all arguments must be aligned. The caller may lose the frame in the transaction. Only the specified part of the page is used for overwriting data.
85        void set_block (Num idx, Page page, unsigned size = PAGE_SIZE, unsigned offset = 0):
86            ocall (page, Iris::Num (CAP_MASTER_DIRECT | SET_BLOCK, size << 16 | offset), idx)
8387
8488    // Every process which wants to be switchable through a terminal must implement this interface.
8589    struct Device : public Cap:
init.config
11    # driver <name> = '<filename>' load a file into memory to be run priviledged.
22    # program <name> = '<filename>' load a file into memory to be run normally.
3    driver driver_lcd = "lcd.elf"
4    driver driver_buzzer = "buzzer.elf"
3    #driver driver_lcd = "lcd.elf"
4    #driver driver_buzzer = "buzzer.elf"
55    driver driver_gpio = "gpio.elf"
6    program alarm = "alarm.elf"
7    program gui = "gui.elf"
6    #program alarm = "alarm.elf"
7    #program gui = "gui.elf"
88    #driver nand = "nand.elf"
99    driver sdmmc = "sd+mmc.elf"
10    program partition = "partition.elf"
11    program fat = "fat.elf"
12    program test = "test.elf"
1013
1114    # receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
12    receive driver_lcd / Display = display
13    receive driver_lcd / Setting = display_bright
14    receive driver_buzzer / Buzzer = buzzer
15    #receive driver_lcd / Display = display
16    #receive driver_lcd / Setting = display_bright
17    #receive driver_buzzer / Buzzer = buzzer
1518    receive driver_gpio / Keyboard , 0 = keyboard
1619    receive driver_gpio / Keyboard , 1 = sysreq
1720    receive driver_gpio / Event = sdmmc_gpio
18    receive alarm / UI = ui
21    #receive alarm / UI = ui
1922    receive sdmmc / WString = sdmmc
23    receive partition / WString, 0 = p0
24    receive partition / WString, 1 = p1
25    receive partition / WString, 2 = p2
26    receive partition / WString, 3 = p3
27    receive fat / Directory = root
2028
2129    # sysreq <cap> use a capability as the system request keyboard.
2230    sysreq sysreq
2331
2432    # give <name> / <type> [, <index>] = <cap> give this capability to this program when it requests it.
25    give gui / UI = ui
26    give gui / Display = display
27    give gui / Setting = display_bright
28    give gui / Buzzer = buzzer
29    give gui / Keyboard = keyboard
33    #give gui / UI = ui
34    #give gui / Display = display
35    #give gui / Setting = display_bright
36    #give gui / Buzzer = buzzer
37    #give gui / Keyboard = keyboard
3038    give sdmmc / Event = sdmmc_gpio
39    give partition / WString = sdmmc
40    give fat / WString = p0
41    give test / Directory = root
3142
3243    # include <file> include a file as another config file.
3344
invoke.ccp
233233            return
234234        case Iris::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
235235            receiver->reply_protected_data = c->data[1]
236            // Adjust target protected data, so the reply will reach the caller.
237            if receiver == reply_target:
238                reply_protected = receiver->reply_protected_data
236239            break
237240        case Iris::Receiver::GET_ALARM & REQUEST_MASK:
238241            reply_num (receiver->alarm_count)
...... 
701704                    t->flags |= Iris::Page::FRAME
702705            kPage_arch_update_mapping (t)
703706            break
707        case Iris::Page::GET_FLAGS & REQUEST_MASK:
708            reply_num (page->flags)
709            return
704710        case Iris::Page::SET_FLAGS & REQUEST_MASK:
705711            if cmd & Iris::Page::READONLY:
706712                dpanic (0, "setting page flags denied")
...... 
989995            c->reply.reset ()
990996            reply_target = (kReceiver *)protected_data.l
991997            reply_protected = reply_target->reply_protected_data
992            kReceiver *r = reply_target
993998            kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
994999        return
9951000    if must_wait:
iris.hhp
294294            return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
295295        void set_alarm (unsigned data):
296296            call (CAP_MASTER_DIRECT | SET_ALARM, data)
297        static inline void sleep (unsigned value)
297        inline void sleep (unsigned value)
298298        Cap create_call_capability ():
299299            icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
300300            return get_arg ()
...... 
567567        my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
568568    inline void unregister_interrupt (unsigned num):
569569        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
570    inline void wait_for_interrupt (unsigned num):
571        my_receiver.set_reply_protected_data (num)
572        Cap ().call ()
573        my_receiver.set_reply_protected_data (~0)
570574    inline Cap get_top_memory ():
571575        my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
572576        return get_arg ()
...... 
576580        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
577581
578582    void Receiver::sleep (unsigned value):
579        my_receiver.set_alarm (value)
583        set_alarm (value)
580584        Cap ().call ()
585    inline void sleep (unsigned value):
586        my_receiver.sleep (value)
581587
582588// The start function has this prototype (there is no main function).
583589Iris::Num start ()
kernel.hhp
122122    unsigned flags
123123    kThreadP schedule_prev, schedule_next
124124    unsigned recv_reply, recv_arg
125    // caps is an array of slots pointers to kCapses.
125    // slot[] is an array of slots pointers to kCapses.
126126    unsigned slots
127127    #ifndef NDEBUG
128128    unsigned id
mbr+fat.txt
1mbr structure. Size: 200.
2
3000 1b8 code or fat:
4    00 3 jump instruction
5    03 8 OEM name
6    0b 2 bytes per sector
7    0d 1 sectors per cluster
8    0e 2 reserved sectors (incl. boot sector, from boot sector)
9    10 1 number of fats
10    11 2 non fat32: number of entries in root directory
11    13 2 total number of sectors on disk if < 32MB
12    15 1 media descriptor (bit 2 set means removable)
13    16 2 non fat32: sectors per fat
14    18 2 sectors per track
15    1a 2 heads
16    1c 4 number of sectors before boot sector
17    20 4 number of sectors on disk, if > 32MB
18    24 xx 4 sectors per fat
19    28 xx 2 bit 0-4: active fat, bit 7 set: write to all fats.
20    2a xx 2 file system version number
21    2c xx 4 cluster number for root directory
22    30 xx 2 sector number for FSInfo structure
23    32 xx 2 boot sector backup sector
24    34 xx c reserved
25    40 24 1 drive number
26    41 25 1 current head (dos internal)
27    42 26 1 boot signature (with 0x29, the next 3 fields are valid)
28    43 27 4 volume id
29    47 2b b volume label
30    52 36 8 file system type "FAT16 " / "FAT32 " / ...
31
321b8 004 disk signature
331bc 002 null
341be 010 partition 0
351ce 010 partition 1
361de 010 partition 2
371ee 010 partition 3
381fe 002 mbr signature: 55 aa.
39
40Partition structure. Size: 10.
41
420 1 bootable flag 00=no; 80=yes.
431 3 first sector in partition, chs
444 1 partition type
455 3 last sector in partition, chs
468 4 first sector in partition, lba
47c 4 number of sectors in partition, for lba
48
49CHS address. Size: 3.
50head = chs[0]
51sector = chs[1] & 0x3f
52cylinder = (chs[1] & 0xc0) << 2 | chs[2]
53
54Fat filesystem information sector. Size: 200.
55000 4 signature: 52 52 61 41
56004 1e0 unused
571e4 4 fsinfo signature: 72 72 41 61
581e8 4 number of free clusters
591ec 4 most recently allocated cluster
601f0 c reserved
611fc 2 unknown
621fe 2 boot record signature: 55 aa
63
64Directory entry. Size: 20.
6500 8 name
6608 3 extension
670b 1 attributes (00arshdv)
680c 1 0
690d 1 creation time: (milli?)seconds
700e 2 creation time: hour and minute
7110 2 creation date
7212 2 last accessed date
7314 2 cluster[31:16]
7416 2 time
7518 2 date
761a 2 cluster[15:0]
771c 4 file size
78
79long file name: stored in directory entries immediately before the 8.3 name (last entry is first part of name)
8000 1 ordinal field, bit 6 set means highest.
8101 a 5 unicode characters.
820b 1 attribute: 000rsh0v.
830c 1 0
840d 1 checksum
850e c 6 unicode characters.
861a 2 0
871c 4 2 unicode characters.
88
mips/arch.ccp
279279    arch_interrupt_receiver[num] = r
280280    // And enable or disable the interrupt.
281281    if r:
282        //if num != 0x18:
283            //kdebug ("enabled interrupt ")
284            //kdebug_num (num)
285            //kdebug (", state: ")
286            //kdebug_num (INTC_ISR)
287            //kdebug ("\n")
282288        intc_unmask_irq (num)
283289    else:
290        //kdebug ("disabled interrupt ")
291        //kdebug_num (num)
292        //kdebug ("\n")
284293        intc_mask_irq (num)
mips/init.ccp
5757    idle_page.address_space = NULL
5858    current = &idle
5959    directory = idle_memory.arch.directory
60    kdebug ("idle thread is ")
61    kdebug_num ((unsigned)&idle)
62    kdebug ("\n")
6063
6164static void init_cp0 ():
6265    // Disable watchpoint interrupts.
...... 
116119    first_alarm = NULL
117120    kReceiver *init_receiver = NULL
118121    for unsigned i = 0; i < NUM_THREADS; ++i:
119        kdebug ("Starting thread ")
120        kdebug_num (i, 2)
121        kdebug ("\n")
122122        kMemory *mem = top_memory.alloc_memory ()
123123        assert (mem)
124124        kThread *thread = mem->alloc_thread (NUM_SLOTS)
125        kdebug ("Starting thread ")
126        kdebug_num (i, 2)
127        kdebug (" at ")
128        kdebug_num ((unsigned)thread)
129        kdebug ("\n")
125130        #ifndef NDEBUG
126131        thread->id = i
127132        #endif
mips/interrupts.ccp
111111            // Handle timer interrupts specially: don't disable them.
112112            if i == TIMER_INTERRUPT:
113113                continue
114            //if i != 0x18:
115                //kdebug ("interrupt: ")
116                //kdebug_num (i, 2)
117                //kdebug ("\n")
114118            // Disable the interrupt while handling it.
115119            intc_mask_irq (i)
116120            intc_ack_irq (i)
...... 
236240            current->pc += 4
237241            #endif
238242            #else
243            unsigned opcode = *(unsigned *)current->pc
244            if opcode == 0x0007000d:
245                panic (0, "Division by zero (detected by compiler)")
239246            current->pc += 4
240247            if current->arch.a[0]:
241248                if dbg_cap.valid ():
mips/nanonote/Makefile.arch
1616# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
1818load = 0x80000000
19UDC_BOOT=1
1920
2021ARCH_CXXFLAGS = -DNUM_THREADS=2
2122ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
...... 
2829arch_iris_sources = mips/interrupts.cc mips/arch.cc
2930boot_sources = mips/init.cc mips/nanonote/board.cc
3031arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
31boot_threads = bootinit udc
32programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui nand sd+mmc
32udc_boot_programs = udc
33sd_boot_programs = sd+mmc partition fat
34standard_boot_programs = bootinit
35ifdef UDC_BOOT
36    boot_threads = $(standard_boot_programs) $(udc_boot_programs)
37    threadlist = mips/nanonote/threadlist-udc
38    INIT_FLAGS = -DUDC_BOOT
39else
40    boot_threads = $(standard_boot_programs) $(sd_boot_programs)
41    threadlist = mips/nanonote/threadlist-sd
42    INIT_FLAGS = -DSD_BOOT
43endif
44programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui nand test $(udc_boot_programs) $(sd_boot_programs) $(standard_boot_programs)
3345
3446all: test
3547
...... 
5264
5365mips/nanonote/sdram-setup.elf: mips/nanonote/sdram-setup.ld
5466mips/nanonote/sdram-setup.elf: LDFLAGS = --omagic -T mips/nanonote/sdram-setup.ld
55mips/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
67$(threadlist).o: $(addprefix fs/,$(addsuffix .elf,$(boot_threads)))
5668mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
57mips/init.o: TARGET_FLAGS = -I/usr/include
58boot-programs/bootinit.o: TARGET_FLAGS = -I/usr/include
69mips/init.o: TARGET_FLAGS = -I/usr/include $(INIT_FLAGS)
70source/bootinit.o: TARGET_FLAGS = -I/usr/include
5971source/elfrun.o: TARGET_FLAGS = -I/usr/include
6072source/gpio.ccp: source/nanonote-gpio.ccp
6173    ln -s $(subst source/,,$<) $@
62$(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I.
63$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
74$(addprefix fs/,$(addsuffix .elf,$(boot_threads))): TARGET_FLAGS = -I.
75$(addprefix fs/,$(addsuffix .elf,$(boot_threads))): LDFLAGS = -EL
6476$(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL
65$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
6677source/lcd.o: source/charset.data
6778
6879source/charset.data: source/charset
...... 
7283    $(CC) $(CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@
7384
7485# entry.o must be the first file. threadlist.o must be the first of the init objects (which can be freed after loading).
75iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources))
86iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) $(threadlist).o mips/boot.o $(subst .cc,.o,$(boot_sources))
7687    $(LD) $(LDFLAGS) $^ -o $@
7788
7889server:
mips/nanonote/jz4740.hhp
163163#define IRQ_SSI 16
164164#define IRQ_CIM 17
165165#define IRQ_AIC 18
166#define IRQ_ETH 19
167166#define IRQ_DMAC 20
168167#define IRQ_TCU2 21
169168#define IRQ_TCU1 22
...... 
12271226#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
12281227  #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) // 1-bit data bus
12291228  #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) // 4-bit data bus
1230  #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT)
1231  #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT)
12321229#define MSC_CMDAT_DMA_EN (1 << 8)
12331230#define MSC_CMDAT_INIT (1 << 7)
12341231#define MSC_CMDAT_BUSY (1 << 6)
...... 
12451242  #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) // Format R4
12461243  #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) // Format R5
12471244  #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) // Format R6
1248
1249#define CMDAT_DMA_EN (1 << 8)
1250#define CMDAT_INIT (1 << 7)
1251#define CMDAT_BUSY (1 << 6)
1252#define CMDAT_STREAM (1 << 5)
1253#define CMDAT_WRITE (1 << 4)
1254#define CMDAT_DATA_EN (1 << 3)
1245  #define MSC_CMDAT_RESPONSE_R7 (0x7 << MSC_CMDAT_RESPONSE_BIT) // Format R7
1246
1247#define MSC_CMDAT_DMA_EN (1 << 8)
1248#define MSC_CMDAT_INIT (1 << 7)
1249#define MSC_CMDAT_BUSY (1 << 6)
1250#define MSC_CMDAT_STREAM (1 << 5)
1251#define MSC_CMDAT_WRITE (1 << 4)
1252#define MSC_CMDAT_DATA_EN (1 << 3)
12551253
12561254// MSC Interrupts Mask Register (MSC_IMASK)
12571255
mips/nanonote/server/usb-server.ccp
156156                if !--lock:
157157                    dir.clear ()
158158                continue
159            case Iris::String::GET_PAGE:
159            case Iris::String::GET_BLOCK:
160160                if buffer[1] >= dir.size ():
161161                    std::cerr << "reading invalid file" << std::endl
162162                    usb_release_interface (handle, 0)
mips/nanonote/threadlist-sd.S
1// Iris: micro-kernel for a capability-based operating system.
2// mips/nanonote/threadlist.S: List of initial threads.
3// Copyright 2009 Bas Wijnen <wijnen@debian.org>
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18    .globl init_start
19    .globl thread_start
20    .set noreorder
21
22    .balign 0x1000
23thread0:
24    .incbin "fs/bootinit.elf"
25
26    .balign 0x1000
27thread1:
28    .incbin "fs/sd+mmc.elf"
29
30    .balign 0x1000
31thread2:
32    .incbin "fs/partition.elf"
33
34    .balign 0x1000
35thread3:
36    .incbin "fs/fat.elf"
37
38    .balign 0x1000
39thread4:
40
41// Everything from here may be freed after kernel initialization.
42init_start:
43
44thread_start:
45    .word thread0
46    .word thread1
47    .word thread2
48    .word thread3
49    .word thread4
mips/nanonote/threadlist-udc.S
1// Iris: micro-kernel for a capability-based operating system.
2// mips/nanonote/threadlist.S: List of initial threads.
3// Copyright 2009 Bas Wijnen <wijnen@debian.org>
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18    .globl init_start
19    .globl thread_start
20    .set noreorder
21
22    .balign 0x1000
23thread0:
24    .incbin "bootinit.elf"
25
26    .balign 0x1000
27thread1:
28    .incbin "udc.elf"
29
30    .balign 0x1000
31thread2:
32
33// Everything from here may be freed after kernel initialization.
34init_start:
35
36thread_start:
37    .word thread0
38    .word thread1
39    .word thread2
mips/nanonote/threadlist.S
1// Iris: micro-kernel for a capability-based operating system.
2// mips/nanonote/threadlist.S: List of initial threads.
3// Copyright 2009 Bas Wijnen <wijnen@debian.org>
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18    .globl init_start
19    .globl thread_start
20    .set noreorder
21
22    .balign 0x1000
23thread0:
24    .incbin "bootinit.elf"
25
26    .balign 0x1000
27thread1:
28    .incbin "udc.elf"
29
30    .balign 0x1000
31thread2:
32
33// Everything from here may be freed after kernel initialization.
34init_start:
35
36thread_start:
37    .word thread0
38    .word thread1
39    .word thread2
screen.png
source/bootinit.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/bootinit.ccp: Bootstrapping code.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "devices.hh"
20#include "iris.hh"
21#include <elf.h>
22
23#define ELFRUN_NAME "elfrun.elf"
24#define INIT_NAME "init.elf"
25#define NUM_SLOTS 8
26#define NUM_CAPS 32
27
28static unsigned _free
29extern unsigned _end
30
31void init_alloc ():
32    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
33
34char *alloc_space (unsigned pages):
35    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
36    _free = ret + (pages << PAGE_BITS)
37    return (char *)ret
38
39void *operator new[] (unsigned size):
40    //kdebug ("new ")
41    void *ret = (void *)_free
42    size = (size + 3) & ~3
43    unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
44    if rest < size:
45        unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
46        for unsigned p = 0; p < pages; ++p:
47            Iris::Page page = Iris::my_memory.create_page ()
48            page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
49            Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
50            Iris::free_cap (page)
51    _free += size
52    //kdebug_num ((unsigned)ret)
53    //kdebug ("+")
54    //kdebug_num (size)
55    //kdebug ("\n")
56    return ret
57
58void *operator new (unsigned size):
59    return new char[size]
60
61static unsigned *bss_mapping
62static Iris::Page bss_page
63
64// Get the initial block device and filesystem.
65static Iris::Directory receive_devices ():
66    Iris::String data
67    Iris::Filesystem fs
68    bool have_data = false, have_fs = false
69    for unsigned i = 0; i < 2; ++i:
70        Iris::wait ()
71        if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY:
72            Iris::panic (Iris::recv.data[0].l, "Invalid bootstrap request.")
73        switch Iris::recv.data[1].l:
74            case Iris::String::ID:
75                if have_data:
76                    Iris::panic (0, "duplicate device.")
77                data = Iris::get_arg ()
78                Iris::recv.reply.invoke ()
79                have_data = true
80                break
81            case Iris::Filesystem::ID:
82                if have_fs:
83                    Iris::panic (0, "duplicate filesystem.")
84                fs = Iris::get_arg ()
85                Iris::recv.reply.invoke ()
86                have_fs = true
87                break
88            default:
89                Iris::panic (Iris::recv.data[1].l, "unexpected device")
90    // Initialize the root file system.
91    Iris::Directory root = fs.use_device_ro (data.copy ())
92    Iris::free_cap (data)
93    Iris::free_cap (fs)
94    return root
95
96static bool stringcmp (char const *s1, char const *s2, unsigned size):
97    for unsigned t = 0; t < size; ++t:
98        if s1[t] != s2[t]:
99            return false
100    return true
101
102static Iris::String find (Iris::Directory root, char const *name):
103    unsigned size = 0
104    while name[size]:
105        ++size
106    Iris::Num num_files = root.get_size ()
107    for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
108        Iris::String n = root.get_name (i)
109        char current_name[16]
110        n.get_chars (0, current_name)
111        Iris::free_cap (n)
112        if !stringcmp (current_name, name, size):
113            continue
114        // Found elfrun.
115        Iris::String ret = root.get_file_ro (i)
116        return ret
117    Iris::panic (0, "bootfile not found")
118
119static void run (Iris::String data, Iris::Memory parent_memory, Iris::Cap parent):
120    // Get the size.
121    Iris::Num size = data.get_size ()
122    if size.value () == 0:
123        Iris::panic (0, "elfrun is empty")
124    // Allocate a caps with all the pages.
125    unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
126    Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
127    unsigned slot = pages_caps.use ()
128    // Map them into the address space as well.
129    char *mapping = alloc_space (pages)
130    // Create a memory for the program.
131    Iris::Memory mem = parent_memory.create_memory ()
132    // Load the file into memory and map it.
133    for unsigned p = 0; p < pages; ++p:
134        //kdebug_num (p)
135        //kdebug ("/")
136        //kdebug_num (pages)
137        //kdebug ("\n")
138        Iris::set_recv_arg (Iris::Cap (slot, p))
139        Iris::my_memory.create_page ()
140        Iris::Page (slot, p).set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
141        data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, Iris::Cap (slot, p))
142        Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
143    Iris::Thread thread = mem.create_thread (NUM_SLOTS)
144    Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
145    for unsigned j = 0; j < SELFMAG; ++j:
146        if header->e_ident[j] != ELFMAG[j]:
147            Iris::panic (header->e_ident[j], "invalid ELF magic")
148            return
149    if header->e_ident[EI_CLASS] != ELFCLASS32:
150        kdebug ("invalid ELF class:")
151        kdebug_num (header->e_ident[EI_CLASS])
152        kdebug (" != ")
153        kdebug_num (ELFCLASS32)
154        kdebug ("\n")
155        Iris::panic (0)
156        return
157    if header->e_ident[EI_DATA] != ELFDATA2LSB:
158        Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
159    if header->e_ident[EI_VERSION] != EV_CURRENT:
160        Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
161    if header->e_type != ET_EXEC:
162        Iris::panic (header->e_type, "invalid ELF type")
163    if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
164        Iris::panic (header->e_machine, "invalid ELF machine")
165    thread.set_pc (header->e_entry)
166    thread.set_sp (0x80000000)
167    for unsigned section = 0; section < header->e_shnum; ++section:
168        Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
169        if ~shdr->sh_flags & SHF_ALLOC:
170            continue
171        bool readonly = !(shdr->sh_flags & SHF_WRITE)
172        //bool executable = shdr->sh_flags & SHF_EXEC_INSTR
173        if shdr->sh_type != SHT_NOBITS:
174            unsigned file_offset = shdr->sh_offset >> PAGE_BITS
175            if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
176                Iris::panic (shdr->sh_size, "thread too large")
177                return
178            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
179                unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
180                unsigned idx = file_offset + section_offset
181                Iris::Page page = mem.mapping ((void *)p)
182                if Iris::recv.data[0].l == Iris::NO_ERROR:
183                    // The address already has a mapping; assume that it is correct.
184                    Iris::free_cap (page)
185                    continue
186                Iris::free_cap (page)
187                page = mem.create_page ()
188                unsigned f
189                if readonly:
190                    f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
191                else:
192                    f = Iris::Page::PAYING
193                page.set_flags (f, f)
194                Iris::Page (slot, idx).share (page, 0)
195                //kdebug ("mapping at ")
196                //kdebug_num (p)
197                //if readonly:
198                // kdebug (" (readonly)")
199                //kdebug ("\n")
200                if !mem.map (page, p):
201                    Iris::panic (0, "unable to map page")
202                    return
203                Iris::free_cap (page)
204        else:
205            if readonly:
206                Iris::panic (0, "unwritable bss section")
207                return
208            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
209                Iris::Page page = mem.mapping ((void *)p)
210                if Iris::recv.data[0].l == Iris::NO_ERROR:
211                    // No error means there is a mapping.
212                    page.share (bss_page, 0)
213                    Iris::free_cap (page)
214                    for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
215                        if a >= shdr->sh_addr + shdr->sh_size:
216                            break
217                        if a < shdr->sh_addr:
218                            continue
219                        bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
220                else:
221                    Iris::free_cap (page)
222                    page = mem.create_page ()
223                    if Iris::recv.data[0].l != Iris::NO_ERROR:
224                        Iris::panic (Iris::recv.data[0].l, "out of memory")
225                    if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
226                        Iris::panic (0, "out of memory")
227                    if !mem.map (page, p):
228                        Iris::panic (0, "unable to map bss page")
229                    Iris::free_cap (page)
230    for unsigned p = 0; p < pages; ++p:
231        Iris::my_memory.destroy (Iris::Page (slot, p))
232    Iris::my_memory.destroy (pages_caps)
233    Iris::free_slot (slot)
234    Iris::Page stackpage = mem.create_page ()
235    stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
236    if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
237        Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
238    Iris::free_cap (stackpage)
239    Iris::Caps caps = mem.create_caps (NUM_CAPS)
240    thread.use (caps, 0)
241    thread.set_info (Iris::Thread::A0, NUM_SLOTS)
242    thread.set_info (Iris::Thread::A1, NUM_CAPS)
243    Iris::Receiver receiver = mem.create_receiver ()
244    receiver.set_owner (thread.copy ())
245    Iris::Cap call = receiver.create_call_capability ()
246    caps.set (__caps_num, caps.copy ())
247    caps.set (__receiver_num, receiver.copy ())
248    caps.set (__thread_num, thread.copy ())
249    caps.set (__memory_num, mem.copy ())
250    caps.set (__call_num, call.copy ())
251    caps.set (__parent_num, parent)
252    thread.run ()
253    Iris::free_cap (receiver)
254    Iris::free_cap (thread)
255    Iris::free_cap (call)
256    Iris::free_cap (caps)
257
258Iris::Num start ():
259    // Wait for the debugging device to be active, in case there is one.
260    Iris::schedule ()
261    kdebug ("Starting bootinit\n")
262    init_alloc ()
263    bss_mapping = (unsigned *)alloc_space (1)
264    bss_page = Iris::my_memory.create_page ()
265    Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
266
267    Iris::Memory top_memory = Iris::get_top_memory ()
268    Iris::Directory root = receive_devices ()
269    root.lock_ro ()
270    Iris::String run_string = find (root, ELFRUN_NAME)
271    Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
272    run (run_string, top_memory, parent_cap)
273    Iris::wait ()
274    if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
275        Iris::panic (0, "elfrun doesn't provide correct capability")
276    Iris::Cap reply = Iris::get_reply ()
277    Iris::Elfrun elfrun = Iris::get_arg ()
278    Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
279    Iris::free_cap (parent_cap)
280    reply.invoke ()
281    Iris::free_cap (reply)
282
283    parent_cap = Iris::my_receiver.create_capability (0)
284    Iris::String init_string = find (root, INIT_NAME)
285    Iris::Caps init_caps = elfrun.run_string (top_memory.copy (), init_string.copy (), parent_cap.copy (), 8, 63)
286
287    Iris::Thread init = init_caps.get (__thread_num)
288    init.make_priv ()
289    init.run ()
290    Iris::free_cap (init)
291    Iris::free_cap (init_caps)
292
293    bool have_root = false
294    bool have_elfrun = false
295    while true:
296        Iris::wait ()
297        switch Iris::recv.data[0].l:
298            case Iris::Parent::GET_CAPABILITY:
299                switch Iris::recv.data[1].l:
300                    case Iris::Directory::ID:
301                        if have_root:
302                            Iris::panic (0, "Init requests root directory twice")
303                        Iris::recv.reply.invoke (0, 0, root.copy ())
304                        have_root = true
305                        break
306                    case Iris::Elfrun::ID:
307                        if have_elfrun:
308                            Iris::panic (0, "Init requests elfrun twice")
309                        Iris::recv.reply.invoke (0, 0, elfrun.copy ())
310                        have_elfrun = true
311                        break
312                    default:
313                        Iris::panic (0, "Invalid device requested by init")
314                break
315            case Iris::Parent::INIT_DONE:
316                if Iris::recv.data[1].value () != 0:
317                    Iris::recv.reply.invoke ()
318                    break
319                // Special response: kill boot threads.
320                Iris::Cap reply = Iris::get_reply ()
321                root.unlock_ro ()
322                reply.invoke ()
323                Iris::free_cap (reply)
324                top_memory.destroy (Iris::my_memory)
325                Iris::panic (0, "bootinit should be destroyed")
326            default:
327                Iris::panic (Iris::recv.data[0].l, "invalid operation from init")
source/crt0.ccp
139139        Iris::Num ret = start ()
140140        Iris::my_parent.exit (ret)
141141        Iris::my_memory.destroy (Iris::my_thread)
142        // The program no longer exists. If it somehow does, generate an address fault.
142        // The program no longer exists. If it somehow does, die again.
143143        while true:
144            Iris::panic (0, "this program should no longer exist.")
144145            *(volatile unsigned *)~0
145146
146147__asm__ volatile ("\t.text\n"
source/elfrun.ccp
8383        //kdebug_num (pages)
8484        //kdebug ("\n")
8585        Iris::set_recv_arg (Iris::Cap (slot, p))
86        data.get_page (p << PAGE_BITS)
86        data.get_block (p << PAGE_BITS)
8787        Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
8888
8989static Iris::Caps map_caps (Iris::Caps data, unsigned p):
source/fat.ccp
1#pypp 0
2#include <iris.hh>
3#include <devices.hh>
4
5#define SECTOR_BITS 9
6#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
7#define ROOT_CLUSTER 0x7fffffff
8
9static unsigned _free
10extern unsigned _end
11
12void init_alloc ():
13    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
14
15char *alloc_space (unsigned pages):
16    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
17    _free = ret + (pages << PAGE_BITS)
18    return (char *)ret
19
20void *operator new[] (unsigned size):
21    //kdebug ("new ")
22    void *ret = (void *)_free
23    size = (size + 3) & ~3
24    unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
25    if rest < size:
26        unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
27        for unsigned p = 0; p < pages; ++p:
28            Iris::Page page = Iris::my_memory.create_page ()
29            page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
30            Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
31            Iris::free_cap (page)
32    _free += size
33    //kdebug_num ((unsigned)ret)
34    //kdebug ("+")
35    //kdebug_num (size)
36    //kdebug ("\n")
37    return ret
38
39void *operator new (unsigned size):
40    return new char[size]
41
42static Iris::WString dev
43static Iris::Num device_size
44static Iris::Page page
45static char *data
46static Iris::Num current_block
47static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
48    if p.code == page.code:
49        if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS:
50            return
51        current_block = idx
52    //kdebug ("fat getting block: ")
53    //kdebug_num (idx.h)
54    //kdebug (":")
55    //kdebug_num (idx.l)
56    //kdebug ("+")
57    //kdebug_num (size)
58    //kdebug ("@")
59    //kdebug_num (offset)
60    //kdebug ("\n")
61    dev.get_block (idx, size, offset, p)
62
63struct Fat:
64    char oem[8]
65    unsigned sector_size_bits
66    unsigned sectors_per_cluster_bits
67    unsigned reserved_sectors
68    unsigned num_fats
69    unsigned root_entries
70    unsigned sectors
71    unsigned media
72    unsigned sectors_per_fat
73    unsigned sectors_per_track
74    unsigned heads
75    unsigned hidden_sectors
76    unsigned active_fat
77    bool write_all_fats
78    unsigned fs_version
79    unsigned root_cluster
80    unsigned fsinfo_sector
81    unsigned boot_backup_sector
82    unsigned drive
83    unsigned current_head
84    unsigned volume_id
85    char label[0xb]
86
87    unsigned bits
88    unsigned clusters
89    unsigned cluster_size_bits
90    unsigned root_sectors
91    unsigned header_sectors
92    unsigned bad_clusters
93
94    unsigned free_clusters
95    unsigned last_alloced
96
97    unsigned *fat
98    unsigned first_free_cluster, first_bad_cluster
99
100    void print_num (char const *pre, unsigned data):
101        kdebug ("\t")
102        kdebug (pre)
103        unsigned bytes = 1
104        while bytes < 8 && data >> (bytes * 4):
105            ++bytes
106        kdebug_num (data, bytes)
107        kdebug ("\n")
108
109    void print_br ():
110        kdebug ("\tOEM: '")
111        for unsigned i = 0; i < 8; ++i:
112            kdebug_char (oem[i])
113        kdebug ("'\n")
114        print_num ("bytes per sector: ", 1 << sector_size_bits)
115        print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits)
116        print_num ("reserved sectors: ", reserved_sectors)
117        print_num ("number of fats: ", num_fats)
118        print_num ("entries in root directory: ", root_entries)
119        print_num ("sectors: ", sectors)
120        print_num ("media descriptor: ", media)
121        print_num ("sectors per fat: ", sectors_per_fat)
122        print_num ("sectors per track: ", sectors_per_track)
123        print_num ("heads: ", heads)
124        print_num ("hidden sectors: ", hidden_sectors)
125        print_num ("active_fat: ", active_fat)
126        kdebug ("\twrite all: ")
127        kdebug (write_all_fats ? "yes\n" : "no\n")
128        print_num ("fs version: ", fs_version)
129        print_num ("root cluster: ", root_cluster)
130        print_num ("fsinfo sector: ", fsinfo_sector)
131        print_num ("boot sector backup sector: ", boot_backup_sector)
132        print_num ("drive: ", drive)
133        print_num ("current head: ", current_head)
134        print_num ("volume id: ", volume_id)
135        kdebug ("\tlabel: '")
136        for unsigned i = 0; i < 0xb; ++i:
137            kdebug_char (label[i])
138        kdebug ("'\n")
139        print_num ("bits: ", bits)
140        print_num ("clusters: ", clusters)
141        print_num ("header sectors: ", header_sectors)
142
143    unsigned read_num (char *data, unsigned bytes):
144        unsigned ret = 0
145        for unsigned i = 0; i < bytes; ++i:
146            ret |= (data[i] & 0xff) << (i * 8)
147        return ret
148
149    void map_fat_cluster (unsigned c, unsigned offset = 0):
150        read_block ((hidden_sectors + reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits)
151
152    unsigned make_bits (unsigned orig):
153        unsigned ret
154        for ret = 0; ret < 32; ++ret:
155            if orig == 1 << ret:
156                return ret
157        Iris::panic (ret, "non-power of 2")
158        return ret
159
160    void reset ():
161        read_block (0)
162        if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
163            kdebug ("invalid boot record signature in fat device\n")
164        for unsigned i = 0; i < 8; ++i:
165            oem[i] = data[3 + i]
166        sector_size_bits = make_bits (read_num (data + 0xb, 2))
167        sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1))
168        cluster_size_bits = sector_size_bits + sectors_per_cluster_bits
169        reserved_sectors = read_num (data + 0xe, 2)
170        num_fats = read_num (data + 0x10, 1)
171        root_entries = read_num (data + 0x11, 2)
172        sectors = read_num (data + 0x13, 2)
173        media = read_num (data + 0x15, 1)
174        sectors_per_fat = read_num (data + 0x16, 2)
175        sectors_per_track = read_num (data + 0x18, 2)
176        heads = read_num (data + 0x1a, 2)
177        hidden_sectors = read_num (data + 0x1c, 4)
178        if !sectors:
179            sectors = read_num (data + 0x20, 4)
180        if Iris::Num (sectors).value () << sector_size_bits > device_size.value ():
181            sectors = device_size.value () >> sector_size_bits
182            kdebug ("warning: limiting sectors because of limited device size\n")
183
184        root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits
185        header_sectors = hidden_sectors + reserved_sectors + sectors_per_fat * num_fats + root_sectors
186        clusters = (sectors - header_sectors) >> sectors_per_cluster_bits
187        unsigned skip
188        if clusters >= 65525:
189            bits = 32
190            sectors_per_fat = read_num (data + 0x24, 4)
191            active_fat = read_num (data + 0x28, 2)
192            write_all_fats = active_fat & 0x80
193            active_fat &= 0xf
194            fs_version = read_num (data + 0x2a, 2)
195            root_cluster = read_num (data + 0x2c, 4)
196            fsinfo_sector = read_num (data + 0x30, 2)
197            boot_backup_sector = read_num (data + 0x32, 2)
198            skip = 0x40 - 0x24
199        else:
200            if clusters < 4085:
201                bits = 12
202            else:
203                bits = 16
204            skip = 0
205            active_fat = 0
206            write_all_fats = true
207            fs_version = 0
208            root_cluster = 0
209            fsinfo_sector = 0
210            boot_backup_sector = 0
211        unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits
212        unsigned fat_entries = sectors_per_fat * fat_entries_per_sector
213        if clusters + 2 > fat_entries:
214            clusters = fat_entries - 2
215            kdebug ("warning: limiting clusters because of limited sector count\n")
216        drive = read_num (data + skip + 0x24, 1)
217        current_head = read_num (data + skip + 0x25, 1)
218        if data[skip + 0x26] == 0x29:
219            volume_id = read_num (data + skip + 0x27, 4)
220            for unsigned i = 0; i < 0xb; ++i:
221                label[i] = data[skip + 0x2b + i]
222            char *id = data + skip + 0x36
223            if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ':
224                kdebug ("warning: file system type field was not 'FATxx '\n")
225            else:
226                switch bits:
227                    case 12:
228                        if id[3] != '1' || id[4] != '2':
229                            kdebug ("warning: id for fat12 is not FAT12\n")
230                        break
231                    case 16:
232                        if id[3] != '1' || id[4] != '6':
233                            kdebug ("warning: id for fat16 is not FAT16\n")
234                        break
235                    case 32:
236                        if id[3] != '3' || id[4] != '2':
237                            kdebug ("warning: id for fat32 wat not FAT32")
238                        break
239        else:
240            volume_id = 0
241            for unsigned i = 0; i < 0xb; ++i:
242                label[i] = 0
243        if fsinfo_sector:
244            read_block (fsinfo_sector << sector_size_bits)
245            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:
246                kdebug ("invalid signature in fsinfo structure\n")
247            free_clusters = read_num (data + 0x1e8, 4)
248            last_alloced = read_num (data + 0x1ec, 4)
249        else:
250            free_clusters = ~0
251            last_alloced = ~0
252
253        // Now read the FAT.
254        bad_clusters = 0
255        fat = new unsigned[clusters]
256        unsigned counted_free_clusters = 0
257        for unsigned c = 0; c < clusters; ++c:
258            // reduced cluster.
259            unsigned rc = c & (1 << sector_size_bits) - 1
260            // The next line does nothing most of the time.
261            map_fat_cluster (c)
262            switch bits:
263                case 12:
264                    fat[c] = data[(rc + 2) * 2] & 0xff
265                    // There may be a sector boundary in the middle of the entry, so optionally reread.
266                    map_fat_cluster (c, 1)
267                    fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8
268                    if c & 1:
269                        fat[c] >>= 4
270                    else:
271                        fat[c] &= 0xfff
272                    break
273                case 16:
274                    fat[c] = read_num (data + (rc + 2) * 2, 2)
275                    break
276                case 32:
277                    fat[c] = read_num (data + (rc + 2) * 4, 4)
278                    break
279            // Correct for the crazy +2 offset, and keep a list of bad and free clusters.
280            if fat[c] == 0:
281                // Free cluster.
282                fat[c] = first_free_cluster
283                first_free_cluster = c
284                ++counted_free_clusters
285            else if fat[c] == 1:
286                // Invalid value.
287                Iris::panic (0, "entry is '1' in fat.")
288            else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff:
289                // Last cluster in chain.
290                fat[c] = ~0
291            else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7:
292                // Bad cluster.
293                fat[c] = first_bad_cluster
294                first_bad_cluster = c
295                ++bad_clusters
296            else:
297                // Non-last cluster in chain.
298                fat[c] -= 2
299    unsigned fat_lookup (unsigned first_cluster, unsigned cluster):
300        while cluster--:
301            first_cluster = fat[first_cluster]
302            if first_cluster == ~0:
303                kdebug ("sector beyond end of file requested\n")
304                return ~0
305        return first_cluster
306    struct File:
307        Fat *fat
308        unsigned size
309        unsigned first_cluster
310        char name[11]
311        bool archive, readonly, system, hidden, directory, volume
312        unsigned create_second, create_minute_hour, create_date, access_date, time, date
313        void load_cluster (unsigned idx, Iris::Page p = page, unsigned offset = 0):
314            unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits)
315            kdebug ("loading cluster ")
316            kdebug_num (idx)
317            kdebug ("@")
318            kdebug_num (cluster)
319            kdebug (" from file\n")
320            if cluster == ~0:
321                kdebug ("invalid cluster requested from file\n")
322                return
323            read_block ((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits, p, 1 << fat->cluster_size_bits, offset)
324            kdebug ("sector ")
325            kdebug_num (fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits))
326            kdebug ("\n")
327    void get_dir_entry (unsigned dir, unsigned idx, File *f):
328        f->fat = this
329        unsigned sector = idx >> (sector_size_bits - 5)
330        unsigned num = (idx << 5) & ~BLOCK_MASK
331        Iris::Num hwsector
332        if dir == ROOT_CLUSTER:
333            if sector < root_sectors:
334                hwsector = header_sectors - root_sectors + sector
335            else:
336                hwsector = ~0
337        else:
338            unsigned entry = fat_lookup (dir, sector)
339            if entry == ~0:
340                hwsector = ~0
341            else:
342                hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits)
343        if hwsector.value () == ~0:
344            kdebug ("invalid sector requested from directory\n")
345            f->first_cluster = ~0
346            return
347        read_block (hwsector.value () << sector_size_bits)
348        char *e = &data[num]
349        for unsigned i = 0; i < 11; ++i:
350            f->name[i] = e[i]
351        f->archive = e[0xb] & 0x20
352        f->readonly = e[0xb] & 0x10
353        f->system = e[0xb] & 0x8
354        f->hidden = e[0xb] & 0x4
355        f->directory = e[0xb] & 0x2
356        f->volume = e[0xb] & 0x1
357        f->create_second = read_num (e + 0xd, 1)
358        f->create_minute_hour = read_num (e + 0xe, 2)
359        f->create_date = read_num (e + 0x10, 2)
360        f->access_date = read_num (e + 0x12, 2)
361        f->time = read_num (e + 0x16, 1)
362        f->date = read_num (e + 0x18, 1)
363        f->size = read_num (e + 0x1c, 4)
364        f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2
365
366// Capability encoding.
367// 0:ROOT_CLUSTER = non fat-32 root directory.
368// 0:cluster = other directory.
369// cluster:index = file index from directory at cluster.
370// cluster|0x80000000:index = filename for file with index from directory at cluster.
371
372Iris::Num start ():
373    init_alloc ()
374    current_block = ~0
375    dev = Iris::my_parent.get_capability <Iris::WString> ()
376    if dev.get_align_bits () > SECTOR_BITS:
377        kdebug ("fat device doesn't support 512 byte access")
378        return 1
379    device_size = dev.get_size ()
380    data = (char *)0x15000; //alloc_space (1)
381    page = Iris::my_memory.create_page ()
382    page.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
383    Iris::my_memory.map (page, (unsigned)data)
384
385    Fat fat
386
387    fat.reset ()
388    fat.print_br ()
389
390    Iris::Cap root
391    if fat.root_cluster:
392        root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0))
393    else:
394        root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0))
395
396    Iris::my_parent.provide_capability <Iris::Directory> (root.copy ())
397    Iris::free_cap (root)
398
399    while true:
400        Iris::wait ()
401        unsigned dir = Iris::recv.protected_data.h
402        if dir & 0x80000000:
403            // File name.
404            unsigned idx = Iris::recv.protected_data.l
405            Iris::Cap reply = Iris::get_reply ()
406            unsigned num = Iris::recv.data[1].l
407            unsigned size = Iris::recv.data[0].h >> 16
408            unsigned cmd = Iris::recv.data[0].l
409            Fat::File f
410            fat.get_dir_entry (dir & ~0x80000000, idx, &f)
411            switch cmd:
412                case Iris::String::GET_SIZE:
413                    kdebug ("filename size requested\n")
414                    reply.invoke (11)
415                    break
416                case Iris::String::GET_CHARS:
417                    //kdebug ("filename chars requested\n")
418                    /**/union { unsigned u[4]; char c[16]; } u
419                    for unsigned k = 0; k < 4; ++k:
420                        u.u[k] = 0
421                    for unsigned k = 0; k + num < 11; ++k:
422                        u.c[k] = f.name[k + num]
423                    reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3]))
424                    break
425                case Iris::String::GET_ALIGN_BITS:
426                    kdebug ("filename align requested\n")
427                    reply.invoke (0)
428                    break
429                case Iris::String::GET_BLOCK:
430                default:
431                    Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename")
432            Iris::free_cap (reply)
433        else if dir:
434            // File.
435            unsigned idx = Iris::recv.protected_data.l
436            Iris::Cap reply = Iris::get_reply ()
437            Iris::Cap arg = Iris::get_arg ()
438            Iris::Num num = Iris::recv.data[1]
439            unsigned size = Iris::recv.data[0].h >> 16
440            unsigned offset = Iris::recv.data[0].h & 0xffff
441            unsigned cmd = Iris::recv.data[0].l
442            Fat::File f
443            fat.get_dir_entry (dir, idx, &f)
444            switch cmd:
445                case Iris::String::GET_SIZE:
446                    kdebug ("file size requested\n")
447                    reply.invoke (f.size)
448                    break
449                case Iris::String::GET_CHARS:
450                    kdebug ("file chars requested\n")
451                    unsigned mask = 1 << (fat.cluster_size_bits) - 1
452                    f.load_cluster (num.l & ~mask)
453                    unsigned n = num.l & mask & ~0xf
454                    unsigned *dat = (unsigned *)(data + n)
455                    reply.invoke (Iris::Num (dat[0], dat[1]), Iris::Num (dat[2], dat[3]))
456                    break
457                case Iris::String::GET_ALIGN_BITS:
458                    kdebug ("file align requested\n")
459                    reply.invoke (fat.cluster_size_bits)
460                    break
461                case Iris::String::GET_BLOCK:
462                    kdebug ("file block requested\n")
463                    unsigned mask = 1 << (fat.cluster_size_bits) - 1
464                    if offset > PAGE_SIZE:
465                        kdebug ("invalid offset requested\n")
466                        break
467                    if size + offset > PAGE_SIZE:
468                        size = PAGE_SIZE - offset
469                    for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits:
470                        f.load_cluster ((num.l & ~mask) + i, arg, i + offset)
471                    reply.invoke ()
472                    break
473                case Iris::WString::TRUNCATE:
474                case Iris::WString::SET_CHARS:
475                case Iris::WString::SET_BLOCK:
476                    Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet")
477                default:
478                    Iris::panic (Iris::recv.data[0].l, "invalid request for fat file")
479            Iris::free_cap (reply)
480            Iris::free_cap (arg)
481        else:
482            // Directory.
483            if Iris::recv.protected_data.l != ROOT_CLUSTER:
484                // Normal directory.
485                switch Iris::recv.data[0].l:
486                    case Iris::Directory::GET_SIZE:
487                        kdebug ("dir size requested\n")
488                        Iris::recv.reply.invoke ()
489                        break
490                    case Iris::Directory::GET_NAME:
491                        kdebug ("dir name requested\n")
492                        Iris::recv.reply.invoke ()
493                        break
494                    case Iris::Directory::GET_FILE_RO:
495                        kdebug ("dir file requested\n")
496                        Iris::Cap reply = Iris::get_reply ()
497                        Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l))
498                        reply.invoke (0, 0, ret.copy ())
499                        Iris::free_cap (reply)
500                        Iris::free_cap (ret)
501                        break
502                    case Iris::Directory::GET_FILE_INFO:
503                        kdebug ("dir file info requested\n")
504                        Iris::recv.reply.invoke ()
505                        break
506                    case Iris::Directory::LOCK_RO:
507                    case Iris::Directory::UNLOCK_RO:
508                        kdebug ("dir lock or unlock requested\n")
509                        Iris::recv.reply.invoke ()
510                        break
511                    default:
512                        kdebug ("invalid dir operation requested\n")
513                        Iris::recv.reply.invoke ()
514                        break
515            else:
516                // Non-fat32 root directory.
517                switch Iris::recv.data[0].l:
518                    case Iris::Directory::GET_SIZE:
519                        kdebug ("root size requested\n")
520                        Iris::recv.reply.invoke (fat.root_entries)
521                        break
522                    case Iris::Directory::GET_NAME:
523                        //kdebug ("root name requested\n")
524                        Iris::Cap reply = Iris::get_reply ()
525                        Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000))
526                        reply.invoke (0, 0, ret.copy ())
527                        Iris::free_cap (reply)
528                        Iris::free_cap (ret)
529                        break
530                    case Iris::Directory::GET_FILE_RO:
531                        kdebug ("root file requested\n")
532                        Iris::Cap reply = Iris::get_reply ()
533                        Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l))
534                        reply.invoke (0, 0, ret.copy ())
535                        Iris::free_cap (reply)
536                        Iris::free_cap (ret)
537                        break
538                    case Iris::Directory::GET_FILE_INFO:
539                        kdebug ("root file info requested\n")
540                        Iris::recv.reply.invoke ()
541                        break
542                    case Iris::Directory::LOCK_RO:
543                    case Iris::Directory::UNLOCK_RO:
544                        kdebug ("root lock or unlock requested\n")
545                        Iris::recv.reply.invoke ()
546                        break
547                    default:
548                        kdebug ("invalid root operation requested\n")
549                        Iris::recv.reply.invoke ()
550                        break
source/init.ccp
182182            unsigned slot = target.use ()
183183            for unsigned p = 0; p < pages; ++p:
184184                Iris::set_recv_arg (Iris::Cap (slot, p))
185                file.get_page (p << PAGE_BITS)
185                file.get_block (p << PAGE_BITS)
186186            Iris::free_slot (slot)
187187        Iris::free_cap (file)
188188        root.unlock_ro ()
...... 
426426            Iris::panic (0, "capability given out twice")
427427        (*d)->dev->client = &**p
428428        ++(*p)->num_waiting
429        kdebug ("registered give device: ")
430        kdebug_num ((*d)->type)
431        kdebug ("\n")
429        //kdebug ("registered give device: ")
430        //kdebug_num ((*d)->type)
431        //kdebug ("\n")
432432    else if match (start, maxlen, "include"):
433433        unsigned name_len
434434        char *name = get_filename (line, maxlen, name_len)
...... 
492492                if !d:
493493                    Iris::panic (type, "unregistered device requested")
494494                Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
495                kdebug ("given device ")
496                kdebug_num (type)
497                kdebug (":")
498                kdebug_num (index)
499                kdebug ("\n")
495                //kdebug ("given device ")
496                //kdebug_num (type)
497                //kdebug (":")
498                //kdebug_num (index)
499                //kdebug ("\n")
500500                break
501501            case Iris::Parent::PROVIDE_CAPABILITY:
502502                if Iris::recv.data[1].h != 0:
...... 
515515                if (*d)->client:
516516                    if !--(*d)->client->num_waiting:
517517                        (*d)->client->run ()
518                kdebug ("provided ")
519                kdebug_num ((*d)->type)
520                kdebug (":")
521                kdebug_num ((*d)->index)
522                kdebug ("\n")
518                //kdebug ("provided ")
519                //kdebug_num ((*d)->type)
520                //kdebug (":")
521                //kdebug_num ((*d)->index)
522                //kdebug ("\n")
523523                break
524524            case Iris::Parent::INIT_DONE:
525                kdebug ("init done\n")
525                //kdebug ("init done\n")
526526                Iris::recv.reply.invoke ()
527527                if caller == sysreq->server:
528528                    Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ)
...... 
530530                    Iris::free_cap (cap)
531531                    kdebug ("registered sysreq\n")
532532                break
533            case Iris::Parent::EXIT:
534                kdebug ("child exits with code ")
535                // TODO: print name.
536                kdebug_num (Iris::recv.data[1].h)
537                kdebug (":")
538                kdebug_num (Iris::recv.data[1].l)
539                kdebug ("\n")
540                // TODO: destroy memory.
541                break
533542            default:
534543                // TODO.
535544                kdebug ("child request: ")
source/partition.ccp
1#pypp 0
2#include <iris.hh>
3#include <devices.hh>
4
5#define NUM_PARTITIONS 4
6#define SECTOR_BITS 9
7#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
8
9struct Partition:
10    static Iris::Num device_size
11    unsigned lba_start, lba_size
12    unsigned type
13    bool active
14    Iris::Num start, size
15    static unsigned read_num (char *data):
16        return data[0] & 0xff | (data[1] & 0xff) << 8 | (data[2] & 0xff) << 16 | (data[3] & 0xff) << 24
17    void read (char *data):
18        if data[0] == 0:
19            active = false
20        else:
21            active = true
22            if (data[0] & 0xff) != 0x80:
23                kdebug ("Warning: invalid active code ")
24                kdebug_num (data[0], 2)
25                kdebug ("\n")
26        type = data[4] & 0xff
27        lba_start = read_num (data + 8)
28        lba_size = read_num (data + 12)
29        start = Iris::Num (lba_start).value () << SECTOR_BITS
30        size = Iris::Num (lba_size).value () << SECTOR_BITS
31        //kdebug ("Partition read: ")
32        //kdebug_num (lba_start)
33        //kdebug ("+")
34        //kdebug_num (lba_size)
35        //kdebug ("\n")
36
37Iris::Num Partition::device_size
38
39static Iris::WString dev
40static void read_block (Iris::Num idx, Iris::Page page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
41    idx = idx.value () >> SECTOR_BITS
42    offset &= ~PAGE_MASK
43    if size + offset > PAGE_SIZE:
44        size = PAGE_SIZE - offset
45    size >>= SECTOR_BITS
46    for unsigned i = 0; i < size; ++i:
47        dev.get_block ((idx.value () + i) << SECTOR_BITS, 1 << SECTOR_BITS, (i << SECTOR_BITS) + offset, page)
48
49Iris::Num start ():
50    Partition::device_size = 0
51    dev = Iris::my_parent.get_capability <Iris::WString> ()
52    if dev.get_align_bits () > SECTOR_BITS:
53        kdebug ("partitioned device doesn't support 512 byte access")
54        return 1
55    Partition::device_size = dev.get_size ()
56    Iris::Page page = Iris::my_memory.create_page ()
57    page.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
58    char *buffer = (char *)0x15000
59    unsigned *ubuffer = (unsigned *)buffer
60    Iris::my_memory.map (page, (unsigned)buffer)
61    read_block (0, page)
62
63    if buffer[0x1fe] != 0x55 || (buffer[0x1ff] & 0xff) != 0xaa:
64        kdebug ("invalid mbr signature\n")
65
66    Partition partition[NUM_PARTITIONS]
67
68    Iris::Cap cap
69    for unsigned i = 0; i < NUM_PARTITIONS; ++i:
70        partition[i].read (buffer + 0x1be + 0x10 * i)
71        cap = Iris::my_receiver.create_capability (i)
72        Iris::my_parent.provide_capability <Iris::WString> (cap.copy (), i)
73        Iris::free_cap (cap)
74
75    page.set_flags (0, Iris::Page::PAYING | Iris::Page::FRAME)
76
77    Iris::my_parent.init_done ()
78
79    while true:
80        Iris::wait ()
81        switch Iris::recv.data[0].l:
82            case Iris::String::GET_SIZE:
83                Iris::recv.reply.invoke (partition[Iris::recv.protected_data.l].size)
84                break
85            case Iris::String::GET_CHARS:
86                Iris::Cap reply = Iris::get_reply ()
87                Iris::Num request = Iris::recv.data[1]
88                Iris::Num offset = (partition[Iris::recv.protected_data.l].start.value () + (request.value () & BLOCK_MASK)) & 0xf
89                unsigned page_offset = request.l & ~BLOCK_MASK
90                page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
91                read_block (offset, page)
92                reply.invoke (Iris::Num (ubuffer[page_offset >> 2 + 0], ubuffer[page_offset >> 2 + 1]), Iris::Num (ubuffer[page_offset >> 2 + 2], ubuffer[page_offset >> 2 + 3]))
93                page.set_flags (0, Iris::Page::PAYING | Iris::Page::FRAME)
94                Iris::free_cap (reply)
95                break
96            case Iris::String::GET_ALIGN_BITS:
97                Iris::recv.reply.invoke (SECTOR_BITS)
98                break
99            case Iris::String::GET_BLOCK:
100                Iris::Cap reply = Iris::get_reply ()
101                Iris::Cap arg = Iris::get_arg ()
102                Iris::Num p = Iris::recv.data[1].value () & BLOCK_MASK
103                Iris::Num offset = partition[Iris::recv.protected_data.l].start.value ()
104                unsigned size = Iris::recv.data[0].h >> 16
105                unsigned out_offset = Iris::recv.data[0].h & 0xffff
106                //kdebug ("partition sending sector ")
107                //kdebug_num (offset.h)
108                //kdebug (":")
109                //kdebug_num (offset.l)
110                //kdebug (" + ")
111                //kdebug_num (p.h)
112                //kdebug (":")
113                //kdebug_num (p.l)
114                //kdebug (" = ")
115                //kdebug_num (Iris::Num (offset.value () + p.value ()).h)
116                //kdebug (":")
117                //kdebug_num (Iris::Num (offset.value () + p.value ()).l)
118                //kdebug ("\n")
119                read_block (offset.value () + p.value (), arg, size, out_offset)
120                reply.invoke ()
121                Iris::free_cap (reply)
122                Iris::free_cap (arg)
123                break
124            case Iris::WString::SET_CHARS:
125            case Iris::WString::SET_BLOCK:
126                Iris::panic (Iris::recv.data[0].l, "writing to partitions not supported yet")
127            case Iris::WString::TRUNCATE:
128            default:
129                Iris::panic (Iris::recv.data[0].l, "invalid request for partition handler")
source/sd+mmc.ccp
2121#include "arch.hh"
2222
2323class Mmc:
24    static unsigned const PORT = 3
25    static unsigned const PIN = 2
26    bool check_sdio ()
24    public:
25    enum Response_type:
26        NONE = MSC_CMDAT_RESPONSE_NONE
27        DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN
28        R1 = MSC_CMDAT_RESPONSE_R1
29        R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
30        R2 = MSC_CMDAT_RESPONSE_R2
31        R3 = MSC_CMDAT_RESPONSE_R3
32        R4 = MSC_CMDAT_RESPONSE_R4
33        R5 = MSC_CMDAT_RESPONSE_R5
34        R6 = MSC_CMDAT_RESPONSE_R6
35        R7 = MSC_CMDAT_RESPONSE_R7
36    static unsigned const POWER_PORT = 3
37    static unsigned const POWER_PIN = 2
38    struct CID:
39        unsigned mid
40        char oid[2]
41        char pnm[5]
42        unsigned prv
43        unsigned psn
44        unsigned year
45        unsigned month
46    struct CSD:
47        unsigned c_size
48        unsigned c_size_mult
49        unsigned read_bl_len, write_bl_len
50        bool copy
51        bool perm_write_protect
52        bool tmp_write_protect
53    bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
54    void check_sd ()
2755    void check_sdmem ()
2856    void check_mmc ()
2957    public:
...... 
3159    void detect ()
3260    void release ()
3361    void interrupt ()
62    CID const &get_cid ():
63        return cid
64    unsigned get_num_blocks ():
65        return num_blocks
66    unsigned get_read_block_size ():
67        return read_block_size
68    unsigned get_block_bits ():
69        return csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
70    void fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
71    private:
72    unsigned rca
73    bool have_sdmem, have_io
74    CID cid
75    CSD csd
76    unsigned num_blocks, read_block_size
77    Iris::Page buffer_page
78    static unsigned const buffer = 0x15000
79
80bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
81    MSC_CMD = cmd
82    MSC_ARG = arg
83    MSC_CMDAT = response_type
84    Iris::register_interrupt (IRQ_MSC)
85    msc_start_op ()
86    Iris::wait_for_interrupt (IRQ_MSC)
87    //kdebug ("cmd: ")
88    //kdebug_num (cmd)
89    unsigned stat = MSC_STAT
90    //kdebug (", stat: ")
91    //kdebug_num (stat)
92    //kdebug ("\n")
93    if stat & MSC_STAT_CRC_RES_ERR:
94        Iris::panic (0, "crc error in mmc response")
95        return false
96    if stat & MSC_STAT_TIME_OUT_RES:
97        //kdebug ("time out waiting for mmc response\n")
98        return false
99    if response_type == R2:
100        unsigned d = MSC_RES
101        if d >> 8 != 0x3f:
102            Iris::panic (d, "invalid r2 response")
103        if cmd == 3:
104            // Read out result.
105            cid.mid = d & 0xff
106            d = MSC_RES
107            cid.oid[0] = d >> 8
108            cid.oid[1] = d & 0xff
109            d = MSC_RES
110            cid.pnm[0] = d >> 8
111            cid.pnm[1] = d & 0xff
112            d = MSC_RES
113            cid.pnm[2] = d >> 8
114            cid.pnm[3] = d & 0xff
115            d = MSC_RES
116            cid.pnm[4] = d >> 8
117            cid.prv = d & 0xff
118            d = MSC_RES
119            cid.psn = d << 16
120            d = MSC_RES
121            cid.psn |= d
122            d = MSC_RES
123            cid.year = 2000 + (d >> 4 & 0xff)
124            cid.month = d & 0xf
125        else:
126            // Header (8) 1.0 1.0
127            // Read out csd.
128            // Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
129            d = MSC_RES
130            // Ignore taac and nsac. 8 + 8 2.0 4.0 ***
131            d = MSC_RES
132            // Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
133            d = MSC_RES
134            // Ignore rest of ccc. 4/12 0.4 6.4
135            // 4 0.4 7.0
136            csd.read_bl_len = (d >> 8) & 0xf
137            // Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
138            // 2/12 0.2 8.0 ***
139            csd.c_size = (d & 0x0003) << 10
140            d = MSC_RES
141            // 10/12 1.2 9.2
142            csd.c_size |= d >> 6
143            // Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
144            d = MSC_RES
145            // Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
146            // 3 0.3 11.1
147            csd.c_size_mult = (d >> 7) & 0x7
148            // Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
149            d = MSC_RES
150            // Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
151            // 2/4 0.4 14.0 ***
152            csd.write_bl_len = (d << 2) & 0xc
153            d = MSC_RES
154            // 2/4 0.2 14.2
155            csd.write_bl_len |= (d >> 14) & 0x3
156            // Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
157            // 1 0.1 15.2
158            csd.copy = d & 0x40
159            // 1 0.1 15.3
160            csd.perm_write_protect = d & 0x20
161            // 1 0.1 15.4
162            csd.tmp_write_protect = d & 0x10
163            // Ignore file_format. 2 (+ 2) 0.4 16.0 ***
164            read_block_size = 1 << csd.read_bl_len
165            num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
166    else if response_type != NONE:
167        unsigned r = MSC_RES
168        if response_type == R3:
169            if r >> 8 != 0x3f:
170                Iris::panic (r, "r3 response was not 3f")
171        else if r >> 8 != cmd:
172            Iris::panic (r, "response doesn't match command")
173        r <<= 24
174        r |= MSC_RES << 8
175        r |= MSC_RES & 0xff
176        if response:
177            *response = r
178    //kdebug ("extra response fifo read: ")
179    //for unsigned i = 0; i < 9; ++i:
180        //kdebug (" ")
181        //kdebug_num (MSC_RES, 4)
182    //kdebug ("\n")
183    MSC_IREG = MSC_IREG_END_CMD_RES
184    return true
34185
35186void Mmc::reset ():
187    // Create a buffer to use for data transfer.
188    buffer_page = Iris::my_memory.create_page ()
189    Iris::my_memory.map (buffer_page, buffer)
190    // Reset all state, by faking a release event.
191    release ()
36192    // Enable slow clock to msc.
37193    CPM_MSCCDR = ~0
38194    cpm_start_msc ()
39195    // Enable msc pins.
40196    gpio_as_msc ()
41197    // Disable power to card.
42    gpio_as_gpio (PORT, 1 << PIN)
43    gpio_as_output (PORT, 1 << PIN)
44    gpio_disable_pull (PORT, 1 << PIN)
45    gpio_set (PORT, 1 << PIN)
198    gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
199    gpio_as_output (POWER_PORT, 1 << POWER_PIN)
200    gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
201    gpio_set (POWER_PORT, 1 << POWER_PIN)
46202
47203    // Stop the clock.
48204    MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
49205    while MSC_STAT & MSC_STAT_CLK_EN:
50        Iris::schedule ()
206        //kdebug (",")
207        Iris::sleep (1)
208
209    // Reset controller and inserted devices.
210    MSC_STRPCL = MSC_STRPCL_RESET
211    while MSC_STAT & MSC_STAT_IS_RESETTING:
212        //kdebug (":")
213        Iris::sleep (1)
51214
52215    // Initialize registers.
53216    MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128
...... 
55218    MSC_RDTO = ~0
56219    MSC_BLKLEN = 0x200
57220    MSC_NOB = 0
58    MSC_IMASK = ~0
221    MSC_IREG = ~0
222    MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ | MSC_IMASK_TXFIFO_WR_REQ)
59223    MSC_ARG = 0
60224
61    // Reset controller and inserted devices.
62    MSC_STRPCL = MSC_STRPCL_RESET
63    while MSC_STAT & MSC_STAT_IS_RESETTING:
64        Iris::schedule ()
65
66225    // Start the clock.
67226    MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
68227    // Set cards, if any, to idle.
69228    MSC_CMD = 0
70229    MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE
230    Iris::register_interrupt (IRQ_MSC)
71231    msc_start_op ()
72    while !msc_ireg_end_cmd_res ():
73        Iris::schedule ()
232    Iris::wait_for_interrupt (IRQ_MSC)
74233    msc_ireg_clear_end_cmd_res ()
75234
76235    // Reset SDIO device, if any.
77236    MSC_CMD = 52
78237    MSC_ARG = 0x88000C08
79238    MSC_CMDAT = MSC_CMDAT_RESPONSE_R5
239    Iris::register_interrupt (IRQ_MSC)
80240    msc_start_op ()
81    while !msc_ireg_end_cmd_res ():
82        Iris::schedule ()
241    Iris::wait_for_interrupt (IRQ_MSC)
83242    msc_ireg_clear_end_cmd_res ()
84243
85bool Mmc::check_sdio ():
86    // 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
87    // 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
88    // 4. If C-bit in the response is ready (the initialization has finished), go to 6.
89    // 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
90    // 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else
91    // it is only a SDIO card.
92    // 7. If it is a combo card, go to check SDMEM to initialize the memory part.
93    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned
94    // from the response.
95    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
96    // 10. Go to check MMC, because we can assure that there is no SDMEM card.
97    return false
244void Mmc::check_mmc ():
245    //kdebug ("checking mmc\n")
246    // 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
247    // 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
248    // 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.)
249    // 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
250    // 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
251    // 6. If the response timeout occurs, goto 9.
252    // 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
98253
99254void Mmc::check_sdmem ():
255    kdebug ("checking sdmem\n")
256    send (0, 0, NONE)
100257    // 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
101258    // 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
259    unsigned code
260    bool hc = false
261    if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
262        kdebug ("hc\n")
263        hc = true
264    if !send (55, 0, R1, &code):
265        check_mmc ()
266        return
102267    // 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
268    if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
269        check_mmc ()
270        return
103271    // 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.)
104272    // 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
273    unsigned retries = 100
274    while !(code & (1 << 31)) && --retries:
275        if !send (55, 0, R1, &code):
276            return
277        if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
278            return
279        Iris::sleep (1)
280    if !(code & (1 << 31)):
281        Iris::panic (code, "card fails to finish setting up")
105282    // 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
283    if !send (2, 0, R2):
284        Iris::panic (0, "card failed to send CID")
106285    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
107286    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
108    // 10. Go to check MMC.
287    rca = 0
288    while !rca:
289        if !send (3, 0, R6, &rca):
290            Iris::panic (0, "card failed to provide rca")
291        rca &= 0xffff0000
292    kdebug ("received rca ")
293    kdebug_num (rca >> 16, 4)
294    kdebug ("\n")
295    have_sdmem = true
109296
110void Mmc::check_mmc ():
111    // 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
112    // 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
113    // 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.)
114    // 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
115    // 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
116    // 6. If the response timeout occurs, goto 9.
117    // 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
118    // 8. If there are other MMC cards, then go to 5.
297void Mmc::check_sd ():
298    //kdebug ("checking sdio\n")
299    if !send (0, 0, NONE):
300        Iris::panic (0, "unable to reset cards?")
301    // 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
302    // 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
303    unsigned code
304    if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
305        check_sdmem ()
306        return
307    // 4. If C-bit in the response is ready (the initialization has finished), go to 6.
308    // 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
309    while !(code & (1 << 31)):
310        if !send (5, 1 << 20, R4, &code):
311            Iris::panic (0, "invalid response to cmd 5")
312    // 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.
313    // 7. If it is a combo card, go to check SDMEM to initialize the memory part.
314    have_io = true
315    if code & (1 << 27):
316        check_sdmem ()
317        return
318    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
319    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
320    rca = 0
321    while rca == 0:
322        if !send (3, 0, R6, &rca):
323            Iris::panic (0, "unable to set rca")
324        rca &= 0xffff0000
325    check_mmc ()
119326
120327void Mmc::detect ():
121328    kdebug ("mmc detect\n")
122    gpio_clear (PORT, 1 << PIN)
123    if check_sdio ():
124        check_sdmem ()
329    gpio_clear (POWER_PORT, 1 << POWER_PIN)
330    check_sd ()
125331    check_mmc ()
332    if have_sdmem:
333        if !send (9, rca, R2):
334            Iris::panic (0, "unable to request csd")
335        if !send (7, rca, R1B):
336            Iris::panic (0, "unable to select sdmem")
337        kdebug ("found device; size = ")
338        kdebug_num (num_blocks)
339        kdebug (" * ")
340        kdebug_num (read_block_size)
341        kdebug (" = ")
342        kdebug_num (num_blocks * read_block_size)
343        kdebug ("\n")
126344
127345void Mmc::release ():
128346    kdebug ("mmc release\n")
129    gpio_set (PORT, 1 << PIN)
347    gpio_set (POWER_PORT, 1 << POWER_PIN)
348    have_sdmem = false
349    have_io = false
350    read_block_size = 0
351    num_blocks = 0
130352
131353void Mmc::interrupt ():
132354    kdebug ("mmc interrupt\n")
133355
356void Mmc::fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
357    if address.h:
358        Iris::panic (0, "page too high: not supported")
359        return
360    unsigned blockmask = ~((1 << get_block_bits ()) - 1)
361    unsigned p = address.l & blockmask
362    size &= blockmask
363    offset &= ~PAGE_MASK
364    if size + offset > PAGE_SIZE:
365        size = PAGE_SIZE - offset
366    page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
367    page.share (buffer_page)
368    buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
369    MSC_NOB = 1
370    MSC_BLKLEN = read_block_size
371    for unsigned a = 0; a < size; a += 1 << get_block_bits ():
372        if !send (17, p + a, DATA):
373            Iris::panic (0, "unable to request data")
374        for unsigned aa = 0; aa < read_block_size; aa += 4:
375            Iris::register_interrupt (IRQ_MSC)
376            Iris::wait_for_interrupt (IRQ_MSC)
377            *(unsigned *)(buffer + a + aa + offset) = MSC_RXFIFO
378        MSC_IREG = MSC_IREG_DATA_TRAN_DONE
379
380static Mmc mmc
134381
135382enum types:
136383    DETECT
...... 
141388    map_gpio ()
142389    map_cpm ()
143390
144    Mmc mmc
145391    mmc.reset ()
146392
147393    Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
...... 
178424                mmc.interrupt ()
179425                break
180426            case REQUEST:
181                kdebug ("sd+mmc request\n")
427                //kdebug ("sd+mmc request ")
428                //kdebug_num (Iris::recv.data[0].l)
429                //kdebug ("\n")
430                switch Iris::recv.data[0].l:
431                    case Iris::String::GET_SIZE:
432                        unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
433                        Iris::recv.reply.invoke (size)
434                        break
435                    case Iris::String::GET_CHARS:
436                        Iris::panic (0, "get chars from mmc not supported yet")
437                        break
438                    case Iris::String::GET_ALIGN_BITS:
439                        Iris::recv.reply.invoke (mmc.get_block_bits ())
440                        break
441                    case Iris::String::GET_BLOCK:
442                        Iris::Cap reply = Iris::get_reply ()
443                        Iris::Page page = Iris::get_arg ()
444                        mmc.fill_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
445                        reply.invoke ()
446                        Iris::free_cap (page)
447                        Iris::free_cap (reply)
448                        break
449                    case Iris::WString::SET_CHARS:
450                    case Iris::WString::SET_BLOCK:
451                        // Fall through: don't support writing yet.
452                    case Iris::WString::TRUNCATE:
453                    default:
454                        Iris::panic (0, "unexpected event for sd+mmc")
182455                break
183456            default:
184457                Iris::panic (0, "unexpected request source for sd+mmc")
source/test.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/test.ccp: Testing program.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include <iris.hh>
20#include <devices.hh>
21
22bool match (char const *a, char const *b):
23    for unsigned i = 0; i < 11; ++i:
24        if a[i] != b[i]:
25            return false
26    return true
27
28Iris::Num start ():
29    Iris::Directory dir = Iris::my_parent.get_capability <Iris::Directory> ()
30    dir.lock_ro ()
31    Iris::Num files = dir.get_size ()
32    for Iris::Num i = 0; i.value () < files.value (); i = i.value () + 1:
33        Iris::String f = dir.get_name (i)
34        char start[16]
35        f.get_chars (0, start)
36        if match (start, "TEST TXT"):
37            Iris::free_cap (f)
38            f = dir.get_file_ro (i)
39            dir.unlock_ro ()
40            Iris::Page p = f.get_block (0)
41            char *mapping = (char *)0x15000
42            Iris::my_memory.map (p, (unsigned)mapping)
43            for unsigned j = 0; j < PAGE_SIZE; ++j:
44                kdebug_char (mapping[j])
45            kdebug_char ('\n')
46            return 0
47        unsigned i
48        for i = 0; i < 16; ++i:
49            if start[i] != 0:
50                break
51        if i < 16:
52            for i = 0; i < 16; ++i:
53                kdebug_num (start[i], 2)
54                kdebug (" ")
55            for i = 0; i < 16; ++i:
56                kdebug_char (start[i])
57            kdebug ("\n")
58        Iris::free_cap (f)
59    kdebug ("file test.txt not found\n")
60    return 1
source/udc.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/udc.ccp: USB device controller driver.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "iris.hh"
20#include "devices.hh"
21#define ARCH
22#include "arch.hh"
23
24class Udc:
25    typedef unsigned char u8
26    typedef unsigned short u16
27    typedef unsigned int u32
28    typedef u8 string
29    // The ugly stuff is because pypp doesn't support __attribute__.
30    /**/struct Setup {
31        u8 request_type;
32        u8 request;
33        u16 value;
34        u16 index;
35        u16 length;
36     } __attribute__ ((packed))
37    /**/struct Device {
38        static u8 const Type = 1;
39        u8 length;
40        u8 type;
41        u16 usb_version;
42        u8 dev_class;
43        u8 subclass;
44        u8 protocol;
45        u8 max_packet_size0;
46        u16 vendor;
47        u16 product;
48        u16 dev_version;
49        string s_manufacturer;
50        string s_product;
51        string s_serial;
52        u8 num_configurations;
53     } __attribute__ ((packed))
54    /**/struct Configuration {
55        static u8 const Type = 2;
56        u8 length;
57        u8 type;
58        u16 total_length;
59        u8 num_interfaces;
60        u8 configuration_value;
61        u8 configuration;
62        u8 attributes;
63        u8 max_power;
64     } __attribute__ ((packed))
65    /**/struct Interface {
66        static u8 const Type = 4;
67        u8 length;
68        u8 type;
69        u8 interface;
70        u8 alternate;
71        u8 num_endpoints;
72        u8 iface_class;
73        u8 subclass;
74        u8 protocol;
75        string name;
76     } __attribute__ ((packed))
77    /**/struct Endpoint {
78        static u8 const Type = 5;
79        u8 length;
80        u8 type;
81        u8 address;
82        u8 attributes;
83        u16 max_packet_size;
84        u8 interval;
85     } __attribute__ ((packed))
86    /**/struct Device_Qualifier {
87        static u8 const Type = 6;
88        u8 length;
89        u8 type;
90        u16 version;
91        u8 dev_class;
92        u8 subclass;
93        u8 protocol;
94        u8 max_packet_size0;
95        u8 num_configurations;
96        u8 reserved;
97     } __attribute__ ((packed))
98    /**/struct Langs {
99        static u8 const Type = 3;
100        u8 length;
101        u8 type;
102        u8 lang;
103     } __attribute__ ((packed))
104    template <unsigned size> struct String {
105        static u8 const Type = 3;
106        u8 length;
107        u8 type;
108        u16 data[size];
109     } __attribute__ ((packed))
110    static unsigned const max_packet_size0 = 64
111    static unsigned const max_packet_size_bulk = 64
112    enum Requests:
113        GET_STATUS = 0
114        CLEAR_FEATURE = 1
115        SET_FEATURE = 3
116        SET_ADDRESS = 5
117        GET_DESCRIPTOR = 6
118        SET_DESCRIPTOR = 7
119        GET_CONFIGURATION = 8
120        SET_CONFIGURATION = 9
121        GET_INTERFACE = 10
122        SET_INTERFACE = 11
123        SYNCH_FRAME = 12
124    enum Request_types:
125        STANDARD_TO_DEVICE = 0
126        VENDOR_TO_DEVICE = 0x40
127        STANDARD_FROM_DEVICE = 0x80
128        VENDOR_FROM_DEVICE = 0xc0
129    enum Endpoint_types:
130        CONTROL = 0
131        ISOCHRONOUS = 1
132        BULK = 2
133        INTERRUPT = 3
134    /**/struct my_config {
135        Configuration config;
136        Interface interface;
137        Endpoint endpoint[2];
138     } __attribute__ ((packed))
139    static Device device_descriptor
140    //static Device_Qualifier device_qualifier_descriptor
141    static my_config config_descriptor; //, other_config_descriptor
142    static String <1> s_langs
143    static String <6> s_manufacturer
144    static String <16> s_product
145    enum State:
146        IDLE
147        TX
148        RX
149    State state
150    char configuration
151    unsigned size
152    unsigned rx_request
153    char const *ptr
154    unsigned cmd_code, cmd_arg
155    bool rebooting
156    bool vendor (Setup *s, unsigned cmd)
157    bool get_descriptor (unsigned type, unsigned idx, unsigned len)
158    bool handle_setup (Setup *s, unsigned cmd)
159    void irq_usb (unsigned cmd)
160    void irq_in (unsigned cmd)
161    void irq_out (unsigned cmd)
162    char log_buffer[1000]
163    unsigned log_buffer_size
164    unsigned log_buffer_start
165    Iris::Cap caller, caller_arg
166    bool have_caller
167    unsigned *page
168    unsigned *p
169    Iris::Page buffer_page
170    public:
171    void init ()
172    void log (unsigned c)
173    void interrupt (unsigned cmd)
174    void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg)
175
176Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
177Udc::my_config Udc::config_descriptor = {
178    (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
179    (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
180        (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
181        (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
182    }
183 }
184Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } }
185Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
186Udc::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' } }
187
188//Udc::Device_Qualifier const Udc::device_qualifier_descriptor = { sizeof (Device_Qualifier), Device_Qualifier::Type, 0x200, 0, 0, 0, max_packet_size0, 1, 0 }
189//Udc::my_config const Udc::other_config_descriptor = {
190// (Configuration){ sizeof (Configuration), 7, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
191// (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
192// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
193// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
194// }
195// }
196
197void Udc::init ():
198    // Initialize the globals. My method of compiling doesn't do that properly.
199    device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
200    config_descriptor = (my_config){
201        (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
202        (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
203            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
204            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
205        }
206     }
207    s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
208    s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
209    s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
210    have_caller = false
211    log_buffer_size = 0
212    log_buffer_start = 0
213    cmd_code = ~0
214    cmd_arg = 0
215
216    // Use the space which is reserved for the framebuffer, because it will not be in use.
217    // Normally a normal new page should be allocated here, but new isn't implemented at this point.
218    page = (unsigned *)LCD_FRAMEBUFFER_BASE
219    p = page
220    buffer_page = Iris::my_memory.create_page ()
221    buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING, Iris::Page::FRAME | Iris::Page::PAYING)
222    Iris::my_memory.map (buffer_page, (unsigned)page)
223
224    // Disconnect from the bus and don't try to get high-speed.
225    UDC_POWER = 0
226    UDC_TESTMODE = 0
227    UDC_INDEX = 0
228    state = IDLE
229    configuration = 0
230    size = 0
231    // exit suspend mode by reading the interrupt register.
232    cpm_start_udc ()
233    // reset all pending endpoint interrupts.
234    unsigned i = UDC_INTRUSB
235    i = UDC_INTRIN
236    i = UDC_INTROUT
237    // enable interrupt on bus reset.
238    UDC_INTRUSBE = UDC_INTR_RESET
239    // enable interrupts on endpoint 0.
240    UDC_INTRINE = 1 << 0
241    // and on out endpoint 1.
242    UDC_INTROUTE = 1 << 1
243    // Wait a while.
244    for unsigned w = 0; w < 10000; ++w:
245        Iris::schedule ()
246    // Connect to the host.
247    UDC_POWER = UDC_POWER_SOFTCONN
248
249bool Udc::vendor (Setup *s, unsigned cmd):
250    if !(s->request_type & 0x80):
251        kdebug ("data to device without size\n")
252        Iris::panic (0)
253        return true
254    if s->request == 10:
255        static unsigned b[2]
256        ptr = (char *)b
257        size = s->length < 8 ? s->length : 8
258        if cmd_code != ~0:
259            b[0] = cmd_code
260            b[1] = cmd_arg
261            if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO:
262                caller.invoke ()
263                Iris::free_cap (caller)
264                Iris::free_cap (caller_arg)
265                have_caller = false
266                //kdebug ("(un)lock response\n")
267            cmd_code = ~0
268        else:
269            if log_buffer_start == log_buffer_size:
270                b[0] = ~1
271                b[1] = 0
272            else:
273                b[0] = ~0
274                b[1] = (log_buffer[log_buffer_start++] & 0xff) * 0x01010101
275            if log_buffer_start == log_buffer_size:
276                log_buffer_start = 0
277                log_buffer_size = 0
278    else:
279        static char const *name = "Reboot"
280        ptr = name
281        size = s->length < 6 ? s->length : 6
282        rebooting = true
283    state = TX
284    return true
285
286void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg):
287    if cmd_code != ~0:
288        kdebug ("new code sent while old one wasn't finished.\n")
289        Iris::panic (0)
290    cmd_code = code
291    cmd_arg = narg
292    caller = reply
293    caller_arg = arg
294    have_caller = true
295
296bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
297    switch type:
298        case Configuration::Type:
299            if idx != 0:
300                return false
301            ptr = reinterpret_cast <char const *> (&config_descriptor)
302            size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor))
303            break
304        case Device::Type:
305            if idx != 0:
306                return false
307            ptr = reinterpret_cast <char const *> (&device_descriptor)
308            size = (len < sizeof (device_descriptor) ? len : sizeof (device_descriptor))
309            break
310        case Device_Qualifier::Type:
311            //if idx != 0:
312            // return false
313            //ptr = reinterpret_cast <char const *> (&device_qualifier_descriptor)
314            //size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
315            //break
316            return false
317        // The 6 is an arbitrary number, except that String <6> is instantiated already.
318        case String <6>::Type:
319            switch idx:
320                case 0:
321                    ptr = reinterpret_cast <char const *> (&s_langs)
322                    size = (len < sizeof (s_langs) ? len : sizeof (s_langs))
323                    break
324                case 1:
325                    ptr = reinterpret_cast <char const *> (&s_manufacturer)
326                    size = (len < sizeof (s_manufacturer) ? len : sizeof (s_manufacturer))
327                    break
328                case 2:
329                    ptr = reinterpret_cast <char const *> (&s_product)
330                    size = (len < sizeof (s_product) ? len : sizeof (s_product))
331                    break
332                default:
333                    return false
334            break
335        default:
336            return false
337    state = TX
338    return true
339
340bool Udc::handle_setup (Setup *s, unsigned cmd):
341    switch s->request_type:
342        case STANDARD_TO_DEVICE:
343            switch s->request:
344                case SET_ADDRESS:
345                    UDC_FADDR = s->value
346                    break
347                case SET_CONFIGURATION:
348                    if s->value >= 2:
349                        return false
350                    configuration = s->value
351                    break
352                case SET_INTERFACE:
353                    if s->value != 0:
354                        return false
355                    break
356                default:
357                    return false
358            UDC_OUTMAXP = 64
359            UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
360            UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
361            break
362        case STANDARD_FROM_DEVICE:
363            switch s->request:
364                case GET_STATUS:
365                    ptr = "\0\0"
366                    size = (s->length < 2 ? s->length : 2)
367                    state = TX
368                    break
369                case GET_DESCRIPTOR:
370                    return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
371                case GET_CONFIGURATION:
372                    ptr = &configuration
373                    size = (s->length < 1 ? s->length : 1)
374                    state = TX
375                    break
376                case GET_INTERFACE:
377                    ptr = "\0"
378                    size = (s->length < 1 ? s->length : 1)
379                    state = TX
380                    break
381                default:
382                    return false
383            break
384        case VENDOR_TO_DEVICE:
385        case VENDOR_FROM_DEVICE:
386            return vendor (s, cmd)
387        default:
388            return false
389    return true
390
391void Udc::irq_usb (unsigned cmd):
392    // Reset.
393    state = IDLE
394
395void Udc::irq_in (unsigned cmd):
396    // Interrupt on endpoint 0.
397    unsigned csr = UDC_CSR0
398    if csr & UDC_CSR0_SENTSTALL:
399        csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL)
400        state = IDLE
401    if csr & UDC_CSR0_SETUPEND:
402        csr |= UDC_CSR0_SVDSETUPEND
403        state = IDLE
404    switch state:
405        case IDLE:
406            if rebooting:
407                Iris::reboot ()
408            if !(csr & UDC_CSR0_OUTPKTRDY):
409                return
410            union { unsigned d[2]; Setup s; } packet
411            packet.d[0] = UDC_FIFO (0)
412            packet.d[1] = UDC_FIFO (0)
413            if !(packet.s.request_type & 0x80) && packet.s.length > 0:
414                // More data will follow; delay handling of packet.
415                state = RX
416                UDC_CSR0 = csr | UDC_CSR0_SVDOUTPKTRDY
417                rx_request = packet.s.request
418                return
419            UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
420            if !handle_setup (&packet.s, cmd):
421                csr |= UDC_CSR0_SENDSTALL
422                break
423            if size == 0:
424                return
425            // Fall through.
426        case TX:
427            unsigned i
428            for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4:
429                UDC_FIFO (0) = *(unsigned *)ptr
430                ptr += 4
431            for ; size > 0 && i < max_packet_size0; ++i, --size:
432                UDC_FIFO8 (0) = *ptr++
433            if i == max_packet_size0:
434                csr |= UDC_CSR0_INPKTRDY
435            else:
436                state = IDLE
437                csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
438            break
439        case RX:
440            // The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
441            switch rx_request & 0xff:
442                case Iris::Directory::GET_SIZE & 0xff:
443                    if !have_caller:
444                        kdebug ("received dir size from server without a caller waiting\n")
445                        Iris::panic (0)
446                    unsigned size_l = UDC_FIFO (0)
447                    unsigned size_h = UDC_FIFO (0)
448                    caller.invoke (Iris::Num (size_l, size_h))
449                    Iris::free_cap (caller)
450                    Iris::free_cap (caller_arg)
451                    have_caller = false
452                    //kdebug ("get_size response\n")
453                    break
454                case Iris::Directory::GET_NAME & 0xff:
455                    if !have_caller:
456                        kdebug ("received filename from server without a caller waiting\n")
457                        Iris::panic (0)
458                    unsigned n[4]
459                    for unsigned i = 0; i < 4; ++i:
460                        n[i] = UDC_FIFO (0)
461                    caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
462                    Iris::free_cap (caller)
463                    Iris::free_cap (caller_arg)
464                    //kdebug ("get_name response\n")
465                    have_caller = false
466                    break
467                case Iris::String::GET_SIZE & 0xff:
468                    if !have_caller:
469                        kdebug ("received string size from server without a caller waiting\n")
470                        Iris::panic (0)
471                    unsigned size_l = UDC_FIFO (0)
472                    unsigned size_h = UDC_FIFO (0)
473                    caller.invoke (Iris::Num (size_l, size_h))
474                    Iris::free_cap (caller)
475                    Iris::free_cap (caller_arg)
476                    have_caller = false
477                    //kdebug ("get_filesize response\n")
478                    break
479                case Iris::String::GET_CHARS & 0xff:
480                    if !have_caller:
481                        kdebug ("received string char data from server without a caller waiting\n")
482                        Iris::panic (0)
483                    unsigned n[4]
484                    for unsigned i = 0; i < 4; ++i:
485                        n[i] = UDC_FIFO (0)
486                    caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
487                    Iris::free_cap (caller)
488                    Iris::free_cap (caller_arg)
489                    have_caller = false
490                    //kdebug ("get_chars response\n")
491                    break
492                default:
493                    kdebug ("invalid vendor request: ")
494                    kdebug_num (rx_request)
495                    kdebug ("\n")
496                    Iris::panic (0)
497            UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
498            state = IDLE
499            break
500    UDC_CSR0 = csr
501
502void Udc::irq_out (unsigned cmd):
503    // Interrupt on OUT endpoint 1.
504    UDC_INDEX = 1
505    if !have_caller:
506        kdebug ("received bulk data from server without a caller waiting\n")
507        Iris::panic (0)
508    unsigned size = UDC_OUTCOUNT
509    unsigned csr = UDC_OUTCSR
510    //kdebug ("handling bulk interrupt for ")
511    //kdebug_num (csr)
512    //kdebug (" with ")
513    //kdebug_num (size)
514    //kdebug (" bytes.\n")
515    csr &= ~UDC_OUTCSR_OUTPKTRDY
516    for unsigned i = 0; i < size; i += 4:
517        *p++ = UDC_FIFO (1)
518    if p - page == PAGE_SIZE >> 2:
519        buffer_page.share (caller_arg, Iris::Page::FORGET)
520        buffer_page.set_flags (Iris::Page::FRAME, Iris::Page::FRAME)
521        caller.invoke ()
522        Iris::free_cap (caller)
523        Iris::free_cap (caller_arg)
524        have_caller = false
525        //kdebug ("bulk response\n")
526        p = page
527    UDC_OUTCSR = csr
528    UDC_INDEX = 0
529
530void Udc::interrupt (unsigned cmd):
531    while true:
532        unsigned usb = UDC_INTRUSB
533        unsigned in = UDC_INTRIN
534        unsigned out = UDC_INTROUT
535        if !(usb & 4) && !(in & 1) && !(out & 2):
536            break
537        //kdebug ("interrupt: ")
538        //kdebug_num (usb, 1)
539        //kdebug ("/")
540        //kdebug_num (in, 1)
541        //kdebug ("/")
542        //kdebug_num (out, 1)
543        //kdebug ("\n")
544        if usb & 4:
545            irq_usb (cmd)
546        if in & 1:
547            irq_in (cmd)
548        if out & 2:
549            irq_out (cmd)
550
551void Udc::log (unsigned c):
552    if log_buffer_size >= sizeof (log_buffer):
553        return
554    log_buffer[log_buffer_size++] = c
555
556enum pdata:
557    LOG = 32
558    FS
559    DATA
560    DIRECTORY
561    FILE
562    NAME
563
564Iris::Num start ():
565    map_udc ()
566    map_gpio ()
567    map_cpm ()
568    Udc udc
569
570    Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
571    __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
572    udc.init ()
573    Iris::register_interrupt (IRQ_UDC)
574    Iris::Filesystem fs = Iris::my_receiver.create_capability (FS)
575    Iris::String data = Iris::my_receiver.create_capability (DATA)
576    Iris::my_parent.provide_capability <Iris::Filesystem> (fs.copy ())
577    Iris::my_parent.provide_capability <Iris::String> (data.copy ())
578    Iris::free_cap (fs)
579    Iris::free_cap (data)
580    unsigned state = 0
581    while true:
582        Iris::wait ()
583        Iris::Cap reply = Iris::get_reply ()
584        Iris::Cap arg = Iris::get_arg ()
585        switch Iris::recv.protected_data.l:
586            case IRQ_UDC:
587                udc.interrupt (state)
588                Iris::register_interrupt (IRQ_UDC)
589                break
590            case LOG:
591                udc.log (Iris::recv.data[0].l)
592                break
593            case DATA:
594                //kdebug ("data request\n")
595                switch Iris::recv.data[0].l:
596                    case Iris::Device::RESET:
597                    case Iris::String::GET_SIZE:
598                    case Iris::String::GET_CHARS:
599                        reply.invoke (0)
600                        Iris::free_cap (reply)
601                        Iris::free_cap (arg)
602                        continue
603                    case Iris::String::GET_BLOCK:
604                    default:
605                        reply.invoke (Iris::ERR_INVALID_OPERATION)
606                        Iris::free_cap (reply)
607                        Iris::free_cap (arg)
608                        continue
609                break
610            case FS:
611                //kdebug ("fs request\n")
612                switch Iris::recv.data[0].l:
613                    case Iris::Device::RESET:
614                        reply.invoke (0)
615                        Iris::free_cap (reply)
616                        Iris::free_cap (arg)
617                        continue
618                    case Iris::Filesystem::USE_DEVICE:
619                    case Iris::Filesystem::USE_DEVICE_RO:
620                        Iris::Directory dir = Iris::my_receiver.create_capability (DIRECTORY)
621                        reply.invoke (0, 0, dir.copy ())
622                        Iris::free_cap (dir)
623                        Iris::free_cap (reply)
624                        Iris::free_cap (arg)
625                        continue
626                    default:
627                        reply.invoke (Iris::ERR_INVALID_OPERATION)
628                        Iris::free_cap (reply)
629                        Iris::free_cap (arg)
630                        continue
631                break
632            case DIRECTORY:
633                //kdebug ("dir request\n")
634                switch Iris::recv.data[0].l:
635                    case Iris::Directory::GET_NAME:
636                        Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (NAME, Iris::recv.data[1].l))
637                        reply.invoke (0, 0, name.copy ())
638                        Iris::free_cap (name)
639                        Iris::free_cap (reply)
640                        Iris::free_cap (arg)
641                        continue
642                    case Iris::Directory::GET_SIZE:
643                    case Iris::Directory::LOCK_RO:
644                    case Iris::Directory::UNLOCK_RO:
645                        state = Iris::recv.data[0].l
646                        if Iris::recv.data[1].h != 0:
647                            kdebug ("index out of supported range\n")
648                            Iris::panic (0)
649                        udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
650                        continue
651                    case Iris::Directory::GET_FILE_RO:
652                        if Iris::recv.data[1].h != 0:
653                            kdebug ("index out of supported range\n")
654                            Iris::panic (0)
655                        //kdebug ("sending file\n")
656                        Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (FILE, Iris::recv.data[1].l))
657                        reply.invoke (0, 0, file.copy ())
658                        Iris::free_cap (file)
659                        Iris::free_cap (reply)
660                        Iris::free_cap (arg)
661                        continue
662                    case Iris::Directory::GET_FILE_INFO:
663                    default:
664                        reply.invoke (Iris::ERR_INVALID_OPERATION)
665                        Iris::free_cap (reply)
666                        Iris::free_cap (arg)
667                        continue
668                break
669            case FILE:
670                //kdebug ("file request\n")
671                switch Iris::recv.data[0].l:
672                    case Iris::String::GET_BLOCK:
673                        if Iris::recv.data[0].h != PAGE_SIZE << 16:
674                            Iris::panic (0, "unsupported get_block arguments for boot usb device driver")
675                        // Fall through.
676                    case Iris::String::GET_SIZE:
677                    case Iris::String::GET_CHARS:
678                        udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.h, reply, arg)
679                        continue
680                    default:
681                        reply.invoke (Iris::ERR_INVALID_OPERATION)
682                        Iris::free_cap (reply)
683                        Iris::free_cap (arg)
684                        continue
685                break
686            case NAME:
687                //kdebug ("name request\n")
688                switch Iris::recv.data[0].l:
689                    case Iris::String::GET_SIZE:
690                        reply.invoke (16)
691                        Iris::free_cap (reply)
692                        Iris::free_cap (arg)
693                        continue
694                    case Iris::String::GET_CHARS:
695                        state = Iris::recv.data[0].l
696                        udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.h, reply, arg)
697                        continue
698                    default:
699                        reply.invoke (Iris::ERR_INVALID_OPERATION)
700                        Iris::free_cap (reply)
701                        Iris::free_cap (arg)
702                        continue
703            default:
704                kdebug ("other request:")
705                kdebug_num (Iris::recv.protected_data.l)
706                kdebug ("\n")
707                udc.log ('~')
708                char digit[] = "0123456789abcdef"
709                for unsigned i = 0; i < 8; ++i:
710                    udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
711                udc.log ('\n')
712                break
713        reply.invoke ()
714        Iris::free_cap (reply)
715        Iris::free_cap (arg)

Archive Download the corresponding diff file

Branches:
master



interactive