Root/
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // invoke.ccp: Capability invocation and kernel responses. |
| 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 "kernel.hh" |
| 20 | |
| 21 | static void log_message (char const *prefix, unsigned target, unsigned pdata, kCapability::Context *c): |
| 22 | kdebug (prefix) |
| 23 | kdebug (": caller=") |
| 24 | if old_current: |
| 25 | kdebug_num (old_current->id, 2) |
| 26 | else |
| 27 | kdebug ("xx") |
| 28 | kdebug (":") |
| 29 | kdebug_num ((unsigned)old_current) |
| 30 | kdebug ("; target=") |
| 31 | kdebug_num (target) |
| 32 | kdebug ("; pdata=") |
| 33 | kdebug_num (pdata) |
| 34 | kdebug ("; data=") |
| 35 | kdebug_num (c->data[0].h) |
| 36 | kdebug (":") |
| 37 | kdebug_num (c->data[0].l) |
| 38 | kdebug (",") |
| 39 | kdebug_num (c->data[1].h) |
| 40 | kdebug (":") |
| 41 | kdebug_num (c->data[1].l) |
| 42 | if c->reply.valid (): |
| 43 | kdebug ("; reply target=") |
| 44 | kdebug_num ((unsigned)c->reply->target) |
| 45 | kdebug ("; pdata=") |
| 46 | kdebug_num (c->reply->protected_data.l) |
| 47 | if c->arg.valid (): |
| 48 | kdebug ("; arg target=") |
| 49 | kdebug_num ((unsigned)c->arg->target) |
| 50 | kdebug ("; pdata=") |
| 51 | kdebug_num (c->arg->protected_data.l) |
| 52 | kdebug ("\n") |
| 53 | |
| 54 | void kThread::raise (unsigned code, unsigned data): |
| 55 | kdebug ("raise ") |
| 56 | if old_current: |
| 57 | kdebug_num (old_current->id, 2) |
| 58 | else: |
| 59 | kdebug ("xx") |
| 60 | kdebug (':') |
| 61 | kdebug_num ((unsigned)old_current) |
| 62 | kdebug ('/') |
| 63 | if code < Iris::NUM_EXCEPTION_CODES: |
| 64 | kdebug (Iris::exception_name(code)) |
| 65 | else: |
| 66 | kdebug ("invalid code:") |
| 67 | kdebug_num (code) |
| 68 | kdebug ('/') |
| 69 | kdebug_num (data) |
| 70 | kdebug ('\n') |
| 71 | dpanic (code, "raise") |
| 72 | unrun () |
| 73 | if slots < 1 || !slot[0].caps || !slot[0].caps->cap (0)->target: |
| 74 | return |
| 75 | kCapability::Context c |
| 76 | c.data[0] = Iris::Num (code, data) |
| 77 | slot[0].caps->cap (0)->invoke (&c) |
| 78 | |
| 79 | // From user-provided, thus untrusted, data, find a capability. |
| 80 | kCapRef kThread::find_capability (unsigned code, bool *copy): |
| 81 | *copy = code & CAP_COPY |
| 82 | unsigned c = code & ~CAP_COPY |
| 83 | unsigned s = c >> 16 |
| 84 | unsigned num = c & 0xffff |
| 85 | if s >= slots || !slot[s].caps || num >= slot[s].caps->size: |
| 86 | if c != CAP_NONE: |
| 87 | kdebug_num ((unsigned)old_current) |
| 88 | kdebug (": invalid capability ") |
| 89 | kdebug_num (code) |
| 90 | kdebug ('\n') |
| 91 | kdebug_num (num) |
| 92 | kdebug (':') |
| 93 | kdebug_num (s) |
| 94 | kdebug (" > ") |
| 95 | if slot[s].caps: |
| 96 | kdebug_num (slot[s].caps->size) |
| 97 | else: |
| 98 | kdebug ("no caps") |
| 99 | kdebug ('\n') |
| 100 | dpanic (code, "invalid capability") |
| 101 | return kCapRef () |
| 102 | return kCapRef (slot[s].caps, num) |
| 103 | |
| 104 | // Try to deliver a message. |
| 105 | bool kReceiver::try_deliver (): |
| 106 | if !messages: |
| 107 | return false |
| 108 | if !owner || !owner->is_waiting (): |
| 109 | return false |
| 110 | kMessage *m = last_message |
| 111 | if protected_only: |
| 112 | for ; m; m = (kMessage *)m->prev: |
| 113 | if m->protected_data.value () == reply_protected_data.value (): |
| 114 | protected_only = false |
| 115 | break |
| 116 | if !m: |
| 117 | return false |
| 118 | bool dummy |
| 119 | kCapRef c = owner->find_capability (owner->recv_reply, &dummy) |
| 120 | if c.valid (): |
| 121 | c.clone (kCapRef (&m->caps, 0), true) |
| 122 | c = owner->find_capability (owner->recv_arg, &dummy) |
| 123 | if c.valid (): |
| 124 | c.clone (kCapRef (&m->caps, 1), true) |
| 125 | kThread_arch_receive (owner, m->protected_data, m->data) |
| 126 | address_space->free_message (this, m) |
| 127 | owner->unwait () |
| 128 | return true |
| 129 | |
| 130 | // Send a message to a receiver; try to deliver it immediately. |
| 131 | bool kReceiver::send_message (Iris::Num protected_data, kCapability::Context *c): |
| 132 | //log_message ("send_message", (unsigned)this, protected_data.l, c) |
| 133 | if owner && owner->is_waiting () && (!protected_only || protected_data.value () == reply_protected_data.value ()): |
| 134 | if protected_only: |
| 135 | protected_only = false |
| 136 | bool dummy |
| 137 | kCapRef cap = owner->find_capability (owner->recv_reply, &dummy) |
| 138 | if cap.valid (): |
| 139 | cap.clone (c->reply, c->copy[0]) |
| 140 | cap = owner->find_capability (owner->recv_arg, &dummy) |
| 141 | if cap.valid (): |
| 142 | cap.clone (c->arg, c->copy[1]) |
| 143 | kThread_arch_receive (owner, protected_data, c->data) |
| 144 | owner->unwait () |
| 145 | return true |
| 146 | // The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. |
| 147 | kMessage *msg = NULL; |
| 148 | if queue_limit: |
| 149 | msg = address_space->alloc_message (this) |
| 150 | if msg: |
| 151 | --queue_limit |
| 152 | if !msg: |
| 153 | // TODO: use sender-provided storage. |
| 154 | if !msg: |
| 155 | return false |
| 156 | msg->protected_data = protected_data |
| 157 | for unsigned i = 0; i < 2; ++i: |
| 158 | msg->data[i] = c->data[i] |
| 159 | msg->caps.clone (0, c->reply, c->copy[0]) |
| 160 | msg->caps.clone (1, c->arg, c->copy[1]) |
| 161 | return true |
| 162 | |
| 163 | static kCapability::Context *context |
| 164 | |
| 165 | static void reply_num (Iris::Num num): |
| 166 | kCapability::Context c |
| 167 | c.data[0] = num |
| 168 | c.data[1] = 0 |
| 169 | if reply_target: |
| 170 | reply_target->send_message (reply_protected, &c) |
| 171 | else |
| 172 | dpanic (0, "nothing to reply to") |
| 173 | |
| 174 | static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0): |
| 175 | kCapability::Context c |
| 176 | c.data[0] = Iris::Num (num1, num2) |
| 177 | c.data[1] = num3 |
| 178 | if reply_target: |
| 179 | reply_target->send_message (reply_protected, &c) |
| 180 | else |
| 181 | dpanic (0, "nothing to reply to") |
| 182 | |
| 183 | static void reply_cap (unsigned target, Iris::Num protected_data, kCapRef *ref, unsigned num = 0): |
| 184 | if !reply_target: |
| 185 | dpanic (0, "nothing to reply to") |
| 186 | return |
| 187 | replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref) |
| 188 | kCapability::Context c |
| 189 | c.arg = kCapRef (&replied_caps, 0) |
| 190 | c.copy[1] = true |
| 191 | c.data[0] = Iris::Num (num, 0) |
| 192 | reply_target->send_message (reply_protected, &c) |
| 193 | c.arg->invalidate () |
| 194 | |
| 195 | static void receiver_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 196 | kReceiver *receiver = (kReceiver *)protected_data.l |
| 197 | switch cmd: |
| 198 | case Iris::Receiver::SET_OWNER & REQUEST_MASK: |
| 199 | if !c->arg.valid (): |
| 200 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 201 | return |
| 202 | unsigned cap = (unsigned)c->arg->target |
| 203 | if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Iris::Thread::SET_OWNER): |
| 204 | // FIXME: This makes it impossible to use a fake kThread capability. |
| 205 | return |
| 206 | receiver->own ((kThread *)c->arg->protected_data.l) |
| 207 | break |
| 208 | case Iris::Receiver::CREATE_CAPABILITY & REQUEST_MASK: |
| 209 | reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities) |
| 210 | return |
| 211 | case Iris::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK: |
| 212 | reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Iris::Receiver::CALL_ASYNC : Iris::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs) |
| 213 | return |
| 214 | case Iris::Receiver::GET_PROTECTED & REQUEST_MASK: |
| 215 | if !c->arg.valid () || c->arg->target != receiver: |
| 216 | if !c->arg.valid (): |
| 217 | kdebug ("invalid arg\n") |
| 218 | else: |
| 219 | kdebug ("target: ") |
| 220 | kdebug_num ((unsigned)c->arg->target) |
| 221 | kdebug ("/") |
| 222 | kdebug_num ((unsigned)c->arg->protected_data.h) |
| 223 | kdebug (":") |
| 224 | kdebug_num ((unsigned)c->arg->protected_data.l) |
| 225 | kdebug ("\n") |
| 226 | dpanic (0, "wrong argument for get_protected") |
| 227 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 228 | return |
| 229 | reply_num (c->arg->protected_data) |
| 230 | return |
| 231 | case Iris::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK: |
| 232 | reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0) |
| 233 | return |
| 234 | case Iris::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK: |
| 235 | receiver->reply_protected_data = c->data[1] |
| 236 | // Adjust target protected data, so the reply will reach the caller. |
| 237 | if receiver == reply_target: |
| 238 | reply_protected = receiver->reply_protected_data |
| 239 | break |
| 240 | case Iris::Receiver::GET_ALARM & REQUEST_MASK: |
| 241 | reply_num (receiver->alarm_count) |
| 242 | return |
| 243 | case Iris::Receiver::SET_ALARM & REQUEST_MASK: |
| 244 | case Iris::Receiver::ADD_ALARM & REQUEST_MASK: |
| 245 | unsigned old = receiver->alarm_count |
| 246 | if cmd == (Iris::Receiver::SET_ALARM & REQUEST_MASK): |
| 247 | receiver->alarm_count = c->data[1].l |
| 248 | else: |
| 249 | receiver->alarm_count += c->data[1].l |
| 250 | if (old == ~0) ^ (receiver->alarm_count == ~0): |
| 251 | // The alarm stopped or started. |
| 252 | if old == ~0: |
| 253 | // It started. |
| 254 | receiver->prev_alarm = NULL |
| 255 | receiver->next_alarm = first_alarm |
| 256 | if receiver->next_alarm: |
| 257 | receiver->next_alarm->prev_alarm = receiver |
| 258 | first_alarm = receiver |
| 259 | else: |
| 260 | // It stopped. |
| 261 | if receiver->prev_alarm: |
| 262 | receiver->prev_alarm->next_alarm = receiver->next_alarm |
| 263 | else: |
| 264 | first_alarm = receiver->next_alarm |
| 265 | if receiver->next_alarm: |
| 266 | receiver->next_alarm->prev_alarm = receiver->prev_alarm |
| 267 | reply_num (receiver->alarm_count) |
| 268 | return |
| 269 | default: |
| 270 | dpanic (cmd, "invalid receiver operation") |
| 271 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 272 | return |
| 273 | reply_num (0) |
| 274 | |
| 275 | static void memory_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 276 | kMemory *mem = (kMemory *)protected_data.l |
| 277 | switch cmd: |
| 278 | case Iris::Memory::CREATE & REQUEST_MASK: |
| 279 | switch c->data[0].h: |
| 280 | case CAPTYPE_RECEIVER: |
| 281 | kReceiver *ret = mem->alloc_receiver () |
| 282 | if ret: |
| 283 | reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 284 | else: |
| 285 | dpanic (0x03311992, "out of memory creating receiver") |
| 286 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 287 | return |
| 288 | case CAPTYPE_MEMORY: |
| 289 | kMemory *ret = mem->alloc_memory () |
| 290 | if ret: |
| 291 | reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 292 | else: |
| 293 | dpanic (0x13311992, "out of memory creating memory") |
| 294 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 295 | return |
| 296 | case CAPTYPE_THREAD: |
| 297 | kThread *ret = mem->alloc_thread (c->data[1].l) |
| 298 | if ret: |
| 299 | reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 300 | kdebug ("(created thread ") |
| 301 | kdebug_num ((unsigned)ret) |
| 302 | kdebug (")\n") |
| 303 | else: |
| 304 | dpanic (0x23311992, "out of memory creating thread") |
| 305 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 306 | return |
| 307 | case CAPTYPE_PAGE: |
| 308 | kPage *ret = mem->alloc_page () |
| 309 | if ret: |
| 310 | reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 311 | else: |
| 312 | dpanic (0x33311992, "out of memory creating page") |
| 313 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 314 | return |
| 315 | case CAPTYPE_CAPS: |
| 316 | kCaps *ret = mem->alloc_caps (c->data[1].l) |
| 317 | if ret: |
| 318 | reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 319 | else: |
| 320 | dpanic (0x43311992, "out of memory creating caps") |
| 321 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 322 | return |
| 323 | case CAPTYPE_LIST: |
| 324 | kList *ret = mem->alloc_list () |
| 325 | if ret: |
| 326 | reply_cap (CAPTYPE_LIST | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 327 | else: |
| 328 | dpanic (0x13311995, "out of memory creating list") |
| 329 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 330 | return |
| 331 | case CAPTYPE_LISTITEM: |
| 332 | kListitem *ret = mem->alloc_listitem () |
| 333 | if ret: |
| 334 | reply_cap (CAPTYPE_LISTITEM | CAP_MASTER, (unsigned)ret, &ret->refs) |
| 335 | else: |
| 336 | dpanic (0x13311997, "out of memory creating list") |
| 337 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 338 | return |
| 339 | default: |
| 340 | dpanic (0, "invalid create type") |
| 341 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 342 | return |
| 343 | break |
| 344 | case Iris::Memory::DESTROY & REQUEST_MASK: |
| 345 | if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem: |
| 346 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 347 | return |
| 348 | // Send the reply before destroying things, because the target may be destroyed. |
| 349 | reply_num (0) |
| 350 | switch (unsigned)c->arg->target & CAPTYPE_MASK: |
| 351 | case CAPTYPE_RECEIVER: |
| 352 | mem->free_receiver ((kReceiver *)c->arg->protected_data.l) |
| 353 | break |
| 354 | case CAPTYPE_MEMORY: |
| 355 | mem->free_memory ((kMemory *)c->arg->protected_data.l) |
| 356 | break |
| 357 | case CAPTYPE_THREAD: |
| 358 | mem->free_thread ((kThread *)c->arg->protected_data.l) |
| 359 | break |
| 360 | case CAPTYPE_PAGE: |
| 361 | mem->free_page ((kPage *)c->arg->protected_data.l) |
| 362 | break |
| 363 | case CAPTYPE_CAPS: |
| 364 | mem->free_caps ((kCaps *)c->arg->protected_data.l) |
| 365 | break |
| 366 | default: |
| 367 | panic (0x55228930, "invalid case") |
| 368 | return |
| 369 | return |
| 370 | case Iris::Memory::LIST & REQUEST_MASK: |
| 371 | // TODO |
| 372 | break |
| 373 | case Iris::Memory::MAP & REQUEST_MASK: |
| 374 | // FIXME: this should work for fake pages as well. |
| 375 | if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE: |
| 376 | dpanic (0x22993341, "Trying to map non-page") |
| 377 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 378 | return |
| 379 | kPage *page = (kPage *)c->arg->protected_data.l |
| 380 | if page->address_space != mem: |
| 381 | dpanic (0x52993341, "Trying to map foreign page") |
| 382 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 383 | return |
| 384 | if c->data[1].l & (unsigned)c->arg->target & Iris::Page::READONLY: |
| 385 | kdebug ("Mapping readonly because capability is readonly\n") |
| 386 | page->flags |= Iris::Page::MAPPED_READONLY |
| 387 | mem->map (page, c->data[1].l & PAGE_MASK) |
| 388 | break |
| 389 | case Iris::Memory::MAPPING & REQUEST_MASK: |
| 390 | kPage *page = mem->get_mapping (c->data[1].l) |
| 391 | if !page: |
| 392 | reply_num (Iris::ERR_UNMAPPED_READ) |
| 393 | return |
| 394 | unsigned t = CAPTYPE_PAGE | CAP_MASTER |
| 395 | if page->flags & Iris::Page::MAPPED_READONLY: |
| 396 | t |= Iris::Page::READONLY |
| 397 | reply_cap (t, (unsigned)page, &page->refs) |
| 398 | return |
| 399 | case Iris::Memory::GET_LIMIT & REQUEST_MASK: |
| 400 | reply_num (mem->limit) |
| 401 | return |
| 402 | case Iris::Memory::SET_LIMIT & REQUEST_MASK: |
| 403 | mem->limit = c->data[1].l |
| 404 | break |
| 405 | default: |
| 406 | dpanic (0, "invalid memory operation") |
| 407 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 408 | return |
| 409 | reply_num (0) |
| 410 | |
| 411 | static void thread_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 412 | kThread *thread = (kThread *)protected_data.l |
| 413 | switch cmd: |
| 414 | case Iris::Thread::GET_INFO & REQUEST_MASK: |
| 415 | switch c->data[0].h: |
| 416 | case Iris::Thread::PC: |
| 417 | reply_num (thread->pc) |
| 418 | return |
| 419 | case Iris::Thread::SP: |
| 420 | reply_num (thread->sp) |
| 421 | return |
| 422 | case Iris::Thread::FLAGS: |
| 423 | reply_num (thread->flags) |
| 424 | return |
| 425 | default: |
| 426 | reply_num (*kThread_arch_info (thread, c->data[0].h)) |
| 427 | return |
| 428 | case Iris::Thread::SET_INFO & REQUEST_MASK: |
| 429 | unsigned *value |
| 430 | switch c->data[0].h: |
| 431 | case Iris::Thread::PC: |
| 432 | value = &thread->pc |
| 433 | break |
| 434 | case Iris::Thread::SP: |
| 435 | value = &thread->sp |
| 436 | break |
| 437 | case Iris::Thread::FLAGS: |
| 438 | // It is not possible to set the PRIV flag (but it can be reset). |
| 439 | if c->data[1].l & Iris::Thread::PRIV: |
| 440 | c->data[1].h &= ~Iris::Thread::PRIV |
| 441 | value = &thread->flags |
| 442 | if c->data[1].h & ~Iris::Thread::USER_FLAGS: |
| 443 | unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h) |
| 444 | if (v & Iris::Thread::WAITING) != (*value & Iris::Thread::WAITING): |
| 445 | if v & Iris::Thread::WAITING: |
| 446 | thread->wait () |
| 447 | else |
| 448 | thread->unwait () |
| 449 | if (v & Iris::Thread::RUNNING) != (*value & Iris::Thread::RUNNING): |
| 450 | if v & Iris::Thread::RUNNING: |
| 451 | thread->run () |
| 452 | else: |
| 453 | thread->unrun () |
| 454 | break |
| 455 | default: |
| 456 | value = kThread_arch_info (thread, c->data[0].h) |
| 457 | break |
| 458 | if value: |
| 459 | *value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h) |
| 460 | break |
| 461 | case Iris::Thread::USE_SLOT & REQUEST_MASK: |
| 462 | if c->data[1].l >= thread->slots || !c->arg.valid (): |
| 463 | if c->data[1].l == 0xdeadbeef: |
| 464 | bool dummy |
| 465 | dbg_code.h = (unsigned)c->arg.deref () |
| 466 | break |
| 467 | dbg_send (5, 3) |
| 468 | dpanic (c->data[1].l, "no argument given for USE_SLOT") |
| 469 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 470 | return |
| 471 | // FIXME: This doesn't allow using a fake caps. |
| 472 | if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Iris::Caps::USE): |
| 473 | dpanic ((unsigned)c->arg->target, "argument for USE_SLOT is not a caps") |
| 474 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 475 | return |
| 476 | unsigned slot = c->data[1].l |
| 477 | kCaps *new_caps = (kCaps *)c->arg->protected_data.l |
| 478 | if slot >= thread->slots: |
| 479 | dpanic (0, "using invalid slot") |
| 480 | return |
| 481 | thread->unset_slot (slot) |
| 482 | thread->slot[slot].caps = new_caps |
| 483 | if new_caps: |
| 484 | thread->slot[slot].next = new_caps->first_slot |
| 485 | thread->slot[slot].caps = new_caps |
| 486 | new_caps->first_slot.thread = thread |
| 487 | new_caps->first_slot.index = slot |
| 488 | break |
| 489 | case Iris::Thread::GET_CAPS & REQUEST_MASK: |
| 490 | unsigned slot = c->data[1].l |
| 491 | if slot < thread->slots: |
| 492 | reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots) |
| 493 | else: |
| 494 | reply_num (thread->slots) |
| 495 | return |
| 496 | case Iris::Thread::SCHEDULE & REQUEST_MASK: |
| 497 | do_schedule = true |
| 498 | return |
| 499 | default: |
| 500 | if !(thread->flags & Iris::Thread::PRIV): |
| 501 | dpanic (0, "invalid thread operation") |
| 502 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 503 | return |
| 504 | switch cmd: |
| 505 | case Iris::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK: |
| 506 | arch_register_interrupt (c->data[1].l, c->arg.valid () && (((unsigned)c->arg->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->arg->protected_data.l : NULL) |
| 507 | break |
| 508 | case Iris::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK: |
| 509 | reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs) |
| 510 | return |
| 511 | case Iris::Thread::PRIV_MAKE_PRIV & REQUEST_MASK: |
| 512 | if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD: |
| 513 | dpanic (0, "not a thread argument for make priv") |
| 514 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 515 | return |
| 516 | ((kThread *)c->arg->protected_data.l)->flags |= Iris::Thread::PRIV |
| 517 | break |
| 518 | case Iris::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK: |
| 519 | if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY: |
| 520 | dpanic (0x54365435, "non-memory argument to alloc_range") |
| 521 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 522 | return |
| 523 | kMemory *mem = (kMemory *)c->arg->protected_data.l |
| 524 | if !mem->use (c->data[1].l): |
| 525 | dpanic (0x34365435, "out of memory during alloc_range") |
| 526 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 527 | return |
| 528 | unsigned data = phys_alloc (c->data[1].l) |
| 529 | if !data: |
| 530 | mem->unuse (c->data[1].l) |
| 531 | dpanic (0x14365435, "out of memory during alloc_range") |
| 532 | reply_num (Iris::ERR_OUT_OF_MEMORY) |
| 533 | return |
| 534 | reply_num (data & ~0xc0000000) |
| 535 | return |
| 536 | case Iris::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK: |
| 537 | if !c->arg.valid (): |
| 538 | panic (0x71342134, "no argument provided for alloc physical") |
| 539 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 540 | return |
| 541 | if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: |
| 542 | panic (0x21342134, "no page provided for alloc physical") |
| 543 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 544 | return |
| 545 | kPage *page = (kPage *)c->arg->protected_data.l |
| 546 | page->forget () |
| 547 | if !(c->data[1].l & 2): |
| 548 | if page->flags & Iris::Page::PAYING: |
| 549 | page->flags &= ~Iris::Page::PAYING |
| 550 | page->address_space->unuse () |
| 551 | else: |
| 552 | // This is for mapping allocated ranges. They are already paid for. Record that. |
| 553 | if page->flags & Iris::Page::PAYING: |
| 554 | page->address_space->unuse () |
| 555 | else: |
| 556 | page->flags |= Iris::Page::PAYING |
| 557 | page->frame = (c->data[1].l & PAGE_MASK) | 0x80000000 |
| 558 | page->flags |= Iris::Page::FRAME |
| 559 | if !(c->data[1].l & 1): |
| 560 | page->flags |= Iris::Page::UNCACHED |
| 561 | if !(c->data[1].l & 2): |
| 562 | page->flags |= Iris::Page::PHYSICAL |
| 563 | kPage_arch_update_mapping (page) |
| 564 | break |
| 565 | case Iris::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK: |
| 566 | if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE: |
| 567 | dpanic (0x99049380, "invalid page for physical address") |
| 568 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 569 | return |
| 570 | kPage *page = (kPage *)c->arg->protected_data.l |
| 571 | reply_num (page->frame & ~0xc0000000) |
| 572 | return |
| 573 | case Iris::Thread::PRIV_REBOOT & REQUEST_MASK: |
| 574 | arch_reboot () |
| 575 | case Iris::Thread::PRIV_POWEROFF & REQUEST_MASK: |
| 576 | arch_poweroff () |
| 577 | case Iris::Thread::PRIV_SUSPEND & REQUEST_MASK: |
| 578 | arch_suspend () |
| 579 | reply_num (~0) |
| 580 | return |
| 581 | case Iris::Thread::PRIV_BOOT & REQUEST_MASK: |
| 582 | arch_boot (c->data[1].l, c->data[1].h) |
| 583 | case Iris::Thread::PRIV_PANIC & REQUEST_MASK: |
| 584 | if c->data[1].l == 0xdeaddead: |
| 585 | dbg_code.l = 1 |
| 586 | break |
| 587 | panic (c->data[1].l, "panic requested by thread") |
| 588 | reply_num (~0) |
| 589 | return |
| 590 | case Iris::Thread::DBG_SEND & REQUEST_MASK: |
| 591 | dbg_send (c->data[1].l, c->data[1].h) |
| 592 | break |
| 593 | default: |
| 594 | dpanic (0, "invalid priv thread operation") |
| 595 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 596 | return |
| 597 | reply_num (0) |
| 598 | return |
| 599 | |
| 600 | static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 601 | kPage *page = (kPage *)protected_data.l |
| 602 | switch cmd & ~Iris::Page::READONLY: |
| 603 | case Iris::Page::SHARE & REQUEST_MASK: |
| 604 | if !c->arg.valid (): |
| 605 | // Cannot share without a target page. |
| 606 | dpanic (0, "no target page for share") |
| 607 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 608 | return |
| 609 | if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: |
| 610 | // FIXME: This makes it impossible to use a fake kPage capability. |
| 611 | dpanic (0, "share target is no page") |
| 612 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 613 | return |
| 614 | kPage *t = (kPage *)c->arg->protected_data.l |
| 615 | //kdebug ("sharing from ") |
| 616 | //kdebug_num ((unsigned)page) |
| 617 | //kdebug (" (frame ") |
| 618 | //kdebug_num (page->frame) |
| 619 | //kdebug (") to ") |
| 620 | //kdebug_num ((unsigned)t) |
| 621 | //kdebug (" (frame ") |
| 622 | //kdebug_num (t->frame) |
| 623 | //kdebug (")\n") |
| 624 | if t != page: |
| 625 | t->forget () |
| 626 | if c->data[0].h & Iris::Page::READONLY || cmd & Iris::Page::READONLY: |
| 627 | t->flags |= Iris::Page::READONLY |
| 628 | if !(page->flags & Iris::Page::FRAME): |
| 629 | kdebug ("share problem: ") |
| 630 | kdebug_num (page->flags) |
| 631 | kdebug ("\n") |
| 632 | dpanic (0, "sharing nothing results in lost page") |
| 633 | kPage_arch_update_mapping (t) |
| 634 | break |
| 635 | if c->data[0].h & Iris::Page::COPY: |
| 636 | if ~t->flags & Iris::Page::PAYING: |
| 637 | kPage_arch_update_mapping (t) |
| 638 | break |
| 639 | if !(c->data[0].h & Iris::Page::FORGET) || page->flags & Iris::Page::SHARED: |
| 640 | unsigned *d = (unsigned *)page->frame |
| 641 | if t == page: |
| 642 | kPage *other = page->share_next ? page->share_next : page->share_prev |
| 643 | if !other: |
| 644 | kPage_arch_update_mapping (t) |
| 645 | break |
| 646 | if page->share_next: |
| 647 | page->share_next->share_prev = page->share_prev |
| 648 | if page->share_prev: |
| 649 | page->share_prev->share_next = page->share_next |
| 650 | page->share_next = NULL |
| 651 | page->share_prev = NULL |
| 652 | other->check_payment () |
| 653 | else: |
| 654 | t->flags |= Iris::Page::FRAME |
| 655 | t->frame = raw_zalloc () |
| 656 | for unsigned i = 0; i < PAGE_SIZE; i += 4: |
| 657 | ((unsigned *)t->frame)[i >> 2] = d[i >> 2] |
| 658 | if c->data[0].h & Iris::Page::FORGET: |
| 659 | page->frame = NULL |
| 660 | page->flags &= ~Iris::Page::FRAME |
| 661 | kPage_arch_update_mapping (page) |
| 662 | else: |
| 663 | if t != page: |
| 664 | t->frame = page->frame |
| 665 | t->flags |= Iris::Page::FRAME |
| 666 | page->frame = NULL |
| 667 | page->flags &= ~Iris::Page::FRAME |
| 668 | kPage_arch_update_mapping (page) |
| 669 | else: |
| 670 | dpanic (0, "sharing page with itself...") |
| 671 | else: |
| 672 | if t == page: |
| 673 | dpanic (0, "sharing page with itself") |
| 674 | kPage_arch_update_mapping (t) |
| 675 | break |
| 676 | if c->data[0].h & Iris::Page::FORGET: |
| 677 | if ~page->flags & Iris::Page::SHARED: |
| 678 | if t->flags & Iris::Page::PAYING: |
| 679 | t->frame = page->frame |
| 680 | t->flags |= Iris::Page::FRAME |
| 681 | else: |
| 682 | dpanic (0, "move page failed because target is not paying") |
| 683 | page->frame = NULL |
| 684 | page->flags &= ~Iris::Page::FRAME |
| 685 | kPage_arch_update_mapping (page) |
| 686 | else: |
| 687 | t->share_prev = page->share_prev |
| 688 | t->share_next = page->share_next |
| 689 | if t->share_prev: |
| 690 | t->share_prev->share_next = t |
| 691 | if t->share_next: |
| 692 | t->share_next->share_prev = t |
| 693 | page->share_prev = NULL |
| 694 | page->share_next = NULL |
| 695 | page->forget () |
| 696 | t->check_payment () |
| 697 | else: |
| 698 | t->share_prev = page->share_prev |
| 699 | t->share_next = page |
| 700 | page->share_prev = t |
| 701 | if t->share_prev: |
| 702 | t->share_prev->share_next = t |
| 703 | t->frame = page->frame |
| 704 | t->flags |= Iris::Page::FRAME |
| 705 | kPage_arch_update_mapping (t) |
| 706 | break |
| 707 | case Iris::Page::GET_FLAGS & REQUEST_MASK: |
| 708 | reply_num (page->flags) |
| 709 | return |
| 710 | case Iris::Page::SET_FLAGS & REQUEST_MASK: |
| 711 | if cmd & Iris::Page::READONLY: |
| 712 | dpanic (0, "setting page flags denied") |
| 713 | reply_num (Iris::ERR_WRITE_DENIED) |
| 714 | return |
| 715 | // Always refuse to set reserved flags. |
| 716 | c->data[1].h &= ~(Iris::Page::PHYSICAL | Iris::Page::UNCACHED) |
| 717 | // Remember the old flags. |
| 718 | unsigned old = page->flags |
| 719 | // Compute the new flags. |
| 720 | page->flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h) |
| 721 | |
| 722 | // If we stop paying, see if the frame is still paid for. If not, free it. |
| 723 | if ~page->flags & old & Iris::Page::PAYING: |
| 724 | // Decrease the use counter in any case. |
| 725 | page->address_space->unuse () |
| 726 | page->check_payment () |
| 727 | |
| 728 | // If we start paying, increase the use counter. |
| 729 | if page->flags & ~old & Iris::Page::PAYING: |
| 730 | if !page->address_space->use(): |
| 731 | dpanic (0, "cannot pay for frame") |
| 732 | // If it doesn't work, refuse to set the flag, and refuse to allocate a frame. |
| 733 | page->flags &= ~(Iris::Page::PAYING | Iris::Page::FRAME) |
| 734 | // However, if there already was a frame, keep it. |
| 735 | if old & Iris::Page::FRAME: |
| 736 | page->flags |= Iris::Page::FRAME |
| 737 | |
| 738 | // If we want a frame, see if we can get it. |
| 739 | if ~old & page->flags & Iris::Page::FRAME: |
| 740 | if ~page->flags & Iris::Page::PAYING: |
| 741 | dpanic (0, "cannot have frame without paying") |
| 742 | page->flags &= ~Iris::Page::FRAME |
| 743 | else: |
| 744 | page->frame = page->address_space->zalloc () |
| 745 | kPage_arch_update_mapping (page) |
| 746 | // If we lose a frame, handle it. |
| 747 | if old & ~page->flags & Iris::Page::FRAME: |
| 748 | page->forget () |
| 749 | break |
| 750 | default: |
| 751 | dpanic (0, "invalid page operation") |
| 752 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 753 | return |
| 754 | if page->flags > 0x7f: |
| 755 | dpanic (page->flags, "weird output from page operation") |
| 756 | reply_num (0) |
| 757 | |
| 758 | static void print_cap (kCapRef cap, kCapRef self): |
| 759 | if cap.deref () == self.deref (): |
| 760 | kdebug ('{') |
| 761 | else: |
| 762 | kdebug ('[') |
| 763 | kdebug_num ((unsigned)cap.caps) |
| 764 | kdebug (':') |
| 765 | kdebug_num (cap.index, 1) |
| 766 | if !cap.valid (): |
| 767 | kdebug ('!') |
| 768 | else: |
| 769 | kdebug ('=') |
| 770 | kdebug_num ((unsigned)cap->target) |
| 771 | kdebug (':') |
| 772 | kdebug_num (cap->protected_data.l) |
| 773 | for kCapRef c = cap->children; c.valid (); c = c->sibling_next: |
| 774 | print_cap (c, self) |
| 775 | if cap.deref () == self.deref (): |
| 776 | kdebug ('}') |
| 777 | else: |
| 778 | kdebug (']') |
| 779 | |
| 780 | static void caps_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 781 | kCaps *caps = (kCapsP)protected_data.l |
| 782 | switch cmd: |
| 783 | case Iris::Caps::GET & REQUEST_MASK: |
| 784 | if c->data[1].l >= caps->size: |
| 785 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 786 | kdebug_num ((unsigned)caps) |
| 787 | kdebug (" size: ") |
| 788 | kdebug_num (caps->size) |
| 789 | kdebug ('\n') |
| 790 | dpanic (c->data[1].l, "invalid index for get caps") |
| 791 | return |
| 792 | kCapability *ret = caps->cap (c->data[1].l) |
| 793 | #if 0 |
| 794 | kdebug_num ((unsigned)caps) |
| 795 | kdebug (" get cap ") |
| 796 | kdebug_num (c->data[1].l) |
| 797 | kdebug (" = ") |
| 798 | kdebug_num ((unsigned)ret->target) |
| 799 | kdebug ("/") |
| 800 | kdebug_num (ret->protected_data.h) |
| 801 | kdebug (":") |
| 802 | kdebug_num (ret->protected_data.l) |
| 803 | kdebug ("\n") |
| 804 | #endif |
| 805 | reply_cap ((unsigned)ret->target, ret->protected_data, ((unsigned)ret->target & ~KERNEL_MASK) == 0 ? &((kObject *)ret->protected_data.l)->refs : &ret->target->capabilities) |
| 806 | return |
| 807 | case Iris::Caps::GET_SIZE & REQUEST_MASK: |
| 808 | reply_num (caps->size) |
| 809 | return |
| 810 | case Iris::Caps::SET & REQUEST_MASK: |
| 811 | if c->data[1].l >= caps->size: |
| 812 | dpanic (0, "invalid index for set caps") |
| 813 | return |
| 814 | caps->clone (c->data[1].l, c->arg, c->copy[1]) |
| 815 | reply_num (0) |
| 816 | //kdebug_num ((unsigned)caps) |
| 817 | //kdebug (" set cap ") |
| 818 | //kdebug_num (c->data[1].l) |
| 819 | //kdebug (" to ") |
| 820 | //kdebug_num ((unsigned)caps->caps[c->data[1].l].target) |
| 821 | //kdebug ("/") |
| 822 | //kdebug_num (caps->caps[c->data[1].l].protected_data.h) |
| 823 | //kdebug (":") |
| 824 | //kdebug_num (caps->caps[c->data[1].l].protected_data.l) |
| 825 | //kdebug ("\n") |
| 826 | return |
| 827 | case Iris::Caps::TRUNCATE & REQUEST_MASK: |
| 828 | dpanic (0, "truncate caps is not implemented yet.") |
| 829 | return |
| 830 | case Iris::Caps::PRINT & REQUEST_MASK: |
| 831 | if c->data[1].l >= caps->size: |
| 832 | dpanic (0, "invalid caps for print") |
| 833 | return |
| 834 | kCapRef cap (caps, c->data[1].l) |
| 835 | kCapRef orig (caps, c->data[1].l) |
| 836 | while cap->parent.valid (): |
| 837 | while cap->sibling_prev.valid (): |
| 838 | if cap->parent.deref () != cap->sibling_prev->parent.deref (): |
| 839 | dpanic (0, "parent problem in cap data") |
| 840 | return |
| 841 | if cap.deref () != cap->sibling_prev->sibling_next.deref (): |
| 842 | dpanic (0, "prev error in cap data") |
| 843 | return |
| 844 | cap = cap->sibling_prev |
| 845 | if cap->parent->children.deref () != cap.deref (): |
| 846 | dpanic (0, "parent error in cap data") |
| 847 | return |
| 848 | cap = cap->parent |
| 849 | while cap->sibling_prev.valid (): |
| 850 | if cap->parent.deref () != cap->sibling_prev->parent.deref (): |
| 851 | dpanic (0, "parent parent problem in cap data") |
| 852 | return |
| 853 | if cap.deref () != cap->sibling_prev->sibling_next.deref (): |
| 854 | dpanic (0, "parent prev error in cap data") |
| 855 | return |
| 856 | cap = cap->sibling_prev |
| 857 | while cap.valid (): |
| 858 | print_cap (cap, orig) |
| 859 | cap = cap->sibling_next |
| 860 | kdebug ('\n') |
| 861 | return |
| 862 | default: |
| 863 | dpanic (cmd, "invalid caps operation") |
| 864 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 865 | return |
| 866 | |
| 867 | static void list_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 868 | kList *list = (kListP)protected_data.l |
| 869 | if cmd == Iris::List::SET_CB & REQUEST_MASK: |
| 870 | list->owner.clone (0, c->arg, c->copy[1]) |
| 871 | return |
| 872 | kListitem *item |
| 873 | if !c->arg.valid (): |
| 874 | item = NULL |
| 875 | else: |
| 876 | if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM: |
| 877 | dpanic (0, "invalid request for list: arg is no listitem") |
| 878 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 879 | return |
| 880 | item = (kListitem *)c->arg->protected_data.l |
| 881 | if item->list != list: |
| 882 | dpanic (0, "item list is not equal to called object") |
| 883 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 884 | return |
| 885 | switch cmd: |
| 886 | case Iris::List::GET_NEXT & REQUEST_MASK: |
| 887 | if !item: |
| 888 | item = list->first_listitem |
| 889 | else: |
| 890 | if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Iris::Listitem::LIST: |
| 891 | dpanic (0, "trying to get next listitem with insufficient rights") |
| 892 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 893 | return |
| 894 | item = item->next_item |
| 895 | if !item: |
| 896 | reply_num (~0) |
| 897 | return |
| 898 | reply_cap (CAPTYPE_LISTITEM | Iris::Listitem::LIST, (unsigned)item, &item->refs) |
| 899 | return |
| 900 | case Iris::List::ADD_ITEM & REQUEST_MASK: |
| 901 | if !item: |
| 902 | dpanic (0, "invalid request: no listitem for List::ADD_ITEM") |
| 903 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 904 | return |
| 905 | if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Iris::Listitem::ADD: |
| 906 | dpanic (0, "trying to add listitem with insufficient rights") |
| 907 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 908 | return |
| 909 | ((kListitem *)c->arg->protected_data.l)->add (list) |
| 910 | break |
| 911 | case Iris::List::GET_INFO & REQUEST_MASK: |
| 912 | if !item: |
| 913 | dpanic (0, "no item for List::GET_INFO") |
| 914 | reply_num (Iris::ERR_INVALID_ARGUMENT, ~0, ~0) |
| 915 | return |
| 916 | reply_num (item->info) |
| 917 | return |
| 918 | case Iris::List::SET_INFO & REQUEST_MASK: |
| 919 | if !item: |
| 920 | dpanic (0, "no item for List::SET_INFO") |
| 921 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 922 | return |
| 923 | item->info = c->data[1] |
| 924 | break |
| 925 | case Iris::List::GET_CAP & REQUEST_MASK: |
| 926 | if !item: |
| 927 | dpanic (0, "no item for List::GET_CAP") |
| 928 | reply_num (Iris::ERR_INVALID_ARGUMENT) |
| 929 | return |
| 930 | kCapability *cap = item->target.cap (0) |
| 931 | reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities) |
| 932 | return |
| 933 | default: |
| 934 | dpanic (0, "invalid list operation") |
| 935 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 936 | return |
| 937 | reply_num (0) |
| 938 | |
| 939 | static void listitem_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 940 | kListitem *item = (kListitemP)protected_data.l |
| 941 | switch cmd: |
| 942 | case Iris::Listitem::CLEAR & REQUEST_MASK: |
| 943 | // Disable linked capability. |
| 944 | item->add (NULL) |
| 945 | break |
| 946 | case Iris::Listitem::SET_CAP & REQUEST_MASK: |
| 947 | // Set linked capability. |
| 948 | item->target.clone (0, c->arg, c->copy[1]) |
| 949 | break |
| 950 | default: |
| 951 | dpanic (0, "invalid listitem operation") |
| 952 | reply_num (Iris::ERR_INVALID_OPERATION) |
| 953 | return |
| 954 | reply_num (0) |
| 955 | |
| 956 | static void kill_reply (kReceiver *r): |
| 957 | kCapRef cap = r->refs |
| 958 | while cap.valid (): |
| 959 | kCapability *c = cap.deref () |
| 960 | cap = c->sibling_next |
| 961 | if (unsigned)c->target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY): |
| 962 | c->invalidate () |
| 963 | |
| 964 | static void kernel_invoke (unsigned target, Iris::Num protected_data, kCapability::Context *c): |
| 965 | // Kernel calling convention: |
| 966 | // data[0].l is the request. |
| 967 | // reply is the reply capability, or (for call capabilities) the target to call. |
| 968 | // other parameters' meanings depend on the operation. |
| 969 | if target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL_ASYNC): |
| 970 | // This is a call capability. reply is the capability to call. |
| 971 | kReceiver *owner = (kReceiver *)protected_data.l |
| 972 | owner->protected_only = target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL) |
| 973 | if must_wait: |
| 974 | old_current->wait () |
| 975 | if !reply_target: |
| 976 | if (c->reply.index & ~CAP_COPY) != CAP_NONE: |
| 977 | kdebug ("target index: ") |
| 978 | kdebug_num (c->reply.index) |
| 979 | kdebug ("\n") |
| 980 | dpanic (0x54635675, "no target to call") |
| 981 | return |
| 982 | if ((unsigned)reply_target & ~KERNEL_MASK) != 0: |
| 983 | // This is a user-implemented object. Create a real reply capability. |
| 984 | kReceiver *call_target = reply_target |
| 985 | c->reply = kCapRef (&reply_caps, 0) |
| 986 | c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Iris::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs) |
| 987 | c->copy[0] = true |
| 988 | call_target->send_message (reply_protected, c) |
| 989 | c->reply->invalidate () |
| 990 | else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY): |
| 991 | // Reply capability: destroy all before invoke. |
| 992 | kReceiver *r = (kReceiver *)reply_protected.l |
| 993 | kill_reply (r) |
| 994 | r->send_message (r->reply_protected_data, c) |
| 995 | else: |
| 996 | // Kernel call: don't create actual capablities. |
| 997 | kCapRef call_target = c->reply |
| 998 | c->reply.reset () |
| 999 | reply_target = (kReceiver *)protected_data.l |
| 1000 | reply_protected = reply_target->reply_protected_data |
| 1001 | kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c) |
| 1002 | return |
| 1003 | if must_wait: |
| 1004 | old_current->wait () |
| 1005 | if target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY): |
| 1006 | // This is a reply capability. |
| 1007 | kReceiver *r = (kReceiver *)protected_data.l |
| 1008 | kill_reply (r) |
| 1009 | r->send_message (r->reply_protected_data, c) |
| 1010 | return |
| 1011 | if !target: |
| 1012 | return |
| 1013 | unsigned cmd |
| 1014 | if (target & REQUEST_MASK) == CAP_MASTER: |
| 1015 | if c->data[0].l & CAP_MASTER_CREATE: |
| 1016 | reply_cap (target | (c->data[0].l & REQUEST_MASK), protected_data, &((kObject *)protected_data.l)->refs) |
| 1017 | return |
| 1018 | cmd = c->data[0].l |
| 1019 | c->data[0].l = 0 |
| 1020 | else: |
| 1021 | cmd = target |
| 1022 | cmd &= REQUEST_MASK |
| 1023 | switch target & CAPTYPE_MASK: |
| 1024 | case CAPTYPE_RECEIVER: |
| 1025 | receiver_invoke (cmd, target, protected_data, c) |
| 1026 | break |
| 1027 | case CAPTYPE_MEMORY: |
| 1028 | memory_invoke (cmd, target, protected_data, c) |
| 1029 | break |
| 1030 | case CAPTYPE_THREAD: |
| 1031 | thread_invoke (cmd, target, protected_data, c) |
| 1032 | break |
| 1033 | case CAPTYPE_PAGE: |
| 1034 | page_invoke (cmd, target, protected_data, c) |
| 1035 | break |
| 1036 | case CAPTYPE_CAPS: |
| 1037 | caps_invoke (cmd, target, protected_data, c) |
| 1038 | break |
| 1039 | case CAPTYPE_LIST: |
| 1040 | list_invoke (cmd, target, protected_data, c) |
| 1041 | break |
| 1042 | case CAPTYPE_LISTITEM: |
| 1043 | listitem_invoke (cmd, target, protected_data, c) |
| 1044 | break |
| 1045 | default: |
| 1046 | panic (0x99337744, "invalid capability type invoked") |
| 1047 | return |
| 1048 | return |
| 1049 | |
| 1050 | void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c): |
| 1051 | if dbg_code.l && old_current->id != 1: |
| 1052 | log_message ("invoke", (unsigned)target, protected_data.l, c) |
| 1053 | if (unsigned)target & ~KERNEL_MASK: |
| 1054 | // This is not a kernel capability: send a message to the receiver. |
| 1055 | if must_wait: |
| 1056 | old_current->wait () |
| 1057 | //else |
| 1058 | // log_message ("user invoke", (unsigned)target, protected_data.l, c) |
| 1059 | target->send_message (protected_data, c) |
| 1060 | return |
| 1061 | // This is a kernel capability. Use a function to allow optimized call capabilities. |
| 1062 | //if !must_wait && old_current->id == ~0 |
| 1063 | // log_message ("kernel invoke", (unsigned)target, protected_data.l, c) |
| 1064 | context = c |
| 1065 | if c->reply.valid (): |
| 1066 | reply_target = c->reply->target |
| 1067 | reply_protected = c->reply->protected_data |
| 1068 | else: |
| 1069 | reply_target = NULL |
| 1070 | reply_protected.l = 0 |
| 1071 | kernel_invoke ((unsigned)target, protected_data, c) |
| 1072 |
Branches:
master
