1 year ago

#193418

test-img

BrandonOConnell

Why does my OS stagnate after calling this function on Linux, but works on Windows?

I'm writing a basic operating system - I've written the boot sector and switched the CPU to 32-bit protected mode, enabling me to write the code in C rather than assembly. In C, I've written a basic screen driver and have successfully loaded the kernel (by that I mean, the code within the kernel.c file begins to be executed).

The problem arises when the terminal_initialise() function is called. Its purpose is to set the background colour and position the cursor at 0, 0. As you can see from the screenshot of Bochs, it runs successfully - finishing the loop and setting the cursor position. The issue is that no code after that function call in kernel.c gets executed. Any ideas why?

Apologies for the lack of error messages, but they're not possible at this stage. I've got a few compiler warnings for implicit function declarations, but that's it.

Update: It seems that the code runs perfectly fine on Windows in both QEMU and Bochs, but fails to run on Linux on both. I'm working on finding out why, but I can't see the solution. My main development environment is Linux, so this is still vital to me, but not quite as critical.

screen.h:

#ifndef HEADER_FILE
#define HEADER_FILE

#define VIDEO_ADDRESS 0xb8000
#define MAX_ROWS 25
#define MAX_COLS 80
#define WHITE_ON_BLACK 0x0f

#define REG_SCREEN_CTRL 0x3D4
#define REG_SCREEN_DATA 0x3D5

/* VARIABLES AND ENUMS */

enum colour {
    COLOUR_BLACK = 0,
    COLOUR_BLUE = 1,
    COLOUR_GREEN = 2,
    COLOUR_CYAN = 3,
    COLOUR_RED = 4,
    COLOUR_MAGENTA = 5,
    COLOUR_BROWN = 6,
    COLOUR_LIGHT_GREY = 7,
    COLOUR_DARK_GREY = 8,
    COLOUR_LIGHT_BLUE = 9,
    COLOUR_LIGHT_GREEN = 10,
    COLOUR_LIGHT_CYAN = 11,
    COLOUR_LIGHT_RED = 12,
    COLOUR_LIGHT_MAGENTA = 13,
    COLOUR_LIGHT_BROWN = 14,
    COLOUR_WHITE = 15,
};

/* FUNCTION PROTOTYPES */

char generate_attribute_byte(enum colour, enum colour);
int get_screen_offset(int, int);
void print_char(char, int, int, char);
void print_at(char*, int, int, char);
void print(char*, char);
void set_cursor(int);
int get_cursor();
void clear_screen();
int handle_scrolling(int);

#endif

screen.c:

#include "screen.h"

/* FUNCTIONS */

char generate_attribute_byte(enum colour fg, enum colour bg) {
    return fg | bg << 4;
}

/* ---------- PRINTING FUNCTIONS ----------*/

void print_char(char character, int col, int row, char attribute_byte) {
    unsigned char *vidmem = (unsigned char *) VIDEO_ADDRESS;
    if (!attribute_byte) {
        attribute_byte = generate_attribute_byte(COLOUR_WHITE, COLOUR_BLACK);
    }

    int offset;
    if (col >= 0 && row >= 0) {
        offset = get_screen_offset(col, row);
    } else {
        offset = get_cursor();
    }

    if (character == '\n') {
        int rows = offset / (2 * MAX_COLS);
        offset =  get_screen_offset(79, rows);
    } else {
        vidmem[offset] = character;
        vidmem[offset + 1] = attribute_byte;
    }

    offset += 2;
    offset = handle_scrolling(offset);
    set_cursor(offset);
}

void print_at(char* message, int col, int row, char attribute_byte) {
    if (col >= 0 && row >= 0) {
        set_cursor(get_screen_offset(col, row));
    }
    int i = 0;
    while(message[i] != 0) {
        print_char(message[i++], col, row, attribute_byte);
    }
}

void print(char* message, char attribute_byte) {
    print_at(message, -1, -1, attribute_byte);
}

/* ---------- OFFSET AND CURSOR CALCULATIONS ----------*/

int get_screen_offset(int col, int row) {
    return ((row * MAX_COLS) + col) * 2;
}

void set_cursor(int offset) {
    offset /= 2;
    port_byte_out(REG_SCREEN_CTRL, 14);
    port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
    port_byte_out(REG_SCREEN_CTRL, 15);
    port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
}

int get_cursor() {
    port_byte_out(REG_SCREEN_CTRL, 14);
    int offset = port_byte_in(REG_SCREEN_DATA) << 8;
    port_byte_out(REG_SCREEN_CTRL, 15);
    offset += port_byte_in(REG_SCREEN_DATA);
    return offset * 2;
}

/* ---------- MISC ----------*/

void clear_screen() {
    int row = 0;
    int col = 0;

    for (row = 0; row < MAX_ROWS; row++) {
        for (col = 0; col < MAX_COLS; col++) {
            print_char(' ', col, row, WHITE_ON_BLACK);
        }
    }

    set_cursor(get_screen_offset(0, 0));
}

int handle_scrolling(int cursor_offset) {
    if (cursor_offset < MAX_ROWS * MAX_COLS * 2) {
        return cursor_offset;
    }

    int i;
    for (i = 1; i < MAX_ROWS; i++) {
        memory_copy(get_screen_offset(0, i) + VIDEO_ADDRESS,
                    get_screen_offset(0, i - i) + VIDEO_ADDRESS,
                    MAX_COLS * 2);
    }

    char* last_line = get_screen_offset(0, MAX_ROWS - 1) + VIDEO_ADDRESS;
    for (i = 0; i < MAX_COLS * 2; i++) {
        last_line[i] = 0;
    }

    cursor_offset -= 2 * MAX_COLS;

    return cursor_offset;
}

kernel.h:

#include "../drivers/screen.h"

/* VARIABLES AND ENUMS */

unsigned char terminal_colour;
unsigned short terminal_buffer;

/* FUNCTION PROTOTYPES */

void terminal_initialise();
char get_scan_code();
char get_char();

/* FUNCTIONS */

void terminal_initialise() {
    terminal_colour = generate_attribute_byte(COLOUR_WHITE, COLOUR_LIGHT_GREEN);
    terminal_buffer = VIDEO_ADDRESS;
    for (char row = 0; row < MAX_ROWS; row++) {
        for (char col = 0; col < MAX_COLS; col++) {
            print_char(' ', col, row, terminal_colour);
        }
    }
    set_cursor(get_screen_offset(0, 0));
}


unsigned char scancode[128] =
{
    0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
    '\b', /* Backspace */
    '\t', /* Tab */
    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',    /* Enter key */
    0,    /* Control */
    'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
    '\'',
    '`',
    0,    /* Left shift */
    '\\', 'z', 'x', 'c', 'v', 'b', 'n',
    'm', ',', '.', '/',
    0,    /* Right shift */
    '*',
    0,    /* Alt */
    ' ',   /* Space bar */
    0,    /* Caps lock */
    0,    /* F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,    /* < ... F10 */
    0,    /* 69 - Num lock*/
    0,    /* Scroll Lock */
    0,    /* Home key */
    0,    /* Up Arrow */
    0,    /* Page Up */
    '-',
    0,    /* Left Arrow */
    0,
    0,    /* Right Arrow */
    '+',
    0,    /* 79 - End key*/
    0,    /* Down Arrow */
    0,    /* Page Down */
    0,    /* Insert Key */
    0,    /* Delete Key */
    0,   0,   0,
    0,    /* F11 Key */
    0,    /* F12 Key */
    0,    /* All other keys are undefined */
};

char get_scan_code() {
    char c = 0;
    do {
        if (port_byte_in(0x60) != c) {
            c = port_byte_in(0x60);
            if (c > 0) {
                return c;
            }
        }
    } while(1);
}

char get_char() {
    return scancode[get_scan_code()+1];
}

kernel.c:

#include "kernel.h"

void _start() {
    terminal_initialise();
    // NO EXECUTION AFTER THIS POINT
    print((char[]){"OS v1.0.0\n"}, generate_attribute_byte(COLOUR_WHITE, COLOUR_LIGHT_GREEN));
    prompt();
}

Makefile:

C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)

OBJ = ${C_SOURCES:.c=.o}

all: os-image

os-image: boot/boot_sect.bin kernel.bin
    cat $^ > os-image

kernel.bin: kernel.tmp
    objcopy -O binary -j .text $< $@

kernel.tmp: kernel/kernel_entry.o ${OBJ}
    ld -m elf_i386 -o $@ -Ttext 0x1000 $^

%.o : %.c ${HEADERS}
    gcc -m32 -ffreestanding -c $< -o $@

%.o : %.asm
    nasm $< -f elf -o $@

%.bin : %.asm
    nasm $< -f bin -I '../../16bit/' -o $@

Bochs Screenshot

c

x86

operating-system

osdev

bochs

0 Answers

Your Answer

Accepted video resources