3 * \brief Arch-generic system calls implementation.
7 * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
19 #include <barrelfish_kpi/syscalls.h>
20 #include <capabilities.h>
21 #include <cap_predicates.h>
24 #include <mdb/mdb_tree.h>
25 #include <cap_predicates.h>
29 #include <paging_kernel_helper.h>
30 #include <paging_kernel_arch.h>
33 #include <trace/trace.h>
34 #include <trace_definitions/trace_defs.h>
37 errval_t sys_print(const char *str, size_t length)
39 /* FIXME: check that string is mapped and accessible to caller! */
40 printf("%.*s", (int)length, str);
44 /* FIXME: lots of missing argument checks in this function */
46 sys_dispatcher_setup(struct capability *to, capaddr_t cptr, int depth,
47 capaddr_t vptr, capaddr_t dptr, bool run, capaddr_t odptr)
49 errval_t err = SYS_ERR_OK;
50 assert(to->type == ObjType_Dispatcher);
51 struct dcb *dcb = to->u.dispatcher.dcb;
55 /* 1. set cspace root */
56 if (cptr != CPTR_NULL) {
58 err = caps_lookup_slot(&dcb_current->cspace.cap, cptr, depth,
59 &root, CAPRIGHTS_READ);
60 if (err_is_fail(err)) {
61 return SYSRET(err_push(err, SYS_ERR_DISP_CSPACE_ROOT));
63 if (root->cap.type != ObjType_CNode) {
64 return SYSRET(err_push(err, SYS_ERR_DISP_CSPACE_INVALID));
66 err = caps_copy_to_cte(&dcb->cspace, root, false, 0, 0);
67 if (err_is_fail(err)) {
68 return SYSRET(err_push(err, SYS_ERR_DISP_CSPACE_ROOT));
72 /* 2. set vspace root */
73 if (vptr != CPTR_NULL) {
74 struct capability *vroot;
75 err = caps_lookup_cap(&dcb_current->cspace.cap, vptr, CPTR_BITS,
76 &vroot, CAPRIGHTS_WRITE);
77 if (err_is_fail(err)) {
78 return SYSRET(err_push(err, SYS_ERR_DISP_VSPACE_ROOT));
81 // Insert as dispatcher's VSpace root
83 case ObjType_VNode_x86_64_pml4:
85 (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_x86_64_pml4.base);
88 case ObjType_VNode_x86_32_pdpt:
90 (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_x86_32_pdpt.base);
93 case ObjType_VNode_x86_32_pdir:
95 (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_x86_32_pdir.base);
98 case ObjType_VNode_ARM_l1:
100 (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_arm_l1.base);
104 return SYSRET(err_push(err, SYS_ERR_DISP_VSPACE_INVALID));
108 /* 3. set dispatcher frame pointer */
109 if (dptr != CPTR_NULL) {
111 err = caps_lookup_slot(&dcb_current->cspace.cap, dptr, CPTR_BITS,
112 &dispcte, CAPRIGHTS_WRITE);
113 if (err_is_fail(err)) {
114 return SYSRET(err_push(err, SYS_ERR_DISP_FRAME));
116 struct capability *dispcap = &dispcte->cap;
117 if (dispcap->type != ObjType_Frame) {
118 return SYSRET(err_push(err, SYS_ERR_DISP_FRAME_INVALID));
121 /* FIXME: check rights, check size */
123 lpaddr = gen_phys_to_local_phys(dispcap->u.frame.base);
124 dcb->disp = local_phys_to_mem(lpaddr);
125 // Copy the cap to dcb also
126 err = caps_copy_to_cte(&dcb->disp_cte, dispcte, false, 0, 0);
127 // If copy fails, something wrong in kernel
128 assert(err_is_ok(err));
131 /* 5. Make runnable if desired -- Set pointer to ipi_data */
133 if (dcb->vspace == 0 ||
134 (!dcb->is_vm_guest &&
135 (dcb->disp == 0 || dcb->cspace.cap.type != ObjType_CNode))) {
136 return SYSRET(err_push(err, SYS_ERR_DISP_NOT_RUNNABLE));
139 // XXX: dispatchers run disabled the first time they start
141 //printf("DCB: %p %.*s\n", dcb, DISP_NAME_LEN, dcb->disp->name);
145 /* 6. Copy domain ID off given dispatcher */
146 if(odptr != CPTR_NULL) {
147 struct capability *odisp;
148 err = caps_lookup_cap(&dcb_current->cspace.cap, odptr, CPTR_BITS,
149 &odisp, CAPRIGHTS_READ_WRITE);
150 if (err_is_fail(err)) {
151 return SYSRET(err_push(err, SYS_ERR_DISP_OCAP_LOOKUP));
153 dcb->domain_id = odisp->u.dispatcher.dcb->domain_id;
156 /* 7. (HACK) Set current core id */
158 struct dispatcher_shared_generic *disp =
159 get_dispatcher_shared_generic(dcb->disp);
160 disp->curr_core_id = my_core_id;
163 if(!dcb->is_vm_guest) {
164 struct dispatcher_shared_generic *disp =
165 get_dispatcher_shared_generic(dcb->disp);
166 err = trace_new_application(disp->name, (uintptr_t) dcb);
168 if (err == TRACE_ERR_NO_BUFFER) {
169 // Try to use the boot buffer.
170 trace_new_boot_application(disp->name, (uintptr_t) dcb);
174 return SYSRET(SYS_ERR_OK);
178 sys_dispatcher_properties(struct capability *to,
179 enum task_type type, unsigned long deadline,
180 unsigned long wcet, unsigned long period,
181 unsigned long release, unsigned short weight)
183 assert(to->type == ObjType_Dispatcher);
185 #ifdef CONFIG_SCHEDULER_RBED
186 struct dcb *dcb = to->u.dispatcher.dcb;
188 assert(type >= TASK_TYPE_BEST_EFFORT && type <= TASK_TYPE_HARD_REALTIME);
189 assert(wcet <= deadline);
190 assert(wcet <= period);
191 assert(type != TASK_TYPE_BEST_EFFORT || weight > 0);
193 trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_SCHED_REMOVE,
195 scheduler_remove(dcb);
197 /* Set task properties */
199 dcb->deadline = deadline;
201 dcb->period = period;
202 dcb->release_time = (release == 0) ? kernel_now : release;
203 dcb->weight = weight;
208 return SYSRET(SYS_ERR_OK);
212 * \param root Root CNode to invoke
213 * \param source_cptr Source capability cptr
214 * \param type Type to retype to
215 * \param objbits Object bits for variable-sized types
216 * \param dest_cnode_cptr Destination cnode cptr
217 * \param dest_slot Destination slot number
218 * \param dest_vbits Valid bits in destination cnode cptr
221 sys_retype(struct capability *root, capaddr_t source_cptr, enum objtype type,
222 uint8_t objbits, capaddr_t dest_cnode_cptr, cslot_t dest_slot,
223 uint8_t dest_vbits, bool from_monitor)
227 /* Parameter checking */
228 if (type == ObjType_Null || type >= ObjType_Num) {
229 return SYSRET(SYS_ERR_ILLEGAL_DEST_TYPE);
232 /* Source capability */
233 struct cte *source_cap;
234 err = caps_lookup_slot(root, source_cptr, CPTR_BITS, &source_cap,
236 if (err_is_fail(err)) {
237 return SYSRET(err_push(err, SYS_ERR_SOURCE_CAP_LOOKUP));
239 assert(source_cap != NULL);
241 /* Destination cnode */
242 struct capability *dest_cnode_cap;
243 err = caps_lookup_cap(root, dest_cnode_cptr, dest_vbits,
244 &dest_cnode_cap, CAPRIGHTS_READ_WRITE);
245 if (err_is_fail(err)) {
246 return SYSRET(err_push(err, SYS_ERR_DEST_CNODE_LOOKUP));
248 if (dest_cnode_cap->type != ObjType_CNode) {
249 return SYSRET(SYS_ERR_DEST_CNODE_INVALID);
252 return SYSRET(caps_retype(type, objbits, dest_cnode_cap, dest_slot,
253 source_cap, from_monitor));
256 struct sysret sys_create(struct capability *root, enum objtype type,
257 uint8_t objbits, capaddr_t dest_cnode_cptr,
258 cslot_t dest_slot, int dest_vbits)
264 /* Paramter checking */
265 if (type == ObjType_Null || type >= ObjType_Num) {
266 return SYSRET(SYS_ERR_ILLEGAL_DEST_TYPE);
269 /* Destination CNode */
270 struct capability *dest_cnode_cap;
271 err = caps_lookup_cap(root, dest_cnode_cptr, dest_vbits,
272 &dest_cnode_cap, CAPRIGHTS_READ_WRITE);
273 if (err_is_fail(err)) {
274 return SYSRET(err_push(err, SYS_ERR_DEST_CNODE_LOOKUP));
277 /* Destination slot */
278 struct cte *dest_cte;
279 dest_cte = caps_locate_slot(dest_cnode_cap->u.cnode.cnode, dest_slot);
280 if (dest_cte->cap.type != ObjType_Null) {
281 return SYSRET(SYS_ERR_SLOTS_IN_USE);
284 /* List capabilities allowed to be created at runtime. */
290 // only certain types of capabilities can be created at runtime
292 return SYSRET(SYS_ERR_TYPE_NOT_CREATABLE);
295 return SYSRET(caps_create_new(type, base, bits, objbits, my_core_id, dest_cte));
299 * Common code for copying and minting except the mint flag and param passing
302 sys_copy_or_mint(struct capability *root, capaddr_t destcn_cptr, cslot_t dest_slot,
303 capaddr_t source_cptr, int destcn_vbits, int source_vbits,
304 uintptr_t param1, uintptr_t param2, bool mint)
312 /* Lookup source cap */
314 err = caps_lookup_slot(root, source_cptr, source_vbits,
315 &src_cap, CAPRIGHTS_READ);
316 if (err_is_fail(err)) {
317 return SYSRET(err_push(err, SYS_ERR_SOURCE_CAP_LOOKUP));
320 /* Lookup destination cnode cap */
321 struct cte *dest_cnode_cap;
322 err = caps_lookup_slot(root, destcn_cptr, destcn_vbits,
323 &dest_cnode_cap, CAPRIGHTS_READ_WRITE);
324 if (err_is_fail(err)) {
325 return SYSRET(err_push(err, SYS_ERR_DEST_CNODE_LOOKUP));
329 if (dest_cnode_cap->cap.type == ObjType_CNode) {
330 return SYSRET(caps_copy_to_cnode(dest_cnode_cap, dest_slot, src_cap,
331 mint, param1, param2));
333 return SYSRET(SYS_ERR_DEST_TYPE_INVALID);
338 sys_map(struct capability *ptable, cslot_t slot, capaddr_t source_cptr,
339 int source_vbits, uintptr_t flags, uintptr_t offset,
342 assert (type_is_vnode(ptable->type));
346 /* Lookup source cap */
347 struct capability *root = &dcb_current->cspace.cap;
349 err = caps_lookup_slot(root, source_cptr, source_vbits, &src_cte,
351 if (err_is_fail(err)) {
352 return SYSRET(err_push(err, SYS_ERR_SOURCE_CAP_LOOKUP));
356 // XXX: this does not check if we do have CAPRIGHTS_READ_WRITE on
357 // the destination cap (the page table we're inserting into)
358 return SYSRET(caps_copy_to_vnode(cte_for_cap(ptable), slot, src_cte, flags,
362 struct sysret sys_delete(struct capability *root, capaddr_t cptr, uint8_t bits)
366 err = caps_lookup_slot(root, cptr, bits, &slot, CAPRIGHTS_READ_WRITE);
367 if (err_is_fail(err)) {
371 err = caps_delete(slot);
375 struct sysret sys_revoke(struct capability *root, capaddr_t cptr, uint8_t bits)
379 err = caps_lookup_slot(root, cptr, bits, &slot, CAPRIGHTS_READ_WRITE);
380 if (err_is_fail(err)) {
384 err = caps_revoke(slot);
388 struct sysret sys_get_state(struct capability *root, capaddr_t cptr, uint8_t bits)
392 err = caps_lookup_slot(root, cptr, bits, &slot, CAPRIGHTS_READ);
393 if (err_is_fail(err)) {
397 distcap_state_t state = distcap_get_state(slot);
398 return (struct sysret) { .error = SYS_ERR_OK, .value = state };
401 struct sysret sys_yield(capaddr_t target)
403 dispatcher_handle_t handle = dcb_current->disp;
404 struct dispatcher_shared_generic *disp =
405 get_dispatcher_shared_generic(handle);
408 debug(SUBSYS_DISPATCH, "%.*s yields%s\n", DISP_NAME_LEN, disp->name,
409 !disp->haswork && disp->lmp_delivered == disp->lmp_seen
410 ? " and is removed from the runq" : "");
412 if (!disp->disabled) {
413 printk(LOG_ERR, "SYSCALL_YIELD while enabled\n");
414 return SYSRET(SYS_ERR_CALLER_ENABLED);
417 struct capability *yield_to = NULL;
418 if (target != CPTR_NULL) {
422 err = caps_lookup_cap(&dcb_current->cspace.cap, target, CPTR_BITS,
423 &yield_to, CAPRIGHTS_READ);
424 if (err_is_fail(err)) {
426 } else if (yield_to == NULL ||
427 (yield_to->type != ObjType_EndPoint
428 && yield_to->type != ObjType_Dispatcher)) {
429 return SYSRET(SYS_ERR_INVALID_YIELD_TARGET);
431 /* FIXME: check rights? */
434 disp->disabled = false;
435 dcb_current->disabled = false;
437 // Remove from queue when no work and no more messages and no missed wakeup
438 systime_t wakeup = disp->wakeup;
439 if (!disp->haswork && disp->lmp_delivered == disp->lmp_seen
440 && (wakeup == 0 || wakeup > (kernel_now + kcb_current->kernel_off))) {
442 trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_SCHED_REMOVE,
443 (uint32_t)(lvaddr_t)dcb_current & 0xFFFFFFFF);
444 trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_SCHED_REMOVE,
447 scheduler_remove(dcb_current);
449 wakeup_set(dcb_current, wakeup);
452 // Otherwise yield for the timeslice
453 scheduler_yield(dcb_current);
456 if (yield_to != NULL) {
457 struct dcb *target_dcb = NULL;
458 if (yield_to->type == ObjType_EndPoint) {
459 target_dcb = yield_to->u.endpoint.listener;
460 } else if (yield_to->type == ObjType_Dispatcher) {
461 target_dcb = yield_to->u.dispatcher.dcb;
463 panic("invalid type in yield cap");
466 trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_YIELD,
467 (uint32_t)(lvaddr_t)target_dcb & 0xFFFFFFFF);
468 make_runnable(target_dcb);
469 dispatch(target_dcb);
471 // trace_event(TRACE_SUBSYS_BNET, TRACE_EVENT_BNET_YIELD,
474 /* undirected yield */
475 dispatch(schedule());
478 panic("Yield returned!");
481 struct sysret sys_suspend(bool do_halt)
483 dispatcher_handle_t handle = dcb_current->disp;
484 struct dispatcher_shared_generic *disp =
485 get_dispatcher_shared_generic(handle);
487 debug(SUBSYS_DISPATCH, "%.*s suspends (halt: %d)\n", DISP_NAME_LEN, disp->name, do_halt);
489 if (!disp->disabled) {
490 printk(LOG_ERR, "SYSCALL_SUSPEND while enabled\n");
491 return SYSRET(SYS_ERR_CALLER_ENABLED);
494 disp->disabled = false;
495 dcb_current->disabled = false;
498 //printf("%s:%s:%d: before halt of core (%"PRIuCOREID")\n",
499 // __FILE__, __FUNCTION__, __LINE__, my_core_id);
502 // Note this only works if we're calling this inside
503 // the kcb we're currently running
504 printk(LOG_NOTE, "in sys_suspend(<no_halt>)!\n");
505 printk(LOG_NOTE, "calling switch_kcb!\n");
506 struct kcb *next = kcb_current->next;
507 kcb_current->next = NULL;
509 // enable kcb scheduler
510 printk(LOG_NOTE, "enabling kcb scheduler!\n");
511 kcb_sched_suspended = false;
512 // schedule something in the other kcb
513 dispatch(schedule());
516 panic("Yield returned!");
521 * The format of the returned ID is:
523 * --------------------------------------------------------------------
524 * | 0 (unused) | coreid | core_local_id |
525 * --------------------------------------------------------------------
529 struct sysret sys_idcap_identify(struct capability *cap, idcap_id_t *id)
531 STATIC_ASSERT_SIZEOF(coreid_t, 1);
533 idcap_id_t coreid = (idcap_id_t) cap->u.id.coreid;
534 *id = coreid << 32 | cap->u.id.core_local_id;
536 return SYSRET(SYS_ERR_OK);
540 * Calls correct handler function to spawn an app core.
542 * At the moment spawn_core_handlers is set-up per
543 * architecture inside text_init() usually found in init.c.
545 * \note Generally the x86 terms of BSP and APP core are used
546 * throughout Barrelfish to distinguish between bootstrap core (BSP)
547 * and application cores (APP).
549 * \param core_id Identifier of the core which we want to boot
550 * \param cpu_type Architecture of the core.
551 * \param entry Entry point for code to start execution.
553 * \retval SYS_ERR_OK Core successfully booted.
554 * \retval SYS_ERR_ARCHITECTURE_NOT_SUPPORTED No handler registered for
555 * the specified cpu_type.
556 * \retval SYS_ERR_CORE_NOT_FOUND Core failed to boot.
558 struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
561 assert(cpu_type < CPU_TYPE_NUM);
562 // TODO(gz): assert core_id valid
563 // TODO(gz): assert entry range?
565 if (cpu_type < CPU_TYPE_NUM &&
566 coreboot_get_spawn_handler(cpu_type) == NULL) {
567 assert(!"Architecture not supported -- " \
568 "or you failed to register spawn handler?");
569 return SYSRET(SYS_ERR_ARCHITECTURE_NOT_SUPPORTED);
572 int r = (coreboot_get_spawn_handler(cpu_type))(core_id, entry);
574 return SYSRET(SYS_ERR_CORE_NOT_FOUND);
577 return SYSRET(SYS_ERR_OK);
580 struct sysret sys_kernel_add_kcb(struct kcb *new_kcb)
584 // update kernel_now offset
585 new_kcb->kernel_off -= kernel_now;
586 // reset scheduler statistics
587 scheduler_reset_time();
588 // update current core id of all domains
589 kcb_update_core_id(new_kcb);
590 // upcall domains with registered interrupts to tell them to re-register
591 irq_table_notify_domains(new_kcb);
593 return SYSRET(SYS_ERR_OK);
596 struct sysret sys_kernel_remove_kcb(struct kcb * to_remove)
598 return SYSRET(kcb_remove(to_remove));
601 struct sysret sys_kernel_suspend_kcb_sched(bool suspend)
603 printk(LOG_NOTE, "in kernel_suspend_kcb_sched invocation!\n");
604 kcb_sched_suspended = suspend;
605 return SYSRET(SYS_ERR_OK);
608 struct sysret sys_handle_kcb_identify(struct capability* to)
610 // Return with physical base address of frame
611 // XXX: pack size into bottom bits of base address
612 assert(to->type == ObjType_KernelControlBlock);
613 lvaddr_t vkcb = (lvaddr_t) to->u.kernelcontrolblock.kcb;
614 assert((vkcb & BASE_PAGE_MASK) == 0);
616 return (struct sysret) {
618 .value = mem_to_local_phys(vkcb) | OBJBITS_KCB,
622 struct sysret sys_get_absolute_time(void)
624 // Return kernel_now.
625 // XXX: this may not provide all the properties of absolute time we want,
626 // but should be sufficient to implement stuff that needs timing with 1/10
627 // of a second accuracy range.
628 return (struct sysret) {
630 .value = kernel_now + kcb_current->kernel_off,
635 sys_debug_print_capabilities(void) {
637 caps_debug_print(&dcb_current->cspace);
639 return SYSRET(SYS_ERR_OK);