Beispiel #1
0
/**
 * Page table mapper init function.
 * @note This function should be called by mmu init.
 */
int ptmapper_init(void)
{
    SUBSYS_INIT("ptmapper");
#if defined(configPTMAPPER_DEBUG)
    kputs("\n");
#endif

    /* Allocate memory for mmu_pagetable_master */
    if (ptmapper_alloc(&mmu_pagetable_master)) {
        /* Critical failure */
        panic("Can't allocate memory for master page table.\n");
    }

    mmu_pagetable_system.master_pt_addr = mmu_pagetable_master.master_pt_addr;
    mmu_pagetable_system.nr_tables =
        (MMU_VADDR_KERNEL_END + 1) / MMU_PGSIZE_SECTION;
    if (ptmapper_alloc(&mmu_pagetable_system)) {
        /* Critical failure */
        panic("Can't allocate memory for system page table.\n");
    }

    /* Initialize system page tables */
    mmu_init_pagetable(&mmu_pagetable_master);
    mmu_init_pagetable(&mmu_pagetable_system);

    /*
     * Init regions
     */

    /* Kernel ro region */
    mmu_region_kernel.num_pages  = MMU_PAGE_CNT_BY_RANGE(
            MMU_VADDR_KERNEL_START, (intptr_t)(&_rodata_end) - 1,
            MMU_PGSIZE_COARSE);
    /* Kernel rw data region */
    mmu_region_kdata.vaddr      = (intptr_t)(&_data_start);
    mmu_region_kdata.num_pages  = MMU_PAGE_CNT_BY_RANGE(
            (intptr_t)(&_data_start), MMU_VADDR_KERNEL_END,
            MMU_PGSIZE_COARSE);
    mmu_region_kdata.paddr      = (intptr_t)(&_data_start);

    /* Fill page tables with translations & attributes */
    {
        mmu_region_t ** regp;
#if defined(configPTMAPPER_DEBUG)
        const char str_type[2][9] = {"sections", "pages"};
#define PRINTMAPREG(region)                             \
        KERROR(KERROR_DEBUG, "Mapped %s: %u %s\n",      \
            #region, region.num_pages,                  \
            (region.pt->pt_type == MMU_PTT_MASTER) ?    \
                str_type[0] : str_type[1]);
#else
#define PRINTMAPREG(region)
#endif
#define MAP_REGION(reg)         \
        mmu_map_region(&reg);   \
        PRINTMAPREG(reg)

        MAP_REGION(mmu_region_kstack);
        MAP_REGION(mmu_region_kernel);
        MAP_REGION(mmu_region_kdata);
        MAP_REGION(mmu_region_page_tables);
#undef MAP_REGION
#undef PRINTMAPREG
        SET_FOREACH(regp, ptmapper_fixed_regions) {
            mmu_map_region(*regp);
        }
    }
Beispiel #2
0
static pthread_t create_uinit_main(void * stack_addr)
{
    struct _sched_pthread_create_args init_ds = {
        .param.sched_policy = SCHED_OTHER,
        .param.sched_priority = NZERO,
        .stack_addr = stack_addr,
        .stack_size = configUSRINIT_SSIZE,
        .flags      = 0,
        .start      = uinit, /* We have to first get into user space to use exec
                              * and mount the rootfs.
                              */
        .arg1       = (uintptr_t)rootfs,
        .del_thread = (void (*)(void *))uinit_exit,
    };

    return thread_create(&init_ds, THREAD_MODE_PRIV);
}

/**
 * Map vmstack to proc.
 */
static void map_vmstack2proc(struct proc_info * proc, struct buf * vmstack)
{
    struct vm_pt * vpt;

    (*proc->mm.regions)[MM_STACK_REGION] = vmstack;
    vm_updateusr_ap(vmstack);

    vpt = ptlist_get_pt(&proc->mm, vmstack->b_mmu.vaddr,
                        MMU_PGSIZE_COARSE, VM_PT_CREAT);
    if (vpt == 0)
        panic("Couldn't get vpt for init stack");

    vmstack->b_mmu.pt = &(vpt->pt);
    vm_map_region(vmstack, vpt);
}

/**
 * Create init process.
 */
int __kinit__ kinit(void)
{
    SUBSYS_DEP(sched_init);
    SUBSYS_DEP(proc_init);
    SUBSYS_DEP(ramfs_init);
    SUBSYS_DEP(sysctl_init);
    SUBSYS_INIT("kinit");

    char strbuf[80]; /* Buffer for panic messages. */
    struct buf * init_vmstack;
    pthread_t tid;
    pid_t pid;
    struct thread_info * init_thread;
    struct proc_info * init_proc;


    /*
     * FIXME Memory allocation, protection or manipulation bug!
     * There is a critical bug causing random crashes in userland. I suspect
     * something is overwriting user space allocation from the kernel space.
     * Allocating some memory before init is executed seems to fix this issue,
     * however naturally this is not the proper way to fix the bug.
     * Without the allocation here the issue is sometimes seen in init or
     * usually after couple of fork + exec + exit cycles. The usual symptom is
     * that the userland app first calls some 0:0 syscalls and then tries to
     * execute undefined instruction, which probably means that either some
     * jump table in the heap or some part of the executable code is modified
     * by a bad access in kernel mode just before this happens.
     */
    (void)geteblk(MMU_PGSIZE_COARSE * 10);


    mount_tmp_rootfs();

    /*
     * User stack for init
     */
    init_vmstack = create_vmstack();
    if (!init_vmstack)
        panic("Can't allocate a stack for init");

    /*
     * Create a thread for init
     */
    tid = create_uinit_main((void *)(init_vmstack->b_mmu.paddr));
    if (tid < 0) {
        ksprintf(strbuf, sizeof(strbuf), "Can't create a thread for init. %i",
                 tid);
        panic(strbuf);
    }

    /*
     * pid of init
     */
    pid = proc_fork();
    if (pid <= 0) {
        ksprintf(strbuf, sizeof(strbuf), "Can't fork a process for init. %i",
                 pid);
        panic(strbuf);
    }

    init_thread = thread_lookup(tid);
    if (!init_thread) {
        panic("Can't get thread descriptor of init_thread!");
    }

    init_proc = proc_ref(pid);
    if (!init_proc || (init_proc->state == PROC_STATE_INITIAL)) {
        panic("Failed to get proc struct or invalid struct");
    }

    init_thread->pid_owner = pid;
    init_thread->curr_mpt = &init_proc->mm.mpt;

    /*
     * Map the previously created user stack with init process page table.
     */
    map_vmstack2proc(init_proc, init_vmstack);

    /*
     * Map tkstack of init with vm_pagetable_system.
     */
    mmu_map_region(&init_thread->kstack_region->b_mmu);
    init_proc->main_thread = init_thread;

    KERROR_DBG("Init created with pid: %u, tid: %u, stack: %p\n",
               pid, tid, (void *)init_vmstack->b_mmu.vaddr);

    proc_unref(init_proc);

    return 0;
}
Beispiel #3
0
void bcm2835_mmio_init(void)
{
    mmu_map_region(&bcm2835_mmio_region);
}