在 ARM 上编写 OS 时,如何实现 x86 中的基本 I/O 功能?

How do I implement basic I/O functionality as in x86 when writing an OS on ARM?

我正在尝试从头开始编写一个简单的操作系统,以加深对 OS 和计算机工作原理的理解。我认为像实模式和保护模式这样的概念很复杂,而且在保持兼容性方面很重要。所以我想尝试在ARM平台上写这个。

我找到了一个关于编写 ARM OS 的很棒的教程:Writing a simple OS kernel。看了一大半,知道怎么用串口输出到QEMU终端,改CPU模式。然而,与'Operating System'和其他material上关于在x86平台上编写OS的正常感觉相比,我发现关于如何在ARM上实现这些东西的文字很少。

如何输出为真实'screen'?

写图形界面真的很辛苦,涉及到很多话题。但在 x86 中,我们有 BIOS 中断调用来将字符输出到屏幕。我使用 QEMU versional 来模拟一个 ARM 设备。现在我唯一能做的就是输出或输入到串口(UART)或从串口(UART)输入,并通过我自己电脑的终端与之交互。有什么办法吗?

如何接受来自设备的输入?

普通的ARM板有USB口可以接键盘。我知道键盘事件会引发中断。我如何在 ARM 平台中通过 USB 完成此操作?

如何制作文件系统?

由于几乎没有人在ARM设备上使用真正的'harddisk',所以我想在OS上选择SD卡(MMC)作为存储项目。我写了一个简单的文件系统模拟器,使用文件作为磁盘。所以我知道文件系统中的概念。但是SD卡的文件系统和普通磁盘的文件系统有什么区别吗?

如何开机?

我使用 QEMU,它使用特定的可执行文件名启动。看起来它只是 'loads' 整个可执行文件进入内存并开始执行指令。但在现实世界中,引导是一个复杂的过程。我在互联网上搜索并知道一个名为 uBoot 的引导加载程序。但是我感到困惑的是引导加载程序还需要从文件中找到内核映像,所以它应该具有访问文件系统的能力?

如何制作程序?

如果我完成以上所有事情。现在我的OS可以当玩具了。但是我可以在其中编写代码并编译它们吗?我在我的电脑上使用交叉编译器。但是新系统没有可用的编译器。即使我把更多的程序放进去,我怎么能把它们 'load' 放到内存中,就像 unix 调用 exec 那样?

这些问题现在让我很困惑,我找不到关于这些主题的好的答案或 material。那么我现在的思维方向是不是错了呢?还是为了学习,基于x86写一个更好?

谢谢。

How to output to real 'screen'?

取决于你连接的是哪种屏幕,如果你有某种图形卡,那么你需要该卡的文档(对于任何具有市场竞争力的产品,通常可以从卡制造商处获得签署 NDA),并写下你的自己driver据此。要创建完全成熟的图形 driver 还支持一些复杂的 API 像 OpenGL 和类似的期望编写自己的 driver 的努力在人- 年。

如果你有一些简单的 LED 显示器,或者一些能够以与 VGA 类似的方式运行的芯片,那么你可能只需很少的控制寄存器设置,将设备视频内存映射到 CPU 内存地址 space,然后将 bits/ASCII 写入该映射内存。

x86 BIOS 是旧 PC XT/AT 显卡的遗留物,当时确实存在很少的标准,例如 CGA -> EGA -> VGA,并且制造商非常合理地遵守这些标准使用通用 drivers。自 windows 时代以来,制造商更容易提供自己的闭源 driver 并以他们希望的任何方式创建自己的硬件(但保持 VGA-like 基本功能可用于 legacy/boot-up 原因 = 如今晶体管便宜并不是一个大问题,因此添加几千个晶体管来模拟 VGA 是可能的)。

How to accept input from devices?

同样,您需要先编写 USB driver,它将处理 ARM 设备端的 USB 总线,然后特定的 USB 设备需要它自己的 driver,具有常见的设备系列就像键盘是通用的,单个 driver 可以处理所有键盘。

How to make a filesystem?

又是一些卡 reader,你需要那个 reader 的文档,看看如何操作它,它很可能有一些 block-device-like API 可以访问卡,从那里它应该与任何其他 block-device 操作相当相似(如果你是 *NIX 熟悉我所说的“块设备”,数据块如扇区)。

But is there any difference between SD cards' filesystem and normal disks' filesystem?

作为 OS 创建者,你可以自己决定,你会从普通的事物方案中转移多少,但卡通常像旧硬盘一样有逻辑扇区(块),所以 driver 设计将任何细节隐藏在“块”后面 API 这对于 FS 代码来说是一样的。闪存盘 drivers 的主要区别在于,它们通常允许与某些文件系统合作以获得额外的额外功能,例如修剪空闲 space 以在删除块时节省写入。

How to boot?

在现实世界中,这取决于电路板及其芯片组、它如何初始化 ARM CPU,以及是否启动了某些固件以及从何处启动。可能每块板在某种 ROM 内存中都有某种“BIOS”,它会在定义的位置(通常是一些 disk-like 设备或​​有一些搜索进一步的用户代码(引导加载程序) net-boot 特征)。

How to make a program?

Even I have put more programs into it, how can I 'load' them into memory just as what unix call exec does?

嗯,这是您 OS 的责任,提供所有进程启动管理,并向应用程序提供已定义的 API。除非您想编写自己的编译器,否则您可以使用一些开源编译器,例如 gcc/clang,但这意味着您将必须实现大部分 *NIX OS API 服务。别担心,这并不难,例如 GNU 内核 "Hurd" 已经投入使用仅 27 年,而且它的形状很好...


说真的,正如 one-man 所示,您可以创建一个“玩具 OS”(除非您想在您的项目上花费数十年)。如果你只想学习一些关于 OS 体系结构和计算机的新知识,在我看来你正处于研究 linux 的来源并阅读一些关于该主题的书籍的地步,可能会给你在更短的时间内获得更多。