永久地址映射

首先要看几个重要的数据结构和概念:

 

 #ifdef CONFIG_X86_PAE
#define   LAST_PKMAP   512
#else
#define   LAST_PKMAP   1024   
#define   LAST_PKMAP_MASK     (LAST_PKMAP - 1)
#endif
定义了永久地址映射的,页表的数量,从这里我们也可以知道,永久地址映射一共映射的大小是4M,即:1024个页表
#define   PKMAP_BASE   (0xff800000UL)
#define   PKMAP_NR(virt)   ((virt - PKMAP_BASE) >> PAGE_SHIFT)
#define   PKMAP_ADDR(nr)   (PKMAP_BASE + ((nr) << PAGE_SHIFT))
PKMAP_BASE定义了永久地址映射线性地址的基地址,然后是线性地址和所映射的第几个PKMAP之间的转换
static   int   pkmap_count[LAST_PKMAP];
static   unsigned int   last_pkmap_nr;
pte_t   * pkmap_page_table;
pkmap_count记录了pkmap nr的count,pkmap_page_table 则就是映射页表的指针
pakmap_page_table的初始化在permanent_kmaps_init()里面初始化
从里面我们可以得到pdg = swapper_pg_dir + pgd_index(PKMAP_BASE);用一个页目录就应该够了,因为一共映射的大小是4M
pkmap_page_table也在这里初始化
下面我们看一下具体是怎么分配的:
void *kmap(struct page *page)
{
   if(!PageHighMem(page))
         return page_address(page);
   return kmap_high(page);
}
如果page不在高端页框中,则线性地址总是存在的,所以就不需要高端映射了,因为高端内存的存在的目的就是用留出的
线性地址来映射无法再ZONE_NORMAL中映射的页框。
void fastcall *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);
   这里我有些小疑问,vaddr如果不为0,那分配的vaddr不会属于当前要映射的kmap_high,下面应该重新分配呐
   pkmap_count[PKMAP_NR(vaddr)]++;
   
   spin_unlock(&kmap_lock);  /*这里释放的有可能是map_new_virtual里面加的锁*/
   return (void *)vaddr;
}
static inline  unsigned long map_new_virtual(struct page *page)
{
   unsigned long vaddr;
   int   count;
   start:
         count = LAST_PKMAP;
         下面要找到一个空的nr
         for(;;){
               last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK;
               if(!last_pkmap_nr){
                     flush_all_zero_pkmaps();
                     count = LAST_PKMAP;
               }
               last_pkmap_nr 已经全部搜索一遍,然而在每次重新搜索之前都有调用flush_all_zero_pkmaps把count计数为0,
               if(!pkmap_count[last_pimap_nr])
                     break;  /*找到一个可以使用的nr*/
               if(--count)
                     continue;
    
               {
                     DECLARE_WAITQUEUE(wait, current);
                     
                     __set_current_state(TASK_UNINTERRUPTIBLE);
                     add_wait_queue(&pkmap_map_wait, &wait);
                     spin_unlock(&kmap_lock);  /*在这里释放的是前面我加的锁,因为要进行调度,切换到别的进程执行*/
                     schedule();
                     remove_wait_queue(&pkmap_map_wait, &wait);
                     spin_lock(&kmap_lock);
                     上面是把当前进程加入到等待队列里
 
                     if(page_address(page))
                           return (unsigned long)page_address(page);
 
                     goto start;
               }          
         }
         vaddr = PKMAP_ADDR(last_pkmap_nr);
         set_pte(&(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));
         转换为线性地址后,设置页表
 
         pkmap_count[last_pkmap_nr] = 1;
         set_page_address(page, (void *)vaddr);
         在高端内存中,建立了专门的散列数据结构来存放页框和线性地址之间的映射
 
         return vaddr;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值