4.1 seL4-Mapping讲解

400 阅读3分钟

Mapping

这一节是关于seL4虚拟内存管理的讲解。

预备知识

在此之前需要学过capability课程。

成果

学完本课程,会有以下收获:

  • 如何在seL4中map和unmap虚拟内存页

背景

虚拟内存

seL4在内核提供的原始的操作硬件页表的结构之上,不提供虚拟内存的管理。用户层必须提供一个服务,用来创建中间页表结构,映射和取消映射页表。 用户可以自由定义自己的地址空间布局,但是有一个限制:seL4占用内存范围较高的部分。在大多数32位的平台上,这个值是0xe0000000及以上。这个值在不同的平台上是不同的,可以在seL4的源码中找到kernelBase

页表结构

作为启动进程的一部分,seL4使用一个顶层的硬件虚拟内存对象初始化root task,被称为VSpace。这个结构体的capability在root task的CSpace的seL4_CapInitThreadVSpaceslot中。对于每种架构,这个capability对应的是一个与硬件相关的不同的对象。下面的表中列举了对于支持的架构中的VSpace对象。

ArchitectureVSpace Object
aarch32seL4_PageDirectory
aarch64seL4_PageGlobalDirectory
ia32seL4_PageDirectory
x86_64seL4_PML4
RISC-VseL4_PageTable

除了顶层的页面结构之外,还需要一个中间硬件虚拟内存对象来映射页面。下面的表中列举了这些对象(仍然是不同的架构不同的对象)

ArchitectureObjects
aarch32seL4_PageTable
aarch64seL4_PageUpperDirectoryseL4_PageDirectoryseL4_PageTable
ia32seL4_PageTable
x86_64seL4_PDPTseL4_PageDirectoryseL4_PageTable
RISC-VseL4_PageTable

这个教程以x86_64架构为例,但是应该可以覆盖seL4中虚拟内存API的所有信息,可以推广到其他的架构上。

每个页面结构都可以被调用来映射和取消映射。下面就是一个映射x86_64 seL4_PDPT对象的例子:

 /* map a PDPT at TEST_VADDR */
    error = seL4_X86_PDPT_Map(pdpt, seL4_CapInitThreadVSpace, TEST_VADDR, seL4_X86_Default_VMAttributes);

所有的映射函数都需要3个参数:

  • 要把对象映射到的CSpace
  • 要把对象映射到的虚拟地址
  • 虚拟内存属性

如果提供的虚拟内存地址没有与分页对象的大小对齐,seL4会遮盖所有没用的部分。举个例子,一个4k的分页要映射到0xDEADBEEF,seL4最终会让他映射到0xDEADB000。后面那部分就不要了。 虚拟内存的属性决定了映射缓存的属性,这也是与架构相关的。除了本教程使用的属性seL4_X86_Default_VMAttributes,其他属性可以在libsel4中找到。

页表

一旦特定范围的虚拟内存都映射到了中级页表结构体上,物理帧可以通过调用frame capability映射到这个范围。下面的代码片段展示了如何把一个frame映射到地址TEST——VADDR

    /* map a read-only page at TEST_VADDR */
    error = seL4_X86_Page_Map(frame, seL4_CapInitThreadVSpace, TEST_VADDR, seL4_CanRead, seL4_X86_Default_VMAttributes);

要使得页面映射成功,所有的中级分页都必须被映射。libsel4的seL4_MappingFailedLookupLevel()可以用于检测哪个等级的页表结构有缺失。需要注意的是,如果对一个frame多次映射,必须同时复制他的frame capability:每个capability只能跟踪一个映射。 除了映射相关的参数外,映射函数还接受一个额外的权限参数。在上面的例子中,把映射的也权限设定为只读。

下一篇学习map的练习部分。