How to Make an Operating System in C++ 
How to Make an Operating System in C++ 
     

                   How to Make an operating system in C++ is asked by many people but developing an Operating System on your own is impossible Because, Windows XP had 40 million lines of code and Windows vista had 55 million line of code, by the way we can create our own Basic kernel  by, Using C or C++, or any programming languages like Java, pascal,but we have to use assembly in some places. 

 Assembly Language
         Assembly is a low-level programming language that you can use it to control everything like adding something to CPU registers, control BIOs memory and much more.


I am going to show you How to Make an Operating System in C++ 

Prerequisite:
          For creating an Basic kernel Operating System you have to know everything of your programming language like pointers, BUILTIN functions here I am gonna use C++, little code of Assembly Language so you must have some knowledge of the these languages too. 


Tools I need to make an operating system

To develop an operating system you must have these:

A cross-compiler
       In order to Make an operating system, you must have a cross compiler because you must compile your kernel for it's executable format here, I am gonna use gcc(gnu compiler collection) you can download it from http://gcc.gnu.org/.

A linker 
                  the linker take's your objects and link them to getter here i use gnu binutils you can download it from http://gnu.org/software/binutils

 An Assembler 
                   Assembler takes your assembly code and give you the low-level outputs like an object containing your controls on CPU registers the assembler here i want to use is nasm(netwide assembler) you can download it from http://nasm.us 

 A virtual machine
                   In order to test your operating system, you must have a vm(virtual machine) but it isn't necessary here i use Virtual box or other virtual machine you can download it from http://virtualbox.org/ 

Note! 
        When developing an operating system we couldn't use the built in directives or header file like <iostream>, <fstream>, <memory>, <cstdio>, <cstdlib>, <windows.h>, <unistd.h> and all the platform API's We should write our own header file.

          When you are making your own Operating System,you have control of everything so, you can destroy one some or all of your hardware that why, I recommend to use a virtual machine to test your operating system instead of rebooting again and again when compiling your code. 

Bootloader 
                  An bootloader is a bunch of code that is written in assembly language and must be 512 byets(1 sector).It load's your operating system's kernel we skip writing code for the Bootloader because its very hard to write and the purpose of the every bootloader from DOS to Windows 10 is the Same just load your kernal so we will use grub as our bootloader. You can download grub source code from http://gnu.org/software/grub.


Now Start Writing kernel

             We want to Make an operating system so, we have to create the functions ourselves first, we will create a file boot.asm an Assembly language file with these contents:      



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
;boot.asm:the bootloader to boot are operating system with grub
[bits 32] ;we are in 32 bit
global start ;start's the operating system:we call it in the linker script
extern _kernel_main ;this is in are .cpp file and it is the main function of are kernel
;do not modify these lines(these are needed by grub)!
section .mbHeader

align 0x4
 
; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002           ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required
 
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM
 
;you can modify these
start:
push ebx ;this is optional and load's the grub structure
call _kernel_main

Now let just create a file named: kernel.cpp with these contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stddef.h> //we can use it: it doesnt use any platform-related api functions
#include <stdint.h> //include it to get int16_t and some integer types

/* Hardware text mode color constants. */
enum vga_color
{
 COLOR_BLACK = 0,
 COLOR_BLUE = 1,
 COLOR_GREEN = 2,
 COLOR_CYAN = 3,
 COLOR_RED = 4,
 COLOR_MAGENTA = 5,
 COLOR_BROWN = 6,
 COLOR_LIGHT_GREY = 7,
 COLOR_DARK_GREY = 8,
 COLOR_LIGHT_BLUE = 9,
 COLOR_LIGHT_GREEN = 10,
 COLOR_LIGHT_CYAN = 11,
 COLOR_LIGHT_RED = 12,
 COLOR_LIGHT_MAGENTA = 13,
 COLOR_LIGHT_BROWN = 14,
 COLOR_WHITE = 15,
};
 
uint8_t make_color(enum vga_color fg, enum vga_color bg)
{
 return fg | bg << 4;
}
 
uint16_t make_vgaentry(char c, uint8_t color)
{
 uint16_t c16 = c;
 uint16_t color16 = color;
 return c16 | color16 << 8;
}
 
size_t strlen(const char* str)
{
 size_t ret = 0;
 while ( str[ret] != 0 )
  ret++;
 return ret;
}
 
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 24;
 
size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;
 
void terminal_initialize()
{
 terminal_row = 0;
 terminal_column = 0;
 terminal_color = make_color(COLOR_LIGHT_GREY, COLOR_BLACK);
 terminal_buffer = (uint16_t*) 0xB8000;
 for ( size_t y = 0; y < VGA_HEIGHT; y++ )
 {
  for ( size_t x = 0; x < VGA_WIDTH; x++ )
  {
   const size_t index = y * VGA_WIDTH + x;
   terminal_buffer[index] = make_vgaentry(' ', terminal_color);
  }
 }
}
 
void terminal_setcolor(uint8_t color)
{
 terminal_color = color;
}
 
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
{
 const size_t index = y * VGA_WIDTH + x;
 terminal_buffer[index] = make_vgaentry(c, color);
}
 
void terminal_putchar(char c)
{
 terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
 if ( ++terminal_column == VGA_WIDTH )
 {
  terminal_column = 0;
  if ( ++terminal_row == VGA_HEIGHT )
  {
   terminal_row = 0;
  }
 }
}
 
void terminal_writestring(const char* data)
{
 size_t datalen = strlen(data);
 for ( size_t i = 0; i < datalen; i++ )
  terminal_putchar(data[i]);
}
 
void kernel_main()
{
terminal_initialize();
terminal_writestring("wellcome to my first operating system!");
for(;;);
}

The linker script

create a file: linker.ld with these contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* The bootloader will look at this image and start execution at the symbol
   designated as the entry point. */
ENTRY(start)

/* Tell where the various sections of the object files will be put in the final
   kernel image. */
SECTIONS
{
 /* Begin putting sections at 1 MiB, a conventional place for kernels to be
    loaded at by the bootloader. */
 . = 1M;

 /* First put the multiboot header, as it is required to be put very early
    early in the image or the bootloader won't recognize the file format.
    Next we'll put the .text section. */
 .text BLOCK(4K) : ALIGN(4K)
 {
  *(.mbHeader)
  *(.text)
 }

 /* Read-only data. */
 .rodata BLOCK(4K) : ALIGN(4K)
 {
  *(.rodata)
 }

 /* Read-write data (initialized) */
 .data BLOCK(4K) : ALIGN(4K)
 {
  *(.data)
 }

 /* Read-write data (uninitialized) and stack */
 .bss BLOCK(4K) : ALIGN(4K)
 {
  *(COMMON)
  *(.bss)
 }

 /* The compiler may produce other sections, by default it will put them in
    a segment with the same name. Simply add stuff here as needed. */
}

How to compile it

go to the shell (on windows cygwin is required):
type these commands:
1
2
3
nasm -f elf boot.asm -o boot.o
g++ -c kernel.cpp -o kernel.o -ffreestandinng -fno-exceptions -fno-rtti
gcc loader.o kernel.o -T linker.ld -o kern -nostdlib -nodefaultlibs -lgcc

kingratulations!
your first operating system has been compiled successfully!
now you can create an image using grub-mkrescue:
create a directory: iso
in that directory, create another directory: boot then in the boot directory, create a directory: grub and then create a file: grub.cfg with these contents(do not add the braces in a new line) in the grub directory:
1
2
3
menuentry "myOS" {
multiboot /boot/kern
}

then copy your kernel (kern) to iso/boot directory and run your shell again:
switch to the main directory of your kernel and type:
 
grub-mkrescue iso --output=kern.iso

now you can boot and enjoy from your first operating system:: this simple kernel without anything

1 Comments

  1. U Copied this: http://www.cplusplus.com/articles/zv07M4Gy/
    What a waste of time

    ReplyDelete

Post a Comment

Previous Post Next Post