免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7461 | 回复: 0
打印 上一主题 下一主题

[OpenBSD] NetBSD、FreeBSD、OpenBSD为何在pmap_growkernel的时候新增的页表项都没有置PG_G? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-06 18:52 |只看该作者 |倒序浏览
NetBSD的代码基本和OpenBSD的一样
/*
* pmap_growkernel: increase usage of KVM space
*
* => we allocate new PTPs for the kernel and install them in all
*    the pmaps on the system.
*/


vaddr_t
pmap_growkernel(maxkvaddr)
    vaddr_t maxkvaddr;
{
    struct pmap *kpm = pmap_kernel(), *pm;
    int needed_kpde;   /* needed number of kernel PTPs */
    int s;
    paddr_t ptaddr;

    needed_kpde = (u_int)(maxkvaddr - VM_MIN_KERNEL_ADDRESS + (NBPD-1))
        / NBPD;
    if (needed_kpde <= nkpde)
        goto out;        /* we are OK */

    /*
     * whoops!   we need to add kernel PTPs
     */


    s = splhigh();    /* to be safe */
    simple_lock(&kpm->pm_obj.vmobjlock);

    for (/*null*/ ; nkpde < needed_kpde ; nkpde++) {

        if (uvm.page_init_done == FALSE) {

            /*
             * we're growing the kernel pmap early (from
             * uvm_pageboot_alloc()).  this case must be
             * handled a little differently.
             */


            if (uvm_page_physget(&ptaddr) == FALSE)
                panic("pmap_growkernel: out of memory");
            pmap_zero_page(ptaddr);

            kpm->pm_pdir[PDSLOT_KERN + nkpde]
=
                ptaddr | PG_RW | PG_V;

            /* count PTP as resident */
            kpm->pm_stats.resident_count++;
            continue;
        }

        /*
         * THIS *MUST* BE CODED SO AS TO WORK IN THE
         * pmap_initialized == FALSE CASE!  WE MAY BE
         * INVOKED WHILE pmap_init() IS RUNNING!
         */


        if (pmap_alloc_ptp(kpm, PDSLOT_KERN + nkpde) == NULL) {
            panic("pmap_growkernel: alloc ptp failed");
        }

        /* PG_u not for kernel */
        kpm->pm_pdir[PDSLOT_KERN + nkpde] &= ~PG_u;

        /* distribute new kernel PTP to all active pmaps */
        simple_lock(&pmaps_lock);
        for (pm = pmaps.lh_first; pm != NULL;
             pm = pm->pm_list.le_next) {
            pm->pm_pdir[PDSLOT_KERN + nkpde] =
                kpm->pm_pdir[PDSLOT_KERN + nkpde];
        }

        /* Invalidate the PDP cache. */
        pool_cache_invalidate(&pmap_pdp_cache);
        pmap_pdp_cache_generation++;

        simple_unlock(&pmaps_lock);
    }

    simple_unlock(&kpm->pm_obj.vmobjlock);
    splx(s);

out:
    return (VM_MIN_KERNEL_ADDRESS + (nkpde * NBPD));
}


FreeBSD的
/*
* grow the number of kernel page table entries, if needed
*/

void
pmap_growkernel(vm_offset_t addr)
{
    struct pmap *pmap;
    vm_paddr_t ptppaddr;
    vm_page_t nkpg;
    pd_entry_t newpdir;
    pt_entry_t *pde;

    mtx_assert(&kernel_map->system_mtx, MA_OWNED);
    if (kernel_vm_end == 0) {
        kernel_vm_end = KERNBASE;
        nkpt = 0;
        while (pdir_pde(PTD, kernel_vm_end)) {
            kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
            nkpt++;
            if (kernel_vm_end - 1 >= kernel_map->max_offset) {
                kernel_vm_end = kernel_map->max_offset;
                break;
            }
        }
    }
    addr = roundup2(addr, PAGE_SIZE * NPTEPG);
    if (addr - 1 >= kernel_map->max_offset)
        addr = kernel_map->max_offset;
    while (kernel_vm_end < addr) {
        if (pdir_pde(PTD, kernel_vm_end)) {
            kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
            if (kernel_vm_end - 1 >= kernel_map->max_offset) {
                kernel_vm_end = kernel_map->max_offset;
                break;
            }
            continue;
        }

        /*
         * This index is bogus, but out of the way
         */

        nkpg = vm_page_alloc(NULL, nkpt,
            VM_ALLOC_NOOBJ | VM_ALLOC_SYSTEM | VM_ALLOC_WIRED);
        if (!nkpg)
            panic("pmap_growkernel: no memory to grow kernel");

        nkpt++;

        pmap_zero_page(nkpg);
        ptppaddr = VM_PAGE_TO_PHYS(nkpg);
        newpdir =
(pd_entry_t)
(ptppaddr | PG_V | PG_RW | PG_A | PG_M);
        pdir_pde(PTD, kernel_vm_end) = newpdir;

        mtx_lock_spin(&allpmaps_lock);
        LIST_FOREACH(pmap, &allpmaps, pm_list) {
            pde = pmap_pde(pmap, kernel_vm_end);
            pde_store(pde, newpdir);
        }
        mtx_unlock_spin(&allpmaps_lock);
        kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
        if (kernel_vm_end - 1 >= kernel_map->max_offset) {
            kernel_vm_end = kernel_map->max_offset;
            break;
        }
    }
}


我的理解是,内核空间总是在最高的1G.在切换CR3的时候TLB里有关内核空间的项目不用被刷新,所以内核空间的页表项都要设置上Global标志PG_G.

但是看样子这几个BSD都能没有设置.不知道出于何种考虑.

[ 本帖最后由 lllaaa 于 2007-10-6 18:54 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP