专栏首页linux驱动个人学习启动期间的内存管理之pagging_init初始化分页机制--Linux内存管理(十四)

启动期间的内存管理之pagging_init初始化分页机制--Linux内存管理(十四)

1 今日内容(分页机制初始化)

在初始化内存的结点和内存区域之前, 内核先通过pagging_init初始化了内核的分页机制.

在分页机制完成后, 才会开始初始化系统的内存数据结构(包括内存节点数据和内存区域), 并在随后初始化buddy伙伴系统来接管内存管理的工作

2 分页机制初始化

arm64架构下, 内核在start_kernel()->setup_arch()中通过arm64_memblock_init( )完成了memblock的初始化之后, 接着通过setup_arch()->paging_init()开始初始化分页机制

paging_init负责建立只能用于内核的页表, 用户空间是无法访问的. 这对管理普通应用程序和内核访问内存的方式,有深远的影响

2.1 虚拟地址空间(以x86_32位系统为例)

因此在仔细考察其实现之前,很重要的一点是解释该函数的目的

在x86_32系统上内核通常将总的4GB可用虚拟地址空间按3:1的比例划分给用户空间和内核空间, 虚拟地址空间的低端3GB

用于用户状态应用程序, 而高端的1GB则专用于内核. 尽管在分配内核的虚拟地址空间时, 当前系统上下文是不相干的, 但每个进程都有自身特定的地址空间.

这些划分主要的动机如下所示

  • 在用户应用程序的执行切换到核心态时(这总是会发生,例如在使用系统调用或发生周期性的时钟中断时),内核必须装载在一个可靠的环境中。因此有必要将地址空间的一部分分配给内核专用.
  • 物理内存页则映射到内核地址空间的起始处,以便内核直接访问,而无需复杂的页表操作.

如果所有物理内存页都映射到用户空间进程能访问的地址空间中, 如果在系统上有几个应用程序在运行, 将导致严重的安全问题. 每个应用程序都能够读取和修改其他进程在物理内存中的内存区. 显然必须不惜任何代价防止这种情况出现.

虽然用于用户层进程的虚拟地址部分随进程切换而改变,但是内核部分总是相同的

出于内存保护等一系列的考虑, 内核将整个进程的虚拟运行空间划分为内核虚拟运行空间和内核虚拟运行空间

按3:1的比例划分地址空间, 只是约略反映了内核中的情况,内核地址空间作为内核的常驻虚拟地址空间, 自身又分为各个段

地址空间的第一段用于将系统的所有物理内存页映射到内核的虚拟地址空间中。由于内核地址空间从偏移量0xC0000000开始,即经常提到的3 GiB,每个虚拟地址x都对应于物理地址x—0xC0000000,因此这是一个简单的线性平移。

直接映射区域从0xC0000000到high_memory地址,high_memory准确的数值稍后讨论。第1章提到过,这种方案有一问题。由于内核的虚拟地址空间只有1 GiB,最多只能映射1 GiB物理内存。IA-32系统(没有PAE)最大的内存配置可以达到4 GiB,引出的一个问题是,如何处理剩下的内存?

这里有个坏消息。如果物理内存超过896 MiB,则内核无法直接映射全部物理内存。该值甚至比此前提到的最大限制1 GiB还小,因为内核必须保留地址空间最后的128 MiB用于其他目的,我会稍后解释。将这128 MiB加上直接映射的896 MiB内存,则得到内核虚拟地址空间的总数为1 024 MiB = 1GiB。内核使用两个经常使用的缩写normal和highmem,来区分是否可以直接映射的页帧。

内核地址空间的最后128 MiB用于何种用途呢?如图3-15所示,该部分有3个用途。

  • 虚拟内存中连续、但物理内存中不连续的内存区,可以在vmalloc区域分配。该机制通常用于用户过程,内核自身会试图尽力避免非连续的物理地址。内核通常会成功,因为大部分大的内存块都在启动时分配给内核,那时内存的碎片尚不严重。但在已经运行了很长时间的系统上,在内核需要物理内存时,就可能出现可用空间不连续的情况。此类情况,主要出现在动态加载模块时
  • 持久映射用于将高端内存域中的非持久页映射到内核中
  • 固定映射是与物理地址空间中的固定页关联的虚拟地址空间项,但具体关联的页帧可以自由 选择。它与通过固定公式与物理内存关联的直接映射页相反,虚拟固定映射地址与物理内存位置之间 的关联可以自行定义,关联建立后内核总是会注意到的

同样我们的用户空间, 也被划分为几个段, 包括从高地址到低地址分别为 :

区域

存储内容

局部变量, 函数参数, 返回地址等

动态分配的内存

BSS段

未初始化或初值为0的全局变量和静态局部变量

数据段

一初始化且初值非0的全局变量和静态局部变量

代码段

可执行代码, 字符串面值, 只读变量

2.2 paging_init初始化分页机制

paging_init函数定义在arch/arm64/mm/mmu.c?v=4.7, line 538

/*
 * paging_init() sets up the page tables, initialises the zone memory
 * maps and sets up the zero page.
 */
void __init paging_init(void)
{
    phys_addr_t pgd_phys = early_pgtable_alloc();
    pgd_t *pgd = pgd_set_fixmap(pgd_phys);

    map_kernel(pgd);
    map_mem(pgd);

    /*
     * We want to reuse the original swapper_pg_dir so we don't have to
     * communicate the new address to non-coherent secondaries in
     * secondary_entry, and so cpu_switch_mm can generate the address with
     * adrp+add rather than a load from some global variable.
     *
     * To do this we need to go via a temporary pgd.
     */
    cpu_replace_ttbr1(__va(pgd_phys));
    memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
    cpu_replace_ttbr1(swapper_pg_dir);

    pgd_clear_fixmap();
    memblock_free(pgd_phys, PAGE_SIZE);

    /*
     * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
     * allocated with it.
     */
    memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE,
              SWAPPER_DIR_SIZE - PAGE_SIZE);
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux内核高端内存

    x86 CPU采用了段页式地址映射模型。进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存。

    233333
  • Linux内存描述之高端内存--Linux内存管理(五)

    过去,CPU的地址总线只有32位, 32的地址总线无论是从逻辑上还是从物理上都只能描述4G的地址空间(232=4Gbit),在物理上理论上最多拥有4G内存(除了...

    233333
  • linux 的swap、swappiness及kswapd原理【转】

    本文讨论的 swap基于Linux4.4内核代码 。Linux内存管理是一套非常复杂的系统,而swap只是其中一个很小的处理逻辑。

    233333
  • 445端口入侵详解

    一 摘要 二 什么是 ipc$ 三 什么是空会话 四 空会话可以做什么 五 ipc$ 所使用的端口 六 ipc 管道在 hack 攻击中的意义 七 ipc$ 连...

    魏晓蕾
  • Bitmap那些事之基础知识

    前言:本来我是做电视应用的,但是因为公司要出手机,人员紧张,所以就抽调我去支援一下,谁叫俺是雷锋呢! 我做的一个功能就是处理手机中的应用ICON,处理无非就是...

    程序员互动联盟
  • tf.math.pow或tf.pow

    于小勇
  • 无人驾驶汽车系统入门——基于Frenet优化轨迹的无人车动作规划方法

    基于 Frenet 坐标系的动作规划方法由于是由 BMW 的 Moritz Werling 提出的,为了简便,我们在后文中也会使用 Werling 方法简称。在...

    AI科技大本营
  • 【原创】机器学习从零开始系列连载(8)——机器学习中的统一框架

    很多机器学习问题都可以放在一个统一的框架下讨论,这样大家在理解各种模型时就是相互联系的。

    lujohn3li
  • 基于thrift的微服务框架

    前一阵开源过一个基于spring-boot的rest微服务框架,今天再来一篇基于thrift的微服务加框,thrift是啥就不多了,大家自行百度或参考我之前介绍...

    菩提树下的杨过
  • 基于thrift的微服务框架

    前一阵开源过一个基于spring-boot的rest微服务框架,今天再来一篇基于thrift的微服务加框,thrift是啥就不多了,大家自行百度或参考我之前介绍...

    菩提树下的杨过

扫码关注云+社区

领取腾讯云代金券