arm64内存-fixmap-宏定义和初始化

 

arch/arm64/include/asm/fixmap.h 中的定义

enum fixed_addresses

地址类型枚举,在 101 行的函数  __set_fixmap(idx, phys) 第一个参数用到。 将一个物理地址,映射到   idx 代表的 VA 地址上面。

  25/*
  26 * Here we define all the compile-time 'special' virtual
  27 * addresses. The point is to have a constant address at
  28 * compile time, but to set the physical address only
  29 * in the boot process.
  30 *
  31 * Each enum increment in these 'compile-time allocated'
  32 * memory buffers is page-sized. Use set_fixmap(idx,phys)
  33 * to associate physical memory with a fixmap index.
  34 */
  35enum fixed_addresses {
  36        FIX_HOLE,
  37
  38        /*
  39         * Reserve a virtual window for the FDT that is 2 MB larger than the
  40         * maximum supported size, and put it at the top of the fixmap region.
  41         * The additional space ensures that any FDT that does not exceed
  42         * MAX_FDT_SIZE can be mapped regardless of whether it crosses any
  43         * 2 MB alignment boundaries.
  44         *
  45         * Keep this at the top so it remains 2 MB aligned.
  46         */
  47#define FIX_FDT_SIZE            (MAX_FDT_SIZE + SZ_2M)
  48        FIX_FDT_END,
  49        FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
  50
  51        FIX_EARLYCON_MEM_BASE,
  52        FIX_TEXT_POKE0,
  53


69 __end_of_permanent_fixed_addresses, 70 71 /* 72 * Temporary boot-time mappings, used by early_ioremap(), 73 * before ioremap() is functional. 74 */ 75#define NR_FIX_BTMAPS (SZ_256K / PAGE_SIZE) 76#define FIX_BTMAPS_SLOTS 7 77#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) 78 79 FIX_BTMAP_END = __end_of_permanent_fixed_addresses, 80 FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, 81 82 /* 83 * Used for kernel page table creation, so unmapped memory may be used 84 * for tables. 85 */ 86 FIX_PTE, 87 FIX_PMD, 88 FIX_PUD, 89 FIX_PGD, 90 91 __end_of_fixed_addresses 92}; 93 94#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) 95#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)

 106extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);

 

94 行, FIXADDR_SIZE        枚举量的最大值 * 2 ^ PAGE_SHIFT ,这儿仅仅时 VA 地址空间上面的预留。

95 行,FIXADDR_START  为 FIXADDR_TOP - FIXADDR_SIZE,fixmap 起始 的 VA地址。仅仅是一个数值。

 

枚举值和 VA 地址关系,通过 include/asm-generic/fixmap.h 得到

 

给的x越大,返回的值 越小。当给定x为0时,返回 FIXADDR_TOP

 

  21#define __fix_to_virt(x)        (FIXADDR_TOP - ((x) << PAGE_SHIFT))
  22#define __virt_to_fix(x)        ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)

__set_fixmap(idx, phys,pgprot_t flags)

建立映射 -  idx 指定VA地址, phys 物理地址,flags 设置 属性 FIXMAP_PAGE_NORMAL /RO/NOCACHE/IO/CLEAR 

取消映射 - phys 填写 0, flags 填写  FIXMAP_PAGE_CLEAR (在  include/asm-generic/fixmap.h )

 

中使用到  __fix_to_virt (idx )  将 idx 转换为 v addr 。

结合 fixed_addresses 类型定义,得到  FIX_HOLE 这个enum 值 为 0,返回  FIXADDR_TOP 。 fixmap 可以访问的最大 VA地址。

FIX_FDT_END    enum 值为1,转换得到的 VA地址 值  为 fixaddr_top -1* 2 ^ page_shift。

FIX_FDT  ,enum 值若为 4, 则转换得到的 VA地址值 为  FIXADDR_TOP -  4* 2^PAGE_SHIFT

 

1243/*
1244 * Unusually, this is also called in IRQ context (ghes_iounmap_irq) so if we
1245 * ever need to use IPIs for TLB broadcasting, then we're in trouble here.
1246 */
1247void __set_fixmap(enum fixed_addresses idx,
1248                               phys_addr_t phys, pgprot_t flags)
1249{
1250        unsigned long addr = __fix_to_virt(idx);
1251        pte_t *ptep;
1252
1253        BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
1254
1255        ptep = fixmap_pte(addr);
1256
1257        if (pgprot_val(flags)) {
1258                set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
1259        } else {
1260                pte_clear(&init_mm, addr, ptep);
1261                flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
1262        }
1263}

 

1255 行,直接 取  VA 地址,对应的   PTE 描述项,是因为 一张 PTE 表里面,有 512个 项,__end_of_fixed_addresses 这个enum 值,不会大于 512,所以不需要修改 bm_pud 、bm_pmd 表。

 

1179static inline pte_t * fixmap_pte(unsigned long addr)
1180{
1181        return &bm_pte[pte_index(addr)];
1182}
1183

 

fixmap 初始化

arch/arm64/mm/mmu.c

bm_pte  /  bm_pmd  / bm_pud 数组定义

 

这样定义的数组在Image 文件的  .bss 段

  58
  59static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
  60static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
  61static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;

相同的   arch/arm64/mm/mmu.c  文件中,有出生后 这三个数组的函数。

1183
1184/*
1185 * The p*d_populate functions call virt_to_phys implicitly so they can't be used
1186 * directly on kernel symbols (bm_p*d). This function is called too early to use
1187 * lm_alias so __p*d_populate functions must be used to populate with the
1188 * physical address from __pa_symbol.
1189 */
1190void __init early_fixmap_init(void)
1191{
1192        pgd_t *pgdp;
1193        p4d_t *p4dp, p4d;
1194        pud_t *pudp;
1195        pmd_t *pmdp;
1196        unsigned long addr = FIXADDR_START;
1197
1198        pgdp = pgd_offset_k(addr);
1199        p4dp = p4d_offset(pgdp, addr);
1200        p4d = READ_ONCE(*p4dp);
1201        if (CONFIG_PGTABLE_LEVELS > 3 &&
1202            !(p4d_none(p4d) || p4d_page_paddr(p4d) == __pa_symbol(bm_pud))) {
1203                /*
1204                 * We only end up here if the kernel mapping and the fixmap
1205                 * share the top level pgd entry, which should only happen on
1206                 * 16k/4 levels configurations.
1207                 */
1208                BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
1209                pudp = pud_offset_kimg(p4dp, addr);
1210        } else {
1211                if (p4d_none(p4d))
1212                        __p4d_populate(p4dp, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
1213                pudp = fixmap_pud(addr);
1214        }
1215        if (pud_none(READ_ONCE(*pudp)))
1216                __pud_populate(pudp, __pa_symbol(bm_pmd), PMD_TYPE_TABLE);
1217        pmdp = fixmap_pmd(addr);
1218        __pmd_populate(pmdp, __pa_symbol(bm_pte), PMD_TYPE_TABLE);
1219
1241}
1242

 

1196 行,得到 FIXADDR_START 这个 VA 地址。

1198 行, pgd_offset_k (addr ) 得到 VA 地址的 pgd 描述项的地址。

1201 ~ 1209  , 的进入条件: page level 大于3级(那就是4级)&& pgd 描述项 不为空;  或者    page level 大于3级(那就是4级)&&  pgd 描述项 中填写的 phy addr 不是 bm_pud 的物理地址。

                         说明,fixmap 这段VA  和 kimage  这段 VA ,使用同一个 pgd 描述项。

             1208 行,对这种 情况进行了 补充检查,因为这种情况,只会发生在  16k/4 levels configurations. 这中配置下。所以,如果不是CONFIG_ARM64_16K_PAGES    就 BUG_ON 报错。

             使用同一个 PGD 描述项,这个描述项已经 在 head.S create_page 里面填充过了。取这个 PGD 指向的 pud 表是 kimage pud 表。所以使用 

             1209 行,使用 pud_offset_kimage  函数得到 v addr 的 pud 表描述项 指针 。 pud pointer.

 

1211 ~ 1213 , fixmap 这段 VA 和 kernel image 这段 VA,使用的不是 同一个 PGD 描述项,

       1211 1212  填写,pgd 描述项 的内容,让它指向  前面定义的 bm_pud 数组。

       1213  从 bm_pud 数组中,取出  v addr 对应的 pud 表的描述项 的指针。 pud pointer .

 

1215 ~ 1216 填写  pud 描述项内容,让它指向  bm_pmd 数组。

 

1217 ~ 1218 填写 pmd 描述项 内容。让它指向 bm_pte 数组。

 

1219 ~ 1240 之间检查内容,省略。

 

pmd 描述符指向 bm_pte 数组。 这个数组里面,可以放 512 个 item。 fixmap 只需要若干个,所以后面 __set_fixmap 中,只修改 bm_pte 表里面内容,不需要修改其他表内容。

 

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