Lazy loaded image[转载]ARM64 内存管理四:setup_arch 简介 (内存管理初始化)
2023-8-22
| 2023-10-17
字数 3647阅读时长 10 分钟
type
status
date
slug
summary
tags
category
icon
password
URL
linux 内存管理主要分 3 个阶段:
  • MMU 未打开,还在汇编时代时;
  • fixmap, memblock 时代,此时伙伴系统还未成形,一直到 mm_init() 函数中 mem_ini() 将空闲内存加载到 zone 中;
  • 伙伴系统建立

start_kernel

start_kernel中和内存管理相关的系统初始化函数主要如下:
—->setup_arch: 体系机构的设置函数,还负责初始化自举分配器
—->setup_per_cpu_areas: 定义 per-cpu 变量, 为各个 cpu 分别创建一份这些变量副本
—->build_all_zonelists: 建立节点 (node) 和内存域 (zone) 的数据结构
—->mem_init: 停用 bootmem 分配器并迁移到实际的内存管理函数
—->kmem_cache_init: 初始化内核内部用于小块内存区的分配器
—->setup_per_cpu_pageset: 为各个 cpu 的 zone 的 pageset 数组的第一个数组元素分配内存

setup_arch

setup_arch
—->machine_specific_memory_setup: 创建一个列表,包括系统占据的内存区和空闲内存区
—->parse_early_param: 解析 dtb 树命令行
—->setup_memory: 确定每个节点可用的物理内存也数目,初始化 bootmem 分配器,分配各种内存区
—->paging_init: 初始化内核页表并启动内存分页
---->pagetable_init: 确保直接映射到内核地址空间的物理内存被初始化
—->zone_size_init: 初始化系统中所有节点的 pgdat_t 实例
---->add_active_range: 对可用的物理内存建立一个相对简单的列表 ---->free_area_init_nodes: 建立完备的内核数据结构

本文主要内容

本篇主要介绍 memblock 建立过程及分页机制化,主要有如下几个步骤
  • setup_machine_fdt: 解析 dtb,收集内存信息及 bootargs
      1. hoosen node。该节点有一个 bootargs 属性,该属性定义了内核的启动参数,而在启动参数中,可能包括了 mem=nn[KMG] 这样的参数项。initrd-start 和 initrd-end 参数定义了 initial ramdisk image 的物理地址范围。
      1. memory node。这个节点主要定义了系统中的物理内存布局。主要的布局信息是通过 reg 属性来定义的,该属性定义了若干的起始地址和 size 条目。
      1. DTB header 中的 memreserve 域。对于 dts 而言,这个域是定义在 root node 之外的一行字符串,例如:/memreserve/ 0x05e00000 0x00100000。
      1. reserved-memory node。这个节点及其子节点定义了系统中保留的内存地址区域。保留内存有两种 (1. 静态定义,用 reg 属性定义的 address 和 size; 2. 动态定义,通过 size 属性定义了保留内存区域的长度,或者通过 alignment 属性定义对齐属性)
  • early_fixmap_init: 对保留的 fixmap 区域创建映射
  • early_ioremap_init: 初始化 early_ioremap 机制
  • arm64_memblock_init: 初始化 memblock 机制
  • paging_init: 初始化内核页表,内存节点,内存域及页帧 page, 此函数功能较为复杂
  • request_standard_resources:将 memblock.memory 挂载到 iomem_resource 资源树下
  • early_ioremap_reset: 结束 early_ioremap 机制
  • unflatten_device_tree: dtb 转换为 device_node tree
  • 根据 device node tree 初始化 CPU,psci

关键函数分析

setup_arch

arm64_memblock_init

setup_arch->arm64_memblock_init

early_init_fdt_scan_reserved_mem

在看 paging_init() 函数前,我们先看下目前的内存状态

目前所有的内存分为了 2 部分

  • OS 已经收集到的内存分布信息 (来自 dtb 解析),保存在 memblock 中,这部分又分为 3 个小部分
      1. 系统内存占据的空间,信息保存在 memblock.memory 中
      1. 已经使用或者保留使用的,信息保存在 memblock.reserve 中
      1. dtb 中 reserved-memory,但是有 No-map 属性,这种内存不属于 OS 管辖
  • OS 还未收集到的内存部分,暂未管辖 (这部分稍后会被加载到伙伴系统中)
在目前状态下,OS 还无法正常使用它们,因为 memblock 中定义的都是物理地址;而目前仅有两段内存是已经 mapping 过 (kernel image, fdt), 其余段都还是黑暗状态,接下来就要给第一部分内存做 mapping

paging_init

buddy 系统初始化

到目前为止,内核完成了如下工作

  • memblock 已经通过 arm64_memblock_init 完成了初始化, 至此系统中的内存可以通过 memblock 分配了
  • paging_init 完成了分页机制的初始化, 至此内核已经布局了一套完整的虚拟内存空间

稀疏内存管理将整个物理地址空间划分为 section

  • 对于 ARM64,一般支持 48bit 物理地址 (256T),section 为 1G 物理块,可以划分为 256K 个 seciton;
  • 每个在位的 section 在软件上抽象为一个 struct mem_section 结构体;
  • 对于每个 section 又可以分为若干 Pageblock,每个 pageblock 的状态由 4bit 来描述

bootmem_init

sparse_init

build_all_zonelists

build_all_zonelists->build_all_zonelists_init->__build_all_zonelists
 
参考资料:
  1. http://www.wowotech.net/memory_management/memory-layout.html
  1. http://www.wowotech.net/memory_management/mem_init_3.html
  1. memblock 结构体介绍
  1. bootmem_init 详细分析
  1. bootmem_init 详细分析 2
 
 
  • 内存管理
  • [转载]ARM64 内存管理三:MMU 前 CPU 初始化及打开 MMULinux物理内存管理三大结构体之struct zone
    Loading...