在Windows环境中开发自己的操作系统内核可能会遇到一些麻烦,因为大多数文档都假设开发机是Linux。本文将介绍如何在Windows XP环境下使用Microsoft Virtual PC 2007虚拟机来测试内核,并通过GRUB引导加载自定义操作系统内核。
首先,需要准备两个软盘镜像文件:
此外,还需要下载GRUB二进制包:
grub-0.97-i386-pc.tar.gz
解压后,可以得到stage1
和stage2
两个文件以及其他一些文件。
在Windows XP中启动虚拟机,然后挂载boot.img
。格式化软盘并在根目录下创建一个名为system
的文件夹。将stage1
和stage2
文件复制到system
文件夹中。然后卸载boot.img
并挂载helper.img
。
接下来,需要将stage1
和stage2
文件合并,并将其作为原始图像复制到helper软盘的第一扇区。可以使用以下DOS命令来完成这个操作:
copy /b stage1 + stage2 grub.bin
然后,使用rawwrite.exe
工具将grub.bin
复制到'helper'软盘。可以从很多地方下载这个文件,有些甚至提供了图形界面。
关闭Windows XP并使用刚刚创建的helper软盘启动虚拟机。为此,必须在启动虚拟机之前挂载软盘镜像。在显示GRUB命令提示符后,卸载helper.img
并捕获boot.img
,在命令提示符下输入以下命令:
grub>install (fd0)/system/stage1 (fd0) (fd0)/system/stage2
现在已经设置了启动盘。接下来,将创建一个简单的内核来测试这个。GRUB加载器需要一个多启动内核。
这里定义了一个非常简单的多启动内核,它在屏幕上显示'Hello World'。将内核分成两个文件,一个是汇编语言,另一个是C语言。实际上,尽可能多地使用C语言,但也需要一些汇编语言。
这个文件定义了多启动头,并调用在C源文件中定义的kernel_main
函数。
BITS 32
[global start]
[extern _kernel_main]
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)
align 4
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd CHECKSUM
start:
call _kernel_main
cli ; stop interrupts
hlt ; halt the CPU
这个文件定义了clrscr
、printxy
和kernel_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);
}
为了编译汇编文件,使用nasm.exe
工具,它是免费的。更喜欢为内核使用ELF文件格式。
nasm -f elf kernel.asm -o ks.o
为了编译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文件夹中,并使用该盘启动。当GRUB命令提示符出现时,输入以下命令:
grub>kernel /system/kernel.bin
GRUB显示有关多启动ELF内核的信息。现在执行以下命令:
grub>boot
Walllla- Hello World消息显示出来了。请注意,GRUB已经设置了保护模式、GDT和A20门等。打印工作的原因是因为GRUB设置GDT的方式使得虚拟内存和物理内存到视频内存是完全相同的。
这是一个非常基础的教程,也是一个相当古老的话题。只是想提供需要开始编写自己的操作系统的东西。下一部分可能涵盖一些高级特性,如保护模式和描述符表,以及一些更高级的话题。请给出评论,以便可以改进这篇文章,并尝试在下一篇文章中提供更好的信息。