操作系统是如何开发的?
你可以使用 C(或者实际上是)C++、汇编语言以及 Ada、Fortran、Pascal 等任何编程语言来开发自己的操作系统。
但你必须在某些地方使用汇编语言。
汇编语言简介
汇编语言是一种低级编程语言,你可以用它来控制一切,例如向 CPU 寄存器添加内容、控制内存等等。
我如何开始开发操作系统?
首先,你必须了解你所用编程语言的所有知识,例如指针、函数(在这里我想使用 C++)。
其次,你必须对汇编语言有一些了解。
开发操作系统需要哪些工具?
开发操作系统必须具备以下条件:
1. 汇编器
汇编器会处理你的汇编代码,并生成低级输出,例如包含你对 CPU 寄存器控制的对象。
这里我想使用的汇编器是 nasm(netwide assembler)。
你可以从 http://nasm.us 下载。
2. 交叉编译器
为了开发操作系统,你必须有一个交叉编译器,因为你必须为操作系统的可执行格式来编译你的内核。
这里我使用的是 gcc(gnu compiler collection)。
你可以从 http://gcc.gnu.org/ 下载。
3. 链接器
链接器会将你的对象文件链接在一起。
这里我使用 gnu binutils。
你可以从 http://gnu.org/software/binutils 下载。
4. 虚拟机
为了测试你的操作系统,你必须有一个虚拟机。
但这不是必需的。
这里我使用 virtualbox。
你可以从 http://virtualbox.org/ 下载。
开始前的注意事项
1. 在开发操作系统时,你不能、不能、绝对不能使用 <iostream>、<fstream>、<memory>、<cstdio>、<cstdlib>、<windows.h>、<unistd.h> 以及所有平台 API。
你必须自己创建所有这些。
2. 你必须非常非常小心。
在开发过程中,你控制着一切。
因此,你可能会损坏你的一个、几个或全部硬件。
在这种情况下,我建议使用虚拟机来测试你的操作系统,而不是一遍又一遍地重启。
引导加载程序
引导加载程序是一段用汇编语言编写的代码,必须是 512 字节(1 个扇区)。
它会加载你的操作系统的内核。
我们跳过这一部分,使用 grub 作为我们的引导加载程序。
你可以从 http://gnu.org/software/grub 下载 grub 源代码。
或者,你可能想要一个为软盘编译的版本:在 Google 上搜索会有帮助。
一个简单的内核
我们要开发一个操作系统。
所以,我们必须自己创建函数。
首先,我们创建一个名为 boot.asm 的文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
;boot.asm:the bootloader to boot are operating system with grub
[bits 32] ;we are in 32 bit
global start ;start's the operating system:we call it in the linker script
extern _kernel_main ;this is in are .cpp file and it is the main function of are kernel
;do not modify these lines(these are needed by grub)!
section .mbHeader
align 0x4
; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
MEMINFO equ 1<<1 ; provide memory map
FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + FLAGS) ; checksum required
MultiBootHeader:
dd MAGIC
dd FLAGS
dd CHECKSUM
;you can modify these
start:
push ebx ;this is optional and load's the grub structure
call _kernel_main
|
现在创建一个名为 kernel.cpp 的文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
#include <stddef.h> //we can use it: it doesnt use any platform-related api functions
#include <stdint.h> //include it to get int16_t and some integer types
/* Hardware text mode color constants. */
enum vga_color
{
COLOR_BLACK = 0,
COLOR_BLUE = 1,
COLOR_GREEN = 2,
COLOR_CYAN = 3,
COLOR_RED = 4,
COLOR_MAGENTA = 5,
COLOR_BROWN = 6,
COLOR_LIGHT_GREY = 7,
COLOR_DARK_GREY = 8,
COLOR_LIGHT_BLUE = 9,
COLOR_LIGHT_GREEN = 10,
COLOR_LIGHT_CYAN = 11,
COLOR_LIGHT_RED = 12,
COLOR_LIGHT_MAGENTA = 13,
COLOR_LIGHT_BROWN = 14,
COLOR_WHITE = 15,
};
uint8_t make_color(enum vga_color fg, enum vga_color bg)
{
return fg | bg << 4;
}
uint16_t make_vgaentry(char c, uint8_t color)
{
uint16_t c16 = c;
uint16_t color16 = color;
return c16 | color16 << 8;
}
size_t strlen(const char* str)
{
size_t ret = 0;
while ( str[ret] != 0 )
ret++;
return ret;
}
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 24;
size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;
void terminal_initialize()
{
terminal_row = 0;
terminal_column = 0;
terminal_color = make_color(COLOR_LIGHT_GREY, COLOR_BLACK);
terminal_buffer = (uint16_t*) 0xB8000;
for ( size_t y = 0; y < VGA_HEIGHT; y++ )
{
for ( size_t x = 0; x < VGA_WIDTH; x++ )
{
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = make_vgaentry(' ', terminal_color);
}
}
}
void terminal_setcolor(uint8_t color)
{
terminal_color = color;
}
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
{
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = make_vgaentry(c, color);
}
void terminal_putchar(char c)
{
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
if ( ++terminal_column == VGA_WIDTH )
{
terminal_column = 0;
if ( ++terminal_row == VGA_HEIGHT )
{
terminal_row = 0;
}
}
}
void terminal_writestring(const char* data)
{
size_t datalen = strlen(data);
for ( size_t i = 0; i < datalen; i++ )
terminal_putchar(data[i]);
}
void kernel_main()
{
terminal_initialize();
terminal_writestring("wellcome to my first operating system!");
for(;;);
}
|
链接器脚本
创建一个名为 linker.ld 的文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
/* The bootloader will look at this image and start execution at the symbol
designated as the entry point. */
ENTRY(start)
/* Tell where the various sections of the object files will be put in the final
kernel image. */
SECTIONS
{
/* Begin putting sections at 1 MiB, a conventional place for kernels to be
loaded at by the bootloader. */
. = 1M;
/* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
.text BLOCK(4K) : ALIGN(4K)
{
*(.mbHeader)
*(.text)
}
/* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
/* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
/* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
/* The compiler may produce other sections, by default it will put them in
a segment with the same name. Simply add stuff here as needed. */
}
|
如何编译它
进入 shell(Windows 上需要 cygwin)。
输入以下命令:
1 2 3
|
nasm -f elf boot.asm -o boot.o
g++ -c kernel.cpp -o kernel.o -ffreestandinng -fno-exceptions -fno-rtti
gcc loader.o kernel.o -T linker.ld -o kern -nostdlib -nodefaultlibs -lgcc
|
恭喜!
你的第一个操作系统已成功编译!
现在你可以使用 grub-mkrescue 创建一个镜像。
创建一个目录:iso
在该目录中,创建另一个目录:boot,然后在 boot 目录中,创建一个目录:grub,然后创建一个名为 grub.cfg 的文件,内容如下(不要将大括号放在新行上),放在 grub 目录中。
1 2 3
|
menuentry "myOS" {
multiboot /boot/kern
}
|
然后将你的内核(kern)复制到 iso/boot 目录,然后再次运行你的 shell。
切换到你的内核的主目录,然后输入:
|
grub-mkrescue iso --output=kern.iso
|
现在你可以启动并享受你的第一个操作系统了:这个简单的内核没有任何功能。