OSDev Wiki — 初学者误区

2021年11月30日 · 387 字 · 2 分钟

很多初学者,刚学了点编程,会写 Hello World 了,就想着开发一个操作系统。这篇 Wiki 从多个方面,介绍了初学者在准备进行操作系统开发时,经常犯的错误。

本文翻译自 : OSDev Wiki:Beginner Mistakes .

由于译者水平有限,本文不免存在遗漏或错误之处。如有疑问,请查阅原文。

以下是译文。


一路指引你到这儿的,是**“编写自己的操作系统”**的想法!

我们的 Wiki ,旨在为你提供全程的帮助,指引,参考。

然而,对于我们的主旨,新手们往往会犯一些相同的错误或是存在相同的误解。这还不算太糟糕 ,其他人也犯过这些初级的错误,并且许多人在今后,还是会犯这些错。

本文的内容,就是确保在深入我们 Wiki 提供的信息之前,你清楚地了解你自己。

1 这 Wiki 不是什么

我们的 Wiki 看起来就像是一系列可直接复制、粘贴使用的教程,以及一个遇到问题、卡壳了,可以随时提问的论坛。

事实上,并不是。

我们非常希望,你能 自己的担子自个儿挑,在开始开发自己的操作系统前,先成为有经验的应用软件开发工程师。

我们也希望,你阅读一些关于操作系统设计的书籍,以及对你要开发的操作系统的目标平台,有所了解。不要把这个 Wiki 和论坛,作为你操作系统开发的完整指南。更不用说是通用的编程技能手册了。

在这里,你能找到的是,那些前人留下的文档。他们通过阅读技术文档,源代码,论坛帖子以及不断的尝试和 debug ,总结了这些文档。其中一些内容,是为了后人在开发操作系统的时候,可以直接查阅。另外一些,则是指向 Wiki 文章的链接,而不是对同一个主题重复阐述。

在开发你的操作系统的路上,我们能提供的,仅是一些提示 和 路标。这并不是一张抵达终点的全面的地图,这本就不是我们的目标。

如果你对 栈(stack)是什么,如何使用 调试器(debugger) 都不清楚,我们不会就这些问题单独解释。

你可以访问上述两个链接网址:你会看他们处理的是特定系统的问题,而不是像我们这样的通用性的阐述。

这不是我们 Wiki 的缺陷,是有意安排的。如果你寻求通用编程技能的启蒙(enlightenment),你应该访问像 StackOverflow 这样的通用编程网站,并在想成为操作系统开发人员前,先成为一名合格的软件开发人员。

我们的 Wiki 不会扩展成为一本面向入门人员的手册,因为这并不是我们的目标。解答那些已经准备好进入内核编程的人的问题,才是我们的目的。

1.1 一条硬道理

任何人,在没有几年的多种开发语言、多种开发环境的开发经验之前,都不应该考虑进入操作系统开发领域。数十年的编程经验,包括几年的底层(low-level)汇编或系统编程语言比如 C 语言的编码经验。这是进入我们操作系统开发主题,并理解我们所进行的工作的最低要求。

此外,近些年来,随着不同的体系标准,计算机和移动设备模型,外设,设计理念的不断发展,这些要求变得越来越现实。

对于像 Dennis Ritchie,Richard Greenblatt,Gary Kildall,或 Steve Wozniak 这些人,他们为当时的硬件(与现在的机器比起来简单多了),写一个简单的操作系统,是一回事。

他们既透彻了解这些机器,当时又没有任何具体的标准需要遵循,或是保证对已有设备的后向兼容。

但是,对于现在的硬件,这些条件已然不成立。

此外,他们每一个人,当时都是经验丰富的编程大师。

尽管如此,他们的系统还是只提供最基础的功能。

大量的其他工作(译者注:比如,文本编辑、代码编译、debug等),都是由大批的低级开发者,完成系统核心部分(内核,现代计算机术语)外围的系统支持功能的编码。

对于这条规则,存在个别例外情况,但是不多。

不要心存侥幸,幻想你在这千分之一的例外之列。

如果你心里有这种想法,建议好好了解一下 达克效应,再来考虑这个问题(译者注:达克效应,是一种认知偏差,能力欠缺的人有一种虚幻的自我优越感,错误地认为自己比真实情况更加优秀。简言之即:庸人容易因欠缺自知之明而自我膨胀。 Dunning 和 Kruger 将其归咎于元认知上的缺陷,能力欠缺的人无法认识到自身的无能,不能准确评估自身的能力)。

Oh ,需要强调的是,Linus Torvalds 并不是上述例外之一—— 当他在写 Linux 内核的时候,他已经用 C 语言写了好几年代码。尽管他达不到十年的编程经验,但是作为一个将个人兴趣作为研究课题的研究生,他有比绝大多数人更多的时间,投入到项目中。

不管怎样,1991年发布到 USENET 著名的Linux 0.0.1 版,不过只是一个轮转(round-robin )调度器,远未达到作为一个完整的操作系统的水平。

仅仅是达到这个程度,就花了他一年的时间。可想而知,开发一个完整的系统将是一个极其庞大的工程。

尽管我们这个 Wiki 的大部分贡献者,非常早就开始参与进来。但是对于我们大部分人来说,这恐怕导致缺乏经验的第一大原因。

这个群体的大部分开拓者,对于一个小操作系统的庞大规模和复杂性毫无概念;对于他们正在进入的项目一无所知。这是一个令人难以接受的苦果。

尤其是当时,根本没有像这个 Wiki 一样触手可及的参考资源。

我们不能强制你吸取我们的教训,但至少我们可以提醒你。

好了,不用太过于气馁。

我们想表达的意思,并不是你不能做。而是,如果你跟大多数人一样的话,那么你可能真的不合适。

对于一个如此巨大的项目,耐心,是另外一种优秀品质。

1.2 有关于xxx 的教程吗?

因为这里不适合初级开发者,对于哪里有某某技术相关教程,详细的技术文档,或易于理解的读物等这些问题,经常被问到。

然而,这些在这里都没有。

这些艰深的主题,难以通过散文的形式轻轻松松地描述清楚。就如同教一只猴子学习,即使有非常丰富的资料,仍然是难度相当大。如果你阅读官方文档有困难,这或许是一个提升的机会。

实际上,目前网上流传的大部分的教程,在某种程度上都是不够完备的。因此,你最好一开始就不要完全相信。

2 范畴(Scope)

2.1 截止期限

不论是为了学术研究,个人爱好,还是商业用途,操作系统开发都是需要时间的。Linux 内核用了整整一年专注的投入,才勉强可用。Linus Torvalds 做的仅是:模仿现有的、文档完备的用户空间程序,使他们在 Linux 上能跑起来,仅此而已。

另外,每一个像 Linux 这么成功的项目的背后,是数百个类似的项目,他们可能花费了一个人一整年时间,甚至更多,却连一个能工作的 shell 都没开发出来。

因此,首先需要对你将要做的工作,规划一个合理的路径(road map)。不要天真的以为,花 3 个月时间就可以开发出带 GUI 和语音识别功能的操作系统。操作系统开发没有捷径(RAD tools)。实际上,所谓的捷径,就是彻头彻尾的虚无( void ,对就是 C 语言里面的那个关键字)。

2.2 定义终极目标

当开始项目的开发,你需要评估你最终的目标,最终的用户,你项目开发的目的,等等。操作系统开发也是如此。对你的目标一个大体的想法和认识,会给激励和指引你向前。然而,当有更好的想法时,也不要拘泥于最初的目标。

不幸的是,大部分操作系统开发者,并不事先评估他们系统最终的目标。因此,他们不知道往哪个方向前进,只能不断地询问 “下一步该怎么办?”

特别需要提到的是,为了评估你最终的目标,你需要对现有的操作系统,概念(技术)上有整体的了解。

2.3 商业化操作系统开发

不要想着开发一个伟大的操作系统,让你一夜暴富。历史已经表明,最优秀的系统并未在商业上取得成功。相反,那些完全缺乏设计和激情的系统,却商业上取得了成功。因为精明的商业恰到好处,恰逢其时,恰好覆盖。

尽管,论坛里面关于“工作(Job)”的内容几乎空白,仅有为数不多的开发者的操作系统取得一定的商业成功。案例之一是 01000101 的“Drop-in Network Security” ,一个专为深度包解析设计开发的操作系统。

注意,这是为特定的应用场景开发的。想要以这种模式推销你的操作系统,你需要对应用领域有足够的理解,就像对操作系统开发一样,甚至还要更加精通。你需要同时擅长这两种系统的编码开发。专业性,是客户对你的期盼。

另一种可能是,向现在正在使用 MS-DOS 的公司,推销你的操作系统。这看起来稍微容易些,毕竟你无需开发编写最终的应用程序,但是你需要对客户的问题和需求做出专业和积极的响应。他们可能需要长期的支持。他们可能不喜欢你真正想要实现的功能特性。

2.4 假设你的系统无人愿意使用

与上面恰恰相反,有些人认为他们的操作系统无人愿意使用。因此,他们的项目代码乱七八糟,也未对重要的方面进行考虑,同时严重依赖一些奇淫技巧。最糟糕的是,他们没有考虑系统的易用性和扩展性。因此,他们的系统,最终成为了一个自我完备的封闭系统(self-fulfilling prophecy)。

事实上,尽管你的操作系统,在你测试机器之外的其他地方,跑起来的几率很低。但仍有非常的多优秀的操作系统,从这一步走出去的。

2.5 避免忽视

初学者经常问道“怎么做 X 最简单?”而不是“做 X 最好,最合适,最正确的方法是什么?” 这是非常危险的想法,初学者不把时间投入到掌握某事更好的实现上,却希望有可以简单复制粘贴的教程。

实际上,捷径终究是过于简单了,从长远看来往往是以带来更多问题结束。

因为初学者忽略了那些更优的选项,而且不清楚最好在什么时候进行切换。

是什么原因,使得大家都不愿意选择困难的路径呢?

常见的例子包括懒得使用跨平台编译器,不懂实模式非实模式保护模式长模式,跳得太快未来得及掌握所有重要的配置,完全用尽硬件的能力(尤其是在启动和初始化阶段用 BIOS 检测基础能力),依赖 BIOS 的非标准调用,不会在自己的操作系统上开发硬件驱动,把测试功能暴露到全局,使用平坦二进制文件而不是 ELF 格式,不懂可执行文件格式,打包文件,图形文件,文档文件等文件格式以及文件压缩算法,等等。

有经验的开发者选择其他高级的方法,你却不懂其中的奥秘。有些情况下,有经验的开发者使用较差的方法,因为他们能仔细地分析是当前场景下是否合适,以及他们清楚什么时候不该使用这种方法。

作为一个初学者或者新手,你可能对这些方法和技术不够透彻,不确定当前情景下较差的选择是否足够好。

记住,如果你反对某个方法,你应该清楚地知道其劣势和优势。而懒惰和忽视,只会导致问题。当遇到疑问,选择看起来保守的方案,而不是简单的。

3 设计

3.1 GUI 设计

从零开始,到你切切实实做与 GUI 相关的编码工作,往往需要好几年的时间。GUI 的外观最好置于次要位置,因为这些很容易溯及既往的修改( be changed retroactively)。决定 GUI 可用性的是 GUI 的功能特性。

如果你目标是创造一个更好的图形显示效果而不是一个操作系统,或许你该考虑实现一个X Window (译者注:Linux 下的窗口管理系统)而不是整个操作系统。

3.2 受欢迎程度

我的操作系统将会比 Windows,Mac OS 和 Linux 更受欢迎!

这是相当不可能的。要达成这一目标,需要大量的时间,资金,和学识。不是每个人都会下载你的操作系统:

  • 他们可能不知道操作系统是什么或如何安装
  • 你的操作系统可能存在安全风险
  • 你的操作系统支持应用程序较少
  • 你的操作系统不够实用(只有少量的命令行接口或者糟糕的 GUI)

你可能足够幸运,吸引到了一些用户使用你的操作系统。现在那些受欢迎的操作系统,唯一受到用户欢迎的原因是:几十年前,当市面只有为数不多的选择的时候,他们出现了,并解决了用户的需求。

3.3 内存使用量

我希望我的操作系统占用的空间不超过几 KB 。

很遗憾,这几乎是不可能的。一个操作系统只使用这点内存,几乎没法用。更别说要实现文件系统驱动,磁盘驱动,usb 驱动等等。如果你只想开发这么小的,不如开发 bootloader ,而不是操作系统。

你可以试试 Native Forth,他像一个带有内核,命令解释器,汇编器的微型操作系统。整个系统就一个二进制文件。部分内核甚至可以脚本化。你甚至不需要文件系统,许多 Forth 是直接编辑和加载磁盘扇区(译者注:Forth是六十年代末期,由查理斯·摩尔 发展出来在天文台使用的电脑自动控制系統及程序设计语言,允许使用者很容易组合系統已有的简单指令,定义成为功能较复杂的高级指令。Forth 以可延伸的词典为核心,采用两个堆栈为基础的高度模块化结构,是一种将解译器和编译器合并运用的双态系统。)。

唯一的一个不足是,Forth 对操作人员技能要求不低。在 Forth 上写程序,简直就像是另一个星球的事,你需要懂得各种底层基础。令人惊奇的是,有些 Forth 迷非常擅于写 Forth 解释器,却不擅于 Forth 编程。你需要成为一个优秀的 Forth 开发(编程)人员,才能理解系统的设计理念或是理解哪部分功能是不需要的。如果你达不到这个水平, 你的系统大小将超过你的需要。

构思如何缩减代码体积,是极其耗时的。 Charles Moore ,Forth 的创始人,写了一个只有 5行的 CAD 程序。当被问到写这 5行花了多长时间时,他答道:“接近 2 年时间!”

3.4 OS 模拟

我的操作系统上,可以运行各种平台的应用程序,从 Windows,Mac OS,Linux 甚至 PDP-11 的应用!!!

实在很抱歉,我要给你泼凉水,上述想法不成立。模拟单个系统平台,都可能需要花几年的时间,尤其模拟一个封闭的系统平台,比如 Windows 或者 Mac OS (Linux 或许这四个平台里面最容易模拟的)。Linux 上的 Windows 模拟器 Wine ,尽管从 1993 就开始开发,运行在用户空间,但是到目前为止,仍然没法运行 Windows 下的许多应用。

因此不要把你的注意力转向模拟其他系统,专注到你自己的系统上。好好设计,开发,与他成为朋友。

3.5 编程语言

一些编程语言非常适合写内核,其他语言就没这么适合了。详情可以浏览 使用 C 以外的语言

4 内核镜像

4.1 启动相关问题

尤其是在早期自己编写 bootloader 的阶段,有关启动的问题往往是因为,从硬盘中读取的扇区太少(不完整)。

解决办法是既可以是调整从磁盘读取的扇区数量,或者是设计一个bootloader/第二阶段 bootloader 建立文件系统。

5 疑难解答

在论坛或 IRC 提问之前,你应该尝试各种可能的办法,尽可能的尝试自己解决问题。当问题是 多重错误(triple faults) 或者 “随机“异常,我们常常误判问题的原因。 使用 debugger 或者 打印语句,定位具体准确的异常产生位置。使用模拟器、调试器(比如 Bochs/QEMU,GDB ),可以帮助定位难以追踪的问题。

如果你能从理论的角度描述问题,并尝试各种方法解决问题,其他人将更容易帮助你(即使你的理论可能不够准确,但是至少告知了别人你对问题的想法和你已经尝试过的解决策略,以及可能被你忽略掉的方法)。

通常,在提问请求别人帮助前,尽可能的尝试自己解决问题。在你发帖求助之前,不妨自问一下:我是否尝试了所有我能做的来诊断和解决问题? 在这个过程中,你会学到许多,你也可能自己就解决了问题(以及将来类似的问题),这是一件好事。

当你提问寻求帮助,请提供与你问题有关的代码。然而,问题也有可能与其他部分代码有关,因此也需提供访问你其他部分代码的方法(如果你的项目代码托管在 GitHub 或者 Bitbucket 上,那就相当简单你,当然也有可能是其他方式)。

至于论坛,请仔细阅读论坛规则。这些规则将提高你的发帖质量,并使得其他人更愿意帮助你。在 IRC 频道上,如果你提问题,不要期望在 10 秒钟或者是 5 分钟内就能收到回复。其他人也有他们的生活。如果你需要离开论坛去做其他事情,同时又不想错过论坛的讨论内容,论坛的 logs 可以方便你从头到尾了解。详情参阅 IRC 主题。

对于如何在提问时,如何成为一个更好的社区成员的更加深度的指导,请咨询 如何提问题 专题。这是一个非常优秀的读物,按理想来说,在任何地方提问之前,你应该先完整读一遍(并不长,非常值得阅读)。

6 推广

6.1 命名

命名通常是最后一个需要解决的问题,尽管我们都希望有一个很 cool 的名字。由于名字的 coolness 与个人品味有关,我们没法提供更多的帮助。此外,如果项目的名字取得与特定的功能特性相关,但是随着项目一路下来,这个特性并没有得到完美诠释,你可能会想要修改这个项目名称——你最初认为是核心的功能特性。如果仅是为了保持现有操作系统的名字不变,而不对系统的核心特性进行演进,这无疑是极其愚蠢的……

许多优秀的关于命名的信息,你可以从这个链接了解到。比较简单的方法是,以 <名字>OS 形式来命名(比如,JackOS,FredOS 等等),除非你有另外的项目伙伴。一个好的方法是,选择一个代号(比如, Longhorn, Chicago, etc.) ,并且选择一个在临近发布的时候,选择一个更佳的代号。

6.2 项目网站

许多操作系统开发的新手,早在有值得展示的完整成果之前,就创建好了网站。在没有想明白项目开发方向或没有输出一行代码,一张系统截图,可供下载的镜像等这些成果前,就创建网站并发布关于项目未来计划的夸张声明,是毫无价值的。

这样的网站,看起来是死的,并且损害个人的声誉。对外宣传你的网站或者外链到你的网站,却只能看到一个“欢迎来到 xxx 项目”的页面,只会让人们你的项目开始之前,就完全失去兴趣。

即使你最终,产生了某些值得展示的成果,你也将会要克服此前给大家留下的糟糕印象。

7 团队合作

7.1 社区项目

不要过高地评估,别人对你项目感兴趣的程度。即使那些更加成功的项目,往往也是只有一个人,或是两个人在开发。并且,往往不是因为缺乏需求。

Brooks 法则表明,向进度落后的项目增加人手会导致项目更加落后。唯一的办法是,把项目分割为许多独立的部分,各人独立分工,共同协作。祝好运。(译者注:Brooks ,即大名鼎鼎的《人月神话》作者 Frederick Phillips Brooks)

7.2 动员

你需要抓住机会(避免被遗憾的告知,你失败了):

如果你没有创建代码库,人们不会加入你的项目;他们会觉得你缺乏经验并且希望你的项目失败。

如果你缺乏设计,人们不会加入你的项目;他们看不到你的系统比他们自己的更感兴趣的地方。

如果你没有名誉高企,那些有经验的人会提防你并且缺乏信任来加入。

如果你没有项目管理技能,仅有的那些已加入的成员也会迅速退出,因为他们只会聚焦于讨论项目管理细节,而不是代码本身。

如果你存在上述几点中缺陷,仍然有人加入;那么说明这些人,是比上述列举出来的人更加拙劣的开发人员。


翻译:StrokMitream

扫码_搜索联合传播样式-白色版