seL4 Untyped(二)

news2024/9/21 23:35:40

链接: 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 retype
                                seL4_UntypedObject, // type
                                untyped_size_bits,  //size
                                seL4_CapInitThreadCNode, // root
                                0, // node_index
                                0, // node_depth
                                child_untyped, // node_offset
                                1 // 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 space
    CSlot   Paddr       Size    Type
   0x12d    0x100000    2^20    device untyped
   0x12e    0x200000    2^21    device untyped
   0x12f    0x400000    2^22    device untyped
   0x130    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 from

error = seL4_Untyped_Retype(parent_untyped, // the untyped capability to retype
                            seL4_UntypedObject, // type
                            untyped_size_bits,  //size
                            seL4_CapInitThreadCNode, // root
                            0, // node_index
                            0, // node_depth
                            child_untyped, // node_offset
                            1 // 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 retype
                               seL4_UntypedObject, // type
                               untyped_size_bits,  //size
                               seL4_CapInitThreadCNode, // root
                               0, // node_index
                               0, // node_depth
                               child_untyped, // node_offset
                               1 // 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 untyped
 error = 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.coloradmin.cn/o/2153598.html

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

相关文章

初始网络编程(下)

所属专栏&#xff1a;Java学习 1. TCP 的简单示例 同时&#xff0c;由于 TCP 是面向字节流的传输&#xff0c;所以说传输的基本单位是字节&#xff0c;接受发送都是使用的字节流 方法签名 方法说明 Socket accept() 开始监听指定端口&#xff08;创建时绑定的端口&…

十七、RC振荡电路

振荡电路 1、振荡电路的组成、作用、起振的相位条件以及振荡电路起振和平衡幅度条件&#xff0c; 2、RC电路阻抗与频率、相位与频率的关系曲线; 3、RC振荡电路的相位条件分析和振荡频率

信息安全数学基础(15)欧拉定理

前言 欧拉定理是数论中的一个重要定理&#xff0c;它建立了模运算下指数与模的互质关系。这个定理在密码学、信息安全等领域有着广泛的应用&#xff0c;特别是在公钥密码体制&#xff08;如RSA加密算法&#xff09;中。 一、表述 设 n 是一个正整数&#xff0c;a 是一个与 n 互…

Tomcat服务器—Windows下载配置详细教程

一、关于 1.1 简介 Tomcat是一个开源的Java Servlet容器和Web服务器&#xff0c;由Apache软件基金会维护。它实现了Java Servlet和JavaServer Pages (JSP) 规范&#xff0c;用于运行Java Web应用程序。Tomcat支持多种Java EE功能&#xff0c;并提供了高效的性能和可扩展性&am…

Spring扩展点系列-MergedBeanDefinitionPostProcessor

文章目录 简介源码分析示例示例一&#xff1a;Spring中Autowire注解的依赖注入 简介 spring容器中Bean的生命周期内所有可扩展的点的调用顺序 扩展接口 实现接口ApplicationContextlnitializer initialize AbstractApplicationContext refreshe BeanDefinitionRegistryPos…

记录一个英语听力网站的开发

背景 在当前全球经济衰退的背景下&#xff0c;国内IT相关工作的竞争日益激烈。为了获得更多的职业机会&#xff0c;学习英语或许能为程序员打开一扇新的窗户。尤其是在国际化背景的远程工作中&#xff0c;英语协作沟通是必不可少的。 尽管我们大多数人从小到大都在学习英语&a…

使用Renesas R7FA8D1BH (Cortex®-M85)和微信小程序App数据传输

目录 概述 1 系统架构 1.1 系统结构 1.2 系统硬件框架结构 1.3 蓝牙模块介绍 2 微信小程序实现 2.1 UI介绍 2.2 代码实现 3 上位机功能实现 3.1 通信协议 3.2 系统测试 4 下位机功能实现 4.1 功能介绍 4.2 代码实现 4.3 源代码文件 5 测试 5.1 编译和下载代码…

RNN的反向传播

目录 1.RNN网络&#xff1a;通过时间反向传播(through time back propagate TTBP) 2.RNN梯度分析 2.1隐藏状态和输出 2.2正向传播&#xff1a; 2.3反向传播&#xff1a; 2.4问题瓶颈&#xff1a; 3.截断时间步分类&#xff1a; 4.截断策略比较 5.反向传播的细节 ​编辑…

大数据新视界 --大数据大厂之JavaScript在大数据前端展示中的精彩应用

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

浙大数据结构:05-树8 File Transfer

数据结构MOOC PTA习题 这道题考察并查集的操作&#xff0c;合并以及找根结点 机翻&#xff1a; 1、条件准备 node是数组存放1-N结点的根节点的&#xff0c;n为总结点数 #include <iostream> using namespace std;const int N 1e4 5; int node[N]; int n; 先初始化…

众数信科AI智能体政务服务解决方案——寻知智能笔录系统

政务服务解决方案 寻知智能笔录方案 融合民警口供录入与笔录生成需求 2分钟内生成笔录并提醒错漏 助办案人员二次询问 提升笔录质量和效率 寻知智能笔录系统 众数信科AI智能体 产品亮点 分析、理解行业知识和校验规则 AI实时提醒用户文书需注意部分 全文校验格式、内…

【在Linux世界中追寻伟大的One Piece】进程间关系与守护进程

目录 1 -> 进程组 1.1 -> 什么是进程组 1.2 -> 组长进程 2 -> 会话 2.1 -> 什么是会话 2.2 -> 如何创建会话 2.3 -> 会话ID(SID) 3 -> 控制终端 4 -> 作业控制 4.1 -> 什么是作业(job)和作业控制(Job Control) 4.2 -> 作业号 4.3…

Spring:项目中的统一异常处理和自定义异常

介绍异常的处理方式。在项目中&#xff0c;都会进行自定义异常&#xff0c;并且都是需要配合统一结果返回进行使用。 1.背景引入 &#xff08;1&#xff09;背景介绍 为什么要处理异常&#xff1f;如果不处理项目中的异常信息&#xff0c;前端访问我们后端就是显示访问失败的…

20240921在友善之臂的NanoPC-T6开发板上确认宸芯的数传模块CX6602N的AT命令

console:/dev # cat ttyUSB1 & console:/dev # echo AT > ttyUSB1 20240921在友善之臂的NanoPC-T6开发板上确认宸芯的数传模块CX6602N的AT命令 2024/9/21 21:03 【必须】Android12/Linux&#xff08;Buildroot&#xff09;都必须要&#xff01; 4、【Android12默认打开U…

电脑硬件-机械硬盘

简介 机械硬盘是电脑的主要存储媒介之一&#xff0c;通常用于存储一些文件资料或者学习视频笔记等比较大的内容。 结构 采用磁盘存储数据&#xff0c;使用温彻斯特的结构&#xff0c;特有四个特点&#xff1a; 1.磁头、盘片和运动机构安装在一个密封的腔体内。 2.盘片告诉旋…

一图快速看懂flink source的设计实现

文章目录 整体来说多个处理流程是解偶的&#xff0c;这样可以在面对多数据源情况下&#xff0c;能更加的灵活。 下面只展示了&#xff0c;主要的一些流程 下面补充一点&#xff0c;读取文件状态的保存&#xff0c;切分信息用了一个 ListState 来保存。具体要保存的信息&#x…

day2-1 app端文章查看

首先一共三张表 然后大致过程就是三层架构 用mp实现 具体出现的问题 1 测试的时候后端代码启动不了 先在maven clean一下 具体流程 然后执行完之后建议把这三个模块的target文件删除一下再运行 最后的话 如果还是报错 也是正常的 因为后边的东西都没写有些文件没有用到 2…

常见的中间件漏洞

Tomcat CVE-2017-12615 访问主页进行抓包 修改传参方式为put 放包进行连接 后台弱⼝令部署war包 访问主页试用默认账号密码tomcat/tomcat进行登录后 将哥斯拉生成的jsp木马文件压缩城成zip文件&#xff0c;然后再修改zip后缀文war 然后进行上传 使用哥斯拉进行测试连接 CVE-…

基于SpringBoot+Vue的在线酒店预订系统

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

微服务——网关登录校验(一)

1.网关登录校验 微服务中的网关登录校验是微服务架构中常见的一种安全机制&#xff0c;用于在请求到达微服务之前&#xff0c;对用户的身份进行验证&#xff0c;确保只有合法的用户才能访问相应的服务。 在微服务架构中&#xff0c;每个微服务都是独立部署的&#xff0c;它们之…