Example #1
0
/*! @brief Handles client un-watching syscalls. */
refos_err_t
proc_unwatch_client_handler(void *rpc_userptr , seL4_CPtr rpc_liveness) 
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb->magic == REFOS_PCB_MAGIC);

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

    /* Retrieve the corresponding client's ASID unwrapped from its liveness cap. */
    if (!dispatcher_badge_liveness(rpc_liveness)) {
        return EINVALIDPARAM;
    }
    
    /* Verify the corresponding client. */
    struct proc_pcb *client = pid_get_pcb(&procServ.PIDList,
                                          rpc_liveness - PID_LIVENESS_BADGE_BASE);
    if (!client) {
        return EINVALIDPARAM; 
    }
    assert(client->magic == REFOS_PCB_MAGIC);

    /* Remove the given client PID from the watch list. */
    client_unwatch(&pcb->clientWatchList, client->pid);
    return ESUCCESS;
}
Example #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);
}
Example #3
0
/*! \brief Handles faults on windows set to external pager.

    This functions handles the VM faults which results in a window that has been set up to be in
    external paged mode. we simply delegate to the external pager and they'll call data_datamap
    back on us and take are of the rest.
    
    @param m The recieved IPC fault message from the kernel.
    @param f The VM fault message info struct.
    @param aw Found associated window of the faulting address & client.
    @param window The window structure of the faulting address & client.
    @return ESUCCESS on success, refos_err_t otherwise.
*/
static int
handle_vm_fault_pager(struct procserv_msg *m, struct procserv_vmfault_msg *f,
        struct w_associated_window *aw, struct w_window *window)
{
    assert(f && f->pcb);
    assert(aw && window && window->mode == W_MODE_PAGER);

    /* Set up and send the fault notification. */
    struct proc_notification vmFaultNotification;
    vmFaultNotification.magic = PROCSERV_NOTIFICATION_MAGIC;
    vmFaultNotification.label = PROCSERV_NOTIFY_FAULT_DELEGATION;
    vmFaultNotification.arg[0] = window->wID;
    vmFaultNotification.arg[1] = window->size;
    vmFaultNotification.arg[2] = f->faultAddr;
    vmFaultNotification.arg[3] = aw->offset;
    vmFaultNotification.arg[4] = f->instruction;
    vmFaultNotification.arg[5] = window->permissions;
    vmFaultNotification.arg[6] = f->pc;

    /* Find the pager's PCB. */
    assert(window->pagerPID != PID_NULL);
    struct proc_pcb* pagerPCB = pid_get_pcb(&procServ.PIDList, window->pagerPID);
    if (!pagerPCB) {
        output_segmentation_fault("Invalid pager PID.", f);
        return EINVALID;
    }

    /* Send the delegation notification. */    
    fault_delegate_notification(f, pagerPCB, window->pager, vmFaultNotification, true);

    /* Return an error here to avoid resuming the client. */
    return EDELEGATED;
}
Example #4
0
void
mem_syscall_postaction()
{
    if (procServ.unblockClientFaultPID != PID_NULL) {
        struct proc_pcb *clientPCB = pid_get_pcb(&procServ.PIDList, procServ.unblockClientFaultPID);
        if (!clientPCB) {
            ROS_WARNING("mem_syscall_postaction error: No such PID!");
            procServ.unblockClientFaultPID = PID_NULL;
            return;
        }

        /* Resume the blocked faulting thread if there is one. */
        proc_fault_reply(clientPCB);
        procServ.unblockClientFaultPID = PID_NULL;
    }
}
Example #5
0
/*! @brief Handles client watching syscalls.

    Most servers would need to call this in order to be notified of client death in order to be able
    to delete any internal book-keeping for the dead client.
 */
refos_err_t
proc_watch_client_handler(void *rpc_userptr , seL4_CPtr rpc_liveness , seL4_CPtr rpc_deathEP ,
                          int32_t* rpc_deathID)
{
    struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr;
    struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr;
    assert(pcb->magic == REFOS_PCB_MAGIC);

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

    /* Retrieve the corresponding client's ASID unwrapped from its liveness cap. */
    if (!dispatcher_badge_liveness(rpc_liveness)) {
        return EINVALIDPARAM;
    }
    
    /* Verify the corresponding client. */
    struct proc_pcb *client = pid_get_pcb(&procServ.PIDList,
                                          rpc_liveness - PID_LIVENESS_BADGE_BASE);
    if (!client) {
        return EINVALIDPARAM; 
    }
    assert(client->magic == REFOS_PCB_MAGIC);

    /* Copy out the death notification endpoint. */
    seL4_CPtr deathNotifyEP = dispatcher_copyout_cptr(rpc_deathEP);
    if (!deathNotifyEP) {
        ROS_ERROR("could not copy out deathNotifyEP.");
        return ENOMEM; 
    }

    /* Add the new client to the watch list of the calling process. */
    int error = client_watch(&pcb->clientWatchList, client->pid, deathNotifyEP);
    if (error) {
        ROS_ERROR("failed to add to watch list. Procserv possibly out of memory.");
        dispatcher_release_copyout_cptr(deathNotifyEP);
        return error;
    }
    if (rpc_deathID) {
        (*rpc_deathID) = client->pid;
    }

    return ESUCCESS;
}
Example #6
0
refos_err_t  proc_set_domain_handler(void *rpc_userptr, int pid, int dom)
{
    printf("\nin set_domain_handler\n");
    struct proc_pcb* ppcb = pid_get_pcb(&procServ.PIDList,pid);

    printf("\nthe name of the process is %s\n", ppcb->debugProcessName);

    struct proc_tcb* ttcb = (struct proc_tcb*)cvector_get(&ppcb->threads, 0);
    seL4_CPtr ttcb_cptr = thread_tcb_obj(ttcb);

    int error = seL4_DomainSet_Set(0xb, dom, ttcb_cptr);
    if(error){
        printf("\nset domain failed!\n");
        return 1;
    }
    printf("after set domain!\n");
    return 0;
}
Example #7
0
/*! @brief Handles faults on windows mapped to anonymous memory.

    This function is responsible for handling VM faults on windows which have been mapped to the
    process server's own anonymous dataspaces, including ones that have been content-initialised.

    If the dataspace has been set to content-initialised, then we will need to delegate and save the
    reply cap to reply to it once the content has been initialised. If it has not been initialised
    we simply map the dataspace page and reply.

    @param m The recieved IPC fault message from the kernel.
    @param f The VM fault message info struct.
    @param aw Found associated window of the faulting address & client.
    @param window The window structure of the faulting address & client.
    @return ESUCCESS on success, refos_err_t otherwise.
*/
static int
handle_vm_fault_dspace(struct procserv_msg *m, struct procserv_vmfault_msg *f,
        struct w_associated_window *aw, struct w_window *window)
{
    assert(f && f->pcb);
    assert(aw && window && window->mode == W_MODE_ANONYMOUS);

    vaddr_t dspaceOffset = (f->faultAddr + window->ramDataspaceOffset) -
                           REFOS_PAGE_ALIGN(aw->offset);
    struct ram_dspace *dspace = window->ramDataspace;
    assert(dspace && dspace->magic == RAM_DATASPACE_MAGIC);

    dvprintf("# PID %d VM fault ―――――▶ anon RAM dspace %d\n", f->pcb->pid, dspace->ID);

    if (dspace->contentInitEnabled) {
        /* Data space is backed by external content. Content initialisation delegation. */
        int contentInitState =  ram_dspace_need_content_init(dspace, dspaceOffset);
        if (contentInitState < 0) {
            output_segmentation_fault("Failed to retrieve content-init state.", f);
            return EINVALID;
        }
        if (contentInitState == true) {
            /* Content has not yet been initialised so we delegate. */
            if (f->faultAddr + window->ramDataspaceOffset >= aw->offset + aw->size) {
                output_segmentation_fault("Fault address out of range!", f);
                return EINVALID;
            }

            /* Find the pager's PCB. */
            assert(dspace->contentInitPID != PID_NULL);
            struct proc_pcb* cinitPCB = pid_get_pcb(&procServ.PIDList, dspace->contentInitPID);
            if (!cinitPCB) {
                output_segmentation_fault("Invalid content initialiser PID.", f);
                return EINVALID;
            }
            if (!dspace->contentInitEP.capPtr) {
                output_segmentation_fault("Invalid content-init endpoint!", f);
                return EINVALID;
            }

            /* Save the reply endpoint. */
            int error = ram_dspace_add_content_init_waiter_save_current_caller(dspace,
                    dspaceOffset);
            if (error != ESUCCESS) {
                output_segmentation_fault("Failed to save reply cap as dspace waiter!", f);
                return EINVALID;
            }

            /* Set up and send the fault notification. */
            struct proc_notification vmFaultNotification;
            vmFaultNotification.magic = PROCSERV_NOTIFICATION_MAGIC;
            vmFaultNotification.label = PROCSERV_NOTIFY_CONTENT_INIT;
            vmFaultNotification.arg[0] = dspace->ID;
            vmFaultNotification.arg[1] = REFOS_PAGE_ALIGN(dspaceOffset);

            fault_delegate_notification(f, cinitPCB, dspace->contentInitEP, vmFaultNotification,
                                        false);

            /* Return an error here to avoid resuming the client. */
            return EDELEGATED;
        }

        /* Fallthrough to normal dspace mapping if content-init state is set to already provided. */
    }

    /* Get the page at the dataspaceOffset into the dataspace. */
    seL4_CPtr frame = ram_dspace_get_page(dspace, dspaceOffset);
    if (!frame) {
        output_segmentation_fault("Out of memory to allocate page or read off end of dspace.", f);
        return ENOMEM;
    }

    /* Map this frame into the client process's page directory. */
    int error = vs_map(&f->pcb->vspace, f->faultAddr, &frame, 1);
    if (error != ESUCCESS) {
        output_segmentation_fault("Failed to map frame into client's vspace at faultAddr.", f);
        return error;
    }

    return ESUCCESS;
}