内核对象与 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
,负责内存分配的capabilities
。seL4
不支持动态内存分配,在内核加载阶段将所有的空闲内存绑定到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
中存的是控制 TCB
的 capability
。
每个 Slot
有两种状态:
empty
:没有存capability
。full
:存了capability
。
出于习惯,0号 Slot
一直为 empty
。
一个 CNode
有 1 << CNodeSizeBits
个 Slot
,一个 Slot
占 1 << seL4_SlotBits
字节。
CSpaces #
CSpace
是一个 线程
的能力空间,包含一个或多个CNode
,构造出一个能力空间的树形结构。
CSpace的寻址方式有两种:
- Invocation
- Direct CSpace addressing
Invocation Addressing #
每个线程有在 TCB
中装载了一个特殊的 CNode
作为它 CSpace
的 root
。这个 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 memory
的 capability
传递给 root task
。
Untyped memory
是一块特定大小的连续物理内存块,而 untyped capabilities
则是 untyped memory
的 capability
。 untyped capabilities
可以被 retyped
。
untyped capabilities
有一个 bool
的属性,指明对应的内存对象是否可以被内核写:内存对象可能不是 RAM
而是其他 Device
,或者它可能位于内核无法寻址到的 RAM
区域。
只要untyped capability
对应的memory大小允许,memory可以被拆分成许多新的object
。使用seL4_Untyped_Retype
函数对untyped capability
进行创建新的capability
(同时也是会对应的untyped object
进行retype
)。新的capability
是原来untyped capability
的children
,children
按顺序获得有效内存,且内存是对齐的。例如,创建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对象中生成一个新的内核对象。