arm64内存-early_ioremap

1、初始化

arch/arm64/kernel/setup.c( setup_arch )-> arch/arm64/mm/ioremap.c( early_ioremap_init ) -> mm/early_ioremap.c ( early_ioremap_setup )

early_ioremap_init

直接调用了 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}

early_ioremap_setup

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}

使用方法

建立映射 - early_ioremap(phys_addr, size) & early_memremap(phys_addr, size )

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}

 

取消映射 early_iounmap(void * addr, size )

这个比较简单,根据addr 这个VA ,查找 prev_map 数组,找到相等的,取idx 作为slot 。

根据size 计算 nrpages

循环 取消 每一页的映射。

 

posted @ 2022-03-26 18:24  张志伟122  阅读(260)  评论(0编辑  收藏  举报