uint32_t ufi_read_capacity(usb_dev_t *udev) { int err; uint32_t ret; struct ufi_cdb cdb; struct xact data; memset(&cdb, 0, sizeof(struct ufi_cdb)); cdb.opcode = READ_CAPACITY; data.type = PID_IN; data.len = 8; err = usb_alloc_xact(udev->dman, &data, 1); if (err) { ZF_LOGF("Out of DMA memory\n"); } err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), &data, 1, UFI_INPUT); if (err) { ZF_LOGF("Transfer error\n"); } ret = *(uint32_t*)data.vaddr; usb_destroy_xact(udev->dman, &data, 1); return ret; }
static void ufi_read12(usb_dev_t *udev, uint32_t lba, uint32_t count) { int err; struct ufi_cdb cdb; struct xact data; memset(&cdb, 0, sizeof(struct ufi_cdb)); cdb.opcode = READ_12; cdb.lba = __builtin_bswap32(lba); cdb.length = __builtin_bswap16(count); data.type = PID_IN; data.len = UFI_BLK_SIZE * count; err = usb_alloc_xact(udev->dman, &data, 1); if (err) { ZF_LOGF("Out of DMA memory\n"); } err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), &data, 1, UFI_INPUT); if (err) { ZF_LOGF("Transfer error\n"); } usb_destroy_xact(udev->dman, &data, 1); }
static void ufi_inquiry(usb_dev_t *udev) { int err; struct ufi_cdb cdb; struct xact data; memset(&cdb, 0, sizeof(struct ufi_cdb)); /* Inquiry UFI disk */ cdb.opcode = INQUIRY; cdb.lba = UFI_INQ_LEN << UFI_LBA_SHF; data.type = PID_IN; data.len = UFI_INQ_LEN; err = usb_alloc_xact(udev->dman, &data, 1); if (err) { ZF_LOGF("Out of DMA memory\n"); } err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), &data, 1, UFI_INPUT); if (err) { ZF_LOGF("Transfer error\n"); } usb_destroy_xact(udev->dman, &data, 1); }
static void ufi_mode_sense(usb_dev_t *udev) { int err; struct ufi_cdb cdb; struct xact data; memset(&cdb, 0, sizeof(struct ufi_cdb)); cdb.opcode = MODE_SENSE; cdb.lba = UFI_MODE_PAGE_ALL; cdb.length = UFI_MODE_SENSE_LEN << UFI_LBA_SHF; data.type = PID_IN; data.len = UFI_MODE_SENSE_LEN; err = usb_alloc_xact(udev->dman, &data, 1); if (err) { ZF_LOGF("Out of DMA memory\n"); } err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), &data, 1, UFI_INPUT); if (err) { ZF_LOGF("Transfer error\n"); } usb_destroy_xact(udev->dman, &data, 1); }
static void ufi_request_sense(usb_dev_t *udev) { int err; struct ufi_cdb cdb; struct xact data; memset(&cdb, 0, sizeof(struct ufi_cdb)); /* Fill in the command */ cdb.opcode = REQUEST_SENSE; cdb.lba = UFI_SENSE_LEN << UFI_LBA_SHF; data.type = PID_IN; data.len = UFI_SENSE_LEN; err = usb_alloc_xact(udev->dman, &data, 1); if (err) { ZF_LOGF("Out of DMA memory\n"); } err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), &data, 1, UFI_INPUT); if (err) { ZF_LOGF("Transfer error\n"); } usb_destroy_xact(udev->dman, &data, 1); }
static void init_allocator(env_t env, test_init_data_t *init_data) { UNUSED int error; UNUSED reservation_t virtual_reservation; /* initialise allocator */ allocman_t *allocator = bootstrap_use_current_1level(init_data->root_cnode, init_data->cspace_size_bits, init_data->free_slots.start, init_data->free_slots.end, ALLOCATOR_STATIC_POOL_SIZE, allocator_mem_pool); if (allocator == NULL) { ZF_LOGF("Failed to bootstrap allocator"); } allocman_make_vka(&env->vka, allocator); /* fill the allocator with untypeds */ seL4_CPtr slot; unsigned int size_bits_index; for (slot = init_data->untypeds.start, size_bits_index = 0; slot <= init_data->untypeds.end; slot++, size_bits_index++) { cspacepath_t path; vka_cspace_make_path(&env->vka, slot, &path); /* allocman doesn't require the paddr unless we need to ask for phys addresses, * which we don't. */ uintptr_t fake_paddr = 0; size_t size_bits = init_data->untyped_size_bits_list[size_bits_index]; error = allocman_utspace_add_uts(allocator, 1, &path, &size_bits, &fake_paddr); if (error) { ZF_LOGF("Failed to add untyped objects to allocator"); } } /* create a vspace */ void *existing_frames[init_data->stack_pages + 2]; existing_frames[0] = (void *) init_data; existing_frames[1] = seL4_GetIPCBuffer(); assert(init_data->stack_pages > 0); for (int i = 0; i < init_data->stack_pages; i++) { existing_frames[i + 2] = init_data->stack + (i * PAGE_SIZE_4K); } error = sel4utils_bootstrap_vspace(&env->vspace, &alloc_data, init_data->page_directory, &env->vka, NULL, NULL, existing_frames); /* switch the allocator to a virtual memory pool */ void *vaddr; virtual_reservation = vspace_reserve_range(&env->vspace, ALLOCATOR_VIRTUAL_POOL_SIZE, seL4_AllRights, 1, &vaddr); if (virtual_reservation.res == 0) { ZF_LOGF("Failed to switch allocator to virtual memory pool"); } bootstrap_configure_virtual_pool(allocator, vaddr, ALLOCATOR_VIRTUAL_POOL_SIZE, env->page_directory); }
void window_init(struct window_t* w, const char* title, const unsigned int width, const unsigned int height, struct window_t* parent) { glfwWindowHint(GLFW_RESIZABLE, false); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); GLFWwindow* sharedContext = (parent == NULL) ? NULL : parent->handle; w->handle = glfwCreateWindow(width, height, title, NULL, sharedContext); w->width = width; w->height = height; if (w->handle == NULL) { ZF_LOGF("Could not create GLFW window."); } setupOpenGL(w, width, height); }
int otg_ep0_setup(usb_otg_t otg, otg_setup_cb cb, void *token) { if (!otg || !otg->ep0_setup) { ZF_LOGF("OTG: Invalid arguments\n"); } return otg->ep0_setup(otg, cb, token); }
/* Handle VM exit in VMM module. */ static void vmm_handle_vm_exit(vmm_vcpu_t *vcpu) { int reason = vmm_guest_exit_get_reason(&vcpu->guest_state); /* Distribute the task according to the exit info. */ vmm_print_guest_context(3, vcpu); if (reason == -1) { ZF_LOGF("Kernel failed to perform vmlaunch or vmresume, we have no recourse"); } if (!vcpu->vmm->vmexit_handlers[reason]) { printf("VM_FATAL_ERROR ::: vm exit handler is NULL for reason 0x%x.\n", reason); vmm_print_guest_context(0, vcpu); vcpu->online = 0; return; } /* Call the handler. */ if (vcpu->vmm->vmexit_handlers[reason](vcpu)) { printf("VM_FATAL_ERROR ::: vmexit handler return error\n"); vmm_print_guest_context(0, vcpu); vcpu->online = 0; return; } /* Reply to the VM exit exception to resume guest. */ vmm_sync_guest_state(vcpu); if (vcpu->guest_state.exit.in_exit && !vcpu->guest_state.virt.interrupt_halt) { /* Guest is blocked, but we are no longer halted. Reply to it */ vmm_reply_vm_exit(vcpu); } }
vka_utspace_alloc_at_fn arch_get_serial_utspace_alloc_at(driver_env_t _env) { static bool call_once = false; if (call_once) { ZF_LOGF("This function can only be called once."); } call_once = true; return serial_utspace_alloc_at_fn; }
static testcase_t * find_test(const char *name) { testcase_t *test = sel4test_get_test(name); if (test == NULL) { ZF_LOGF("Failed to find test %s", name); } return test; }
void init_timer(env_t env, test_init_data_t *init_data) { /* minimal simple implementation to get the platform * default timer off the ground */ env->simple.arch_simple.irq = get_irq; env->simple.data = (void *) init_data; env->simple.arch_simple.data = (void *) init_data; UNUSED int error; arch_init_simple(&env->simple); error = vka_alloc_notification(&env->vka, &env->timer_notification); if (error != 0) { ZF_LOGF("Failed to allocate notification object"); } env->timer = sel4platsupport_get_default_timer(&env->vka, &env->vspace, &env->simple, env->timer_notification.cptr); if (env->timer == NULL) { ZF_LOGF("Failed to initialise default timer"); } }
static seL4_Error get_irq(void *data, int irq, seL4_CNode root, seL4_Word index, uint8_t depth) { test_init_data_t *init = (test_init_data_t *) data; assert(irq == DEFAULT_TIMER_INTERRUPT); int error = seL4_CNode_Copy(root, index, depth, init->root_cnode, init->timer_irq, seL4_WordBits, seL4_AllRights); if (error != 0) { ZF_LOGF("Failed to copy irq cap\n"); } return error; }
static void ufi_test_unit_ready(usb_dev_t *udev) { int err; struct ufi_cdb cdb; memset(&cdb, 0, sizeof(struct ufi_cdb)); /* Fill in the command */ cdb.opcode = TEST_UNIT_READY; err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), NULL, 0, UFI_OUTPUT); if (err) { ZF_LOGF("Transfer error\n"); } }
static void ufi_prevent_allow_medium_removal(usb_dev_t *udev, int enable) { int err; struct ufi_cdb cdb; memset(&cdb, 0, sizeof(struct ufi_cdb)); cdb.opcode = ALLOW_REMOVAL; cdb.lba = enable << 8; err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb), NULL, 0, UFI_OUTPUT); if (err) { ZF_LOGF("Transfer error\n"); } }
void cb_tcpclient(uint16_t ev, struct pico_socket *s) { static int w_size = 0; static int r_size = 0; static int closed = 0; int r, w; char buf[1024]; ZF_LOGD("tcpclient> wakeup %lu, event %u\n", count, ev); if (ev & PICO_SOCK_EV_RD) { do { r = pico_socket_read(s, buf, 1024); if (r > 0) { printf("READ >>"); fwrite(buf, r, 1, stdout); } if (r < 0){ ZF_LOGF("READ ERROR\n"); } } while(r > 0); } if (ev & PICO_SOCK_EV_CONN) { ZF_LOGD("Connection established with server.\n"); } if (ev & PICO_SOCK_EV_FIN) { ZF_LOGD("Socket closed. Exit normally. \n"); } if (ev & PICO_SOCK_EV_ERR) { ZF_LOGD("Socket error received: %s. Bailing out.\n", strerror(pico_err)); } if (ev & PICO_SOCK_EV_CLOSE) { ZF_LOGD("Socket received close from peer - Wrong case if not all client data sent!\n"); pico_socket_close(s); } if (ev & PICO_SOCK_EV_WR) { ZF_LOGD("Pico socket write cb\n"); } }
int main(int argc, char **argv) { test_init_data_t *init_data; struct env env; assert(argc >= 2); /* in order to have some shitty almost-fork-like semantics * main can get run multiple times. Look in src/helpers.c * for where this is used. Just means we check the first * arg, and if not NULL jmp to it */ void (*helper_thread)(int argc,char **argv) = (void(*)(int, char**))atol(argv[1]); if (helper_thread) { helper_thread(argc, argv); } /* parse args */ assert(argc == 3); endpoint = (seL4_CPtr) atoi(argv[2]); /* read in init data */ init_data = receive_init_data(endpoint); /* configure env */ env.cspace_root = init_data->root_cnode; env.page_directory = init_data->page_directory; env.endpoint = endpoint; env.priority = init_data->priority; env.cspace_size_bits = init_data->cspace_size_bits; env.tcb = init_data->tcb; env.domain = init_data->domain; #ifndef CONFIG_KERNEL_STABLE env.asid_pool = init_data->asid_pool; env.asid_ctrl = init_data->asid_ctrl; #endif /* CONFIG_KERNEL_STABLE */ #ifdef CONFIG_IOMMU env.io_space = init_data->io_space; #endif env.num_regions = init_data->num_elf_regions; memcpy(env.regions, init_data->elf_regions, sizeof(sel4utils_elf_region_t) * env.num_regions); /* initialse cspace, vspace and untyped memory allocation */ init_allocator(&env, init_data); /* initialise the timer */ init_timer(&env, init_data); /* find the test */ testcase_t *test = find_test(init_data->name); /* run the test */ int result = 0; if (test) { printf("Running test %s (%s)\n", test->name, test->description); result = test->function(&env); } else { result = FAILURE; ZF_LOGF("Cannot find test %s\n", init_data->name); } printf("Test %s %s\n", init_data->name, result == SUCCESS ? "passed" : "failed"); /* send our result back */ seL4_MessageInfo_t info = seL4_MessageInfo_new(seL4_NoFault, 0, 0, 1); seL4_SetMR(0, result); seL4_Send(endpoint, info); /* It is expected that we are torn down by the test driver before we are * scheduled to run again after signalling them with the above send. */ assert(!"unreachable"); return 0; }
int main(int argc, char **argv) { env_t *env; irquser_results_t *results; vka_object_t endpoint = {0}; static size_t object_freq[seL4_ObjectTypeCount] = { [seL4_TCBObject] = 2, [seL4_EndpointObject] = 1, #ifdef CONFIG_KERNEL_RT [seL4_SchedContextObject] = 2, [seL4_ReplyObject] = 2 #endif }; env = benchmark_get_env(argc, argv, sizeof(irquser_results_t), object_freq); benchmark_init_timer(env); results = (irquser_results_t *) env->results; if (vka_alloc_endpoint(&env->slab_vka, &endpoint) != 0) { ZF_LOGF("Failed to allocate endpoint\n"); } /* set up globals */ done_ep = endpoint.cptr; timer = &env->timer; timer_signal = env->ntfn.cptr; int error = ltimer_reset(&env->timer.ltimer); ZF_LOGF_IF(error, "Failed to start timer"); error = ltimer_set_timeout(&env->timer.ltimer, INTERRUPT_PERIOD_NS, TIMEOUT_PERIODIC); ZF_LOGF_IF(error, "Failed to configure timer"); sel4bench_init(); sel4utils_thread_t ticker, spinner; /* measurement overhead */ ccnt_t start, end; for (int i = 0; i < N_RUNS; i++) { SEL4BENCH_READ_CCNT(start); SEL4BENCH_READ_CCNT(end); results->overheads[i] = end - start; } /* create a frame for the shared time variable so we can share it between processes */ ccnt_t *local_current_time = (ccnt_t *) vspace_new_pages(&env->vspace, seL4_AllRights, 1, seL4_PageBits); if (local_current_time == NULL) { ZF_LOGF("Failed to allocate page"); } /* first run the benchmark between two threads in the current address space */ benchmark_configure_thread(env, endpoint.cptr, seL4_MaxPrio - 1, "ticker", &ticker); benchmark_configure_thread(env, endpoint.cptr, seL4_MaxPrio - 2, "spinner", &spinner); error = sel4utils_start_thread(&ticker, (sel4utils_thread_entry_fn) ticker_fn, (void *) results->thread_results, (void *) local_current_time, true); if (error) { ZF_LOGF("Failed to start ticker"); } char strings[1][WORD_STRING_SIZE]; char *spinner_argv[1]; sel4utils_create_word_args(strings, spinner_argv, 1, (seL4_Word) local_current_time); error = sel4utils_start_thread(&spinner, (sel4utils_thread_entry_fn) spinner_fn, (void *) 1, (void *) spinner_argv, true); assert(!error); benchmark_wait_children(endpoint.cptr, "child of irq-user", 1); /* stop spinner thread */ error = seL4_TCB_Suspend(spinner.tcb.cptr); assert(error == seL4_NoError); error = seL4_TCB_Suspend(ticker.tcb.cptr); assert(error == seL4_NoError); /* now run the benchmark again, but run the spinner in another address space */ /* restart ticker */ error = sel4utils_start_thread(&ticker, (sel4utils_thread_entry_fn) ticker_fn, (void *) results->process_results, (void *) local_current_time, true); assert(!error); sel4utils_process_t spinner_process; benchmark_shallow_clone_process(env, &spinner_process, seL4_MaxPrio - 2, spinner_fn, "spinner"); /* share the current time variable with the spinner process */ void *current_time_remote = vspace_share_mem(&env->vspace, &spinner_process.vspace, (void *) local_current_time, 1, seL4_PageBits, seL4_AllRights, true); assert(current_time_remote != NULL); /* start the spinner process */ sel4utils_create_word_args(strings, spinner_argv, 1, (seL4_Word) current_time_remote); error = sel4utils_spawn_process(&spinner_process, &env->slab_vka, &env->vspace, 1, spinner_argv, 1); if (error) { ZF_LOGF("Failed to start spinner process"); } benchmark_wait_children(endpoint.cptr, "child of irq-user", 1); /* done -> results are stored in shared memory so we can now return */ benchmark_finished(EXIT_SUCCESS); return 0; }
static json_t * process(void *results) { irq_results_t *irq_results = (irq_results_t *) results; /* Sort and group data by tracepoints. A stable sort is used so the first N_IGNORED * results of each tracepoint can be ignored, as this keeps the data in chronological * order. */ logging_stable_sort_log(irq_results->kernel_log, irq_results->n); logging_group_log_by_key(irq_results->kernel_log, irq_results->n, sizes, offsets, CONFIG_MAX_NUM_TRACE_POINTS); /* Copy the cycle counts into a separate array to simplify further processing */ for (int i = 0; i < irq_results->n; ++i) { kernel_log_data[i] = kernel_logging_entry_get_data(&irq_results->kernel_log[i]); } /* Process log entries generated by an "empty" tracepoint, which recorded * the number of cycles between starting a tracepoint and stopping it * immediately afterwards. This will determine the overhead introduced by * using tracepoints. */ int n_overhead_data = sizes[TRACE_POINT_OVERHEAD] - N_IGNORED; if (n_overhead_data <= 0) { ZF_LOGF("Insufficient data recorded. Was the kernel built with the relevant tracepoints?\n"); } ccnt_t *overhead_data = &kernel_log_data[offsets[TRACE_POINT_OVERHEAD] + N_IGNORED]; /* The results of the IRQ path benchmark are split over multiple tracepoints. * A new buffer is allocated to store the amalgamated results. */ int n_data = sizes[TRACE_POINT_IRQ_PATH_START] - N_IGNORED; if (n_data <= 0) { ZF_LOGF("Insufficient data recorded. Was the kernel built with the relevant tracepoints?\n"); } ccnt_t *data = (ccnt_t*)malloc(sizeof(ccnt_t) * n_data); if (data == NULL) { ZF_LOGF("Failed to allocate memory\n"); } json_t *array = json_array(); result_desc_t desc = {0}; result_t result = process_result(n_overhead_data, overhead_data, desc); result_set_t set = { .name = "Tracepoint overhead", .n_results = 1, .results = &result, }; json_array_append_new(array, result_set_to_json(set)); /* Add the results from the IRQ path tracepoints to get the total IRQ path cycle counts. * The average overhead is subtracted from each cycle count (doubled as there are 2 * tracepoints) to account for overhead added to the cycle counts by use of tracepoints. */ ccnt_t *starts = &kernel_log_data[offsets[TRACE_POINT_IRQ_PATH_START] + N_IGNORED]; ccnt_t *ends = &kernel_log_data[offsets[TRACE_POINT_IRQ_PATH_END] + N_IGNORED]; for (int i = 0; i < n_data; ++i) { data[i] = starts[i] + ends[i] - (result.mean * 2); } set.name = "IRQ Path Cycle Count (accounting for overhead)"; result = process_result(n_data, data, desc); json_array_append_new(array, result_set_to_json(set)); free(data); return array; } static benchmark_t irq_benchmark = { .name = "irq", .enabled = config_set(CONFIG_APP_IRQBENCH) && CONFIG_MAX_NUM_TRACE_POINTS == 3, .results_pages = BYTES_TO_SIZE_BITS_PAGES(sizeof(irq_results_t), seL4_PageBits), .process = process, .init = blank_init }; benchmark_t * irq_benchmark_new(void) { return &irq_benchmark; } static json_t * irquser_process(void *r) { irquser_results_t *raw_results = r; result_desc_t desc = { .ignored = N_IGNORED, .name = "IRQ user measurement overhead" }; result_t results[3]; results[0] = process_result(N_RUNS, raw_results->overheads, desc); desc.overhead = results[0].min; results[1] = process_result(N_RUNS, raw_results->thread_results, desc); results[2] = process_result(N_RUNS, raw_results->process_results, desc); char *types[] = {"Measurement overhead", "Without context switch", "With context switch"}; column_t col = { .header = "Type", .type = JSON_STRING, .string_array = types }; result_set_t set = { .name = "IRQ path cycle count (measured from user level)", .n_results = 3, .results = results, .n_extra_cols = 1, .extra_cols = &col }; json_t *json = json_array(); json_array_append_new(json, result_set_to_json(set)); return json; } static benchmark_t irquser_benchmark = { .name = "irquser", .enabled = config_set(CONFIG_APP_IRQUSERBENCH), .results_pages = BYTES_TO_SIZE_BITS_PAGES(sizeof(irquser_results_t), seL4_PageBits), .process = irquser_process, .init = blank_init }; benchmark_t * irquser_benchmark_new(void) { return &irquser_benchmark; }
int serial_utspace_alloc_at_fn(void *data, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, uintptr_t paddr, seL4_Word *cookie) { ZF_LOGF("Serial on RISC-V doesn't use utspace"); return -1; }
static void ufi_format_unit() { ZF_LOGF("Not implemented\n"); }