Writing your own Kernel

About

This tutorial will take you through a walk-through on the assembly code and c-programming language that will build up to a minimal kernel which boots up with the grub2 boot-loader. This being said keeping in mind that I am using a Ubuntu 16.04(LTS) operating system. But this will work smoothly with any older version or any other distro for that matter. This is simply because the entire process right from building the kernel to loading it from the boot-loader is independent of the operating system you use, for instance you will have a Grub boot-loader instead of Grub2. I will write separate terminal commands for both of these down below.

Pre-Requisites

1] A distro based on Linux

2] NASM assembler

3] Id(GNU LINKER)

 An Introduction

The entire code we will be writing for the custom kernel will be based on three files. The first one is written completely in assembly language, so if you are an intermediate or novice it would be great if you spend more time on understanding what it roughly means by Googling ofcourse! An attempt to fully cover the assembly code and it’s interpretation is out of the scope of this blog.

Assembly code (part 1/3 of kernel code)

bits 32
section .text
        ;multiboot spec
        align 4
        dd 0x1BADB002            
        dd 0x00                  
        dd - (0x1BADB002 + 0x00) 

global start
extern kmain	        ;kmain is defined in the c file

start:
  cli 			;block interrupts
  mov esp, stack_space	;set stack pointer
  call kmain
  hlt		 	;halt the CPU

section .bss
resb 8192		;8KB for stack
stack_space:

(Open your favourite text editor,say vim or gedit and save this file 
as kernel.asm)

(Refer this link to know more About asm extension)

The content after the “;”(semi-colon) are the comments similar to those found in the modern high level languages. The initial line of assembly code starts with bits 32 indicating it’s a directive for a 32 bit system, but my post claims to work even for a 64bit system, this is because they are backwards compatible to a lower bit version. we also invoke a kmain function in line four, this will be declared in the C-programming part of the code.

C-Programme (Part 2/3 of kernel code)

Now we start the C part of the kernel by declaring the kmain() function.

void kmain(void)
{
	const char *str = "your message";
	char *vidptr = (char*)0xb8000; 	
	unsigned int i = 0;
	unsigned int j = 0;

	
	while(j < 80 * 25 * 2) {
		/* blank character */
		vidptr[j] = ' ';
		/* attribute-byte - light grey on black screen */
		vidptr[j+1] = 0x07; 		
		j = j + 2;
	}

	j = 0;

	/* this loop writes the string to video memory */
	while(str[j] != '\0') {
		/* the character's ascii */
		vidptr[i] = str[j];
		
		vidptr[i+1] = 0x07;
		++j;
		i = i + 2;
	}
	return;
}

This essentially prints your message to a black screen when your kernel boots up.

 

The linkage (part 3/3 of kernel code)

Now to the most interesting part of the entire project, the end! Yes the last part of building your kernel is to link both the assembly code and the C-code that we wrote earlier. This is were NASM and gcc come into the picture(gcc is a c/c++ compiler) . First using NASM we compile the kernel.asm file to  a object file and again using gcc we compile kernel.c to another object file. Once that is done it is time to link both of the files together using the following linker script.

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
 {
   . = 0x100000;
   .text : { *(.text) }
   .data : { *(.data) }
   .bss  : { *(.bss)  }
 }

(We save this as link.id)

 

Now that we have the requisite files coded and ready we are left with only the bootloader issue. Next we take the kernel we created( the object files ) and make up a executable in our /boot directory and write the code with appropriate permissions to show in the Grub menu.

Building and running the Kernel

Open your command line and type in the following commands to create the object files as mentioned in the latter sections.

nasm -f elf32 kernel.asm -o kasm.o

The above code uses NASM  to compile the assembly code whereas gcc does the same for the C-code.

gcc -m32 -c kernel.c -o kc.o

As already mentioned the linker script we listed last will link the two by the following command.

ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o

Configuring Grub/Grub2 menu

Remember when I first wrote about a subtle change in code right at the end for older versions to that of the newer versions? Well, its the different line of code which pops up our entire kernel in the boot-loader menu.

 Grub users please type in the following into the last part of your grub.cfg file. You can find the grub.cfg file in the following path

g.png
/boot/grub/grub.cfg
title myKernel
	root (hd0,0)
	kernel /boot/kernel-701 ro

 

Grub2 users make the following changes, grub.cfg file locations will be the same as above.

menuentry 'kernel 7001' {
	set root='hd0,msdos1'
	multiboot /boot/kernel-7001 ro
}
    (We can access the grub menu at startup by pressing
                  either shift or esc key)

The Verdict

Now we have completely build a raw kernel which loads at boot-up. To test successfully you must get a black screen with the message that you typed in the kernel.c file appearing on it. We have not coded any I/O functions or responsive commands into it, so the kernel hangs after it.

This marks the end of your first kernel build. Stay tuned to this blog for more content, until next time, PEACE!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s