65.9K
CodeProject 正在变化。 阅读更多。
Home

操作系统开发 - 第一部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.39/5 (32投票s)

2008年6月5日

CPOL

4分钟阅读

viewsIcon

73988

downloadIcon

694

OS 开发的环境设置

引言

在这个第一个基础教程中,我将展示如何创建一个非常基础的内核,并从软盘启动我们的内核系统。

即使是构建一个简单的“实模式 Hello World”内核也需要大量的工作。在 Windows 环境下使用自己的 OS 内核会有点麻烦,因为大多数文档都假定开发机是 Linux。

我使用 Windows XP,并通过 Microsoft Virtual PC 2007 来测试我的内核。在虚拟机中测试内核可以节省大量时间。在软盘菜单中,我们可以连接或分离软盘镜像。任何长度为 1,474,560 字节的文件都可以用作软盘镜像。Virtual PC 有一个安装了 Windows XP 的虚拟硬盘(实际上 DOS 就能满足我们所有的需求 - 但我安装了 XP,因为我习惯用它)。

有些人喜欢编写自己的引导加载程序。但我更喜欢使用 GRUB 来加载我的内核,这样我就可以立即开始编写内核代码。GRUB 是一个非常好的引导加载程序,支持很多文件系统和文件格式。

GRUB 设置

要设置 GRUB,我们需要 2 个软盘镜像

  1. boot.img
  2. helper.img

boot.img 将是我们的启动盘,而另一个用于创建启动盘。

现在我们下载 GRUB 二进制包 grub-0.97-i386-pc.tar.gz 并解压。我们得到 2 个文件,名为 stage1stage2,以及其他文件。

现在我们启动安装了 Windows XP 的 Virtual PC,然后连接 boot.img。格式化软盘,并在软盘根目录下创建一个名为 'system' 的文件夹。将 stage1stage2 文件复制到 system 文件夹。然后分离 boot.img,并连接 helper.img

现在我们需要将 stage1stage2 文件合并,并将它们作为原始镜像从第一个扇区开始复制到 helper 软盘。我们使用以下 DOS 命令进行合并

>copy /b stage1 + stage2 grub.bin

现在,使用 rawwrite.exe 工具,将 grub.bin 复制到 'helper' 软盘。您可以从许多地方下载此文件 - 有些甚至带有图形界面。

现在关闭 Windows XP,并用我们刚创建的 helper 软盘启动 Virtual PC。要做到这一点,我们必须在启动 Virtual PC 之前连接软盘镜像。出现 grub 命令提示符后,我们分离 helper.img,然后捕获 boot.img,并在命令提示符处输入以下命令。

grub>install (fd0)/system/stage1 (fd0) (fd0)/system/stage2

现在我们已经设置好了启动盘。接下来我们创建简单的内核来测试它。GRUB 加载器需要 multiboot 内核(https://gnu.ac.cn/software/grub/manual/multiboot/multiboot.html)。在这里,我们构建我们的 multiboot 内核。

内核

在这里,我们定义了一个非常简单的 multiboot 内核,它会在屏幕上显示“Hello World”。我们将内核分成两个文件。一个是用汇编编写的,另一个是用 C 编写的。实际上,我们希望尽可能多地使用 C 语言 - 但我们也需要一些汇编。不多。

Kernel.asm 文件

此文件定义了 multiboot 头,并调用 C 源文件中定义的 kernel_main 函数。

[BITS 32]
[global start]
[extern _kernel_main] ; this is in the c file
    
    ; ----- Multiboot Header Starts Here -----

    MULTIBOOT_PAGE_ALIGN   equ 1<<0
    MULTIBOOT_MEMORY_INFO  equ 1<<1

    MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
    MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
    CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

    ; The Multiboot header
    align 4
    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd CHECKSUM     

    ; ----- Multiboot Header Ends Here -----

start:
call _kernel_main
cli ; stop interrupts
hlt ; halt the CPU

为了构建汇编文件,我使用 nasm.exe 工具,它是免费提供的。我更喜欢 ELF 文件格式作为我的内核。

>nasm -f elf kernel.asm -o ks.o  

Kernel.c 文件

此文件定义了 clrscrprintxykernel_main 函数。

#define WHITE_SPACE 0x07
#define VIDEO_MEMORY 0xb8000

char *videoMemory = (char*) VIDEO_MEMORY;

void clrscr()
{
    int i;
    for(i=0;i < (80*25*2);i+=2)
    {
        videoMemory[i]=' ';
        videoMemory[i+1]=WHITE_SPACE;
    }
}

void printxy(char *message, unsigned int x, unsigned int y)
{
    unsigned int i=0;
    i=(y*80*2)+x;
    while(*message!=0)
    {
        if(*message=='\n')
        {
            y++;
            i=(y*80*2);
        } else {
            videoMemory[i++]=*message;            
            videoMemory[i++]=WHITE_SPACE;
        }
        *message++;
    }
}

kernel_main()
{
    clrscr();
    printxy("Hello World", 0, 0);
}

为了编译 C 语言文件,我使用 DJGPP,它是 GCC 在 Windows 上的移植版本。它是一个免费工具,您可以在 Google 搜索后下载。我们使用以下命令行进行编译

>gcc -c kernel.c -o kernel.o

链接目标文件

对于链接,我们还需要 binutils 工具来支持 elf。您可以从 这里 下载。

我们首先定义一个链接脚本(link.ld 文件)。它非常重要,因为它有助于将各个部分放置在正确的位置。

OUTPUT_FORMAT("elf32-i386") 
ENTRY(start) 
phys = 0x00100000; 
SECTIONS 
{ 
.text phys : AT(phys) 
{ 
code = .; 
*(.text) 
*(.rodata) 
. = ALIGN(4096); 
} 
.data : AT(phys + (data - code)) 
{ 
data = .; 
*(.data) 
. = ALIGN(4096); 
} 
.bss : AT(phys + (bss - code)) 
{ 
bss = .; 
*(.bss) 
. = ALIGN(4096); 
}

.rodata : AT(phys + (rodata - code)) 
{ 
rodata = .; 
*(.rodata) 
. = ALIGN(4096); 
}
 
end = .; 
} 

好的。我们差不多完成了,使用以下命令来构建我们的内核(kernel.bin)。

>ld-elf -T link.ld --oformat elf32-i386 -o kernel.bin ks.o kernel.o

要查看文件是否正确创建,我们可以使用以下命令

>objdump-elf kernel.bin --all

用内核启动

现在我们将 kernel.bin 复制到我们的启动盘的 system 文件夹中,并用该盘启动。当 GRUP 命令提示符出现时,我们输入以下命令

grub>kernel /system/kernel.bin

grub 显示了有关我们的 multiboot-elf 内核的信息。现在我们执行以下命令

grub>boot

voilà - “Hello World”消息显示了。请注意,GRUB 已经设置了保护模式、GDT 和 A20 gate。打印工作的原因是 GRUB 以一种方式设置了 GDT,使得虚拟内存和物理内存到视频内存完全相同。

结论

这是一个非常基础的教程,也是一个非常老的话题。我只是想提供我们开始编写自己的 OS 所需的东西。下一部分可能会涵盖一些高级功能,如保护模式和描述符表,再下一部分可能涵盖更多高级主题。请给我您的评论,以便我改进这篇文章,并在下一篇文章中提供更好的信息。

此外,请注意本文的内容并非我原创。我只是收集了手册和教程并将它们整合在一起。主要目的是建立基本环境。

历史

  • 2008 年 6 月 5 日:初次发布
© . All rights reserved.