为默认不支持的设备(如 MacBook 12-inch)启用 Windows Connected Standby

2018-07-09 01:51:29 +08:00
 imbushuo

MacBook 12-inch 使用的 CPU / SoC 整一个都是为 Windows 设计的,然后 Apple 强行拿来往 macOS 上用。于是装了 Windows 之后我在想怎么样可以让它更好用一点。因为之前写了好几个面向不同平台的 UEFI & ACPI 实现,我就想干脆启动 Connected Standby 好了。

Note: AMD 很可能没有 Connected Standby。

在 MacBook 12-inch 上的效果

你可以看视频: https://twitter.com/imbushuo/status/1016015791827836929

问题


You cannot switch between S3 and Modern Standby by changing a setting in the BIOS. Switching the power 
model is not supported in Windows without a complete OS re-install.

实现

不同于 ACPI S3,S0ix 并不需要 ACPI DSDT 引入特殊的 ACPI 方法。自 ACPI 5.0 后,只需要在 FADT 表里标记 S0 Low Power Idle: EFI_ACPI_5_0_LOW_POWER_S0_IDLE_CAPABLE 即可。如果支持 5.0+,EDK2 的宏的 5_0 换成对应版本,不过总之都是 Flag 的 Bit 21。标记好后重新算一遍 FADT 表的 Checksum。核心实现如下:

if (Rsdp != NULL && XsdtHeader != NULL)
{
    UINT64* EntryAddress = (UINT64*)&XsdtHeader[1];
    UINT32 EntryArraySize = (XsdtHeader->Length - sizeof(*XsdtHeader)) / sizeof(UINT64);

    Print(L"XSDT: Count = %d\n", EntryArraySize);
    for (UINT32 j = 0; j < EntryArraySize; j++)
    {
        EFI_ACPI_DESCRIPTION_HEADER* Entry = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)EntryAddress[j]);
        if (Entry->Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE)
        {
            Print(L"%d: Not FADT table \n", j);
            continue;
        }

        if (Entry->Revision < EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION)
        {
            Print(L"%d: FADT revision is below ACPI 5.0 \n", j);
            continue;
        }

        Print(L"FADT table located. \n");

        // Iteration completed
        Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE*) Entry;
        break;
    }
}

if (Fadt != NULL)
{
    Print(L"FADT Flags: 0x%x \n", Fadt->Flags);

    if ((Fadt->Flags >> 21) & 1U)
    {
        Print(L"S0 Low Power Idle State Flag is already enabled on this platform \n");
    }
    else
    {
        Print(L"Setting S0 Low Power Idle State Flag \n");

        // Low Power S0 Idle (V5) is bit 21, enable it
        Fadt->Flags |= 1UL << 21;

        // Re-calc checksum
        Print(L"Setting new checksum \n");
        SetAcpiSdtChecksum(Fadt);

        Print(L"FADT patch completed. \n");
    }
}

然后启动系统安装,启动系统初始化即可。目前这段代码需要每次开机跑一次,我也没做 Chainload,比较麻烦。我暂时用 rEFInd 解决。未来会加入 Chainload 来启动 Windows Boot Manager。

代码

Github

Disclaimer

由于平台设计的不同和特殊设备的不确定性,我对这个项目在其他笔记本设备上使用造成的后果概不负责。

3430 次点击
所在节点    分享创造
6 条回复
hahasong
2018-07-09 09:19:01 +08:00
大神你的 12 寸 macbook 快被你玩坏了
mritd
2018-07-09 09:49:30 +08:00
大佬,请问这个语言有没有啥好的资料? 折腾黑苹果时候想学累着 后来官方文档撸不动了🙃
mcluyu
2018-07-09 09:50:48 +08:00
哇,第一次见有人折腾 win 下的 ACPI,腻害
hljjhb
2018-07-09 11:12:13 +08:00
厉害了 最好的 windows 笔记本—— macbook
LuvLetter
2018-07-09 12:18:18 +08:00
不过考虑到里面还有一张 BCM 的垃圾卡
Tink
2018-07-12 09:14:35 +08:00
真的是大佬……

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/469148

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX