如何从软盘启动并运行自定义操作系统内核

在Windows环境中开发自己的操作系统内核可能会遇到一些麻烦,因为大多数文档都假设开发机是Linux。本文将介绍如何在Windows XP环境下使用Microsoft Virtual PC 2007虚拟机来测试内核,并通过GRUB引导加载自定义操作系统内核。

准备工作

首先,需要准备两个软盘镜像文件:

  • boot.img:作为启动盘
  • helper.img:用于创建启动盘

此外,还需要下载GRUB二进制包:

grub-0.97-i386-pc.tar.gz

解压后,可以得到stage1stage2两个文件以及其他一些文件。

GRUB设置

Windows XP中启动虚拟机,然后挂载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软盘启动虚拟机。为此,必须在启动虚拟机之前挂载软盘镜像。在显示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

这个文件定义了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); }

编译和链接

为了编译汇编文件,使用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的方式使得虚拟内存和物理内存到视频内存是完全相同的。

这是一个非常基础的教程,也是一个相当古老的话题。只是想提供需要开始编写自己的操作系统的东西。下一部分可能涵盖一些高级特性,如保护模式和描述符表,以及一些更高级的话题。请给出评论,以便可以改进这篇文章,并尝试在下一篇文章中提供更好的信息。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485