用于微控制器的虚拟机

2021-06-03 23:00:43

关于作者:Kasper Lund是一款编程语言和虚拟机退伍军人。他共同创立了Google的V8和Dart项目,并为JavaScript带来了适应性优化作为曲轴项目的技术领导。他住在丹麦的Aarhus附近,他是Toit的联合创始人。

我的第一个与低级系统软件的经验之一是从头开始构建自己的操作系统。放置我的代码 - 除了我的代码 - 在软盘上并从中启动,让我令人难以置信的兴奋。每当我无意中引入我的代码中的一些错误时,我略显不那么兴奋,导致我的计算机重启的三重故障。解决这些错误的试用和错误方法是有趣的侦探工作,但它并不是很富有成效。我觉得我的主要目的是我 - 确实是任何其他操作系统的目的是提供有关行为不端的软件的有意义,可操作的反馈,因此我大部分时间都摆脱了页面和描述符表来使用用于捕获的硬件提供的手段报告此类问题。

当第一个版本的Linux到达现场时,我才能建立自己真正有用的操作系统的工作,所以当我加入2006年加入谷歌时,我的兴趣已经转向事物的语言实施方面(Java, SmallTalk)和我愉快地花了旧浏览器中的JavaScript在浏览器中运行。这是关于软件,使开发人员能够做更多。我喜欢它。

我现在知道,启用软件开发人员绝对是我的事情,所以我很兴奋,看看我师父论文的主题的关心堂兄 - 事情互联网(IOT) - 一直经历了一个阶段,在那里专注于连接的阶段硬件与专注于软件提供的功能匹配。今天,很多开发人员都来自软件背景的IoT,他们选择了使它们富有成效的工具。它们选择像覆盆子PI等硬件,而不是高功率高效的微控制器,因为与Linux相结合,它为他们提供了高级和强大的工作基础。

如果您想为微控制器构建,您将被迫使用不同的,更加精致的开发工作流程。通过USB连接器焊接熨斗,C编译器和闪烁,如果您走该路由,请在菜单上。这可能是一种相当痛苦的经历,所以你自己就能支撑。简而言之,问题是在微控制器上,一切都是编译,链接和部署在一起使用真正的旧式工具的固件。改变任何东西意味着改变一切。所有不同的Codebase也会一起崩溃,因此如果您在代码的一部分中介绍了一个错误,那么它将破坏您的设备的整个功能,使您的设备在美好的一天中无用,并完全砖块下雨天。

现代计算机通过提供安全轨和故障隔离,实现了支持开发人员的操作系统,但这种支持和安全性尚未到达微控制器。现在是改变的时候了!

微控制器通常运行所谓的实时操作系统(RTOS)。它们运行这些剥离的操作系统的原因,这些系统不视义安全和稳健性是典型的操作系统依赖于硬件提供多个保护域和内存隔离。没有硬件支持,操作系统仅处理更简单的事件,如调度,同步和内存分配。

通过软件可以提供容错和隔离,但它需要一个软件层,该软件层屏蔽从底层硬件上运行的应用程序。该层通常称为虚拟机。

您可能已经听说过两种不同的虚拟机:模拟混凝土计算系统的那些和那些为特定类别的高级语言提供独立于平台的托管环境。由于其系统显着降低要求,我们专注于后一种类型,并设计了一个嵌入式虚拟机,在Java的传统 - 而不是Docker - 对于微控制器。它在eSP32芯片上从ESPRESSIF系统中运行,它增加了基本的FreERTOS操作系统,该系统捆绑在eSpressif的IOT开发框架(ESP-IDF)中,并以并排安全地运行独立的软件应用程序。

操作系统,虚拟机和编程语言的概念密切相关。从开发人员的角度来看,我们隐藏了操作系统和物理硬件,并给出了一个高级语言和环境。它就像现代Web浏览器如何让开发人员在Windows,Linux和MacOS中运行他们的应用程序在不同种类的处理器上,但这一次用于微控制器。 Toit Virtual Machine实现是我们的秘密酱,而且不仅仅是另一个操作系统。

操作系统是一种不适合语言的东西的集合。不应该有一个。 - Dan Ingalls.

Toit平台允许您并排在像ESP32这样的小型微控制器上并排安装独立开发的应用程序。虚拟机基于位和重定位信息流构建闪存中的应用图像的内置支持。重定位信息至关重要,因为它允许设备自由地选择闪存中安装应用程序的位置。我们没有使用虚拟内存的奢侈内存让系统认为应用程序始终从内存中的特定位置运行,因此我们必须将应用程序映像调整到闪存中的实际位置,即它最终存储在闪存中。

TOIT平台通过COAP通过COAP将应用程序图像流传输,并且设备一次接收32个单词并在将它们写入闪存之前重新安置它们。我们已经设计了它,所以我们永远必须在RAM中保持完整的形象,因为这是一个相当有限的资源。一旦完成所有应用程序映像位,我们使用校验和机制验证它们并最终提交标题,将应用程序转换为有效和可运行的功能。

典型的Toit应用程序图像总共约为30kB。绝大多数是以一种易于解释的形式描述单个方法行为的字节码。我们从程序的层次结构,类和接口中提取基本信息,并以紧凑的形式存储它们。同样,我们通过将方法统称为类似于ELF文件的.text段的某些字节的一个扁平字节序列来节省空间。图像中唯一的结构化对象是使用该应用程序的编译时常量。

Toit虚拟机最终与基于闪存的文件系统相同,具有动态重定位链接器,用于安装,升级和卸载可以直接从Flash运行的应用程序映像。应用程序完全分开,仅共享设备上虚拟机提供的内容。

出于稳健性和安全性原因,应用程序需要在您的微控制器上进行安全的环境来运行。应用程序启动时,Toit虚拟机会分配内存中的新进程结构。该结构包括与系统的其余部分隔离的对象堆,因此我们有一个可以保留在该特定进程中运行的代码分配的所有对象的位置。最小过程的足迹是4KB的RAM,包括物体堆。开始小,只在必要时长大!

设置过程后,虚拟机会告诉调度程序,该过程已准备好运行。该过程计划在固定数量的FreerTOS线程之上 - 一个用于CPU的每个核心 - 但您可以轻松拥有比线程更多的进程。在大多数情况下,我们在esp​​32上使用两个线程运行,因为它是双核处理器。线程具有与它们相关联的小,固定的执行栈,并且通过运行与它们相关联的应用程序一段时间来实现单个进程一段时间,直到线程被调度器预先按到另一个进程。具有完全隔离的地址空间的多个先发分便的程序。查看。

在进程中,应用程序包括多个轻量级任务,每个都有每个都有自己的执行堆栈。这些堆栈在对象堆中分配,它们按需增长,因此您不必预先采用或为您的任务选择正确的堆栈大小。该系统为您提供了处理。任务是协作计划的,因此只有在一个任务无法在同一过程中选择另一个任务并继续运行其代码时,才会才能进行进展。

此设置为您的应用程序提供了他们自己的孤立内存区域。这对于安全性和稳健性非常重要,但它也是支持将您的设备功能分解成有意义和解耦的模块化应用程序的完美方式。在内部,应用程序可以由基于任务的活动组成,阻止等待事件的操作非常便宜,因为您只阻止了轻量级任务,而不是整个过程或Freertos线程。这导致可理解的代码易于编写,避免对大多数异步操作的需求:

另一个好处是,该过程的对象堆可以是垃圾完全独立收集的。我们看到暂停时间小于毫秒,因为各个堆很小而且可管理。为复杂系统构建可扩展和复杂的垃圾收集器,如我们为JavaScript做的很有趣,但对于嵌入式设备来说,更好地设计系统,因此内存管理可以保持简单。真的小堆是一种很好的方式来允许这一点。

一旦您在微控制器上运行了很多少数流程,您希望确保他们不会不必要地消耗太多珍贵的资源:RAM。实现这一目标的最佳方法是确保虚拟机本身不会带有太多的开销并在执行代码时保持精益。

对于动态和灵活的编程语言,常见的开销来源实际上是用于使方法呼叫快速的优化技术。当虚拟机执行方法时,请调用:

它需要根据运行时类型的数月确定要调用哪个附加方法。从历史上看,通过使用方法查找表来优化,该表使用极快的散列来查找和验证右追加方法,但哈希表在运行时更新,并且必须存储在RAM中。为了避免太多的碰撞,它也需要具有相当不良的大小,因此这对于快速制作方法调用的唯一目的,这增加了相当多的开销。

在Google的V8 JavaScript引擎中,我们最终使用了更昂贵的方法,即关联所谓的内联缓存与您呼叫方法的代码中的所有各个位置。除此之外,这种内联高速缓存存储了在代码中的该点调用的最后一个方法,因为随着时间的推移,缓存必须在RAM中进行变化。它是快速的,但在记忆方面非常昂贵。

对于Toit,我们知道我们需要更好的东西,使我们能够直接从Flash执行高效的方法调用,没有RAM开销。我们首先在系统中进行深度首次编号,并指出,对于给定类的所有子类,将其普遍导致到连续数字。

这意味着方法由特定类编号范围内的类继承。例如,如果B类定义了一个名为Append的方法,则方法B.Append由[1,3]范围中的所有类别继承。如果F类还定义了Append方法,则F.Append方法仅适用于F的实例。您可以轻松关联与其不同实现的所有类编号的方法名称。通过此,您可以对所示的方法名称进行特定于特定的一维调度表:

所以要在对象上调用附加,您所要做的就是在表格中找到与您所在对象的类的类对应的表中的条目。这是一个廉价的恒定时间操作,表中的任何内容都需要由于查找而改变,因此表格在Flash中非常适合。桌子里有很多洞,这是浪费的,但如果你小心你可以通过重叠它们来实际上可以为其他这样的表一起使用这些漏洞并压缩您需要在闪存中存储的整体调度数据结构。

压缩技术称为基于选择器的行位移,如果完成,它会消除表中的所有不必要的孔。您可以在Karel Driesen的书中阅读更多关于它的信息,有效的多态电话。

有些人声称IOT中的S代表安全。随着微控制器的开发人员体验的当前状态,它也可以代表软件或简单性。他们都丢失了。开发人员为其在设备上功能提供了强大的基础。随之而来,他们将被赋予更快地尝试并更快创新。如果相同的基础允许简单,模块化软件替换复杂的单片固件并提供内存安全和沙箱加强安全性,我们还不接近将S放在IOT中吗?您的C编译器和原始的实时操作系统将不会让您在那里。

编程语言和虚拟机在这里有助于让您成为一个更好的程序员 - 以及通过我在这篇文章中概述的一些技术,即使在微控制器上也为您提供这些好处。 Toit是由谷歌和优步专家的软件平台专家团队构建,相信如果您在生产中更新软件,则不会经常这样做。问题不是你,这是你的平台。停止担心三倍的错误,并开始担心快速移动以保持相关性。

您可以阅读更多关于我们新语言的信息,甚至可以尝试一下,如果您在行动中看到其中一些。