示例#1
0
/*
 * 该函数释放进程用户态内存空间。关于释放进程内存空间,需明确以下几点:
 *
 * 对于进程0,释放用户态内存则意味着其刚开始执行execve(),此时只需将其
 * 用户态页目录项清零即可。不能释放,因为0进程与内核共用页表!
 *
 * 由于各个进程共用一套内核态的二级页表页面,因此不能释放内核空间。
 *
 * 同时,并不释放页目录表所在页面,因为进程当前运行于内核态,依然依赖
 * 于内核地址空间。而在该进程挂掉之后,由其父进程释放页目录表。那么0号
 * 进程的父进程是谁呢?别想它了,除非系统关闭,否则0号进程是不会灭亡滴 :-)
 *
 * 由于可能存在多个进程在使用当前页目录表(实际上在创建新进程时,子进程
 * 默认与父进程具有相同的CR3),因此释放进程页目录表时,只需将引用数减1。
 *
 * 另外,我们需要使TLB无效,以保持TLB的一致性(幸好Intel CPU会负责维护
 * Cache与内存的一致性)。但有时(比如当前进程退出时),我们无需使TLB无效,
 * 因为它没有机会再去运行,很快其父进程就会将其页目录回收掉。
 *
 * I:from - 起始线性地址, size - 内存空间大小, invtlb - 是否使TLB无效.
 */
void free_user_pages(unsigned long from, unsigned long size, BOOL invtlb)
{
	if(0 == get_cur_proc_nr())
		zeromem((char *)current->tss.cr3, 4*INIT_UPDE_COUNT);
	else
		free_shared_pages(from, size);
	if(invtlb)
		invalidate_tlb();
}
示例#2
0
 * 可能没有自己独立的页目录表(因为创建进程时页目录表也是共享的),因此,
 * 我们还要考虑是否为其中某些进程分配页目录表。二级页表页面同样需考虑。
 * I: vaddr - 发生页保护中断的页面的虚拟地址.
 */
BOOL un_page_wp(unsigned long vaddr)
{
	unsigned long addr, tmp;

	if(vaddr >= V_KERNEL_ZONE_START)	/* 用于调试内核代码 */
		panic("un_page_wp: BAD, write to kernel address space.");
	if(vaddr < current->code_start || vaddr >= current->data_end
		|| (vaddr >= current->code_end && vaddr < current->data_start))
		panic("un_page_wp: out of code or data space limit.");

	/* 进程还没有自己独立的页目录表,则分配 */
	if(1 < mem_map[M2MAP(current->tss.cr3)]) {
		addr = current->tss.cr3;
		if(!copy_page_dir(&(current->tss.cr3))) {
			k_printf("un_page_wp: have no free-page!");
			return FALSE;
		}
		load_cr3(current->tss.cr3);
		--mem_map[M2MAP(addr)];
	}
	addr = ADDR_IN_1PT(current->tss.cr3, vaddr);

	/* 进程还没有自己独立的二级页表页面,则分配 */
	if(1 < mem_map[M2MAP(ALIGN_PAGE(*(unsigned long *)addr))]) {
		/* get_free_page而不是clean,因为接下来会复制整个页面 */
		if(NULL == (tmp=get_free_page())) {
			k_printf("un_page_wp: have no free-page!");
			return FALSE;
		}
		memcpy((char *)tmp, (char *)ALIGN_PAGE(*(unsigned long *)addr),
			PAGE_SIZE);
		--mem_map[M2MAP(ALIGN_PAGE(*(unsigned long *)addr))];
		*(unsigned long *)addr = tmp + P_UWP;
	}
	addr = ALIGN_PAGE(*(unsigned long *)addr);
	addr = ADDR_IN_2PT(addr, vaddr);

	/* 最终页面引用次数为1则设置其可写,否则分配独立页面 */
	if(1 == mem_map[M2MAP(ALIGN_PAGE(*(unsigned long *)addr))]) {
		*(unsigned long *)addr |= 0x00000002;	/* 设置页面可写 */
	} else {
		if(NULL == (tmp=get_free_page())) {
			k_printf("un_page_wp: have no enough memory!");
			return FALSE;
		}
		memcpy((char *)tmp, (char *)ALIGN_PAGE(*(unsigned long *)addr),
			PAGE_SIZE);
		--mem_map[M2MAP(ALIGN_PAGE(*(unsigned long *)addr))];
		*(unsigned long *)addr = tmp + P_UWP;
	}

	/* 刷新TLB */
示例#3
0
/*
 * 该函数共享页目录表,也就是共享了进程全部内存。虽然再次设置代
 * 码段只读是没必要的,但增加代码段内存页面的引用次数却是必要的。
 */
void share_page_dir(long * cr3)
{
	if(!cr3)
		panic("share_page_dir: cr3-pointer is NULL!");
	*cr3 = current->tss.cr3;
	++mem_map[M2MAP(*cr3)];
	set_shared_pages(current->code_start,
		current->data_end-current->code_start);
	invalidate_tlb();
}
示例#4
0
void mmu_setup(void)
{
	setup_mmu_state();
	setup_direct_map();
	invalidate_tlb();
	install_pt_address();
	printk("Installed page table address\n");
	set_domain_permissions();
	printk("Set domain permissions\n");
	flush_caches();
	enable_mmu();
	printk("MMU setup complete.\n");
}
示例#5
0
int32_t copy_pages_parent_child( pid_t parent, pid_t child_pid )
{
    if(parent < 0 || child_pid < 0)
    {
        return -1;
    }
    vma_t    *vma        = NULL;
    process_t* par_proc =  get_proc_from_pid(parent);
    process_t* child_proc = get_proc_from_pid(child_pid);

    if (!par_proc || !child_proc)
    {
        #ifdef LOG
            printf("Failed to get child/parent pid\n");
        #endif
        return -1;
    }

    uint64_t *parent_table_base = PHYS_TO_VA(par_proc->page_table_base);
    uint64_t *parent_proc_pte;
    uint64_t *child_proc_pte;
    
    if ( curr_running_proc->page_table_base != NULL  
        && child_proc->page_table_base != NULL )
    {
        
        /* For the fourth level page table, we need to copy only the user level
        * entries. Above 'kernel_start', shared kernel level page tables exist
        * which are not supposed to be copied. Hence check from the parent process
        vma */
        vma = par_proc->mm.vma_list;
        while ( vma )
        {
            uint64_t va_start = ROUNDDOWN(vma->vma_start, PGSIZE, uint64_t);
            uint64_t va_end = ROUNDUP(vma->vma_start + vma->memsz, PGSIZE, uint64_t);
            for ( ; va_start < va_end; va_start += PGSIZE )
            {
                //Retrieve parent process page table entry for this vma_start
                //value
                parent_proc_pte = page_lookup( parent_table_base , va_start);
               
                if( parent_proc_pte == NULL)
                {
                    //Entry is not mapped in parent vma
                    //Move to next entry.
                    continue;
                }
               
                //Increase the reference for shared page between
                // parent and child
                Pages* shared_page = PHYS_TO_PAGE(*parent_proc_pte);
                shared_page->ref++;

                uint64_t perm = PTE_U | PTE_P;
                if ( *parent_proc_pte & PTE_W || *parent_proc_pte & PTE_COW)
                {
                    perm |= PTE_W;
                }

                //Map this value of va_start in child page table with
                //appropriate permissions
                map_range_va2pa(PHYS_TO_VA(child_proc->page_table_base),
                                va_start,
                                va_start + PGSIZE,
                                *parent_proc_pte,
                                perm);

                //If parent write bit is set, then change parents pte to cow
                //Also test for cow bit in parent in case of multiple child
                //Because parent cow bit might already have been set
                //Due to a earlier child
                if ( *parent_proc_pte & PTE_W || *parent_proc_pte & PTE_COW)
                {
                    //Set the parent process page table entry bit to COW
                    *parent_proc_pte = (( *parent_proc_pte & MASK_PAGE_PERM) 
                                    | (( PTE_U | PTE_COW | PTE_P) & 0xFFF) );
                    invalidate_tlb(va_start);

                    //This permission ends being used for children

                    child_proc_pte = page_lookup(PHYS_TO_VA(child_proc->page_table_base),
                                                 va_start);
                    if (child_proc_pte)
                    {
                        *child_proc_pte = (*child_proc_pte & MASK_PAGE_PERM) | PTE_U | PTE_P | PTE_COW;
                    }
                }

            } /* for ( uint64_t va_start = ...) */
            vma = vma->vma_next;
        }
    }
    else
    {
        #ifdef LOG
            printf(" Some problem occured while copying of pages from parent to child \n");
        #endif
        return -1;
    }
    return 0;
}
示例#6
0
/* We run cpu_init_early_f in AS = 1 */
void cpu_init_early_f(void)
{
	u32 mas0, mas1, mas2, mas3, mas7;
	int i;
#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT)
	ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
	u32  *l2srbar, *dst, *src;
	void (*setup_ifc_sram)(void);
#endif

	/* Pointer is writable since we allocated a register for it */
	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);

	/*
	 * Clear initial global data
	 *   we don't use memset so we can share this code with NAND_SPL
	 */
	for (i = 0; i < sizeof(gd_t); i++)
		((char *)gd)[i] = 0;

	mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(13);
	mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
	mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G);
	mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS, 0, MAS3_SW|MAS3_SR);
	mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_PHYS);

	write_tlb(mas0, mas1, mas2, mas3, mas7);

/*
 * Work Around for IFC Erratum A-003549. This issue is P1010
 * specific. LCLK(a free running clk signal) is muxed with IFC_CS3 on P1010 SOC
 * Hence specifically selecting CS3.
 */
#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
	setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_LCLK_IFC_CS3);
#endif

	init_laws();

/*
 * Work Around for IFC Erratum A003399, issue will hit only when execution
 * from NOR Flash
 */
#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT)
#define SRAM_BASE_ADDR	(0x00000000)
	/* TLB for SRAM */
	mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(9);
	mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS |
		MAS1_TSIZE(BOOKE_PAGESZ_1M);
	mas2 = FSL_BOOKE_MAS2(SRAM_BASE_ADDR, MAS2_I);
	mas3 = FSL_BOOKE_MAS3(SRAM_BASE_ADDR, 0, MAS3_SX|MAS3_SW|MAS3_SR);
	mas7 = FSL_BOOKE_MAS7(0);

	write_tlb(mas0, mas1, mas2, mas3, mas7);

	out_be32(&l2cache->l2srbar0, SRAM_BASE_ADDR);

	out_be32(&l2cache->l2errdis,
		(MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC));

	out_be32(&l2cache->l2ctl,
		(MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE));

	/*
	 * Copy the code in setup_ifc to L2SRAM. Do a word copy
	 * because NOR Flash on P1010 does not support byte
	 * access (Erratum IFC-A002769)
	 */
	setup_ifc_sram = (void *)SRAM_BASE_ADDR;
	dst = (u32 *) SRAM_BASE_ADDR;
	src = (u32 *) setup_ifc;
	for (i = 0; i < 1024; i++)
		*l2srbar++ = *src++;

	setup_ifc_sram();

	/* CLEANUP */
	clrbits_be32(&l2cache->l2ctl,
			(MPC85xx_L2CTL_L2E |
			 MPC85xx_L2CTL_L2SRAM_ENTIRE));
	out_be32(&l2cache->l2srbar0, 0x0);
#endif

	invalidate_tlb(1);

#if defined(CONFIG_SECURE_BOOT)
	/* Disable the TLBs created by ISBC */
	for (i = CONFIG_SYS_ISBC_START_TLB;
	     i < CONFIG_SYS_ISBC_START_TLB + CONFIG_SYS_ISBC_NUM_TLBS; i++)
			disable_tlb(i);
#endif

	init_tlbs();
}
示例#7
0
int update_curr_page_table(uint64_t phys, uint64_t virt,
                                                        uint64_t access_perm) {

    // Design notes
    //  - This function uses self referencing trick to access page translation
    //  objects
    //  - Do NOT use phys_mem_virt_map_base directly or indirectly
    //  (VIRTUAL_ADDR, functions)

    uint64_t pdp, pd, pt; // physical addresses
    uint64_t *pml4e_vaddr, *pdpe_vaddr, *pde_vaddr, *pte_vaddr;

    pml4e_vaddr = (uint64_t*)SELF_REF_PML4E(virt);

    // Check PDP present
    if(!((*pml4e_vaddr) & PAGE_TRANS_PRESENT)) {

        if(!phys) {
            return -1;
        }

        pdpe_vaddr = (uint64_t*)get_zeroed_page_trans_obj(&pdp);
        if(!pdpe_vaddr) {
            return -1;
        }

        *pml4e_vaddr = PAGE_TRANS_NEXT_LEVEL_ADDR(pdp) | PAGE_TRANS_PRESENT
                        | PAGE_TRANS_READ_WRITE | PAGE_TRANS_USER_SUPERVISOR;
    }

    pdpe_vaddr = (uint64_t*)SELF_REF_PDPE(virt);

    // Check PD present
    if(!((*pdpe_vaddr) & PAGE_TRANS_PRESENT)) {

        if(!phys) {
            return -1;
        }

        pde_vaddr = (uint64_t*)get_zeroed_page_trans_obj(&pd);
        if(!pde_vaddr) {
            return -1;
        }

        *pdpe_vaddr = PAGE_TRANS_NEXT_LEVEL_ADDR(pd) | PAGE_TRANS_PRESENT
                        | PAGE_TRANS_READ_WRITE | PAGE_TRANS_USER_SUPERVISOR;
    }

    pde_vaddr = (uint64_t*)SELF_REF_PDE(virt);

    // Check PT present
    if(!((*pde_vaddr) & PAGE_TRANS_PRESENT)) {

        if(!phys) {
            return -1;
        }

        pte_vaddr = (uint64_t*)get_zeroed_page_trans_obj(&pt);
        if(!pte_vaddr) {
            return -1;
        }

        *pde_vaddr = PAGE_TRANS_NEXT_LEVEL_ADDR(pt) | PAGE_TRANS_PRESENT
                        | PAGE_TRANS_READ_WRITE | PAGE_TRANS_USER_SUPERVISOR;
    }

    pte_vaddr = (uint64_t*)SELF_REF_PTE(virt);
    if((*pte_vaddr) & PAGE_TRANS_PRESENT) {

        if(!phys) {
            *pte_vaddr = PAGE_TRANS_NEXT_LEVEL_ADDR(*pte_vaddr)
                                    | PAGE_TRANS_NON_ADDR_FIELDS(access_perm);

            invalidate_tlb((char*)virt);
            return 0;
        }

        // TODO: Replace with logger

        //printf("Mapping again!\n");
    }

    if(!phys) {
        return -1;
    }

    *pte_vaddr = PAGE_TRANS_NEXT_LEVEL_ADDR(phys) | PAGE_TRANS_PRESENT
                                    | PAGE_TRANS_NON_ADDR_FIELDS(access_perm);

    invalidate_tlb((char*)virt);
    return 0;
}
示例#8
0
/* We run cpu_init_early_f in AS = 1 */
void cpu_init_early_f(void *fdt)
{
	u32 mas0, mas1, mas2, mas3, mas7;
	int i;
#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
#ifdef CONFIG_A003399_NOR_WORKAROUND
	ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
	u32  *dst, *src;
	void (*setup_ifc_sram)(void);
#endif

	/* Pointer is writable since we allocated a register for it */
	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);

	/*
	 * Clear initial global data
	 *   we don't use memset so we can share this code with NAND_SPL
	 */
	for (i = 0; i < sizeof(gd_t); i++)
		((char *)gd)[i] = 0;

#ifdef CONFIG_QEMU_E500
	/*
	 * CONFIG_SYS_CCSRBAR_PHYS below may use gd->fdt_blob on ePAPR systems,
	 * so we need to populate it before it accesses it.
	 */
	gd->fdt_blob = fdt;
#endif

	mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(13);
	mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
	mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G);
	mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS, 0, MAS3_SW|MAS3_SR);
	mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_PHYS);

	write_tlb(mas0, mas1, mas2, mas3, mas7);

/*
 * Work Around for IFC Erratum A-003549. This issue is P1010
 * specific. LCLK(a free running clk signal) is muxed with IFC_CS3 on P1010 SOC
 * Hence specifically selecting CS3.
 */
#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
	setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_LCLK_IFC_CS3);
#endif

	init_laws();

/*
 * Work Around for IFC Erratum A003399, issue will hit only when execution
 * from NOR Flash
 */
#ifdef CONFIG_A003399_NOR_WORKAROUND
#define SRAM_BASE_ADDR	(0x00000000)
	/* TLB for SRAM */
	mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(9);
	mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS |
		MAS1_TSIZE(BOOKE_PAGESZ_1M);
	mas2 = FSL_BOOKE_MAS2(SRAM_BASE_ADDR, MAS2_I);
	mas3 = FSL_BOOKE_MAS3(SRAM_BASE_ADDR, 0, MAS3_SX|MAS3_SW|MAS3_SR);
	mas7 = FSL_BOOKE_MAS7(0);

	write_tlb(mas0, mas1, mas2, mas3, mas7);

	out_be32(&l2cache->l2srbar0, SRAM_BASE_ADDR);

	out_be32(&l2cache->l2errdis,
		(MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC));

	out_be32(&l2cache->l2ctl,
		(MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE));

	/*
	 * Copy the code in setup_ifc to L2SRAM. Do a word copy
	 * because NOR Flash on P1010 does not support byte
	 * access (Erratum IFC-A002769)
	 */
	setup_ifc_sram = (void *)SRAM_BASE_ADDR;
	dst = (u32 *) SRAM_BASE_ADDR;
	src = (u32 *) setup_ifc;
	for (i = 0; i < 1024; i++) {
		/* cppcheck-suppress nullPointer */
		*dst++ = *src++;
	}

	/* cppcheck-suppress nullPointer */
	setup_ifc_sram();

	/* CLEANUP */
	clrbits_be32(&l2cache->l2ctl,
			(MPC85xx_L2CTL_L2E |
			 MPC85xx_L2CTL_L2SRAM_ENTIRE));
	out_be32(&l2cache->l2srbar0, 0x0);
#endif

	invalidate_tlb(1);

#if defined(CONFIG_SYS_PPC_E500_DEBUG_TLB) && \
	!(defined(CONFIG_SPL_INIT_MINIMAL) && defined(CONFIG_SPL_BUILD)) && \
	!defined(CONFIG_NAND_SPL)
	disable_tlb(CONFIG_SYS_PPC_E500_DEBUG_TLB);
#endif

	init_tlbs();
}