Root/kernel/invoke.ccp

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
21static 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
54void 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.
80kCapRef 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.
105bool 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.
131bool 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
163static kCapability::Context *context
164
165static 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
174static 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
183static 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
195static 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
275static 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
411static 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
600static 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
758static 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
780static 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
867static 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
939static 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
956static 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
964static 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
1050void 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

Archive Download this file

Branches:
master



interactive