Pi Zero 2W,AROS 这次的裸机移植,开机到界面能点,五秒。图形还只有裸 framebuffer,2D、3D 驱动都在写。
评论区有句话比文章本身重要:先能跑,再谈快。顺序是对的。
一个系统五秒开机,不是优化得好,是启动路径上没几件事。AROS 从 Amiga 那条线长出来,帖子里有人列了一串继承下来的设计——可拖动的屏幕、ram disk、逻辑 assign、共享库、资源和设备。列得挺全,但没说到点上。真正让它轻的,是 Exec 之上根本没有"服务"这个概念。全是库和设备,一大堆挂在链表上的结构体。
先贴结构体。这是一个共享库的全部头。
struct Library {
struct Node lib_Node;
UBYTE lib_Flags;
UBYTE lib_pad;
UWORD lib_NegSize; /* 负方向:跳转表 */
UWORD lib_PosSize; /* 正方向:数据 */
UWORD lib_Version;
UWORD lib_Revision;
APTR lib_IdString;
ULONG lib_Sum;
UWORD lib_OpenCnt;
};
后面跟两块内存。调一个库函数,就是把库基址塞进 a6,按负偏移跳过去。
move.l DOSBase,a6
jsr _LVOOpen(a6)
就这样。没有符号表,没有重定位,没有 PLT/GOT,运行时也不按名字解析。装载一个库=把内存挂进链表、把基址交出去。
这套形式我照着记忆写的,字段顺序可能有出入,但"负方向跳转表 + 正方向数据 + 一个基址寄存器"这个布局不会错。它是整套东西能轻的根。
设备也一样。
struct IORequest {
struct Message io_Message;
struct Device *io_Device;
struct Unit *io_Unit;
UWORD io_Command;
UBYTE io_Flags;
BYTE io_Error;
};
开设备是 OpenDevice,请求是一个带消息端口的结构体,发过去,回一个信号。设备列表启动时走一遍链表就搭起来了。没有 udev 那种冷插拔,也没有哪个后台进程在等着给谁发通知。
五秒的来源在这,不在什么编译选项。
下面是这篇我真正想说的部分。
评论区有人在追一件事:希望不同 ARM 移植之间保持应用二进制兼容。
这是往启动路径上塞"以后可能"。
二进制兼容不是白捡的。它意味着 ABI 冻死:寄存器约定不能动,结构体布局不能动,负偏移表里的槽位顺序不能动。任何能省一次跳转的改动,都得先回答"会不会弄坏某个两年前编出来的二进制"。你想让同一个应用在 AArch64 的各种实现上都跑,就得把新指令、新特性、新的调用约定全供起来。
最能说明问题的例子就在 AROS 自己身上。i386 和 x64 在这个项目里是两套独立架构。i386 的软件库最大,x64 到现在还不能直接跑 i386 的二进制,得靠一层模拟垫着——有人就是拿它去跑 Hollywood 那类 x86 程序。同一套 API、同一个项目、同一条 ISA 谱系,兼容还是没白捡到。x64 那边应用几乎每天都有移植进来,库在追,但那是重编,不是"同一个二进制直接跑"。
有人拿 RISC OS 在 Pi 上的向后兼容当正面例子。那例子恰恰是反的:老 ARM 核对老软件安全,新指令集一变,兼容就碎。这不是 RISC OS 的错,是"把二进制兼容当目标"的必然结果——每往前走一步,都要背一具尸体。
AROS 躲过这个坑不是因为它设计好,是因为没得选。从头写的,不依赖更老的 ARM 架构,所以没有一仓库必须继续跑的二进制拖着它。
我觉得二进制兼容被高估了。它服务的是已经编出来的东西,账单寄给还没写的东西。
真正的兼容在源码级和 API 级。把这两种兼容搅在一起,就是在替未来的维护者收一笔他根本不知道自己在付的税。
这段里我还有没想明白的地方。有人希望出现受 Amiga 硬件启发的定制 ARM 一体机。那个愿望我理解,但定制造型和标准化是反方向的:你越定制造型,越远离"同一个二进制到处能跑"。两件事不能都要,得挑一个。
回到图形。
只走 framebuffer、加速驱动还在写,有人看着觉得这是半成品。我觉得这是这个项目现在唯一正确的顺序。
现代桌面要让光标出现,得先有 KMS、有 Mesa、有合成器,中间还夹着好几层。任何一环没写完,你连画面都看不到,也就没法调试上面那几千行。没有画面,你连自己改错了哪一行都不知道。framebuffer 是那条没有中间层的路:把一块内存画到屏幕上,五秒钟就能用,出错看得见,改一行重编一次不心疼。
先有一个能干活的系统,加速以后再加。倒过来,是最容易把一个业余项目拖到烂尾的路径。
说句题外话——为什么我们这么怕让一个东西只做一件事。一个只画像素的 framebuffer,一个只存字节的 store。我们总觉得它不够,要加一层,再加一层。加完确实能干更多,也确实更没人能一口气读完。上面这段我自己写得有点念旧,扯回来。
所以这条就一句:凡是有人要把"以后可能需要"写进启动路径,先让他回答以后是谁、需要什么、不加会不会死。答不上来的,砍掉。
五秒开机不是奇迹,是没往里塞东西的结果。