void __iomem *__ref
acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
的作用是将形参指定的物理地址的范围映射为虚拟地址。
其源码分析如下:
void __iomem *__ref
acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
{
struct acpi_ioremap *map;
void __iomem *virt;
acpi_physical_address pg_off;
acpi_size pg_sz;
#要映射的物理地址超过范围就直接报 error退出
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
return NULL;
}
#开来映射还分为临时映射和永久映射,这样一般都是永久映射
if (!acpi_permanent_mmap)
return __acpi_map_table((unsigned long)phys, size);
mutex_lock(&acpi_ioremap_lock);
/* Check if there's a suitable mapping already. */
#所有通过这个函数映射的物理地址都会在acpi_ioremaps 这个链表中,这些会先检查这个物理
#地址是否已经被映射过了,如果已经被映射过了,就不会重复映射,增加refcount 即可,这里也可以看出同一个物理地址是可以被重复映射的
map = acpi_map_lookup(phys, size);
if (map) {
map->refcount++;
goto out;
}
#走到这里说明这个地址没有被映射过,这里申请一个struct acpi_ioremap *map #用于保存映射的结果
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map) {
mutex_unlock(&acpi_ioremap_lock);
return NULL;
}
#转换要映射的地址和范围
pg_off = round_down(phys, PAGE_SIZE);
pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
#调用acpi_map 映射后得到虚拟地址virt
virt = acpi_map(pg_off, pg_sz);
if (!virt) {
mutex_unlock(&acpi_ioremap_lock);
kfree(map);
return NULL;
}
#将映射后的虚拟地址和映射前的物理地址保存在map中
INIT_LIST_HEAD(&map->list);
map->virt = virt;
map->phys = pg_off;
map->size = pg_sz;
map->refcount = 1;
#所有的映射结果也就是物理地址和虚拟地址的对应关系都保存在acpi_ioremaps
list_add_tail_rcu(&map->list, &acpi_ioremaps);
out:
mutex_unlock(&acpi_ioremap_lock);
return map->virt + (phys - map->phys);
}
内核ACPI函数API之acpi_os_map_iomem
最新推荐文章于 2024-08-27 22:47:34 发布