Can't write a char array in my kernel written in C

Viewed 203

I'm going to preface this by saying that I'm far from good at C or C++, but nonetheless I've decided to try and write my kernel in it... my problem lies with writting a string (char array), I can write a character but as soon as I give it an array of chars it doesn't work.

I've also done some testing and I found out that it apperently sees the char array length as being 0.

Here's my kernel...

#include "kernel.h"

void clear_screen(enum vga_color back, enum vga_color fore);
void print(char* msg, unsigned int line, enum vga_color back, enum vga_color fore);

int hex_combine(unsigned int x, unsigned int y);
int get_length(char* str);


void main(void)
{
    clear_screen(BLUE, WHITE);
    print("Unga Bunga", 0, BLUE, WHITE);
    for(;;);
};


void clear_screen(enum vga_color back, enum vga_color fore)
{
    unsigned char *vidmem = (unsigned char *) VGA_ADDR;
    unsigned int i = 0;
    while (i < (80*25*2))
    {
        vidmem[i] = ' ';
        vidmem[i+1] = hex_combine(back, fore);
        i+=2;
    };
};


void print(char* msg, unsigned int line, enum vga_color back, enum vga_color fore)
{
    unsigned char* vidmem = (unsigned char*) VGA_ADDR;
    unsigned int i = (line*80*2);

    for (char* chr = msg; *chr != '\0'; chr++)
    {
        vidmem[i]   = *chr;
        vidmem[i+1] = hex_combine(back, fore);

        chr++;
        i+=2;
    };
};


int hex_combine(unsigned int x, unsigned int y) { return (x<<4)|(y); }
int get_length(char* str)
{
    char* c;
    for (c = str; *c != '\0'; c++);
    return c - str;
}

And here's the header file for the kernel...

#ifndef KERNEL_H
#define KERNEL_H

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;

#define VGA_ADDR 0xB8000
#define BUFSIZE 2200

uint16* vga_buffer;

#define NULL 0

enum vga_color {
    BLACK,
    BLUE,
    GREEN,
    CYAN,
    RED,
    MAGENTA,
    BROWN,
    GREY,
    DARK_GREY,
    BRIGHT_BLUE,
    BRIGHT_GREEN,
    BRIGHT_CYAN,
    BRIGHT_RED,
    BRIGHT_MAGENTA,
    YELLOW,
    WHITE,
};

#endif

I don't know if you need it, but here's my bootloader...

[org 0x7C00]

KERNEL_ADDRESS equ 0x100000

cli
lgdt [gdt_descriptor]

; Switch to PM
mov eax, cr0
or eax, 0x1
mov cr0, eax

jmp 0x8:init_pm


[bits 32]

init_pm:
    mov ax, 0x10
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

call build_page_tables

; Enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax

mov eax, cr4
or eax, 1 << 7
mov cr4, eax

mov eax, 0x1000
mov cr3, eax

; Set LME bit in EFER register
mov ecx, 0xC0000080     ; Operand of 'rdmsr' and 'wrmsr'
rdmsr                   ; Read before so we don't overwrite the content
or eax, 1 << 8          ; eax : operand of wrmsr
wrmsr

; Enable paging by setting CR0.PG bit to 1
mov eax, cr0
or eax, (1 << 31)
mov cr0, eax

; Load 64-bit GDT
lgdt [gdt64_descriptor]

; Jump to code segment in 64-bit GDT
jmp 0x8:init_lm


[bits 64]

init_lm:
    mov ax, 0x10
    mov fs, ax
    mov gs, ax

    mov rbp, 0x90000
    mov rsp, rbp

    ; Load kernel from disk
    xor ebx, ebx    ; Upper 2 bytes above bh in ebx is for cylinder = 0x0
    mov bl, 0x2     ; Read from 2nd sector
    mov bh, 0x0     ; Head
    mov ch, 1       ; Read 1 sector
    mov rdi, KERNEL_ADDRESS
    call ata_chs_read

    
    jmp KERNEL_ADDRESS
    jmp $

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[bits 16]
;; http://wiki.osdev.org/ATA_in_x86_RealMode_%28BIOS%29

;load_loader:
    ;mov bx, LOADER_OFFSET  
    ;mov dh, 1          ; Load 1 sector (max allowed by BIOS is 128)
    ;mov dl, 0x80       ; Drive number

    ;mov ah, 0x02       ; Read function
    ;mov al, dh
    ;mov ch, 0x00       ; Cylinder
    ;mov dh, 0x00       ; Head
    ;; !! Sector is 1-based, and not 0-based
    ;mov cl, 0x02       ; 1st sector to read 
    ;int 0x13
    ;ret


[bits 32]
build_page_tables:
    ; PML4 starts at 0x1000
    mov eax, 0x2000     ; PDP base address
    or eax, 0b11        ; P and R/W bites
    mov ebx, 0x1000     ; MPL4 base address
    mov [ebx], eax

    mov eax, 0x3000     ; PD base address
    mov ebx, 0x2000     ; PDP physical address
    mov ecx, 64         ; 64 PDP

    build_PDP:
        or eax, 0b11
        mov [ebx], eax
        add ebx, 0x8
        add eax, 0x1000 ; Next PD page base address
        loop build_PDP

    mov eax, 0x0        ; 1st page physical base address
    mov ebx, 0x3000     ; PD physical base address
    mov ecx, 512

    build_PD:
        or eax, 0b10000011  ;P + R/W + PS (bit for 2MB page)
        mov [ebx], eax
        add ebx, 0x8
        add eax, 0x200000   ; Next 2MB physical page
        loop build_PD

    ;(tables end at 0x4000 => fits before Bios boot sector at 0x7c00)
    ret


;=============================================================================
; ATA read sectors (CHS mode) 
; Max head index is 15, giving 16 possible heads
; Max cylinder index can be a very large number (up to 65535)
; Sector is usually always 1-63, sector 0 reserved, max 255 sectors/track
; If using 63 sectors/track, max disk size = 31.5GB
; If using 255 sectors/track, max disk size = 127.5GB
; See OSDev forum links in bottom of [http://wiki.osdev.org/ATA]
;
; @param EBX The CHS values; 2 bytes, 1 byte (BH), 1 byte (BL) accordingly
; @param CH The number of sectors to read
; @param RDI The address of buffer to put data obtained from disk               
;
; @return None
;=============================================================================
[bits 64]
ata_chs_read:   pushfq
                push rax
                push rbx
                push rcx
                push rdx
                push rdi

                mov rdx, 0x1f6      ; Port to send drive & head numbers
                mov al, bh          ; Head index in BH
                and al, 00001111b   ; Head is only 4 bits long
                or  al, 10100000b   ; Default 1010b in high nibble
                out dx, al

                mov rdx, 0x1f2      ; Sector count port
                mov al, ch          ; Read CH sectors
                out dx, al

                mov rdx, 0x1f3      ; Sector number port
                mov al, bl          ; BL is sector index
                out dx, al

                mov rdx, 0x1f4      ; Cylinder low port
                mov eax, ebx        ; Byte 2 in ebx, just above BH
                mov cl, 16
                shr eax, cl         ; Shift down to AL
                out dx, al

                mov rdx, 0x1f5      ; Cylinder high port
                mov eax, ebx        ; Byte 3 in ebx, just above byte 2
                mov cl, 24
                shr eax, cl         ; Shift down to AL
                out dx, al

                mov rdx, 0x1f7      ; Command port
                mov al, 0x20        ; Read with retry
                out dx, al

.still_going:   in al, dx
                test al, 8          ; The sector buffer requires servicing
                jz .still_going     ; Until the sector buffer is ready

                mov rax, 512/2      ; To read 265 words = 1 sector
                xor bx, bx
                mov bl, ch          ; Read CH sectors
                mul bx
                mov rcx, rax        ; RCX is counter for INSW
                mov rdx, 0x1f0      ; Data port, in and out
                rep insw            ; In to [RDI]

                pop rdi
                pop rdx
                pop rcx
                pop rbx
                pop rax
                popfq
                ret

                
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]

GDT:
; Null :
    dd 0x0
    dd 0x0

; Code :
    dw 0xffff       ; Limit
    dw 0x0          ; Base
    db 0x0          ; Base
    db 10011010b    ; 1st flag, Type flag
    db 11001111b    ; 2nd flag, Limit
    db 0x0          ; Base

; Data :
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_descriptor:
    dw $ - GDT - 1  ; 16-bit size
    dd GDT          ; 32-bit start address


[bits 32]
GDT64:
; Null :
    dq 0x0

; Code :
    dd 0x0
    db 0x0
    db 0b10011000
    db 0b00100000
    db 0x0

; Data :
    dd 0x0
    db 0x0
    db 0b10010000
    db 0b00000000
    db 0x0

gdt64_descriptor:
    dw $ - GDT64 - 1    ; 16-bit size
    dd GDT64            ; 32-bit start address

    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]
times 510 - ($-$$) db 0
dw 0xaa55
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

I compile the whole thing using the bat file...

@echo off
wsl nasm -f bin boot.asm -o boot.bin -l dump/boot.list
wsl nasm -f elf64 loader.asm -o loader.o -l dump/loader.list

wsl cc -m64 -masm=intel -c kernel.c
wsl ld -Ttext 0x100000 -o kernel.elf loader.o kernel.o
wsl objcopy -R .note -R .comment -S -O binary kernel.elf kernel.bin

wsl dd if=/dev/zero of=images/image.bin bs=512 count=2880
wsl dd if=boot.bin of=images/image.bin conv=notrunc
wsl dd if=kernel.bin of=images/image.bin conv=notrunc bs=512 seek=1

del boot.bin kernel.bin kernel.o loader.o kernel.elf

qemu-system-x86_64 images/image.bin
pause > nul
cls
0 Answers
Related