如何制作一个操作系统(翻译版)
翻译地址: GitHub:How to Make a Computer Operating System-ZH-cn
目录
介绍
第一章: 介绍 x86 架构和我们的操作系统
第二章: 设置开发环境
第三章: GRUB 主引导
暂未翻译
Online book about how to write a computer operating system in C/C++ from scratch.
一本关于如何用 C/ c++ 从零开始编写计算机操作系统的在线书籍.
Caution: This repository is a remake of my old course. It was written several years ago as one of my first projects when I was in High School https://github.com/SamyPesse/devos , I'm still refactoring some parts. The original course was in French and I'm not an English native. I'm going to continue and improve this course in my free-time.
谨慎: 这个资源库是我以前课程的翻版. 它是几年前写的作为我高中时的第一个项目之一 https://github.com/SamyPesse/devos , 我仍然在重构一些部分. 这个课程最初的是用法语, 我的母语不是英语. 我打算在空闲时间继续改进这门课.
Book: An online version is available at (PDF, Mobi and ePub). It was generated using GitBook https://www.gitbook.com/ .
书籍: 网上版本可于 (PDF, Mobi 及 ePub)下载. 它是使用 GitBook https://www.gitbook.com/ 生成的.
Source Code: All the system source code will be stored in the directory. Each step will contain links to the different related files.
源代码: 所有系统源代码将存储在目录中. 每个步骤将包含指向不同相关文件的链接.
Contributions: This course is open to contributions, feel free to signal errors with issues or directly correct the errors with pull-requests.
投稿: 本课程开放投稿, 有问题可以随时通知错误, 也可以直接用 pull-request 更正错误.
Questions: Feel free to ask any questions by adding issues or commenting sections.
问题: 可以通过添加问题 (issues) 或评论 (commenting) 来提问.
You can follow me on Twitter @SamyPesse https://twitter.com/SamyPesse or GitHub https://github.com/SamyPesse .
你可以关注我的推特 @SamyPesse https://twitter.com/SamyPesse 或者 GitHub https://github.com/SamyPesse .
What kind of OS are we building?
我们在构建什么样的操作系统?
The goal is to build a very simple UNIX-based operating system in C++, not just a "proof-of-concept". The OS should be able to boot, start a userland shell, and be extensible.
目标是用 c++ 构建一个非常简单的基于 UNIX 的操作系统, 而不仅仅是 "概念验证". 操作系统应该能够引导, 启动用户界面 shell 并具有可扩展性.
Chapter 1: Introduction to the x86 architecture and about our OS
第 1 章: 介绍 x86 架构和我们的操作系统
What is the x86 architecture?
什么是 x86 架构?
The term x86 denotes a family of backward compatible instruction set architectures based on the Intel 8086 CPU.
x86 是指一组基于 Intel 8086 CPU 的向后兼容指令集架构.
The x86 architecture is the most common instruction set architecture since its introduction in 1981 for the IBM PC. A large amount of software, including operating systems (OS's) such as DOS, Windows, Linux, BSD, Solaris and Mac OS X, function with x86-based hardware.
x86 体系结构是自 1981 年引入 IBM PC 以来最常见的指令集体系结构. 大量的软件, 包括 DOS,Windows,Linux,BSD,Solaris 和 Mac OS X 等操作系统, 都使用基于 x86 的硬件.
In this course we are not going to design an operating system for the x86-64 architecture but for x86-32, thanks to backward compatibility, our OS will be compatible with our newer PCs (but take caution if you want to test it on your real machine).
在本课程中, 我们不打算设计 x86-64 架构的操作系统, 而是设计 x86-32 的操作系统, 由于向后兼容性, 我们的操作系统将与我们的新 pc 兼容(但如果您想在实际机器上测试它, 请谨慎).
Our Operating System
我们的操作系统
The goal is to build a very simple UNIX-based operating system in C++, but the goal is not to just build a "proof-of-concept". The OS should be able to boot, start a userland shell and be extensible.
目标是用 c++ 构建一个非常简单的基于 unix 的操作系统, 但目标不仅仅是构建一个 "概念验证". 该操作系统应该能够引导, 启动用户界面 shell 并具有可扩展性.
The OS will be built for the x86 architecture, running on 32 bits, and compatible with IBM PCs.
该操作系统将为 x86 架构构建, 运行在 32 位上, 并与 IBM pc 兼容.
Specifications(规范):
Code in C++ | c++ 代码
x86, 32 bit architecture | x86, 32 位架构
Boot with Grub | 使用 Grub 启动
Kind of modular system for drivers | 驱动程序的模块化系统
Kind of UNIX style | UNIX 风格
Multitasking | 多任务
ELF executable in userland
Modules (accessible in userland using /dev/...) | 模块(可在用户区使用 / dev/... 访问): :
IDE disks | IDE 磁盘
DOS partitions | DOS 分区
Clock | 时钟
EXT2 (read only) | EXT2(只读)
Boch VBE | 卷 VBE
Userland : | 用户:
API Posix
LibC
"Can" run a shell or some executables (e.g., lua) "可以" 运行 shell 或一些可执行文件(例如 lua)
Chapter 2: Setup the development environment
第 2 章: 设置开发环境
The first step is to setup a good and viable development environment. Using Vagrant and VirtualBox, you'll be able to compile and test your OS from all the OSs (Linux, Windows or Mac).
第一步是建立一个良好和可行的开发环境. 使用 Vagrant 和 VirtualBox, 您将能够从很多平台 (Linux,Windows 或 Mac) 编译和测试您的操作系统.
Install Vagrant
安装 Vagrant
Vagrant is free and open-source software for creating and configuring virtual development environments. It can be considered a wrapper around VirtualBox.
Vagrant 是一款用于创建和配置虚拟开发环境的免费开源软件. 它可以看作是 VirtualBox 的包装器.
Vagrant will help us create a clean virtual development environment on whatever system you are using.
The first step is to download and install Vagrant for your system at http://www.vagrantup.com/.
Vagrant 将帮助我们在您使用的任何系统上创建一个干净的虚拟开发环境. 第一步是在 http://www.vagrantup.com/ 为您的系统下载并安装 Vagrant.
Install VirtualBox
安装 VirtualBox
Oracle VM VirtualBox is a virtualization software package for x86 and AMD64/Intel64-based computers.
Oracle VM VirtualBox 是一个针对 x86 和 AMD64/intel64 计算机的虚拟化软件包.
Vagrant needs VirtualBox to work, Download and install for your system at https://www.virtualbox.org/wiki/Downloads.
Vagrant 先需要安装 VirtualBox, 将它下载和安装到您的系统, 下载地址: https://www.virtualbox.org/wiki/Downloads .
Start and test your development environment
启动并测试您的开发环境
Once Vagrant and VirtualBox are installed, you need to download the Ubuntu lucid32 image for Vagrant:
安装好 Vagrant 和 VirtualBox 后, 需要下载 Ubuntu lucid32 的 Vagrant:
Vagrant box add lucid32 http://files.vagrantup.com/lucid32.box
Once the lucid32 image is ready, we need to define our development environment using a Vagrantfile, create a file named Vagrantfile. This file defines what prerequisites our environment needs: nasm, make, build-essential, grub and qemu.
一但 lucid32 映像准备好了, 我们就可以使用 Vagrantfile 定义开发环境, 创建一个名为 Vagrantfile 的文件. 使用这个文件需要先准备以下环境: nasm,make,build-essential,grub 和 qemu.
Start your box using:
启动你的虚拟机
- Vagrant up
- You can now access your box by using SSH to connect to the virtual box using:
您现在可以使用 SSH 访问您的虚拟机, 使用:
- Vagrant SSH
- The directory containing the Vagrantfile will be mounted by default in the /Vagrant directory of the guest VM (in this case, Ubuntu Lucid32):
包含 Vagrantfile 的目录将默认挂载在客户 VM 的 /Vagrant 目录中(本例中为 Ubuntu Lucid32):
- cd /Vagrant
- Build and test our operating system
构建和测试我们的操作系统
The file defines some basics rules for building the kernel, the user libc and some userland programs.
文件定义了一些构建内核, 用户 libc 和一些用户空间程序的基本命令规则.
Build:
构建:
- make all
- Test our operating system with qemu:
使用 qemu 测试我们的操作系统:
- make run
- The documentation for qemu is available at QEMU Emulator Documentation http://wiki.qemu.org/download/qemu-doc.html .
- You can exit the emulator using: Ctrl-a.
qemu 的文档可以在 QEMU Emulator Documentation(qemu 模拟器文档) http://wiki.qemu.org/download/qemu-doc.html 中找到.
您可以使用: Ctrl-a 退出模拟器.
Chapter 3: First boot with GRUB
第 3 章: GRUB 主引导
How the boot works?
引导是如何工作的?
When an x86-based computer is turned on, it begins a complex path to get to the stage where control is transferred to our kernel's"main"routine (kmain()). For this course, we are only going to consider the BIOS boot method and not it's successor (UEFI).
当一台基于 x86 的计算机被启动时, 它会经历一段很复杂的路程, 以到达将控制权转移到内核 "主" 例程 ("kmain()") 的阶段. 对于本课程, 我们只考虑 BIOS 引导方法, 而不考虑它的后续方法(UEFI).
The BIOS boot sequence is: RAM detection -> Hardware detection/Initialization -> Boot sequence.
BIOS 引导序列为: RAM 检测 ->硬件检测 / 初始化 ->引导序列.
The most important step for us is the "Boot sequence", where the BIOS is done with its initialization and tries to transfer control to the next stage of the bootloader process.
对我们来说最重要的步骤是 "引导序列", 此时 BIOS 完成了初始化, 并试图将控制转移到引导加载程序的下一个阶段.
During the "Boot sequence", the BIOS will try to determine a "boot device" (e.g. floppy disk, hard-disk, CD, USB flash memory device or network). Our Operating System will initially boot from the hard-disk (but it will be possible to boot it from a CD or a USB flash memory device in future). A device is considered bootable if the bootsector contains the valid signature bytes 0x55 and 0xAA at offsets 511 and 512 respectively (called the magic bytes of the Master Boot Record, also known as the MBR). This signature is represented (in binary) as 0b1010101001010101. The alternating bit pattern was thought to be a protection against certain failures (drive or controller). If this pattern is garbled or 0x00, the device is not considered bootable.
在 "引导顺序" 期间, BIOS 将尝试确定一个 "引导设备"(例如软盘, 硬盘, CD,USB 闪存设备或网络). 我们的操作系统最初将从硬盘引导 (但是将来可以从 CD 或 USB 闪存设备引导它). 如果引导扇区在偏移量 511 和 512 处分别包含有效的签名字节'0x55'和'0xAA'(称为主引导记录的魔法字节, 也称为 MBR), 则认为设备是可引导的. 此签名(以二进制) 表示为 0b1010101001010101. 交替位模式被认为是对某些故障 (驱动或控制器) 的保护. 如果该模式被打乱或 0x00, 则认为该设备不可引导.
BIOS physically searches for a boot device by loading the first 512 bytes from the bootsector of each device into physical memory, starting at the address 0x7C00 (1 KiB below the 32 KiB mark). When the valid signature bytes are detected, BIOS transfers control to the 0x7C00 memory address (via a jump instruction) in order to execute the bootsector code.
BIOS 从地址 "0x7C00"(低于 32 KiB 标记的 1 KiB)开始, 通过将每个设备的引导扇区中的前 512 字节加载到物理内存中来物理搜索引导设备. 当检测到有效的签名字节时, BIOS 将控制传输到 "0x7C00" 内存地址(通过跳转指令), 以便执行引导扇区代码.
Throughout this process the CPU has been running in 16-bit Real Mode, which is the default state for x86 CPUs in order to maintain backwards compatibility. To execute the 32-bit instructions within our kernel, a bootloader is required to switch the CPU into Protected Mode.
在整个过程中, CPU 一直以 16 位实模式运行, 这是 x86 CPU 为了保持向后兼容性的默认状态. 要在内核中执行 32 位指令, 需要一个引导加载程序将 CPU 切换到保护模式.
What is GRUB?
什么是 GRUB?
GNU GRUB (short for GNU GRand Unified Bootloader) is a boot loader package from the GNU Project. GRUB is the reference implementation of the Free Software Foundation's Multiboot Specification, which provides a user the choice to boot one of multiple operating systems installed on a computer or select a specific kernel configuration available on a particular operating system's partitions.
GNU GRUB (GNU GRand Unified Bootloader 的简称)是 GNU 项目中的一个引导加载程序包. GRUB 是自由软件基金会 (Free Software Foundation) 的多引导规范的参考实现, 该规范为用户提供了从安装在计算机上的多个操作系统中引导一个操作系统或选择特定操作系统分区上可用的特定内核配置的选项.
To make it simple, GRUB is the first thing booted by the machine (a boot-loader) and will simplify the loading of our kernel stored on the hard-disk.
简单来说, GRUB 是机器 (引导加载程序) 启动的第一件事, 它将简化存储在硬盘上的内核的加载
Why are we using GRUB?
我们为什么要使用 GRUB?
- GRUB is very simple to use
- Make it very simple to load 32bits kernels without needs of 16bits code
- Multiboot with Linux, Windows and others
- Make it easy to load external modules in memory
GRUB 非常容易使用
使加载 32 位内核非常简单, 不需要 16 位代码
多引导与 Linux, Windows 和其他
便于在内存中加载外部模块
How to use GRUB?
如何使用 GRUB?
GRUB uses the Multiboot specification, the executable binary should be 32bits and must contain a special header (multiboot header) in its 8192 first bytes. Our kernel will be a ELF executable file ("Executable and Linkable Format", a common standard file format for executables in most UNIX system).
GRUB 使用多引导规范, 可执行二进制文件应该是 32 位的, 并且必须包含一个特殊的头(多引导头), 头 8192 个字节. 我们的内核将是 ELF 可执行文件("可执行和可链接格式", 大多数 UNIX 系统中可执行文件的通用标准文件格式).
The first boot sequence of our kernel is written in Assembly: and we use a linker file to define our executable structure: .
我们内核的第一个引导序列是使用汇编编写的:, 我们使用一个链接器文件来定义我们的可执行结构:.
This boot process also initializes some of our C++ runtime, it will be described in the next chapter.
这个引导过程还初始化了一些 c++ 运行时, 将在下一章中进行描述.
Multiboot header structure:
Multiboot 头结构:
- struct multiboot_info {
- u32 flags;
- u32 low_mem;
- u32 high_mem;
- u32 boot_device;
- u32 cmdline;
- u32 mods_count;
- u32 mods_addr;
- struct {
- u32 num;
- u32 size;
- u32 addr;
- u32 shndx;
- } elf_sec;
- unsigned long mmap_length;
- unsigned long mmap_addr;
- unsigned long drives_length;
- unsigned long drives_addr;
- unsigned long config_table;
- unsigned long boot_loader_name;
- unsigned long apm_table;
- unsigned long vbe_control_info;
- unsigned long vbe_mode_info;
- unsigned long vbe_mode;
- unsigned long vbe_interface_seg;
- unsigned long vbe_interface_off;
- unsigned long vbe_interface_len;
- };
- You can use the command mbchk kernel.elf to validate your kernel.elf file against the multiboot standard. You can also use the command nm -n kernel.elf to validate the offset of the different objects in the ELF binary.
您可以使用命令 mbchk kernel.elf 来根据多引导标准验证 kernel.elf 文件. 您还可以使用 nm -n kernel.elf 验证 elf 二进制文件中不同对象的偏移量.
Create a disk image for our kernel and grub
为内核和 grub 创建一个磁盘映像
The script will generate a hard disk image that can be used by QEMU.
脚本将生成一个可以使用 QEMU 启动的硬盘映像.
The first step is to create a hard-disk image (c.img) using qemu-img:
第一步是使用 qemu-img 创建硬盘映像(c.img):
- qemu-img create c.img 2M
- We need now to partition the disk using fdisk:
我们现在需要使用 fdisk 来分区磁盘:
- fdisk ./c.img
- # Switch to Expert commands 切换到专家命令
- > x
- # Change number of cylinders (1-1048576) 修改柱面数量(1-1048576)
- > c
- > 4
- # Change number of heads (1-256, default 16) 改变磁头数量(1-256, 默认 16)
- > h
- > 16
- # Change number of sectors/track (1-63, default 63) 更改磁道数目(1-63, 默认 63)
- > s
- > 63
- # Return to main menu 返回主菜单
- > r
- # Add a new partition 添加一个新分区
- > n
- # Choose primary partition 选择主分区
- > p
- # Choose partition number 选择分区号
- > 1
- # Choose first sector (1-4, default 1) 选择第一个扇区(1-4, 默认 1)
- > 1
- # Choose last sector, +cylinders or +size{
- K,M,G
- } (1-4, default 4) 选择最后一个扇区,+ 柱面或 + 大小{
- K,M,G
- }(1-4, 默认 4)
- > 4
- # Toggle bootable flag 切换启动的标志
- > a
- # Choose first partition for bootable flag 为可引导标志选择第一个分区
- > 1
- # Write table to disk and exit 将表写到磁盘并退出
- > w
We need now to attach the created partition to the loop-device using losetup. This allows a file to be access like a block device. The offset of the partition is passed as an argument and calculated using: offset= start_sector * bytes_by_sector.
现在我们需要使用 losetup 命令将创建的分区附加到循环设备上. 这允许像块设备一样访问文件. 分区的偏移量作为参数传递并使用: offset= start_扇区 * bytes_by_扇区计算.
Using fdisk -l -u c.img, you get: 63 * 512 = 32256.
使用 fdisk -l -u c.img, 你将得到: 63 * 512 = 32256.
- losetup -o 32256 /dev/loop1 ./c.img
- We create a EXT2 filesystem on this new device using:
我们使用以下命令在这个新设备上创建 EXT2 文件系统:
- mke2fs /dev/loop1
- We copy our files on a mounted disk:
我们复制我们的文件在一个挂载磁盘:
- mount /dev/loop1 /mnt/
- cp -R bootdisk/*/mnt/
- umount /mnt/
- Install GRUB on the disk:
在磁盘上安装 GRUB:
- grub --device-map=/dev/null << EOF
- device (hd0) ./c.img
- geometry (hd0) 4 16 63
- root (hd0,0)
- setup (hd0)
- quit
- EOF
- And finally we detach the loop device:
最后我们分离驱动循环:
- losetup -d /dev/loop1
- See Also
参考
- GNU GRUB on Wikipedia http://en.wikipedia.org/wiki/GNU_GRUB
- Multiboot specification
来源: https://www.cnblogs.com/LexMoon/p/How_to_Make_a_Computer_Operating_System.html