/* * Inject data into the given vspace. * TODO: Don't keep these pages mapped in */ static int load_segment_into_vspace(seL4_RISCV_PageDirectory dest_as, char *src, unsigned long segment_size, unsigned long file_size, unsigned long dst, unsigned long permissions) { assert(file_size <= segment_size); unsigned long pos; /* We work a page at a time in the destination vspace. */ pos = 0; while(pos < segment_size) { seL4_Word paddr; seL4_CPtr sos_cap, tty_cap; seL4_Word vpage, kvpage; unsigned long kdst; int nbytes; int err; kdst = dst + PROCESS_SCRATCH; vpage = PAGE_ALIGN(dst); kvpage = PAGE_ALIGN(kdst); /* First we need to create a frame */ paddr = ut_alloc(seL4_PageBits); conditional_panic(!paddr, "Out of memory - could not allocate frame"); err = cspace_ut_retype_addr(paddr, seL4_RISCV_4K, seL4_PageBits, cur_cspace, &tty_cap); conditional_panic(err, "Failed to retype to a frame object"); /* Copy the frame cap as we need to map it into 2 address spaces */ sos_cap = cspace_copy_cap(cur_cspace, cur_cspace, tty_cap, seL4_AllRights); conditional_panic(sos_cap == 0, "Failed to copy frame cap"); /* Map the frame into tty_test address spaces */ err = map_page(tty_cap, dest_as, vpage, permissions, seL4_RISCV_Default_VMAttributes); conditional_panic(err, "Failed to map to tty address space"); /* Map the frame into sos address spaces */ err = map_page(sos_cap, seL4_CapInitThreadPD, kvpage, seL4_AllRights, seL4_RISCV_Default_VMAttributes); conditional_panic(err, "Failed to map sos address space"); /* Now copy our data into the destination vspace. */ nbytes = PAGESIZE - (dst & PAGEMASK); if (pos < file_size){ memcpy((void*)kdst, (void*)src, MIN(nbytes, file_size - pos)); } /* Not observable to I-cache yet so flush the frame */ // seL4_ARM_Page_Unify_Instruction(sos_cap, 0, PAGESIZE); pos += nbytes; dst += nbytes; src += nbytes; } return 0; }
/* * This function need to be called after network_init * As it requires nfs to be mounted */ static void _filesystem_init(void) { int err; struct vnode* vn = malloc(sizeof(struct vnode)); conditional_panic(vn == NULL, "Failed to allocate mountpoint vnode memory\n"); vn->vn_name = (char*)malloc(strlen(ROOT_PATH)); conditional_panic(vn->vn_name == NULL, "Failed to allocate mountpoint vnode memory\n"); strcpy(vn->vn_name, ROOT_PATH); vn->vn_ops = malloc(sizeof(struct vnode_ops)); conditional_panic(vn->vn_ops == NULL, "Failed to allocate mountpoint vnode memory\n"); err = nfs_dev_init_mntpoint_vnode(vn, &mnt_point); conditional_panic(err, "Failed to initialise mountpoint vnode\n"); dprintf(3, "main mnt_poitn = %p\n", &mnt_point); vn->vn_opencount = 1; err = vfs_vnt_insert(vn); conditional_panic(err, "Failed to insert mountpoint vnode to vnode table\n"); /* Setup the timeout for NFS */ nfs_dev_setup_timeout(); }
static void _sos_ipc_init(seL4_CPtr* ipc_ep, seL4_CPtr* async_ep){ seL4_Word ep_addr, aep_addr; int err; /* Create an Async endpoint for interrupts */ aep_addr = ut_alloc(seL4_EndpointBits); conditional_panic(!aep_addr, "No memory for async endpoint"); err = cspace_ut_retype_addr(aep_addr, seL4_AsyncEndpointObject, seL4_EndpointBits, cur_cspace, async_ep); conditional_panic(err, "Failed to allocate c-slot for Interrupt endpoint"); /* Bind the Async endpoint to our TCB */ err = seL4_TCB_BindAEP(seL4_CapInitThreadTCB, *async_ep); conditional_panic(err, "Failed to bind ASync EP to TCB"); /* Create an endpoint for user application IPC */ ep_addr = ut_alloc(seL4_EndpointBits); conditional_panic(!ep_addr, "No memory for endpoint"); err = cspace_ut_retype_addr(ep_addr, seL4_EndpointObject, seL4_EndpointBits, cur_cspace, ipc_ep); conditional_panic(err, "Failed to allocate c-slot for IPC endpoint"); }
/* A faulting page walk. May need to alloc various frames for SOS and seL4 page tables. */ int page_walk(sos_pcb *pcb, seL4_Word proc_vaddr, page_attrs attrs, page_table_cb cb, void *cb_data) { int err; seL4_Word pd_idx; dprintf(6, "page_walk: seeking %p\n", proc_vaddr); // malloc a structure to store all intermediate data page_walk_data *data = malloc(sizeof(struct page_walk_data)); if (data == NULL) { dprintf(1, "sos_page_alloc: Could not allocate callback data (OOM)\n"); return SOS_PAGE_TABLE_OOM; } // Stash the attrs and callbacks for later data->attrs = attrs; data->cb = cb; data->cb_data = cb_data; data->pcb = pcb; // Sanity checks - if these fail, process has been corrupted // These are ok - no need to check for abort since synchronous call conditional_panic(((void*) pcb->sos_pd == NULL), "No page directory"); conditional_panic((pcb->cspace == NULL), "Process cspace does not exist"); // Grab PD and PT indices from the given vaddr pd_idx = PAGE_TABLE(proc_vaddr); data->pt_idx = PAGE_TABLE_ENTRY(proc_vaddr); // Index into page directory, which *must* exist (else process is corrupt) // pt stores the address of the pointer to the PT, i.e. (**) data->pt = (sos_page_table *) (pcb->sos_pd + pd_idx); dprintf(6, "page_walk: setting up alloc or finaliser\n"); if ((*(data->pt)) == NULL) { // PT we want doesn't exist, so we alloc it dprintf(6, "page_walk: time for frame_alloc\n"); err = frame_alloc(&_page_table_frame_alloc_cb, (void*) data); // frame_alloc is asynchronous - it will finalise for us return err; } else { // Return to syscall loop, then finalise dprintf(6, "page_walk: ready to finalise\n"); err = sos_task_add_ready(&_sos_page_alloc_finalise, (void *) data, SOS_TASK_PRIORITY_HIGH); if (err) { dprintf(1, "sos_page_alloc: Could not finalise (%d)\n", err); // XXX Could tear down the process here free(data); } return SOS_PAGE_TABLE_SUCCESS; } }
/* Frame is being evicted. Synchronously update PTE with swap_num */ int sos_page_swapout(sos_pcb *pcb, seL4_Word proc_vaddr, seL4_Word swap_num) { int err; page_table_entry *pte; if (pcb->abort) { sos_swap_free(swap_num); return SOS_PAGE_TABLE_ABORT; } dprintf(5, "sos_page_swapout: pcb %p\tproc_vaddr %p\tswap_num %p\n", pcb, proc_vaddr, swap_num); // Walk the page table err = page_walk_nofault(pcb, proc_vaddr, &pte); if (err != SOS_PAGE_TABLE_SUCCESS) { // Attempt to swap out a page that's never been faulted or mapped! conditional_panic(err, "page_swapout: page walk failed unexpectedly"); return SOS_PAGE_TABLE_INVAL; } // Update PTE dprintf(6, "sos_page_swapout: updating attributes / swap number\n"); pte->attrs.swapped = 1; pte->framenumber = swap_num; dprintf(6, "sos_page_swapout: done\n"); return SOS_PAGE_TABLE_SUCCESS; }
int main(void) { int result; dprintf(0, "\nSOS Starting...\n"); _sos_init(&_sos_ipc_ep_cap, &_sos_interrupt_ep_cap); /* Initialise the network hardware */ network_init(badge_irq_ep(_sos_interrupt_ep_cap, IRQ_BADGE_NETWORK)); /* Initialize timer driver */ result = start_timer(badge_irq_ep(_sos_interrupt_ep_cap, IRQ_BADGE_TIMER)); conditional_panic(result != CLOCK_R_OK, "Failed to initialize timer\n"); /* Init file system */ _filesystem_init(); //frametable_test(TEST_1 | TEST_2); /* Start the user application */ //start_first_process(TTY_NAME, _sos_ipc_ep_cap); starting_first_process = true; proc_list_init(); proc_create(TTY_NAME, strlen(TTY_NAME), _sos_ipc_ep_cap, first_process_created, NULL); dprintf(0, "\nSOS entering syscall loop\n"); syscall_loop(_sos_ipc_ep_cap); return 0; }
/* Initialise the fhandle_t for the swap file */ void _swap_file_init(task_cb cb, void *cookie) { enum rpc_stat err; // Put args on the heap for later swap_file_init_data *data = malloc(sizeof(struct swap_file_init_data)); conditional_panic(!data, "Kernel OOM - cannot initialise swap file"); data->cb = cb; data->cookie = cookie; // Build swap metadata table assert(SWAP_META_START > DMA_VEND); assert(SOS_SWAP_MAX * sizeof(struct swapped_frames) <= SWAP_META_SIZE); err = _range_alloc_retype_and_map(SWAP_META_START, SWAP_META_SIZE); conditional_panic(err, "Failed to allocate swap metadata table"); err = nfs_lookup(&mnt_point, SWAP_FILE_NAME, &_swap_file_ready, (uintptr_t) data); if (err) { dprintf(1, "swap_file_init: failed to create file. NFS rpc_stat = %d\n", err); assert(!"swap_file_init: failed to create"); } return; }
/* Frame retrieved from swapfile. Synchronously update PTE with frame_num */ int sos_page_swapin(sos_pcb *pcb, seL4_Word proc_vaddr, seL4_Word frame_num) { int err; page_table_entry *pte; if (pcb->abort) { frame_free(frame_translate_number(frame_num)); return SOS_PAGE_TABLE_ABORT; } // Walk the page table err = page_walk_nofault(pcb, proc_vaddr, &pte); if (err != SOS_PAGE_TABLE_SUCCESS) { // Fundamental assumption has been broken. Somehow, our page table has // been damaged, or this request is erroneous. conditional_panic(err, "page_swapin: page walk failed unexpectedly"); return SOS_PAGE_TABLE_INVAL; } // Update PTE pte->attrs.swapped = 0; pte->framenumber = frame_num; return SOS_PAGE_TABLE_SUCCESS; }
int elf_load(seL4_RISCV_PageDirectory dest_as, char *elf_file) { int num_headers; int err; int i; /* Ensure that the ELF file looks sane. */ if (elf_checkFile(elf_file)){ return seL4_InvalidArgument; } num_headers = elf_getNumProgramHeaders(elf_file); for (i = 0; i < num_headers; i++) { char *source_addr; unsigned long flags, file_size, segment_size, vaddr; /* Skip non-loadable segments (such as debugging data). */ if (elf_getProgramHeaderType(elf_file, i) != PT_LOAD) continue; /* Fetch information about this segment. */ source_addr = elf_file + elf_getProgramHeaderOffset(elf_file, i); file_size = elf_getProgramHeaderFileSize(elf_file, i); segment_size = elf_getProgramHeaderMemorySize(elf_file, i); vaddr = elf_getProgramHeaderVaddr(elf_file, i); flags = elf_getProgramHeaderFlags(elf_file, i); /* Copy it across into the vspace. */ dprintf(1, " * Loading segment %08x-->%08x\n", (int)vaddr, (int)(vaddr + segment_size)); err = load_segment_into_vspace(dest_as, source_addr, segment_size, file_size, vaddr, get_sel4_rights_from_elf(flags) & seL4_AllRights); conditional_panic(err != 0, "Elf loading failed!\n"); } return 0; }
static void _sos_init(seL4_CPtr* ipc_ep, seL4_CPtr* async_ep){ seL4_Word dma_addr; seL4_Word low, high; int err; /* Retrieve boot info from seL4 */ _boot_info = seL4_GetBootInfo(); conditional_panic(!_boot_info, "Failed to retrieve boot info\n"); if(verbose > 0){ print_bootinfo(_boot_info); } /* Initialise the untyped sub system and reserve memory for DMA */ err = ut_table_init(_boot_info); conditional_panic(err, "Failed to initialise Untyped Table\n"); /* DMA uses a large amount of memory that will never be freed */ dma_addr = ut_steal_mem(DMA_SIZE_BITS); conditional_panic(dma_addr == 0, "Failed to reserve DMA memory\n"); /* find available memory */ ut_find_memory(&low, &high); /* Initialise the untyped memory allocator */ ut_allocator_init(low, high); /* Initialise the cspace manager */ err = cspace_root_task_bootstrap(ut_alloc, ut_free, ut_translate, malloc, free); conditional_panic(err, "Failed to initialise the c space\n"); /* Initialise DMA memory */ err = dma_init(dma_addr, DMA_SIZE_BITS); conditional_panic(err, "Failed to intiialise DMA memory\n"); /* Initialise IPC */ _sos_ipc_init(ipc_ep, async_ep); /* Initialise frame table */ err = frame_init(); conditional_panic(err, "Failed to initialise frame table\n"); }
static void _enable_ipc(int err, seL4_Word sos_vaddr, void *cookie) { process_create_data *proc = (process_create_data *) cookie; if (err) { dprintf(6, "process_create_enable_ipc: could not pin IPC buf (%d)\n", err); _fail(err, proc); return; } // Record the faulted frame address proc->pcb->ipc_vaddr = sos_vaddr; // Store the process capability for the IPC buffer into our PCB dprintf(6, "\t\tCopying process cap...\n"); err = frame_process_cap(proc->pcb->ipc_vaddr, proc->pcb, &(proc->pcb->ipc_cap)); // Broken invariant if that failed conditional_panic(err, "Failed to obtain IPC process cap"); // Copy the fault endpoint to the user app to enable IPC dprintf(6, "\t\tMinting cap...\n"); proc->pcb->ep_cap = cspace_mint_cap(proc->pcb->cspace, cur_cspace, _sos_ipc_ep_cap, seL4_AllRights, seL4_CapData_Badge_new(proc->pcb->pid)); // Make sure fault endpoint is in the first cspace slot if (!(proc->pcb->ep_cap == 1)) { _fail(1, proc); return; } // remainder of process creation dprintf(5, "\tCreating stack frame...\n"); err = _create_stack_frame(proc->pcb); if (err) { _fail(err, proc); return; } dprintf(5, "\tCreating heap...\n"); err = _create_heap(proc->pcb); if (err) { _fail(err, proc); return; } dprintf(5, "\tCreating seL4 TCB...\n"); err = _create_tcb(proc->pcb, SOS_PROCESS_PRIORITY); if (err) { _fail(err, proc); return; } dprintf(5, "\tLoading ELF...\n"); err = _load_elf(proc->pcb, proc->pcb->app_name, proc); if (err) { _fail(err, proc); return; } dprintf(5, "\tCreating children list...\n"); proc->pcb->children = list_init(); if (proc->pcb->children == NULL) { dprintf(5, "FAILED to create list head\n"); _fail(SOS_PROCESS_OOM, proc); return; } }
static inline seL4_CPtr badge_irq_ep(seL4_CPtr ep, seL4_Word badge) { seL4_CPtr badged_cap = cspace_mint_cap(cur_cspace, cur_cspace, ep, seL4_AllRights, seL4_CapData_Badge_new(badge | IRQ_EP_BADGE)); conditional_panic(!badged_cap, "Failed to allocate badged cap"); return badged_cap; }