source/boot.ccp |
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // source/boot.ccp: Boot into another kernel. |
| 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 | extern "C": |
| 23 | extern unsigned pre_code, pre_end, post_code, post_end |
| 24 | |
| 25 | struct args_t: |
| 26 | unsigned load |
| 27 | unsigned size |
| 28 | unsigned entry |
| 29 | unsigned source |
| 30 | |
| 31 | Iris::Num start (): |
| 32 | unsigned *loader_addr = (unsigned *)0x15000 |
| 33 | unsigned *page_addr = (unsigned *)0x16000 |
| 34 | unsigned *tmp_addr = (unsigned *)0x17000 |
| 35 | Iris::Boot cap = Iris::my_receiver.create_capability (0) |
| 36 | Iris::my_parent.provide_capability <Iris::Boot> (cap.copy ()) |
| 37 | Iris::free_cap (cap) |
| 38 | Iris::my_parent.init_done () |
| 39 | |
| 40 | while true: |
| 41 | Iris::wait () |
| 42 | switch Iris::recv.data[0].l: |
| 43 | case Iris::Boot::BOOT: |
| 44 | Iris::String code = Iris::get_arg () |
| 45 | unsigned load = Iris::recv.data[1].l |
| 46 | unsigned entry = Iris::recv.data[1].h |
| 47 | Iris::Num lsize = code.get_size () |
| 48 | if lsize.h != 0: |
| 49 | Iris::panic (lsize.h, "string to boot is too large to be loaded") |
| 50 | unsigned size = lsize.l |
| 51 | unsigned pages = ((size + ~PAGE_MASK) >> PAGE_BITS) + 1 |
| 52 | unsigned phys = Iris::my_memory.alloc_range (pages) |
| 53 | if phys & ~PAGE_MASK: |
| 54 | Iris::panic (size, "unable to allocate space for string to load") |
| 55 | unsigned target, offset |
| 56 | if phys < (load & ~0xa0000000): |
| 57 | Iris::debug ("pre-loading\n") |
| 58 | Iris::Page pre = Iris::my_memory.create_page () |
| 59 | pre.alloc_physical (phys, true, true) |
| 60 | Iris::my_memory.map (pre, (unsigned)loader_addr) |
| 61 | for unsigned i = 0; i < &pre_end - &pre_code; ++i: |
| 62 | loader_addr[i] = (&pre_code)[i] |
| 63 | target = phys |
| 64 | offset = 1 |
| 65 | else: |
| 66 | Iris::debug ("post-loading\n") |
| 67 | Iris::Page post = Iris::my_memory.create_page () |
| 68 | post.alloc_physical (phys + ((pages - 1) << PAGE_BITS), true, true) |
| 69 | Iris::my_memory.map (post, (unsigned)loader_addr) |
| 70 | for unsigned i = 0; i < &post_end - &post_code; ++i: |
| 71 | loader_addr[i] = (&post_code)[i] |
| 72 | target = phys + ((pages - 1) << PAGE_BITS) |
| 73 | offset = 0 |
| 74 | Iris::Page tmp = Iris::my_memory.create_page () |
| 75 | tmp.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 76 | Iris::my_memory.map (tmp, (unsigned)tmp_addr) |
| 77 | for unsigned i = 0; i < pages - 1; ++i: |
| 78 | Iris::Page page = Iris::my_memory.create_page () |
| 79 | page.alloc_physical (phys + ((i + offset) << PAGE_BITS), true, true) |
| 80 | Iris::my_memory.map (page, (unsigned)page_addr) |
| 81 | code.get_block (i << PAGE_BITS, PAGE_SIZE, 0, tmp) |
| 82 | for unsigned t = 0; t < PAGE_SIZE / 4; ++t: |
| 83 | page_addr[t] = tmp_addr[t] |
| 84 | args_t *args = (args_t *)((unsigned)loader_addr + PAGE_SIZE - sizeof (args_t)) |
| 85 | unsigned phys_args = target + PAGE_SIZE - sizeof (args_t) |
| 86 | args->load = load |
| 87 | args->entry = entry |
| 88 | args->size = size |
| 89 | args->source = phys + (offset << PAGE_BITS) | 0x80000000 |
| 90 | Iris::debug ("booting into: %x+%x->%x@%x (%x, %x)\n", args->source, args->size, args->load, args->entry, args, phys_args) |
| 91 | // Everything is set up; jump to the loader. |
| 92 | Iris::boot (target | 0x80000000, phys_args | 0x80000000) |
| 93 | Iris::panic (0, "Iris::boot should not return, but it does") |
| 94 | default: |
| 95 | Iris::panic (Iris::recv.data[0].l, "invalid commend received on boot capability") |
| 96 | |
| 97 | asm volatile ("\t.set noreorder\n" |
| 98 | "\t.globl pre_code, pre_end, post_code, post_end\n" |
| 99 | "\t.text\n" |
| 100 | "pre_code:\n" |
| 101 | "\tlw $t0, 0($a0)\n" // t0 is the load address |
| 102 | "\tlw $t1, 4($a0)\n" // t1 is the size |
| 103 | "\tlw $t9, 8($a0)\n" // t9 is the entry point |
| 104 | "\tlw $t2, 12($a0)\n" // t2 is the source of the loaded image |
| 105 | "\tadd $t0, $t0, $t1\n" // t0 is the end of the load region |
| 106 | "\tadd $t2, $t2, $t1\n" // t2 is the end of the source |
| 107 | "1:\n" |
| 108 | "\tlw $t3, -4($t2)\n" |
| 109 | "\tsw $t3, -4($t0)\n" |
| 110 | "\taddiu $t2, $t2, -4\n" |
| 111 | "\taddiu $t1, $t1, -4\n" |
| 112 | "\tbnez $t1, 1b\n" |
| 113 | "\taddiu $t0, $t0, -4\n" |
| 114 | // Done copying |
| 115 | "\tjr $t9\n" |
| 116 | "\tnop\n" |
| 117 | "pre_end:\n" |
| 118 | "\n" |
| 119 | "post_code:\n" |
| 120 | "\tlw $t0, 0($a0)\n" // t0 is the load address |
| 121 | "\tlw $t1, 4($a0)\n" // t1 is the size |
| 122 | "\tlw $t9, 8($a0)\n" // t9 is the entry point |
| 123 | "\tlw $t2, 12($a0)\n" // t2 is the source of the loaded image |
| 124 | "1:\n" |
| 125 | "\tlw $t3, 0($t2)\n" |
| 126 | "\tsw $t3, 0($t0)\n" |
| 127 | "\taddiu $t2, $t2, 4\n" |
| 128 | "\taddiu $t1, $t1, -4\n" |
| 129 | "\tbnez $t1, 1b\n" |
| 130 | "\taddiu $t0, $t0, 4\n" |
| 131 | // Done copying |
| 132 | "\tjr $t9\n" |
| 133 | "\tnop\n" |
| 134 | "post_end:\n" |
| 135 | "\n" |
| 136 | "\t.set reorder\n") |
source/init.ccp |
26 | 26 | #define NUM_SLOTS 8 |
27 | 27 | #define NUM_CAPS 32 |
28 | 28 | |
29 | | #define SYSREQ 0x100 |
| 29 | enum Captype: |
| 30 | SYSREQ |
| 31 | PROGRAM |
| 32 | FILE |
30 | 33 | |
31 | 34 | static unsigned _free |
32 | 35 | extern unsigned _end |
... | ... | |
104 | 107 | |
105 | 108 | struct Program |
106 | 109 | |
107 | | struct Serverdevice: |
| 110 | struct Devbase: |
108 | 111 | char *name |
109 | 112 | unsigned name_len |
110 | | unsigned type, index |
| 113 | unsigned type |
| 114 | Program *client |
111 | 115 | Iris::Cap cap |
| 116 | |
| 117 | struct Serverdevice : public Devbase: |
| 118 | unsigned index |
112 | 119 | Program *server |
113 | | Program *client |
114 | 120 | |
115 | 121 | struct Clientdevice: |
116 | 122 | unsigned type, index |
117 | | Serverdevice *dev |
| 123 | Devbase *dev |
118 | 124 | |
119 | 125 | static Iris::Memory top_memory |
120 | 126 | static Iris::Directory root |
... | ... | |
132 | 138 | unsigned num_waiting |
133 | 139 | bool priv |
134 | 140 | void run (): |
135 | | Iris::Cap cap = Iris::my_receiver.create_capability ((unsigned)this) |
| 141 | Iris::Cap cap = Iris::my_receiver.create_capability (Iris::Num (PROGRAM, (unsigned)this)) |
136 | 142 | if priv: |
137 | 143 | kdebug ("priv ") |
138 | 144 | kdebug ("running ") |
... | ... | |
148 | 154 | thread.make_priv () |
149 | 155 | thread.run () |
150 | 156 | |
| 157 | struct File : public Devbase: |
| 158 | unsigned size |
| 159 | Iris::Caps pages |
| 160 | |
151 | 161 | static List <Program> programs |
| 162 | static List <File> files |
152 | 163 | static Serverdevice *sysreq |
153 | 164 | |
154 | 165 | static bool name_match (char const *name, unsigned name_len, Iris::String n): |
... | ... | |
238 | 249 | while name_len < len && isnamechar (line[name_len]): |
239 | 250 | ++name_len |
240 | 251 | name = new char[name_len] |
| 252 | kdebug ("name: ") |
241 | 253 | for unsigned i = 0; i < name_len; ++i: |
242 | 254 | name[i] = line[i] |
| 255 | kdebug_char (name[i]) |
| 256 | kdebug_char ('\n') |
243 | 257 | line += name_len |
244 | 258 | len -= name_len |
245 | 259 | delspace (line, len) |
... | ... | |
272 | 286 | static Type types[] = { |
273 | 287 | { "String", 6, Iris::String::ID }, |
274 | 288 | { "WString", 7, Iris::WString::ID }, |
| 289 | { "Boot", 4, Iris::Boot::ID }, |
275 | 290 | { "Device", 6, Iris::Device::ID }, |
276 | 291 | { "Event", 5, Iris::Event::ID }, |
277 | 292 | { "Parent", 6, Iris::Parent::ID }, |
... | ... | |
303 | 318 | return |
304 | 319 | Iris::panic (0, "no valid type found") |
305 | 320 | |
306 | | static bool find_cap (char *&line, unsigned &len, Program *&server, Serverdevice *&dev): |
| 321 | static bool find_cap (char *&line, unsigned &len, Program **server, Devbase *&dev, bool &present): |
307 | 322 | char *n |
308 | 323 | unsigned l |
309 | 324 | if !get_name (line, len, n, l): |
310 | 325 | Iris::panic (0, "no capability name found in init.config") |
311 | | List <Program>::Item *p |
312 | | for p = programs.begin (); p; p = p->next: |
| 326 | for List <Program>::Item *p = programs.begin (); p; p = p->next: |
313 | 327 | List <Serverdevice>::Item *d |
314 | 328 | for d = (*p)->server_devices.begin (); d; d = d->next: |
315 | 329 | if string_match (n, l, (*d)->name, (*d)->name_len): |
316 | | server = &**p |
| 330 | if server: |
| 331 | *server = &**p |
317 | 332 | dev = &**d |
| 333 | present = false |
318 | 334 | return true |
| 335 | if server: |
| 336 | return false |
| 337 | for List <File>::Item *f = files.begin (); f; f = f->next: |
| 338 | if string_match (n, l, (*f)->name, (*f)->name_len): |
| 339 | dev = &**f |
| 340 | present = true |
| 341 | return true |
319 | 342 | return false |
320 | 343 | |
321 | 344 | static void parse_line (char *&line, unsigned maxlen) |
... | ... | |
374 | 397 | if !maxlen: |
375 | 398 | return |
376 | 399 | if match (start, maxlen, "program"): |
| 400 | // program <name> = "<filename>" |
377 | 401 | do_load (start, maxlen, false) |
378 | 402 | else if match (start, maxlen, "driver"): |
| 403 | // driver <name> = "<filename>" |
379 | 404 | do_load (start, maxlen, true) |
| 405 | else if match (start, maxlen, "file"): |
| 406 | // file <name> = "<filename>" |
| 407 | File *f = &**files.insert () |
| 408 | f->type = Iris::String::ID |
| 409 | if !get_name (start, maxlen, f->name, f->name_len) || !match (start, maxlen, "=") || !maxlen: |
| 410 | Iris::panic (0, "syntax error in init.config (file name)") |
| 411 | unsigned l |
| 412 | char *n = get_filename (start, maxlen, l) |
| 413 | f->pages = load (n, l, f->size) |
| 414 | f->cap = Iris::my_receiver.create_capability (Iris::Num (FILE, (unsigned)f)) |
| 415 | ++line |
| 416 | --maxlen |
380 | 417 | else if match (start, maxlen, "receive"): |
381 | 418 | // receive <name> / <type> [, <index>] = <cap> |
382 | 419 | char *n |
... | ... | |
400 | 437 | Program *server |
401 | 438 | if sysreq: |
402 | 439 | Iris::panic (0, "double registration of sysreq") |
403 | | if !find_cap (start, maxlen, server, sysreq): |
| 440 | bool dummy |
| 441 | if !find_cap (start, maxlen, &server, *(Devbase **)&sysreq, dummy): |
404 | 442 | Iris::panic (0, "capability not found for sysreq") |
405 | 443 | if sysreq->type != Iris::Keyboard::ID: |
406 | 444 | kdebug ("capability for sysreq is not a keyboard\n") |
... | ... | |
420 | 458 | find_type (start, maxlen, (*d)->type, (*d)->index) |
421 | 459 | if !match (start, maxlen, "="): |
422 | 460 | Iris::panic (1, "syntax error in init.config (give)") |
423 | | Program *server |
424 | | if !find_cap (start, maxlen, server, (*d)->dev): |
| 461 | bool present |
| 462 | if !find_cap (start, maxlen, NULL, (*d)->dev, present): |
425 | 463 | Iris::panic (0, "capability not found for give") |
426 | 464 | if (*d)->dev->type != (*d)->type: |
427 | 465 | kdebug ("capability type mismatch for give\n") |
428 | 466 | if (*d)->dev->client: |
429 | 467 | Iris::panic (0, "capability given out twice") |
430 | 468 | (*d)->dev->client = &**p |
431 | | ++(*p)->num_waiting |
| 469 | if !present: |
| 470 | ++(*p)->num_waiting |
432 | 471 | //kdebug ("registered give device: ") |
433 | 472 | //kdebug_num ((*d)->type) |
434 | 473 | //kdebug ("\n") |
... | ... | |
452 | 491 | Iris::Num start (): |
453 | 492 | init_alloc () |
454 | 493 | programs.init () |
| 494 | files.init () |
455 | 495 | root = Iris::my_parent.get_capability <Iris::Directory> () |
456 | 496 | elfrun = Iris::my_parent.get_capability <Iris::Elfrun> () |
457 | 497 | sysreq = NULL |
... | ... | |
469 | 509 | kdebug ("waiting for events.\n") |
470 | 510 | while true: |
471 | 511 | Iris::wait () |
472 | | if Iris::recv.protected_data.l == SYSREQ: |
473 | | if Iris::recv.data[0].l & Iris::Keyboard::RELEASE: |
| 512 | switch Iris::recv.protected_data.l: |
| 513 | case SYSREQ: |
| 514 | if Iris::recv.data[0].l & Iris::Keyboard::RELEASE: |
| 515 | Iris::poweroff () |
| 516 | continue |
| 517 | kdebug ("sysreq event: powering device off at release\n") |
474 | 518 | continue |
475 | | kdebug ("sysreq event: powering device off\n") |
476 | | Iris::poweroff () |
477 | | continue |
478 | | Program *caller = (Program *)Iris::recv.protected_data.l |
479 | | switch Iris::recv.data[0].l: |
480 | | case Iris::Parent::GET_CAPABILITY: |
481 | | unsigned index = Iris::recv.data[0].h |
482 | | unsigned type = Iris::recv.data[1].l |
483 | | if Iris::recv.data[1].h: |
484 | | Iris::panic (Iris::recv.data[1].h, "high device requested") |
485 | | //kdebug ("requested device ") |
486 | | //kdebug_num (type) |
487 | | //kdebug (":") |
488 | | //kdebug_num (index) |
489 | | //kdebug ("\n") |
490 | | List <Clientdevice>::Item *d |
491 | | for d = caller->client_devices.begin (); d; d = d->next: |
492 | | //kdebug ("checking ") |
493 | | //kdebug_num ((*d)->type) |
494 | | //kdebug (":") |
495 | | //kdebug_num ((*d)->index) |
496 | | //kdebug ("\n") |
497 | | if (*d)->type == type && (*d)->index == index: |
| 519 | case FILE: |
| 520 | File *file = (File *)Iris::recv.protected_data.h |
| 521 | switch Iris::recv.data[0].l: |
| 522 | case Iris::String::GET_SIZE: |
| 523 | Iris::recv.reply.invoke (file->size) |
498 | 524 | break |
499 | | if !d: |
500 | | Iris::panic (type, "unregistered device requested") |
501 | | Iris::recv.reply.invoke (0, 0, (*d)->dev->cap) |
502 | | //kdebug ("given device ") |
503 | | //kdebug_num (type) |
504 | | //kdebug (":") |
505 | | //kdebug_num (index) |
506 | | //kdebug ("\n") |
507 | | break |
508 | | case Iris::Parent::PROVIDE_CAPABILITY: |
509 | | if Iris::recv.data[1].h != 0: |
510 | | kdebug ("init: too high device provided\n") |
511 | | continue |
512 | | unsigned type = Iris::recv.data[1].l |
513 | | unsigned index = Iris::recv.data[0].h |
514 | | List <Serverdevice>::Item *d |
515 | | for d = caller->server_devices.begin (); d; d = d->next: |
516 | | if (*d)->type == type && (*d)->index == index: |
| 525 | case Iris::String::GET_CHARS: |
| 526 | Iris::panic (0, "get_chars is not defined for init strings") |
| 527 | case Iris::String::GET_ALIGN_BITS: |
| 528 | Iris::recv.reply.invoke (PAGE_BITS) |
517 | 529 | break |
518 | | if !d: |
519 | | Iris::panic (0, "unregistered device provided") |
520 | | (*d)->cap = Iris::get_arg () |
521 | | Iris::recv.reply.invoke () |
522 | | if (*d)->client: |
523 | | if !--(*d)->client->num_waiting: |
524 | | (*d)->client->run () |
525 | | //kdebug ("provided ") |
526 | | //kdebug_num ((*d)->type) |
527 | | //kdebug (":") |
528 | | //kdebug_num ((*d)->index) |
529 | | //kdebug ("\n") |
530 | | break |
531 | | case Iris::Parent::INIT_DONE: |
532 | | //kdebug ("init done\n") |
533 | | Iris::recv.reply.invoke () |
534 | | if caller == sysreq->server: |
535 | | Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ) |
536 | | Iris::Keyboard (sysreq->cap).set_cb (cap.copy ()) |
537 | | Iris::free_cap (cap) |
538 | | kdebug ("registered sysreq\n") |
539 | | break |
540 | | case Iris::Parent::EXIT: |
541 | | kdebug ("child exits with code ") |
542 | | // TODO: print name. |
543 | | kdebug_num (Iris::recv.data[1].h) |
544 | | kdebug (":") |
545 | | kdebug_num (Iris::recv.data[1].l) |
546 | | kdebug ("\n") |
547 | | // TODO: destroy memory. |
| 530 | case Iris::String::GET_BLOCK: |
| 531 | Iris::Cap reply = Iris::get_reply () |
| 532 | Iris::Page target = Iris::get_arg () |
| 533 | Iris::Page source = file->pages.get (Iris::recv.data[1].l >> PAGE_BITS) |
| 534 | source.share (target, Iris::Page::READONLY) |
| 535 | reply.invoke () |
| 536 | Iris::free_cap (reply) |
| 537 | Iris::free_cap (source) |
| 538 | Iris::free_cap (target) |
| 539 | break |
| 540 | default: |
| 541 | Iris::panic (Iris::recv.data[0].l, "unknown request for init string") |
548 | 542 | break |
549 | | default: |
550 | | // TODO. |
551 | | kdebug ("child request: ") |
552 | | kdebug_num (Iris::recv.data[0].l) |
553 | | kdebug (" from ") |
554 | | for unsigned i = 0; i < caller->name_len; ++i: |
555 | | kdebug_char (caller->name[i]) |
556 | | kdebug ("\n") |
| 543 | case PROGRAM: |
| 544 | Program *caller = (Program *)Iris::recv.protected_data.h |
| 545 | switch Iris::recv.data[0].l: |
| 546 | case Iris::Parent::GET_CAPABILITY: |
| 547 | unsigned index = Iris::recv.data[0].h |
| 548 | unsigned type = Iris::recv.data[1].l |
| 549 | if Iris::recv.data[1].h: |
| 550 | Iris::panic (Iris::recv.data[1].h, "high device requested") |
| 551 | //kdebug ("requested device ") |
| 552 | //kdebug_num (type) |
| 553 | //kdebug (":") |
| 554 | //kdebug_num (index) |
| 555 | //kdebug ("\n") |
| 556 | List <Clientdevice>::Item *d |
| 557 | for d = caller->client_devices.begin (); d; d = d->next: |
| 558 | //kdebug ("checking ") |
| 559 | //kdebug_num ((*d)->type) |
| 560 | //kdebug (":") |
| 561 | //kdebug_num ((*d)->index) |
| 562 | //kdebug ("\n") |
| 563 | if (*d)->type == type && (*d)->index == index: |
| 564 | break |
| 565 | if !d: |
| 566 | Iris::panic (type, "unregistered device requested") |
| 567 | Iris::recv.reply.invoke (0, 0, (*d)->dev->cap) |
| 568 | //kdebug ("given device ") |
| 569 | //kdebug_num (type) |
| 570 | //kdebug (":") |
| 571 | //kdebug_num (index) |
| 572 | //kdebug ("\n") |
| 573 | break |
| 574 | case Iris::Parent::PROVIDE_CAPABILITY: |
| 575 | if Iris::recv.data[1].h != 0: |
| 576 | kdebug ("init: too high device provided\n") |
| 577 | continue |
| 578 | unsigned type = Iris::recv.data[1].l |
| 579 | unsigned index = Iris::recv.data[0].h |
| 580 | List <Serverdevice>::Item *d |
| 581 | for d = caller->server_devices.begin (); d; d = d->next: |
| 582 | if (*d)->type == type && (*d)->index == index: |
| 583 | break |
| 584 | if !d: |
| 585 | Iris::panic (0, "unregistered device provided") |
| 586 | (*d)->cap = Iris::get_arg () |
| 587 | Iris::recv.reply.invoke () |
| 588 | if (*d)->client: |
| 589 | if !--(*d)->client->num_waiting: |
| 590 | (*d)->client->run () |
| 591 | //kdebug ("provided ") |
| 592 | //kdebug_num ((*d)->type) |
| 593 | //kdebug (":") |
| 594 | //kdebug_num ((*d)->index) |
| 595 | //kdebug ("\n") |
| 596 | break |
| 597 | case Iris::Parent::INIT_DONE: |
| 598 | //kdebug ("init done\n") |
| 599 | Iris::recv.reply.invoke () |
| 600 | if caller == sysreq->server: |
| 601 | Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ) |
| 602 | Iris::Keyboard (sysreq->cap).set_cb (cap.copy ()) |
| 603 | Iris::free_cap (cap) |
| 604 | kdebug ("registered sysreq\n") |
| 605 | break |
| 606 | case Iris::Parent::EXIT: |
| 607 | kdebug ("child ") |
| 608 | for unsigned i = 0; i < caller->name_len; ++i: |
| 609 | kdebug_char (caller->name[i]) |
| 610 | kdebug (" exits with code ") |
| 611 | kdebug_num (Iris::recv.data[1].h) |
| 612 | kdebug (":") |
| 613 | kdebug_num (Iris::recv.data[1].l) |
| 614 | kdebug ("\n") |
| 615 | top_memory.destroy (caller->memory) |
| 616 | break |
| 617 | default: |
| 618 | // TODO. |
| 619 | kdebug ("child request: ") |
| 620 | kdebug_num (Iris::recv.data[0].l) |
| 621 | kdebug (" from ") |
| 622 | for unsigned i = 0; i < caller->name_len; ++i: |
| 623 | kdebug_char (caller->name[i]) |
| 624 | kdebug ("\n") |