Esempio n. 1
0
/*! \brief Reply from another dataserver to provide the process server with content, in reply to a
           notification the process server has sent it which asked for content.
*/
refos_err_t
data_provide_data_from_parambuffer_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd ,
                                           uint32_t rpc_offset , uint32_t rpc_contentSize)
{
    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;
    }

    /* 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;
    }

    char *initContentBuffer = dispatcher_read_param(pcb, rpc_contentSize);
    if (!initContentBuffer) {
        ROS_WARNING("data_provide_data_from_parambuffer_handler: failed to read from paramBuffer.");
        return ENOPARAMBUFFER;
    }

    /* Initialise the page of the ram dataspace with these contents. */
    int error = ram_dspace_write(initContentBuffer, rpc_contentSize, dspace, rpc_offset);
    if (error != ESUCCESS) {
        return error;
    }

    /* Set the bit that says this page has been provided, and notify all waiters blocking on it. */
    rpc_offset = REFOS_PAGE_ALIGN(rpc_offset);
    int npages = (rpc_contentSize / REFOS_PAGE_SIZE) + (rpc_contentSize % REFOS_PAGE_SIZE ? 1 : 0);
    for (vaddr_t i = 0; i < npages; i++) {
        vaddr_t offset = rpc_offset + (i * REFOS_PAGE_SIZE);
        ram_dspace_set_content_init_provided(dspace, offset);
        ram_dspace_content_init_reply_waiters(dspace, offset);
    }

    return ESUCCESS;
}
Esempio n. 2
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;
}