「DAY 01」- 从计算机结构到汇编程序入门

第一步、编写汇编程序(day-01.nas)

; hello-os
; TAB=4

; 以下这段是标准 FAT12 格式软盘专用的代码

DB 0xeb, 0x4e, 0x90
DB “HELLOIPL” ; 启动区名称可以是任意字符串
DW 512 ; 每个扇区的大小,必须是 512 字节
DB 1 ; 簇(Cluster)的大小,必须为 1 个扇区
DW 1 ; FAT 的起始位置(一般从第一个扇区开始)
DB 2 ; FAT 的个数(必须为 2)
DW 224 ; 根目录的大小(一般设成 244 项)
DW 2880 ; 该磁盘的大小(必须是 2880 扇区)
DB 0xf0 ; 磁盘的种类(必须是 0xf0)
DW 9 ; FAT的长度(必须是 9 扇区)
DW 18 ; 1 个磁道(Track)有几个扇区(必须是 18)
DW 2 ; 磁头数(必须是 2)
DD 0 ; 不使用分区(必须是 0)
DD 2880 ; 重写一次磁盘大小
DB 0,0,0×29 ; 意义不明,固定
DD 0xffffffff ; 可能是卷标号码
DB “HELLO-OS ” ; 磁盘的名称(11 字节)
DB “FAT12 ” ; 磁盘格式名称(8 字节)
RESB 18 ; 先空出 18 字节

; 程序主体

DB 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB 0xee, 0xf4, 0xeb, 0xfd

; 信息显示部分

DB 0x0a, 0x0a ; 2 个换行
DB “hello, world”
DB 0x0a ; 1 个换行
DB 0

RESB 0x1fe – ($ – $$) ; 使用 0x00 填充,直到 0x01fe 结束

DB 0x55, 0xaa

; 以下是启动区以外的部分的输出

DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 4600
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x[……]

READ MORE

「DAY 03」- 进入 32 位模式并导入 C 语言

昨天的启动区,虽然是 IPL,但是没有装载任何程序,今天将用它装载程序。
第一步、编写汇编程序

第二步、编译并运行程序
bootpack.c => (ccl.exe) => bookpack.gas => (gas2nask.exe) => bootpack.nas
bootpack.nas => (nask.exe) => bootpack.obj => (obj2bim.exe) => bootpack.bim
bootpack.bim => (bim2hrb) => bootpack.hrb[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「DAY 03」-

内容简介[……]

READ MORE

「z.Error List」-

内容简介[……]

READ MORE

「Linux」- 系统启动流程

问题描述
当修改内核参数、系统启动参数、错误操作后,我们经常会遇到一些问题: 1)当修改系统启动配置后,进行操作系统重启。然而此时操作系统没有如期启动,而是在屏幕上显示 grub> 提示符。如果不了解 GRUB 在系统启动流程中是如何工作的,就无法处理这种系统启动问题。 2)当升级操作系统内核后,进行操作系统重启以加载新内核。然而此时操作系统没有如期启动,而是在屏幕上显示 (initramfs) 提示。如果不了解在系统启动流程中内核是如何加载的,就无法处理该启动问题。 3)如果不了解系统启动流程,就不知道:如何在 BIOS 下从 GPT 中引导启动;如何从LVM中引导启动;引导加载程序(如 GRUB、LILO 等)参数含义以及如何配置;如何使用GRUB实现多操作系统的引导盘。
所以,熟知系统启动流程,对于理解原理、调整配置、排查问题、实现功能是非常有帮助的。
该笔记将记录:从 BIOS 上电开始 到 Linux systemd 运行 的整个过程,以及相关问题解决方案。
注意事项
本部分将描述系统启动流程。我们基于GNU/Linux环境,从启动按钮按下的那刻开始,到显示器终端提示用户登录结束。
本部分涉及极少的硬件知识。由于硬件不是我们的兴趣所在,因此我们在硬件方面投入的研究较少,自然也不是我们的专长(当然这不是在说硬件技术无聊)。对于硬件方面,我们只需熟悉它们的组成部分、工作原理即可(因为硬件的特性影响驱动及软件的实现,在软件中会看到硬件的相关概念)。
本部分笔记以理论知识为主。重点讲述系统启动流程,参与系统启动的组件,组建的详细信息,组件之间的协作。
本部分笔记存在完整性问题。由于知识体系之庞大,无法单次完成,需要要日积月累,不断完善,在此为内容完整性深表歉意。
本部分笔记存在准确性问题。此外由于我们知识有限,部分内容可能有失准确,我们会及时更正。
本部分笔记存在连贯性问题。由于篇幅有限且内容较多,所以本文负责概述流程,相关细节可参考附属章节。
解决方案
从程序执行角度观察
我们读过很多介绍系统启动流程的文章,多数基于1.BIOS => 2.MBR => 3.BOOTLOADER => 4.KERNEL => 5.INIT流程展开介绍。
通过该流程可以概览系统启动过程,但是却存在问题: 1)主引导记录(MBR)与引导加载程序(BOOTLOADER)的分界不明显。参与系统启动的是在 MBR 中的引导代码,而引导代码属于 Bootloader,引导代码是通过命令安装到 MBR 中。导致在讲述第二步的主引导记录时,需要涉及第三步的引导加载程序的引导代码,引发笔记结构混乱问题。
为了规避这些问题,我们决定从新角度来解释系统启动流程[……]

READ MORE

「Linux Boot Process and Shutdown」- System startup/Hardware initilazation (BIOS/System start)

当计算机开机或重置时,首先执行 BIOS (Basic Input/Output System) 或 UEFI(Universal Extended Firmware Interface)代码,运行系列被称为 POST(Power on Self Test)的诊断。
在按照固件配置顺序定位到软盘、光驱、硬盘等引导设备时,该阶段即将接近尾声结束。
此时 BIOS 开始检查可引导设备的引导签名(魔数),引导签名位于零号扇区,在第 510 与 511 字节包含 0x55, 0xAA 字节序列。
当 BIOS 找到该扇区时,将该扇区加载到内存 0x0000:0x7c00(segment 0, address 0x7c00)。但是,某些 BIOS 加载到 0x07c0:0x0000(segment 0x07c0, offset 0),虽然解析为相同的物理地址,但这可能令人惊讶。较好的做法是在启动扇区的开始里强制制定 CS:IP。
在加载结束后,执行被传递给已载入内存的引导记录。
相关链接
卓易云课堂:https://cloudclass.zqtong.com/hall[……]

READ MORE

「BIOS」- 基本输入输出系统

什么是“基本输入输出系统”?
BIOS,在出厂时已经安装在系统或服务器主板上的固件程序,在 ROM 中,使用汇编语言编写。
这里面保存操作系统开发人员常用的函数,使用 INT 指令调用,INT 指令的参数则为函数编号。需要查看 BIOS 官方文档以获取其用法。
在系统启动过程中的作用
在启动时,该程序负责硬件初始化。该程序主要工作是执行自检(POST,Power On Self Test),即进行硬件自身测试,在若干位置进行简单读写测试。
在执行自检过程中,主要会发生两类错误:

(1)致命错误:由于硬件自身问题导致;
(2)非致命错误:由于软件问题导致;

在自检中,主要执行以下任务:

(1)验证处理器的寄存器;
(2)验证自身代码的完整;
(3)验证某些基础组件:DMA,TIMMER,INTERRUPT CONTROLLER
(4)找到系统内存,获取大小并验证;
(5)初始化自身
(6)识别,组织,选择可以用于启动的设备;

在自检结束后,蜂鸣声表明结果,可以参考手册获取其含义。
它作为处理器与读写设备的中介,消除操作系统与软件需要感知处理器和其他读写设备细节的需要。如果任何磁盘设备或读写设备发生变更,只需要更新它即可。
它保存在 EEPROM (Electrically Erasable Programmable ROM) 或闪存中,它不能存储在硬盘或者其他设备中,因为它要管理这些设备。
在自检完成后,找到启动设备,加载主引导记录(MBR),执行其中的引导程序。
不是不能,而是不好
为什么 BIOS 不能直接加载 KERNEL,而需要 BOOTLOADER?
有 BIOS 提供的中断例程
[[https://wiki.osdev.org/BIOS#BIOS_functions|BIOS – OSDev Wiki/BIOS functions
]]===== 相关链接 ===== System Initialization (x86) – OSDev Wiki
参考文献
Wikipedia/BIOS BIOS – OSDev Wiki 6 Stages of Linux Boot Process (Startup Sequence) Stages of Linux booting process – explanation, step by step tutorial[……]

READ MORE

「UEFI」- Unified Extensible Firmware Interface

问题描述
BIOS,用于启动计算机,但是只是个过渡程序,并非标准化固件。因其易用,才存在如此之久。
在服务器领域中,BIOS 局限性较多。
解决方案
1998,Intel 开始着手 EFI(Extensible Firmware Interface)规范。EFI 最大的意义是建立一条标准,规定计算机固件的标准功能及行为,并且在设计时就充分考虑后续计算机的扩展需求,成为当下计算机标准。
2006,Apple 切换到 Intel 架构,并开始采用 EFI 技术;
2007,Intel、AMD、Microsoft、Apple,还有其他 PC 制造商,建立 UEFI Forum(UEFI.ORG),并将 EFI 改名 UEFI(Unified Extensible Firmware Interface,可扩展固件接口),就该规范达成一致。这是个由管理的全行业标准,并非仅由英特尔驱动。
特征优劣
与经典 BIOS 固件相比: 1)标准化; 2)使用 C 语言开发(经典 BIOS 使用汇编,开发维护难度较大),高效、低难度
Intel 和 Microsoft 试图将 OS 认证做到固件之中,不认证则无法运行系统。而 Linus 则表示不满,通过某些方法绕过该机制。 EDK2 庞大、繁杂,门槛极高,要掌握其中内容需要非常多的努力。 部分 EDK2 代码需要付费(部分开源,某些芯片初始化代码并不免费)
相关文档及其关系
UEFI Specification,其中规定计算机固件应该提供的标准功能,都是 C 语言风格的接口。Platform Initialization (PI) Specification,其中规定计算机平台分阶段初始化的标准流程以及各种细节说明。Advanced Configuration and Power Interface (ACPI) Specification,高级配置与电源接口特性,包括电源管理、硬件特性等内容,计算机硬件、软件相关的行为、流程、功能在该文档中得以详细描述。配合 USB4 DP Tunneling Compliance Test Specification,PCIE Specification 标准,等等,这些标准形成完成的标准系统,影响力巨大。
Intel 开源随后开源 EFI Development Kit II 来降低 UEFI Standard 的实现难度,即降低主板厂商开发的难度。而后,主板厂商、显卡厂商,还有其他硬件厂商就能够使用 EDK2 来开发固件和驱动。
符合 UEFI 规范的主板,都会提供一套基本功能,这些功能涵盖最常用的部分。此外,还允许厂商进行定制化开发,提供个性化功能,扩展性很好
参考文献
Do hard[……]

READ MORE

「UEFI」- 原理与结构

启动流程(广义)
What is UEFI’s boot sequence? – Stack Overflow
流程概述
在 UEFI 中,当运行时,按照如下程序来启动操作系统:

UEFI Firmware // 1)查找 FAT32 分区(通常 100M 左右,对大小无具体要求),并被是作为 EFI 启动项目而出现在启动菜单,
| // 2)当用户选择某个菜单项后,固件在其中查找 /EFI/Boot/Boot.efi(BootX64.efi)文件,并运行
| // 主板的 UEFI Firmware 仅识别 efi 格式的文件
|
V
OS Loader // 3)Boot.efi 加载 os-kernel.elf 文件,并加载到内存并运行;
| // 这里的 BootX64.efi 便是 OS Loader(负责运行操作系统),其为 efi 格式,由操作系统厂商实现;
| // 此外,UEFI 提供相关的服务(接口),供开发者在 BootX64.efi 中调用;
|
V
OS Kernel // 4)操作系统内核开始运行,后续工作交由内核来处理
// 此外,在 UEFI 内,仅提供硬件的基本驱动,想要发挥硬件的最高性能,需要在操作系统内安装相关驱动程序;

// 参考 UEFI Specification 文档,获取更多细节说明;

操作实践
Check if Your Computer Uses UEFI or BIOS [in Linux & Windows] FAT – ArchWiki
接下来,我们要在操作系统中开始探索 UEFI 相关内容,以验证前面的内容。
检查操作系统是否以 UEFI 模式启动:

// Linux

# ll /sys/firmware/efi
ls: cannot access ‘/sys/firmware/efi’: No such file or directory // 表示操作系统没有使用 UEFI 启动

# apt-get install efibootmgr
# efibootmgr
EFI variables are not supported on this system. // 表示操作系统没有使[……]

READ MORE

「Linux Boot Process and Shutdown」- Boot loader Stage 1(MBR loading)

在软盘中,整个引导扇区的 512 字节全为可执行代码(除了引导签名);在磁盘中,主引导记录的 0x0000 – 0x01bd 含有可执行代码,后面为四个分区表,每个分区表十六字节,以及两字节引导签名。
主引导记录代码执行的“环境”
这种早期环境是高度实现定义的(即由特定 BIOS 实现定义的),具有很多不确定性,切勿对寄存器的内容做任何假设:可能被初始化为零,也可能包含伪值。包括 FLGAS Register 与 SP Register,可能也没有有效的栈!唯一能够确定是 DL Register 存有引导代码(来自引导代码加载地方)。
当前处理器处于 Real Mode(除非你使用某些罕见 BIOS 帮你激活 Protected Mode),就是说需要编写代码激活以激活其他硬件的 Protected Mode,还要测试是否已经激活保护模式。这些都是主引导记录代码需要处理的问题。
主引导记录代码的工作任务
这些都是引导代码需要完成的工作,除此之外它还要完成其他工作(少量): 1)决定从哪个分区引导启动,或者显示菜单以让用户选择引导分区 2)确定内核位置以载入内存(要么检测文件系统,要么从固定位置加载) 3)将操作系统内核载入内存(需要磁盘读写) 4)启用保护模式 5)准备内核的运行环境(比如设置栈空间)
虽然不必按以上顺序完成这些任务,但是这些任务是必须完成的(历史遗留问题要求我们完成这些任务)。
完成引导工作任务的几种途径
第一种,极客式,MBR only 在主引导记录中完成所有事情。然而这几乎不可能,并且没有办法处理特殊场景以及显示错误信息(空间无法容纳更多程序)。
第二种,单阶段,MBR => Stub Program + Kernel 编写“桩程序(Stub Program)”,链接到内核镜像前面。引导记录加载内核映像(低于 1MiB 内存标记,因为在实模式下,这是内存上限!),跳转到桩程序,桩程序负责切换到保护模式并进行准备工作,正确跳转到内核。
第三种,两阶段,MBR => Stub Program => Kernel 编写分离的“桩程序(Stub Program)”(即不与内核链接),加载到 1MiB 内存标记以下,然后完成上述工作。
当前实现方案(以 GRUB 为例)
如果实现方式不同,那么 MBR 的工作内容也有所不同。
我们以 GRUB 为例,它提供 主引导记录代码 与 桩程序,主引导记录代码完成以下工作: TODO 整理 GRUB 主引导记录代码的任务
关于编写引导加载程序
棘手问题:由于 GCC 只能生成 Protected Mode 的可执行代码,所以用于该早期环境的的代码不能使用 C 编写。
在传统上,MBR[……]

READ MORE