arch/arm64/kernel/setup.c( setup_arch )-> arch/arm64/mm/ioremap.c( early_ioremap_init ) -> mm/early_ioremap.c ( early_ioremap_setup )
直接调用了 early_ioremap_setup
95/* 96 * Must be called after early_fixmap_init 97 */ 98void __init early_ioremap_init(void) 99{ 100 early_ioremap_setup(); 101}
71 ~ 73 定义了三个数组,数组中存放的数据类型 指针, unsigned long , unsigned long; 名称 prev_map ; prev_size; slot_virt ; bss 段的静态数据,应该都被 设置为 0 。
slot_virt 记录 每个slot的起始虚拟地址,
prev_size 表示已经分配出去slot的size
prev_map 表示已经分配出去slot的地址
FIX_BTMAPS_SLOTS为 7 , 定义在 arch/arm64/include/asm/fixmap.h 中 https://www.cnblogs.com/zhangzhiwei122/p/16058671.html 中, enum fixed_addresses 的定义。
79 ~ 81 遍历 prev_map 数组,确保里面的值都是0,如果不是,就warn
83 ~ 84 遍历 填充 slot_virt 数组的值。使用 __fix_to_virt ,传入idx 得到 VA 地址。
i = 0时,传入FIX_BTMAP_BEGIN 是一个大值, __fix_to_virt 返回一个小地址,即 slot_virt[0] < slot_virt[1],且 每个slot_virt 之间相差 256K。 即 slot_virt[1] - slot_virt[0] = 256k
71static void __iomem *prev_map[FIX_BTMAPS_SLOTS] __initdata; 72static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata; 73static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata; 74 75void __init early_ioremap_setup(void) 76{ 77 int i; 78 79 for (i = 0; i < FIX_BTMAPS_SLOTS; i++) 80 if (WARN_ON(prev_map[i])) 81 break; 82 83 for (i = 0; i < FIX_BTMAPS_SLOTS; i++) 84 slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i); 85}
mm/early_ioremap.c
215/* Remap an IO device */ 216void __init __iomem * 217early_ioremap(resource_size_t phys_addr, unsigned long size) 218{ 219 return __early_ioremap(phys_addr, size, FIXMAP_PAGE_IO); 220} 221 222/* Remap memory */ 223void __init * 224early_memremap(resource_size_t phys_addr, unsigned long size) 225{ 226 pgprot_t prot = early_memremap_pgprot_adjust(phys_addr, size, 227 FIXMAP_PAGE_NORMAL); 228 229 return (__force void *)__early_ioremap(phys_addr, size, prot); 230}
都调用 __early_ioremap(phys_addr, size , flags) ,仅仅是flags 填充 FIXMAP_PAGE_NORMAL / FIXMAP_PAGE_IO 的差异。
首先,目的是: 给定物理地址 和 size ,映射出 VA 地址。
114 如果是在 RUNNING state时,使用了这个函数,就warning
117 ~ 122 遍历 prev_map 数组,找到里面内容为 0 的 一项,取 idx 到 slot 变量。 124 ~ 126 再对 slot 变量进行检查。
129 ~ 131 得到 并检查 结束物理地址 值 last_addr
133 记录 size 到 prev_size 数组,使用 slot 作 idx
137 计算 phys_addr 值,在 page 内的 offset , 映射都是 PAGE ALIGNED , 164 设置 prev_map [slot] 时使用,prev_map [slot] = VA + offset
138 ~ 139 计算 page aligned 物理起始地址和size
144 ~ 146 由size 得到需要的 page 个数,如果大于arch/arm64/include/asm/fixmap.h 中定义的 一个 slot 里面的page 个数,就报警告,返回null 退出。
151 由 slot 计算 fixmap 使用的 idx 值
152 ~ 160 循环调用 fixmap 模块里面的函数,映射 idx 指定的VA 地址和 phys_addr , 映射 nrpages 个页。
根据 变量 after_paging_init 的值,选择 调用 __early_set_fixmap 和 __late_set_fixmap
这两个都在arm64 fixmap 头文件 arch/arm64/include/asm/fixmap.h 设置。关于 __set_fixmap 见 https://www.cnblogs.com/zhangzhiwei122/p/16058671.html
100 101#define __early_set_fixmap __set_fixmap 102 103#define __late_set_fixmap __set_fixmap 104#define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
mm/early_ioremap.c
105static void __init __iomem * 106__early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot) 107{ 108 unsigned long offset; 109 resource_size_t last_addr; 110 unsigned int nrpages; 111 enum fixed_addresses idx; 112 int i, slot; 113 114 WARN_ON(system_state >= SYSTEM_RUNNING); 115 116 slot = -1; 117 for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { 118 if (!prev_map[i]) { 119 slot = i; 120 break; 121 } 122 } 123 124 if (WARN(slot < 0, "%s(%pa, %08lx) not found slot\n", 125 __func__, &phys_addr, size)) 126 return NULL; 127 128 /* Don't allow wraparound or zero size */ 129 last_addr = phys_addr + size - 1; 130 if (WARN_ON(!size || last_addr < phys_addr)) 131 return NULL; 132 133 prev_size[slot] = size; 134 /* 135 * Mappings have to be page-aligned 136 */ 137 offset = offset_in_page(phys_addr); 138 phys_addr &= PAGE_MASK; 139 size = PAGE_ALIGN(last_addr + 1) - phys_addr; 140 141 /* 142 * Mappings have to fit in the FIX_BTMAP area. 143 */ 144 nrpages = size >> PAGE_SHIFT; 145 if (WARN_ON(nrpages > NR_FIX_BTMAPS)) 146 return NULL; 147 148 /* 149 * Ok, go for it.. 150 */ 151 idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; 152 while (nrpages > 0) { 153 if (after_paging_init) 154 __late_set_fixmap(idx, phys_addr, prot); 155 else 156 __early_set_fixmap(idx, phys_addr, prot); 157 phys_addr += PAGE_SIZE; 158 --idx; 159 --nrpages; 160 } 161 WARN(early_ioremap_debug, "%s(%pa, %08lx) [%d] => %08lx + %08lx\n", 162 __func__, &phys_addr, size, slot, offset, slot_virt[slot]); 163 164 prev_map[slot] = (void __iomem *)(offset + slot_virt[slot]); 165 return prev_map[slot]; 166}
这个比较简单,根据addr 这个VA ,查找 prev_map 数组,找到相等的,取idx 作为slot 。
根据size 计算 nrpages
循环 取消 每一页的映射。