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.
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.
AL
. This tutorial copies DH
to AL
inside the disk_load
function.