/* Some more generic routines for helping with mapping */ void * sel4utils_dup_and_map(vka_t *vka, vspace_t *vspace, seL4_CPtr page, size_t size_bits) { int error; cspacepath_t page_path; cspacepath_t copy_path; void *mapping; /* First need to copy the cap */ error = vka_cspace_alloc_path(vka, ©_path); if (error != seL4_NoError) { return NULL; } vka_cspace_make_path(vka, page, &page_path); error = vka_cnode_copy(©_path, &page_path, seL4_AllRights); if (error != seL4_NoError) { vka_cspace_free(vka, copy_path.capPtr); return NULL; } /* Now map it in */ mapping = vspace_map_pages(vspace, ©_path.capPtr, NULL, seL4_AllRights, 1, size_bits, 1); if (!mapping) { vka_cnode_delete(©_path); vka_cspace_free(vka, copy_path.capPtr); return NULL; } return mapping; }
seL4_CPtr vmm_create_async_event_notification_cap(vmm_t *vmm, seL4_Word badge) { if (!(badge & BIT(27))) { ZF_LOGE("Invalid badge"); return seL4_CapNull; } // notification cap seL4_CPtr ntfn = vmm->plat_callbacks.get_async_event_notification(); // path to notification cap slot cspacepath_t ntfn_path = {}; vka_cspace_make_path(&vmm->vka, ntfn, &ntfn_path); // allocate slot to store copy cspacepath_t minted_ntfn_path = {}; vka_cspace_alloc_path(&vmm->vka, &minted_ntfn_path); // mint the notification cap seL4_CapData_t badge_data = seL4_CapData_Badge_new(badge); int error = vka_cnode_mint(&minted_ntfn_path, &ntfn_path, seL4_AllRights, badge_data); if (error != seL4_NoError) { ZF_LOGE("Failed to mint notification cap"); return seL4_CapNull; } return minted_ntfn_path.capPtr; }
static void map_unity_ram(vm_t* vm) { /* Dimensions of physical memory that we'll use. Note that we do not map the entirety of RAM. */ static const uintptr_t paddr_start = RAM_BASE; static const uintptr_t paddr_end = 0x60000000; int err; uintptr_t start; reservation_t res; unsigned int bits = 21; res = vspace_reserve_range_at(&vm->vm_vspace, (void*)paddr_start, paddr_end - paddr_start, seL4_AllRights, 1); assert(res.res); for (start = paddr_start;; start += BIT(bits)) { cspacepath_t frame; err = vka_cspace_alloc_path(vm->vka, &frame); assert(!err); err = simple_get_frame_cap(vm->simple, (void*)start, bits, &frame); if (err) { vka_cspace_free(vm->vka, frame.capPtr); break; } err = vspace_map_pages_at_vaddr(&vm->vm_vspace, &frame.capPtr, &bits, (void*)start, 1, bits, res); assert(!err); } }
static seL4_CPtr _platsupport_find_device_cap(seL4_Word paddr, seL4_Word page_bits, simple_t *simple, vka_t *vka) { int UNUSED error; cspacepath_t path; error = vka_cspace_alloc_path(vka, &path); assert(!error); error = simple_get_frame_cap(simple,(void *) paddr, page_bits, &path); assert(error == seL4_NoError); return path.capPtr; }
static void map_unity_ram(vm_t* vm) { int err; uintptr_t start; reservation_t res; unsigned int bits = 21; res = vspace_reserve_range_at(&vm->vm_vspace, (void*)RAM_START, RAM_END - RAM_START, seL4_AllRights, 1); assert(res.res); for (start = RAM_START;; start += BIT(bits)) { cspacepath_t frame; err = vka_cspace_alloc_path(vm->vka, &frame); assert(!err); err = simple_get_frame_cap(vm->simple, (void*)start, bits, &frame); if (err) { vka_cspace_free(vm->vka, frame.capPtr); break; } err = vspace_map_pages_at_vaddr(&vm->vm_vspace, &frame.capPtr, &bits, (void*)start, 1, bits, res); assert(!err); } }
int vm_create(const char* name, int priority, seL4_CPtr vmm_endpoint, seL4_Word vm_badge, vka_t *vka, simple_t *simple, vspace_t *vmm_vspace, ps_io_ops_t* io_ops, vm_t* vm) { seL4_CapData_t null_cap_data = {{0}}; seL4_CapData_t cspace_root_data; cspacepath_t src, dst; int err; vm->name = name; vm->ndevices = 0; vm->onode_head = NULL; vm->entry_point = NULL; vm->vka = vka; vm->simple = simple; vm->vmm_vspace = vmm_vspace; vm->io_ops = io_ops; vm->vchan_num_cons = 0; vm->vchan_cons = NULL; /* Create a cspace */ err = vka_alloc_cnode_object(vka, VM_CSPACE_SIZE_BITS, &vm->cspace); assert(!err); vka_cspace_make_path(vka, vm->cspace.cptr, &src); cspace_root_data = seL4_CapData_Guard_new(0, 32 - VM_CSPACE_SIZE_BITS); dst.root = vm->cspace.cptr; dst.capPtr = VM_CSPACE_SLOT; dst.capDepth = VM_CSPACE_SIZE_BITS; err = vka_cnode_mint(&dst, &src, seL4_AllRights, cspace_root_data); assert(!err); /* Create a vspace */ err = vka_alloc_page_directory(vka, &vm->pd); assert(!err); err = simple_ASIDPool_assign(simple, vm->pd.cptr); assert(err == seL4_NoError); err = sel4utils_get_vspace(vmm_vspace, &vm->vm_vspace, &vm->data, vka, vm->pd.cptr, &vm_object_allocation_cb, (void*)vm); assert(!err); /* Badge the endpoint */ vka_cspace_make_path(vka, vmm_endpoint, &src); err = vka_cspace_alloc_path(vka, &dst); assert(!err); err = vka_cnode_mint(&dst, &src, seL4_AllRights, seL4_CapData_Badge_new(vm_badge)); assert(!err); /* Copy it to the cspace of the VM for fault IPC */ src = dst; dst.root = vm->cspace.cptr; dst.capPtr = VM_FAULT_EP_SLOT; dst.capDepth = VM_CSPACE_SIZE_BITS; err = vka_cnode_copy(&dst, &src, seL4_AllRights); assert(!err); /* Create TCB */ err = vka_alloc_tcb(vka, &vm->tcb); assert(!err); err = seL4_TCB_Configure(vm_get_tcb(vm), VM_FAULT_EP_SLOT, priority - 1, vm->cspace.cptr, cspace_root_data, vm->pd.cptr, null_cap_data, 0, seL4_CapNull); assert(!err); /* Create VCPU */ err = vka_alloc_vcpu(vka, &vm->vcpu); assert(!err); err = seL4_ARM_VCPU_SetTCB(vm->vcpu.cptr, vm_get_tcb(vm)); assert(!err); /* Initialise fault system */ vm->fault = fault_init(vm); assert(vm->fault); return err; }
seL4_Error serial_server_parent_spawn_thread(simple_t *parent_simple, vka_t *parent_vka, vspace_t *parent_vspace, uint8_t priority) { const size_t shmem_max_size = SERIAL_SERVER_SHMEM_MAX_SIZE; seL4_Error error; size_t shmem_max_n_pages; cspacepath_t parent_cspace_cspath; seL4_MessageInfo_t tag; if (parent_simple == NULL || parent_vka == NULL || parent_vspace == NULL) { return seL4_InvalidArgument; } memset(get_serial_server(), 0, sizeof(serial_server_context_t)); /* Get a CPtr to the parent's root cnode. */ shmem_max_n_pages = BYTES_TO_4K_PAGES(shmem_max_size); vka_cspace_make_path(parent_vka, 0, &parent_cspace_cspath); get_serial_server()->server_vka = parent_vka; get_serial_server()->server_vspace = parent_vspace; get_serial_server()->server_cspace = parent_cspace_cspath.root; get_serial_server()->server_simple = parent_simple; /* Allocate the Endpoint that the server will be listening on. */ error = vka_alloc_endpoint(parent_vka, &get_serial_server()->server_ep_obj); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: failed to alloc endpoint, err=%d.", error); return error; } /* And also allocate a badged copy of the Server's endpoint that the Parent * can use to send to the Server. This is used to allow the Server to report * back to the Parent on whether or not the Server successfully bound to a * platform serial driver. * * This badged endpoint will be reused by the library as the Parent's badged * Endpoint cap, if the Parent itself ever chooses to connect() to the * Server later on. */ get_serial_server()->parent_badge_value = serial_server_badge_value_alloc(); if (get_serial_server()->parent_badge_value == SERIAL_SERVER_BADGE_VALUE_EMPTY) { error = seL4_NotEnoughMemory; goto out; } error = vka_mint_object(parent_vka, &get_serial_server()->server_ep_obj, &get_serial_server()->_badged_server_ep_cspath, seL4_AllRights, seL4_CapData_Badge_new(get_serial_server()->parent_badge_value)); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: Failed to mint badged Endpoint cap to " "server.\n" "\tParent cannot confirm Server thread successfully spawned."); goto out; } /* Allocate enough Cnode slots in our CSpace to enable us to receive * frame caps from our clients, sufficient to cover "shmem_max_size". * The problem here is that we're sort of forced to assume that we get * these slots contiguously. If they're not, we have a problem. * * If a client tries to send us too many frames, we respond with an error, * and indicate our shmem_max_size in the SSMSGREG_RESPONSE * message register. */ get_serial_server()->frame_cap_recv_cspaths = calloc(shmem_max_n_pages, sizeof(cspacepath_t)); if (get_serial_server()->frame_cap_recv_cspaths == NULL) { error = seL4_NotEnoughMemory; goto out; } for (size_t i = 0; i < shmem_max_n_pages; i++) { error = vka_cspace_alloc_path(parent_vka, &get_serial_server()->frame_cap_recv_cspaths[i]); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: Failed to alloc enough cnode slots " "to receive shmem frame caps equal to %d bytes.", shmem_max_size); goto out; } } error = sel4utils_configure_thread(parent_vka, parent_vspace, parent_vspace, get_serial_server()->server_ep_obj.cptr, priority, parent_cspace_cspath.root, seL4_NilData, &get_serial_server()->server_thread); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: sel4utils_configure_thread failed " "with %d.", error); goto out; } error = sel4utils_start_thread(&get_serial_server()->server_thread, &serial_server_main, NULL, NULL, 1); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: sel4utils_start_thread failed with " "%d.", error); goto out; } /* When the Server is spawned, it will reply to tell us whether or not it * successfully bound itself to the platform serial device. Block here * and wait for that reply. */ seL4_SetMR(SSMSGREG_FUNC, FUNC_SERVER_SPAWN_SYNC_REQ); tag = seL4_MessageInfo_new(0, 0, 0, SSMSGREG_SPAWN_SYNC_REQ_END); tag = seL4_Call(get_serial_server()->_badged_server_ep_cspath.capPtr, tag); /* Did all go well with the server? */ if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_SERVER_SPAWN_SYNC_ACK) { ZF_LOGE(SERSERVP"spawn_thread: Server thread sync message after spawn " "was not a SYNC_ACK as expected."); error = seL4_InvalidArgument; goto out; } error = seL4_MessageInfo_get_label(tag); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: Server thread failed to bind to the " "platform serial device."); goto out; } get_serial_server()->shmem_max_size = shmem_max_size; get_serial_server()->shmem_max_n_pages = shmem_max_n_pages; return 0; out: if (get_serial_server()->frame_cap_recv_cspaths != NULL) { for (size_t i = 0; i < shmem_max_n_pages; i++) { /* Since the array was allocated with calloc(), it was zero'd out. So * those indexes that didn't get allocated will have NULL in them. * Break early on the first index that has NULL. */ if (get_serial_server()->frame_cap_recv_cspaths[i].capPtr == 0) { break; } vka_cspace_free_path(parent_vka, get_serial_server()->frame_cap_recv_cspaths[i]); } } free(get_serial_server()->frame_cap_recv_cspaths); if (get_serial_server()->_badged_server_ep_cspath.capPtr != 0) { vka_cspace_free_path(parent_vka, get_serial_server()->_badged_server_ep_cspath); } if (get_serial_server()->parent_badge_value != SERIAL_SERVER_BADGE_VALUE_EMPTY) { serial_server_badge_value_free(get_serial_server()->parent_badge_value); } vka_free_object(parent_vka, &get_serial_server()->server_ep_obj); return error; }