为什么这个内核引起问题?

时间:2020-07-28 18:53:58

标签: c pointers gcc osdev

我决定尝试编写一个C Hello世界保护模式的内核,尽管直接访问视频内存可以手动打印字符,但我还是决定尝试编写一个字符串,虽然没有警告或错误,但可以引导至一个闪烁的光标,但大约半毫秒后它黑屏。 这是代码:

#include <stdint.h>

void kmain() {
    // Startup
    int i = 0;
    
    uint16_t* vidmem = (uint16_t*) 0xB8000;
    
    char string[] = "Hello, kernel world!";
    while (string[i]) {
        vidmem[i] = string[i];
        vidmem[i+1] = 0;
        i+=2;
    }

    // Hang the system
    for (;;) {
        
    }
}

编译为:gcc -m32 -c kernel.c -o kernel.o -std = gnu99 -ffreestanding -O1 -Wall -Wextra

然后与通用boot.o链接,然后使用grub制成ISO

我在linux上的qemu中对其进行了测试,任何帮助将不胜感激!

在尝试打印字符串功能之前,这能够打印字符:

vidmem[0] = "C";
vidmem[1] = 1;

哪个会打印字母C。不过没什么。

尝试修复一些错误后,我想到了这一点:

#include <stdint.h>

void kmain() {
    // Startup
    int i = 0;
    int j = 0;
    
    uint16_t* vidmem = (uint16_t*) 0xB8000;
    
    char string[] = "Hello, kernel world!";
    while (string[i]) {
        vidmem[i] = string[i];
        vidmem[j] = 0;
        i+=1;
        j=i*2;
    }

    // Hang the system
    for (;;) {
        
    }
}

哪些仍然是黑屏。

2 个答案:

答案 0 :(得分:3)

您正在努力地执行不需要的算术运算。请记住,C语言中的指针算术和数组索引总是以所指向类型的大小为单位。如果您想将string的字节复制到vidmem中,并将每个字节后跟一个零字节,那么由于x86上的整数是低位优先的,因此这样做就足够了

int i = 0;
uint16_t* vidmem = (uint16_t*) 0xB8000;

unsigned char string[] = "Hello, kernel world!";
while (string[i]) {
    vidmem[i] = string[i];
    i++;
}

或者,如果您愿意

for (i = 0; string[i]; i++)
    vidmem[i] = string[i];

就是这样。

如果您想要的颜色不是黑底黑字,可以将其更改为vidmem[i] = string[i] | 0x7000;

答案 1 :(得分:0)

两个版本都不正确;

    uint8_t* vidmem = (uint8_t*) 0xB8000;
    
    char string[] = "Hello, kernel world!";
    for(size_t i = 0; string[i]; i++) {
        vidmem[i*2] = string[i];
        vidmem[i*2 + 1] = 0;
    }