OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [posix/] [mm0/] [mm/] [capability.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Pager's capabilities for kernel resources
3
 *
4
 * Copyright (C) 2009 Bahadir Balban
5
 */
6
#include <bootm.h>
7
#include <init.h>
8
#include <memory.h>
9
#include <capability.h>
10
#include <l4/api/errno.h>
11
#include <l4/lib/list.h>
12
#include L4LIB_INC_ARCH(syscalls.h)
13
#include <l4/generic/cap-types.h>       /* TODO: Move this to API */
14
#include L4LIB_INC_ARCH(syslib.h)
15
#include <malloc/malloc.h>
16
#include <user.h>
17
 
18
/* Capability descriptor list */
19
struct cap_list capability_list;
20
 
21
__initdata static struct capability *caparray;
22
__initdata static int total_caps = 0;
23
 
24
void cap_list_print(struct cap_list *cap_list)
25
{
26
        struct capability *cap;
27
        printf("Capabilities\n"
28
               "~~~~~~~~~~~~\n");
29
 
30
        list_foreach_struct(cap, &cap_list->caps, list)
31
                cap_print(cap);
32
 
33
        printf("\n");
34
}
35
 
36
#define PAGER_TOTAL_MUTEX               5
37
int setup_children_mutex(int total_caps, struct cap_list *cap_list)
38
{
39
        struct capability *diff_cap, *mutex_cap;
40
 
41
        struct task_ids ids;
42
        int err;
43
 
44
        l4_getid(&ids);
45
 
46
        //cap_list_print(cap_list);
47
 
48
        /* Find out own mutex capability on our own container */
49
        list_foreach_struct(mutex_cap, &cap_list->caps, list) {
50
                if (cap_type(mutex_cap) == CAP_TYPE_QUANTITY &&
51
                    cap_rtype(mutex_cap) == CAP_RTYPE_MUTEXPOOL)
52
                        goto found;
53
        }
54
        printf("cont%d: %s: FATAL: Could not find ipc "
55
               "capability to own container.\n",
56
               __cid(ids.tid), __FUNCTION__);
57
        BUG();
58
 
59
found:
60
        /* Create a new capability */
61
        BUG_ON(!(diff_cap = kzalloc(sizeof(*mutex_cap))));
62
 
63
        /* Copy it over to new mutex cap buffer */
64
        memcpy(diff_cap, mutex_cap, sizeof (*mutex_cap));
65
 
66
        /*
67
         * We would like to take some mutexes,
68
         * and leave the rest to children.
69
         *
70
         * We set up a capability that we want
71
         * to separate out from the original
72
         */
73
        if (mutex_cap->size <= PAGER_TOTAL_MUTEX) {
74
                printf("%s: FATAL: Can't reserve enough mutexes "
75
                       "for children. capid = %d, mutexes = %lu, "
76
                       "pager needs = %d\n", __FUNCTION__,
77
                       mutex_cap->capid, mutex_cap->size,
78
                       PAGER_TOTAL_MUTEX);
79
                BUG();
80
        }
81
 
82
        /* Reserve out some mutexes to self */
83
        diff_cap->size = PAGER_TOTAL_MUTEX;
84
 
85
        /* Split the mutex capability, passing the difference */
86
        if ((err = l4_capability_control(CAP_CONTROL_SPLIT,
87
                                         0, diff_cap)) < 0) {
88
                printf("l4_capability_control() replication of "
89
                       "ipc capability failed.\n Could not "
90
                       "complete CAP_CONTROL_SPLIT request on cap (%d), "
91
                       "err = %d.\n", diff_cap->capid, err);
92
                BUG();
93
        }
94
 
95
        /*
96
         * The returned one is the given diff, but
97
         * created as a new capability, add it to list
98
         */
99
        cap_list_insert(diff_cap, cap_list);
100
        // cap_list_print(cap_list);
101
 
102
        /*
103
         * Share the remainder capability with our container.
104
         *
105
         * This effectively enables all threads/spaces in this container
106
         * to use this pool of mutexes.
107
         */
108
        if ((err = l4_capability_control(CAP_CONTROL_SHARE, CAP_SHARE_SINGLE,
109
                                         mutex_cap)) < 0) {
110
                printf("l4_capability_control() sharing of "
111
                       "capabilities failed.\n Could not "
112
                       "complete CAP_CONTROL_SHARE request.\n");
113
                BUG();
114
        }
115
        // cap_list_print(cap_list);
116
 
117
        /* Find mutex syscall operation capability on our own container */
118
        list_foreach_struct(mutex_cap, &cap_list->caps, list) {
119
                if (cap_type(mutex_cap) == CAP_TYPE_UMUTEX &&
120
                    cap_rtype(mutex_cap) == CAP_RTYPE_CONTAINER)
121
                        goto found2;
122
        }
123
        printf("cont%d: %s: FATAL: Could not find UMUTEX "
124
               "capability to own container.\n",
125
               __cid(ids.tid), __FUNCTION__);
126
        BUG();
127
 
128
found2:
129
 
130
        /*
131
         * Share it with our container.
132
         *
133
         * This effectively enables all threads/spaces in this container
134
         * to use this pool of mutexes.
135
         */
136
        if ((err = l4_capability_control(CAP_CONTROL_SHARE, CAP_SHARE_SINGLE,
137
                                         mutex_cap)) < 0) {
138
                printf("l4_capability_control() sharing of "
139
                       "capabilities failed.\n Could not "
140
                       "complete CAP_CONTROL_SHARE request.\n");
141
                BUG();
142
        }
143
 
144
        return 0;
145
}
146
 
147
 
148
/*
149
 * Replicate, deduce and grant to children the capability to
150
 * talk to us only.
151
 *
152
 * We are effectively creating an ipc capability from what we already
153
 * own, and the new one has a reduced privilege in terms of the
154
 * targetable resource.
155
 *
156
 * We are replicating our capability to talk to our complete container
157
 * into a capability to only talk to our current space. Our space is a
158
 * reduced target, since it is a subset contained in our container.
159
 */
160
int setup_children_ipc(int total_caps, struct cap_list *cap_list)
161
{
162
        struct capability *ipc_cap, *cap;
163
        struct task_ids ids;
164
        int err;
165
 
166
        l4_getid(&ids);
167
 
168
        // cap_list_print(cap_list);
169
 
170
        /* Find out our own ipc capability on our own container */
171
        list_foreach_struct(cap, &cap_list->caps, list) {
172
                if (cap_type(cap) == CAP_TYPE_IPC &&
173
                    cap_rtype(cap) == CAP_RTYPE_CONTAINER &&
174
                    cap->resid == __cid(ids.tid))
175
                        goto found;
176
        }
177
        printf("cont%d: %s: FATAL: Could not find ipc "
178
               "capability to own container.\n",
179
               __cid(ids.tid), __FUNCTION__);
180
        BUG();
181
 
182
found:
183
        /* Create a new capability */
184
        BUG_ON(!(ipc_cap = kzalloc(sizeof(*ipc_cap))));
185
 
186
        /* Copy it over to new ipc cap buffer */
187
        memcpy(ipc_cap, cap, sizeof (*cap));
188
 
189
        /* Replicate the ipc capability, giving original as reference */
190
        if ((err = l4_capability_control(CAP_CONTROL_REPLICATE,
191
                                         0, ipc_cap)) < 0) {
192
                printf("l4_capability_control() replication of "
193
                       "ipc capability failed.\n Could not "
194
                       "complete CAP_CONTROL_REPLICATE request on cap (%d), "
195
                       "err = %d.\n", ipc_cap->capid, err);
196
                BUG();
197
        }
198
 
199
        /* Add it to list */
200
        cap_list_insert(ipc_cap, cap_list);
201
        // cap_list_print(cap_list);
202
 
203
        /*
204
         * The returned capability is a replica.
205
         *
206
         * Now deduce it such that it applies to talking only to us,
207
         * instead of to the whole container as original.
208
         */
209
        cap_set_rtype(ipc_cap, CAP_RTYPE_SPACE);
210
        ipc_cap->resid = ids.spid; /* This space is target resource */
211
        if ((err = l4_capability_control(CAP_CONTROL_DEDUCE,
212
                                         0, ipc_cap)) < 0) {
213
                printf("l4_capability_control() deduction of "
214
                       "ipc capability failed.\n Could not "
215
                       "complete CAP_CONTROL_DEDUCE request on cap (%d), "
216
                       "err = %d.\n", ipc_cap->capid, err);
217
                BUG();
218
        }
219
 
220
        // cap_list_print(cap_list);
221
 
222
        /*
223
         * Share it with our container.
224
         *
225
         * This effectively enables all threads/spaces in this container
226
         * to communicate to us only, and be able to do nothing else.
227
         */
228
        if ((err = l4_capability_control(CAP_CONTROL_SHARE,
229
                                         CAP_SHARE_SINGLE,
230
                                         ipc_cap)) < 0) {
231
                printf("l4_capability_control() sharing of "
232
                       "capabilities failed.\n Could not "
233
                       "complete CAP_CONTROL_SHARE request.\n");
234
                BUG();
235
        }
236
        // cap_list_print(cap_list);
237
 
238
        return 0;
239
}
240
 
241
int setup_children_caps(int total_caps, struct cap_list *cap_list)
242
{
243
        setup_children_ipc(total_caps, cap_list);
244
        setup_children_mutex(total_caps, cap_list);
245
        return 0;
246
}
247
 
248
/* Copy all init-memory allocated capabilities */
249
void copy_boot_capabilities(int ncaps)
250
{
251
        struct capability *cap;
252
 
253
        capability_list.ncaps = 0;
254
        link_init(&capability_list.caps);
255
 
256
        for (int i = 0; i < ncaps; i++) {
257
                cap = kzalloc(sizeof(struct capability));
258
 
259
                /* This copies kernel-allocated unique cap id as well */
260
                memcpy(cap, &caparray[i], sizeof(struct capability));
261
 
262
                /* Initialize capability list */
263
                link_init(&cap->list);
264
 
265
                /* Add capability to global cap list */
266
                cap_list_insert(cap, &capability_list);
267
        }
268
}
269
 
270
int cap_read_all()
271
{
272
        int ncaps;
273
        int err;
274
        struct capability *cap;
275
 
276
        /* Read number of capabilities */
277
        if ((err = l4_capability_control(CAP_CONTROL_NCAPS,
278
                                         0, &ncaps)) < 0) {
279
                printf("l4_capability_control() reading # of"
280
                       " capabilities failed.\n Could not "
281
                       "complete CAP_CONTROL_NCAPS request.\n");
282
                BUG();
283
        }
284
        total_caps = ncaps;
285
 
286
        /* Allocate array of caps from boot memory */
287
        caparray = alloc_bootmem(sizeof(struct capability) * ncaps, 0);
288
 
289
        /* Read all capabilities */
290
        if ((err = l4_capability_control(CAP_CONTROL_READ,
291
                                         0, caparray)) < 0) {
292
                printf("l4_capability_control() reading of "
293
                       "capabilities failed.\n Could not "
294
                       "complete CAP_CONTROL_READ_CAPS request.\n");
295
                BUG();
296
        }
297
 
298
 
299
        /* Copy them to real allocated structures */
300
        copy_boot_capabilities(ncaps);
301
 
302
        // cap_list_print(&capability_list);
303
 
304
        memset(&cont_mem_regions, 0, sizeof(cont_mem_regions));
305
 
306
        /* Set up pointers to important capabilities */
307
        list_foreach_struct(cap, &capability_list.caps, list) {
308
                /* Physical memory bank */
309
                if (cap_type(cap) == CAP_TYPE_MAP_PHYSMEM)
310
                        cont_mem_regions.physmem = cap;
311
 
312
                /* Virtual regions */
313
                if (cap_type(cap) == CAP_TYPE_MAP_VIRTMEM) {
314
 
315
                        /* Pager address region (get from linker-defined) */
316
                        if (__pfn_to_addr(cap->start)
317
                            == (unsigned long)virtual_base)
318
                                cont_mem_regions.pager = cap;
319
 
320
                        /* UTCB address region */
321
                        else if (UTCB_REGION_START ==
322
                                 __pfn_to_addr(cap->start)) {
323
                                if (UTCB_REGION_END !=
324
                                    __pfn_to_addr(cap->end)) {
325
                                        printf("FATAL: Region designated "
326
                                               "for UTCB allocation does not "
327
                                               "match on start/end marks");
328
                                        BUG();
329
                                }
330
 
331
                                if (!(cap->access & CAP_MAP_UTCB)) {
332
                                        printf("FATAL: Region designated "
333
                                               "for UTCB allocation does not "
334
                                               "have UTCB map permissions");
335
                                        BUG();
336
                                }
337
                                cont_mem_regions.utcb = cap;
338
                        }
339
 
340
                        /* Shared memory disjoint region */
341
                        else if (SHMEM_REGION_START ==
342
                                 __pfn_to_addr(cap->start)) {
343
                                if (SHMEM_REGION_END !=
344
                                    __pfn_to_addr(cap->end)) {
345
                                        printf("FATAL: Region designated "
346
                                               "for SHM allocation does not "
347
                                               "match on start/end marks");
348
                                        BUG();
349
                                }
350
 
351
                                cont_mem_regions.shmem = cap;
352
                        }
353
 
354
                        /* Task memory region */
355
                        else if (TASK_REGION_START ==
356
                                 __pfn_to_addr(cap->start)) {
357
                                if (TASK_REGION_END !=
358
                                    __pfn_to_addr(cap->end)) {
359
                                        printf("FATAL: Region designated "
360
                                               "for Task address space does"
361
                                               "not match on start/end mark.");
362
                                        BUG();
363
                                }
364
                                cont_mem_regions.task = cap;
365
                        }
366
                }
367
        }
368
 
369
        if (!cont_mem_regions.task ||
370
            !cont_mem_regions.shmem ||
371
            !cont_mem_regions.utcb ||
372
            !cont_mem_regions.physmem ||
373
            !cont_mem_regions.pager) {
374
                printf("%s: Error, pager does not have one of the required"
375
                       "mem capabilities defined. (TASK, SHM, PHYSMEM, UTCB, PAGER)\n",
376
                       __TASKNAME__);
377
                printf("%p, %p, %p, %p, %p\n", cont_mem_regions.task,
378
                       cont_mem_regions.shmem, cont_mem_regions.utcb,
379
                       cont_mem_regions.physmem, cont_mem_regions.pager);
380
                BUG();
381
        }
382
 
383
        return 0;
384
}
385
 
386
void setup_caps()
387
{
388
        cap_read_all();
389
        setup_children_caps(total_caps, &capability_list);
390
}
391
 
392
/*
393
 * Find our own, widened replicable capability of same type as given,
394
 * replicate, reduce and grant as described with given parameters.
395
 * Assumes parameters have already been validated and security-checked.
396
 */
397
int cap_find_replicate_reduce_grant(struct capability *cap)
398
{
399
        struct capability *possessed;
400
        struct capability new_cap;
401
        int err;
402
 
403
        /* Merely match type, kernel does actual check on suitability */
404
        list_foreach_struct(possessed, &capability_list.caps, list) {
405
                /* Different type, pass */
406
                if (cap_type(possessed) != cap_type(cap))
407
                        continue;
408
 
409
                /* Copy possessed one to new one's buffer */
410
                memcpy(&new_cap, possessed, sizeof(*possessed));
411
 
412
                /* Replicate capability, giving original as reference */
413
                if ((err = l4_capability_control(CAP_CONTROL_REPLICATE,
414
                                                 0, &new_cap)) < 0) {
415
                        printf("l4_capability_control() replication of "
416
                               "capability failed.\n Could not complete "
417
                               "CAP_CONTROL_REPLICATE request on cap (%d), "
418
                               "err = %d.\n", new_cap.capid, err);
419
                        return err;
420
                }
421
 
422
                /*
423
                 * The returned capability is a replica.
424
                 *
425
                 * We don't add the newly created one to our own internal
426
                 * list because we will grant it shortly and lose its
427
                 * possession
428
                 *
429
                 * Now deduce it such that it looks like the one requested.
430
                 * Note, we assume the request had been validated before.
431
                 * Also note, the owner shall be still us.
432
                 */
433
                new_cap.resid = cap->resid;
434
                new_cap.type = cap->type;
435
                new_cap.access = cap->access;
436
                new_cap.start = cap->start;
437
                new_cap.end = cap->end;
438
                new_cap.size = cap->size;
439
                new_cap.used = cap->used;
440
 
441
                /*
442
                 * Make sure it is transferable,
443
                 * since we will need to grant it soon
444
                 */
445
                new_cap.access |= CAP_TRANSFERABLE;
446
 
447
 
448
                if ((err = l4_capability_control(CAP_CONTROL_DEDUCE,
449
                                                 0, &new_cap)) < 0) {
450
                        /* Couldn't deduce this one, destroy the replica */
451
                        if ((err =
452
                             l4_capability_control(CAP_CONTROL_DESTROY,
453
                                                   0, &new_cap)) < 0) {
454
                                printf("l4_capability_control() destruction of "
455
                                       "capability failed.\n Could not "
456
                                       "complete CAP_CONTROL_DESTROY request "
457
                                       " on cap (%d), err = %d.\n",
458
                                       new_cap.capid, err);
459
                                BUG();
460
                        }
461
                } else /* Success */
462
                        goto success;
463
        }
464
 
465
        return -ENOCAP;
466
 
467
success:
468
        /*
469
         * Found suitable one to replicate/deduce.
470
         * Grant it to requested owner.
471
         *
472
         * This effectively enables the owner to have all
473
         * operations defined in the capability. However,
474
         * we use a flag to make the capability immutable
475
         * as we grant it. (We wouldn't be able to grant
476
         * it if it had no grant permission originally. We
477
         * remove it _as_ we grant it)
478
         */
479
        new_cap.owner = cap->owner; /* Indicate new owner */
480
        if ((err = l4_capability_control(CAP_CONTROL_GRANT,
481
                                         CAP_GRANT_SINGLE |
482
                                         CAP_GRANT_IMMUTABLE,
483
                                         &new_cap)) < 0) {
484
                printf("l4_capability_control() granting of "
485
                       "capability (%d) failed.\n Could not "
486
                       "complete CAP_CONTROL_GRANT request.\n",
487
                       new_cap.capid);
488
                return err;
489
        }
490
        return 0;
491
}
492
 
493
/*
494
 * A task that we manage requests a capability to do an operation
495
 * from us, such as the capability to do a particular ipc to a
496
 * particular thread. We consider the request and give the
497
 * capability if it is appropriate. This currently supports only
498
 * ipc.
499
 */
500
int sys_request_cap(struct tcb *task, struct capability *__cap_userptr)
501
{
502
        struct tcb *target;
503
        struct capability *cap;
504
        int ret;
505
 
506
        if (!(cap = pager_get_user_page(task, __cap_userptr,
507
                                        sizeof(*__cap_userptr),
508
                                        VM_READ | VM_WRITE)))
509
                return -EFAULT;
510
 
511
        /* Only support IPC requests for now */
512
        if (cap_type(cap) != CAP_TYPE_IPC) {
513
                ret = -EPERM;
514
        }
515
 
516
        /* Validate rest of the fields */
517
        if (cap->start || cap->end || cap->used || cap->size) {
518
                ret = -EINVAL;
519
                goto out;
520
        }
521
 
522
        if (cap_generic_perms(cap) != CAP_IMMUTABLE) {
523
                ret = -EPERM;
524
                goto out;
525
        }
526
 
527
        /* Find out who the task wants to ipc */
528
        switch (cap_rtype(cap)) {
529
        /* Is it a thread? */
530
        case CAP_RTYPE_THREAD:
531
                /* Find the thread */
532
                if (!(target = find_task(cap->resid))) {
533
                        ret = -ESRCH;
534
                        goto out;
535
                }
536
 
537
                /* Requester must be the owner */
538
                if (cap->owner != task->tid) {
539
                        ret = -EPERM;
540
                        goto out;
541
                }
542
 
543
                /*
544
                 * It is a thread that we are managing, nothing
545
                 * special requested here, just grant it
546
                 */
547
                if ((ret = cap_find_replicate_reduce_grant(cap)) < 0)
548
                        goto out;
549
                break;
550
        case CAP_RTYPE_SPACE:
551
                /* Space requests not allowed */
552
                ret = -EPERM;
553
                goto out;
554
        case CAP_RTYPE_CONTAINER:
555
                /* Container requests not allowed */
556
                ret = -EPERM;
557
                goto out;
558
        }
559
 
560
out:
561
        return ret;
562
}
563
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.