assemblyx86kernelbootloaderosdev

Kernel.c not executing complete code [OS from scratch]


I am a beginner in operating systems and I am trying to build os from scratch (following the tutorial). Although I can execute the code provided by the author. But when I add my custom bootloader (which obviously takes more memory, and waits for keyboard interrupt to load kernel) and then try to add drivers as mentioned in the tutorial, my kernel doesn't execute the complete code( may or may not be).

Actually I have 5 print statements in kernel.c (and all the statements are working fine when I don't add any driver), but as soon as I start adding drivers (even though I am not executing any driver function), the code seems to avoid the print statements at the bottom.

I tried changing the kernel offset, but it doesn't seem to show any effect.

kernel.c


void clear_screen() // clear the entire text screen
{
    char *vga = (char *)0xb8000;
    unsigned int i = 0;
    while (i < (80 * 25 * 2))
    {
        vga[i] = ' ';
        i++;
        vga[i] = COLOR;
        i++;
    }
}

unsigned int kprintf(char *message, unsigned int line) // the message and then the line #
{
    char *vga = (char *)0xb8000;
    unsigned int i = 0;

    i = (line * 80 * 2);

    while (*message != 0)
    {
        if (*message == '\n') 
        {
            line++;
            i = (line * 80 * 2);
            *message++;
        }
        else
        {
            vga[i] = *message;
            *message++;
            i++;
            vga[i] = COLOR;
            i++;
        }
    }

    return (1);
}


void main() // like main in a normal C program
{
    clear_screen();
    kprintf("Hi!\nThis is our Kernel\n", 2);
    kprintf("Our Team Members:\n", 12);
    kprintf("1. Aditya Garg \n",13);
    kprintf("2. Ayush Agarwal\n", 14);
    kprintf("3. Anup Aglawe \n", 15);
    kprintf("4. Anshuman yadav \n", 16);
    kprintf("5. Ujjaval shah \n", 17);
};

bootsect.asm

[org 0x7c00]
KERNEL_OFFSET equ 0x1000 

    mov [BOOT_DRIVE], dl 
    mov bp, 0x9000
    mov sp, bp
    call start1
    call load_kernel 
    call switch_to_pm 
    jmp $ 

%include "boot/print.asm"
%include "boot/print_hex.asm"
%include "boot/disk.asm"
%include "boot/gdt.asm"
%include "boot/32bit_print.asm"
%include "boot/switch_pm.asm"

[bits 16]
start1:
    mov ax, 0x0          
    mov ds, ax           
    mov es, ax           
    mov bx, 0x8000
    mov ax, 13;clearScreen 
    int 0x10       
    mov ah,2 ;big font
    int 0x10

    ;Position
    mov ah,0x02         
    mov bh,0x00         
    mov dh,0x06         
    mov dl,0x09         
    int 0x10
    mov si, start_os_intro              
    call Color_String        

    ;New Position
    mov ah,0x02
    mov bh,0x00
    mov dh,0x10
    mov dl,0x0a
    int 0x10
    mov si, press_key                    
    call RedColor_String       

    mov ax,0x00         
    int 0x16 

    mov al,2 ;change font             
    mov ah,0 ;clear screen             
    int 0x10  

    ret

start_os_intro db 'Welcome to DarkraiOS!',0
press_key db '>>Press any key<<',0        
; text db 'loading ', 0   


load_kernel:

    mov bx, KERNEL_OFFSET 
    mov dh, 1 
    mov dl, [BOOT_DRIVE]
    call disk_load
    ret

[bits 32]
BEGIN_PM:

    call KERNEL_OFFSET 
    jmp $ 


BOOT_DRIVE db 0 

times 510 - ($-$$) db 0
dw 0xaa55

Makefile

C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o}

# Change this if your cross-compiler is somewhere else
CC = i686-elf-gcc
GDB = i686-elf-gdb
# -g: Use debugging symbols in gcc
CFLAGS = -g

# First rule is run by default
os-image.bin: boot\bootsect.bin kernel.bin
    type $^ > os-image.bin

# '--oformat binary' deletes all symbols as a collateral, so we don't need
# to 'strip' them manually on this case
kernel.bin: boot/kernel_entry.o ${OBJ}
    i686-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary

# Used for debugging purposes
kernel.elf: boot\kernel_entry.o ${OBJ}
    i686-elf-ld -o $@ -Ttext 0x1000 $^ 

run: os-image.bin
    qemu-system-i386 -fda os-image.bin

# Open the connection to qemu and load our kernel-object file with symbols
debug: os-image.bin kernel.elf
    qemu-system-x86_64 -s -fda os-image.bin &
    ${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"

# Generic rules for wildcards
# To make an object, always compile from its .c
%.o: %.c ${HEADERS}
    ${CC} ${CFLAGS} -ffreestanding -c $< -o $@

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

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

clean:
    rm -rf *.bin *.dis *.o os-image.bin *.elf
    rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o

Drivers ports.c

    unsigned char result;

    __asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
    return result;
}

void port_byte_out (unsigned short port, unsigned char data) {

    __asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}

unsigned short port_word_in (unsigned short port) {
    unsigned short result;
    __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
    return result;
}

void port_word_out (unsigned short port, unsigned short data) {
    __asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
}

Drivers/ports.h

unsigned char port_byte_in (unsigned short port);
void port_byte_out (unsigned short port, unsigned char data);
unsigned short port_word_in (unsigned short port);
void port_word_out (unsigned short port, unsigned short data);

Before adding the drivers' folder

After adding the drivers' folder( I'm not using any of the driver's function)

P.S. - If anyone requests, I can share my entire code.


Solution

  • Based on the screenshot where only part of the menu is printed I can guess that your kernel (kernel.bin) hasn't been entirely loaded into memory. In load_kernel you do:

    load_kernel:    
        mov bx, KERNEL_OFFSET 
        mov dh, 1                ; <----- Number of sectors to read
        mov dl, [BOOT_DRIVE]
        call disk_load
        ret
    

    The tutorial you are using passes the number of sectors to read in DH. It is documented in boot_sect_disk.asm as:

    ; load 'dh' sectors from drive 'dl' into ES:BX
    

    You need to increase that number to read enough sectors to load your entire kernel. To figure out how many sectors to load you find the size of kernel.bin, add 511 to it, and then divide by 512. numsectors=(filesize+511)/512 computes the number of 512 byte sectors needed to load a file of filesize rounded up to the nearest 512 byte sector. Load that value into DH.


    Notes