| source/bootinit.ccp |
| 1 | 1 | #pypp 0 |
| 2 | 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> |
| 3 | // source/bootinit.ccp: Bootstrapping code. |
| 4 | // Copyright 2009-2010 Bas Wijnen <wijnen@debian.org> |
| 5 | 5 | // |
| 6 | 6 | // This program is free software: you can redistribute it and/or modify |
| 7 | 7 | // it under the terms of the GNU General Public License as published by |
| ... | ... | |
| 22 | 22 | |
| 23 | 23 | #define ELFRUN_NAME "elfrun.elf" |
| 24 | 24 | #define INIT_NAME "init.elf" |
| 25 | |
| 25 | 26 | #define NUM_SLOTS 8 |
| 26 | 27 | #define NUM_CAPS 32 |
| 27 | 28 | |
| ... | ... | |
| 45 | 46 | unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS |
| 46 | 47 | for unsigned p = 0; p < pages; ++p: |
| 47 | 48 | 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 | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 49 | 50 | Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS)) |
| 50 | 51 | Iris::free_cap (page) |
| 51 | 52 | _free += size |
| ... | ... | |
| 63 | 64 | |
| 64 | 65 | // Get the initial block device and filesystem. |
| 65 | 66 | 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: |
| 67 | Iris::String device |
| 68 | bool have_device = false |
| 69 | Iris::Cap reply[2] |
| 70 | bool have_reply[2] |
| 71 | have_reply[0] = false |
| 72 | have_reply[1] = false |
| 73 | unsigned next = 2 |
| 74 | while true: |
| 70 | 75 | 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 |
| 76 | kdebug_num (Iris::recv.protected_data.l, 1) |
| 77 | kdebug (": ") |
| 78 | if Iris::recv.protected_data.l == 0: |
| 79 | kdebug ("sd detect event device request\n") |
| 80 | // SD detection event device request. |
| 81 | // Ignore all; that will result in the driver thinking there is a card. |
| 82 | Iris::recv.reply.invoke () |
| 83 | continue |
| 84 | switch Iris::recv.data[0].l: |
| 85 | case Iris::Parent::PROVIDE_CAPABILITY: |
| 86 | switch Iris::recv.data[1].l: |
| 87 | case Iris::String::ID: |
| 88 | case Iris::WString::ID: |
| 89 | // Ignore other partitions. |
| 90 | Iris::Cap r = Iris::get_reply () |
| 91 | if Iris::recv.data[0].h != 0: |
| 92 | kdebug ("ignoring non-0 partition\n") |
| 93 | else: |
| 94 | if have_device: |
| 95 | Iris::panic (0, "double device provided") |
| 96 | device = Iris::get_arg () |
| 97 | if have_reply[next - 2]: |
| 98 | kdebug ("string provided (used)\n") |
| 99 | reply[next++ - 2].invoke (0, 0, device.copy ()) |
| 100 | Iris::free_cap (device) |
| 101 | else: |
| 102 | kdebug ("string provided (stored)\n") |
| 103 | have_device = true |
| 104 | r.invoke () |
| 105 | Iris::free_cap (r) |
| 106 | break |
| 107 | case Iris::Directory::ID: |
| 108 | kdebug ("directory provided\n") |
| 109 | Iris::Directory ret = Iris::get_arg () |
| 110 | Iris::recv.reply.invoke () |
| 111 | return ret |
| 112 | default: |
| 113 | Iris::panic (Iris::recv.data[1].l, "invalid capability type provided by boot thread") |
| 80 | 114 | break |
| 81 | | case Iris::Filesystem::ID: |
| 82 | | if have_fs: |
| 83 | | Iris::panic (0, "duplicate filesystem.") |
| 84 | | fs = Iris::get_arg () |
| 115 | case Iris::Parent::GET_CAPABILITY: |
| 116 | if Iris::recv.data[1].l == Iris::Event::ID: |
| 117 | kdebug ("event requested\n") |
| 118 | // Detection of sd card. |
| 119 | Iris::Cap reply = Iris::get_reply () |
| 120 | Iris::Cap event = Iris::my_receiver.create_capability (0) |
| 121 | reply.invoke (0, 0, event.copy ()) |
| 122 | Iris::free_cap (event) |
| 123 | Iris::free_cap (reply) |
| 124 | break |
| 125 | if Iris::recv.data[1].l != Iris::String::ID && Iris::recv.data[1].l != Iris::WString::ID: |
| 126 | Iris::panic (Iris::recv.data[1].l, "invalid capability type requested by boot thread") |
| 127 | if next == Iris::recv.protected_data.l && have_device: |
| 128 | kdebug ("string requested (sent)\n") |
| 129 | Iris::recv.reply.invoke (0, 0, device.copy ()) |
| 130 | Iris::free_cap (device) |
| 131 | have_device = false |
| 132 | ++next |
| 133 | else: |
| 134 | kdebug ("string requested (not sent)\n") |
| 135 | reply[Iris::recv.protected_data.l - 2] = Iris::get_reply () |
| 136 | have_reply[Iris::recv.protected_data.l - 2] = true |
| 137 | break |
| 138 | case Iris::Parent::INIT_DONE: |
| 139 | kdebug ("init done\n") |
| 140 | // Ignore. |
| 85 | 141 | Iris::recv.reply.invoke () |
| 86 | | have_fs = true |
| 87 | 142 | break |
| 143 | case Iris::Parent::EXIT: |
| 144 | Iris::panic (Iris::recv.protected_data.l, "boot thread exits") |
| 88 | 145 | 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 |
| 146 | Iris::panic (Iris::recv.protected_data.l, "invalid boot request") |
| 95 | 147 | |
| 96 | 148 | static bool stringcmp (char const *s1, char const *s2, unsigned size): |
| 97 | 149 | for unsigned t = 0; t < size; ++t: |
| ... | ... | |
| 137 | 189 | //kdebug ("\n") |
| 138 | 190 | Iris::set_recv_arg (Iris::Cap (slot, p)) |
| 139 | 191 | Iris::my_memory.create_page () |
| 140 | | Iris::Page (slot, p).set_flags (Iris::Page::PAYING, Iris::Page::PAYING) |
| 192 | Iris::Page (slot, p).set_flags (Iris::Page::PAYING) |
| 141 | 193 | data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, Iris::Cap (slot, p)) |
| 142 | 194 | Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS]) |
| 143 | 195 | Iris::Thread thread = mem.create_thread (NUM_SLOTS) |
| ... | ... | |
| 190 | 242 | f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY |
| 191 | 243 | else: |
| 192 | 244 | f = Iris::Page::PAYING |
| 193 | | page.set_flags (f, f) |
| 245 | page.set_flags (f) |
| 194 | 246 | Iris::Page (slot, idx).share (page, 0) |
| 195 | 247 | //kdebug ("mapping at ") |
| 196 | 248 | //kdebug_num (p) |
| ... | ... | |
| 222 | 274 | page = mem.create_page () |
| 223 | 275 | if Iris::recv.data[0].l != Iris::NO_ERROR: |
| 224 | 276 | 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): |
| 277 | if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME): |
| 226 | 278 | Iris::panic (0, "out of memory") |
| 227 | 279 | if !mem.map (page, p): |
| 228 | 280 | Iris::panic (0, "unable to map bss page") |
| ... | ... | |
| 232 | 284 | Iris::my_memory.destroy (pages_caps) |
| 233 | 285 | Iris::free_slot (slot) |
| 234 | 286 | Iris::Page stackpage = mem.create_page () |
| 235 | | stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME) |
| 287 | stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 236 | 288 | if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000): |
| 237 | 289 | Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page") |
| 238 | 290 | Iris::free_cap (stackpage) |
| source/buffer.ccp |
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // source/buffer.ccp: block device buffer. |
| 4 | // Copyright 2010 Bas Wijnen <wijnen@debian.org> |
| 5 | // |
| 6 | // This program is free software: you can redistribute it and/or modify |
| 7 | // it under the terms of the GNU General Public License as published by |
| 8 | // the Free Software Foundation, either version 3 of the License, or |
| 9 | // (at your option) any later version. |
| 10 | // |
| 11 | // This program is distributed in the hope that it will be useful, |
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | // GNU General Public License for more details. |
| 15 | // |
| 16 | // You should have received a copy of the GNU General Public License |
| 17 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | |
| 19 | #include "iris.hh" |
| 20 | #include "devices.hh" |
| 21 | |
| 22 | static unsigned align |
| 23 | static Iris::Page page, rpage |
| 24 | static unsigned mapping, rmapping |
| 25 | static Iris::Num size, current |
| 26 | static Iris::String dev |
| 27 | |
| 28 | static void read_block (Iris::Num idx): |
| 29 | idx = idx.value () & PAGE_MASK |
| 30 | if idx.value () == current.value (): |
| 31 | return |
| 32 | //kdebug ("buffering block ") |
| 33 | //kdebug_num (idx.h) |
| 34 | //kdebug (":") |
| 35 | //kdebug_num (idx.l) |
| 36 | //kdebug ("\n") |
| 37 | dev.get_block (idx, PAGE_SIZE, 0, page) |
| 38 | //kdebug ("buffered\n") |
| 39 | current = idx |
| 40 | |
| 41 | Iris::Num start (): |
| 42 | dev = Iris::my_parent.get_capability <Iris::WString> () |
| 43 | align = dev.get_align_bits () |
| 44 | size = dev.get_size () |
| 45 | if align > PAGE_BITS: |
| 46 | Iris::panic (align, "invalid alignment value for block device") |
| 47 | page = Iris::my_memory.create_page () |
| 48 | rpage = Iris::my_memory.create_page () |
| 49 | page.set_flags (Iris::Page::PAYING) |
| 50 | rpage.set_flags (Iris::Page::PAYING) |
| 51 | mapping = 0x15000 |
| 52 | rmapping = 0x17000 |
| 53 | Iris::my_memory.map (page, mapping) |
| 54 | Iris::my_memory.map (rpage, rmapping) |
| 55 | current.h = ~0 |
| 56 | current.l = ~0 |
| 57 | Iris::Cap cap = Iris::my_receiver.create_capability (0) |
| 58 | Iris::my_parent.provide_capability <Iris::WString> (cap.copy ()) |
| 59 | Iris::free_cap (cap) |
| 60 | Iris::my_parent.init_done () |
| 61 | while true: |
| 62 | Iris::wait () |
| 63 | switch Iris::recv.data[0].l: |
| 64 | case Iris::String::GET_SIZE: |
| 65 | Iris::recv.reply.invoke (size) |
| 66 | break |
| 67 | case Iris::String::GET_ALIGN_BITS: |
| 68 | // Use 16 byte alignment to make implementing GET_CHARS easier. |
| 69 | Iris::recv.reply.invoke (4) |
| 70 | break |
| 71 | case Iris::String::GET_CHARS: |
| 72 | Iris::Cap reply = Iris::get_reply () |
| 73 | unsigned offset = Iris::recv.data[1].l & ~PAGE_MASK & ~((1 << 4) - 1) |
| 74 | read_block (Iris::recv.data[1]) |
| 75 | unsigned *data = (unsigned *)((char *)mapping)[offset] |
| 76 | reply.invoke (Iris::Num (data[0], data[1]), Iris::Num (data[2], data[3])) |
| 77 | Iris::free_cap (reply) |
| 78 | break |
| 79 | case Iris::String::GET_BLOCK: |
| 80 | Iris::Cap reply = Iris::get_reply () |
| 81 | Iris::Page arg = Iris::get_arg () |
| 82 | unsigned offset = Iris::recv.data[1].l & ~PAGE_MASK & ~((1 << 4) - 1) |
| 83 | unsigned sz = Iris::recv.data[0].h >> 16 |
| 84 | unsigned roffset = Iris::recv.data[0].h & 0xffff |
| 85 | Iris::Num idx = Iris::recv.data[1] |
| 86 | arg.set_flags (Iris::Page::FRAME | Iris::Page::PAYING) |
| 87 | arg.share (rpage) |
| 88 | rpage.set_flags (Iris::Page::FRAME) |
| 89 | read_block (idx) |
| 90 | for unsigned i = 0; i < sz; ++i: |
| 91 | ((char *)rmapping)[roffset + i] = ((char *)mapping)[offset + i] |
| 92 | rpage.set_flags (0, Iris::Page::FRAME) |
| 93 | reply.invoke () |
| 94 | Iris::free_cap (reply) |
| 95 | Iris::free_cap (arg) |
| 96 | break |
| 97 | default: |
| 98 | Iris::panic (Iris::recv.data[0].l, "invalid request for buffer") |
| source/fat.ccp |
| 26 | 26 | unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS |
| 27 | 27 | for unsigned p = 0; p < pages; ++p: |
| 28 | 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) |
| 29 | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 30 | 30 | Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS)) |
| 31 | 31 | Iris::free_cap (page) |
| 32 | 32 | _free += size |
| ... | ... | |
| 147 | 147 | return ret |
| 148 | 148 | |
| 149 | 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) |
| 150 | //unsigned b = current_block.l |
| 151 | read_block ((reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits) |
| 152 | //if b != current_block.l: |
| 153 | //for unsigned i = 0; i < 0x20; ++i: |
| 154 | //kdebug (" ") |
| 155 | //kdebug_num (data[i], 2) |
| 156 | //kdebug ("\n") |
| 151 | 157 | |
| 152 | 158 | unsigned make_bits (unsigned orig): |
| 153 | 159 | unsigned ret |
| 154 | 160 | for ret = 0; ret < 32; ++ret: |
| 155 | 161 | if orig == 1 << ret: |
| 156 | 162 | return ret |
| 157 | | Iris::panic (ret, "non-power of 2") |
| 158 | | return ret |
| 163 | //Iris::panic (orig, "non-power of 2") |
| 164 | kdebug ("not a power of two, using 16\n") |
| 165 | return 16 |
| 159 | 166 | |
| 160 | 167 | void reset (): |
| 161 | 168 | read_block (0) |
| ... | ... | |
| 182 | 189 | kdebug ("warning: limiting sectors because of limited device size\n") |
| 183 | 190 | |
| 184 | 191 | 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 |
| 192 | header_sectors = reserved_sectors + sectors_per_fat * num_fats + root_sectors |
| 186 | 193 | clusters = (sectors - header_sectors) >> sectors_per_cluster_bits |
| 187 | 194 | unsigned skip |
| 188 | 195 | if clusters >= 65525: |
| ... | ... | |
| 254 | 261 | bad_clusters = 0 |
| 255 | 262 | fat = new unsigned[clusters] |
| 256 | 263 | unsigned counted_free_clusters = 0 |
| 264 | first_free_cluster = ~0 |
| 257 | 265 | for unsigned c = 0; c < clusters; ++c: |
| 258 | 266 | // reduced cluster. |
| 259 | 267 | unsigned rc = c & (1 << sector_size_bits) - 1 |
| ... | ... | |
| 288 | 296 | else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff: |
| 289 | 297 | // Last cluster in chain. |
| 290 | 298 | fat[c] = ~0 |
| 299 | kdebug ("last cluster: ") |
| 300 | kdebug_num (c) |
| 301 | kdebug ("\n") |
| 291 | 302 | else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7: |
| 292 | 303 | // Bad cluster. |
| 293 | 304 | fat[c] = first_bad_cluster |
| ... | ... | |
| 296 | 307 | else: |
| 297 | 308 | // Non-last cluster in chain. |
| 298 | 309 | fat[c] -= 2 |
| 310 | kdebug_num (c) |
| 311 | kdebug (" -> ") |
| 312 | kdebug_num (fat[c]) |
| 313 | kdebug ("\n") |
| 299 | 314 | unsigned fat_lookup (unsigned first_cluster, unsigned cluster): |
| 315 | //kdebug ("looking up ") |
| 316 | //kdebug_num (first_cluster) |
| 317 | //kdebug ("+") |
| 318 | //kdebug_num (cluster) |
| 319 | //kdebug (":") |
| 300 | 320 | while cluster--: |
| 301 | 321 | first_cluster = fat[first_cluster] |
| 322 | //kdebug ("->") |
| 323 | //kdebug_num (first_cluster) |
| 302 | 324 | if first_cluster == ~0: |
| 303 | | kdebug ("sector beyond end of file requested\n") |
| 325 | //kdebug ("sector beyond end of file requested\n") |
| 304 | 326 | return ~0 |
| 327 | //kdebug ("\n") |
| 305 | 328 | return first_cluster |
| 306 | 329 | struct File: |
| 307 | 330 | Fat *fat |
| ... | ... | |
| 310 | 333 | char name[11] |
| 311 | 334 | bool archive, readonly, system, hidden, directory, volume |
| 312 | 335 | unsigned create_second, create_minute_hour, create_date, access_date, time, date |
| 336 | unsigned checksum |
| 313 | 337 | void load_cluster (unsigned idx, Iris::Page p = page, unsigned offset = 0): |
| 314 | 338 | 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") |
| 339 | //kdebug ("loading cluster ") |
| 340 | //kdebug_num (idx) |
| 341 | //kdebug ("@") |
| 342 | //kdebug_num (cluster) |
| 343 | //kdebug (" from file\n") |
| 320 | 344 | if cluster == ~0: |
| 321 | 345 | kdebug ("invalid cluster requested from file\n") |
| 322 | 346 | return |
| 323 | 347 | 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 |
| 348 | //kdebug ("sector ") |
| 349 | //kdebug_num (fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) |
| 350 | //kdebug ("\n") |
| 351 | char *load_dir_entry (unsigned dir, unsigned idx): |
| 329 | 352 | unsigned sector = idx >> (sector_size_bits - 5) |
| 330 | 353 | unsigned num = (idx << 5) & ~BLOCK_MASK |
| 331 | 354 | Iris::Num hwsector |
| ... | ... | |
| 333 | 356 | if sector < root_sectors: |
| 334 | 357 | hwsector = header_sectors - root_sectors + sector |
| 335 | 358 | else: |
| 336 | | hwsector = ~0 |
| 359 | return NULL |
| 337 | 360 | else: |
| 338 | 361 | unsigned entry = fat_lookup (dir, sector) |
| 339 | 362 | 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 |
| 363 | return NULL |
| 364 | hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits) |
| 347 | 365 | read_block (hwsector.value () << sector_size_bits) |
| 348 | | char *e = &data[num] |
| 366 | return &data[num] |
| 367 | char *find_idx (unsigned dir, unsigned *idx, unsigned *count = NULL): |
| 368 | unsigned todo = *idx + 1 |
| 369 | char *e |
| 370 | if count: |
| 371 | *count = 0 |
| 372 | for *idx = 0; todo; ++*idx: |
| 373 | e = load_dir_entry (dir, *idx) |
| 374 | if !e: |
| 375 | return NULL |
| 376 | if (e[0xb] & 0xff) == 0xf: |
| 377 | // This is part of a long filename. |
| 378 | continue |
| 379 | if (e[0] & 0xff) == 0xe5: |
| 380 | // This is a deleted file. |
| 381 | continue |
| 382 | if !e[0]: |
| 383 | // This is a free entry. |
| 384 | continue |
| 385 | if count: |
| 386 | ++*count |
| 387 | --todo |
| 388 | --*idx |
| 389 | return e |
| 390 | unsigned get_dir_size (unsigned dir): |
| 391 | unsigned num = 0 - 2 |
| 392 | unsigned ret |
| 393 | find_idx (dir, &num, &ret) |
| 394 | return ret |
| 395 | bool get_dir_entry (unsigned dir, unsigned idx, File *f): |
| 396 | char *e = load_dir_entry (dir, idx) |
| 397 | if !e: |
| 398 | kdebug ("unable to load dir entry\n") |
| 399 | return false |
| 400 | f->fat = this |
| 349 | 401 | for unsigned i = 0; i < 11; ++i: |
| 350 | 402 | f->name[i] = e[i] |
| 351 | | f->archive = e[0xb] & 0x20 |
| 352 | | f->readonly = e[0xb] & 0x10 |
| 353 | | f->system = e[0xb] & 0x8 |
| 403 | f->readonly = e[0xb] & 0x1 |
| 404 | f->system = e[0xb] & 0x2 |
| 354 | 405 | f->hidden = e[0xb] & 0x4 |
| 355 | | f->directory = e[0xb] & 0x2 |
| 356 | | f->volume = e[0xb] & 0x1 |
| 406 | f->volume = e[0xb] & 0x8 |
| 407 | f->directory = e[0xb] & 0x10 |
| 408 | f->archive = e[0xb] & 0x20 |
| 357 | 409 | f->create_second = read_num (e + 0xd, 1) |
| 358 | 410 | f->create_minute_hour = read_num (e + 0xe, 2) |
| 359 | 411 | f->create_date = read_num (e + 0x10, 2) |
| ... | ... | |
| 362 | 414 | f->date = read_num (e + 0x18, 1) |
| 363 | 415 | f->size = read_num (e + 0x1c, 4) |
| 364 | 416 | f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2 |
| 417 | f->checksum = 0 |
| 418 | for unsigned i = 0; i < 11; ++i: |
| 419 | f->checksum = ((((f->checksum & 1) << 7) | ((f->checksum & 0xfe) >> 1)) + f->name[i]) & 0xff |
| 420 | //kdebug ("loaded dir entry, first cluster = ") |
| 421 | //kdebug_num (f->first_cluster) |
| 422 | //kdebug ("\n") |
| 423 | return true |
| 424 | struct LFN: |
| 425 | unsigned ordinal |
| 426 | unsigned name[13] |
| 427 | unsigned checksum |
| 428 | bool load_lfn (unsigned dir, unsigned idx, unsigned t, unsigned checksum, LFN *lfn): |
| 429 | if t >= idx: |
| 430 | return false |
| 431 | char *e = load_dir_entry (dir, idx - t - 1) |
| 432 | if (e[0xb] & 0xff) != 0xf: |
| 433 | return false |
| 434 | lfn->ordinal = read_num (e + 0x00, 1) |
| 435 | for unsigned i = 0; i < 5; ++i: |
| 436 | lfn->name[i] = read_num (e + 0x01 + 2 * i, 2) |
| 437 | lfn->checksum = read_num (e + 0xd, 1) |
| 438 | for unsigned i = 0; i < 6; ++i: |
| 439 | lfn->name[i + 5] = read_num (e + 0xe + 2 * i, 2) |
| 440 | for unsigned i = 0; i < 2; ++i: |
| 441 | lfn->name[i + 11] = read_num (e + 0x1c + 2 * i, 2) |
| 442 | return true |
| 443 | unsigned parse_shortname (File const &f, char *name): |
| 444 | if f.name[0] == ' ': |
| 445 | Iris::panic (0, "fat name starts with space") |
| 446 | unsigned len = 8 |
| 447 | while f.name[len - 1] == ' ': |
| 448 | --len |
| 449 | char *ptr = name |
| 450 | for unsigned i = 0; i < len; ++i: |
| 451 | *ptr++ = f.name[i] |
| 452 | if f.name[8] == ' ': |
| 453 | return len |
| 454 | *ptr++ = '.' |
| 455 | len = 3 |
| 456 | while f.name[8 + len - 1] == ' ': |
| 457 | --len |
| 458 | for unsigned i = 0; i < len; ++i: |
| 459 | *ptr++ = f.name[8 + i] |
| 460 | return ptr - name |
| 461 | unsigned get_name_size (unsigned dir, unsigned idx, File const &f): |
| 462 | LFN lfn |
| 463 | unsigned num = 0 |
| 464 | if !load_lfn (dir, idx, 0, f.checksum, &lfn): |
| 465 | // Not a long filename. |
| 466 | char n[12] |
| 467 | return parse_shortname (f, n) |
| 468 | unsigned ordinal = 0 |
| 469 | while true: |
| 470 | if !load_lfn (dir, idx, num, f.checksum, &lfn): |
| 471 | Iris::panic (0, "error parsing long filename") |
| 472 | if (lfn.ordinal & 0x3f) != ++ordinal: |
| 473 | Iris::panic (lfn.ordinal, "error in sequence for long filename") |
| 474 | if lfn.ordinal & 0x40: |
| 475 | break |
| 476 | ++num |
| 477 | unsigned i |
| 478 | for i = 0; i < 13; ++i: |
| 479 | if !lfn.name[i]: |
| 480 | break |
| 481 | return num * 13 + i |
| 365 | 482 | |
| 366 | 483 | // Capability encoding. |
| 367 | 484 | // 0:ROOT_CLUSTER = non fat-32 root directory. |
| ... | ... | |
| 379 | 496 | device_size = dev.get_size () |
| 380 | 497 | data = (char *)0x15000; //alloc_space (1) |
| 381 | 498 | page = Iris::my_memory.create_page () |
| 382 | | page.set_flags (Iris::Page::PAYING, Iris::Page::PAYING) |
| 499 | page.set_flags (Iris::Page::PAYING) |
| 383 | 500 | Iris::my_memory.map (page, (unsigned)data) |
| 384 | 501 | |
| 385 | 502 | Fat fat |
| ... | ... | |
| 400 | 517 | Iris::wait () |
| 401 | 518 | unsigned dir = Iris::recv.protected_data.h |
| 402 | 519 | if dir & 0x80000000: |
| 520 | dir &= ~0x80000000 |
| 403 | 521 | // File name. |
| 404 | 522 | unsigned idx = Iris::recv.protected_data.l |
| 405 | 523 | Iris::Cap reply = Iris::get_reply () |
| ... | ... | |
| 407 | 525 | unsigned size = Iris::recv.data[0].h >> 16 |
| 408 | 526 | unsigned cmd = Iris::recv.data[0].l |
| 409 | 527 | Fat::File f |
| 410 | | fat.get_dir_entry (dir & ~0x80000000, idx, &f) |
| 528 | if !fat.find_idx (dir, &idx): |
| 529 | Iris::panic (Iris::recv.protected_data.l, "invalid index") |
| 530 | if !fat.get_dir_entry (dir, idx, &f): |
| 531 | Iris::panic (Iris::recv.protected_data.l, "invalid dir entry requested for filename") |
| 411 | 532 | switch cmd: |
| 412 | 533 | case Iris::String::GET_SIZE: |
| 413 | | kdebug ("filename size requested\n") |
| 414 | | reply.invoke (11) |
| 534 | //kdebug ("filename size requested\n") |
| 535 | reply.invoke (fat.get_name_size (dir, idx, f)) |
| 415 | 536 | break |
| 416 | 537 | case Iris::String::GET_CHARS: |
| 417 | 538 | //kdebug ("filename chars requested\n") |
| 539 | //kdebug ("flags: ") |
| 540 | //kdebug_char (f.readonly ? 'R' : 'r') |
| 541 | //kdebug_char (f.system ? 'S' : 's') |
| 542 | //kdebug_char (f.hidden ? 'H' : 'h') |
| 543 | //kdebug_char (f.volume ? 'V' : 'v') |
| 544 | //kdebug_char (f.directory ? 'D' : 'd') |
| 545 | //kdebug_char (f.archive ? 'A' : 'a') |
| 546 | //kdebug_char ('\n') |
| 547 | |
| 418 | 548 | /**/union { unsigned u[4]; char c[16]; } u |
| 419 | 549 | for unsigned k = 0; k < 4; ++k: |
| 420 | 550 | u.u[k] = 0 |
| 421 | | for unsigned k = 0; k + num < 11; ++k: |
| 422 | | u.c[k] = f.name[k + num] |
| 551 | Fat::LFN lfn |
| 552 | if !fat.load_lfn (dir, idx, 0, f.checksum, &lfn): |
| 553 | // Not a long filename. |
| 554 | char n[12] |
| 555 | unsigned len = fat.parse_shortname (f, n) |
| 556 | //kdebug ("short filename: ") |
| 557 | for unsigned k = 0; k + num < len; ++k: |
| 558 | u.c[k] = n[k + num] |
| 559 | //kdebug_char (u.c[k]) |
| 560 | //kdebug ("\n") |
| 561 | else: |
| 562 | // Very inefficient, but it works: reload everything for every character. |
| 563 | //kdebug ("filename: ") |
| 564 | for unsigned c = 0; c < 16; ++c: |
| 565 | if !fat.load_lfn (dir, idx, (num + c) / 13, f.checksum, &lfn): |
| 566 | // Filename isn't this long: keep the rest at 0. |
| 567 | break |
| 568 | u.c[c] = lfn.name[(num + c) % 13] |
| 569 | if u.c[c] == 0: |
| 570 | break |
| 571 | //kdebug_char (u.c[c]) |
| 572 | //kdebug ("\n") |
| 423 | 573 | reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3])) |
| 424 | 574 | break |
| 425 | 575 | case Iris::String::GET_ALIGN_BITS: |
| 426 | | kdebug ("filename align requested\n") |
| 576 | //kdebug ("filename align requested\n") |
| 427 | 577 | reply.invoke (0) |
| 428 | 578 | break |
| 429 | 579 | case Iris::String::GET_BLOCK: |
| ... | ... | |
| 431 | 581 | Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename") |
| 432 | 582 | Iris::free_cap (reply) |
| 433 | 583 | else if dir: |
| 434 | | // File. |
| 584 | // If it *has* a directory, it *is* a file. |
| 435 | 585 | unsigned idx = Iris::recv.protected_data.l |
| 436 | 586 | Iris::Cap reply = Iris::get_reply () |
| 437 | 587 | Iris::Cap arg = Iris::get_arg () |
| ... | ... | |
| 439 | 589 | unsigned size = Iris::recv.data[0].h >> 16 |
| 440 | 590 | unsigned offset = Iris::recv.data[0].h & 0xffff |
| 441 | 591 | unsigned cmd = Iris::recv.data[0].l |
| 592 | if !fat.find_idx (dir, &idx): |
| 593 | Iris::panic (0, "file not found") |
| 442 | 594 | Fat::File f |
| 443 | 595 | fat.get_dir_entry (dir, idx, &f) |
| 444 | 596 | switch cmd: |
| 445 | 597 | case Iris::String::GET_SIZE: |
| 446 | | kdebug ("file size requested\n") |
| 598 | //kdebug ("file size requested\n") |
| 447 | 599 | reply.invoke (f.size) |
| 448 | 600 | break |
| 449 | 601 | case Iris::String::GET_CHARS: |
| 450 | | kdebug ("file chars requested\n") |
| 602 | //kdebug ("file chars requested\n") |
| 451 | 603 | unsigned mask = 1 << (fat.cluster_size_bits) - 1 |
| 452 | 604 | f.load_cluster (num.l & ~mask) |
| 453 | 605 | unsigned n = num.l & mask & ~0xf |
| ... | ... | |
| 455 | 607 | reply.invoke (Iris::Num (dat[0], dat[1]), Iris::Num (dat[2], dat[3])) |
| 456 | 608 | break |
| 457 | 609 | case Iris::String::GET_ALIGN_BITS: |
| 458 | | kdebug ("file align requested\n") |
| 610 | //kdebug ("file align requested\n") |
| 459 | 611 | reply.invoke (fat.cluster_size_bits) |
| 460 | 612 | break |
| 461 | 613 | case Iris::String::GET_BLOCK: |
| 462 | | kdebug ("file block requested\n") |
| 614 | //kdebug ("file block requested\n") |
| 463 | 615 | unsigned mask = 1 << (fat.cluster_size_bits) - 1 |
| 464 | 616 | if offset > PAGE_SIZE: |
| 465 | | kdebug ("invalid offset requested\n") |
| 617 | //kdebug ("invalid offset requested\n") |
| 466 | 618 | break |
| 467 | 619 | if size + offset > PAGE_SIZE: |
| 468 | 620 | size = PAGE_SIZE - offset |
| ... | ... | |
| 480 | 632 | Iris::free_cap (arg) |
| 481 | 633 | else: |
| 482 | 634 | // 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 |
| 635 | switch Iris::recv.data[0].l: |
| 636 | case Iris::Directory::GET_SIZE: |
| 637 | //kdebug ("dir size requested\n") |
| 638 | Iris::Cap reply = Iris::get_reply () |
| 639 | reply.invoke (fat.get_dir_size (Iris::recv.protected_data.l)) |
| 640 | Iris::free_cap (reply) |
| 641 | break |
| 642 | case Iris::Directory::GET_NAME: |
| 643 | //kdebug ("dir name requested\n") |
| 644 | Iris::Cap reply = Iris::get_reply () |
| 645 | Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000)) |
| 646 | reply.invoke (0, 0, ret.copy ()) |
| 647 | Iris::free_cap (reply) |
| 648 | Iris::free_cap (ret) |
| 649 | break |
| 650 | case Iris::Directory::GET_FILE_RO: |
| 651 | //kdebug ("dir file requested\n") |
| 652 | Iris::Cap reply = Iris::get_reply () |
| 653 | dir = Iris::recv.protected_data.l |
| 654 | unsigned idx = Iris::recv.data[1].l |
| 655 | if !fat.find_idx (dir, &idx): |
| 656 | Iris::panic (0, "file not found") |
| 657 | Fat::File f |
| 658 | fat.get_dir_entry (dir, idx, &f) |
| 659 | Iris::Cap ret |
| 660 | if f.directory: |
| 661 | ret = Iris::my_receiver.create_capability (Iris::Num (f.first_cluster, 0)) |
| 662 | else: |
| 663 | ret = Iris::my_receiver.create_capability (Iris::Num (idx, dir)) |
| 664 | reply.invoke (0, 0, ret.copy ()) |
| 665 | Iris::free_cap (reply) |
| 666 | Iris::free_cap (ret) |
| 667 | break |
| 668 | case Iris::Directory::GET_FILE_INFO: |
| 669 | //kdebug ("dir file info requested\n") |
| 670 | Iris::Cap reply = Iris::get_reply () |
| 671 | dir = Iris::recv.protected_data.l |
| 672 | unsigned idx = Iris::recv.data[1].l |
| 673 | if !fat.find_idx (dir, &idx): |
| 674 | Iris::panic (0, "file not found") |
| 675 | unsigned type = Iris::recv.data[0].h |
| 676 | Fat::File f |
| 677 | fat.get_dir_entry (dir, idx, &f) |
| 678 | reply.invoke (f.directory ? 1 : 0) |
| 679 | Iris::free_cap (reply) |
| 680 | break |
| 681 | case Iris::Directory::LOCK_RO: |
| 682 | case Iris::Directory::UNLOCK_RO: |
| 683 | //kdebug ("dir lock or unlock requested\n") |
| 684 | Iris::recv.reply.invoke () |
| 685 | break |
| 686 | default: |
| 687 | //kdebug ("invalid dir operation requested\n") |
| 688 | Iris::recv.reply.invoke () |
| 689 | break |
| source/sd+mmc.ccp |
| 66 | 66 | unsigned get_read_block_size (): |
| 67 | 67 | return read_block_size |
| 68 | 68 | unsigned get_block_bits (): |
| 69 | | return csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len |
| 69 | return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len |
| 70 | 70 | void fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset) |
| 71 | 71 | private: |
| 72 | 72 | unsigned rca |
| 73 | 73 | bool have_sdmem, have_io |
| 74 | bool hc |
| 74 | 75 | CID cid |
| 75 | 76 | CSD csd |
| 76 | 77 | unsigned num_blocks, read_block_size |
| ... | ... | |
| 94 | 95 | Iris::panic (0, "crc error in mmc response") |
| 95 | 96 | return false |
| 96 | 97 | if stat & MSC_STAT_TIME_OUT_RES: |
| 97 | | //kdebug ("time out waiting for mmc response\n") |
| 98 | kdebug ("time out waiting for mmc response\n") |
| 99 | MSC_IREG = MSC_IREG_END_CMD_RES |
| 98 | 100 | return false |
| 99 | 101 | if response_type == R2: |
| 100 | 102 | unsigned d = MSC_RES |
| ... | ... | |
| 161 | 163 | // 1 0.1 15.4 |
| 162 | 164 | csd.tmp_write_protect = d & 0x10 |
| 163 | 165 | // Ignore file_format. 2 (+ 2) 0.4 16.0 *** |
| 164 | | read_block_size = 1 << csd.read_bl_len |
| 166 | read_block_size = hc ? 512 : 1 << csd.read_bl_len |
| 165 | 167 | num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2) |
| 168 | if hc: |
| 169 | if csd.read_bl_len < 9: |
| 170 | num_blocks >>= 9 - csd.read_bl_len |
| 171 | else: |
| 172 | num_blocks <<= csd.read_bl_len - 9 |
| 166 | 173 | else if response_type != NONE: |
| 167 | 174 | unsigned r = MSC_RES |
| 168 | 175 | if response_type == R3: |
| 169 | 176 | if r >> 8 != 0x3f: |
| 170 | 177 | Iris::panic (r, "r3 response was not 3f") |
| 171 | 178 | else if r >> 8 != cmd: |
| 179 | kdebug ("stat: ") |
| 180 | kdebug_num (MSC_STAT) |
| 172 | 181 | Iris::panic (r, "response doesn't match command") |
| 173 | 182 | r <<= 24 |
| 174 | 183 | r |= MSC_RES << 8 |
| 175 | 184 | r |= MSC_RES & 0xff |
| 176 | 185 | if response: |
| 177 | 186 | *response = r |
| 187 | else: |
| 178 | 188 | //kdebug ("extra response fifo read: ") |
| 179 | 189 | //for unsigned i = 0; i < 9; ++i: |
| 180 | 190 | //kdebug (" ") |
| ... | ... | |
| 225 | 235 | // Start the clock. |
| 226 | 236 | MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START |
| 227 | 237 | // Set cards, if any, to idle. |
| 228 | | MSC_CMD = 0 |
| 229 | | MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE |
| 230 | | Iris::register_interrupt (IRQ_MSC) |
| 231 | | msc_start_op () |
| 232 | | Iris::wait_for_interrupt (IRQ_MSC) |
| 233 | | msc_ireg_clear_end_cmd_res () |
| 238 | send (0, 0, NONE) |
| 234 | 239 | |
| 235 | 240 | // Reset SDIO device, if any. |
| 236 | | MSC_CMD = 52 |
| 237 | | MSC_ARG = 0x88000C08 |
| 238 | | MSC_CMDAT = MSC_CMDAT_RESPONSE_R5 |
| 239 | | Iris::register_interrupt (IRQ_MSC) |
| 240 | | msc_start_op () |
| 241 | | Iris::wait_for_interrupt (IRQ_MSC) |
| 242 | | msc_ireg_clear_end_cmd_res () |
| 241 | send (52, 0x88000c08, R5) |
| 243 | 242 | |
| 244 | 243 | void Mmc::check_mmc (): |
| 245 | 244 | //kdebug ("checking mmc\n") |
| ... | ... | |
| 253 | 252 | |
| 254 | 253 | void Mmc::check_sdmem (): |
| 255 | 254 | kdebug ("checking sdmem\n") |
| 256 | | send (0, 0, NONE) |
| 257 | 255 | // 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55. |
| 258 | 256 | // 3. If the response is correct (CMD55 has response), then continue, else go to check MMC. |
| 259 | 257 | unsigned code |
| 260 | | bool hc = false |
| 258 | hc = false |
| 261 | 259 | if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa: |
| 262 | 260 | kdebug ("hc\n") |
| 263 | 261 | hc = true |
| ... | ... | |
| 357 | 355 | if address.h: |
| 358 | 356 | Iris::panic (0, "page too high: not supported") |
| 359 | 357 | return |
| 360 | | unsigned blockmask = ~((1 << get_block_bits ()) - 1) |
| 358 | //kdebug ("smc get page ") |
| 359 | //kdebug_num (address.l) |
| 360 | //kdebug ("+") |
| 361 | //kdebug_num (size) |
| 362 | //kdebug ("@") |
| 363 | //kdebug_num (offset) |
| 364 | //kdebug ("\n") |
| 365 | unsigned blockmask = ~((1 << 9) - 1) |
| 361 | 366 | unsigned p = address.l & blockmask |
| 362 | 367 | size &= blockmask |
| 363 | 368 | offset &= ~PAGE_MASK |
| 364 | 369 | if size + offset > PAGE_SIZE: |
| 365 | 370 | size = PAGE_SIZE - offset |
| 366 | | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME) |
| 371 | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 367 | 372 | page.share (buffer_page) |
| 368 | | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME) |
| 373 | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 369 | 374 | MSC_NOB = 1 |
| 370 | | MSC_BLKLEN = read_block_size |
| 371 | | for unsigned a = 0; a < size; a += 1 << get_block_bits (): |
| 375 | MSC_BLKLEN = 1 << 9 |
| 376 | for unsigned a = 0; a < size; a += 1 << 9: |
| 377 | //kdebug_num (a) |
| 378 | //kdebug ("/") |
| 379 | //kdebug_num (size) |
| 380 | //kdebug (" ==> ") |
| 372 | 381 | if !send (17, p + a, DATA): |
| 373 | 382 | 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) |
| 383 | for unsigned aa = 0; aa < 1 << 9; aa += 4: |
| 384 | while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY: |
| 385 | Iris::register_interrupt (IRQ_MSC) |
| 386 | Iris::wait_for_interrupt (IRQ_MSC) |
| 377 | 387 | *(unsigned *)(buffer + a + aa + offset) = MSC_RXFIFO |
| 388 | //unsigned d = *(unsigned *)(buffer + a + aa + offset) |
| 389 | //if (aa & 0x3f) == 0: |
| 390 | //kdebug ("\n") |
| 391 | //for unsigned i = 0; i < 4; ++i: |
| 392 | //kdebug (" ") |
| 393 | //kdebug_num (d >> (8 * i), 2) |
| 394 | //kdebug ("\n") |
| 378 | 395 | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
| 396 | //kdebug ("done filling page\n") |
| 379 | 397 | |
| 380 | 398 | static Mmc mmc |
| 381 | 399 | |
| ... | ... | |
| 436 | 454 | Iris::panic (0, "get chars from mmc not supported yet") |
| 437 | 455 | break |
| 438 | 456 | case Iris::String::GET_ALIGN_BITS: |
| 439 | | Iris::recv.reply.invoke (mmc.get_block_bits ()) |
| 457 | Iris::recv.reply.invoke (9) |
| 440 | 458 | break |
| 441 | 459 | case Iris::String::GET_BLOCK: |
| 442 | 460 | Iris::Cap reply = Iris::get_reply () |