linux iotable_init 静态映射与内核页表的建立

40 篇文章 2 订阅

arm32 linux3.18 mach-vexpress

常用的ioremap或者of_iomap都是动态映射,静态映射的接口是iotable_init

void __init iotable_init(struct map_desc *io_desc, int nr)
struct map_desc {
	unsigned long virtual;
	unsigned long pfn;
	unsigned long length;
	unsigned int type;
};

如map_desc所示通过实例化这个结构体我们可以创建对某个物理地址的固定的虚拟地址映射

iotable_init 一般是在machine desc 的map_io的call函数里具体的call stack如下

start_kernel-->setup_arch-->paging_init-->devicemaps_init-->mdesc->map_io()

iotable_init会调用函数create_mapping来创建内核页表和映射关系,不只是iotable_init 包括内核页表的创建都是通过该函数

盗一张3+1的32bit linux 的memeory layout 对比kernel启动过程中的LOG帮助后面理解

log 出自 start_kernel-->mm_init-->mem_init

/*
 * Create the page directory entries and any necessary
 * page tables for the mapping specified by `md'.  We
 * are able to cope here with varying sizes and address
 * offsets, and we take full advantage of sections and
 * supersections.
 */
static void __init create_mapping(struct map_desc *md)
{
	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
		pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n",
			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
		return;
	}
//vectors_base是中断向量表的位置0xffff0000  TASK_SIZE是userspace的空间大小为0x7f000000 
//iotable_init 是从vmalloc区域拿地址空间,或者说low memory区,所以先判断所申请的虚拟地址是否在此范围内
	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
	    md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
		pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
	}
//PAGE_OFFSET是kernel space虚拟地址的起始0x80000000 是2+2的memory分布,跟TASK_SIZE gap 了16M
//FIXADDR_START 是kernel space的永久映射区 0xffc00000
//vmalloc_start 0xa0800000 vmaloc_end 0xff000000 大概1.5G 
//vmalloc区域大小也会有boot cmdline vmalloc=  决定
	
	type = &mem_types[md->type];

	addr = md->virtual & PAGE_MASK;
//分配的地址以page为offset
	phys = __pfn_to_phys(md->pfn);
//从页框号获得要映射的物理地址
	length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
//分配的size也是以page为offset
	if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
		printk(KERN_WARNING "BUG: map for 0x%08llx at 0x%08lx can not "
		       "be mapped using pages, ignoring.\n",
		       (long long)__pfn_to_phys(md->pfn), addr);
		return;
	}

	pgd = pgd_offset_k(addr);
//根据虚拟地址去查询kernel页表swapper_pg_dir找到对应的pgd(虚拟地址在text段的前0x4000,16k)
	end = addr + length;
	do {
		unsigned long next = pgd_addr_end(addr, end);

		alloc_init_pud(pgd, addr, next, phys, type);

		phys += next - addr;
		addr = next;
	} while (pgd++, addr != end);
}
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr)	pgd_offset(&init_mm, addr)
#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
/* to find an entry in a page-table-directory */
#define pgd_index(addr)		((addr) >> PGDIR_SHIFT)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shenhuxi_yu

感谢投币,继续输出

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值