Josh Triplett以一个“笑点”开始了他在PyCon 2015上的演讲:移植Python使其无需操作系统运行:他和他的英特尔同事让解释器能够在GRUB引导程序、BIOS或EFI系统上运行。连演讲的休息时间也没放过,他有很多有趣的要说的事情,还有许多让人大开眼界的演示。

Python在Boot Loader上运行的最初想法是能够测试硬件,像BIOS,可扩展固件接口(EFI)以及高级配置和电源接口(ACPI),而无需去写一些“一次性测试项目“程序集。传统来说,英特尔已经写了很多针对DOS(BIOS系统)或EFI系统的测试程序。无论是DOS还是EFI都不提供环境保护,这样程序就能够驻入在内存和硬件中去做他们所需的任何事情。

他不过是想用脚本来写测试代码而已,“因为这样比较有趣”。他既不想写太多的 C 语言代码,也不想像以前那样用那个能计算 C-类 表达式的 GRUB shell。 其实, 他说,“C 代码写的越少, 我就越轻松”。

随着时间的推移, 移植到 GRUB 中的 Python 已经变成操控硬件的利器。它又把我们带回到使用 PEEK 和 POKE 在 Commodore 64(or DOS) 上面操控硬件的美好时光。“那些事是现在的硬件设备无法完成的”他说。

GRUB中的PYTHON

BIOS Implementation Test Suite(BITS),正如其名,将会运行在多种固件上的GRUB中:32位BIOS或32/64位EFI。他使用原始的GRUB或GRUB 2。基于标准的PYTHON解释器(如CPython),但是他道歉道:它使用PYTHON2.7。这个工具的目标受众对这个版本的语言相当熟悉。如果不是这样,他更喜欢在以后迁移到Python 3.

有一个“读取-求值-输出 循环” 交互环境[read-eval-print loop (REPL)]让你完全访问Python语言。它包括Tab完成,历史记录,和行编辑。一个标准库的“大量碎片”已经被一直BITS上运行。最重要的是,这个项目已经添加了一些对平台支持的模块:CPU,SMP(symmetric multi-processing),ACPI,EFI以及其他。INTEL已经创建了一个测试集以及 使用Python写了使用以上模块的一些试探性的工具。

Triplett然后从幻灯片切换到了虚拟机的GRUB中运行一个Python解释器的提示界面。他输入了两句语句到解释器来展示它支持列表解析和任意大的整数(如:bignums)。

要获得一个python交互环境,GRUB需要调用一个单独的函数:

1
PyRun_InteractiveLoop(stdin, "<stdin>");

它会处理所有REPL[读取-执行-输出 循环],包括对输入的解析和执行、行编辑等等。
这两个参数简单的表明了在哪里获取输入 和 当发生异常时在traceback里要输出什么来当做源文件。但是想要能在GRUB里调用那个函数还有一些工作要做。

因为不能使用来自于 Linux 主机的工具链和特性,这个项目不能像平常那样安装和配置 Python。对于 GRUB 来说,没有 GNU 目标声明(例如:用于交叉编译的 cpu-vendor-od-triple)和目标头文件可以使用。因此,BITS 将所有的 Python 源文件添加到了 GRUB 的构件系统中。本质上说那仅仅是一些GRUB 添加 Python 所必需的 C 语言文件。通常,autoconf 将创建 Python 构件程序中的apyconfig.h 文件来说明哪些功能在平台上存在。相反的,这个项目手动的创建 apyconfig.h 文件大量“不,我没有这个功能”的配置参数和一小撮“是”的条目。

许多在 pyconfig.h 文件中被列出的功能是被(或不被)操作系统所提供的,但是在这种情况下是没有操作系统的。Python 的确需要最低限度的一些支持功能,以及一些额外被配置的特性。这个项目需要去做的是提供任何被渴望而又不存在功能。

CPython 需要什么

那么,什么情况下你真的需要运行 CPython?Triplett 提供的大量实例来证明什么时候需要运行 CPython。有一些平常的文件操作就需要了,比如说:使用 stat () 来确定一个路径是否包含 __init__或是文件中是否包含 __init__。增加 simpleisatty()(以位为单位,文件描述符是少于三则返回 true)好比经历一个 seek() 执行一样。为了支持那些功能,不得不添加一个简单的文件描述符表,因为 GRUB 的文件功能使用结构体指针,而不是描述符。

解析器把一个字符放回在输入流的时候,Python 也需要使用 ungetc() 。而不是在添加一个字符缓冲区的时候使用,即添加”快速 hack”来寻找后一个字符。添加开放式编码的 qsort() 时也一样一样要使用  ungetc();GRUB 不任何支持排序。

GRUB还没有支持的另一个方面是浮点运算。项目组发现了一个许可的浮点运算库FDLIBM。它没有使用任何浮点硬件加速,这在GRUB环境是非常有用的。这意味啊即使在固件没完全初始化浮点运算硬件时也能使用浮点运算。

在使用Python时,我们大量使用printf()和sprintf()。大部分情况,GRUB版本工作很好,但对“%%”(输出一个”%“)这种特殊格式还不支持。事实证明,Python频繁使用格式化的字符串输出。

在被发现和修复之前,怪异的BUG仍然存在。

这个工程还有一些性能问题需要解决。首先,启动时间出乎意料的长。对硬件来说,这是十分痛苦的事情,但是在 CPU 的模拟电路上也很糟糕(“我们不想花三天时间做引导”)。部分问题来自于 Python 的解释器,每次它读取一个数据的时候都要调用 usesungetc()。GRUB 没有太多高速缓存的磁盘,所以所有 I/O 端口直接访问磁盘。

通过加入对 .pyc (Python 字节代码)文件格式的支持,这个工程能够提前减少许多语法分析工作。主机的版本和 GRUB 的版本在同一时刻编译,用于 Python 文件在启动时的编译工作。

这做出了实质性的提升,但是由于stat()的原因,启动时间仍然有些慢。他说在Linux系统上,stat()仅花费几微秒的时间,但是BITS版本会花费几毫秒。增加对zipimport的支持能让工程把所有的.py文件打包放入一个单一的ZIP文件中来避免对stat()的调用。

这个工程希望做有历史和tab自动补全的REPL(读取﹣求值﹣输出循环),但是一般获得支持的方式是使用GUN的Readline library。这个库由有终端设备的POSIX(可移植操作系统接口)提供环境支持。开发者不想写一个“C代码文件”来支持它,所以他们用Python写了一个读取线支持来替代。CPython的PyOS_ReadlineFunctionPointer被称为一个使用C语言API的新Python函数的C函数集合。

为了能够使用其他的操作和多种的测试套件,仍迫切需要构建 GRUB 的动态菜单。GRUB 已经为设备提供了磁盘和文件系统像磁盘分区和 CD 驱动器(例如:“(hd0)”,”(cd)”)因此 BITS 增加了一个的“(python)”设备和一个工作起来像在 Linux 用户空间的文件系统(译者注:打不开请加梯子)。因此 Python 代码能访问任意的内存文件,例如在 (python)/menu.cfg 下的菜单配置文件,“即使我们没有写更多的C代码”,Triplett 说道。

访问硬件

既然目标是提供一个友好的测试硬件环境,Python 需要能够访问它。一个叫做“bits”的模块被添加进来提供访问各种硬件的功能,例如:CPUID,特殊模块寄存器 (MSRs),I/O 端口,和内存映射 I/O。他用几行代码展示了这些能力。

1
2
3
4
5
>>> import bits
>>> from ctypes import *
>>> c = bits.cpuid(0, 0)
>>> c
cpuid_result(eax=0x..., ebx=..., ecx=..., edx=...)

他引入ctypes模块,以便在下一部分演示中“操作原始内存片”。对于那些想要深挖一些的人来说,几乎所有演示都可以在这个YouTube视频的演讲中看到。cpuid()调用返回了CPU0的CPUID,他之后将其打印出来。他问:“这是不是很有趣?我们正从Python中得到处理器的寄存器信息。” 接着,他使用Python来解释这个结果:

1
2
3
>>> buf = (c_uint32*3)(c.ebx, c.edx, c.ecx)
>>> (c_char*12).from_buffer(buf).value
'GenuineIntel'

三个寄存器包含描述处理器类型的标识符。他使用ctypes模块中的类型,以字符串的形式重新解释这三个寄存器(按照之前的顺序)的信息,结果显示为处理器类型。

Intel希望能够测试高度并行化的系统,但GRUB只了解启动了的CPU的信息。所以BITS在系统中唤醒每个CPU,并把它们放入一个睡眠循环中,使用MWAIT(x86监视器等待指令)等待工作的到来。特定CPU有专门的唤醒函数和执行函数。

这个项目还准备用Python获取ACPI的信息和方法。这参考了ACPI组件架构 (ACPICA)的实现并把它加入BITS中。由于全部是C代码,所以增加了Python绑定。这一做法使得Python可以调用任意ACPI方法——只要先将参数转换成ACPI类型并将结果转成Python类型。他用了一个简单的Python程序演示了如何将虚拟机中所有设备的硬件ID显示出来:

1
2
>>> import acpi
>>> print acpi.dump('_HID')

Triplett声称他不会继续深入讲解BITS硬件探索的细节。他已经在其它演讲中更加详尽地解释过了。

英特尔也希望系统能使用这个固件而不是BIOS访问EFI。这种扩展名义上是指一切在EFI中都是”协议“,每一个都包含了原生c语言函数调用。要做到这样,通过libffi提供的外部函数接口被移植到GRUB并且添加了支持EFI调用转换的功能。使用这种方式和Python c类型的模块(Python提供的c语言类型的接口和函数)允许解释器访问EFI。他仅使用Python演示了访问EFI的方法:

1
2
3
4
5
6
>>> import efi
>>> out = efi.system_table.ConOut.contents
>>> out.ClearScreen(out)
[ which clears the screen ]
>>> out.OutputString(out, 'Hello world!\r\n')
Hello world!

访问EFI后,允许Python使用EFI文件协议去创建目录和写文件到EFI文件系统中。这是非常有帮助的,因为GRUB仅仅能够读文件。不仅仅如此,存在着图像输出协议(GOP)能够读写屏幕内容。正如他所解释的,幻灯片就是简单的图像,事实上是通过在笔记本上BITS和EFI显示出来的。在BITS的环境下,做出了这个幻灯片和demo,因此,事实来说,整个演示就是一个demo,他说这些话时周围响起了掌声。这样做是不需要任何一行新的C语言代码的。

最后他保存了认为最好的demo,并从EFI(可扩展固件接口)GOP(画面组)的帧缓冲区中作为Python启动,当他敲完最后的几行代码,很明显机器开始识别了,计算并显示了一个400×400大小的 Mandelbrot set(曼德布洛特集合)的灰度图片。他对周围鼓掌的人说:“在EFI图形协议中仅用八行Python代码显示了不规则图形(Fractal)”。大约要15秒来绘出图像,有点慢,他说,那不是Python的问题,而是因为使用纯软件进行浮点运算了。

在谈话最后,Triplett指出在BITS(后台智能传输服务)里没有中断处理的钩子函数(hook),但是这很容易就添加上的。他说,在像Mirage OS(和其它的“类似操作系统”)也能在BITS上添加Python代码,并且和这没有多大区别。“待办事件清单上的下一个有趣的项目”是添加Python绑定的EFI TCP网络协议和钩子到Python的socket模块,看看能否在那样的环境(BITS)下运行一个简单的HTTP服务(SimpleHTTPServer)。这样就能添加一个“网络REPL(web REPL)”到BITS环境了。

无需操作系统直接运行 Python 代码的更多相关文章

  1. Python--day02(编程语言、运行python代码、变量)

    day01主要内容回顾 1.进制转换: 二进制: 1111  0101 1010 十六进制          f        5      a 2.内存分布:堆区 和 栈区 外来人只能访问栈区的数据 ...

  2. SAE部署Python-让云端自动运行Python代码

    之前写过模拟登录新浪微博的帖子,然而我并没有去爬过微博的数据,觉得有点浪费,于是就想写一个代码来发微博.写完之后觉得如果能自动发微博就好了,但是我又不可能24小时开始(晚上12点后还会断网),也没有v ...

  3. 在notepad++中运行python代码

    #在notepad++中运行python代码 ''' 1.安装插件pyNPP, 2.允许插件pyNPP中的第一个和第二个选项即可,如果代码过少代码执行一闪而过,可能无法看到,可加入少量sleep时间即 ...

  4. 转-Pycharm中运行Python代码的几种方式

    转自:Pycharm中运行Python代码的几种方式 在pycharm中的Python代码运行会出现各种奇葩的问题,比如,密码输入时不显示或没有提示,给我们带来一些麻烦,下面介绍几种代码运行的几种方式 ...

  5. shell脚本命令 运行python文件&python命令行运行python代码

    单独的python文件运行的时候 报错: 在shell脚本中,运行shell脚本命令:在Python命令行中,运行Python代码.然而,“python hello.py”是一个脚本命令,不是pyth ...

  6. 无需操作系统和虚拟机,直接运行Python代码

    Josh Triplett以一个“笑点”开始了他在PyCon 2015上的演讲:移植Python使其无需操作系统运行:他和他的英特尔同事让解释器能够在GRUB引导程序.BIOS或EFI系统上运行.连演 ...

  7. jython实现java运行python代码

    Jython是一种完整的语言,而不是一个Java翻译器或仅仅是一个Python编译器,它是一个Python语言在Java中的完全实现.最近的一个项目需要将python代码转换成java实现,所以用了一 ...

  8. Python入门2(Python与C语言语法的不同、Notepad++运行Python代码)

    本篇博客主要介绍Python的基本语法与C语言不同的地方 [不同] 一.Python代码需要有严格的缩进,即C语言中所谓的良好的编码习惯.缩进不正确就会报错. 二.C语言需要圆括号 三.C语言每个语句 ...

  9. 命令行下设置 PYTHONPATH 来正确运行Python代码

    写Python程序,总要使用一些自己使用的库:在运行此类程序的时候,就需要先配置好 PYTHONPATH 环境变量:否则会导致找不到库错误. Windows下,可以写一个bat来简化配置: @ECHO ...

随机推荐

  1. k8s对接ceph存储

    前提条件:已经部署好ceph集群 本次实验由于环境有限,ceph集群是部署在k8s的master节点上的 一.创建ceph存储池 在ceph集群的mon节点上执行以下命令: ceph osd pool ...

  2. Oracle创建物化视图

    1.物化视图语法 create materialized view [view_name] refresh [fast|complete|force] [ on [commit|demand] | s ...

  3. tab选项卡--jq

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. redis_字符串对象

    Redis总共支持五种数据类型:string,hash,list,set及zset.这里介绍字符串类型的实现 首先了解字符串对象的结构 // redis对象内存分配,列出主要相关的属性 redisOb ...

  5. python生成exe文件

    安装pyinstaller pyinstaller支持python2和python3 命令行安装:pip install pyinstaller pyinstaller --icon=duoguan. ...

  6. linux下使用iptables统计ip/端口流量

    1.添加ip/端口的流量统计 入网流量: iptables -A INPUT -d 出网流量: iptables -A OUTPUT -s 2.查看流量统计信息 iptables -L -v -n - ...

  7. let,const,var

    1.const定义的变量不可以修改,而且必须初始化. 1 const b = 2;//正确 2 // const b;//错误,必须初始化 3 console.log('函数外const定义b:' + ...

  8. Python序列结构--字典

    字典:反映对应关系的映射类型 字典(dict)是包含若干“键:值”元素的无序可变序列 字典中元素的“键”可以是python中任意不可变数据,例如整数.实数.复数.字符串.元组等类型可哈希数据,“键”不 ...

  9. git 团队开发常用操作流程(适用于 gogs、gitlab、github)

    git 团队开发常用操作流程(适用于 gogs.gitlab.github) NO1 项目构建者 (1)在远程仓库创建仓库 (2)将伙伴添加到仓库合作者中(无先后要求) (2)cd 到项目将要存放项目 ...

  10. The test form is only available for requests from the local machine

    使用浏览器测试Web服务时出现提示“The test form is only available for requests from the local machine.”的解决办法 在Web服务项 ...