seL4 Capabilities(翻自官网)(一)

news2024/11/14 13:59:48

官网教程链接: Capability

初始化Capabilities tutorials

// 先使用repo拉取一下tutorials,然后执行repo sync,所有的教程都在里面,学习某个的时候只需要改变的是 --tut 后面的参数
./init --tut capabilities
# building the tutorial exercise
cd capabilities_build
ninja

什么是Capability?

简单的讲是一个访问系统中实体或者对象的凭证(token),可以将其简单理解为是一个访问权限的指针,再seL4中有三种capabilities。

  • 控制访问内核对象的,例如TCB(thread control blocks)
  • 控制访问抽象资源的,例如IRQControl(Interrupt Requests, IRQ)
  • 未分类能力

seL4中,初始化时,由内核控制的资源的能力赋予给根任务。若用户代码想要改变任何资源的状态,则可以使用内核API,可在libsel4中请求对特定能力指向的资源进行操作。
举例而言,根任务初始化的时候会携带一个指向它自己线程控制块(TCB)的能力,也即是 seL4_CapInitThreadTCB,其是一个由libsel4定义的常量。若想改变初始TCB的属性,则可以在该能力上使用TCB API中的任何方法。
下面是一个更改根任务TCB栈指针的例子,如果需要一个更大的栈则需要以下的操作:

// 这两行不懂,先扔这吧
seL4_UserContext registers;
seL4_Word num_registers = sizeof(seL4_UserContext)/sizeof(seL4_Word);

/* Read the registers of the TCB that the capability in seL4_CapInitThreadTCB grants access to. */
seL4_Error error = seL4_TCB_ReadRegisters(seL4_CapInitThreadTCB, 0, 0, num_registers, &registers);
assert(error == seL4_NoError);

/* set new register values */
registers.sp = new_sp; // the new stack pointer, derived by prior code.

/* Write new values */
error = seL4_TCB_WriteRegisters(seL4_CapInitThreadTCB, 0, 0, num_registers, &registers);
assert(error == seL4_NoError);

seL4_TCB_ReadRegisters和seL4_TCB_WriteRegisters的第一个参数指向seL4_CapInitThreadTCB插槽中的能力(capability)的地址。之后会解释地址(address)和插槽(slots)。剩余的参数是此次调用中特定的,进一步的解释可以查API。

CNodes和CSlots

一个CNode是一个装满能力的对象,可以将其理解为一个能力数组。将插槽(slot)称为功能插槽(capability-slots)。在上面的例子中,seL4_CapInitThreadTCB是根任务的CNode的插槽,该CNode包含着根任务TCB的能力。每个CNode中的插槽可能有如下状态:

  • empty:插槽中没有能力
  • full:包含一个指向内核资源的能力

按照惯例(by convention),0号插槽一般是空的,类似于在进程虚拟地址空间中将NULL标识未分配或者无效的内存位置一样,是为了避免在不小心使用未初始化的槽位时出现错误。
info->CNodeSizeBits字段给出了初始CNode大小的度量:它将会有1<<CNodeSizeBits个插槽(2CNodeSizeBits)。一个插槽有1<<seL4_SlotBits(2seL4_SlotBits)个字节,所以一个CNode的大小未2CNodeSizeBits+seL4_SlotBits个字节。

CSpace

CSpace指的是能力空间,也就是一个线程中所有可访问的能力,可能是由一个或者多个CNodes组成的。在这一篇教程中,我们主要集中于由seL4的初始化协议为根任务构建的能力空间,是由一个CNode组成的。

CSpace addressing

为了引用一个能力且利用其执行操作,你必须要对其进行定位。在seL4 API中有两种方式对能力进行寻址。首先是通过调用,其次是通过直接寻址。调用是一种简写,我们用它来操作根任务TCB的寄存器(registers),下面是对其的进一步解释。

Invocation 调用

每个线程在其TCB中都有一个特殊的CNode能力,该能力作为其能力空间的根。这个根可以是空的(不包含任何能力),例如这个线程没有被授权调用任何能力,或者这个根节点也可以指向一个CNode,线程就可以使用其指向的那个CNode中的能力,这样该线程就可以在他的CSpace中管理和使用其他能力。
在一次invocation中,是通过隐式的调用执行该调用的线程的能力空间根来寻址能力插槽的。在上面的例子中,我们使用seL4_CapInitThreadTCB CSlot的调用,来读取和写入由该特定CSlot中的能力所表示的TCB(线程控制块)的寄存器。

seL4_TCB_WriteRegisters(seL4_CapInitThreadTCB, 0, 0, num_registers, &registers);

这会隐式的查询“调用线程能力空间根能力指向的CNode”(真他妈拗口)中的seL4_CapInitThreadTCB CSlot,这里指的就是根任务。
在某些情况下,当上下文足够清晰且其他信息不重要时,我们有时会用能力(capability)来代指它所指向的对象。比如,代替说“由 CSpace 根能力指向的 CNode”,我们有时会直接说“CSpace 根(其实是个能力)”。但如果不确定,最好还是保持精确。就像 C 语言中的结构体(structs)和指针(pointers)一样,对象(object)和能力(capabilities)并不是完全可互换的:一个对象可以被多个能力指向,而这些能力可能对该对象具有不同的权限级别。

能力空间直接寻址

对比起调用寻址,直接寻址允许你指定CNode进行查找能力,而不是隐式的使用能力空间根。这种方式主要用于构造和操作CSpaces的结构——可能是其他线程的CSpace。需要注意的式直接寻址也需要调用:这个操作需要调用一个CNode能力,而这个能力本身是从CSpace root索引的(搁着套娃呢)。
当对插槽进行直接寻址的时候,以下字段会被用到:

  • _service/root CNode操作的能力
  • index CNode地址中插槽的索引
  • depth 在解析出CSlot之前要遍历CNode多远

对于初始的,单一级别的能力空间,depth的值总是seL4_WordBits。对于调用而言,depth默认的就是seL4_WordBits。为了将会对该值进行更多的讨论。
在下面的例子中,我们直接寻址根任务的TCB然后将其进行复制到能力空间根中的0号插槽位置(其实是将一个指向TCB的能力复制到另外一个插槽中去)。CNode复制需要两个直接寻址的插槽,为什么称为CNode复制而不叫slot复制呢?因为在进行能力复制的时候实际上实在CNode中操作能力槽,而且slot只是CNode中的一个元素,用于存储能力。复制能力的过程不仅仅是复制槽内容,而是需要操作整个CNode中的多个槽来完成复制,所以称为CNode复制更为合适。需要寻址的两个插槽,一个是目标插槽,另外一个是源插槽。seL4_CapInitThreadCNode的三种角色:

  1. 源根(source root):seL4_CapInitThreadCNode被用作源根,因为我们在同一个CNode中进行复制——即初始线程的CNode
  2. 目标根(destination root),seL4_CapInitThreadCNode也被用作目标根,复制操作发生在同一个CNode内部
  3. 源插槽(source slot),seL4_CapInitThreadCNode 被用作源插槽,因为在初始线程的 CNode 内,seL4_CapInitThreadCNode 是我们想要复制的能力所在的插槽(而 0号插槽是目标)。
 seL4_Error error = seL4_CNode_Copy(
    seL4_CapInitThreadCNode, 0, seL4_WordBits, // destination root, slot, and depth
    seL4_CapInitThreadCNode, seL4_CapInitThreadTCB, seL4_WordBits, // source root, slot, and depth
    seL4_AllRights);
assert(error == seL4_NoError);

所有的CNode调用都需要直接能力空间寻址。

初始化能力空间

根任务的能力空间是由seL4在启动时设置的,包含了由seL4管理的所有资源能力。我们已经看到了在根能力空间的几个能力:seL4_CapInitThreadTCB以及seL4_CapInitThreadCNode。这些都是在libsel4中由常量指定的,但是并不是所有的初始能力都是静态指定的。其他能力由libsel4中的seL4_BootInfo数据结构进行解释,由seL4进行初始化。seL4_BootInfo描述了初始能力的范围,包括了初始能力空间中的可用的插槽。

实操

zjx@in-container:/host$ ./init --tut capabilities

执行成功后是这样的
在这里插入图片描述
看一眼capabilities教程的源码
capabilities的源码

//使用qemu仿真硬件,./simulate进行执行,执行结果如下所示
./simulate

在这里插入图片描述
可以看到其中的主要内容是:

Booting all finished, dropped to user space
Initial CNode is 65536 slots in size
The CNode is 0 bytes in size
<<seL4(CPU 0) [decodeInvocation/646 T0xffffff801fe08400 "rootserver" @4013be]: Attempted to invoke a null cap #65535.>>
main@main.c:31 [Cond failed: error]
	Failed to set priority

运行时所有的输出都是有意义的。但是现在而言,第一行的输出信息来自内核,第二行的输出信息告诉你初始化CNode有多少个插槽。第三行则阐述了CSpace空间的大小,但是可以看出第三行的输出是错误的,现在的首要任务是将其改为对的。
从源码中可以看到:

 size_t initial_cnode_object_size_bytes = 0; // TODO calculate this.
 printf("The CNode is %zu bytes in size\n", initial_cnode_object_size_bytes);

根据上面理论上的内容来看,想要计算出CSpace(即此处的一个CNode的大小)还需要知道一个值,也就是seL4_SlotBits,也就是插槽的size_bits,根据下表可以看出,针对某一个对象的大小有两种表达方式Size in Bytes = 2size_bits,为此查询了seL4的手册,发现如下表:
在这里插入图片描述
而我的qemu仿真的是x86-64,因此此处的seL4_SlotBits的值位5,每个插槽也就占了25个字节,因此可以将上面的程序更改如下:

#define seL4_SlotBits 5
 size_t initial_cnode_object_size_bytes = BIT(info->initThreadCNodeSizeBits + seL4_SlotBits); // TODO calculate this.
 printf("The CNode is %zu bytes in size\n", initial_cnode_object_size_bytes);

修改之后可以看到输出:
在这里插入图片描述
这里看到,下面的输出有一个报错,“尝试调用了一个空能力,可以看到是未能设置优先级”,修改代码如下所示:

seL4_CPtr last_slot = info->empty.end - 1;
 /* TODO use seL4_CNode_Copy to make another copy of the initial TCB capability to the last slot in the CSpace */
 error = seL4_CNode_Copy(seL4_CapInitThreadCNode, last_slot, seL4_WordBits, 
                         seL4_CapInitThreadCNode, seL4_CapInitThreadTCB, seL4_WordBits,
                         seL4_AllRights);
 ZF_LOGF_IF(error, "Failed to copy cap!");
 /* set the priority of the root task */
 error = seL4_TCB_SetPriority(last_slot, last_slot, 10);
 ZF_LOGF_IF(error, "Failed to set priority");

这里有一些需要说明的点,info这个指针指向的对象里面到底都有什么?如下图所示
在这里插入图片描述
可以看到里面empty字段,字段类型是seL4_SlotRegion,在文档的上方找到了对该字段的说明,该类型是一个C结构体,该结构体包含了两个这指针,即start和end。它标示着初始线程CNode插槽的区域,start指向第一个插槽,而end指向最后一个插槽的下一个位置,因此end-1指向的是这片插槽中的最后一个位置。
在代码中,经常能够看到一些突兀的的量,例如seL4_CapInitThreadCNode,seL4_CapInitThreadTCB,这些东西都没定义,从何而来?
在这里插入图片描述
可以是在初始线程的CSpace中包含的,前15个槽(如果没有MSC的是14个槽)包含了如上表指定的特定的能力。
在修改了上述代码之后,再次编译运行可以看到如下的输出:
在这里插入图片描述
从main.c中继续寻找TODO:

 // TODO delete the created TCB capabilities

// check first_free_slot is empty
error = seL4_CNode_Move(seL4_CapInitThreadCNode, first_free_slot, seL4_WordBits,
                        seL4_CapInitThreadCNode, first_free_slot, seL4_WordBits);
ZF_LOGF_IF(error != seL4_FailedLookup, "first_free_slot is not empty");

// check last_slot is empty
error = seL4_CNode_Move(seL4_CapInitThreadCNode, last_slot, seL4_WordBits,
                        seL4_CapInitThreadCNode, last_slot, seL4_WordBits);
ZF_LOGF_IF(error != seL4_FailedLookup, "last_slot is not empty");

可以看到,这里要求我们做到是删除创建的能力。

如何删除能力?

上面的代码检查first_free_slot和last_slot是不是空的,结果当然不是空的,因为你复制了TCB能力到这些槽里面去。检查一个能力槽是不是空的方法很巧妙:尝试移动能力槽中的能力到他们自身。如果源槽是空的则该操作应以一个错误码seL4_FailedLookup而结束,如果不是空的则是错误码seL4_DeleteFirst。
有两种可以删除能力的方法:

  • 在复制的能力上使用seL4_CNode_Delete删除
  • 在原生的能力上使用seL4_CNode_Revoke进行能力回收,回收所有复制的能力

下面查一下这两个方法:

在这里插入图片描述
seL4_CPtr 是一个无符号整数类型,表示能力指针(capability pointer),它实际上是能力槽的索引。也就是说,first_free_slot 本身就是一个索引,指向 CSpace 中的某个能力槽。这里的深度指的是传入后进行解析的时候的解析位数,例如传入的index为10101100,那么深度为1的时候就解析一位,即最高位1,当深度4的时候解析前四位,即1010,也就是十进制10,以此类推,所以深度是一个必不可少且非常重要的值,因此first_free_slot是第二个参数。

error = seL4_CNode_Revoke(seL4_CapInitThreadCNode, seL4_CapInitThreadTCB,seL4_WordBits);

//或者使用Delete
error = seL4_CNode_Delete(seL4_CapInitThreadCNode, first_free_slot, seL4_WordBits);
ZF_LOGF_IF(error,"Failed to delete slot");

error = seL4_CNode_Delete(seL4_CapInitThreadCNode, last_slot, seL4_WordBits);
ZF_LOGF_IF(error,"Failed to delete slot");

主要是深度无法确定,在输出的初始化CNode插槽数量的时候可以看到,输出是65536,也就是2的16次方,我以为深度是16,但是传入16不对,错误信息是非法槽,所以应该是深度错了,解析的时候有问题。再看到复制能力的时候,也需要传入深度,程序中传入的深度是seL4_WordBits,将这个值输出后发现是64,是再64位的机器上,所以插槽的索引也是64位的,但是插槽数量只有216个,所以就是有多余的用不上的,因此深度应是64,实际有用的只有低16位,但是默认解析是从高位解析的。
输出为:
在这里插入图片描述

调用能力

在这里插入图片描述
可以看到最后一个TODO是调用能力挂起当前线程,可以使用seL4_TCB_Suspend这个方法尝试挂起当前线程。先查到该方法:

在这里插入图片描述
这个简单,代码如下

seL4_TCB_Suspend(seL4_CapInitThreadTCB);

传入的是对线程TCB操作的能力。输出如下:
在这里插入图片描述
还有进一步的训练,啥时候想起来再做吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2149792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电商商品详情API接口对电商跨境电商企业运营的好处

为了获取更大利益&#xff0c;电商商家经常需要使用价格&#xff0c;ERP接口系统。价格接口对电商商家有多方面的好处&#xff0c;主要体现在以下几个方面&#xff1a; 1、价格接口系统可以帮助品牌和商家实现更加科学和精准的定价策略。通过实时获取多个主流电商平台&#xf…

我与Linux的爱恋:进程优先级|进程切换

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 1.进程优先级1.什么是进程优先级&#xff1f;2.进程优先级的类型3.进程优先级的作用4.进程优先级的实现5.进程优先级的重要性6.查看系统进程7.修改进程优先级8.优先…

通过蓝图Blueprint完成项目拆分、模块化以及模块化后项目结构分析

1、不拆分项目之前的写法 在上一篇Flask入门和视图中我们讲解了Flask项目的一个启动流程&#xff0c;引入Flask、创建Flask对象&#xff0c;然后由路由进入在视图函数中通过模版渲染或者json系列化的方式返回页面或者数据。我们发现这些所有的操作都是在一个页面中完成的&…

信息化时代下的高标准农田灌区:变革与机遇并存

在信息化时代的浪潮中&#xff0c;高标准农田灌区的建设与管理正经历着前所未有的变革&#xff0c;这既是一个挑战重重的历程&#xff0c;也孕育着无限的发展机遇。随着物联网、大数据、云计算以及人工智能等先进技术的飞速发展与融合应用&#xff0c;传统的农田灌溉模式正在被…

【Docker】安装全流程与配置完整镜像源(可安装 nginx)

目录 一、卸载历史版本&#xff08;选&#xff09;二、配置 yum 源三、安装 docker四、配置 docker 镜像源加速&#xff08;选、强烈建议&#xff09;4.1 配置阿里镜像加速4.2 配置其他镜像源 五、启动 docker参考文章与视频 本文基于 Linux - CentOS 7 操作系统。 一、卸载历史…

PG198-jesd204-phy阅读笔记

简介 介绍 JESD204 PHY IP核实现了JESD204的物理接口&#xff0c;简化在发送和接收核心之间共享串行收发器信息通道。此内核一般不单独使用&#xff0c;只能与JESD204或JESD204C内核结合使用。 特性 根据JESD204B和JESD204C草案设计   支持1至12lane配置   JESD204 IP支持…

clousx6整点报时指令怎么写?

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

对称加密算法使用示例

Demo包括以下对称加密算法组合 备注&#xff1a;XTS仅支持AES128和AES256&#xff0c;不支持AES192 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import cmac from cryptography.hazmat.primitives.…

SpringBoot 基于 Vue 的地方美食分享网站

摘要 首先&#xff0c;论文一开始便是清楚的论述了系统的研究内容。其次&#xff0c;剖析系统需求分析&#xff0c;弄明白“做什么”&#xff0c;分析包括业务分析和业务流程的分析以及用例分析&#xff0c;更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地…

smardaten无代码这么牛逼?逻辑编排不用代码!

目录 前言 经典案例 ①计划编排&#xff1a;数据操作自动化 ②工单派工&#xff1a;流程变更自动化 smardaten能力解析 一、逻辑控制篇 &#xff08;1&#xff09;变量定义与操作 &#xff08;2&#xff09;数据校验与反馈 &#xff08;3&#xff09;动态数据获取与回填…

企业微信oauth2提示应用无法使用

问题描述&#xff1a; 生成oauth2之后&#xff0c;我a公司是服务商&#xff0c;我给b公司的人去点授权链接会提示这个 应用服务商还没有在企业微信为你开通接口调用许可」&#xff0c;导致无法使用此应用&#xff0c;请联系服务商开通 正文 你先要知道一件事&#xff01;&…

基于SpringBoot+Vue的“课件通”中小学教学课件共享平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

后端原型设计

一&#xff1a;导航设计 1.1 横向导航栏 常用于浏览器对客的系统。 1.2 纵向导航栏 纵向导航左边可以进行一级菜单和二级菜单&#xff0c;每个二级菜单右边还可以继续再使用标签栏进行导航三级分类。 头条号和CSDN都是采用该方式。 1.3 横纵结合导航栏 横向为一级菜单&…

ConvexHull-凸包-原理-代码实现

定义&#xff1a;凸包是包围点云的最小凸多面体&#xff0c;所有点都在该多面体的内部或表面上。优点&#xff1a;能够精确地包围点云&#xff0c;并且不存在额外的空白区域。缺点&#xff1a;计算复杂度高&#xff0c;尤其是在高密度点云中&#xff0c;生成凸包的过程较慢。 …

前后端分离项目--下载功能

文章目录 不使用代理服务器blobblob构造函数通过FormData对象的getBlob方法创建Blob对象将Blob对象转换成UR 使用代理服务器 前后端分离项目中下载与其他接口的使用不同&#xff0c;一般下载不走node&#xff0c;不通过代理服务器&#xff0c;而是直接在前台发送请求&#xff0…

人工智能安全治理新篇章:《2024人工智能安全治理框架1.0版》深度解读@附20页PDF文件下载

在数字化浪潮席卷全球的今天&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度融入我们的日常生活&#xff0c;从智能助手到自动驾驶&#xff0c;从医疗诊断到金融风控&#xff0c;AI的身影无处不在。然而&#xff0c;技术的双刃剑特性也让我们不得不面对…

3657A/B/AM/BM矢量网络分析仪

苏州新利通 3657A/B/AM/BM 矢量网络分析仪 3657系列矢量网络分析仪适用于无线通信、有线电视、教育及汽车电子等领域&#xff0c;可用于对滤波器、放大器、天线、电缆、有线电视分接头等射频元件的性能测量。该产品采用Windows操作系统&#xff1b;具有误差校准功能、时域功能…

Java基础面试必知:HashMap的数据结构与扩容机制

Java基础面试必知&#xff1a;HashMap的数据结构与扩容机制 在Java开发中&#xff0c; HashMap是使用最为广泛的数据结构之一&#xff0c;它提供了基于键值对的快速存取功能。然而&#xff0c;在面试中&#xff0c;经常会涉及到HashMap的底层实现原理&#xff0c;特别是其数据…

Abp vNext(五)集成MQTTnet,可收发消息

一 前言 MQTT的相关理论内容这里不做过多介绍&#xff0c;请看下面两篇文章&#xff1a; Introduction MQTT协议中文版 MQTT协议-CSDN博客 这篇文章只做代码实现&#xff0c;文章中使用MQTTnet作为MQTT开发的组件。 MQTT分为服务端和客户端&#xff0c;一个服务端对应多个…

Docker + Win 10 学习记录

下载Docker Release notes | Docker Docs 推荐使用4.33版本&#xff0c;最新的Docker版本在win10 22H2无法安装。需要升级到win11. 查看Win10版本是否与最新版的Docker兼容 运行 win R&#xff0c; 然后输入winver 如果你的Docker版本无法在当前的win10安装&#xff0c;请更…