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 | | |
28 | | static unsigned _free |
29 | | extern unsigned _end |
30 | | |
31 | | void init_alloc (): |
32 | | _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK |
33 | | |
34 | | char *alloc_space (unsigned pages): |
35 | | unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK |
36 | | _free = ret + (pages << PAGE_BITS) |
37 | | return (char *)ret |
38 | | |
39 | | void *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 | | |
58 | | void *operator new (unsigned size): |
59 | | return new char[size] |
60 | | |
61 | | static unsigned *bss_mapping |
62 | | static Iris::Page bss_page |
63 | | |
64 | | // Get the initial block device and filesystem. |
65 | | static 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 | | |
96 | | static 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 | | |
102 | | static 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 | | |
119 | | static 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 | | |
258 | | Iris::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/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 | | |
24 | | class 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 | | |
176 | | Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 } |
177 | | Udc::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 | | } |
184 | | Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } } |
185 | | Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } } |
186 | | Udc::String <16> Udc::s_product = { sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } } |
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 | | |
197 | | void 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 | | |
249 | | bool 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 | | |
286 | | void 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 | | |
296 | | bool 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 | | |
340 | | bool 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 | | |
391 | | void Udc::irq_usb (unsigned cmd): |
392 | | // Reset. |
393 | | state = IDLE |
394 | | |
395 | | void 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 | | |
502 | | void 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 | | |
530 | | void 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 | | |
551 | | void Udc::log (unsigned c): |
552 | | if log_buffer_size >= sizeof (log_buffer): |
553 | | return |
554 | | log_buffer[log_buffer_size++] = c |
555 | | |
556 | | enum pdata: |
557 | | LOG = 32 |
558 | | FS |
559 | | DATA |
560 | | DIRECTORY |
561 | | FILE |
562 | | NAME |
563 | | |
564 | | Iris::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) |
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 | |
| 28 | static unsigned _free |
| 29 | extern unsigned _end |
| 30 | |
| 31 | void init_alloc (): |
| 32 | _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK |
| 33 | |
| 34 | char *alloc_space (unsigned pages): |
| 35 | unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK |
| 36 | _free = ret + (pages << PAGE_BITS) |
| 37 | return (char *)ret |
| 38 | |
| 39 | void *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 | |
| 58 | void *operator new (unsigned size): |
| 59 | return new char[size] |
| 60 | |
| 61 | static unsigned *bss_mapping |
| 62 | static Iris::Page bss_page |
| 63 | |
| 64 | // Get the initial block device and filesystem. |
| 65 | static 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 | |
| 96 | static 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 | |
| 102 | static 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 | |
| 119 | static 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 | |
| 258 | Iris::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/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 | |
| 9 | static unsigned _free |
| 10 | extern unsigned _end |
| 11 | |
| 12 | void init_alloc (): |
| 13 | _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK |
| 14 | |
| 15 | char *alloc_space (unsigned pages): |
| 16 | unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK |
| 17 | _free = ret + (pages << PAGE_BITS) |
| 18 | return (char *)ret |
| 19 | |
| 20 | void *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 | |
| 39 | void *operator new (unsigned size): |
| 40 | return new char[size] |
| 41 | |
| 42 | static Iris::WString dev |
| 43 | static Iris::Num device_size |
| 44 | static Iris::Page page |
| 45 | static char *data |
| 46 | static Iris::Num current_block |
| 47 | static 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 | |
| 63 | struct 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 | |
| 372 | Iris::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/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 | |
| 9 | struct 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 | |
| 37 | Iris::Num Partition::device_size |
| 38 | |
| 39 | static Iris::WString dev |
| 40 | static 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 | |
| 49 | Iris::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 |
21 | 21 | #include "arch.hh" |
22 | 22 | |
23 | 23 | class 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 () |
27 | 55 | void check_sdmem () |
28 | 56 | void check_mmc () |
29 | 57 | public: |
... | ... | |
31 | 59 | void detect () |
32 | 60 | void release () |
33 | 61 | 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 | |
| 80 | bool 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 |
34 | 185 | |
35 | 186 | void 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 () |
36 | 192 | // Enable slow clock to msc. |
37 | 193 | CPM_MSCCDR = ~0 |
38 | 194 | cpm_start_msc () |
39 | 195 | // Enable msc pins. |
40 | 196 | gpio_as_msc () |
41 | 197 | // 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) |
46 | 202 | |
47 | 203 | // Stop the clock. |
48 | 204 | MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP |
49 | 205 | 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) |
51 | 214 | |
52 | 215 | // Initialize registers. |
53 | 216 | MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128 |
... | ... | |
55 | 218 | MSC_RDTO = ~0 |
56 | 219 | MSC_BLKLEN = 0x200 |
57 | 220 | 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) |
59 | 223 | MSC_ARG = 0 |
60 | 224 | |
61 | | // Reset controller and inserted devices. |
62 | | MSC_STRPCL = MSC_STRPCL_RESET |
63 | | while MSC_STAT & MSC_STAT_IS_RESETTING: |
64 | | Iris::schedule () |
65 | | |
66 | 225 | // Start the clock. |
67 | 226 | MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START |
68 | 227 | // Set cards, if any, to idle. |
69 | 228 | MSC_CMD = 0 |
70 | 229 | MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE |
| 230 | Iris::register_interrupt (IRQ_MSC) |
71 | 231 | msc_start_op () |
72 | | while !msc_ireg_end_cmd_res (): |
73 | | Iris::schedule () |
| 232 | Iris::wait_for_interrupt (IRQ_MSC) |
74 | 233 | msc_ireg_clear_end_cmd_res () |
75 | 234 | |
76 | 235 | // Reset SDIO device, if any. |
77 | 236 | MSC_CMD = 52 |
78 | 237 | MSC_ARG = 0x88000C08 |
79 | 238 | MSC_CMDAT = MSC_CMDAT_RESPONSE_R5 |
| 239 | Iris::register_interrupt (IRQ_MSC) |
80 | 240 | msc_start_op () |
81 | | while !msc_ireg_end_cmd_res (): |
82 | | Iris::schedule () |
| 241 | Iris::wait_for_interrupt (IRQ_MSC) |
83 | 242 | msc_ireg_clear_end_cmd_res () |
84 | 243 | |
85 | | bool 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 |
| 244 | void 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. |
98 | 253 | |
99 | 254 | void Mmc::check_sdmem (): |
| 255 | kdebug ("checking sdmem\n") |
| 256 | send (0, 0, NONE) |
100 | 257 | // 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55. |
101 | 258 | // 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 |
102 | 267 | // 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 |
103 | 271 | // 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.) |
104 | 272 | // 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") |
105 | 282 | // 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") |
106 | 285 | // 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response. |
107 | 286 | // 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 |
109 | 296 | |
110 | | void 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. |
| 297 | void 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 () |
119 | 326 | |
120 | 327 | void Mmc::detect (): |
121 | 328 | 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 () |
125 | 331 | 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") |
126 | 344 | |
127 | 345 | void Mmc::release (): |
128 | 346 | 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 |
130 | 352 | |
131 | 353 | void Mmc::interrupt (): |
132 | 354 | kdebug ("mmc interrupt\n") |
133 | 355 | |
| 356 | void 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 | |
| 380 | static Mmc mmc |
134 | 381 | |
135 | 382 | enum types: |
136 | 383 | DETECT |
... | ... | |
141 | 388 | map_gpio () |
142 | 389 | map_cpm () |
143 | 390 | |
144 | | Mmc mmc |
145 | 391 | mmc.reset () |
146 | 392 | |
147 | 393 | Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> () |
... | ... | |
178 | 424 | mmc.interrupt () |
179 | 425 | break |
180 | 426 | 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") |
182 | 455 | break |
183 | 456 | default: |
184 | 457 | Iris::panic (0, "unexpected request source for sd+mmc") |
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 | |
| 24 | class 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 | |
| 176 | Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 } |
| 177 | Udc::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 | } |
| 184 | Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } } |
| 185 | Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } } |
| 186 | Udc::String <16> Udc::s_product = { sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } } |
| 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 | |
| 197 | void 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 | |
| 249 | bool 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 | |
| 286 | void 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 | |
| 296 | bool 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 | |
| 340 | bool 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 | |
| 391 | void Udc::irq_usb (unsigned cmd): |
| 392 | // Reset. |
| 393 | state = IDLE |
| 394 | |
| 395 | void 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 | |
| 502 | void 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 | |
| 530 | void 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 | |
| 551 | void Udc::log (unsigned c): |
| 552 | if log_buffer_size >= sizeof (log_buffer): |
| 553 | return |
| 554 | log_buffer[log_buffer_size++] = c |
| 555 | |
| 556 | enum pdata: |
| 557 | LOG = 32 |
| 558 | FS |
| 559 | DATA |
| 560 | DIRECTORY |
| 561 | FILE |
| 562 | NAME |
| 563 | |
| 564 | Iris::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) |