Root/
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // iris.hhp: header file for userspace programs. |
| 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 | #ifndef __IRIS_HHP |
| 20 | #define __IRIS_HHP |
| 21 | |
| 22 | // Without the standard library, we don't have this definition. |
| 23 | // I preferred ((void*)0), but C++ has too strict type-checking to |
| 24 | // make that work. |
| 25 | #ifndef NULL |
| 26 | #define NULL 0 |
| 27 | #endif |
| 28 | |
| 29 | // Number of clock interrupts per second. |
| 30 | #define HZ 100 |
| 31 | |
| 32 | #define PAGE_BITS (12) |
| 33 | #define PAGE_SIZE (1 << PAGE_BITS) |
| 34 | #define PAGE_MASK (~(PAGE_SIZE - 1)) |
| 35 | |
| 36 | #define KERNEL_MASK 0xfff |
| 37 | #define CAPTYPE_MASK 0xe00 |
| 38 | #define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK) |
| 39 | #define CAPTYPE_INVALID 0x000 |
| 40 | #define CAPTYPE_RECEIVER 0x200 |
| 41 | #define CAPTYPE_MEMORY 0x400 |
| 42 | #define CAPTYPE_THREAD 0x600 |
| 43 | #define CAPTYPE_PAGE 0x800 |
| 44 | #define CAPTYPE_CAPS 0xa00 |
| 45 | #define CAPTYPE_LIST 0xc00 |
| 46 | #define CAPTYPE_LISTITEM 0xe00 |
| 47 | |
| 48 | // All kernel capabilities have a master capability, which can create others. |
| 49 | #define CAP_MASTER 0 |
| 50 | |
| 51 | // Create, invoke and forget, with masked data set to 0. |
| 52 | #define CAP_MASTER_DIRECT 0 |
| 53 | // Master capabilities can create others. |
| 54 | #define CAP_MASTER_CREATE (1 << 31) |
| 55 | |
| 56 | #define __caps_num 0 |
| 57 | #define __receiver_num 1 |
| 58 | #define __thread_num 2 |
| 59 | #define __memory_num 3 |
| 60 | #define __call_num 4 |
| 61 | #define __parent_num 5 |
| 62 | |
| 63 | // If this flag is set in a capability, it is copied instead of mapped. |
| 64 | // If it is set in the target capability, the Thread waits after the request. |
| 65 | #define CAP_COPY ((unsigned)0x80000000) |
| 66 | // This constant signifies that no capability is passed. |
| 67 | #define CAP_NONE (~CAP_COPY) |
| 68 | |
| 69 | namespace Iris: |
| 70 | struct Parent |
| 71 | enum Exception_code: |
| 72 | NO_ERROR |
| 73 | ERR_WRITE_DENIED |
| 74 | ERR_UNMAPPED_READ |
| 75 | ERR_UNMAPPED_WRITE |
| 76 | ERR_INVALID_ADDRESS_READ |
| 77 | ERR_INVALID_ADDRESS_WRITE |
| 78 | ERR_RESERVED_INSTRUCTION |
| 79 | ERR_COPROCESSOR_UNUSABLE |
| 80 | ERR_OVERFLOW |
| 81 | ERR_TRAP |
| 82 | ERR_WATCHPOINT |
| 83 | ERR_BREAKPOINT |
| 84 | ERR_NO_PAGE_DIRECTORY |
| 85 | ERR_NO_PAGE_TABLE |
| 86 | ERR_OUT_OF_MEMORY |
| 87 | // The following are not raised, but returned. |
| 88 | ERR_INVALID_OPERATION |
| 89 | ERR_INVALID_ARGUMENT |
| 90 | NUM_EXCEPTION_CODES |
| 91 | |
| 92 | #ifndef NDEBUG |
| 93 | static inline const char *exception_name(int code): |
| 94 | const char *names[] = { |
| 95 | "no error", |
| 96 | "write denied", |
| 97 | "unmapped read", |
| 98 | "unmapped write", |
| 99 | "invalid address read", |
| 100 | "invalid address write", |
| 101 | "reserved instruction", |
| 102 | "coprocessor unusable", |
| 103 | "overflow", |
| 104 | "trap", |
| 105 | "watchpoint", |
| 106 | "breakpoint", |
| 107 | "no page directory", |
| 108 | "no page table", |
| 109 | "out of memory", |
| 110 | "invalid operation" |
| 111 | } |
| 112 | return names[code] |
| 113 | #endif |
| 114 | |
| 115 | struct Num: |
| 116 | unsigned l, h |
| 117 | inline Num (unsigned long long n = 0) : l (n), h (n >> 32): |
| 118 | inline Num (unsigned ll, unsigned hh) : l (ll), h (hh): |
| 119 | inline unsigned long long value () const: |
| 120 | return ((unsigned long long)h << 32) | l |
| 121 | inline unsigned &low (): |
| 122 | return l |
| 123 | inline unsigned &high (): |
| 124 | return h |
| 125 | inline unsigned const &low () const: |
| 126 | return l |
| 127 | inline unsigned const &high () const: |
| 128 | return h |
| 129 | |
| 130 | struct Cap |
| 131 | struct Caps |
| 132 | struct Receiver |
| 133 | struct Thread |
| 134 | struct Page |
| 135 | struct Memory |
| 136 | struct List |
| 137 | |
| 138 | void print_caps () |
| 139 | unsigned alloc_slot () |
| 140 | Cap alloc_cap () |
| 141 | void free_slot (unsigned slot) |
| 142 | void free_cap (Cap cap) |
| 143 | extern bool enable_debug |
| 144 | |
| 145 | struct Cap: |
| 146 | unsigned code |
| 147 | inline Cap copy () const |
| 148 | inline Cap () |
| 149 | explicit inline Cap (unsigned c) |
| 150 | inline Cap (unsigned slot, unsigned idx) |
| 151 | inline unsigned slot () const |
| 152 | inline unsigned idx () const |
| 153 | struct IMessage |
| 154 | inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE)) |
| 155 | inline Num call (Num d0 = 0, Num d1 = 0) |
| 156 | inline Num icall (Num d0 = 0, Num d1 = 0) |
| 157 | inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0) |
| 158 | inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0) |
| 159 | inline void _invoke (IMessage const *i) |
| 160 | inline void _call (IMessage *i) |
| 161 | |
| 162 | struct __recv_data_t: |
| 163 | Num data[2] |
| 164 | Num protected_data |
| 165 | Cap reply, arg |
| 166 | |
| 167 | extern Caps my_caps |
| 168 | extern Receiver my_receiver |
| 169 | extern Thread my_thread |
| 170 | extern Memory my_memory |
| 171 | extern Cap my_call |
| 172 | extern Parent my_parent |
| 173 | extern __recv_data_t recv |
| 174 | |
| 175 | inline Cap get_reply (): |
| 176 | Cap ret = recv.reply |
| 177 | recv.reply = alloc_cap () |
| 178 | return ret |
| 179 | inline Cap get_arg (): |
| 180 | Cap ret = recv.arg |
| 181 | recv.arg = alloc_cap () |
| 182 | return ret |
| 183 | inline void set_recv_arg (Cap c): |
| 184 | free_cap (recv.arg) |
| 185 | recv.arg = c |
| 186 | |
| 187 | struct Cap::IMessage: |
| 188 | Num data[2] |
| 189 | Cap reply, arg |
| 190 | Cap Cap::copy () const: |
| 191 | return Cap (code | CAP_COPY) |
| 192 | Cap::Cap () : code (CAP_NONE): |
| 193 | Cap::Cap (unsigned c) : code (c): |
| 194 | Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)): |
| 195 | unsigned Cap::slot () const: |
| 196 | return (code >> 16) & 0x7fff |
| 197 | unsigned Cap::idx () const: |
| 198 | return code & 0xffff |
| 199 | void Cap::_invoke (IMessage const *i): |
| 200 | __recv_data_t *r = &recv |
| 201 | __asm__ volatile ("lw $v0, %1\n" |
| 202 | "\tlw $a0, 0($v0)\n" |
| 203 | "\tlw $a1, 4($v0)\n" |
| 204 | "\tlw $a2, 8($v0)\n" |
| 205 | "\tlw $a3, 12($v0)\n" |
| 206 | "\tlw $t0, 16($v0)\n" |
| 207 | "\tlw $t1, 20($v0)\n" |
| 208 | "\tlw $v0, %2\n" |
| 209 | "\tlw $t2, 24($v0)\n" |
| 210 | "\tlw $t3, 28($v0)\n" |
| 211 | "\tlw $v0, %0\n" |
| 212 | "\tsyscall\n" |
| 213 | "\tlw $v0, %2\n" |
| 214 | "\tsw $a0, 0($v0)\n" |
| 215 | "\tsw $a1, 4($v0)\n" |
| 216 | "\tsw $a2, 8($v0)\n" |
| 217 | "\tsw $a3, 12($v0)\n" |
| 218 | "\tsw $t0, 16($v0)\n" |
| 219 | "\tsw $t1, 20($v0)" |
| 220 | :: "m"(code), "m"(i), "m"(r) |
| 221 | : "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3") |
| 222 | void Cap::_call (IMessage *i): |
| 223 | i->reply = *this |
| 224 | my_call.copy ()._invoke (i) |
| 225 | void Cap::invoke (Num d0, Num d1, Cap arg): |
| 226 | IMessage i |
| 227 | i.data[0] = d0 |
| 228 | i.data[1] = d1 |
| 229 | i.reply = Cap (CAP_NONE) |
| 230 | i.arg = arg |
| 231 | _invoke (&i) |
| 232 | Num Cap::call (Num d0, Num d1): |
| 233 | IMessage i |
| 234 | i.data[0] = d0 |
| 235 | i.data[1] = d1 |
| 236 | i.arg = Cap (CAP_NONE) |
| 237 | _call (&i) |
| 238 | return recv.data[0] |
| 239 | Num Cap::icall (Num d0, Num d1): |
| 240 | IMessage i |
| 241 | i.data[0] = d0 |
| 242 | i.data[1] = d1 |
| 243 | i.arg = Cap (CAP_NONE) |
| 244 | _call (&i) |
| 245 | return recv.data[0] |
| 246 | Num Cap::ocall (Cap c, Num d0, Num d1): |
| 247 | IMessage i |
| 248 | i.data[0] = d0 |
| 249 | i.data[1] = d1 |
| 250 | i.arg = c |
| 251 | _call (&i) |
| 252 | return recv.data[0] |
| 253 | Num Cap::iocall (Cap c, Num d0, Num d1): |
| 254 | IMessage i |
| 255 | i.data[0] = d0 |
| 256 | i.data[1] = d1 |
| 257 | i.arg = c |
| 258 | _call (&i) |
| 259 | return recv.data[0] |
| 260 | |
| 261 | struct Receiver : public Cap: |
| 262 | Receiver (unsigned slot, unsigned idx) : Cap (slot, idx): |
| 263 | Receiver (Cap c = Cap ()) : Cap (c): |
| 264 | enum request: |
| 265 | // Operations |
| 266 | SET_OWNER = CAPTYPE_RECEIVER + 1 |
| 267 | CREATE_CAPABILITY |
| 268 | CREATE_CALL_CAPABILITY |
| 269 | CREATE_ASYNC_CALL_CAPABILITY |
| 270 | GET_PROTECTED |
| 271 | GET_REPLY_PROTECTED_DATA |
| 272 | SET_REPLY_PROTECTED_DATA |
| 273 | GET_ALARM |
| 274 | SET_ALARM |
| 275 | ADD_ALARM |
| 276 | // Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability. |
| 277 | REPLY |
| 278 | // A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY. |
| 279 | CALL |
| 280 | // A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY. |
| 281 | CALL_ASYNC |
| 282 | void set_owner (Cap owner): |
| 283 | ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER) |
| 284 | Cap create_capability (Num protected_data): |
| 285 | icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) |
| 286 | return get_arg () |
| 287 | Num get_protected (Cap target): |
| 288 | return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED) |
| 289 | Num get_reply_protected_data (): |
| 290 | return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) |
| 291 | void set_reply_protected_data (Num data): |
| 292 | call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data) |
| 293 | unsigned get_alarm (): |
| 294 | return call (CAP_MASTER_DIRECT | GET_ALARM).l |
| 295 | unsigned add_alarm (unsigned data): |
| 296 | return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l |
| 297 | void set_alarm (unsigned data): |
| 298 | call (CAP_MASTER_DIRECT | SET_ALARM, data) |
| 299 | inline void sleep (unsigned value) |
| 300 | Cap create_call_capability (): |
| 301 | icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY) |
| 302 | return get_arg () |
| 303 | Cap create_async_call_capability (): |
| 304 | icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY) |
| 305 | return get_arg () |
| 306 | |
| 307 | struct Thread : public Cap: |
| 308 | Thread (unsigned slot, unsigned idx) : Cap (slot, idx): |
| 309 | Thread (Cap c = Cap ()) : Cap (c): |
| 310 | enum request: |
| 311 | // Info details are arch-specific. |
| 312 | GET_INFO = CAPTYPE_THREAD + 1 |
| 313 | SET_INFO |
| 314 | USE_SLOT |
| 315 | GET_CAPS |
| 316 | SCHEDULE |
| 317 | PRIV_ALLOC_RANGE |
| 318 | PRIV_PHYSICAL_ADDRESS |
| 319 | PRIV_ALLOC_PHYSICAL |
| 320 | PRIV_MAKE_PRIV |
| 321 | PRIV_GET_TOP_MEMORY |
| 322 | PRIV_REGISTER_INTERRUPT |
| 323 | // This is not an operation, but having this capability allows using the thread in Receiver::set_owner. |
| 324 | SET_OWNER |
| 325 | DBG_SEND |
| 326 | PRIV_REBOOT |
| 327 | PRIV_POWEROFF |
| 328 | PRIV_SUSPEND |
| 329 | PRIV_BOOT |
| 330 | PRIV_PANIC |
| 331 | // These get/set_info are not arch-specific. |
| 332 | enum info_type: |
| 333 | PC = ~0 |
| 334 | SP = ~1 |
| 335 | FLAGS = ~2 |
| 336 | // These are arch-specific. |
| 337 | AT = 1 |
| 338 | V0 |
| 339 | V1 |
| 340 | A0 |
| 341 | A1 |
| 342 | A2 |
| 343 | A3 |
| 344 | T0 |
| 345 | T1 |
| 346 | T2 |
| 347 | T3 |
| 348 | T4 |
| 349 | T5 |
| 350 | T6 |
| 351 | T7 |
| 352 | S0 |
| 353 | S1 |
| 354 | S2 |
| 355 | S3 |
| 356 | S4 |
| 357 | S5 |
| 358 | S6 |
| 359 | S7 |
| 360 | T8 |
| 361 | T9 |
| 362 | K0 |
| 363 | K1 |
| 364 | GP |
| 365 | SP_ |
| 366 | FP |
| 367 | RA |
| 368 | enum flags: |
| 369 | PRIV = 1 << 31 |
| 370 | WAITING = 1 << 30 |
| 371 | RUNNING = 1 << 29 |
| 372 | USER_FLAGS = ~(PRIV | WAITING | RUNNING) |
| 373 | void make_priv (): |
| 374 | my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV) |
| 375 | unsigned get_info (unsigned info): |
| 376 | return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l |
| 377 | void set_info (unsigned info, unsigned value, unsigned mask = ~0): |
| 378 | call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask)) |
| 379 | void set_pc (unsigned pc): |
| 380 | set_info (PC, pc) |
| 381 | void set_sp (unsigned sp): |
| 382 | set_info (SP, sp) |
| 383 | void set_flags (unsigned set, unsigned reset = 0): |
| 384 | set_info (FLAGS, set, set | reset) |
| 385 | unsigned get_pc (): |
| 386 | return get_info (PC) |
| 387 | unsigned get_sp (): |
| 388 | return get_info (SP) |
| 389 | unsigned get_flags (): |
| 390 | return get_info (FLAGS) |
| 391 | void run (bool run = true): |
| 392 | set_flags (run ? RUNNING : 0, run ? 0 : RUNNING) |
| 393 | void wait (bool wait): |
| 394 | set_flags (wait ? WAITING : 0, wait ? 0 : WAITING) |
| 395 | inline unsigned use (Caps caps, unsigned slot = alloc_slot ()) |
| 396 | inline Caps get_caps (unsigned slot) |
| 397 | unsigned get_num_caps (): |
| 398 | return call (CAP_MASTER_DIRECT | GET_CAPS, ~0).l |
| 399 | |
| 400 | struct Caps : public Cap: |
| 401 | Caps (unsigned slot, unsigned idx) : Cap (slot, idx): |
| 402 | Caps (Cap c = Cap ()) : Cap (c): |
| 403 | enum request: |
| 404 | // Not an operation; this capability can be used in Thread::USE_SLOT. |
| 405 | USE = CAPTYPE_CAPS + 1 |
| 406 | GET |
| 407 | GET_SIZE |
| 408 | SET |
| 409 | TRUNCATE |
| 410 | |
| 411 | unsigned use (unsigned slot = alloc_slot ()): |
| 412 | return my_thread.use (*this, slot) |
| 413 | Cap get (unsigned idx): |
| 414 | call (CAP_MASTER_DIRECT | GET, idx) |
| 415 | return get_arg () |
| 416 | unsigned get_size (): |
| 417 | return call (CAP_MASTER_DIRECT | GET_SIZE).l |
| 418 | void set (unsigned idx, Cap cap): |
| 419 | ocall (cap, CAP_MASTER_DIRECT | SET, idx) |
| 420 | void truncate (unsigned new_size): |
| 421 | call (CAP_MASTER_DIRECT | TRUNCATE, new_size) |
| 422 | void print (unsigned idx): |
| 423 | invoke (CAP_MASTER_DIRECT | PRINT, idx) |
| 424 | |
| 425 | Caps Thread::get_caps (unsigned slot): |
| 426 | call (CAP_MASTER_DIRECT | GET_CAPS, slot) |
| 427 | return get_arg () |
| 428 | |
| 429 | unsigned Thread::use (Caps caps, unsigned slot): |
| 430 | ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot) |
| 431 | return slot |
| 432 | |
| 433 | struct Page : public Cap: |
| 434 | Page (unsigned slot, unsigned idx) : Cap (slot, idx): |
| 435 | Page (Cap c = Cap ()) : Cap (c): |
| 436 | enum request: |
| 437 | SHARE = CAPTYPE_PAGE + 1 |
| 438 | GET_FLAGS |
| 439 | SET_FLAGS |
| 440 | // Not an operation; a capability with this bit cannot write to the page. |
| 441 | READONLY = 8 |
| 442 | enum share_detail: |
| 443 | // Operation details for PAGE_SHARE |
| 444 | // Forget the source page during the operation. This makes it a move. |
| 445 | FORGET = 1 |
| 446 | // Make the target independent of the source (make a copy if needed). |
| 447 | COPY = 2 |
| 448 | // Make the target unwritable. |
| 449 | //READONLY: use the value from request. |
| 450 | enum flag_values: |
| 451 | // This is a read-only flag, which is set if the Page is shared. |
| 452 | SHARED = 1 |
| 453 | // When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them. |
| 454 | PAYING = 2 |
| 455 | // Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems. |
| 456 | FRAME = 4 |
| 457 | // A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request. |
| 458 | //READONLY = 8 |
| 459 | // If this flag is set, the page is or will be mapped read-only. |
| 460 | MAPPED_READONLY = 0x10 |
| 461 | // This is a read-only flag, saying if this is physical memory, which mustn't be freed. |
| 462 | PHYSICAL = 0x20 |
| 463 | // This is a read-only flag, saying if this is uncachable memory. |
| 464 | UNCACHED = 0x40 |
| 465 | void share (Cap target, unsigned flags = 0): |
| 466 | ocall (target, Num (CAP_MASTER_DIRECT | SHARE, flags)) |
| 467 | unsigned get_flags (): |
| 468 | return call (CAP_MASTER_DIRECT | GET_FLAGS).l |
| 469 | bool set_flags (unsigned set, unsigned reset = 0): |
| 470 | call (CAP_MASTER_DIRECT | SET_FLAGS, Num (set, set | reset)) |
| 471 | return recv.data[0].l == NO_ERROR |
| 472 | unsigned long physical_address (): |
| 473 | return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l |
| 474 | void alloc_physical (unsigned long address, bool cachable, bool freeable): |
| 475 | my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0)) |
| 476 | |
| 477 | struct Listitem : public Cap: |
| 478 | Listitem (Cap c = Cap ()) : Cap (c): |
| 479 | enum request: |
| 480 | CLEAR = CAPTYPE_LISTITEM + 1 |
| 481 | SET_CAP |
| 482 | ADD |
| 483 | LIST |
| 484 | // Remove the listitem from its list. |
| 485 | void clear (): |
| 486 | call (CAP_MASTER_DIRECT | CLEAR) |
| 487 | // Set the capability of an item. |
| 488 | void set_cap (Cap c): |
| 489 | call (CAP_MASTER_DIRECT | SET_CAP, c.code) |
| 490 | // To add a listitem to a list, the listitem capability must be of type ADD or MASTER. |
| 491 | // A list iterator must be of type LIST or MASTER |
| 492 | |
| 493 | struct List : public Cap: |
| 494 | List (Cap c = Cap ()) : Cap (c): |
| 495 | enum request: |
| 496 | GET_NEXT = CAPTYPE_LIST + 1 |
| 497 | SET_CB |
| 498 | ADD_ITEM |
| 499 | GET_INFO |
| 500 | SET_INFO |
| 501 | GET_CAP |
| 502 | // Get the next listitem from the given one. Use this to loop over all listitems. |
| 503 | Listitem get_next (Listitem current = Listitem ()): |
| 504 | iocall (current, CAP_MASTER_DIRECT | GET_NEXT) |
| 505 | if recv.data[0].l: |
| 506 | return Cap () |
| 507 | return get_arg () |
| 508 | // Set the callback. This is called when an item is removed from the list. |
| 509 | // When called, data[0] is 0 when the list is now empty; 1 otherwise. data[1] is the removed item's info. |
| 510 | void set_cb (Cap cb): |
| 511 | ocall (cb, CAP_MASTER_DIRECT | SET_CB) |
| 512 | // Add an item to the front of the list. |
| 513 | void add_item (Listitem item): |
| 514 | ocall (item, CAP_MASTER_DIRECT | ADD_ITEM) |
| 515 | // Return item info. |
| 516 | Num get_info (Listitem item): |
| 517 | return ocall (item, CAP_MASTER_DIRECT | GET_INFO) |
| 518 | // Set item info. |
| 519 | void set_info (Listitem item, Num info): |
| 520 | ocall (item, CAP_MASTER_DIRECT | SET_INFO, info) |
| 521 | // Get item capability. |
| 522 | Cap get_cap (Listitem item): |
| 523 | iocall (item, CAP_MASTER_DIRECT | GET_CAP) |
| 524 | return get_arg () |
| 525 | |
| 526 | struct Memory : public Cap: |
| 527 | Memory (unsigned slot, unsigned idx) : Cap (slot, idx): |
| 528 | Memory (Cap c = Cap ()) : Cap (c): |
| 529 | enum request: |
| 530 | CREATE = CAPTYPE_MEMORY + 1 |
| 531 | DESTROY |
| 532 | LIST |
| 533 | MAP |
| 534 | MAPPING |
| 535 | GET_LIMIT |
| 536 | SET_LIMIT |
| 537 | Page create_page (): |
| 538 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE)) |
| 539 | return get_arg () |
| 540 | Thread create_thread (unsigned slots): |
| 541 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots) |
| 542 | return get_arg () |
| 543 | Receiver create_receiver (): |
| 544 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER)) |
| 545 | return get_arg () |
| 546 | Memory create_memory (): |
| 547 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY)) |
| 548 | return get_arg () |
| 549 | Caps create_caps (unsigned size): |
| 550 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size) |
| 551 | return get_arg () |
| 552 | List create_list (): |
| 553 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_LIST)) |
| 554 | return get_arg () |
| 555 | Listitem create_listitem (): |
| 556 | icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_LISTITEM)) |
| 557 | return get_arg () |
| 558 | void destroy (Cap target): |
| 559 | ocall (target, CAP_MASTER_DIRECT | DESTROY) |
| 560 | // TODO: LIST |
| 561 | bool map (Cap page, unsigned long address): |
| 562 | return ocall (page, CAP_MASTER_DIRECT | MAP, address).l == NO_ERROR |
| 563 | bool unmap (Cap page): |
| 564 | return map (page, ~0) |
| 565 | Page mapping (void *address): |
| 566 | icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned long)address)) |
| 567 | return get_arg () |
| 568 | unsigned get_limit (): |
| 569 | return call (CAP_MASTER_DIRECT | GET_LIMIT).l |
| 570 | void set_limit (unsigned limit): |
| 571 | call (CAP_MASTER_DIRECT | SET_LIMIT, limit) |
| 572 | unsigned alloc_range (unsigned pages): |
| 573 | return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l |
| 574 | |
| 575 | inline void wait (): |
| 576 | Cap::IMessage i |
| 577 | Cap ().copy ()._invoke (&i) |
| 578 | inline void schedule (): |
| 579 | my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE) |
| 580 | inline void register_interrupt (unsigned num): |
| 581 | my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) |
| 582 | inline void unregister_interrupt (unsigned num): |
| 583 | my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) |
| 584 | inline unsigned wait_for_interrupt (): |
| 585 | my_receiver.set_reply_protected_data (0) |
| 586 | Cap ().call () |
| 587 | unsigned ret = recv.data[0].l |
| 588 | my_receiver.set_reply_protected_data (~0) |
| 589 | return ret |
| 590 | inline Cap get_top_memory (): |
| 591 | my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY) |
| 592 | return get_arg () |
| 593 | inline void dbg_send (unsigned code, unsigned bits = 32): |
| 594 | my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits)) |
| 595 | inline void reboot (): |
| 596 | my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT) |
| 597 | inline void poweroff (): |
| 598 | my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_POWEROFF) |
| 599 | inline void suspend (): |
| 600 | my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_SUSPEND) |
| 601 | inline void boot (unsigned address, unsigned arg): |
| 602 | my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_BOOT, Iris::Num (address, arg)) |
| 603 | |
| 604 | void Receiver::sleep (unsigned value): |
| 605 | set_alarm (value) |
| 606 | Cap ().call () |
| 607 | inline void sleep (unsigned value): |
| 608 | my_receiver.sleep (value) |
| 609 | |
| 610 | // The start function has this prototype (there is no main function). |
| 611 | Iris::Num start () |
| 612 | |
| 613 | #ifndef __KERNEL__ |
| 614 | #ifndef __NATIVE__ |
| 615 | #if 1 |
| 616 | // Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. |
| 617 | #define kdebug_char(_c) do { unsigned _d = (_c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(_d) : "a0", "a1", "memory"); } while (0) |
| 618 | #else |
| 619 | #define kdebug_char(_c) do {} while (0) |
| 620 | #endif |
| 621 | #define kdebug(str) do { const char *s = (str); while (*s) { kdebug_char (*s); ++s; } } while (0) |
| 622 | #define __stringify2(x) #x |
| 623 | #define __stringify(x) __stringify2 (x) |
| 624 | #define kdebug_line() do { kdebug (__FILE__ ":"); kdebug (__PRETTY_FUNCTION__); kdebug (":"); kdebug (__stringify (__LINE__)); kdebug_char ('\n'); } while (0) |
| 625 | |
| 626 | static void kdebug_num (unsigned n, unsigned digits = 8): |
| 627 | unsigned i |
| 628 | char const *encode = "0123456789abcdef" |
| 629 | for i = 0; i < digits; ++i: |
| 630 | kdebug_char (encode[(n >> (4 * ((digits - 1) - i))) & 0xf]) |
| 631 | |
| 632 | namespace Iris: |
| 633 | inline void panic (unsigned code, char const *message = NULL): |
| 634 | if message: |
| 635 | kdebug_num (code) |
| 636 | kdebug_char ('\n') |
| 637 | kdebug (message) |
| 638 | kdebug_char ('\n') |
| 639 | my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code) |
| 640 | if code == 0xdeaddead: |
| 641 | return |
| 642 | while true: |
| 643 | wait () |
| 644 | |
| 645 | inline void debug_num (unsigned num, unsigned base): |
| 646 | char const *encode = "0123456789abcdef" |
| 647 | unsigned digits = 1 |
| 648 | unsigned power = 1 |
| 649 | while power <= num / base: |
| 650 | power *= base |
| 651 | ++digits |
| 652 | for unsigned i = 0; i < digits; ++i: |
| 653 | unsigned d = num / power |
| 654 | kdebug_char (encode[d]) |
| 655 | num -= d * power |
| 656 | power /= base |
| 657 | |
| 658 | inline void debug (const char *f, ...): |
| 659 | unsigned *last = (unsigned *)&f |
| 660 | while *f: |
| 661 | if *f == '%': |
| 662 | ++f |
| 663 | switch *f: |
| 664 | case '%': |
| 665 | kdebug_char ('%') |
| 666 | break |
| 667 | case 'd': |
| 668 | ++last |
| 669 | debug_num (*last, 10) |
| 670 | break |
| 671 | case 'x': |
| 672 | ++last |
| 673 | debug_num (*last, 0x10) |
| 674 | break |
| 675 | case 's': |
| 676 | ++last |
| 677 | kdebug ((char *)*last) |
| 678 | break |
| 679 | case 'c': |
| 680 | ++last |
| 681 | kdebug_char (*last) |
| 682 | break |
| 683 | default: |
| 684 | panic (*f, "invalid character in dbg format string") |
| 685 | else: |
| 686 | kdebug_char (*f) |
| 687 | ++f |
| 688 | #else |
| 689 | namespace Iris: |
| 690 | inline void panic(unsigned code, char const *message = NULL): |
| 691 | inline void debug_num (unsigned num, unsigned base): |
| 692 | inline void debug (const char *f, ...): |
| 693 | #endif // !defined(__NATIVE__) |
| 694 | #endif // !defined(__KERNEL__) |
| 695 | #endif |
| 696 |
Branches:
master
