函数 ioremap 物理地址到内核映射空间的映射函数
2007-07-24 17:25
435 查看
源代码:
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*
* NOTE! We need to allow non-page-aligned mappings too: we will obviously
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*
* 'flags' are the extra L_PTE_ flags that you want to specify for this
* mapping. See include/asm-arm/proc-armv/pgtable.h for more information.
*/
void * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags)
{
void * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;
/*
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr) - phys_addr;
/*
* Ok, go for it..
*/
area = get_vm_area(size, VM_IOREMAP);
if (!area)
return NULL;
addr = area->addr;
if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
vfree(addr);
return NULL;
}
return (void *) (offset + (char *)addr);
}
功能就是将I/O内存资源的物理地址映射到核心虚地址空间(3GB-4GB)中.
1、返回映射后的虚拟地址(get_vm_area获取)
2、对获取的虚拟空间进行页面映射(remap_area_pages)
下面是相关的函数:
struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
{
unsigned long addr, next;
struct vm_struct **p, *tmp, *area;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
size += PAGE_SIZE;
if (!size) {
kfree (area);
return NULL;
}
addr = VMALLOC_START;
write_lock(&vmlist_lock);
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if ((size + addr) < addr)
goto out;
if (size + addr <= (unsigned long) tmp->addr)
break;
next = tmp->size + (unsigned long) tmp->addr;
if (next > addr)
addr = next;
if (addr > VMALLOC_END-size)
goto out;
}
area->flags = flags;
area->addr = (void *)addr;
area->size = size;
area->next = *p;
*p = area;
write_unlock(&vmlist_lock);
return area;
out:
write_unlock(&vmlist_lock);
kfree(area);
return NULL;
}
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
unsigned long size, unsigned long flags)
{
int error;
pgd_t * dir;
unsigned long end = address + size;
phys_addr -= address;
dir = pgd_offset_k(address);
flush_cache_all();
if (address >= end)
BUG();
spin_lock(&init_mm.page_table_lock);
do {
pmd_t *pmd;
pmd = pmd_alloc(&init_mm, dir, address);
error = -ENOMEM;
if (!pmd)
break;
if (remap_area_pmd(pmd, address, end - address,
phys_addr + address, flags))
break;
error = 0;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
spin_unlock(&init_mm.page_table_lock);
flush_tlb_all();
return error;
}
其中的一些映射关系参考内存管理的分页管理
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*
* NOTE! We need to allow non-page-aligned mappings too: we will obviously
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*
* 'flags' are the extra L_PTE_ flags that you want to specify for this
* mapping. See include/asm-arm/proc-armv/pgtable.h for more information.
*/
void * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags)
{
void * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;
/*
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr) - phys_addr;
/*
* Ok, go for it..
*/
area = get_vm_area(size, VM_IOREMAP);
if (!area)
return NULL;
addr = area->addr;
if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
vfree(addr);
return NULL;
}
return (void *) (offset + (char *)addr);
}
功能就是将I/O内存资源的物理地址映射到核心虚地址空间(3GB-4GB)中.
1、返回映射后的虚拟地址(get_vm_area获取)
2、对获取的虚拟空间进行页面映射(remap_area_pages)
下面是相关的函数:
struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
{
unsigned long addr, next;
struct vm_struct **p, *tmp, *area;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
size += PAGE_SIZE;
if (!size) {
kfree (area);
return NULL;
}
addr = VMALLOC_START;
write_lock(&vmlist_lock);
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if ((size + addr) < addr)
goto out;
if (size + addr <= (unsigned long) tmp->addr)
break;
next = tmp->size + (unsigned long) tmp->addr;
if (next > addr)
addr = next;
if (addr > VMALLOC_END-size)
goto out;
}
area->flags = flags;
area->addr = (void *)addr;
area->size = size;
area->next = *p;
*p = area;
write_unlock(&vmlist_lock);
return area;
out:
write_unlock(&vmlist_lock);
kfree(area);
return NULL;
}
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
unsigned long size, unsigned long flags)
{
int error;
pgd_t * dir;
unsigned long end = address + size;
phys_addr -= address;
dir = pgd_offset_k(address);
flush_cache_all();
if (address >= end)
BUG();
spin_lock(&init_mm.page_table_lock);
do {
pmd_t *pmd;
pmd = pmd_alloc(&init_mm, dir, address);
error = -ENOMEM;
if (!pmd)
break;
if (remap_area_pmd(pmd, address, end - address,
phys_addr + address, flags))
break;
error = 0;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
spin_unlock(&init_mm.page_table_lock);
flush_tlb_all();
return error;
}
其中的一些映射关系参考内存管理的分页管理
相关文章推荐
- 函数 ioremap 物理地址到内核映射空间的映射函数
- ioremap 函数映射操作已知的物理地址(寄存器、端口、IO)
- Unix v6中对虚拟地址映射到物理地址以及在内核态如何访问用户空间的u值
- 外设IO地址空间中的地址怎么转换到内核态的虚拟地址空间(一个ioremap函数真的解释清楚了么)
- 物理地址,虚拟地址,总线地址,i/o地址空间,内存地址空间,以及他们的映射关系
- 从MDL(把应用层的地址空间映射到系统内核空间)得到系统虚拟空间地址
- mmap将物理地址映射到用户空间
- Linux的内存管理主要分为两部分:物理地址到虚拟地址的映射,内核内存分配管理(主要基于slab)。
- 内核物理地址和虚拟地址之间的静态映射过程
- linux 内存映射 remap_pfn_range操作(内核地址映射到用户空间)
- cpu为什么使用虚拟地址到物理地址的空间映射,解决了什么样的问题?
- 通过mmap将连续物理地址映射到用户空间
- Linux下将物理地址映射到用户空间
- 内核虚拟地址转物理地址的函数
- Linux内核---62.用户空间获得变量的物理地址
- 内核态空间地址直接映射到用户态空间访问
- 内核态空间地址直接映射到用户态空间访问
- ioremap和iounmap -- 内核态地址映射
- Linux 内核空间地址映射 高端内存 总结
- 内核空间怎么访问物理地址