seL4 Untyped(二)

链接: Untyped

Untyped

这篇主要是针对seL4物理内存管理的介绍。

物理内存

在seL4系统中,除了内核占用的一小部分静态内存之外,其他的所有的物理内存都是用户一级管理的。seL4在启动时创建的对象能力,以及seL4管理的其余物理资源,都会在启动时传递给根任务。

未分类内存以及能力

除了用于创建根任务的对象,对于其他的所有可用物理内存的能力都被传递给了根任务作为untyped内存 。未类型化内存是一块连续的指定大小的物理内存。Untyped capabilities是针对未类型化内存的能力。未类型化能力可以被retyped成为内核对象以及针对这些对象的能力,或者进一步成为通常来讲更小的未类型化能力。
未类型化能力有一个布尔类型的属性即device,该属性指明这块内存是不是内核可写的:也就是说这块内存可能不是由RAM支持的而是一些其他的设备,或者说在RAM区域中这块内存是无法被内核寻址的。Device untyped能力只能重新类型化为帧对象(即物理内存帧,可映射到虚拟内存中),并且内核不能对其进行写操作。

初始状态

提供给根任务的seL4_BootInfo描述了所有的未类型化能力,包括他们的大小,如果他们是未类型化设备(device),还会提供未类型化设备的地址。下面的代码展示了如何输出由seL4_BootInfo提供的初始的未类型化的能力。

  printf("    CSlot   \tPaddr           \tSize\tType\n");for (seL4_CPtr slot = info->untyped.start; slot != info->untyped.end; slot++) {seL4_UntypedDesc *desc = &info->untypedList[slot - info->untyped.start];printf("%8p\t%16p\t2^%d\t%s\n", (void *) slot, (void *) desc->paddr, desc->sizeBits, desc->isDevice ? "device untyped" : "untyped");}

重新类型化

未类型化的能力只有一个函数调用:seL4_Untyped_Retype,也即是从一个未类型化的能力创建一个新的能力(以及潜在的对象)。特别的是,由重新类型化调用创建的新能力提供了对原始内存功能内存范围子集的访问,或者作为一个更小的未类型化的能力(前面提到过),或者是作为一个特定的类型指向一个新的对象。由重新类型化一个未类型化能力创建的新能力被认为是那个未类型化能力的孩子。
未类型化的能力以一种贪心的策略从调用的未类型化能力中增量的重新类型化,在seL4系统中,为了获得有效的内存利用,理解这一点很重要。每个未类型化的能力都维持了一个水印,水印之前的地址不可用(已重新类型化),而水印之后的地址仍然空闲(尚未重新类型化)。在重新类型化的操作中,水印首先移动到正在创建的对象的对齐的位置,然后到对象大小的末尾。
例如,如果我们先创建了一个4KiB的对象,然后又创建了一个16KiB的对象(KiB是210B,而KB指的是103B),有12KiB空间若位于4KiB对象的末尾以及16KiB对象的开头则会因对其而被浪费掉。这块内存将在这两个孩子都被撤销之后才能被回收。
应该按照尺寸从大到小给对象进行分配,最大的最先分配,这样做可以避免浪费内存。

 error = seL4_Untyped_Retype(parent_untyped, // the untyped capability to retypeseL4_UntypedObject, // typeuntyped_size_bits,  //sizeseL4_CapInitThreadCNode, // root0, // node_index0, // node_depthchild_untyped, // node_offset1 // num_caps);

上面的代码片段展现了将未类型化能力重新类型化为一个更小的4KiB未类型能力的案例。尽管名称未seL4_UntypedObject,但是没有创建任何对象,新的无类型能力只是指向了parent_untyped的未类型化内存的子集。但是处于此操作的目的,将这一块内存视为对象是比较方便的。当我们在下面讨论重新类型化调用的每个参数时,我们会引用这个代码片段。 回想一下,第一个参数时正在被调用进行重新类型化的未类型化能力。

type

在seL4中的每个对象都有一个特定的类型,并且所有的类型常量都可以在libsel4中找到。有一些类型时特定于体系结构的,而其他类型则是跨体系结构通用的。在上面改的例子中,我们创建了一个新的未类型化的能力(也就是创建的这个能力可以被进一步的重新类型化)。其他的所有对象类型都会创建一个内核对象以及操作该对象的能力,所创建的对象(及能力)的类型决定了该能力上可以执行的调用操作。例如,假如我们重新类型化了一个线程控制块(TCB——seL4_TCBObject),那么我们就可以对新的TCB对象的能力执行TCB调用操作,包括seL4_TCB_SetPriority。

Size

size参数决定了新对象的大小。参数的含义取决于正在被请求创建的对象类型(Type)。

  • seL4中的大多数对象大小都是固定的,因此创建这类对象的时候,内核会忽略该参数
  • 对于seL4_UntypedObject以及seL4_SchedContextObject这两个对象允许一个可变的大小,这是在size_bits中指定的(更多信息见下文)
  • seL4_CapTableObject这个对象的大小也是可变的,type参数会指定能力插槽的数量。类似于size_bits一样的机制,但是指定的是插槽的数量,而不是字节数的大小。

通常来讲,在seL4中,如果以位(bit)为单位,他们是两个的幂。“Bits”并不是指该对象占据的位数,而是值需要描述其内容所需的位宽度。位大小位n的对象大小为2n个字节。同样的,通常来说在seL4中,对象和内存区域对齐于他们的大小,例如一个n-bit的对象对齐于2n字节,或者,同样的,对象的地址将0作为其n个底部位。
对于重新类型化而言,记住size_bits参数意味着对象大小为2size_bits且对于seL4_CapTableObject而言,其意味着插槽数量为2size_bits就足够了(计算CapTableObject对象的大小在(一)中已经讲过)。

Root,node_index&node_depth

root、node_index以及node_depth参数用于指定将新能力放置在哪个CNode中去。取决于depth参数,使用的插槽是通过调用或者直接寻址进行定址(一中已经讲过)。
在上面的案例中,node_depth被设置为0,着意味着使用的是调用寻址:使用当前线程的CSpace根以seL4_WordBits为参数进行隐含查找root。所以上面的案例指定了根任务的CNode。而node_index参数在这种情况下是被忽略的。
如果node_depth的值不为0,那么将对当前线程CSpace根作为根进行直接寻址。然后node_index参数被用于定位CNode能力以放置新的能力。简单点来说就是node_index给出地址,然后node_depth给出解析深度,root作为根。主要是面向多级CSpaces设计的,在这篇课程中并不涉及。

Node_offset

node_offset用于指定开始创建新能力的CSlot,就是在前面参数指定的CNode中。在上面的代码案例中,初始CNode的第一个空槽会被选中。前面三个参数用于选择CNode,这个参数用于选择空槽。

Num_caps

重新类型化能够被用于一次创建多个能力以及对象——能力的数量使用这个参数指定。注意,该值有两个限制:

  1. 未分类对象必须足够大以能适应所有的重新类型化内存。(num_caps * (1u << size_bits))
  2. CNode必须有足够的连续的空槽以放置新的能力

上面个几个东西看的人有点迷糊,再总结一下:

  • root:指定了根CNode能力,表示从哪个CNode开始查找要放置新能力的槽位。
  • node_index 和 node_depth:用于在这个根CNode中进行层次结构的寻址。这两个参数结合起来指定了从根CNode到目标CNode的路径,用于找到要放置新能力的具体CNode。
  • node_offset:指定在目标CNode中的具体槽位位置,即将新能力放置在哪个槽位。

总结:root、node_index、node_depth是用于寻址到CNode的,而node_offset在目标CNode中指定了最终放置新能力的槽位。

实操

创建一个未类型化能力

先拉取好教程:

./init --tut untyped
cd untyped_build
ninja
./simulate

当你运行这个tutorials的时候,你将会看到类似于下面的输出:列出了所有在启动时提供给根任务的所有未类型化的能力:

Booting all finished, dropped to user spaceCSlot   Paddr       Size    Type0x12d    0x100000    2^20    device untyped0x12e    0x200000    2^21    device untyped0x12f    0x400000    2^22    device untyped0x130    0xb2e000    2^13    device untyped

可以看到我的执行结果如下:
在这里插入图片描述
在输出的最后有一个错误:
在这里插入图片描述
出现这个错误的原因是因为我们想要创建一个大小为0的未类型化对象。
实操:计算出孩子未类型化对象所需要的大小,以便该未类型化子级可用于创建objects数组中列出的所有对象。需要牢记的是对象的大小使用bit_size进行标识的,这是两个玩意的幂。

首先代码中看到两行这玩意,在API中进行查找也没找到,seL4_Word通常用于表示无符号整数,具体来说它通常是一个固定大小的整数类型,这里就很奇怪,怎么一个Object能定义为一个整数(应该是在seL4的某个.h文件里面定义的),后来仔细想了一下,发现这其实是一种设计,将一种类型用一个整数来标识,在对一块untyped空间进行retype的时候可以使用整数值快速的指定想要重新类型化为什么对象。而这里定义这个数组也是为了告诉读者,你一会需要retype这三种对象,而下面的sizes数组保持与上面的objects数组对齐,好让读者去计算每类对象所占空间的大小,对于程序而言,这两行代码没什么实际意义。
在这里插入图片描述
不妨将这三个Bits输出出来,看一下各自是多大。

printf("TCB: %zu,EndPoint: %zu,Notification: %zu\n",seL4_TCBBits, seL4_EndpointBits, seL4_NotificationBits);

在这里插入图片描述
可以看到最大为11,因此size写12即可,而且还有很多空间用不到,完全足够。

seL4_Word untyped_size_bits = 12;//主要是将这里改成12
seL4_CPtr parent_untyped = 0;
seL4_CPtr child_untyped = info->empty.start;// First, find an untyped big enough to fit all of our objects
// for循环查找未类型化对象中能够放得下Bits为12的,且是非device,然后在其内进行重新类型化
for (int i = 0; i < (info->untyped.end - info->untyped.start); i++) {if (info->untypedList[i].sizeBits >= untyped_size_bits && !info->untypedList[i].isDevice) {parent_untyped = info->untyped.start + i;break;}
}
// create an untyped big enough to retype all of the above objects fromerror = seL4_Untyped_Retype(parent_untyped, // the untyped capability to retypeseL4_UntypedObject, // typeuntyped_size_bits,  //sizeseL4_CapInitThreadCNode, // root0, // node_index0, // node_depthchild_untyped, // node_offset1 // num_caps);
ZF_LOGF_IF(error != seL4_NoError, "Failed to retype");

此时可以看到输出已经变了,没有了Failed to retype,而是如下
在这里插入图片描述
需要做下一步的练习。

创建一个TCB对象

优先级检查失败是因为child_tcb是一个空插槽。看一下代码

seL4_CPtr child_untyped = info->empty.start;
error = seL4_Untyped_Retype(parent_untyped, // the untyped capability to retypeseL4_UntypedObject, // typeuntyped_size_bits,  //sizeseL4_CapInitThreadCNode, // root0, // node_index0, // node_depthchild_untyped, // node_offset1 // num_caps);
seL4_CPtr child_tcb = child_untyped + 1;
error = seL4_TCB_SetPriority(child_tcb, seL4_CapInitThreadTCB, 10);

child_untyped原本是第一个空槽,在进行了retype之后,该槽用于放置新的能力,而child_untyped+1此时应该是一个空槽。而在最后一行代码中对该空槽设置了优先级,所以会出现Failed to set priority的错误。因此这步需要做的是从child_untyped中创建一个TCB对象,然后将能力插入到child_tcb这个空槽里面。考虑到上面理论部分,重新类型化的时候直接寻址一般是用于多级CNode的,这里的CSpace只是由一个CNode组成的。因此应使用调用寻址,也就是node_index和node_depth都为0,下面是实现代码。

error = seL4_Untyped_Retype(child_untyped, seL4_TCBObject, seL4_TCBBits, seL4_CapInitThreadCNode, 0, 0, child_tcb, 1 );

正确创建之后可以看到输出的错误信息已经来到了下一步,如下所示
在这里插入图片描述

创建一个端点对象

现在的错误是因为一个非法的端点能力,看一下代码

// use the slot after child_tcb for the new endpoint cap:
seL4_CPtr child_ep = child_tcb + 1;
/* TODO create an endpoint in CSlot child_ep */// identify the type of child_ep
uint32_t cap_id = seL4_DebugCapIdentify(child_ep);
ZF_LOGF_IF(cap_id == 0, "Endpoint cap is null cap");

可以看到child_ep指向了下一个空槽,因此在此处我们要创建一个端点对象,类似于创建TCB对象,代码如下:

error = seL4_Untyped_Retype(child_untyped,seL4_EndpointObject,seL4_EndpointBits,seL4_CapInitThreadCNode,0,0,child_ep,1);

此时输出的错误信息来到了下一步:
在这里插入图片描述

创建一个信号量对象

下一部分代码尝试使用了一个不存在的信号量对象,因此我们需要从child_untyped中重新类型化出一个信号量对象,然后将新的能力放置在child_ntfn插槽里面,类似于上面的直接上代码。

error = seL4_Untyped_Retype(child_untyped,seL4_NotificationObject,seL4_NotificationBits,seL4_CapInitThreadCNode,0,0,child_ntfn,1);

此时输出的错误信息来到了下一步:
在这里插入图片描述

删除对象

可以看到输出的错误信息是未能创建端点,因为最后一部分是尝试创建足够多的端点对象将child_untyped来消耗完整个未类型化的对象。失败的原因是因为该未类型化对象已经被先前的对象完全分配掉了(存疑)。看一眼代码:

// TODO revoke the child untyped// allocate the whole child_untyped as endpoints
// Remember the sizes are exponents, so this computes 2^untyped_size_bits / 2^seL4_EndpointBits:
// 这里作减法,除法->幂相减,再取指
seL4_Word num_eps = BIT(untyped_size_bits - seL4_EndpointBits);
error = seL4_Untyped_Retype(child_untyped, seL4_EndpointObject, 0, seL4_CapInitThreadCNode, 0, 0, child_t>
ZF_LOGF_IF(error != seL4_NoError, "Failed to create endpoints.");printf("Success\n");

因此需要将之前创建的对象都删除掉,回收之前已经分配出去的untyped空间。使用(一)中提到的seL4_CNode_Delete(),这个方法,将使用retype方法创建的对象删除掉,只需要删除掉在seL4_CapInitThreadCNode中插入的新能力。代码如下:

// TODO revoke the child untypederror = seL4_CNode_Delete(seL4_CapInitThreadCNode, child_ntfn, 64);ZF_LOGF_IF(error, "Failed to delete notification object.");error = seL4_CNode_Delete(seL4_CapInitThreadCNode, child_ep, 64);ZF_LOGF_IF(error, "Failed to delete Endpoint object.");error = seL4_CNode_Delete(seL4_CapInitThreadCNode, child_tcb, 64);ZF_LOGF_IF(error, "Failed to delete TCB object.");

运行之后结果如下:
在这里插入图片描述

进一步实操

把课程过一遍再说吧

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

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

相关文章

tensorflow底层架构

tensorflow底层架构 架构图 Training libraries 和 Inference libs&#xff08;训练库和推理库&#xff09; Training libraries&#xff1a;用于模型的训练过程&#xff0c;包括定义模型、计算梯度、更新模型权重等。这些库提供了在训练过程中所需的所有功能。Inference lib…

推荐几本值得阅读的书籍!

大家好&#xff0c;这里是大话硬件。 初次关注我公众号的朋友第一反应基本都是认为内容太专业&#xff01; 其实不然&#xff0c;大话硬件公众号除了有硬件设计方面的内容&#xff0c;还包含书籍推荐&#xff0c;个人反思总结模块等内容。 今天这篇文章继上篇荐书《相见恨晚的…

学习IEC 62055付费系统标准

1.IEC 62055 国际标准 IEC 62055 是目前关于付费系统的唯一国际标准&#xff0c;涵盖了付费系统、CIS 用户信息系统、售电系统、传输介质、数据传输标准、预付费电能表以及接口标准等内容。 IEC 62055-21 标准化架构IEC 62055-31 1 级和 2 级有功预付费电能表IEC 62055-41 STS…

如何快速恢复误删除的文件?教你一招,不花一分钱,三步就可以搞定!

电脑文件越存越多&#xff0c;我们都会不定时的进行清理&#xff0c;但有时候&#xff0c;我们难免会误删除一些重要文件。当遇到类似情况的时候&#xff0c;不要着急&#xff0c;很多时候&#xff0c;删除的文件是有办法恢复的。 市面上有很多文件恢复软件&#xff0c;就可以帮…

常用工具推荐!分享7款AI论文修改软件工具网站

在当今学术研究和写作领域&#xff0c;AI论文修改软件工具已经成为了不可或缺的助手。这些工具不仅能够帮助研究人员提高写作效率&#xff0c;还能确保论文的质量和原创性。以下是七款值得推荐的AI论文修改软件工具网站&#xff0c;其中特别推荐千笔-AIPassPaper。 1. 千笔-AI…

YOLOv8改进 | 特征融合篇,YOLOv8添加iAFF(多尺度通道注意力模块),并与C2f结构融合,提升小目标检测能力

摘要 特征融合,即来自不同层或分支的特征的组合,是现代网络架构中无处不在的一部分。虽然它通常通过简单的操作(如求和或拼接)来实现,但这种方式可能并不是最佳选择。在这项工作中,提出了一种统一且通用的方案,即注意力特征融合(Attentional Feature Fusion),适用于…

心理辅导系统:Spring Boot技术驱动

3 系统分析 3.1可行性分析 在进行可行性分析时&#xff0c;我们通常根据软件工程里方法&#xff0c;通过四个方面来进行分析&#xff0c;分别是技术、经济、操作和法律可行性。因此&#xff0c;在基于对目标系统的基本调查和研究后&#xff0c;对提出的基本方案进行可行性分析。…

攻防世界---->Windows_Reverse1(补)

做题笔记。 做题回顾。 假设&#xff0c;我们不知道地址随机怎么办&#xff1f;不能动调&#xff0c;只能静态分析。 下载 查壳 upx脱壳。 32ida打开。 动调报错。 重新打开&#xff0c;静态分析。 跟进关键函数。 不明白可以反汇编和汇编一起看。 溯源。 *decode 取值等于 by…

robomimic应用教程(一)——模型训练

Robomimic使用集中式配置系统来指定所有级别的(超)参数 本文介绍了配置&#xff08;推荐&#xff09;和启动训练运行的两种方法 目录 一、使用config json&#xff08;推荐&#xff09; 二、在代码中构造一个配置对象 三、查看运行结果 1. 实验结果会存在一个固定文件夹中…

嵌入式入门小工程

此代码基于s3c2440 1.点灯 //led.c void init_led(void) {unsigned int t;t GPBCON;t & ~((3 << 10) | (3 << 12) | (3 << 14) | (3 << 16));t | (1 << 10) | (1 << 12) | (1 << 14) | (1 << 16);GPBCON t; }void le…

如何精准高效做好网站安全防护?一文解读

企业数字化转型过程中&#xff0c;难免会受到多种网络安全威胁带来的负面影响。比如攻击者通过利用Web服务程序以及网站系统的安全漏洞&#xff0c;对企业进行数据窃取等破坏活动&#xff0c;严重损害企业利益。如何精准高效做好网站安全防护&#xff1f;相信本文会为你带来启发…

心觉:保持感恩的心,为什么可以吸引更多好机会和财富

​Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作176/1000天 保持一颗感恩的心&#xff0c;就可以吸引更多的机会和财富 很多人可能不理解&#xff0c;但是这是事实 千正万确的…

armbian debian 系统安装overlayroot后无法启用

千盼万盼 终于debian12可以用了 它终于也跟ubuntu 系统一样可以安装overlayroot了 但是 满怀欣喜的装完了发现 压根没法启动 这。。。。。 原因吗 也简单。。。 默认的映像里没有busybox......... 而它有这个要求。。。 overlayroot 包中有一个小错误&#xff1a;它要求 gr…

Java基础(上)

Java基础&#xff08;上&#xff09; 基础概念与常识 Java语言有哪些特点&#xff1f; 简单易学&#xff08;语法简单&#xff0c;上手容易&#xff09;面向对象&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;平台无关性&#xff08;Java虚拟机实现平台无关…

黑群晖安装教程

黑群晖&#xff08;一种非官方的群晖NAS系统安装方式&#xff09;的安装教程相对复杂&#xff0c;但按照以下步骤操作&#xff0c;可以顺利完成安装。请注意&#xff0c;由于黑群晖涉及非官方操作&#xff0c;安装过程中可能遇到各种不确定因素&#xff0c;建议具备一定的计算机…

AI智能跟踪技术核心!

1. 目标检测技术 在视频序列的第一帧中&#xff0c;通过目标检测算法确定要追踪的目标对象的位置和大小。 技术实现&#xff1a;目标检测算法可以基于传统的图像处理技术&#xff0c;如颜色、纹理、形状等特征&#xff0c;也可以基于深度学习方法&#xff0c;如卷积神经网络&…

Wireshark学习使用记录

wireshark 是一个非常好用的抓包工具&#xff0c;使用 wireshark 工具抓包分析&#xff0c;是学习网络编程必不可少的一项技能。 原理 Wireshark使用的环境大致分为两种:一种是电脑直连互联网的单机环境&#xff0c;另外一种就是应用比较多的互联网环境&#xff0c;也就是连接…

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分即可。 为了更好理解本文的内容&#xff0c;优先说明下SystemUI中与Ke…

虚拟机VMware安装+centos8

1、安装虚拟机 这里以VMware-workstation-full-14.1.1-7528167.exe为例进行安装虚拟机。 注意win11&#xff0c;不能安装14的版本&#xff0c;新建虚拟机打开会崩的。建议换成16版本的。 此处安装的为centos7版本&#xff0c;双击就可以开始安装了。 选择下一步 勾选我接受&a…

【电路笔记】-运算放大器积分器

运算放大器积分器 文章目录 运算放大器积分器1、概述2、运算放大器积分器的表示2.1 理想积分器2.2 交流响应2.3 输出公式3、限制4、总结1、概述 在我们之前与运算放大器相关的大多数文章中,配置都是基于带有电阻器作为反馈环路、分压器或互连许多运算放大器的一部分的放大器。…