Example #1
0
/**
 * Configure a thrd
 */
void thrd_configure(thrd_env_t *env, thrd_t *thread) {
    UNUSED int error;

    error = vka_alloc_endpoint(&env->vka, &thread->local_endpoint);
    assert(error == 0);

    thread->is_process = false;
    thread->fault_endpoint = env->endpoint;
    seL4_CapData_t data = seL4_CapData_Guard_new(0, seL4_WordBits - env->cspace_size_bits);
    error = sel4utils_configure_thread(&env->vka, &env->vspace, &env->vspace, env->endpoint,
                                       THRDS_OUR_PRIO - 1, env->cspace_root, data, &thread->thread);
    assert(error == 0);
}
Example #2
0
int test_allocator(env_t env)
{
    /* Perform a bunch of allocations and frees */
    vka_object_t endpoint;
    int error;

    for (int i = 0; i < MIN_EXPECTED_ALLOCATIONS; i++) {
        error = vka_alloc_endpoint(&env->vka, &endpoint);
        test_assert(error == 0);
        test_assert(endpoint.cptr != 0);
        vka_free_object(&env->vka, &endpoint);
    }

    return sel4test_get_result();
}
Example #3
0
void
create_helper_process(env_t env, helper_thread_t *thread)
{
    UNUSED int error;

    error = vka_alloc_endpoint(&env->vka, &thread->local_endpoint);
    assert(error == 0);

    thread->is_process = true;

    sel4utils_process_config_t config = {
        .is_elf = false,
        .create_cspace = true,
        .one_level_cspace_size_bits = env->cspace_size_bits,
        .create_vspace = true,
        .reservations = env->regions,
        .num_reservations = env->num_regions,
        .create_fault_endpoint = false,
        .fault_endpoint = { .cptr = env->endpoint },
        .priority = OUR_PRIO - 1,
#ifndef CONFIG_KERNEL_STABLE
        .asid_pool = env->asid_pool,
#endif
    };

    error = sel4utils_configure_process_custom(&thread->process, &env->vka, &env->vspace,
                                               config);
    assert(error == 0);

    /* copy the elf reservations we need into the current process */
    memcpy(thread->regions, env->regions, sizeof(sel4utils_elf_region_t) * env->num_regions);
    thread->num_regions = env->num_regions;

    /* clone data/code into vspace */
    for (int i = 0; i < env->num_regions; i++) {
        error = sel4utils_bootstrap_clone_into_vspace(&env->vspace, &thread->process.vspace, thread->regions[i].reservation);
        assert(error == 0);
    }

    thread->thread = thread->process.thread;
    assert(error == 0);
}
Example #4
0
File: test.c Project: Zolok/refos
static int
test_kalloc(void)
{
    test_start("kalloc");

    /* Test that malloc works and the process server can allocate from static heap properly. */
    for (int repeats = 0; repeats < 100; repeats++) {
        int *a = kmalloc(sizeof(int) * 10240);
        assert(a);
        for (int i = 0; i < 10240; i++) a[i] = i;
        for (int i = 0; i < 10240; i++) test_assert(a[i] == i);
        kfree(a);
    }

    /* Test that kernel obj allocation works and that the VKA allocator has been
       bootstrapped properly. */
    vka_object_t obj[100];
    int error = -1;
    for (int repeats = 0; repeats < 100; repeats++) {
        for (int i = 0; i < 100; i++) {
            error = vka_alloc_endpoint(&procServ.vka, &obj[i]);
            test_assert(!error);
            test_assert(obj[i].cptr != 0);
        }
        for (int i = 0; i < 100; i++) {
            vka_free_object(&procServ.vka, &obj[i]);
        }
        for (int i = 0; i < 100; i++) {
            error = vka_alloc_frame(&procServ.vka, seL4_PageBits, &obj[i]);
            test_assert(!error);
            test_assert(obj[i].cptr != 0);
        }
        for (int i = 0; i < 100; i++) {
            vka_free_object(&procServ.vka, &obj[i]);
        }
    }

    return test_success();
}
Example #5
0
/*! @brief Creates a kernel endpoint object for the given process.

    Creates a kernel endpoint object for the given process. Also does the book-keeping underneath so
    that the created objects can be destroyed when the process exits.

    @param pcb Handle to the process to create the object for. (no ownership)
    @param type The kernel endpoint object type to create for the process; sync or async.
    @return Handle to the created object if successful (no ownership), NULL if there was an
            error. (eg. ran out of heap or untyped memory).
 */
static seL4_CPtr
proc_syscall_allocate_endpoint(struct proc_pcb *pcb, kobject_t type)
{
    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);

    /* Allocate the kernel object. */
    vka_object_t endpoint;
    int error = -1;
    if (type == KOBJECT_ENDPOINT_SYNC) {
        error = vka_alloc_endpoint(&procServ.vka, &endpoint);
    } else if (type == KOBJECT_ENDPOINT_ASYNC) {
        error = vka_alloc_async_endpoint(&procServ.vka, &endpoint);
    } else {
        assert(!"Invalid endpoint type.");
    }
    if (error || endpoint.cptr == 0) {
        ROS_ERROR("failed to allocate endpoint for process. Procserv out of memory.\n");
        return 0;
    }

    /* Track this allocation, so it may be freed along with the process vspace. */
    vs_track_obj(&pcb->vspace, endpoint);
    return endpoint.cptr;
}
Example #6
0
int main(void)
{
    UNUSED int error;

    /* Set up logging and give us a name: useful for debugging if the thread faults */
    zf_log_set_tag_prefix("hello-3:");
    name_thread(seL4_CapInitThreadTCB, "hello-3");

    /* get boot info */
    info = seL4_GetBootInfo();

    /* init simple */
    simple_default_init_bootinfo(&simple, info);

    /* print out bootinfo and other info about simple */
    simple_print(&simple);

    /* create an allocator */
    allocman = bootstrap_use_current_simple(&simple, ALLOCATOR_STATIC_POOL_SIZE,        allocator_mem_pool);
    ZF_LOGF_IF(allocman == NULL, "Failed to initialize alloc manager.\n"
        "\tMemory pool sufficiently sized?\n"
        "\tMemory pool pointer valid?\n");

    /* create a vka (interface for interacting with the underlying allocator) */
    allocman_make_vka(&vka, allocman);

    /* get our cspace root cnode */
    seL4_CPtr cspace_cap;
    cspace_cap = simple_get_cnode(&simple);

    /* get our vspace root page directory */
    seL4_CPtr pd_cap;
    pd_cap = simple_get_pd(&simple);

    /* create a new TCB */
    vka_object_t tcb_object = {0};
    error = vka_alloc_tcb(&vka, &tcb_object);
    ZF_LOGF_IFERR(error, "Failed to allocate new TCB.\n"
        "\tVKA given sufficient bootstrap memory?");

    /*
     * create and map an ipc buffer:
     */

    /* TODO 1: get a frame cap for the ipc buffer */
    /* hint: vka_alloc_frame()
     * int vka_alloc_frame(vka_t *vka, uint32_t size_bits, vka_object_t *result)
     * @param vka Pointer to vka interface.
     * @param size_bits Frame size: 2^size_bits
     * @param result Structure for the Frame object.  This gets initialised.
     * @return 0 on success
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_1:
     */
    vka_object_t ipc_frame_object;
    error = vka_alloc_frame(&vka, IPCBUF_FRAME_SIZE_BITS, &ipc_frame_object);
    ZF_LOGF_IFERR(error, "Failed to alloc a frame for the IPC buffer.\n"
        "\tThe frame size is not the number of bytes, but an exponent.\n"
        "\tNB: This frame is not an immediately usable, virtually mapped page.\n")
    /*
     * map the frame into the vspace at ipc_buffer_vaddr.
     * To do this we first try to map it in to the root page directory.
     * If there is already a page table mapped in the appropriate slot in the
     * page diretory where we can insert this frame, then this will succeed.
     * Otherwise we first need to create a page table, and map it in to
     * the page directory, before we can map the frame in. */

    seL4_Word ipc_buffer_vaddr = IPCBUF_VADDR;

    /* TODO 2: try to map the frame the first time  */
    /* hint 1: seL4_ARCH_Page_Map()
     * The *ARCH* versions of seL4 sys calls are abstractions over the architecture provided by libsel4utils
     * this one is defined as:
     * #define seL4_ARCH_Page_Map seL4_X86_Page_Map
     * in: Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_2:
     * The signature for the underlying function is:
     * int seL4_X86_Page_Map(seL4_X86_Page service, seL4_X86_PageDirectory pd, seL4_Word vaddr, seL4_CapRights rights, seL4_X86_VMAttributes attr)
     * @param service Capability to the page to map.
     * @param pd Capability to the VSpace which will contain the mapping.
     * @param vaddr Virtual address to map the page into.
     * @param rights Rights for the mapping.
     * @param attr VM Attributes for the mapping.
     * @return 0 on success.
     *
     * Note: this function is generated during build.  It is generated from the following definition:
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_2:
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
     *
     * hint 2: for the rights, use seL4_AllRights
     * hint 3: for VM attributes use seL4_ARCH_Default_VMAttributes
     * Hint 4: It is normal for this function call to fail. That means there are
     *	no page tables with free slots -- proceed to the next step where you'll
     *	be led to allocate a new empty page table and map it into the VSpace,
     *	before trying again.
     */
    error = seL4_ARCH_Page_Map(ipc_frame_object.cptr, pd_cap, ipc_buffer_vaddr,
        seL4_AllRights, seL4_ARCH_Default_VMAttributes);

    if (error != 0) {
        /* TODO 3: create a page table */
        /* hint: vka_alloc_page_table()
		 * int vka_alloc_page_table(vka_t *vka, vka_object_t *result)
		 * @param vka Pointer to vka interface.
		 * @param result Structure for the PageTable object.  This gets initialised.
		 * @return 0 on success
		 * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_3:
         */
        vka_object_t pt_object;
        error =  vka_alloc_page_table(&vka, &pt_object);
        ZF_LOGF_IFERR(error, "Failed to allocate new page table.\n");

        /* TODO 4: map the page table */
        /* hint 1: seL4_ARCH_PageTable_Map()
		 * The *ARCH* versions of seL4 sys calls are abstractions over the architecture provided by libsel4utils
		 * this one is defined as:
		 * #define seL4_ARCH_PageTable_Map seL4_X86_PageTable_Map
         * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_4:
		 * The signature for the underlying function is:
		 * int seL4_X86_PageTable_Map(seL4_X86_PageTable service, seL4_X86_PageDirectory pd, seL4_Word vaddr, seL4_X86_VMAttributes attr)
		 * @param service Capability to the page table to map.
		 * @param pd Capability to the VSpace which will contain the mapping.
		 * @param vaddr Virtual address to map the page table into.
		 * @param rights Rights for the mapping.
		 * @param attr VM Attributes for the mapping.
		 * @return 0 on success.
		 *
		 * Note: this function is generated during build.  It is generated from the following definition:
         * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_4:
		 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
		 *
         * hint 2: for VM attributes use seL4_ARCH_Default_VMAttributes
         */
    	error = seL4_ARCH_PageTable_Map(pt_object.cptr, pd_cap,
            ipc_buffer_vaddr, seL4_ARCH_Default_VMAttributes);
        ZF_LOGF_IFERR(error, "Failed to map page table into VSpace.\n"
            "\tWe are inserting a new page table into the top-level table.\n"
            "\tPass a capability to the new page table, and not for example, the IPC buffer frame vaddr.\n")

        /* TODO 5: then map the frame in */
        /* hint 1: use seL4_ARCH_Page_Map() as above
         * hint 2: for the rights, use seL4_AllRights
         * hint 3: for VM attributes use seL4_ARCH_Default_VMAttributes
         */
        error = seL4_ARCH_Page_Map(ipc_frame_object.cptr, pd_cap,
            ipc_buffer_vaddr, seL4_AllRights, seL4_ARCH_Default_VMAttributes);
        ZF_LOGF_IFERR(error, "Failed again to map the IPC buffer frame into the VSpace.\n"
			"\t(It's not supposed to fail.)\n"
            "\tPass a capability to the IPC buffer's physical frame.\n"
            "\tRevisit the first seL4_ARCH_Page_Map call above and double-check your arguments.\n");
    }

    /* set the IPC buffer's virtual address in a field of the IPC buffer */
    seL4_IPCBuffer *ipcbuf = (seL4_IPCBuffer*)ipc_buffer_vaddr;
    ipcbuf->userData = ipc_buffer_vaddr;

    /* TODO 6: create an endpoint */
    /* hint: vka_alloc_endpoint()
     * int vka_alloc_endpoint(vka_t *vka, vka_object_t *result)
     * @param vka Pointer to vka interface.
     * @param result Structure for the Endpoint object.  This gets initialised.
     * @return 0 on success
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_6:
     */
    error = vka_alloc_endpoint(&vka, &ep_object);
    ZF_LOGF_IFERR(error, "Failed to allocate new endpoint object.\n");

    /* TODO 7: make a badged copy of it in our cspace. This copy will be used to send
     * an IPC message to the original cap */
    /* hint 1: vka_mint_object()
     * int vka_mint_object(vka_t *vka, vka_object_t *object, cspacepath_t *result, seL4_CapRights rights, seL4_CapData_t badge)
     * @param[in] vka The allocator for the cspace.
     * @param[in] object Target object for cap minting.
     * @param[out] result Allocated cspacepath.
     * @param[in] rights The rights for the minted cap.
     * @param[in] badge The badge for the minted cap.
     * @return 0 on success
     *
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_7:
     *
     * hint 2: for the rights, use seL4_AllRights
     * hint 3: for the badge use seL4_CapData_Badge_new()
     * seL4_CapData_t CONST seL4_CapData_Badge_new(seL4_Uint32 Badge)
     * @param[in] Badge The badge number to use
     * @return A CapData structure containing the desired badge info
     *
     * seL4_CapData_t is generated during build.
     * The type definition and generated field access functions are defined in a generated file:
     * build/x86/pc99/libsel4/include/sel4/types_gen.h
     * It is generated from the following definition:
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_7:
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
     *
     * hint 4: for the badge use EP_BADGE
     */
    error = vka_mint_object(&vka, &ep_object, &ep_cap_path, seL4_AllRights,
        seL4_CapData_Badge_new(EP_BADGE));
    ZF_LOGF_IFERR(error, "Failed to mint new badged copy of IPC endpoint.\n"
        "\tseL4_Mint is the backend for vka_mint_object.\n"
        "\tseL4_Mint is simply being used here to create a badged copy of the same IPC endpoint.\n"
        "\tThink of a badge in this case as an IPC context cookie.\n");

    /* initialise the new TCB */
    error = seL4_TCB_Configure(tcb_object.cptr, seL4_CapNull, seL4_PrioProps_new(seL4_MaxPrio, seL4_MaxPrio),
        cspace_cap, seL4_NilData, pd_cap, seL4_NilData,
        ipc_buffer_vaddr, ipc_frame_object.cptr);
    ZF_LOGF_IFERR(error, "Failed to configure the new TCB object.\n"
        "\tWe're running the new thread with the root thread's CSpace.\n"
        "\tWe're running the new thread in the root thread's VSpace.\n");


    /* give the new thread a name */
    name_thread(tcb_object.cptr, "hello-3: thread_2");

    /* set start up registers for the new thread */
    seL4_UserContext regs = {0};
    size_t regs_size = sizeof(seL4_UserContext) / sizeof(seL4_Word);

    /* set instruction pointer where the thread shoud start running */
    sel4utils_set_instruction_pointer(&regs, (seL4_Word)thread_2);

    /* check that stack is aligned correctly */
    const int stack_alignment_requirement = sizeof(seL4_Word) * 2;
    uintptr_t thread_2_stack_top = (uintptr_t)thread_2_stack + sizeof(thread_2_stack);

    ZF_LOGF_IF(thread_2_stack_top % (stack_alignment_requirement) != 0,
        "Stack top isn't aligned correctly to a %dB boundary.\n"
        "\tDouble check to ensure you're not trampling.",
        stack_alignment_requirement);

    /* set stack pointer for the new thread. remember the stack grows down */
    sel4utils_set_stack_pointer(&regs, thread_2_stack_top);

    /* set the fs register for IPC buffer */
    regs.fs = IPCBUF_GDT_SELECTOR;

    /* actually write the TCB registers. */
    error = seL4_TCB_WriteRegisters(tcb_object.cptr, 0, 0, regs_size, &regs);
    ZF_LOGF_IFERR(error, "Failed to write the new thread's register set.\n"
        "\tDid you write the correct number of registers? See arg4.\n");

    /* start the new thread running */
    error = seL4_TCB_Resume(tcb_object.cptr);
    ZF_LOGF_IFERR(error, "Failed to start new thread.\n");

    /* we are done, say hello */
    printf("main: hello world\n");

    /*
     * now send a message to the new thread, and wait for a reply
     */

    seL4_Word msg;
    seL4_MessageInfo_t tag;

    /* TODO 8: set the data to send. We send it in the first message register */
    /* hint 1: seL4_MessageInfo_new()
     * seL4_MessageInfo_t CONST seL4_MessageInfo_new(seL4_Uint32 label, seL4_Uint32 capsUnwrapped, seL4_Uint32 extraCaps, seL4_Uint32 length)
     * @param label The value of the label field
     * @param capsUnwrapped The value of the capsUnwrapped field
     * @param extraCaps The value of the extraCaps field
     * @param length The number of message registers to send
     * @return The seL4_MessageInfo_t containing the given values.
     *
     * seL4_MessageInfo_new() is generated during build. It can be found in:
     * build/x86/pc99/libsel4/include/sel4/types_gen.h
     * It is generated from the following definition:
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_8:
     *
     * hint 2: use 0 for the first 3 fields.
     * hint 3: send only 1 message register of data
     *
     * hint 4: seL4_SetMR()
     * void seL4_SetMR(int i, seL4_Word mr)
     * @param i The message register to write
     * @param mr The value of the message register
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_8:
     * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
     *
     * hint 5: send MSG_DATA
     */
    tag = seL4_MessageInfo_new(0, 0, 0, 1);
    seL4_SetMR(0, MSG_DATA);

    /* TODO 9: send and wait for a reply. */
    /* hint: seL4_Call()
     * seL4_MessageInfo_t seL4_Call(seL4_CPtr dest, seL4_MessageInfo_t msgInfo)
     * @param dest The capability to be invoked.
     * @param msgInfo The messageinfo structure for the IPC.  This specifies information about the message to send (such as the number of message registers to send).
     * @return A seL4_MessageInfo_t structure.  This is information about the repy message.
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_9:
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
     *
     * hint 2: seL4_MessageInfo_t is generated during build.
     * The type definition and generated field access functions are defined in a generated file:
     * build/x86/pc99/libsel4/include/sel4/types_gen.h
     * It is generated from the following definition:
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_9:
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
     */
    tag = seL4_Call(ep_cap_path.capPtr, tag);

    /* TODO 10: get the reply message */
    /* hint: seL4_GetMR()
     * seL4_Word seL4_GetMR(int i)
     * @param i The message register to retreive
     * @return The message register value
     * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_10:
     * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf
     */
    msg = seL4_GetMR(0);

    /* check that we got the expected repy */
    ZF_LOGF_IF(seL4_MessageInfo_get_length(tag) != 1,
        "Response data from thread_2 was not the length expected.\n"
        "\tHow many registers did you set with seL4_SetMR within thread_2?\n");

    ZF_LOGF_IF(msg != ~MSG_DATA,
        "Response data from thread_2's content was not what was expected.\n");

    printf("main: got a reply: %#x\n", msg);

    return 0;
}
Example #7
0
int main(void)
{
    UNUSED int error;

    /* give us a name: useful for debugging if the thread faults */
    name_thread(seL4_CapInitThreadTCB, "hello-3");

    /* get boot info */
    info = seL4_GetBootInfo();

    /* init simple */
    simple_default_init_bootinfo(&simple, info);

    /* print out bootinfo and other info about simple */
    simple_print(&simple);

    /* create an allocator */
    allocman = bootstrap_use_current_simple(&simple, ALLOCATOR_STATIC_POOL_SIZE,        allocator_mem_pool);
    assert(allocman);

    /* create a vka (interface for interacting with the underlying allocator) */
    allocman_make_vka(&vka, allocman);

    /* get our cspace root cnode */
    seL4_CPtr cspace_cap;
    cspace_cap = simple_get_cnode(&simple);

    /* get our vspace root page directory */
    seL4_CPtr pd_cap;
    pd_cap = simple_get_pd(&simple);

    /* create a new TCB */
    vka_object_t tcb_object = {0};
    error = vka_alloc_tcb(&vka, &tcb_object);
    assert(error == 0);

    /*
     * create and map an ipc buffer:
     */

    /* TODO 1: get a frame cap for the ipc buffer */
    /* hint: vka_alloc_frame()
     * int vka_alloc_frame(vka_t *vka, uint32_t size_bits, vka_object_t *result)
     * @param vka Pointer to vka interface.
     * @param size_bits Frame size: 2^size_bits
     * @param result Structure for the Frame object.  This gets initialised.
     * @return 0 on success
     * https://github.com/seL4/libsel4vka/blob/master/include/vka/object.h#L147
     */
    vka_object_t ipc_frame_object;
    error = vka_alloc_frame(&vka, IPCBUF_FRAME_SIZE_BITS, &ipc_frame_object);
    assert(error == 0);

    /*
     * map the frame into the vspace at ipc_buffer_vaddr.
     * To do this we first try to map it in to the root page directory.
     * If there is already a page table mapped in the appropriate slot in the
     * page diretory where we can insert this frame, then this will succeed.
     * Otherwise we first need to create a page table, and map it in to
     * the page directory, before we can map the frame in. */

    seL4_Word ipc_buffer_vaddr = IPCBUF_VADDR;

    /* TODO 2: try to map the frame the first time  */
    /* hint 1: seL4_ARCH_Page_Map()
     * The *ARCH* versions of seL4 sys calls are abstractions over the architecture provided by libsel4utils
     * this one is defined as:
     * #define seL4_ARCH_Page_Map seL4_IA32_Page_Map
     * in: https://github.com/seL4/libsel4utils/blob/master/include/sel4utils/mapping.h#L69
     * The signature for the underlying function is:
     * int seL4_IA32_Page_Map(seL4_IA32_Page service, seL4_IA32_PageDirectory pd, seL4_Word vaddr, seL4_CapRights rights, seL4_IA32_VMAttributes attr)
     * @param service Capability to the page to map.
     * @param pd Capability to the VSpace which will contain the mapping.
     * @param vaddr Virtual address to map the page into.
     * @param rights Rights for the mapping.
     * @param attr VM Attributes for the mapping.
     * @return 0 on success.
     *
     * Note: this function is generated during build.  It is generated from the following definition:
     * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/interfaces/sel4arch.xml#L52
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf    
     *
     * hint 2: for the rights, use seL4_AllRights 
     * hint 3: for VM attributes use seL4_ARCH_Default_VMAttributes
     */
    error = seL4_ARCH_Page_Map(ipc_frame_object.cptr, pd_cap, ipc_buffer_vaddr,
        seL4_AllRights, seL4_ARCH_Default_VMAttributes);
    if (error != 0) {
        /* TODO 3: create a page table */
        /* hint: vka_alloc_page_table()
	 * int vka_alloc_page_table(vka_t *vka, vka_object_t *result)
	 * @param vka Pointer to vka interface.
	 * @param result Structure for the PageTable object.  This gets initialised.
	 * @return 0 on success
         * https://github.com/seL4/libsel4vka/blob/master/include/vka/object.h#L178
         */
        vka_object_t pt_object;
        error =  vka_alloc_page_table(&vka, &pt_object);
        assert(error == 0);

        /* TODO 4: map the page table */
        /* hint 1: seL4_ARCH_PageTable_Map()
	 * The *ARCH* versions of seL4 sys calls are abstractions over the architecture provided by libsel4utils
	 * this one is defined as:
	 * #define seL4_ARCH_PageTable_Map seL4_IA32_PageTable_Map
	 * in: https://github.com/seL4/libsel4utils/blob/master/include/sel4utils/mapping.h#L73
	 * The signature for the underlying function is:
	 * int seL4_IA32_PageTable_Map(seL4_IA32_PageTable service, seL4_IA32_PageDirectory pd, seL4_Word vaddr, seL4_IA32_VMAttributes attr)
	 * @param service Capability to the page table to map.
	 * @param pd Capability to the VSpace which will contain the mapping.
	 * @param vaddr Virtual address to map the page table into.
	 * @param rights Rights for the mapping.
	 * @param attr VM Attributes for the mapping.
	 * @return 0 on success.
	 *
	 * Note: this function is generated during build.  It is generated from the following definition:
	 * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/interfaces/sel4arch.xml#L37
	 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf    
	 * 
         * hint 2: for VM attributes use seL4_ARCH_Default_VMAttributes
         */
    	error = seL4_ARCH_PageTable_Map(pt_object.cptr, pd_cap,
            ipc_buffer_vaddr, seL4_ARCH_Default_VMAttributes);
        assert(error == 0);

        /* TODO 5: then map the frame in */
        /* hint 1: use seL4_ARCH_Page_Map() as above
         * hint 2: for the rights, use seL4_AllRights 
         * hint 3: for VM attributes use seL4_ARCH_Default_VMAttributes
         */
        error = seL4_ARCH_Page_Map(ipc_frame_object.cptr, pd_cap,
            ipc_buffer_vaddr, seL4_AllRights, seL4_ARCH_Default_VMAttributes);
        assert(error == 0);
    }

    /* set the IPC buffer's virtual address in a field of the IPC buffer */
    seL4_IPCBuffer *ipcbuf = (seL4_IPCBuffer*)ipc_buffer_vaddr;
    ipcbuf->userData = ipc_buffer_vaddr;

    /* TODO 6: create an endpoint */
    /* hint: vka_alloc_endpoint() 
     * int vka_alloc_endpoint(vka_t *vka, vka_object_t *result)
     * @param vka Pointer to vka interface.
     * @param result Structure for the Endpoint object.  This gets initialised.
     * @return 0 on success
     * https://github.com/seL4/libsel4vka/blob/master/include/vka/object.h#L94
     */
    error = vka_alloc_endpoint(&vka, &ep_object);
    assert(error == 0);

    /* TODO 7: make a badged copy of it in our cspace. This copy will be used to send 
     * an IPC message to the original cap */
    /* hint 1: vka_mint_object()
     * int vka_mint_object(vka_t *vka, vka_object_t *object, cspacepath_t *result, seL4_CapRights rights, seL4_CapData_t badge) 
     * @param[in] vka The allocator for the cspace.
     * @param[in] object Target object for cap minting.
     * @param[out] result Allocated cspacepath.
     * @param[in] rights The rights for the minted cap.
     * @param[in] badge The badge for the minted cap. 
     * @return 0 on success
     * 
     * https://github.com/seL4/libsel4vka/blob/master/include/vka/object_capops.h#L41
     *
     * hint 2: for the rights, use seL4_AllRights
     * hint 3: for the badge use seL4_CapData_Badge_new()
     * seL4_CapData_t CONST seL4_CapData_Badge_new(seL4_Uint32 Badge)
     * @param[in] Badge The badge number to use
     * @return A CapData structure containing the desired badge info
     * 
     * seL4_CapData_t is generated during build.
     * The type definition and generated field access functions are defined in a generated file: 
     * build/x86/pc99/libsel4/include/sel4/types_gen.h
     * It is generated from the following definition:
     * https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/types.bf#L30
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf     
     * 
     * hint 4: for the badge use EP_BADGE
     */
    error = vka_mint_object(&vka, &ep_object, &ep_cap_path, seL4_AllRights,
        seL4_CapData_Badge_new(EP_BADGE));
    assert(error == 0);

    /* initialise the new TCB */
    error = seL4_TCB_Configure(tcb_object.cptr, seL4_CapNull, seL4_MaxPrio,
        cspace_cap, seL4_NilData, pd_cap, seL4_NilData,
        ipc_buffer_vaddr, ipc_frame_object.cptr);
    assert(error == 0);

    /* give the new thread a name */
    name_thread(tcb_object.cptr, "hello-3: thread_2");

    /* set start up registers for the new thread */
    seL4_UserContext regs = {0};
    size_t regs_size = sizeof(seL4_UserContext) / sizeof(seL4_Word);

    /* set instruction pointer where the thread shoud start running */
    sel4utils_set_instruction_pointer(&regs, (seL4_Word)thread_2);

    /* check that stack is aligned correctly */
    uintptr_t thread_2_stack_top = (uintptr_t)thread_2_stack + sizeof(thread_2_stack);
    assert(thread_2_stack_top % (sizeof(seL4_Word) * 2) == 0);

    /* set stack pointer for the new thread. remember the stack grows down */
    sel4utils_set_stack_pointer(&regs, thread_2_stack_top);

    /* set the gs register for thread local storage */
    regs.gs = IPCBUF_GDT_SELECTOR;

    /* actually write the TCB registers. */
    error = seL4_TCB_WriteRegisters(tcb_object.cptr, 0, 0, regs_size, &regs);
    assert(error == 0);

    /* start the new thread running */
    error = seL4_TCB_Resume(tcb_object.cptr);
    assert(error == 0);

    /* we are done, say hello */
    printf("main: hello world\n");

    /*
     * now send a message to the new thread, and wait for a reply
     */

    seL4_Word msg;
    seL4_MessageInfo_t tag;

    /* TODO 8: set the data to send. We send it in the first message register */
    /* hint 1: seL4_MessageInfo_new()
     * seL4_MessageInfo_t CONST seL4_MessageInfo_new(seL4_Uint32 label, seL4_Uint32 capsUnwrapped, seL4_Uint32 extraCaps, seL4_Uint32 length) 
     * @param label The value of the label field
     * @param capsUnwrapped The value of the capsUnwrapped field
     * @param extraCaps The value of the extraCaps field
     * @param length The number of message registers to send
     * @return The seL4_MessageInfo_t containing the given values.
     *
     * seL4_MessageInfo_new() is generated during build. It can be found in:
     * build/x86/pc99/libsel4/include/sel4/types_gen.h
     * It is generated from the following definition:
     * https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/types.bf#L35
     *
     * hint 2: use 0 for the first 3 fields.
     * hint 3: send only 1 message register of data
     *
     * hint 4: seL4_SetMR()
     * void seL4_SetMR(int i, seL4_Word mr)
     * @param i The message register to write
     * @param mr The value of the message register
     * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/sel4/arch/functions.h#L41
     * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf
     *
     * hint 5: send MSG_DATA
     */
    tag = seL4_MessageInfo_new(0, 0, 0, 1);
    seL4_SetMR(0, MSG_DATA);

    /* TODO 9: send and wait for a reply. */
    /* hint: seL4_Call() 
     * seL4_MessageInfo_t seL4_Call(seL4_CPtr dest, seL4_MessageInfo_t msgInfo)
     * @param dest The capability to be invoked.
     * @param msgInfo The messageinfo structure for the IPC.  This specifies information about the message to send (such as the number of message registers to send).
     * @return A seL4_MessageInfo_t structure.  This is information about the repy message.
     * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/sel4/arch/syscalls.h#L242
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf 
     *
     * hint 2: seL4_MessageInfo_t is generated during build.
     * The type definition and generated field access functions are defined in a generated file: 
     * build/x86/pc99/libsel4/include/sel4/types_gen.h
     * It is generated from the following definition:
     * https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/types.bf#L35
     * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf     
     */
    tag = seL4_Call(ep_cap_path.capPtr, tag);

    /* TODO 10: get the reply message */
    /* hint: seL4_GetMR()
     * seL4_Word seL4_GetMR(int i)
     * @param i The message register to retreive
     * @return The message register value
     * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/sel4/arch/functions.h#L33
     * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf
     */
    msg = seL4_GetMR(0);

    /* check that we got the expected repy */
    assert(seL4_MessageInfo_get_length(tag) == 1);
    assert(msg == ~MSG_DATA);

    printf("main: got a reply: %#x\n", msg);

    return 0;
}
Example #8
0
seL4_Error
serial_server_parent_spawn_thread(simple_t *parent_simple, vka_t *parent_vka,
                                  vspace_t *parent_vspace,
                                  uint8_t priority)
{
    const size_t shmem_max_size = SERIAL_SERVER_SHMEM_MAX_SIZE;
    seL4_Error error;
    size_t shmem_max_n_pages;
    cspacepath_t parent_cspace_cspath;
    seL4_MessageInfo_t tag;

    if (parent_simple == NULL || parent_vka == NULL || parent_vspace == NULL) {
        return seL4_InvalidArgument;
    }

    memset(get_serial_server(), 0, sizeof(serial_server_context_t));

    /* Get a CPtr to the parent's root cnode. */
    shmem_max_n_pages = BYTES_TO_4K_PAGES(shmem_max_size);
    vka_cspace_make_path(parent_vka, 0, &parent_cspace_cspath);

    get_serial_server()->server_vka = parent_vka;
    get_serial_server()->server_vspace = parent_vspace;
    get_serial_server()->server_cspace = parent_cspace_cspath.root;
    get_serial_server()->server_simple = parent_simple;

    /* Allocate the Endpoint that the server will be listening on. */
    error = vka_alloc_endpoint(parent_vka, &get_serial_server()->server_ep_obj);
    if (error != 0) {
        ZF_LOGE(SERSERVP"spawn_thread: failed to alloc endpoint, err=%d.",
                error);
        return error;
    }

    /* And also allocate a badged copy of the Server's endpoint that the Parent
     * can use to send to the Server. This is used to allow the Server to report
     * back to the Parent on whether or not the Server successfully bound to a
     * platform serial driver.
     *
     * This badged endpoint will be reused by the library as the Parent's badged
     * Endpoint cap, if the Parent itself ever chooses to connect() to the
     * Server later on.
     */

    get_serial_server()->parent_badge_value = serial_server_badge_value_alloc();
    if (get_serial_server()->parent_badge_value == SERIAL_SERVER_BADGE_VALUE_EMPTY) {
        error = seL4_NotEnoughMemory;
        goto out;
    }

    error = vka_mint_object(parent_vka, &get_serial_server()->server_ep_obj,
                            &get_serial_server()->_badged_server_ep_cspath,
                            seL4_AllRights,
                            seL4_CapData_Badge_new(get_serial_server()->parent_badge_value));
    if (error != 0) {
        ZF_LOGE(SERSERVP"spawn_thread: Failed to mint badged Endpoint cap to "
                "server.\n"
                "\tParent cannot confirm Server thread successfully spawned.");
        goto out;
    }

    /* Allocate enough Cnode slots in our CSpace to enable us to receive
     * frame caps from our clients, sufficient to cover "shmem_max_size".
     * The problem here is that we're sort of forced to assume that we get
     * these slots contiguously. If they're not, we have a problem.
     *
     * If a client tries to send us too many frames, we respond with an error,
     * and indicate our shmem_max_size in the SSMSGREG_RESPONSE
     * message register.
     */
    get_serial_server()->frame_cap_recv_cspaths = calloc(shmem_max_n_pages,
                                                   sizeof(cspacepath_t));
    if (get_serial_server()->frame_cap_recv_cspaths == NULL) {
        error = seL4_NotEnoughMemory;
        goto out;
    }

    for (size_t i = 0; i < shmem_max_n_pages; i++) {
        error = vka_cspace_alloc_path(parent_vka,
                                      &get_serial_server()->frame_cap_recv_cspaths[i]);
        if (error != 0) {
            ZF_LOGE(SERSERVP"spawn_thread: Failed to alloc enough cnode slots "
                "to receive shmem frame caps equal to %d bytes.",
                shmem_max_size);
            goto out;
        }
    }

    error = sel4utils_configure_thread(parent_vka, parent_vspace, parent_vspace,
                                       get_serial_server()->server_ep_obj.cptr, priority,
                                       parent_cspace_cspath.root, seL4_NilData,
                                       &get_serial_server()->server_thread);
    if (error != 0) {
        ZF_LOGE(SERSERVP"spawn_thread: sel4utils_configure_thread failed "
                "with %d.", error);
        goto out;
    }

    error = sel4utils_start_thread(&get_serial_server()->server_thread,
                                   &serial_server_main,
                                   NULL, NULL, 1);
    if (error != 0) {
        ZF_LOGE(SERSERVP"spawn_thread: sel4utils_start_thread failed with "
                "%d.", error);
        goto out;
    }

    /* When the Server is spawned, it will reply to tell us whether or not it
     * successfully bound itself to the platform serial device. Block here
     * and wait for that reply.
     */
    seL4_SetMR(SSMSGREG_FUNC, FUNC_SERVER_SPAWN_SYNC_REQ);
    tag = seL4_MessageInfo_new(0, 0, 0, SSMSGREG_SPAWN_SYNC_REQ_END);
    tag = seL4_Call(get_serial_server()->_badged_server_ep_cspath.capPtr, tag);

    /* Did all go well with the server? */
    if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_SERVER_SPAWN_SYNC_ACK) {
        ZF_LOGE(SERSERVP"spawn_thread: Server thread sync message after spawn "
                "was not a SYNC_ACK as expected.");
        error = seL4_InvalidArgument;
        goto out;
    }
    error = seL4_MessageInfo_get_label(tag);
    if (error != 0) {
        ZF_LOGE(SERSERVP"spawn_thread: Server thread failed to bind to the "
                "platform serial device.");
        goto out;
    }

    get_serial_server()->shmem_max_size = shmem_max_size;
    get_serial_server()->shmem_max_n_pages = shmem_max_n_pages;
    return 0;

out:
    if (get_serial_server()->frame_cap_recv_cspaths != NULL) {
        for (size_t i = 0; i < shmem_max_n_pages; i++) {
            /* Since the array was allocated with calloc(), it was zero'd out. So
             * those indexes that didn't get allocated will have NULL in them.
             * Break early on the first index that has NULL.
             */
            if (get_serial_server()->frame_cap_recv_cspaths[i].capPtr == 0) {
                break;
            }
            vka_cspace_free_path(parent_vka, get_serial_server()->frame_cap_recv_cspaths[i]);
        }
    }
    free(get_serial_server()->frame_cap_recv_cspaths);

    if (get_serial_server()->_badged_server_ep_cspath.capPtr != 0) {
        vka_cspace_free_path(parent_vka, get_serial_server()->_badged_server_ep_cspath);
    }
    if (get_serial_server()->parent_badge_value != SERIAL_SERVER_BADGE_VALUE_EMPTY) {
        serial_server_badge_value_free(get_serial_server()->parent_badge_value);
    }
    vka_free_object(parent_vka, &get_serial_server()->server_ep_obj);
    return error;
}
Example #9
0
static int
vmm_init(void)
{
    vka_object_t fault_ep_obj;
    vka_t* vka;
    simple_t* simple;
    vspace_t* vspace;
    int err;

    vka = &_vka;
    vspace = &_vspace;
    simple = &_simple;
    fault_ep_obj.cptr = 0;

    /* Camkes adds nothing to our address space, so this array is empty */
    void *existing_frames[] = {
        NULL
    };

    camkes_make_simple(simple);

    start_extra_frame_caps = simple_last_valid_cap(simple) + 1;

    /* Initialize allocator */
    allocman = bootstrap_use_current_1level(
            simple_get_cnode(simple),
            simple_get_cnode_size_bits(simple),
            simple_last_valid_cap(simple) + 1 + num_extra_frame_caps,
            BIT(simple_get_cnode_size_bits(simple)),
            sizeof(allocator_mempool), allocator_mempool
    );
    assert(allocman);
    err = allocman_add_simple_untypeds(allocman, simple);
    assert(!err);
    allocman_make_vka(vka, allocman);

    /* Initialize the vspace */
    err = sel4utils_bootstrap_vspace(vspace, &_alloc_data,
            simple_get_init_cap(simple, seL4_CapInitThreadPD), vka, NULL, NULL, existing_frames);
    assert(!err);

    /* Initialise device support */
    err = sel4platsupport_new_io_mapper(*simple, *vspace, *vka,
                                        &_io_ops.io_mapper);
    assert(!err);

    /* Initialise MUX subsystem */
    err = mux_sys_init(&_io_ops, &_io_ops.mux_sys);
    assert(!err);

    /* Initialise DMA */
    err = dma_dmaman_init(&_dma_morecore, NULL, &_io_ops.dma_manager);
    assert(!err);

    /* Allocate an endpoint for listening to events */
    err = vka_alloc_endpoint(vka, &fault_ep_obj);
    assert(!err);
    _fault_endpoint = fault_ep_obj.cptr;

    /* Create an IRQ server */
    err = irq_server_new(vspace, vka, simple_get_cnode(simple), IRQSERVER_PRIO,
                         simple, fault_ep_obj.cptr,
                         IRQ_MESSAGE_LABEL, 256, &_irq_server);
    assert(!err);


    return 0;
}
Example #10
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;
}