void pre_init(void) { int error; set_putchar(putchar_putchar); /* Camkes adds nothing to our address space, so this array is empty */ void *existing_frames[] = { NULL }; camkes_make_simple(&camkes_simple); camkes_simple.IOPort_cap = simple_ioport_wrapper; camkes_simple.frame_cap = simple_frame_cap_wrapper; /* Initialize allocator */ allocman = bootstrap_use_current_1level( simple_get_cnode(&camkes_simple), simple_get_cnode_size_bits(&camkes_simple), simple_last_valid_cap(&camkes_simple) + 1, BIT(simple_get_cnode_size_bits(&camkes_simple)), sizeof(allocator_mempool), allocator_mempool ); assert(allocman); error = allocman_add_simple_untypeds(allocman, &camkes_simple); make_proxy_vka(&vka, allocman); /* Initialize the vspace */ error = sel4utils_bootstrap_vspace(&vspace, &vspace_data, simple_get_init_cap(&camkes_simple, seL4_CapInitThreadPD), &vka, NULL, NULL, existing_frames); assert(!error); /* Create temporary mapping reservation, and map in a frame to * create any book keeping */ reservation_t reservation; reservation.res = allocman_mspace_alloc(allocman, sizeof(sel4utils_res_t), &error); assert(reservation.res); void *reservation_vaddr; error = sel4utils_reserve_range_no_alloc(&vspace, reservation.res, PAGE_SIZE_4K, seL4_AllRights, 1, &reservation_vaddr); assert(!error); error = vspace_new_pages_at_vaddr(&vspace, reservation_vaddr, 1, seL4_PageBits, reservation); assert(!error); vspace_unmap_pages(&vspace, reservation_vaddr, 1, seL4_PageBits, VSPACE_FREE); proxy_give_vspace(&vka, &vspace, reservation_vaddr, reservation); sel4utils_reserve_range_no_alloc(&vspace, &muslc_brk_reservation_memory, BRK_VIRTUAL_SIZE, seL4_AllRights, 1, &muslc_brk_reservation_start); muslc_this_vspace = &vspace; muslc_brk_reservation = (reservation_t){.res = &muslc_brk_reservation_memory}; }
/* Run a single test. * Each test is launched as its own process. */ int run_test(struct testcase *test) { UNUSED int error; sel4utils_process_t test_process; /* Test intro banner. */ printf(" %s\n", test->name); error = sel4utils_configure_process(&test_process, &env.vka, &env.vspace, env.init->priority, TESTS_APP); assert(error == 0); /* set up caps about the process */ env.init->page_directory = copy_cap_to_process(&test_process, test_process.pd.cptr); env.init->root_cnode = SEL4UTILS_CNODE_SLOT; env.init->tcb = copy_cap_to_process(&test_process, test_process.thread.tcb.cptr); env.init->domain = copy_cap_to_process(&test_process, simple_get_init_cap(&env.simple, seL4_CapDomain)); #ifndef CONFIG_KERNEL_STABLE env.init->asid_pool = copy_cap_to_process(&test_process, simple_get_init_cap(&env.simple, seL4_CapInitThreadASIDPool)); #endif /* CONFIG_KERNEL_STABLE */ #ifdef CONFIG_IOMMU env.init->io_space = copy_cap_to_process(&test_process, simple_get_init_cap(&env.simple, seL4_CapIOSpace)); #endif /* CONFIG_IOMMU */ /* setup data about untypeds */ env.init->untypeds = copy_untypeds_to_process(&test_process, untypeds, num_untypeds); copy_timer_caps(env.init, &env, &test_process); /* copy the fault endpoint - we wait on the endpoint for a message * or a fault to see when the test finishes */ seL4_CPtr endpoint = copy_cap_to_process(&test_process, test_process.fault_endpoint.cptr); /* WARNING: DO NOT COPY MORE CAPS TO THE PROCESS BEYOND THIS POINT, * AS THE SLOTS WILL BE CONSIDERED FREE AND OVERRIDDEN BY THE TEST PROCESS. */ /* set up free slot range */ env.init->cspace_size_bits = CONFIG_SEL4UTILS_CSPACE_SIZE_BITS; env.init->free_slots.start = endpoint + 1; env.init->free_slots.end = (1u << CONFIG_SEL4UTILS_CSPACE_SIZE_BITS); assert(env.init->free_slots.start < env.init->free_slots.end); /* copy test name */ strncpy(env.init->name, test->name + strlen("TEST_"), TEST_NAME_MAX); #ifdef SEL4_DEBUG_KERNEL seL4_DebugNameThread(test_process.thread.tcb.cptr, env.init->name); #endif /* set up args for the test process */ char endpoint_string[10]; char sel4test_name[] = { TESTS_APP }; char zero_string[] = {"0"}; char *argv[] = {sel4test_name, zero_string, endpoint_string}; argv[0] = endpoint_string; snprintf(endpoint_string, 10, "%d", endpoint); /* spawn the process */ error = sel4utils_spawn_process_v(&test_process, &env.vka, &env.vspace, ARRAY_SIZE(argv), argv, 1); assert(error == 0); /* send env.init_data to the new process */ void *remote_vaddr = send_init_data(&env, test_process.fault_endpoint.cptr, &test_process); /* wait on it to finish or fault, report result */ seL4_Word badge; seL4_MessageInfo_t info = seL4_Wait(test_process.fault_endpoint.cptr, &badge); int result = seL4_GetMR(0); if (seL4_MessageInfo_get_label(info) != seL4_NoFault) { sel4utils_print_fault_message(info, test->name); result = FAILURE; } /* unmap the env.init data frame */ vspace_unmap_pages(&test_process.vspace, remote_vaddr, 1, PAGE_BITS_4K, NULL); /* reset all the untypeds for the next test */ for (int i = 0; i < num_untypeds; i++) { cspacepath_t path; vka_cspace_make_path(&env.vka, untypeds[i].cptr, &path); vka_cnode_revoke(&path); } /* destroy the process */ sel4utils_destroy_process(&test_process, &env.vka); test_assert(result == SUCCESS); return result; }
/* Entry point of of VMM main host module. */ void vmm_run(vmm_t *vmm) { int error; DPRINTF(2, "VMM MAIN HOST MODULE STARTED\n"); for (int i = 0; i < vmm->num_vcpus; i++) { vmm_vcpu_t *vcpu = &vmm->vcpus[i]; vcpu->guest_state.virt.interrupt_halt = 0; vcpu->guest_state.exit.in_exit = 0; /* sync the existing guest state */ vmm_sync_guest_state(vcpu); vmm_sync_guest_context(vcpu); /* now invalidate everything */ assert(vmm_guest_state_no_modified(&vcpu->guest_state)); vmm_guest_state_invalidate_all(&vcpu->guest_state); } /* Start the boot vcpu guest thread running */ vmm->vcpus[BOOT_VCPU].online = 1; /* Get our interrupt pending callback happening */ seL4_CPtr notification = vmm->plat_callbacks.get_async_event_notification(); error = seL4_TCB_BindNotification(simple_get_init_cap(&vmm->host_simple, seL4_CapInitThreadTCB), vmm->plat_callbacks.get_async_event_notification()); assert(error == seL4_NoError); while (1) { /* Block and wait for incoming msg or VM exits. */ seL4_Word badge; int fault; vmm_vcpu_t *vcpu = &vmm->vcpus[BOOT_VCPU]; if (vcpu->online && !vcpu->guest_state.virt.interrupt_halt && !vcpu->guest_state.exit.in_exit) { seL4_SetMR(0, vmm_guest_state_get_eip(&vcpu->guest_state)); seL4_SetMR(1, vmm_guest_state_get_control_ppc(&vcpu->guest_state)); seL4_SetMR(2, vmm_guest_state_get_control_entry(&vcpu->guest_state)); fault = seL4_VMEnter(vcpu->guest_vcpu, &badge); if (fault == SEL4_VMENTER_RESULT_FAULT) { /* We in a fault */ vcpu->guest_state.exit.in_exit = 1; /* Update the guest state from a fault */ seL4_Word fault_message[SEL4_VMENTER_RESULT_FAULT_LEN]; for (int i = 0 ; i < SEL4_VMENTER_RESULT_FAULT_LEN; i++) { fault_message[i] = seL4_GetMR(i); } vmm_guest_state_invalidate_all(&vcpu->guest_state); vmm_update_guest_state_from_fault(vcpu, fault_message); } else { /* update the guest state from a non fault */ seL4_Word int_message[SEL4_VMENTER_RESULT_NOTIF_LEN]; for (int i = 0 ; i < SEL4_VMENTER_RESULT_NOTIF_LEN; i++) { int_message[i] = seL4_GetMR(i); } vmm_guest_state_invalidate_all(&vcpu->guest_state); vmm_update_guest_state_from_interrupt(vcpu, int_message); } } else { seL4_Wait(notification, &badge); fault = SEL4_VMENTER_RESULT_NOTIF; } if (fault == SEL4_VMENTER_RESULT_NOTIF) { assert(badge >= vmm->num_vcpus); /* assume interrupt */ int raise = vmm->plat_callbacks.do_async(badge); if (raise == 0) { /* Check if this caused PIC to generate interrupt */ vmm_check_external_interrupt(vmm); } continue; } /* Handle the vm exit */ vmm_handle_vm_exit(vcpu); vmm_check_external_interrupt(vmm); DPRINTF(5, "VMM main host blocking for another message...\n"); } }
static int vmm_init(void) { vka_object_t fault_ep_obj; vka_t* vka; simple_t* simple; vspace_t* vspace; int err; vka = &_vka; vspace = &_vspace; simple = &_simple; fault_ep_obj.cptr = 0; /* Camkes adds nothing to our address space, so this array is empty */ void *existing_frames[] = { NULL }; camkes_make_simple(simple); start_extra_frame_caps = simple_last_valid_cap(simple) + 1; /* Initialize allocator */ allocman = bootstrap_use_current_1level( simple_get_cnode(simple), simple_get_cnode_size_bits(simple), simple_last_valid_cap(simple) + 1 + num_extra_frame_caps, BIT(simple_get_cnode_size_bits(simple)), sizeof(allocator_mempool), allocator_mempool ); assert(allocman); err = allocman_add_simple_untypeds(allocman, simple); assert(!err); allocman_make_vka(vka, allocman); /* Initialize the vspace */ err = sel4utils_bootstrap_vspace(vspace, &_alloc_data, simple_get_init_cap(simple, seL4_CapInitThreadPD), vka, NULL, NULL, existing_frames); assert(!err); /* Initialise device support */ err = sel4platsupport_new_io_mapper(*simple, *vspace, *vka, &_io_ops.io_mapper); assert(!err); /* Initialise MUX subsystem */ err = mux_sys_init(&_io_ops, &_io_ops.mux_sys); assert(!err); /* Initialise DMA */ err = dma_dmaman_init(&_dma_morecore, NULL, &_io_ops.dma_manager); assert(!err); /* Allocate an endpoint for listening to events */ err = vka_alloc_endpoint(vka, &fault_ep_obj); assert(!err); _fault_endpoint = fault_ep_obj.cptr; /* Create an IRQ server */ err = irq_server_new(vspace, vka, simple_get_cnode(simple), IRQSERVER_PRIO, simple, fault_ep_obj.cptr, IRQ_MESSAGE_LABEL, 256, &_irq_server); assert(!err); return 0; }