如何编写一个hello world内核?

16

我正在编写一个内核,所以从内核中的“Hello World”程序开始。

我已经用C++编写了一个“Hello World”内核,并且它成功编译。

但是当我启动它时,屏幕上没有显示任何内容。

这段代码有什么问题?

link.ld

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS{
. = 0x00100000;

.text :{
    *(.text)
}

.rodata ALIGN (0x1000) : {
    *(.rodata)
}

.data ALIGN (0x1000) : {
    *(.data)
}

.bss : {
    sbss = .;
    *(COMMON)
    *(.bss)
    ebss = .;
}
}

loader.asm

[BITS 32]

global start
extern _main

start:
    call _main
    cli 
    hlt

video.h

#ifndef VIDEO_H
#define VIDEO_H

class Video{
    public:
        Video();
        ~Video();
        void clear();
        void write(char *cp);
        void put(char c);
    private:
        unsigned short *videomem;
        unsigned int off;
        unsigned int pos;
};
#endif

video.cpp

#include "Video.h"

Video::Video(){
pos = 0;
off = 0;
videomem = (unsigned short*)0xb8000;
}

Video::~Video(){}

void Video::clear(){
unsigned int i;
for(i=0;i<(80*25);i++){
    videomem[i] = (unsigned short)' '|0x0700;
}
pos = 0;
off = 0;
}

void Video::write(char *cp){
char *str = cp, *ch;
for(ch=str;*ch;ch++){
    put(*ch);
}
}

void Video::put(char c){
if(pos>=80){
    pos = 0;
    off+=80;
}
if(off>=(80*25)){
    clear();
}

videomem[off+pos] = (unsigned short)c|0x0700;
pos++;
}

Kernel.cpp

#include "Video.h"
int _main(void){
Video vid;
vid.clear();
vid.write("Hello World!");
}

我正在使用以下命令进行编译:

g++ -c video.cpp -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions
g++ -c Kernel.cpp -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions
nasm -f aout Loader.asm -o Loader.o
ld -T linker.ld -o Kernel.bin Loader.o Video.o Kernel.o

它没有给出任何错误。

如果可以进行调试,请帮忙说明如何进行调试。

我正在虚拟机中启动它。

非常感谢您的帮助。


4
你使用的是哪个启动加载程序?如果是GRUB,你可能需要在你的加载器汇编文件中添加多重引导样板代码。 - Martin Törnwall
我正在使用 grub,但当我从 grub 引导时,它只显示 grub 控制台。 - user636424
4个回答

12
如果您愿意,可以查看本学期我课堂上使用的操作系统作为示例。它是用 c 编写的。我们使用GRUB引导程序和qemu来运行它。
它的代码编写得非常干净,第一个增量恰好是“Hello world”操作系统,而最后一个增量包含了完整的shell、线程和进程以及许多其他内容。您可以在其中找到源代码、makefile和链接器脚本的示例(从简单的到相当复杂的示例)。

http://sourceforge.net/projects/oszur11/

我还想链接到沿着增量的脚本,但不幸的是,它不是用英语编写的。
哦,还有一个增量专门用于调试,但那更多地是为了调试为您的操作系统编写的过程,而不是调试整个操作系统(如果我记得正确,我们使用了两个控制台,一个带有qemu,另一个则连接到在另一个控制台上运行的操作系统的gdb)。

1
这是我最近看到的最棒的“如何逐步为蠢货XYZ”项目之一,点赞!虽然我对编写操作系统完全不感兴趣,但你的这个项目将占据我整个周末……只是因为它太棒了 :-) - Damon
嗯,我已经搜索了一个星期,这个指南是我见过的最好的东西,非常感谢。 - Trevor Rudolph
@TrevorRudolph 这太老了 :) 我很久以前就上过这门课了。很高兴知道它仍然存在,那确实是任何课程中最好的材料之一。 - penelope
学习编写内核是深入了解软件和硬件的细节,这是最基本的联系。我自学了所有东西,想要更好的C语言编程体验,但现在我被拉入汇编语言的世界,这是一种奇怪的语言,但我只需要足够的汇编知识来传递给C函数即可。 - Trevor Rudolph
1
不错!我还在 https://github.com/cirosantilli/x86-bare-metal-examples 上发布了一些更简约的示例。 - Ciro Santilli OurBigBook.com

5
当电脑启动时,BIOS会加载物理地址为0x7c00的MBR内的内容,然后跳转到该地址。因此,您应该将代码链接到0x7c00开始而不是0x00100000。
因此,按照以下方式更改您的链接器脚本即可解决问题:
...
SECTIONS{
    . = 0x7c00;
    ...
}

编辑: 在查看您的代码后,我注意到了更多问题。如果您没有使用引导程序,那么在开始执行32位代码之前,有一些需要设置的内容,最重要的是启用保护模式。这里 有一些教程可以帮助您。


2

你尝试过qemu吗?在大学制作微型操作系统时,它被证明是最适合这种类型的程序的。


0

要使其工作,您将必须执行以下操作之一:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接