arm64内存-arm64_memblock_init

请先了解:

1、线性空间下移:https://www.cnblogs.com/zhangzhiwei122/p/16058173.html

2、整体流程:https://www.cnblogs.com/zhangzhiwei122/p/16085238.html

 

5.10 版本,linux/arch/arm64/mm/init.c

 

总体来讲,就是根据dtb,命令行参数,内核配置来  添加、删除  memblock 中的记录信息。这个搞完之后,memblock 中就记录了设备的物理内存 拥有、使用、空闲情况。

 

272,vabits_actual 实际使用的VA bits ,假设为 48, 则 线性空间 为  ffff000000000000 ffff7fffffffffff ,大小为  800000000000

275 解析 chosen 节点下面的 linux.usable-memory-range 属性

参考 Documentation/devicetree/bindings/chosen.txt 文档,

e.g.

/ {
    chosen {
        linux,usable-memory-range = <0x9 0xf0000000 0x0 0x10000000>;
    };
};

对这段地址空间,调用 memblock_cap_memory_range ( base, size ) 进行处理。设置  capacity ?

 

 270void __init arm64_memblock_init(void)
 271{
 272        const s64 linear_region_size = BIT(vabits_actual - 1);
 273
 274        /* Handle linux,usable-memory-range property */
 275        fdt_enforce_memory_region();
 276
 277        /* Remove memory above our supported physical address size */
 278        memblock_remove(1ULL << PHYS_MASK_SHIFT, ULLONG_MAX);
 279
 280        /*
 281         * Select a suitable value for the base of physical memory.
 282         */
 283        memstart_addr = round_down(memblock_start_of_DRAM(),
 284                                   ARM64_MEMSTART_ALIGN);
 285
 286        /*
 287         * Remove the memory that we will not be able to cover with the
 288         * linear mapping. Take care not to clip the kernel which may be
 289         * high in memory.
 290         */
 291        memblock_remove(max_t(u64, memstart_addr + linear_region_size,
 292                        __pa_symbol(_end)), ULLONG_MAX);
 293        if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) {
 294                /* ensure that memstart_addr remains sufficiently aligned */
 295                memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size,
 296                                         ARM64_MEMSTART_ALIGN);
 297                memblock_remove(0, memstart_addr);
 298        }
 299
 300        /*
 301         * If we are running with a 52-bit kernel VA config on a system that
 302         * does not support it, we have to place the available physical
 303         * memory in the 48-bit addressable part of the linear region, i.e.,
 304         * we have to move it upward. Since memstart_addr represents the
 305         * physical address of PAGE_OFFSET, we have to *subtract* from it.
 306         */
 307        if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52))
 308                memstart_addr -= _PAGE_OFFSET(48) - _PAGE_OFFSET(52);
 309
 310        /*
 311         * Apply the memory limit if it was set. Since the kernel may be loaded
 312         * high up in memory, add back the kernel region that must be accessible
 313         * via the linear mapping.
 314         */
 315        if (memory_limit != PHYS_ADDR_MAX) {
 316                memblock_mem_limit_remove_map(memory_limit);
 317                memblock_add(__pa_symbol(_text), (u64)(_end - _text));
 318        }
 319
 320        if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size) {
 321                /*
 322                 * Add back the memory we just removed if it results in the
 323                 * initrd to become inaccessible via the linear mapping.
 324                 * Otherwise, this is a no-op
 325                 */
 326                u64 base = phys_initrd_start & PAGE_MASK;
 327                u64 size = PAGE_ALIGN(phys_initrd_start + phys_initrd_size) - base;
 328
 329                /*
 330                 * We can only add back the initrd memory if we don't end up
 331                 * with more memory than we can address via the linear mapping.
 332                 * It is up to the bootloader to position the kernel and the
 333                 * initrd reasonably close to each other (i.e., within 32 GB of
 334                 * each other) so that all granule/#levels combinations can
 335                 * always access both.
 336                 */
 337                if (WARN(base < memblock_start_of_DRAM() ||
 338                         base + size > memblock_start_of_DRAM() +
 339                                       linear_region_size,
 340                        "initrd not fully accessible via the linear mapping -- please check your bootloader ...\n")) {
 341                        phys_initrd_size = 0;
 342                } else {
 343                        memblock_remove(base, size); /* clear MEMBLOCK_ flags */
 344                        memblock_add(base, size);
 345                        memblock_reserve(base, size);
 346                }
 347        }
 348
 349        if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
 350                extern u16 memstart_offset_seed;
 351                u64 range = linear_region_size -
 352                            (memblock_end_of_DRAM() - memblock_start_of_DRAM());
 353
 354                /*
 355                 * If the size of the linear region exceeds, by a sufficient
 356                 * margin, the size of the region that the available physical
 357                 * memory spans, randomize the linear region as well.
 358                 */
 359                if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) {
 360                        range /= ARM64_MEMSTART_ALIGN;
 361                        memstart_addr -= ARM64_MEMSTART_ALIGN *
 362                                         ((range * memstart_offset_seed) >> 16);
 363                }
 364        }
 365
 366        /*
 367         * Register the kernel text, kernel data, initrd, and initial
 368         * pagetables with memblock.
 369         */
 370        memblock_reserve(__pa_symbol(_text), _end - _text);
 371        if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size) {
 372                /* the generic initrd code expects virtual addresses */
 373                initrd_start = __phys_to_virt(phys_initrd_start);
 374                initrd_end = initrd_start + phys_initrd_size;
 375        }
 376
 377        early_init_fdt_scan_reserved_mem();
 378
 379        if (IS_ENABLED(CONFIG_ZONE_DMA)) {
 380                zone_dma_bits = ARM64_ZONE_DMA_BITS;
 381                arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS);
 382        }
 383
 384        if (IS_ENABLED(CONFIG_ZONE_DMA32))
 385                arm64_dma32_phys_limit = max_zone_phys(32);
 386        else
 387                arm64_dma32_phys_limit = PHYS_MASK + 1;
 388
 389        reserve_crashkernel();
 390
 391        reserve_elfcorehdr();
 392
 393        high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
 394
 395        dma_contiguous_reserve(arm64_dma32_phys_limit);
 396}
 397

278 删除支持的 物理地址以上的区域,假设 支持物理地址 48 bits ,则  物理地址 0000 0000 0000 0000 ~  0000 ffff ffff ffff 。 0000 ffff ffff ffff 以上的物理地址都不可访问。memblock 中不必存在。

283 行,取memblock 中 memory 类型的 regions[0].base 地址。在这个之前,内存段  已经使用 memblock_add 加入到了 memblock 中。 memstart_addr 表示物理内存地址 起始值。

    以这个起始值,线性映射区域结尾 为  memstart_addr + linear_region_size 。如果 _end 值大于这个值, 则 线性区域 需要继续向后延伸到 _end 值。

291 行 - 线性映射区域  对应 物理内存  之后的,memblock 也不关心【因为memblock 只负责 内核启动过程   内存管理, 只给内核功能模块分配内存,内核分配的内存也只在线性映射区域。】  给 remove 掉。

 

293 行,这时再取 memblock end of DRAM , 因为 291 行,已经将 高于 线性映射区域的 remove 调了,所以,只可能取得到 _end  或者 memstart_addr + linear_region_size , 如果是 _end 地址,进入 294 行处理

        保证 memstart_addr + linear region size >=  _end .

 

301 ~ 308 行,配置VA 地址 52 bits,但是 设备不支持时的处理。暂时略。

 

309 ~ 319 行,如果命令和参数设置了  mem=xx 参数,限定了 使用内存大小,memory_limit 值为 设置的值。删除这个值之后的。但是,有可能把 内核镜像 装载的部分页删除了,所以再 加回来。

 

320 ~ 348,如果配置了 CONFIG_BLK_DEV_INITRD ,并且加载了 initrd 文件,则保留 initrd 文件占据部分的内存。

 

349 ~ 364 暂时略,randomize base 相关。

 

370 reserve  内核镜像 占据部分

 

371 ~ 375 处理 initrd 文件,设置变量 initrd_start   initrd_end

 

377 处理 dtb 中 reserve memory 节点

 

379 ~ 387 处理 arm64_dma_phys_limit

 182static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
 183{
 184        phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits);
 185        return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM());
 186}

max zone phys  - Return the maximum physical address for a zone with a given address size limit.

输入参数 为 bits , 返回值为  最大物理地址。

举例: 内存起始地址, memblock start of DRAM  0x0000 0000 1000 0000 , 给定  zone-bits 为 6 。则返回值为 0x0000 0000 1000 0400 即 6 bits 在 一个 zone ,它从 0x0000 0000 1000 0000 0x0000 0000 1000 0400

GENMASK_ULL(63, zone_bits) ; 生成一个 unsigned long long 类型的数值。 【zone_bits ~ 63) 之间的bit 被设置 为 1 。示例:GENMASK(10, 8): 0x700 。

将 start of DRAM 和 mask 进行与操作,起始地址中,小于 zone_bits 的bit 位 清零。高于 zone_bits 的bit 位保留,相当于 offset 记录了 起始地址所在的 台阶。

185 行,取min ,防止计算出来的 地址,超过 end of DRAM 物理地址。

 

389   391  调用同文件中的 static 函数,进行 reserve memory

 

393 计算high_mem 值

 

395 调用 kernel/dma/contiguous.c 中的函数,处理命令行,或者内核配置 的 cma 预留区域。

 

posted @ 2022-04-01 14:05  张志伟122  阅读(809)  评论(0编辑  收藏  举报