我最近一直在用 C 开发一个操作系统。但是我怎样才能关闭计算机呢?通过说“关闭计算机”,我的意思是强制关闭。
我如何在 C 内核开发中做到这一点?
任何帮助,将不胜感激。
1 回答
总结答案中的所有评论,使其保持不变:
处理电源管理和关机的现代方式(大约在 2020 年)是使用高级配置和电源接口 (ACPI),例如,请参阅ACPI和操作系统关机入门。
ACPI的历史
ACPI 是由英特尔、微软、东芝、惠普和 Phoenix 在 1990 年代中期合作开发的。在 ACPI 开发之前,操作系统 (OS) 主要使用 BIOS(基本输入/输出系统)接口进行电源管理以及设备发现和配置。这种电源管理方法利用操作系统本身调用系统 BIOS 进行电源管理的能力。BIOS 还用于根据探测输入/输出 (I/O) 发现系统设备和加载驱动程序,并尝试将正确的驱动程序与正确的设备匹配(即插即用)。设备的位置也可以在 BIOS 中进行硬编码,因为平台本身是不可枚举的。这些解决方案在三个关键方面存在问题。第一的,OS 应用程序的行为可能会受到 BIOS 配置的电源管理设置的负面影响,导致系统在演示或其他不方便的时间进入睡眠状态。其次,电源管理接口在每个系统上都是专有的。这要求开发人员学习如何为每个单独的系统配置电源管理。最后,各种设备的默认设置也可能相互冲突,导致设备崩溃、行为异常或变得不可发现。ACPI 的开发旨在解决这些问题和其他问题。这要求开发人员学习如何为每个单独的系统配置电源管理。最后,各种设备的默认设置也可能相互冲突,导致设备崩溃、行为异常或变得不可发现。ACPI 的开发旨在解决这些问题和其他问题。这要求开发人员学习如何为每个单独的系统配置电源管理。最后,各种设备的默认设置也可能相互冲突,导致设备崩溃、行为异常或变得不可发现。ACPI 的开发旨在解决这些问题和其他问题。
什么是 ACPI?
ACPI 首先可以理解为一个独立于架构的电源管理和配置框架,它在主机操作系统中形成一个子系统。该框架建立了一个硬件寄存器集来定义电源状态(睡眠、休眠、唤醒等)。硬件寄存器集可以适应专用硬件和通用硬件上的操作。标准 ACPI 框架和硬件寄存器集的主要目的是在不直接从操作系统本地调用固件的情况下启用电源管理和系统配置。ACPI作为系统固件(BIOS)和操作系统之间的接口层,如图0-1和图0-2所示,有一定的限制和规则。
来源:高级配置和电源接口 (ACPI) 规范,2019 年 1 月 6.3 版
这个答案提供了操作系统控制计算机电源和关机问题的历史背景,以及为什么需要这么长时间才能达到某个标准。报价:
一些历史...
在 1995 年和采用 ATX 标准之前,绝大多数台式 PC 都有电源开关,直接连接到电源,仅作为机械开关,打开时会中断电路。因此,软件不可能控制电源的状态。但这最初并不是什么大问题:在设计 IBM PC 时,存储介质(包括硬盘驱动器)没有缓存,所以当硬件告诉操作系统写入完成时,确实是这样。在 DOS 下,内核和 shell 协同工作以确保在显示 DOS 提示符时,所有缓冲区都被刷新;当软件缓存出现时,他们也坚持这一点(至少,表现良好的那些)。用户被教导退出程序,等待提示,并等待驱动灯关闭,然后再关闭系统电源。(他们可能还需要 PARK 驱动磁头,但那是另一回事了。)即使是 95 之前的 Windows 版本,用户在关闭系统之前也退出了 DOS。
Windows 95 和其他多任务操作系统改变了情况:它们在关机时没有“退出到 DOS”(因为它们不应该这样做,或者因为没有 DOS 可以返回),所以用户不能等待提示出现后再关闭。在大多数真正的多任务系统中,从来没有真正的静止状态,在正常操作中系统可以安全关闭电源;所以大多数多任务操作系统都有一种方式让用户说“我想关闭系统电源,准备这样做”,然后操作系统需要告诉用户何时可以安全关闭电源。这可以确保所有应用程序都已完成将用户文件写入磁盘,并且系统处于一致状态(此处忽略硬盘驱动器缓存...)。
关闭电脑
有两个特性将系统电源置于操作系统控制之下:一方面是 APM,另一方面是 ATX。APM 最初是为笔记本电脑设计的,它为软件提供了请求更改系统电源状态的机制:完全打开、待机、暂停或关闭。ATX改变了系统中的物理连接,让电源控制无处不在:它要求电源按钮不再是直接连接电源的开关,而是连接到主板,由主板控制电源本身。电源也进行了更改,使其始终提供少量电流,从而使系统处于“软关闭”状态,即有足够的能力在请求时再次自行重新开启。
您可以在 Shutdown 中看到使用 APM 关闭 PC 的示例,这是一个为 DOS 编写的小型汇编语言程序。Windows 95 等操作系统(安装了 APM 驱动程序)也会做同样的事情。
看到 APM 和 ATX 在 90 年代后半期逐步推出,并且看到系统突然获得了无需人工干预而自行关闭的能力,并且在按下某些系统上的键。这是个人电脑“成长”的又一个迹象(“真正的”电脑,即我当时心目中的 Unix 工作站,已经有一段时间了,就像 Mac 一样)。
为什么花了这么长时间?
所有这些都没有解决实际问题:
实现自动关机真的那么难吗?计算机花了很长时间才具有此功能的原因是什么。
如果你从一开始就设计它,实现自动关闭并不是那么难,而且在 PC 获得它的几年前,许多系统就已经存在这种能力。
[..]在九十年代初,尽管现在看起来令人惊讶,但对于计算的未来会发生什么,存在相当多的不确定性。苹果正在以更便宜的 Mac 卷土重来,工作站制造商正在发布低价系统(或者更确切地说,不是那么昂贵的系统),各种操作系统和平台正在争夺注意力(Be、RiscPC...)、IBM仍在推动 OS/2 和 Taligent,微软在推动 Windows NT 等。
最终,一个公司联盟自行“补救”了这种情况:英特尔和微软(当时称为 Wintel)。这始于九十年代初,但很长一段时间都没有完成。当 ATX 于 1995 年(由英特尔自己发布)发布时,专家们喜欢它,但不确定它是否能说服整个行业,尽管他们很快就被证明是错误的。不过,Windows 95 完成了交易,英特尔和微软成为了 PC 平台的定义者(特别是 PC 系统设计指南)。
这是90 年代的一项 Microsoft 专利,用于软件控制的计算机休眠,它与软件控制的电源管理有关。
实际上,软件控制的关机是关机的一种模拟,因为真正的关机发生在硬件电源实际关闭时。软关机有效地使计算机完全不做任何事情并尽可能减少功耗。因此操作系统确保结束所有进程并使 CPU 转到模拟关机的特定操作系统例程(注意:这种状态通常不能逆转,除非通过重启的硬件中断)。进行软关机的操作系统例程是否使用 ACPI 或其他方法/接口来模拟是另一个问题。
这篇文章粗略地描述了linux内核的关闭过程,以获得一个想法。
[..]无论如何,我们基本上有三个功能来勾勒关闭系统的过程
void kernel_halt(void) // which ends with a system in halt state void kernel_power_off(void) // which ends with a system powered off void kernel_restart(char *cmd) // which ends the system to yet restart it
这些功能非常简短,因此可以完整地粘贴在这里。他们的代码最好地显示了在内核中关闭的过程中采取了哪些步骤。(评论来自我,可能不是 100% 理想和正确的,请检查自己是否确定。这很简单,一试。
void kernel_halt(void) { // 1st step does: // a) call functions/callback registered to run at reboot/shutdown // b) set system_sate to SYSTEM_HALT // c) stop the userspacetool interaction // d) call device_shutdown() function kernel_shutdown_prepare(SYSTEM_HALT); // 2nd step: I think this is mostly a necessity for multi-cpu systems migrate_to_reboot_cpu(); // 3rd step: // syscore_shutdown - Execute all the registered system core shutdown callbacks syscore_shutdown(); // 4th messages pr_emerg("System halted\n"); kmsg_dump(KMSG_DUMP_HALT); // 5th call arch specific cpu-halt-code machine_halt(); }