REE和TEE的schedule

来源:互联网 发布:java在线笔试题 编辑:程序博客网 时间:2024/06/03 09:32

n年前,基于ARM的trust-zone技术,需要实现Security OS。当年Lianro的OP-TEE还不成熟,所以评估了当时可见的一些OS,确认是否适合做为Security OS。此篇文档是当年基于Trust-zone知识,拍脑袋写出来的REE和TEE的关系。当年并没有按照GP规范去思考TEE和REE的关系,现在回过头来看,好稚嫩。。。


TEE_REE_Schedule


1、 TEE和REE的关系

根据需求,TEE 可有如下两种形式:

  • TEE只提供“单函数调用”功能,即前后台功能,则不需要TEE OS;
  • TEE需支持多任务功能,则需要TEE OS调度;

本文后续“TEE”指支持OS的TEE。


在安全平台中,TEE和REE由于共享CPU,可存在如下的关系:

  • 约定TEE优先级高于REE,即TEE可以抢占REE;
  • 约定REE优先级高于TEE,即REE可以抢占TEE;
  • 约定TEE和REE的优先级相等,即先到先服务;

TEE优先级高于REE的情形:

  • 在同一个CPU上,当TEE运行时,REE不能处理中断,不能切换任务等;
  • TEE的行为可体现为2种形式:
    • 时间片:运行完自己的时间片,TEE需主动切换回REE;
    • 事件触发:响应REE的事件,处理完事件后才切换回REE;

由此可见,此约定会导致TEE阻塞REE。


REE优先级高于TEE的情形:

  • REE可以中断TEE,比如在TEE运行时响应“非安全中断”;
  • TEE的行为可体现为REE功能的扩展,如:
    • REE向TEE发起服务请求,TEE的运行时间体现为REE请求行为的运行时间;
    • REE的代理行为。即向TEE发起服务请求的行为都在特定的REE任务中执行,则TEE虚拟为REE的某个任务;
    • 对于TEE的时间片调度,可由REE以事件触发的方式让TEE发起调度;

为了保证REE的响应及时性,特别考虑到用户体验,约定REE可抢占TEE。


2. SMP


对于多核平台,需要支持SMP。REE可以沿用原有的SMP设计,需要在驱动方面做增强和优化。
TEE SMP可有2个层次的定义:

  • (目标1)TEE可以分散于多个CPU,但同一时刻只能存在于单个CPU上;
  • 目标2)TEE可以分散于多个CPU,且同一时刻可以占有多个CPU;

SMP需要TEE和REE统一设计,然后分别考虑。


2.1 REE SMP

为实现目标1,根据上述的设计原则,REE可以做如下增强:

  • REE采用一个任务做为“安全服务代理”(SSA);
  • SSA拥有一个“安全服务请求队列”(SSRQ),发起“安全服务请求”(SSR)的任务将SSR压入到SSRQ中;SSA负责从队列中取出SSR并发起请求;
  • SSA使用SMC指令使当前CPU进入TEE;
  • TEE处理完SSR后返回REE。在TEE处理SSR过程中,可能会发生多次TEE/REE的切换;

此方案优点:

利用代理的方式让SMP可以看到SSA的实例,即其所存在的任务,从而将其作为调度实体参与到SMP的调度策略当中,所以对SSR进行服务的CPU并不是固定的,将TEE侧对REE侧的负载均衡影响减少到最小。

缺点:

  • 所有安全服务的负载只体现在SSA的线程,而无法体现在发起请求的线程上;导致其所在CPU的负载会有跳变现象;
  • 由于采用队列方式,只能串行处理安全服务请求,性能会有影响;
  • SSR一般有同步和异步之分,在此方案中需要软件针对性设计;
  • 如果TEE有自调度行为,而不是由REE事件触发。那么在处理SSR时,TEE内部可能会切换至其他任务,然后再切换回处理SSR,则SSA所体现的CPU运行时间不仅仅是SSR的处理时间,也包括了TEE其他安全任务等的处理时间。

这里写图片描述
SMP方案框图

为实现目标2,上述方案的一个增强方法就是将SSA扩展到每个CPU,即每个CPU各有一个SSA。各个CPU上发起的SSR都由本CPU的SSA处理。
此方法的一个优点就是将原本SSA的负载可以分散至多个CPU;缺点是对TEE有负载平衡的需求。


2.2 TEE SMP

从REE切换至TEE,一般有如下2种方式:

  • SMC指令
  • 安全中断

对于目标1,由于REE只会在一个CPU发起请求,同时刻只会在一个CPU上发起SMC;
而SPI一般是路由给CPU0,所以CPU0有可能会经常切换至TEE。

假设SSR是在CPU1上发起且正由CPU1在TEE中处理,此时一个SPI被触发而被CPU0响应并被处理,则此时刻TEE占有2个CPU。一种选择是TEE收到中断后,将中断事件路由给CPU1,由CPU1处理中断;或者直接由CPU0处理此中断。2种处理的差别体现在计算CPU负载上。

可见对目标1和目标2,TEE都需要实现类似的功能,以便负载均衡。


2.2.1 TEE 调度行为

如果TEE支持SMP,则一般的行为可能如下:

  • TEE在所有CPU处于idle状态;REE接管所有CPU;
  • 某个CPU(比如CPU1)上,REE触发事件,切换至TEE;
  • TEE响应事件,分析事件,并需递交给特定的任务(比如T1)进一步处理;
  • 调度器选择合适的CPU(Proper CPU, PCPU), 并将T1压入PCPU对应的Runnable queue(Rq)中。此处PCPU可能为CPU1,也可能是其他CPU;
  • 如果PCPU正处于”TEE idle状态”,则CPU1会发核间中断唤醒PCPU,以便PCPU调度T1;
  • 如果T1需要其他TEE的服务,则会唤醒服务对应的任务(比如T2,T3…),并由调度器按照步骤4~5的方式调度;
  • 最终,T1处理完请求后进入挂起状态,调度器会选择进入PCU的idle任务,此时PCPU进入”TEE idle状态”。

注:TEE idle状态:是指在TEE中,认为当前CPU是处于idle状态;但是此时CPU可能正处理REE任务。
选择PCPU,除了需考虑负载因素之外,还需要考虑Idle CPU因素。如果按照性能优先的原则,则需优先选择Idle CPU作为PCPU。

以上步骤没有考虑REE抢占TEE的情况。如果发生了抢占,那么什么时候才会又切换至TEE呢?有2种可行性:

  • REE在其idle时主动切换回TEE,即REE主动释放CPU后TEE才可使用;
  • TEE Tick:TEE支持Tick。如有TEE没有进入TEE idle状态,则TEE Tick会周期性产生安全中断,利用安全中断切换回TEE,并继续调度Runnable Task。

对于TEE tick方式,有可能TEE刚执行了一小段时间片就又被REE抢占的情况,导致颠簸。为解决此问题,可以将REE和TEE的Tick事件统一,可有如下几种方式:

  • TEE主控。保留TEE tick,去除REE tick,REE tick事件由TEE模拟,触发后作为主动事件上报给REE。缺点是对REE的修改比较大。
  • REE主控。保留REE tick,去除TEE tick,TEE tick事件由REE模拟并触发。缺点是TEE的调度行为被REE控制,是否符合安全要求?

以的难点在于如果支持NOHZ模式,怎么决定Tick是否能关闭呢?比如:

  • 如果TEE主控,则在TEE进入TEE idle时,此时应该是不能关闭Tick,因为REE可能正处于运行当中。当只有CPU真正进入idle时才能关闭Tick事件。

同样,在REE在REE idle状态时切换回TEE,此时可能还需继续处理TEE任务,CPU并没有真正idle。

当TEE占用CPU时,什么条件下才会切换至REE?有如下场景:

  • TEE处理完请求后主动切换回REE。有如下2个切换点:
  • TEE的请求分发任务。即接受请求,等待请求处理完后,此任务再主动切换回REE。
  • TEE idle任务。当TEE调度至idle时,主动切换回REE。此方式相对比较简单,但是计算负载时比较麻烦。
  • 非安全中断,导致切换回REE。

2.2.2 idle 管理

需辨别Idle CPU,即怎么去确认哪些CPU是Idle的。为了避免TEE/REE调度数据的交互,一个简单的方法就是利用TEE/REE的idle交互。
首先要选择当CPU 空闲时,CPU是在TEE还是REE?考虑到REE的完整性和复杂性,可以采用如下的idle流程:

  • 当TEE进入idle线程时,强制切换回REE。否则TEE的idle时间会占用REE所需要的CPU资源。
  • 当REE进入idle线程,处理完所需流程之后,在进入睡眠前(比如WFI)将自己切换回TEE,且告知REE已经进入睡眠。TEE则认为当前CPU是idle状态。
  • 当CPU从idle状态被唤醒后,TEE首先检查是否是被其他CPU的TEE唤醒。如是,则执行相应的TEE请求,比如如果是调度请求,则从运行队列中选取线程后并调度,线程执行完之后切换回REE,即步骤1处;如果是由REE唤醒,将CPU置为非idle状态后,直接切换至REE,按照REE的idle流程继续走下去。

经过上述的处理之后,TEE可以知道哪些CPU是idle,从而可以选择性的将安全应用分散到idle CPU上,大概的流程见下图,此图只涉及CPU idle部分。

这里写图片描述

从以上的分析可见,为保证idle状态的TEE和REE的一致性,有个隐含的约定:

  • 即TEE优先原则,只有当TEE在某个CPU上进入idle之后,即只有当TEE主动放弃此CPU,REE才能使用此CPU。

此原则可能导致REE性能的一些损失。

从上的原则也可知有如下的事实:

  • 只有当REE进入idle,TEE才有机会在此CPU上发起自调度。

当是REE因发起服务请求而主动切换至TEE时,可认为是REE主动放弃CPU,以将资源释放给TEE。此时的TEE被事件驱动,被动调度。

由于TEE的一些调度是发生在REE的idle期间,REE在计算CPU的占用率时,会将TEE的运行时间归并为idle时间,从而导致计算得到的占用率比实际值低。这些被“错误”划分的时间其实就是TEE的自调度时间。这个耗时是TEE的运行时间,REE的idle时间,将来是否需要在计算负载时调整此时间,待考虑。

对于big.LITTLE架构,TEE在选择idle CPU时,是否也需要有偏向性?待考虑。

由于CPU占用率不够精确,会影响到“省电管理”章节所涉及的一些功能。


2.2.3 TEE调度需求

  • 需能及时更新CPU的idle状态;
  • TEE与REE的idle状态同步机制;
  • 支持核间调度请求和响应;

3. big.LITTLE

如果按照GP规范走,TEE和REE的互访需要保证session的完整性。则功能性方面和具体的CPU架构无关。考虑的还是性能和功耗方面的问题。