ioremap()

offset: 物理空间( I/O设备上的一块物理内存 )的起始地址
size:   物理空间的大小

给一段物理地址(起始地址offset)建立页表(地址映射)
--------------------------------------------------
static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
{   
    return __ioremap(offset, size, 0);
}    



    Remap an arbitrary physical address space into the kernel virtual address space. Needed when the kernel wants to access high addresses directly.
--------------------------------------------------
void __iomem *  __ioremap (unsigned long phys_addr, unsigned long size, unsigned long flags){
    void __iomem * addr;
    struct vm_struct * area;
    unsigned long offset, last_addr;
    last_addr = phys_addr + size - 1;
    if (!size || last_addr < phys_addr)
        return NULL;
    if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
        return (void __iomem *) phys_to_virt(phys_addr);

如果需要映射的空间的起始地址phys_addr为于ZONE_NORMAL区,通过virt_to_page()进行映射
|------------------------------------------------------------------------------|
|   if (phys_addr <= virt_to_phys(high_memory - 1))                            |
|    {                                                                         | 
|       char *t_addr, *t_end;                                                  |
|       struct page *page;                                                     |
|       t_addr = __va(phys_addr);                                              |
|       t_end = t_addr + (size - 1);                                           |
|       for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) -|
|           if(!PageReserved(page))                                            |
|               return NULL;                                                   |
|   }                                                                          |
|------------------------------------------------------------------------------|
    offset = phys_addr & ~PAGE_MASK;
    phys_addr &= PAGE_MASK;
    size = PAGE_ALIGN(last_addr+1) - phys_addr;

通过“非连续存储器区”进行映射
get_vm_area()创建类型为vm_struct的新描述符
get_vm_area()首先调用kmalloc()为新描述符获得一个存储区;然后扫描类型为struct vm_struct的描述符表,查找一个可用线性地址空间(至少包含size+4096个地址)。
|----------------------------------------------------------|
|   area = get_vm_area(size, VM_IOREMAP | (flags << 20)); -|
|   if (!area)                                             |
|       return NULL;                                       |
|----------------------------------------------------------|

    area->phys_addr = phys_addr;
    addr = (void __iomem *) area->addr;

ioremap_page_range()负责为一段物理地址(起始地址为phys_addr)和一段线性地址(起始地址为addr > VMALLOC_START, 大小为size)建立映射页表(建立的页表由内核页表的最高32项的其中几个目录项进行管理),如果建立成功则返回0
|-----------------------------------------------------------|
|   if (ioremap_page_range( -(unsigned long) addr,          |
|                            (unsigned long) addr + size,   |
|                            phys_addr,                     |
|                            flags))                        |
|    {                                                      |
|       vunmap((void __force *) addr);                      |
|       return NULL;                                        |
|   }                                                       |
|-----------------------------------------------------------|

   return (void __iomem *) (offset + (char __iomem *)addr);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值