Chinaunix首页 | 论坛 | 博客
  • 博客访问: 811044
  • 博文数量: 118
  • 博客积分: 2067
  • 博客等级: 大尉
  • 技术积分: 1751
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-17 14:27
文章存档

2016年(1)

2013年(1)

2012年(3)

2011年(26)

2010年(47)

2009年(40)

分类: LINUX

2011-01-06 14:20:30

转换步骤:

1. 首先确定转换地址是“程序地址”还是“数据地址”,根据不同,E500会查找L1MMU的I-L1VSP,I-L1TLB4K和D-L1VSP,D-L1TLB4K.
2. 在L1 MMU中根据当前虚拟地址,查找物理地址RPN,命中则返回RPN(Real Page Number),结束转换。否则查找L2 MMU。
3. 在L2 MMU中的TLB1,TLB0根据虚拟地址查找物理地址RPN,命中则返回。
4. TLB0和TLB1都没命中则产生ITLB或DTLB Miss异常,在异常处理程序中搜索在物理内存中的PTE表,获得RPN,并对TLB0进行更新
5. 如果PTE表也没有合适的RPN,则进一步分析虚拟地址,page_fault函数处理这种情况。

powerpc 32位有关页表的常量定义:

PAGE_SHIFT: 12
PAGE_MASK: 0xffff f000
PAGE_SIZE: 0x0000 1000

PTE_SHIFT: 10

PMD_SHIFT: 22
PMD_SIZE: 0x0040 0000
PMD_MASK: 0xffc0 0000

PUD_SHIFT: 22
PUD_SIZE: 0x0040 0000
PUD_MASK: 0xffc0 0000

PGDIR_SHIFT: 22
PGDIR_SIZE: 0x0040 0000
PGDIR_MASK: 0xffc0 0000

linux 支持的结构:
|<-------------------- BITS_PER_LONG ------------------------------------>|
               |<--------------------- PGDIR_SHIFT ---------------------->|
                           |<---------------- PUD_SHIFT ----------------->|       
                                          |<---------- PMD_SHIFT -------->|
                                                          |<- PAGE_SHIFT->|
 -------------------------------------------------------------------------                  
|      PGD    |     PUD    |     PMD      |      PTE      |       Offset  |
 -------------------------------------------------------------------------

实际上PowerPC E500支持的结构:
|<-------------------- BITS_PER_LONG ------------------------------------>|
                            |<-------- PGDIR_SHIFT ---------------------->|
                            |<---------- PUD_SHIFT ---------------------->|       
                            |<------------------------ PMD_SHIFT -------->|
                            |<-- PTE_SHIFT -->|
                                              |<------- PAGE_SHIFT ------>|
 -------------------------------------------------------------------------                  
|      PGD     <10b>        |       PTE <10b> |             <12b> Offset  |
 -------------------------------------------------------------------------

PTE表的开始建立(内核部分):
主要在下面函数中建立映射表:
分析:以虚拟地址(指程序使用的有效地址,VA表示)f1005000 映射物理地址ffe42000为例分析:
  1. int map_page(unsigned long va, phys_addr_t pa, int flags)
  2. {
  3.     pmd_t *pd;
  4.     pte_t *pg;
  5.     int err = -ENOMEM;

  6.     /* Use upper 10 bits of VA to index the first level map */
  7.     pd = pmd_offset(pud_offset(pgd_offset_k(va), va), va);
  8.     /* Use middle 10 bits of VA to index the second-level map */
  9.     pg = pte_alloc_kernel(pd, va);
  10.     if (pg != 0) {
  11.         err = 0;
  12.         /* The PTE should never be already set nor present in the
  13.          * hash table
  14.          */
  15.         BUG_ON((pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE)) &&
  16.                flags);
  17.         set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
  18.                              __pgprot(flags)));
  19.     }
  20.     return err;
  21. }

1. pmd_offset函数是取得PTE表虚拟地址的偏移,由于32位PowerPC没有使用PUD与PMD部分,所以pgd_offset_k的返回值就是PTE表的偏移。

#define pgd_offset_k(address) pgd_offset(&init_mm, address)
  ->  #define pgd_offset(mm, address)  ((mm)->pgd + pgd_index(address))
  ->  #define pgd_index(address)   ((address) >> PGDIR_SHIFT)
  ->  #define PGDIR_SHIFT (PAGE_SHIFT + PTE_SHIFT)  //  = 12 + 10 = 22

由于是映射kernel部分,所以用pgd_offset_k,即init_mm为PGD表。
否则用pgd_offset,(mm)->pgd为PGD表来计算。
计算结果为:(设:init_mm->pgd = 0xc064 7000) + 0xf1005000 >> 22 = 0xc064 7000 + 0x3c4 * 4
因为pgd每个entry占4个字节,所以后面的偏移要*4. = 0xc0647f10

2. pte_alloc_kernel(pd, va)
#define pte_alloc_kernel(pmd, address)          \
    ((unlikely(!pmd_present(*(pmd))) && __pte_alloc_kernel(pmd, address))? \
              NULL: pte_offset_kernel(pmd, address))
#define pmd_present(pmd)    (pmd_val(pmd) & _PMD_PRESENT_MASK)
#define pte_offset_kernel(dir, addr) \
            ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))

#define pmd_page_vaddr(pmd) \
            ((unsigned long) (pmd_val(pmd) & PAGE_MASK))
#define pte_index(address)      \
         (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define PTRS_PER_PTE    (1 << PTE_SHIFT) = 1 << 10

由此可以看出此函数功能为:
如果与虚拟地址相关联的PMD项为空则分配一页,否则不分配,返回PTE表项的地址。
注意此处返回值是存放PTE表页面的页面虚拟地址,此地址有两部分构成:虚拟地址的高20位(低12位总是为0,因为4K对齐的关系,并且此12位用来存放PTE偏移)+PTE偏移(低12位)此地址的内容为物理地址高20位+12位的标志位。
3 set_pte_at函数相当于把物理地址写入PTE表项。
写入的内容为pfn_pte计算结果,即物理地址的PFN(占20位)+flags(占12位)。即
ffe42+flags








阅读(2681) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~