diff --git a/articles/20220410-riscv-sparsemem.md b/articles/20220410-riscv-sparsemem.md index ba839f473e5040c738a09ecaf25f685e9941a09b..faf39f0ed8ac535449725559610fafb63650528e 100644 --- a/articles/20220410-riscv-sparsemem.md +++ b/articles/20220410-riscv-sparsemem.md @@ -1,3 +1,4 @@ +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.1-rc2 - [comments codeinline images urls pangu]
> Author: Jack Y.
> Date: 2022/04/10
> Revisor: Falcon
@@ -12,7 +13,7 @@ 学习过操作系统课程的同学都知道,Linux 把 RAM 空间分成大小相同的页帧(Page Frame),Page Frame 是 Linux 内存管理的基本单位,在大多数情况下一般把一页的大小配置为 4 KB。每个页帧对应着一个「页帧号」(Page Frame Number,简称 PFN)。只要得知该页帧的 PFN,就能得知该页帧的物理地址,即可在硬件 RAM 上对这个地址对应的内存空间进行访问。 -而为了对一个页帧进行管理,Linux 设计了 `struct page` 这个结构体,该结构体中包括了该页的状态标志位、映射的地址空间、引用计数等内容,具体可参考[这篇文章](http://linux.laoqinren.net/kernel/memory-page/)。 +而为了对一个页帧进行管理,Linux 设计了 `struct page` 这个结构体,该结构体中包括了该页的状态标志位、映射的地址空间、引用计数等内容,具体可参考[这篇文章][001]。 物理内存的每一个页帧,都有一个对应的 `struct page` 结构体,而如何将这些结构体进行有效地组织和管理,就是 Linux 物理内存模型。更加通俗的来说,物理内存模型主要的作用是完成 PFN 和 `struct page` 之间的相互查找,即 `pfn_to_page()` 和 `page_to_pfn()`。 @@ -31,7 +32,7 @@ Linux 最早采用的是简单直接的 FLATMEM 模型,从名字可以看出 从 PFN 到 `struct page` 的地址,只需在 `struct page` 数组的基地址 `mem_map` 的基础上,加上 PFN(再减去体系结构定义的偏移量 `ARCH_PFN_OFFSET`,以适配不从 0x0 地址开始的物理空间)即可;而从 `struct page` 的地址到 PFN 也仅仅是把上述公式进行一下移项变换而已。FLATMEM 模型的 `struct page` 结构如下图所示: -![](images/riscv_sparsemem/FLATMEM.png) +![FLATMEM.png](images/riscv_sparsemem/FLATMEM.png) FLATMEM 模型的优点是结构简单,而且 `pfn_to_page()` 和 `page_to_pfn()` 只需进行两次加减法运算,十分高效。 @@ -49,7 +50,7 @@ SPARSEMEM 模型在当时被称为「一个新的、实验性的 DISCONTIGMEM 在 SPARSEMEM 模型中,设计了一个比 page 更大的内存管理粒度「mem_section」。 -一个 `mem_section` 所对应的内存大小由宏 `SECTION_SIZE_BITS` 定义。在 RISC-V 中,其被定义为 27(见arch/riscv/include/asm/sparsemem.h),即一个 `mem_section` 对应 $2^{27} = 128 $ MB 物理内存。 +一个 `mem_section` 所对应的内存大小由宏 `SECTION_SIZE_BITS` 定义。在 RISC-V 中,其被定义为 27(见 arch/riscv/include/asm/sparsemem.h),即一个 `mem_section` 对应 $2^{27} = 128 $ MB 物理内存。 而 SPARSEMEM 的总共数量则由宏 `NR_MEM_SECTIONS` 来定义,后者的定义整理如下: @@ -84,9 +85,9 @@ struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT] ____cacheline_internodealigned_in_smp; ``` -由于在经典 SPARSEMEM 模型中, `SECTIONS_PER_ROOT` 被定义为 1,`mem_section` 二维数组实际上就是长度为 `NR_MEM_SECTIONS` 的一维数组。经典 SPARSEMEM 模型中 `struct mem_section` 的组织结构如下: +由于在经典 SPARSEMEM 模型中,`SECTIONS_PER_ROOT` 被定义为 1,`mem_section` 二维数组实际上就是长度为 `NR_MEM_SECTIONS` 的一维数组。经典 SPARSEMEM 模型中 `struct mem_section` 的组织结构如下: -![](images/riscv_sparsemem/classic_sparsemem.png) +![classic_sparsemem.png](images/riscv_sparsemem/classic_sparsemem.png) 每一个 `struct mem_section` 都有一个编号,叫做 `section_nr`,定义方式为物理地址右移 `PA_SECTION_SHIFT` 位,可以轻易理解的是,`PA_SECTION_SHIFT` 的值就等于 `SECTION_SIZE_BITS`。 @@ -200,7 +201,7 @@ SPARSEMEM 模型设计了 `struct mem_section` 这样一个层级,将 FLATMEM 但经典 SPARSEMEM 模型仍有两大问题: 1. 经典 SPARSEMEM 模型的 `mem_section` 数组是固定分配的,在 RV32 架构下,共 128 个,这样的开销还可以接受;但在 RV64 架构下,其数量达到 $2^{29} = 536,870,912$ 个,实在是浪费空间十分严重。 -2. 尽管已经做了非常「巧妙」的编码,经典 SPARSEMEM 模型的 `pfn_to_page()` 和 `page_to_pfn()` 与 FLATMEM相比,仍然较为复杂。就 `pfn_to_page()` 来说,前者需要 2 次加法操作、1 次移位操作、1 次按位与操作和 1 次内存读取操作;而后者只需 1 次加法操作和 1 次减法操作即可。 +2. 尽管已经做了非常「巧妙」的编码,经典 SPARSEMEM 模型的 `pfn_to_page()` 和 `page_to_pfn()` 与 FLATMEM 相比,仍然较为复杂。就 `pfn_to_page()` 来说,前者需要 2 次加法操作、1 次移位操作、1 次按位与操作和 1 次内存读取操作;而后者只需 1 次加法操作和 1 次减法操作即可。 因此后续又增加了 SPARSEMEM 模型的两个扩展版本:SPARSEMEM_EXTREME 和 SPARSEMEM_VMEMMAP。 @@ -290,7 +291,7 @@ static int __meminit sparse_index_init(unsigned long section_nr, int nid) 下图是 SPARSEMEM_EXTREME 扩展的 `struct mem_section` 组织结构,在图中下标为 $1$ 的 MEM_SECTION_ROOT 中无任何物理内存与其对应,即可不分配相应的 `struct mem_section` 结构体。 -![](images/riscv_sparsemem/SPARSEMEM_EXTREME.png) +![SPARSEMEM_EXTREME.png](images/riscv_sparsemem/SPARSEMEM_EXTREME.png) ## SPARSEMEM_VMEMMAP 扩展 @@ -339,6 +340,11 @@ SPARSEMEM_VMEMMAP 扩展是为了解决上文中提到的经典 SPARSEMEM 模型 ## 参考文档 -1.[Memory: the flat, the discontiguous, and the sparse](https://lwn.net/Articles/789304/) -2.[从 pfn_to_page/page_to_pfn 看 Linux SPARSEMEM 内存模型](https://www.cnblogs.com/liuhailong0112/p/14515466.html) -3.[Remove DISCINTIGMEM memory model](https://lwn.net/Articles/858333/) \ No newline at end of file +1. [Memory: the flat, the discontiguous, and the sparse][002] +2. [从 pfn_to_page/page_to_pfn 看 Linux SPARSEMEM 内存模型][004] +3. [Remove DISCINTIGMEM memory model][003] + +[001]: http://linux.laoqinren.net/kernel/memory-page/ +[002]: https://lwn.net/Articles/789304/ +[003]: https://lwn.net/Articles/858333/ +[004]: https://www.cnblogs.com/liuhailong0112/p/14515466.html