【MIPS CPU 体系结构概述2】连载14:

下面是笔者在为godson CPU的页面可执行保护功能增加内核支持时分析linux-mips mmu实现的一些笔记。也许第5节对整个工作过程的分析会有些用,其它语焉不详的 东西多数只是对笔者本人有点用.
首先的,关键的,要明白MIPS CPU的tlb是软件管理的,cache也不是透明的,具体的 参见它们的用户手册.
(for sgi-cvs kernel 2.4.17)

1. mmu context
cpu用8位asid来区分tlb表项所属的进程,但是进程超过256个怎么办?
linux实现的思想是软件扩展,每256个一组,TLB任何时候只存放同一组的asid 因此不会冲突. 从一组的某个进程切换到另一组时,把tlb刷新
ASID switch
include/asm/mmu_context.h:
asid_cache:
8bit physical asid + software extension, the software extension bits are used as a version; this records the newest asid allocated,while process->mm->context records its own version.
get_new_mmu_context:
asid_cache++, if increasement lead to change of software extension part then flush icache & tlb to avoid conflicting with old versions.
asid_cache = 0 reserved to represent no valid mmu context case,so the first asid_cache version start from 0x100.
switch_mm:
if asid version of new process differs from current process',get a new context for it.( it's safe even if it gets same 8bit asid as previous
because this process' tlb entries must have been flushed at the time of version increasement)
set entryhi,install pgd
activate_mm:
get new asid,set to entryhi,install pgd.

2. pte bits
页表的内容和TLB表项关系
entrylo[01]:
3130 29 6 5 3 2 1 0

| | PFN | C |D|V|G|

r4k pte:
31 12 111098 7 6 5 3 2 1 0

| PFN | C |D|V|G|B|M|A|W|R|P|

C: cache attr.
D: Dirty
V: valid
G: global
B: R4K_BUG
M: Modified
A: Accessed
W: Write
R: Read
P: Present
(last six bits implemented in software)

godson entrylo:
bit 30 is used as execution protect bit E,only bit25-6 are used as PFN.
instruction fetch from a page has E cleared lead to address error exception.
godson pte:
31 12 111098 7 6 5 3 2 1 0

| PFN | C |D|V|G|E|M|A|W|R|P|

E: software implementation of execute protection.Page is executable when E is set,non-executable otherwise.(Notice,it is different from hardware bit 30 in entrylo)

3. actions dealing with pte
pte_page: get page struct from its pte value

pte_{none,present,read,write,dirty,young}: get pte status,use software bits
pte_wrprotect: &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE)
pte_rdprotect: &= ~(_PAGE_READ | _PAGE_SILENT_READ)
pte_mkclean: &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE)
pte_mkold: &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ)
pte_mkwrite: |= _PAGE_WRITE && if (_PAGE_MODIFIED) |= _PAGE_SILENT_WRITE pte_mkread: |= _PAGE_READ && if (_PAGE_ACCESSED) |= _PAGE_SILENT_READ pte_mkdirty: |= _PAGE_MODIFIED && if (_PAGE_WRITE) |= _PAGE_SILENT_WRITE pte_mkyoung: |= _PAGE_ACCESSED && if (_PAGE_READ) |= _PAGE_SILENT_READ pgprot_noncached: (&~CACHE_MASK) | (_CACHE_UNCACHED)
mk_pte(page,prot): (unsigned long) ( page - memmap ) << PAGE_SHIFT | prot
mk_pte_phys(physpage,prot): physpage | prot
pte_modify(pte,prot): ( pte & _PAGE_CHG_MASK ) | newprot page_pte_{prot}: unused?
set_pte: *ptep = pteval
pte_clear: set_pte(ptep,__pte(0));

ptep_get_and_clear

pte_alloc/free

--电子创新网--
粤ICP备12070055号