1. Kernel Object & Capabiltiy

内核对象与 Capability机制 #

ReL4继承了seL4对内核对象的定义和管理,提供了7种基本的内核对象:

  • 线程(Thread):内核调度的基本单位,保存了用户态运行的上下文寄存器。
  • 能力空间(CNode):权限控制负责,维护了各个内核对象的能力对象和对应权限。
  • 内存页(Frame):可访问的物理内存块。
  • VSpace(PageTable):地址空间,维护了
  • 端点(Endpoint):同步IPC的桥梁,维护了一个消息收发的状态机以及对应的阻塞队列。
  • 通知对象(Notification):异步通知机制的桥梁,维护了一个通知状态位。
  • 未初始化的内存对象(Untyped):通过系统调用转化为其他内核对象。

What’s a capability #

A capability is a unique, unforgeable token that gives the possessor permission to access an entity or object in system.

按照seL4文档定义,可以理解为 capability 是访问系统中一切实体或对象的令牌,这个令牌包含了某些访问权力,只有持有这个令牌,才能按照特定的方式访问系统中的某个对象。可以将 capability 视为一个拥有访问权限的指针,而在C语言中,指针常常可以共享,因此这里隐含着一层 capability 可以传递和分享的意思。

seL4 中将 capability 分做三种:

  • 内核对象(如 线程控制块)的访问控制的 capability
  • 抽象资源(如 IRQControl )的访问控制的 capability 。(中断控制块是干啥的,以后会提到)
  • untyped capabilities ,负责内存分配的 capabilitiesseL4 不支持动态内存分配,在内核加载阶段将所有的空闲内存绑定到 untyped capabilities 上,后续的内核对象申请新的内存,都通过系统调用和 untyped caability 来申请。 在 seL4 内核初始化时,指向内核控制资源的所有的 capability 全部被授权给特殊的任务 root task ,用户代码向修改某个资源的状态,必须使用 kernel API 在指定的 capability 上请求操作。

关于 Root Task,有几个概念上的疑惑问答,参考: About Root Task in seL4

CNodes and CSlots #

A CNode (capability-node) is an object full of capabilities: you can think of a CNode as an array of capabilities.

简单来说, CNode 也是一个对象,但这个对象存的是一个数组,数组里的元素是 capability 。数组中的各个位置我们称为 CSlots ,在上面的例子中, seL4_CapInitThreadTCB 实际上就是一个 CSlot ,这个 CSlot 中存的是控制 TCBcapability

每个 Slot 有两种状态:

  • empty:没有存 capability
  • full:存了 capability

出于习惯,0号 Slot 一直为 empty。 一个 CNode1 << CNodeSizeBitsSlot,一个 Slot1 << seL4_SlotBits 字节。

CSpaces #

CSpace 是一个 线程 的能力空间,包含一个或多个CNode,构造出一个能力空间的树形结构。 CSpace的寻址方式有两种:

  • Invocation
  • Direct CSpace addressing

Invocation Addressing #

每个线程有在 TCB 中装载了一个特殊的 CNode 作为它 CSpaceroot。这个 root 可以为空(代表这个线程没有被赋予任何 capability )。

Invocation 方式中,我们通过隐式地调用线程的 CSpace root 来寻址 CSlot 。例如:我们使用对 seL4_CapInitThreadTCB CSlot 的调用来读取和写入由该特定 CSlot 中的功能表示的 TCB 的寄存器。 这个模式会在 CSpace root 中隐式地查找 seL4_CapInitThreadTCB Slot

Direct CSpace addressing #

Invocation 默认在 CSpace root 中查找不同,你可以指定你要在哪个 CNode 中查找。这种操作主要用于构建和操作 CSpace 的形状(可能是另一个线程的 CSpace )。

Capability派生 #

capability可以通过若干系统调用(如Copy、Mint、retype等)进行能力派生,派生出来的新的cap作为原始cap的子节点插入能力派生树中。

能力派生树与CSpace是不同的概念。CSpace是一个线程中可以操作的内核对象的cap集合。而能力派生树则是以某一个cap(往往是untyped cap)为根节点,维护和管理系统中所有cap的生命周期的数据结构,由整个系统共享。

Untyped #

除了一小部分静态的内核内存,seL4 所有的物理内存都在用户态被管理。在启动时由 seL4 创建root task持有的内核对象的 capability ,以及由 seL4 管理的其他的物理资源,在启动后都会传递给 root task。除了用于创建 root task 的对象之外,所有可用的物理内存的 capability 都作为 untyped memorycapability 传递给 root task

Untyped memory 是一块特定大小的连续物理内存块,而 untyped capabilities 则是 untyped memorycapabilityuntyped capabilities 可以被 retyped

untyped capabilities 有一个 bool 的属性,指明对应的内存对象是否可以被内核写:内存对象可能不是 RAM 而是其他 Device,或者它可能位于内核无法寻址到的 RAM 区域。

只要untyped capability对应的memory大小允许,memory可以被拆分成许多新的object。使用seL4_Untyped_Retype函数对untyped capability进行创建新的capability(同时也是会对应的untyped object进行retype)。新的capability是原来untyped capabilitychildrenchildren按顺序获得有效内存,且内存是对齐的。例如,创建4k object以后创建16k object,这样有12k就被浪费了。

Interface #

  • seL4_CNode_Copy:复制cap,同时设置其访问权限。
  • seL4_CNode_Delete:删除一个cap。
  • seL4_CNode_Mint:复制cap,同时设置权限及徽章(badge)。
  • seL4_CNode_Move:移动一个cap。
  • seL4_CNode_Revoke:删除所有派生出去的cap。
  • seL4_Untyped_Retype:从untyped对象中生成一个新的内核对象。