/* * 该函数释放进程用户态内存空间。关于释放进程内存空间,需明确以下几点: * * 对于进程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(); }
* 可能没有自己独立的页目录表(因为创建进程时页目录表也是共享的),因此, * 我们还要考虑是否为其中某些进程分配页目录表。二级页表页面同样需考虑。 * 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 */
/* * 该函数共享页目录表,也就是共享了进程全部内存。虽然再次设置代 * 码段只读是没必要的,但增加代码段内存页面的引用次数却是必要的。 */ 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(); }
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"); }
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; }
/* 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(); }
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; }
/* 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(); }