Surface Pro 5 安装 Batocera.linux 并多系统共存
时间:2023年12月17日 人气:...

当时买的Surface Pro 5的硬盘比较小,只有128G,出厂预装的Windows10,几轮更新下来,C盘直接满了,啥也干不了,已经好几次执行恢复出厂了,然后运行Windows Update Blocker就可以又坚挺一段时间了。

现在的硬盘价格倒是下来了,最近入手了一块移动SSD,于是就想着为surface扩容了。当扩容后,windows系统就已经满足不了了,然后立马安装了Ubuntu,之后想着娱乐方面还缺点啥,于是上网了解了一下,发现原来还真有个娱乐系统:Botacera.linux。我直接发现,原来好多国产掌机就用的这玩意儿,简直。。。。

好了,下面说下surface使用移动硬盘安装多系统思路。

首先,为了能存在多个主分区,需要将SSD设置成GPT分区表,这样就理论上支持无限多主分区(MBR分区表只能支持4个主分区,所以逻辑分区总共算一个主分区)。

然后,需要创建一个EFI和ESP分区,可以根据自身是否需要安装windows系统决定,这里我无需。我将整个SSD分为了3个分区,第一个分区ext4文件系统安装Ubuntu(因使用频率并不高所以并不需要详细设置更多分区),第二个分区fat32文件系统放置Botacera启动文件(3G左右即可放下,4G当前版本就足够了),第三个分区NTFS文件系统用来放置游戏数据和windows系统共享数据盘等。

botacera的设计非常简单,它的内核也是linux,启动文件可以放在fat32文件系统上,所以常见的口号是将batocera装在u盘上,随时玩游戏啥啥啥的。紧跟着fat32分区后需要弄个分区放置游戏ROM、BIOS之类的文件,这个分区也是支持格式化成其它多种文件系统的,batocera有文档详细列举了每种文件系统可能存在的问题:

这里我选择了ntfs,一来batocrea基本没啥大问题,二来windows和ubuntu系统也可以直接使用。总结下来就是,直接把压缩包里的vfat.img镜像中的文件拖到fat32分区中中(该分区卷标名一定要为BATOCERA,全部大写字母,否则启动会因找不到该分区而失败),userdata数据分区放置网上下载的rom、bios集成包(不用管压缩包里那个userdata.img镜像,该分区卷标名可以为SHARE也可以不是),不同的解压工具可能看到的这俩压缩包名字不一样,但是fat.img那个基本大差不差。

下面用一张图说明botacera的架构,就能明白为啥可以这样做了:

因为我将ubuntu和batocera.linux是安装在移动ssd上的,不喜欢ubuntu那命令菜单,所以我在安装ubuntu时并没有选择以grup替换windows的boot manager菜单。这里我选择了一个开源的EFI程序:rEFInd。因为十几年前我在mac上就是使用的rEFIt来引导windows和macOS,对它比较满意,现在这个项目升级为rEFInd了,那我就继续选择了它。rEFInd还是图形化的启动界面,支持多种系统、工具、驱动之类的启动,还能定制主题。唯一有个比较尴尬的问题,那就是rEFInd的作者没有为这个程序实现签名,这样导致开启了安全启动(Secure Boot)的电脑就没法运行rEFInd了。所以要想能正常使用rEFInd就只能在EFI设置中关闭安全启动,安全自动这特性是微软推出的,关闭对其它完全没啥影响,可能有些电脑如surface之类的启动时就会出现个被解锁的图标。但这都不是事,对使用毫无影响,所以我还是坚定的使用rEFInd。

rEFInd支持使用refind.conf进行各种配置,使用移动SSD的,需要设置

scanfor internal,external,manual,biosexternal
scan_delay 3

设置delay是为了能更加好的检测到移动SSD,检查类型这里只填写external不好使,填写biosexternal才能识别到移动SSD中的系统,但也会出现一个新的问题:那就是每次启动会出现一个提示,必须按键才能下一步,这个目前还没选项屏蔽(也有解决办法,可见本文最末尾)。

然后等待几秒

就会出现启动菜单的图形化界面

关于这里的菜单,windows系统和Ubuntu系统他是可以自动扫描识别到并显示出来,但是botacera.linux使用的syslinux引导是无法自动识别的,这里需要手动添加,如:

menuentry "Batocera.linux" {
    icon /EFI/refind/icons/os_batocera.png
    volume 6C68D809-DB3F-4ED1-A74D-6C1ED41CB5EE
    loader /boot/linux
    initrd /boot/initrd.gz
    options "label=BATOCERA console=tty3 quiet loglevel=0 vt.global_cursor_default=0 mitigations=off"
}

其中的os_batocera.png是我自己给rEFInd中添加的图片,volume那串数字是这个分区的GUID(可以通过DiskGenius查看到)。启动文件和启动参数别问我咋知道的,我也是从这个分区的syslinux启动配置文件中复制过来的

当然,也可以手动指定Windows和Ubuntu的启动菜单,如:

menuentry "Windows" {
    loader /EFI/Microsoft/Boot/bootmgfw.efi
}

menuentry "Ubuntu" {
    icon /EFI/refind/icons/os_ubuntu.png
    volume 81376A1D-2B46-40EA-860B-86C60AED18F9
    loader /boot/vmlinuz-6.2.0-39-generic
    initrd /boot/initrd.img-6.2.0-39-generic
    options "ro root=UUID=0093d64b-9e72-4f1e-9759-75c0cec42a80 initrd=bootinitrd.img-6.2.0-39-generic"
}

不过,不推荐将windows和ubuntu手动来设置,因为尤其ubuntu内核是可以升级的,升级后就需要再改一次配置文件了,而它自动识别的话,他会自动将最新的一个内核版本作为启动菜单显示出来的,操作上更加灵活。


在启动菜单界面上选择Botacera.linux后就可以启动Botacera.linux了,这玩意儿还有启动的动画,效果看着还挺棒,进入后就会自动播放音乐,也挺燃的:

因为版权原因,botacera.linux官网并没有提供bios和游戏文件等的下载,这里可以网上找其它玩家提供的懒人包,下载后放到那个数据分区,botacera启动后就会自动检测到,这里不再详细分析了。

另外,这个系统他支持KODI,所以又衍生出了一个流派,那就是直播m3u8文件制作,用来观看影视节目。。。

botacera.linux也支持十几年前的老电脑,老电脑下载x86版本即可,但是目测后来某个版本开始x86就不太兼容老电脑了,所以老电脑不能成功运行时,不要怀疑其它,直接找着下载之前的某个版本进行尝试,一般尝试几个版本就能找到能用的版本。

有botacera.linux能成功启动时,有些时候会发现,它会将数据分区识别为不可写状态,一般这种情况多半是因为没有识别userdata分区,它就创建了ram临时性质的userdata分区供用户体验自己。遇到这种情况,可以有很多种解法:

    1. 如果你对linux相当熟悉,那么就可以使用mount指令重新挂载某个分区为userdata分区即可。可按F1进入文件管理界面,然后打开应用窗口,找到终端程序,进行分区挂载。

    2. batocera.linux也支持在图形化界面选择userdata分区位置:空格键--->系统设置--->存储位置--->选择列出来的磁盘分区即可,设置之后需要重启才能生效。batocera.linux会在选择的分区中创建一个batocera文件夹作为userdata分区使用,并不会干掉原分区数据,比较稳妥。

    3. 也可以手动修改batocera-boot.conf文件,将userdata分区进行指定。一般的教程都是将userdata分区紧跟着BATOCERA分区放置,并且两者都是在同一个磁盘上的安装思路。但是也会可能有遇到这样一种情况:BATOCERA分区在磁盘1上,而userdata分区在磁盘2上,这种情况,除了图形化界面选择之外,就可以在batocera-boot.conf中指定,如

sharedevice=DEV 84C0A434C0A42DFC

那串数字为要作为userdata分区的GUID(相对于windows系统的文件系统分区这个一般被称之为Volume ID,linux系的文件系统分区这个一般叫GUID)。


最后,再提一下那就是rEFInd也可以引导黑苹果启动:如先使用OpenCore安装macOS并能成功启动后,就可以切换为使用rEFInd引导,在rEFInd中添加一个macOS启动项,指向OpenCore。这样当在rEFInd中选择macOS后就会先启动到OpenCore,OpenCore再次引导启动macOS。

menuentry "macOS" {
    icon /EFI/refind/icons/os_mac.png
    loader /EFI/OC/OpenCore.efi
}


前面提到的refind启动的时候会有Legacy设备的警告,可以重新编译refind来解决。refind工程完全开源,完全可以按照自己的想法对它进行改造。下载rEFInd的源码,然后阅读BUILDING.txt文档就可以知道其编译方法。

按作者所述,refind支持两种方式编译:使用UDK环境编译和使用gnu-efi环境编译。这两种方法都是可以的,任选其一即可,这里我推荐选择gnu-eif环境。在ubuntu下编译非常简单,先下载好gnu-efi源码,然后执行make和make install就可以完成gnu-efi的安装。之后在refind源码目录下,修改Make.common文件:

# Comment out above and uncomment below if using locally-compiled GNU-EFI....
#EFIINC          = /usr/local/include/efi
#GNUEFILIB       = /usr/local/lib
#EFILIB          = /usr/local/lib
#EFICRT0         = /usr/local/lib

可以明显看到,需要打开下面四行配置的注释,并注释掉上面同名的四行配置,最后执行make就可以等待refind_x64.efi生成了。

回到上面提到的那个启动警告,阅读源码可知出现这个的流程为:

efi_main ---> WarnIfLegacyProblems ---> PauseForKey
//
// main entry point
//
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
    ......
    WarnIfLegacyProblems();
    ......

    return EFI_SUCCESS;
} /* efi_main() */

// Warn the user if legacy OS scans are enabled but the firmware can't support them....
VOID WarnIfLegacyProblems(VOID) {
    BOOLEAN  found = FALSE;
    UINTN    i = 0;

    if (GlobalConfig.LegacyType == LEGACY_TYPE_NONE) {
        do {
            if (GlobalConfig.ScanFor[i] == 'H' || GlobalConfig.ScanFor[i] == 'h' ||
                GlobalConfig.ScanFor[i] == 'C' || GlobalConfig.ScanFor[i] == 'c' ||
                GlobalConfig.ScanFor[i] == 'B' || GlobalConfig.ScanFor[i] == 'b')
               found = TRUE;
            i++;
        } while ((i < NUM_SCAN_OPTIONS) && (!found));

        if (found) {
            LOG(1, LOG_LINE_NORMAL, L"BIOS/CSM/legacy support enabled in rEFInd but unavailable in EFI!");
            Print(L"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy
");
            Print(L"(BIOS) boot options; however, this is not possible because your computer lacks
");
            Print(L"the necessary Compatibility Support Module (CSM) support or that support is
");
            Print(L"disabled in your firmware.
");
            PauseForKey();
        } // if (found)
    } // if no legacy support
} // VOID WarnIfLegacyProblems()

VOID PauseForKey(VOID)
{
    UINTN index;

    Print(L"
");
    PrintUglyText(L"* Hit any key to continue *", BOTTOM);

    if (ReadAllKeyStrokes()) {  // remove buffered key strokes
        refit_call1_wrapper(BS->Stall, 5000000);     // 5 seconds delay
        ReadAllKeyStrokes();    // empty the buffer again
    }

    refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
    ReadAllKeyStrokes();        // empty the buffer to protect the menu
}

所以,修改方法很简单,我将WarnIfLegacyProblems中调用的PauseForKey修改为调用一个新的函数PauseForKeyTimeout3S:

VOID PauseForKeyTimeout3S(VOID)
{
    UINTN count = 0;
    EFI_STATUS Status;

    Print(L"
");
    PrintUglyText(L"* Hit any key to continue *", BOTTOM);

    if (ReadAllKeyStrokes()) {  // remove buffered key strokes
        refit_call1_wrapper(BS->Stall, 5000000);     // 5 seconds delay
        ReadAllKeyStrokes();    // empty the buffer again
    }

    while (1) {
        Status = refit_call1_wrapper(BS->CheckEvent, ST->ConIn->WaitForKey);
        if (Status == EFI_SUCCESS) {
            ReadAllKeyStrokes();        // empty the buffer to protect the menu
            break;
        } else {
            if (count++ >= ((3 * 1000) / 100)) { // 3s
                Print(L"
");
                PrintUglyText(L"* Hit any key timeout *", BOTTOM);
                break;
            }
            refit_call1_wrapper(BS->Stall, 100 * 1000); // delay 100ms
        }
    }
}

这样之后,启动后还是会出现这个警告,可以按键立马取消,也可以等待3秒继续往下执行,从此不用再每次按一下键触发了。

热门评论