A user
A user

Reputation: 104

Why is this kernel causing problems?

I decided to try and write a C Hello world protected mode Kernel, and although directly accessing the video memory works to print characters manually, I decided to try to write a string, and there are no warnings or errors but it boots to a blinking cursor, but after about half a millisecond it black screens. Here is the code:

#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 (;;) {
        
    }
}

Compiled with: gcc -m32 -c kernel.c -o kernel.o -std=gnu99 -ffreestanding -O1 -Wall -Wextra

And then linked with a generic boot.o and then made into an ISO with grub

I tested it in qemu on linux, any help would be appreciated!

Before I attempted the printstring funciton, this was able to print characters:

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

Which would print the letter C. Nothing fancy though.

After trying to fix some erros I came up with this:

#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 (;;) {
        
    }
}

Which still blackscreens.

Upvotes: 0

Views: 112

Answers (2)

0___________
0___________

Reputation: 67476

Both versions are incorrect;

    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;
    }

Upvotes: 0

Nate Eldredge
Nate Eldredge

Reputation: 58072

You are trying too hard to do arithmetic that isn't needed. Remember that pointer arithmetic and array indexing in C are always in units of the size of the type pointed to. If you want to copy the bytes of string into vidmem with a zero byte after each one, then thanks to the fact that integers on x86 are little-endian, it should be sufficient to do

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

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

Or if you prefer

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

That's it.

If you want a different color that is not black-on-black, you could change this to vidmem[i] = string[i] | 0x7000;.

Upvotes: 3

Related Questions