2007/0910-2007/0914工作周记

原创 2007年09月16日 23:43:00

    经过上个星期的试验,我们觉得有必要关注Leon3MMU

    硬件背景:

    由于Leon3Sparc架构,所以我查看了Sparc V8手册。SparcMMU大体结构是将32位虚拟地址分为4个段。(这里贴图不能直接贴,好麻烦!)

    第一,二层为PTD:PTP为下一级页表的物理地址

    PTD:(Page Table Descriptor)

    |_________PTP_______________|__ET_|

    31                             2 1 0

    第三层为PTE:PPN36位物理地址的高24(Leon3PPN20)

    PTE:(Page Table Entry )

    |_________PPN___________|_________|

    31                       8 7        0

    最后的当然就是偏移地址了。

    具体的寻址过程和x86几乎一样,不过x86cr3就变为一个特定的上下文寄存器,这个寄存器标识当前进程。

    具体过程:

    上下文寄存器从上下文表中获得当前进程的标识Root PointerRoot Pointer指向当前进程的全局页表的物理地址PA,然后从PTD获得偏移量PTPPA+PTP就是第二层页表的物理地址,以此类推,直到第三层。从指向的PTE中获得PPN也就是物理地址的前20位,然后再加上OFFSET12位,最后得到相应的物理地址。

    看看头文件的定义是否和手册说的一样。

../include/asm-sparc/pgtsrmmu.h

/* Number of contexts is implementation-dependent; 64k is the most we support */

#define SRMMU_MAX_CONTEXTS 65536


/* PMD_SHIFT determines the size of the area a second-level page table entry can map */

#define SRMMU_REAL_PMD_SHIFT 18

#define SRMMU_REAL_PMD_SIZE (1UL << SRMMU_REAL_PMD_SHIFT)

#define SRMMU_REAL_PMD_MASK (~(SRMMU_REAL_PMD_SIZE-1))

#define SRMMU_REAL_PMD_ALIGN(__addr) (((__addr)+SRMMU_REAL_PMD_SIZE-1)&SRMMU_REAL_PMD_MASK)


/* PGDIR_SHIFT determines what a third-level page table entry can map */

#define SRMMU_PGDIR_SHIFT 24

#define SRMMU_PGDIR_SIZE (1UL << SRMMU_PGDIR_SHIFT)

#define SRMMU_PGDIR_MASK (~(SRMMU_PGDIR_SIZE-1))

#define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK)


#define SRMMU_REAL_PTRS_PER_PTE 64

#define SRMMU_REAL_PTRS_PER_PMD 64

#define SRMMU_PTRS_PER_PGD 256

    单从上面的定义,可以看出定义和手册说明是一样的。但是现实往往要想象的残酷,在头文件中作者(David Miller)提到了一个问题。原文是:

/*

* To support pagetables in highmem, Linux introduces APIs which

* return struct page* and generally manipulate page tables when

* they are not mapped into kernel space. Our hardware page tables

* are smaller than pages. We lump hardware tabes into big,

* page sized software tables.

*

* PMD_SHIFT determines the size of the area a second-level page

* table entry can map, and our pmd_t is 16 times larger than

* normal. The values which were once defined here are now

* generic for 4c and srmmu, so they're found in pgtable.h.

*/

    大概的意思就是为了映射到高位内存,内存的页表大小必须作出调整。但是很遗憾他没有继续说明如何调整,我也找不到其他的文档说明。这也直接导致了没办法看懂源代码的一些页表操作。

    后来也发现了另外一个问题,Linux2.6.11开始,页表映射统一形式为四层:

pgd->pud->pmd->ptd。这真的让我很诧异,因为从头文件的定义怎样都看不出是分四层,而我们的内核是2.6.21.1。这是否说明这个内核Sparc部分处理MMU是有一定问题的?那么多问题,看来也只能是阅读源代码来解决了。

    以我目前的水平,读内核源代码带来的痛苦远远比快乐要多。错综复杂的宏定义、言简意赅的内嵌汇编、微妙而陌生的Sparc架构都让我沮丧不已,放弃的念头曾经象春天的野草一样在我大脑疯长。不过老子说得好:合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。唉,以此自勉吧。

    我们主要关注的文件是../arch/sparc/srmmu.c。首先要认识一些类型转换宏(特别是:__pte__pgd __pgprot)把一个无符号整数转换成所需的类型。这里值得注意的是__pmd被注释了。

../include/asm/page.h

typedef struct { unsigned long pte; } pte_t;

typedef struct { unsigned long iopte; } iopte_t;

typedef struct { unsigned long pmdv[16]; } pmd_t;

typedef struct { unsigned long pgd; } pgd_t;

typedef struct { unsigned long ctxd; } ctxd_t;

typedef struct { unsigned long pgprot; } pgprot_t;

typedef struct { unsigned long iopgprot; } iopgprot_t;



#define __pte(x) ((pte_t) { (x) } )

#define __iopte(x) ((iopte_t) { (x) } )

/* #define __pmd(x) ((pmd_t) { (x) } ) */ /* XXX procedure with loop */

#define __pgd(x) ((pgd_t) { (x) } )

#define __ctxd(x) ((ctxd_t) { (x) } )

#define __pgprot(x) ((pgprot_t) { (x) } )

#define __iopgprot(x) ((iopgprot_t) { (x) } )

    另外的类型转换宏执行和以上宏相反的转换,即把上面提到的特殊的类型转换成一个无符号整数。

#define pte_val(x) ((x).pte)

#define iopte_val(x) ((x).iopte)

#define pmd_val(x) ((x).pmdv[0])

#define pgd_val(x) ((x).pgd)

#define ctxd_val(x) ((x).ctxd)

#define pgprot_val(x) ((x).pgprot)

#define iopgprot_val(x) ((x).iopgprot)

    下面还有很多操作页表的宏和函数。不过这些函数用得并不多,但是理解它们对我们理解Sparc架构很有好处。

../arch/sparc/mm/srmmu.c

    向一个pte页表写入指定的值。

static inline void srmmu_set_pte(pte_t *ptep, pte_t pteval)

{

    srmmu_swap((unsigned long *)ptep, pte_val(pteval));

}


static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value)

{

    __asm__ __volatile__(

        "swap [%2], %0" :

        "=&r" (value) :

        "0" (value), "r" (addr));

        return value;

}

    汇编代码的意思也很简单,执行的语句就是Sparcswap汇编指令,%2就是指addr%0就是value。语句中的“0”也可以用r互换。

如果pte页表为0,返回1,否则为0

static inline int srmmu_pte_none(pte_t pte)

{

    return !(pte_val(pte) & 0xFFFFFFF);

}

    利用标志位,检测页面是否pte页面,是返回1,否则为0

static inline int srmmu_pte_present(pte_t pte)

{

    return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE);

}

    检测pte页指向的物理页是否有执行和读的权限。

static inline int srmmu_pte_read(pte_t pte)

{

    return !(pte_val(pte) & SRMMU_NOREAD);

}

    清除相应pte页表的一个表项,由此禁止进程使用由该页表 项映射的线性地址。

static inline void srmmu_pte_clear(pte_t *ptep)

{

    srmmu_set_pte(ptep, __pte(0));

}

    如果pmd表为0,返回1,否则为0

static inline int srmmu_pmd_none(pmd_t pmd)

{

    return !(pmd_val(pmd) & 0xFFFFFFF);

}

    利用标志位,检测页面是否pmd页面,是返回0,否则为1(yes is bad)

static inline int srmmu_pmd_bad(pmd_t pmd)

{

    return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }

    利用标志位,检测页面是否pmd页面,是返回1,否则为0

static inline int srmmu_pmd_present(pmd_t pmd)

{

    return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD);

}

    清除相应pmd页表的一个表项,由此禁止进程使用由该页表 项映射的线性地址。只是代码的for循环实现的有点莫名其妙。强制转换为pte_t类型是为了重用srmmu_set_pte 函数。

static inline void srmmu_pmd_clear(pmd_t *pmdp)

{

    int i;

    for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++)

    srmmu_set_pte((pte_t *)&pmdp->pmdv[i], __pte(0));

}

pgtable.h:

#define PTRS_PER_PTE 1024

#define PTE_SIZE (PTRS_PER_PTE*4)

pgtsrmmu.h:

typedef struct { unsigned long pmdv[16]; } pmd_t;(page.h)

#define SRMMU_REAL_PTRS_PER_PTE 64

#define SRMMU_REAL_PTE_TABLE_SIZE (SRMMU_REAL_PTRS_PER_PTE*4)


    如果pgd表为0,返回1,否则为0

static inline int srmmu_pgd_none(pgd_t pgd)

{

    return !(pgd_val(pgd) & 0xFFFFFFF);

}

    利用标志位,检测页面是否pgd页面,是返回0,否则为1(yes is bad)

static inline int srmmu_pgd_bad(pgd_t pgd)

{

    return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }

    利用标志位,检测页面是否pmd页面,是返回1,否则为0

static inline int srmmu_pgd_present(pgd_t pgd)

{

    return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD);

}

    清除相应pgd页表的一个表项,由此禁止进程使用由该页表 项映射的线性地址。

static inline void srmmu_pgd_clear(pgd_t * pgdp)

{

    srmmu_set_pte((pte_t *)pgdp, __pte(0));

}

page.h:

typedef struct { unsigned long pgd; } pgd_t;

    清除pte的读写标志。

static inline pte_t srmmu_pte_wrprotect(pte_t pte)

{

    return __pte(pte_val(pte) & ~SRMMU_WRITE);

}

    清除ptedirty位。

static inline pte_t srmmu_pte_mkclean(pte_t pte)

{

    return __pte(pte_val(pte) & ~SRMMU_DIRTY);

}

    清除pteReferenced位,意味着把此页标志为未访问。

static inline pte_t srmmu_pte_mkold(pte_t pte)

{

    return __pte(pte_val(pte) & ~SRMMU_REF);

}

    设置pte的读写位。

static inline pte_t srmmu_pte_mkwrite(pte_t pte)

{

    return __pte(pte_val(pte) | SRMMU_WRITE);

}

    设置ptedirty位。

static inline pte_t srmmu_pte_mkdirty(pte_t pte)

{

    return __pte(pte_val(pte) | SRMMU_DIRTY);

}

    设置pteReferenced位,意味着把此页标志为访问过。

static inline pte_t srmmu_pte_mkyoung(pte_t pte)

{

    return __pte(pte_val(pte) | SRMMU_REF);

}



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

工作周记(2015.9.20回来了)

从去年毕业以来,好久没有使用博客了。一方面工作太忙了,另一方面是工作和这个相关性不大。工作一年多以来,感觉过的算是浑浑噩噩的。没有很多的总结和输出,没有学习额外的新知识,感觉只限于工作。工作中的苦恼和...

Word 2007关闭时出现“已停止工作”的解决方法

http://support.microsoft.com/kb/2654846/zh-tw 我用过微软的Office 2003和2007及2010,在Word中,2007和2010都...

工作流引擎 (2007-10-12 16:53)

工作流引擎是 BOS 系统的一个重要组件。它可以根据客户具体的业务逻辑,来定义工作流模型。整个应用程序就根据所定义的流程来运行。它把应用系统模块和工作流程分开。当流程发生变化,只需修改流程模型,具体...

做事的态度与工作态度 (2007-04-29 09:19)

公司里有一个优秀的工程师,当他的主管问他,你工作做得非常出色,动力是什么?他回答到,“我不是把它当作一项工作去做,而是当作一件事去做,全力做好”。 他的回答很简单、朴实,但说到点子上。对于一个员工的工...

免费的快速开发平台(ES2007)下载试用|SOA中间件|BPM工作流|J2EE架构

一、为什么要推出免费SOA中间件中间件在国内市场上,厂商并不多,因为其对技术和经验的要求都比较高,在国内属于起步阶段。早年的企业管理软件,一套ERP系统动则百万,而如今随着信息化产业的发展很多企业管理...

免费的快速开发平台(ES2007)下载试用|SOA中间件|BPM工作流|J2EE架构

一、为什么要推出免费SOA中间件 中间件在国内市场上,厂商并不多,因为其对技术和经验的要求都比较高,在国内属于起步阶段。早年的企业管理软件,一套ERP系统动则百万,而如今随着信息化产业的发展很多企业管...

周记一.不管在哪里工作,你都可以创造不一样的价值

这个月开始新的试用期,想做点工作的记录,以及对目前开发状态的记录,在一家券商外包公司工作,最近在完成一个客户端的项目,负责写接口,其实这部分工作在5月份初就有原型稿,开始做一部分工作了,其实已经把大部...

工作-2017.08.06-周记总结篇(二)

拦截器(比如CXF框架中的)和过滤器都是拿来做什么的???都有些什么作用??? 参考链接 http://blog.csdn.net/tanggao1314/article/details/4841...

工作-2017.07.30-周记总结篇(一)

又是一周刷刷过,都还没来得及切扯淡呢,就已经又是一周了。虽然在学校的时候,有注意把自己的作息时间调成跟上班的类似。但是,这真的上班跟自己想的还是有点不一样。 嗯,闲言少叙,来看看本篇总结涉及的要点内容
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)