Ejemplo n.º 1
0
seL4_CPtr
proc_get_mem_window_dspace_handler(void *rpc_userptr , seL4_CPtr rpc_window ,
                                   refos_err_t* rpc_errno)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000001, 1)) {
        SET_ERRNO_PTR(rpc_errno, EINVALIDWINDOW);
        return 0;
    }

    if (!dispatcher_badge_window(rpc_window)) {
        SET_ERRNO_PTR(rpc_errno, EINVALIDWINDOW);
        return 0;
    }
    
    /* Retrieve the window from global window list. */
    struct w_window *window = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE);
    if (!window) {
        ROS_ERROR("Failed to find associated window in global list. Procserv book-keeping bug.");
        SET_ERRNO_PTR(rpc_errno, EINVALIDWINDOW);
        return 0;
    }

    if (window->mode != W_MODE_ANONYMOUS) {
        SET_ERRNO_PTR(rpc_errno, ESUCCESS);
        return 0;
    }
    assert(window->ramDataspace && window->ramDataspace->magic == RAM_DATASPACE_MAGIC);

    SET_ERRNO_PTR(rpc_errno, ESUCCESS);
    return window->ramDataspace->capability.capPtr;
}
Ejemplo n.º 2
0
/*! @brief Handles device server device map syscalls. */
refos_err_t
proc_device_map_handler(void *rpc_userptr , seL4_CPtr rpc_window , uint32_t rpc_windowOffset ,
        uint32_t rpc_paddr , uint32_t rpc_size , int rpc_cached)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000001, 1)) {
        return EINVALIDPARAM;
    }

    if ((pcb->systemCapabilitiesMask & PROCESS_PERMISSION_DEVICE_MAP) == 0) {
        dvprintf("Process needs device map permissions to perform this.\n");
        return EACCESSDENIED;
    }

    /* Retrieve and verify window. */
    struct w_window *window = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE);
    if (!window) {
        ROS_ERROR("window does not exist!\n");
        return EINVALIDWINDOW;
    }

    /* Get the client PCB that owns the given window. */
    struct proc_pcb* clientPCB = pid_get_pcb(&procServ.PIDList, window->clientOwnerPID);
    if (!clientPCB) {
        ROS_ERROR("invalid window owner!\n");
        return EINVALID;
    }
    assert(clientPCB->magic == REFOS_PCB_MAGIC);

    return vs_map_device(&clientPCB->vspace, window, rpc_windowOffset, rpc_paddr, rpc_size,
                         rpc_cached ? true : false);
}
Ejemplo n.º 3
0
refos_err_t
proc_unregister_as_pager_handler(void *rpc_userptr , seL4_CPtr rpc_window)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000001, 1)) {
        return EINVALIDPARAM;
    }

    /* Retrieve and verify the window cap. */
    if (!dispatcher_badge_window(rpc_window)) {
        ROS_WARNING("Invalid window badge.");
        return EINVALIDPARAM;
    }
    struct w_window *win = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE);
    if (!win) {
        ROS_ERROR("invalid window ID.");
        return EINVALIDPARAM;
    }
    assert(win->magic == W_MAGIC);

    /* Unset the pager endpoint. If there was anything else mapped to this window, it will be
       unmapped. */
    cspacepath_t emptyPath;
    memset(&emptyPath, 0, sizeof(cspacepath_t));
    w_set_pager_endpoint(win, emptyPath, PID_NULL);
    return ESUCCESS;
}
Ejemplo n.º 4
0
refos_err_t
data_dataunmap_handler(void *rpc_userptr , seL4_CPtr rpc_memoryWindow)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000001, 1)) {
        return EINVALIDPARAM;
    }

    /* Retrieve and validate window badge. */
    if (!dispatcher_badge_window(rpc_memoryWindow)) { 
        return EINVALIDWINDOW;
    }
    struct w_window *window = w_get_window(&procServ.windowList, rpc_memoryWindow - W_BADGE_BASE);
    if (!window) {
        return EINVALIDWINDOW;
    }
    
    /* If window is already empty, then there's nothing to do here. */
    if (window->mode == W_MODE_EMPTY) {
        return ESUCCESS;
    }

    /* If window is mapped to something else, the un-do operation should not be data_unmap. */
    if (window->mode != W_MODE_ANONYMOUS) {
        return EINVALIDPARAM;
    }

    /* Reset the window back to empty. */
    w_set_anon_dspace(window, NULL, 0);
    return ESUCCESS;
}
Ejemplo n.º 5
0
int
proc_get_window_flag_handler(void *rpc_userptr , seL4_CPtr window)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    struct w_window *w = w_get_window(&procServ.windowList, window - W_BADGE_BASE);

    if (!w) {
        ROS_ERROR("Failed to find associated window in global list. Procserv book-keeping bug.");
        return 0;
    }
    
    return w->flags;
}
Ejemplo n.º 6
0
/*! @brief Handles server pager setup syscalls.

    A dataserver calls the process server with this call in order to set up to be the pager of
    one of its client processes for a particular window. The client process is identified by the
    passing of its liveliness cap. All faults for the client's process which happen at that window
    will then be delegated to the dataserver to be handled.
*/
refos_err_t
proc_register_as_pager_handler(void *rpc_userptr , seL4_CPtr rpc_window ,
                               seL4_CPtr rpc_faultNotifyEP , seL4_Word* rpc_winID) 
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000001, 2)) {
        return EINVALIDPARAM;
    }

    /* Retrieve and verify the window cap. */
    if (!dispatcher_badge_window(rpc_window)) {
        ROS_WARNING("Invalid window badge.");
        return EINVALIDPARAM;
    }
    struct w_window *win = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE);
    if (!win) {
        ROS_ERROR("invalid window ID.");
        return EINVALIDPARAM;
    }
    assert(win->magic == W_MAGIC);

    /* Copy out the fault endpoint. */
    seL4_CPtr faultNotifyEP = dispatcher_copyout_cptr(rpc_faultNotifyEP);
    if (!faultNotifyEP) {
        dvprintf("could not copy out faultNotifyEP.");
        return EINVALIDPARAM; 
    }

    /* Set the pager endpoint. If there was anything else mapped to this window, it will be
       unmapped. */
    cspacepath_t faultNotifyEPPath;
    vka_cspace_make_path(&procServ.vka, faultNotifyEP, &faultNotifyEPPath);
    w_set_pager_endpoint(win, faultNotifyEPPath, pcb->pid);

    if (rpc_winID) {
        (*rpc_winID) = win->wID;
    }
    return ESUCCESS;
}
Ejemplo n.º 7
0
/*! \brief Maps the given dataspace to the given memory window. */
refos_err_t
data_datamap_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , seL4_CPtr rpc_memoryWindow,
                     uint32_t rpc_offset)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000003, 2)) {
        return EINVALIDPARAM;
    }

    /* Retrieve and validate window badge. */
    if (!dispatcher_badge_window(rpc_memoryWindow)) { 
        return EINVALIDWINDOW;
    }
    struct w_window *window = w_get_window(&procServ.windowList, rpc_memoryWindow - W_BADGE_BASE);
    if (!window) {
        return EINVALIDWINDOW;
    }

    /* Verify and find the RAM dataspace. */
    if (!dispatcher_badge_dspace(rpc_dspace_fd)) {
        ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n");
        return EINVALIDPARAM;
    }
    struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd);
    if (!dspace) {
        ROS_ERROR("EINVALIDPARAM: dataspace not found.\n");
        return EINVALIDPARAM;
    }

    /* Check that the offset is sane. */
    if (rpc_offset > (dspace->npages * REFOS_PAGE_SIZE)) {
        return EINVALIDPARAM;
    }

    /* Associate the dataspace with the window. This will release whatever the window was associated
       with beforehand. */
    w_set_anon_dspace(window, dspace, rpc_offset);
    return ESUCCESS;
}
Ejemplo n.º 8
0
/*! @brief Handles memory window creation syscalls.

    The window must not be overlapping with an existing window in the client's VSpace, or
    EINVALIDPARAM will be the returned.
    
    When mapping a dataspace to a non-page aligned window, the dataspace will actually be mapped to
    the page-aligned address of the window base due to technical restrictions. Thus, the first B -
    PAGE_ALIGN(B) bytes of the mapped dataspace is unaccessible. This can have unintended effects
    when two processes map the same dataspace for sharing purposes. In other words, when sharing
    dataspaces, it's easiest for the window bases for BOTH processes to be page-aligned.
 */
seL4_CPtr
proc_create_mem_window_internal_handler(void *rpc_userptr , uint32_t rpc_vaddr , uint32_t rpc_size ,
                                        uint32_t rpc_permissions, uint32_t flags,
                                        refos_err_t* rpc_errno)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    /* Check that this window does not override protected kernel memory. */
    if (rpc_vaddr >= PROCESS_KERNEL_RESERVED || PROCESS_KERNEL_RESERVED < (rpc_size + rpc_vaddr)) {
        dvprintf("memory window out of bounds, overlaps kernel reserved.\n");
        SET_ERRNO_PTR(rpc_errno, EINVALIDPARAM);
        return 0;
    }

    /* Create the window. */
    int windowID = W_INVALID_WINID;
    bool cached = (flags & W_FLAGS_UNCACHED) ? false : true;
    int error = vs_create_window(&pcb->vspace, rpc_vaddr, rpc_size, rpc_permissions, cached,
            &windowID);
    if (error != ESUCCESS || windowID == W_INVALID_WINID) {
        dvprintf("Could not create window.\n");
        SET_ERRNO_PTR(rpc_errno, error);
        return 0;
    }

    /* Find the window and return the window capability. */
    struct w_window* window = w_get_window(&procServ.windowList, windowID);
    if (!window) {
        assert(!"Successfully allocated window failed to be found. Process server bug.");
        /* Cannot recover from this situation cleanly. Shouldn't ever happen. */
        SET_ERRNO_PTR(rpc_errno, EINVALID);
        return 0;
    }

    assert(window->magic == W_MAGIC);
    assert(window->capability.capPtr);
    SET_ERRNO_PTR(rpc_errno, ESUCCESS);
    return window->capability.capPtr;
}
Ejemplo n.º 9
0
seL4_CPtr
proc_get_mem_window_handler(void *rpc_userptr , uint32_t rpc_vaddr)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    /* Find the window at the vaddr. */
    struct w_associated_window *aw = w_associate_find(&pcb->vspace.windows, rpc_vaddr);
    if (!aw) {
        return 0;
    }

    /* Retrieve the window from global window list. */
    struct w_window *window = w_get_window(&procServ.windowList, aw->winID);
    if (!window) {
        ROS_ERROR("Failed to find associated window in global list. Procserv book-keeping bug.");
        return 0;
    }

    assert(window->capability.capPtr);
    return window->capability.capPtr;
}
Ejemplo n.º 10
0
/*! @brief Handles server window map syscalls.

    A server calls this on the process server in response to a prior fault delegation notification
    made by the process server, in order to map the given frame in the dataserver's VSpace into
    the faulting address frame, resolving the fault.
 */
refos_err_t
proc_window_map_handler(void *rpc_userptr , seL4_CPtr rpc_window , uint32_t rpc_windowOffset ,
                        uint32_t rpc_srcAddr)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    if (!check_dispatch_caps(m, 0x00000001, 1)) {
        return EINVALIDPARAM;
    }

    /* Retrieve and verify the window cap. */
    if (!dispatcher_badge_window(rpc_window)) {
        return EINVALIDPARAM;
    }
    struct w_window *window = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE);
    if (!window) {
        ROS_ERROR("window does not exist!\n");
        return EINVALIDWINDOW;
    }
    
    /* Map the frame from src vspace to dest vspace. */
    struct proc_pcb *clientPCB = NULL;
    int error = vs_map_across_vspace(&pcb->vspace, rpc_srcAddr, window, rpc_windowOffset,
                                    &clientPCB);
    if (error) {
        return error;
    }
    assert(clientPCB != NULL && clientPCB->magic == REFOS_PCB_MAGIC);

    /* Resume the blocked faulting thread if there is one. */
    assert(procServ.unblockClientFaultPID == PID_NULL);
    procServ.unblockClientFaultPID = clientPCB->pid;
    return ESUCCESS;
}
Ejemplo n.º 11
0
/*! @brief Handles client VM fault messages sent by the kernel.

    Handles the VM fault message by looking up the details of the window that it faulted in, and
    decides whether this fault should be delegated to an external dataspace server for paging
    or content initalisation, or be handled internally by the process server's own dataspace
    implementation for RAM, or is an invalid memory access.
    
    In the case of an invalid memory access, or if the process server runs out of RAM, then
    the fault is unable to be handled and the faulting process is blocked indefinitely.

    @param m The recieved IPC fault message from the kernel.
    @param f The VM fault message info struct.
*/
static void
handle_vm_fault(struct procserv_msg *m, struct procserv_vmfault_msg *f)
{
    assert(f && f->pcb);
    dvprintf("# Process server recieved PID %d VM fault\n", f->pcb->pid);
    dvprintf("# %s %s fault at 0x%x, Instruction Pointer 0x%x, Fault Status Register 0x%x\n",
            f->instruction ? "Instruction" : "Data", f->read ? "read" : "write",
            f->faultAddr, f->pc, f->fsr);

    /* Thread should never be fault blocked (or else how did this VM fault even happen?). */
    if (f->pcb->faultReply.capPtr != 0) {
        ROS_ERROR("(how did this VM fault even happen? Check book-keeping.\n");
        output_segmentation_fault("Process should already be fault-blocked.", f);
        return;
    }

    /* Check faulting vaddr in segment windows. */
    struct w_associated_window *aw = w_associate_find(&f->pcb->vspace.windows, f->faultAddr);
    if (!aw) {
        output_segmentation_fault("invalid memory window segment", f);
        return;
    }

    /* Retrieve the associated window. */
    struct w_window *window = w_get_window(&procServ.windowList, aw->winID);
    if (!window) {
        output_segmentation_fault("invalid memory window - procserv book-keeping error.", f);
        assert(!"Process server could not find window - book-keeping error.");
        return;
    }

    /* Check window permissions. */
    if (f->read && !(window->permissions | W_PERMISSION_READ)) {
        output_segmentation_fault("no read access permission to window.", f);
        return;
    }
    if (!f->read && !(window->permissions | W_PERMISSION_WRITE)) {
        output_segmentation_fault("no write access permission to window.", f);
        return;
    }

    /* Check that there isn't a page entry already mapped. */
    cspacepath_t pageEntry = vs_get_frame(&f->pcb->vspace, f->faultAddr);
    if (pageEntry.capPtr != 0) {
        output_segmentation_fault("entry already occupied; book-keeping error.", f);
        return;
    }

    /* Handle the dispatch request depending on window mode. */
    int error = EINVALID;
    switch (window->mode) {
        case W_MODE_EMPTY:
            output_segmentation_fault("fault in empty window.", f);
            break;
        case W_MODE_ANONYMOUS:
            error = handle_vm_fault_dspace(m, f, aw, window);
            break;
        case W_MODE_PAGER:
            error = handle_vm_fault_pager(m, f, aw, window);
            break;
        default:
            assert(!"Invalid window mode. Process server bug.");
            break;
    }

    /* Reply to the faulting process to unblock it. */
    if (error == ESUCCESS) {
        seL4_Reply(_dispatcherEmptyReply);
    }
}