How to Make a Computer Operating System
如何制作一個操作系統(翻譯版)
原文地址:Github:How to Make a Computer Operating System
翻譯地址:Github:How to Make a Computer Operating System-ZH-cn
目錄
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, 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.
謹慎:這個資源庫是我以前課程的翻版。它是幾年前寫的作為我高中時的第一個項目之一,我仍然在重構一些部分。這個課程最初的是用法語,我的母語不是英語。我打算在空閑時間繼續改進這門課。
Book: An online version is available at http://samypesse.gitbooks.io/how-to-create-an-operating-system/ (PDF, Mobi and ePub). It was generated using GitBook.
書籍: 網上版本可於http://samypesse.gitbooks.io/howtocreateanoperating-system/ (PDF, Mobi及ePub)下載。它是使用GitBook生成的。
Source Code: All the system source code will be stored in the src directory. Each step will contain links to the different related files.
源代碼:所有系統源代碼將存儲在[src](https://github.com/samypesse/howto - make -a- computer - operating-system/tree/master/src)目錄中。每個步驟將包含指向不同相關文件的鏈接。
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 or GitHub.
你可以關注我的推特@SamyPesse或者GitHub。
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 Makefile defines some basics rules for building the kernel, the user libc and some userland programs.
文件Makefile定義了一些構建內核、用戶libc和一些用戶空間程序的基本命令規則。
Build:
構建:
make all
Test our operating system with qemu:
使用qemu測試我們的操作系統:
make run
The documentation for qemu is available at QEMU Emulator Documentation.
You can exit the emulator using: Ctrl-a.
qemu的文檔可以在QEMU Emulator Documentation(qemu模擬器文檔)中找到。
您可以使用: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: start.asm and we use a linker file to define our executable structure: linker.ld.
我們內核的第一個引導序列是使用匯編編寫的:start.asm,我們使用一個鏈接器文件來定義我們的可執行結構:linker.ld。
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 diskimage.sh will generate a hard disk image that can be used by QEMU.
腳本diskimage.sh將生成一個可以使用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