当前位置: 华文星空 > 知识

在龙芯3A5000上运行Windows程序

2022-03-18知识

2022-03-18:本文所述操作步骤较为繁琐,另写了一篇操作简单的替代本文内容:

龙芯3A5000是龙芯最新的桌面CPU,它基于龙芯自主设计的LoongArch架构(指令集),性能接近市场主流CPU水平。因为各种操作系统和应用程序都与指令集相关,所以x86架构(指令集)的CPU就不能直接运行ARM架构(指令集)的应用程序,反之亦然。因此诞生了各种各样的二进制(指令)翻译技术,用于跨架构模拟运行其它平台的操作系统和应用程序,各种二进制(指令)翻译技术可以分为软件翻译、硬件翻译、软硬结合的翻译这三大类。我先简述一下二进制翻译技术,然后再给出在UOS和龙芯3A5000上运行任何Windows程序的方法。

二进制翻译技术简述

以软件方式进行二进制(指令)翻译必须存在一个宿主系统,模拟器程序在宿主系统上运行。比如各种游戏模拟器,用来在电脑上玩红白机游戏、街机游戏、PS游戏等,以纯软件的方式构建了一个虚拟的主机环境,让那些游戏程序成为缸中之脑,游戏程序执行的所有指令、请求的所有资源都是由翻译软件模拟出来的,但它以为自己是在真正的主机中运行。

模拟通用计算机的CPU和相关硬件环境要比模拟游戏主机复杂得多。这方面的代表软件,有开源的可虚拟多种架构的qemu、苹果的rosetta 2、以及微软Windows11在arm上模拟x86和在x86上模拟arm的技术等等。其中qemu可以在多种架构(指令集)之间相互转换,不但只支持动态翻译,而且性能最低,平均运行效率仅为原生性能的5%左右。苹果和微软都是一对一的专用翻译,且与操作系统深度结合,效率较高。

硬件翻译以Transmeta CPU为代表,它的CPU本身是一种「超长指令字」架构,但在指令译码的阶段,接受的是x86指令,然后把x86指令转换为它自己的指令来运行。这种方式使它的CPU看起来就是一块x86架构的CPU,并且不需要对电脑中的其它硬件进行模拟,各种支持x86指令集的操作系统和应用程序都可以在使用Transmeta CPU的电脑上直接安装运行。Intel/AMD现在的CPU其实也是硬件翻译技术的代表,它们内部是执行的「微码(类似于精简指令集)」,而对于的表现则依然是x86架构的处理器。

龙芯的LoongArch架构(指令集)则代表了第三个分类,即软件和硬件结合的二进制翻译方式。这种方式既有软件翻译的灵活性,又能接近或达到硬件翻译的效率,兼具二者的优点。龙芯的二进制翻译本质上也是软件翻译,但是对软件翻译中比较耗时的处理提供了专门的硬件指令来加速翻译过程,因此称它为软硬结合的二进制翻译技术。龙芯之所以不使用纯硬件的翻译方式,是因为我们必须建立自主的软件生态体系。如果像Transmeta那样对外表现为x86的CPU,那么它能直接运行的就只有基于x86的操作系统和应用程序,生存状况高度依赖于Intel和微软的态度,因此它虽然在Intel的诉讼中获胜,但却在Intel对市场的操作下惨然离场。

龙芯的LoongArch架构(指令集)本身是一种独立的,完善的指令系统,可以建立独立于x86/ARM之外的软件生态体系。 龙芯的二进制翻译技术主要是在LoongArch原生软件生态建设的初期,用于补充原生软件的不足,LoongArch架构和龙芯CPU的生存不依赖于Intel/ARM/MS/Google等主导的软件生态。 二进制翻译技术具有单方面的决定权,任何公司都没有理由阻止任何软件以二进制翻译的方式在某种原生不支持的架构上运行。即使软件开发商以检测CPU型号等技术手段阻止运行,那么以软件为主体的二进制翻译技术也能轻松解决这个问题,而固化在CPU硬件中的各种信息和特征则不可能像软件那样在线升级。以软件翻译为主体的二进制翻译,甚至可以针对特定程序把自己模拟成特定的CPU型号。

即使要翻译的目标架构频繁升级指令集版本,增加新的指令,不断推陈出新,对于龙芯来说,要模拟最新的CPU和指令集,也只是更新一下软件的事儿。而那些需要架构授权的CPU产品,如果没有购买到新版本的架构授权,那就无论如何发布多少个新款CPU产品,都不可能兼容新版架构的新指令。

龙芯二进制翻译系统的简单结构说明

龙芯的二进制翻译系统仍在开发当中,尚未公开技术资料,但当前已经有可以使用的测试版本。我仅仅根据对当前状态分析的结果,简单描述一下它的基本结构如下图,可能不太准确,也不够详细,意会就好。

基于龙芯LoongArch架构(指令集)的CPU,在运行原生的LoongArch指令集的程序时,不需要二进制翻译,可以直接运行。

在运行基于其它架构(指令集)的Linux程序时,由龙芯的二进制翻译模块对指令进行转译。程序对Linux的API调用,可以直接由操作系统本身提供支持。

在运行Windows(x86)的程序时,由于Linux系统本身不能提供Windows系统的API,因此需要使用Wine来提供对Windows API的支持。Wine是给Windows(x86)程序提供虚拟的API接口,而不负责对指令的转译,因此只用wine并不能在非x86的CPU运行Windows程序。 在x86的应用程序中,不但程序自身逻辑以及第三方库的二进制代码都是x86指令,而且用于调用Windows API的二进制代码也是x86指令,如果没有二进制翻译,在LoongArch上Windows程序甚至连程序入口的代码都不能执行,也无法调用Window API,程序自身的代码和第三方库就更不可能运行了。

操作系统API(应用程序编程接口)是由操作系统提供给应用程序的接口,在Linux上运行Windows程序时,假如调用读取文件数据的API,就可以由Wine给应用程序提供这个接口,但接口内部不再是Windows的代码,而是由Wine去调用Linux的相关接口来实现相同的功能,这就是对API的模拟。在应用程序读取到数据之后做的操作,就不在Wine的管辖范围内了。比如程序取得数据后可能加密解密、可能作为图像数据计算对比度、可能作为音频数据计算特殊音效……这些操作可能是由程序自身代码来完成,也可能是调用其它的库文件的接口来实现。 这些在Wine支持范围之外的代码,在x86架构(指令集)的CPU上是由CPU直接执行,在LoongArch架构(指令集)的CPU上,就只能由二进制翻译模块转译为LoongArch的指令来执行。

操作系统和应用程序对CPU指令的使用,是属于ABI(应用程序二进制接口)的一部分,ABI的层级很低,是二进制代码的规范。在基于LoongArch架构的CPU上运行x86程序时,就是由二进制翻译模块来处理对指令的转译,也就是对x86的ABI规范的模拟。不管是Linux还是Windows的应用程序,只要它不是LoongArch原生指令集的,最终都需要经过二进制翻译才能在龙芯的CPU上运行。

龙芯的二进制翻译模块当前和qemu一样也是只支持动态翻译,但效率比原生的qemu高出一个数量级。将来会支持动、静态结合的翻译模式,也就是程序运行时的动态翻译结果可以保留下来,下次运行相同的程序就直接使用翻译的结果,仅对程序运行时修改自身代码等行为需要动态翻译。这样可以降低翻译的CPU消耗,翻译运行的效率可以大幅度提高,预计运行x86程序可以达到80%的原生效率。这里的80%是指平均80%,而不像某些纯软件的翻译方案仅对特定类型程序翻译效率较高,就笼统地宣传「高效率」。

在龙芯3A5000上实战运行Windows程序

最简单的方式,是在使用3A5000的电脑上安装统信的UOS系统,然后等着UOS系统的应用商店中提供了什么Windows软件,就安装什么软件,可以无障碍,无门槛,无后顾之忧……可是Windows的软件千奇百怪,UOS的应用商店不可能提供所有的Windows软件,那么我们就需要动动小手,自己解决自己的需求。

目前只有UOS for 3A5000(体验版)系统中集成了龙芯的二进制翻译模块,而龙芯自己的Loongnix为什么反而还没有提供二进制翻译的支持呢?「体验版」这三个字很重要,是否稳定无关紧要。龙芯的Loongnix却是已经正式发布的产品,对于龙芯的行业用户来说,往系统中更新一个还没有开发完成的、可能不稳定的功能模块,大概不是什么喜闻乐见的事情。因此我下面就以UOS为例说明一下如何在龙芯3A5000上运行「任何」的Windows软件,「任何」是指可以尝试任何软件,但不能保证所有软件都能正常运行。

UOS中已经集成了龙芯二进制翻译模块,但要运行Windows软件仍然需要一个Wine环境。 UOS本身有多个版本的Wine,有经过深度/统信改良了效率和兼容性的deepin-wine,也有原生的版本,我们要使用deepin-wine。最简单的方式是从UOS应用商店中安装一个由Wine支持的软件,环境就自动配置好了。如果使用Loongnix或其它的系统,就需要手工完成这个过程,可能还需要从UOS复制一些文件和配置,比较麻烦。建议安装的软件是PhotoShop,因为PhotoShop是一个很大很复杂的软件,能够让PhotoShop正常运行的环境,就能让大多数软件正常运行。

UOS对Wine版软件的组织方式是给每个软件一套单独的Windows环境,也就是说每个软件包中都有配套的Windows、Program Files、ProgramData、User等系统文件夹。这些文件夹和软件本身,都被打包成一个files.7z文件,安装到「/opt/apps」文件夹下以包名命名的子文件夹中。软件首次运行时,files.7z被解压到「/home/用户名/.deepinwine/」文件夹中,并自动配置相关的运行环境。这种方式的好处是每个软件都相对独立,避免因某些共用文件的版本不同导致不能运行,坏处就是会增加许多额外的文件。但实际增加的文件体积并不会很大,因为前面说了Wine只是提供虚拟的API接口,因此包中的操作系统的DLL文件实际都是只有接口没有代码的「代理」版本,每个文件只几KB大小。系统DLL接口的功能是由Wine文件夹中的对应的.so文件来实现的。只有系统DLL之外的,软件自身的以及第三方的DLL文件才是「真实」的DLL文件。

在安装了PhotoShop(Wine)之后,在「/opt/apps/com.pscs6.deepin/files」文件夹中的files.7z和run.sh是我们需要用到的。

如果你已经运行过刚刚安装的PhotoShop,那么在「/home/用户名/.deepinwine」文件夹中会有「Deepin-CS6」文件夹,「.deepinwine」是隐藏文件夹,在Linux中文件(夹)名字前面加「.」表示隐藏,在文件管理器中看不到,需要手工在地址栏输入才能打开。它里面的内容如下:

dosdevices文件夹中的内容是虚拟硬盘盘符和com接口的链接文件,比如「c:」文件就链接到「drive_c」文件夹。「drive_c」文件夹是虚拟的Windodws系统的C盘,里面的内容一看就眼熟:

如果你要向这个由Wine虚拟的Windows环境中安装软件,或复制绿色软件来运行,就把「drive_c」当成Windows的C盘来用,都往里面复制就行了。其实直接使用PhotoShop的这个Wine环境文件夹也可以,但是为了避免一些麻烦,比如防止意外卸载了PhotoShop之后你放在里面的软件也被一同删除,我们还是最好自己弄个单独的环境。另外说明一下,这是32位的Wine环境,不能运行64位的Windows程序,如果要运行64位的程序,需要手工配置64位的环境,因为UOS还没有提供直接安装的64位Windows程序。

先把前面在「/opt/apps/com.pscs6.deepin/files」中看到的files.7z复制到「/home/用户名/.deepinwine」文件夹中,然后在files.7z上单击右键,在右键菜单中选择「解压到当前文件夹」。然后「/home/用户名/.deepinwine」下面就会多出一个「files」文件夹,把它改个名字,比如「MyGames」或者像我一样改成「Default」。这个文件夹中的内容和之前「Deepin-CS6」文件夹中的一样,但你不需要在这里运行PhotoShop,因此可以把「/home/guee/.deepinwine/Default/drive_c/Program Files」里面的Adoeb删除掉,节省一些空间。

再然后可以把下载到的绿色软件或者安装程序等都复制到「/home/guee/.deepinwine/Default/drive_c」中你喜欢的位置,最后把前面看到的「run.sh」复制出来进行一些修改,就可以运行它们了。当然也可以复制下面的内容,保存为一个扩展名为「.sh」的文件,注意要在文件属性的「权限管理」中设置「允许以程序执行」。

#!/bin/sh #在/home/guee/.deepinwine/下面你的Windows环境所在的子文件夹名。 BOTTLENAME = "Default" #Wine的版本 APPVER = "13.0deepin6~wine5" #要运行的程序的路径,你的drive_c文件夹就是c:/,后是相对于它的路径。 #注意Linux中的路径分隔符是/,而Windows中是\,这里按照Linux的规则写。 EXEC_PATH = "c:/ali213-AngryBirdschs/AngryBirds.exe" #启动Wine的脚本程序,是Wine自带的。 START_SHELL_PATH = "/opt/deepinwine/tools/run_v4.sh" #大概是这个程序关联的文档类型,这里设置为""。 export MIME_TYPE = "" #Wine的主程序,这是环境变量,在run_v4.sh这个启动脚本中会使用它。 export APPRUN_CMD = "deepin-wine5-stable" #语言环境设置 export PATCH_LOADER_ENV = "LC_ALL=zh_CN.UTF-8" #也是环境变量设置 export SPECIFY_SHELL_DIR = ` dirname $START_SHELL_PATH ` DEEPIN_WINE_BIN_DIR = ` dirname $APPRUN_CMD ` DEEPIN_WINE_DIR = ` dirname $DEEPIN_WINE_BIN_DIR ` #export WINEPREDLL="$ARCHIVE_FILE_DIR/dlls" #还是环境变量设置 if [ -n " $PATCH_LOADER_ENV " ] && [ -n " $EXEC_PATH " ] ; then export $PATCH_LOADER_ENV fi if [ -d " $DEEPIN_WINE_BIN_DIR " ] && [ " $DEEPIN_WINE_BIN_DIR " != "." ] ; then export DEEPIN_WINE_BIN_DIR fi #启动Wine,并指定由Wine启动的应用程序。 $START_SHELL_PATH $BOTTLENAME $APPVER " $EXEC_PATH " " $@ "

上面的「EXEC_PATH」后面的字符串就是你要运行的程序路径,我是从「游侠网」下载了一个绿色版本的【愤怒的小鸟】,其实看到文件夹名中的「ali213」应该就猜到了。这是绿色软件,如果要运行的不是绿色软件而是安装程序,过程也一样,只要把安装程序设置为要运行的程序就可以了。安装完成后,可以再修改一下运行脚本,把「EXEC_PATH」后面的字符串改为安装完成的程序路径。

安装程序运行时如果在Windows的桌面或开始菜单创建了快捷方式,一般情况下Wine就会自动帮你在UOS的桌面和开始菜单中创建对应的Linux格式的快捷方式。如果Wine没帮你创建,那么也可以自己创建,也就是编写一个扩展名为「.desktop」的文件放在桌面上,或者「/usr/share/applications」中(开始菜单中的程序快捷方式)。只是向「/usr/share/applications」这个文件夹写文件需要root权限,如果没有打开UOS的开发者模式,那么把「.desktop」文件放在「/home/用户名/.local/share/applications」中也可以。

「.desktop」文件的格式我就不详细说明了,在网上有很多资料。

至此,就可以尝试在龙芯3A5000的电脑上用二进制翻译功能运行任何的32位Windows程序了。可能成功,也可能运行出错。反正我已经成功安装、运行了很多小软件和游戏,比如7z、帝国时代2、仙剑奇侠传、愤怒的小鸟、CS……等等。并不只是小程序和老游戏可以运行,已经有一些网友测试了一些较大的和较新的软件,可以正常运行的程序很多。

补充:

本处补充的内容其实文中已经提到,甚至是黑体加粗的,但总有人假装看不到,那么这里我再集中说一下。

1. 龙芯二进制翻译和苹果罗塞塔2的异同:

原理都一样,实现有区别。

二进制翻译的基本流程是:读取可执行文件->解析指令流->把源指令翻译为目标指令->运行目标指令。中间涉及到寄存器的重定向、源程序(系统)虚拟地址到目标平台的物理地址转换、系统中断的模拟、各种API的调用等等,所有的二进制翻译都是这个样子。

罗塞塔2只运行苹果自己系统的软件,因此软件对系统API的调用,可以由系统自己提供支持。龙芯如果只运行x86的Linux软件,软件需要的API也可以由系统本身提供,这样和罗塞塔2就没有什么本质区别。

运行效率方面,罗塞塔2当前优于龙芯的二进制翻译,因为它支持静态翻译,也就是曾经翻译过的代码可以把结果保存起来。对于非动态代码,下次运行时可以运行之前翻译的结果,使部分代码的运行效率与原生效率相当。龙芯的二进制翻译有支持静态翻译的计划,但当前还没有完成,也就是基本上是和qemu差不多的纯动态翻译。但是,龙芯当前的纯动态翻译效率是qemu的10倍,这就是龙芯二进制翻译相关的硬件指令和对x86的一些硬件特性模拟带来的效果。如果继续优化,并且加上静态翻译,理论上最终效率会高于罗塞塔2。

罗塞塔2只支持从x86到ARM的翻译,龙芯的规划中支持x86、ARM、MIPS、RISC-V到LoongArch的翻译。如果以纯软件方式翻译,其实任何架构之间都可以实现互译,但龙芯的LoongArch当前只对上述架构进行了硬件加速的支持。

2. Wine和龙芯二进制翻译的关系:

Wine只是提供对Windows API的支持,不包含指令转译的功能,因此在ARM Linux需要E x aGear来提供二进制翻译功能,再加上Wine才能运行Windows程序,在龙芯LoongArch上也是一样,Linux上没有Wine时只能运行其它架构的Linux程序,加上了Wine才能运行Windows程序。

如果没有二进制翻译,就不可能在非x86架构的CPU上通过Wine运行x86架构的Windows程序。

3. LoongArch架构和二进制翻译的意义:

LoongArch在层级上,是与x86/AMD64、ARM、MIPS等并列的,是建设自主软件生态的基础。只有建设了自主软件生态,才能摆脱对国外巨头控制的软件生态的依赖。

LoongArch不是国内第一个自主设计的指令集,但LoongArch是国内自主设计的指令集中最适合通用计算机的,且有最完善的指令功能设计的,且有最强大的推广和行动能力的。

二进制翻译功能不是为了「融入国际主流」,而是为了在自主生态建设初期补充原生软件的不足。「融入国际主流」本质上是给国际巨头开疆拓土,然后有被卸磨杀驴的可能性。二进制翻译则完全相反,是在发展自身的同时借用其它软件生态的成果,只会强大自身,而不会反哺对手。