Page 1 of 1

Simple C++ Kernel

Posted: Fri May 29, 2009 1:21 am
by BetaWar
Hello, as you probably expect I am fairly new to OS dev. I have finished reading through the baby steps tutorials (found them in another topic and people seemed to get annoyed when the OP hadn't already put forth some effort) and found it a little difficult to understand how to correctly enter protected mode (I get that it is setting a single bit, but am unsure how to go about accomplishing this).

Now, I understand that many of you will read that previous paragraph and believe that there isn't a point in wasting your time with the rest of this, that may be the case (depending on how helpful I can be in answering questions and clarifying the problems I am encountering), but I hope to get some help.

I am attempting to create a simple Kernel (print out "Hello world") with C++ (mainly because Assembly is not my strong point, and I only started looking into it about 3 weeks ago). So I am trying to get as quick a sprint to something I am more comfortable with (C/C++) as possible.

On to the point. As the later baby steps tutorials left me a little puzzled, I chose to try and strip out as much as possible from them and get the desired effect (which I have failed at obtaining). Here is all my code:

boot.asm

Code: Select all

[BITS 32]
[global start]
[extern main]
start:
	call main
hang:
	jmp hang

times 510-($-$$) db 0
db 0x55
db 0xAA
Video.h

Code: Select all

#ifndef VIDEO_HEADER
#define VIDEO_HEADER

class Video{
private:
	unsigned short* videoMemory;
	unsigned int row;
	unsigned int column;
public:
	Video();
//	~Video();
	void clear();
	void write(char* p);
	void put(char c);
};
#endif
Video.cpp

Code: Select all

#include "Video.h"
Video::Video(){
	row = column = 0;
	videoMemory = (unsigned short*)0xb800;
}
//Video::~Video(){
//}
void Video::clear(){
	for(unsigned int i=0; i<(80*25); i++){
		videoMemory[i] = (unsigned char)' '|0x0700;
	}
	row = column = 0;
}
void Video::write(char* cp){
	char* str = cp;
	for(char* ch = str; *ch && *ch!='\0'; ch++){
		put(*ch);
	}
}
void Video::put(char c){
	if(column >= 80 || c == '\n'){
		column = 0;
		row += 80;
	}
	if(row >= (80*25)){
		clear(); // scroll the screen later on.
	}
	videoMemory[row+column] = (unsigned char)c|0x0700;
	column++;
}
Kernel.cpp

Code: Select all

#include "Video.h"
int main(void){
	Video vid;
	vid.clear();
	vid.write("Hello World!!!!");
}
Link.ld

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS{
	.text 0x100000 : {
		code = .; _code = .; __code = .;
		*(.text)
		. = ALIGN(4096);
	}
	.data : {
		date = .; _data = .; __data = .;
		*(.data)
		. = ALIGN(4096);
	}
	.bss : {
		bss = .; _bss = .; __bss = .;
		*(.bss)
		. = ALIGN(4096);
	}
	end = .; _end = .; __end = .;
}
Compiling, linking, and floppy burning directives:
nasm -f aout boot.asm -o boot.o
g++-2.95 -c Video.cpp -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions
g++-2.95 -c Kernel.cpp -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions
ld -T Link.ld -o Kernel.bin boot.o Kernel.o Video.o
dd if=Kernel.bin of=/dev/fd0
Desired effect:
Clear out the video memory (effectively clearing the screen)
Printing out "Hello World!!!!" to the screen

At this point that isn't happening. After reading through this thread it sounds like you have to enter protected mode to be able to do any of this.

As far as I can tell, the issue is with the boot.asm file which I believe I want to have as a binary file instead of a .o, the only problem there is that nasm won't allow you to make external calls from a binary file.

Any help/ guidance is greatly appreciated,
Beta

Re: Simple C++ Kernel

Posted: Fri May 29, 2009 1:42 am
by quanganht
Again, read CAREFULLY the Tutorials

Code: Select all

dd if=Kernel.bin of=/dev/fd0
You can't put that output file directly to the floopy driver. It's just an excutable file. And you must have an bootloader to load it and execute it. The C++ barebones didn't say but you must know that. Or, read this Bare_bones for starting.

Another thing: Your idea about 'boot.asm' is wrong. It's also one PART of the kernel and is include in the kernel.bin, not a binary.
The seperate binary file that you want is actually the BOOTLOADER. It lies on the 1st sector of the disk, which will load your kernel.bin onto the memory, then call the function "start" in your boot.asm.
Read this: Rolling_Your_Own_Bootloader
Although, you may find using GRUB make your life easier. GRUB

Also, visit JameM's tutorials here:
http://www.jamesmolloy.co.uk/tutorial_html/index.html
Remember to follow every single step, and try to fingure out what things mean. This page has details on using GRUB too.

And, try C first before attemping C++ Bare_bones

EDIT: You should rename the boot.asm to something else ( like start.asm etc... ), to not confuse it with the real bootloader

Re: Simple C++ Kernel

Posted: Fri May 29, 2009 3:25 am
by JamesM
Hi,

Given the phrasing of your question and the obvious effort you have put in it is highly likely that many people will attempt to help you (myself included) - so don't worry on that score.

To your problem then - it appears that you are mixing two tutorials in a way that will not work. You're attempting to jump to a C++ kernel, but the assembly bootstrap code you have to do that is completely incorrect.

By the "times 510-($-$$) db 0 ..." I can see that you're padding to byte 510 and then writing the MS-DOS MBR signature. This is required for an MBR (master boot record), which is what the BIOS immediately boots to. However, when the BIOS boots to it the CPU is in 16-bit real mode. This means that you cannot run any 32-bit code until you change to protected mode. Also, with an MBR you only have 512 bytes at your disposal - to get any more you literally have to ask the BIOS to load specific sectors from disk and JMP to them (which is why you can't outreference from pure binary in NASM).

So, you have two choices. Firstly, write yourself a bootloader. This will involve quite a bit of assembler - you'll need to load some sectors from disk (usually called a second stage loader), jump to them - now you have more instruction space at your disposal you'll want to load your kernel in and change to protected mode then jump to it.

Or, you could use a premade bootloader. From your aims, this is the option that I highly reccommend. GRUB is an excellent bootloader, and has an open specification to which it expects kernels to conform, called the Multiboot specification. I have written a series of tutorials in writing a small C kernel that is booted from GRUB (if you've read the wiki you'll know how to convert the C into C++). I don't usually like to namedrop them, but as someone already has in this thread here they are: http://www.jamesmolloy.co.uk/tutorial_html .

I do hope I've shed some light on your problem - let me know if not though.

Cheers,

James

Re: Simple C++ Kernel

Posted: Fri May 29, 2009 6:56 am
by sebihepp
By the way: Video Memory is at physical linear (ignore the last two words, if you don't use paging) 0xB8000.
0xB800 would be okay, if you use it as segment in Real Mode. :)

And you need some knowledge about assembler, especially when using interrupts. It is not as hard
as it sounds. It is complex, that's true, but most things are like LEGO: Complex things are built
with simple things.

If you need help with setting up your environment like the crosscompiler, GRUB, ... or with writing your
kernel, just write me a message in ICQ.
My ICQ: 241502754

Greetings
Sebihepp