kernel mappings of high-memory page frames

linux使用3种方法来实现这个目标:
1.permanent kernel mappings:
这种实现方法有两个核心的数据结构,一个是dedicated page table,地址由变量pkmap_page_table来指明,这个table有512或者1024中entries,取决于pae是否被激活,负责将线性地址转为物理
地址。
另一个核心数据结构是一个名为page_address_htable的哈希表,跟这个表有关的函数为page_address(),它负责根据一个page descriptor,返回对应的线性地址。
kmap()函数用来建立一个permanent kernel mapping,代码如下:
void * kmap(struct page * page)
{
if (!PageHighMem(page))
return page_address(page);
return kmap_high(page);
}

kmap_high函数代码如下:
void * kmap_high(struct page * page)
{
unsigned long vaddr;
spin_lock(&kmap_lock);
vaddr = (unsigned long) page_address(page);
if (!vaddr)
vaddr = map_new_virtual(page);
pkmap_count[(vaddr-PKMAP_BASE) >> PAGE_SHIFT]++;
spin_unlock(&kmap_lock);
return (void *) vaddr;
}
map_new_virtual函数将page frame的物理地址插入到pkmap_page_table中,而且添加一个元素到page_address_htable中。
这种映射方法在页表没有空余entry时,会阻塞执行(map_new_virtual函数中),所以不能用于那些不能被阻塞的情况。
这里还有个值得学习的地方在于kunmap()函数负责释放映射,但是它只是减少counter的计数,而没有真正做释放的操作,那么释放的操作是在哪里执行的呢?答案是在map_new_virtual函数中,也就是建立
map的函数中会检查count的值,并将没有引用的entry删除。
2.temporary kernel mappings:
kernel是这样来实现的,每个cpu都有自己的一个window集,实际上是由enum km_type数据结构来实现的,它的值可以是KM_BOUNCE_READ, KM_USER0, or KM_PTE0。
每个值都是一个fix-mapped linear address的index。
建立一个临时内核映射,是通过调用函数kmap_atomic(),代码如下:
void * kmap_atomic(struct page * page, enum km_type type)
{
enum fixed_addresses idx;
unsigned long vaddr;

current_thread_info( )->preempt_count++;
if (!PageHighMem(page))
return page_address(page);
idx = type + KM_TYPE_NR * smp_processor_id( );
vaddr = fix_to_virt(FIX_KMAP_BEGIN + idx);
set_pte(kmap_pte-idx, mk_pte(page, 0x063));
_ _flush_tlb_single(vaddr);
return (void *) vaddr;
}
3.noncontiguous memeory allocation
2009/02/03 二

你可能感兴趣的:(thread,数据结构,linux)