Understanding Operating System by creating a simple Operating System.
Let’s create a better understanding!
Operating systems are like underwear — nobody really wants to look at them. -Bill Joy-
Hi there!
When we look into the operating system concepts there are so many things such as memory management, process management, I/O Management, scheduling, file systems, etc. If you really want to understand the concepts of operating systems very well then try to make a simple operating system on your own. Here, I’m not going to write about “The operating system concepts” or “How the operating system works”, but I’m going to share the basics for creating a simple operating system.
Let’s start>
What actually happens when you press the power button?
When the power button is pressed, the wires connected to the button send an electronic signal to the motherboard. The motherboard simply reroutes this signal to the power supply unit(PSU). This signal contains a single bit of data 0 or 1. If it is 0, there is no power (so the computer is off, or the motherboard is dead). If it is 1 (active signal), it means that power is being supplied. When the PSU receives this active signal, it begins supplying power to the rest of the system. Then the PSU sends a signal, called the “power good signal” into the Basic Input Output System (BIOS) which was stored in a ROM chip on the motherboard. When the BIOS receives this “power good signal”, the BIOS initializes a process called POST (Power On Self Test) to determine if there any hardware-related issues with the computer. If there are no issues with hardware, the BIOS then needs to find an operating system. The BIOS does several things. It creates an Interrupt Vector Table (IVT) and provides some basic interrupt services. So based on the boot order that you set in the BIOS Setup, the BIOS will execute Interrupt (INT) 0x19 to find a bootable device. This INT 0x19 handler reads 512 bytes from the first sector of boot device into the memory at address 0x7c00. If no bootable device is found (INT 0x19 returns), the BIOS goes on to the next device listed in the boot order and so on. If there is no bootable device, it will print an error and halt the system. If it finds any bootable device the control is transferred to its bootloader….
What is a bootable device and What is a bootloader or bootstrap loader?
The BIOS interrupt 0x19 reads 512 bytes from the first sector of the device, If there is a bootloader in the first 512 bytes the BIOS recognizes that device as a bootable device. So a bootable device is a device that stores a boot loader in its first 512 bytes. The bootloader is a small portion of executable code which determines the location of the kernel image on the device and load it into memory.
How to copy your bootloader into the first 512 bytes of a device.
To do in Linux:
sudo dd if=./boot.bin bs=512 of=/dev/sdc
To do it in Windows, you can download dd for windows, it’s open-source and uses this code:
dd if=c\boot.bin of=\\.\f bs=512 conv=notrunc
Do we really need to write our own bootloader to load our OS?
Many won’t write a bootloader because that would be a complex project on its own. Instead, they use one of the many well-tested bootloaders out there to boot our kernel. For example Grub2, rEFInd, Clover EFI bootloader, etc. But it will be very helpful when we understand the codes in a bootloader and how a bootloader works. Usually, bootloaders are written in assembly language because low-level languages can easily communicate with the machine. So you need some sort of knowledge in assembly language to understand a bootloader.
Here I used a bootloader code from http://www.brokenthorn.com/Resources/OSDev4.html to load my kernel to the memory.
org 0x7c00 ; loaded by BIOS at 0x7C00dw 0xAA55 ; Boot Signiture
The Kernel
Operating systems are built out of two main parts:
- The kernel
- System programs.
The kernel is the heart of the operating system. It manages computer resources, and it handles requests from system programs and applications. System programs run on top of the kernel. Here I didn’t create any system programs or include any system programs to my kernel but I just create a simple kernel that will show a prompt with some options and is capable of printing some CPU details of your machine.
Read this article about Kernal http://www.osdever.net/bkerndev/Docs/intro.htmKernel development is not an easy task. This is a testament to your programming expertise: To develop a kernel is to say that you understand how to create software that interfaces with and manages the hardware. A kernel is designed to be a central core to the operating system - the logic that manages the resources that the hardware has to offer.One of the most important system resources that you need to manage is the processor or CPU - this is in the form of allotting time for specific operations, and possibly interrupting a task or process when it is time for another scheduled event to happen. This implies multitasking. There is cooperative multitasking, in which the program itself calls a 'yield' function when it wants to give up processing time to the next runnable process or task. There is preemptive multitasking, where the system timer is used to interrupt the current process to switch to a new process: a form of forcive switch, this more guarantees that a process can be given a chunk of time to run. There are several scheduling algorithms used in order to find out what process will be run next. The simplest of which is called 'Round Robin'. This is where you simply get the next process in the list, and choose that to be runnable. A more complicated scheduler involves 'priorities', where certain higher-priority tasks are allowed more time to run than a lower-priority task. Even more complicated still is a Real-time scheduler. This is designed to guarantee that a certain process will be allowed at least a set number of timer ticks to run. Ultimately, this number one resource calculates to time.The next most important resource in the system is fairly obvious: Memory. There are some times where memory can be more precious than CPU time, as memory is limited, however CPU time is not. You can either code your kernel to be memory- efficient, yet require alot of CPU, or CPU efficient by using memory to store caches and buffers to 'remember' commonly used items instead of looking them up. The best approach would be a combination of the two: Strive for the best memory usage, while preserving CPU time.The last resource that your kernel needs to manage are hardware resources. This includes Interrupt Requests (IRQs), which are special signals that hardware devices like the keyboard and hard disk can use to tell the CPU to execute a certain routine to handle the data that these devices have ready. Another hardware resource is Direct Memory Access (DMA) channels. A DMA channel allows a device to lock the memory bus and transfer it's data directly into system memory whenever it needs to, without halting the processor's execution. This is a good way to improve performance on a system: a DMA-enabled device can transfer data without bothering the CPU, and then can interrupt the CPU with an IRQ, telling it that the data transfer is complete: Soundcards and ethernet cards are known for using both IRQs and DMA channels. The third hardware resource is in the form of an address, like memory, but it's an address on the I/O bus in the form of a port. A device can be configured, read, or given data using it's I/O port(s). A Device can use many I/O ports, typically in the form of ranges like ports 8 through 16, for example.
You can find my project files here
In my kernel code, I used CPUID instruction to discover details of the processor or CPU. You can find the full documentation of CPUID opcode here:
For example: to get processor brand information
ProcessorType:
mov al, 0x01
int 0x21mov eax, 0x80000002
cpuid
mov [strcputype], eax
mov [strcputype+4], ebx
mov [strcputype+8], ecx
mov [strcputype+12], edxmov eax,0x80000003
cpuid
mov [strcputype+16],eax
mov [strcputype+20],ebx
mov [strcputype+24],ecx
mov [strcputype+28],edxmov eax,0x80000004
cpuid
mov [strcputype+32],eax
mov [strcputype+36],ebx
mov [strcputype+40],ecx
mov [strcputype+44],edxmov si, strcputype
call Print
mov al, 0x01
int 0x21
ret[SEGMENT .bss]
strcputype resb 44
You can use other BIOS interrupts to manage and get information from hardware resources. You can find the full documentation of BIOS Interrupts here:
For example: to get how many hard drives connected to your system
HardDriveInfo:
mov al, 0x01
int 0x21mov ax,0040h ; look at 0040:0075 for a number
mov es,ax ;
mov dl,[es:0075h] ; move the number into DL register
add dl,30h ; add 48 to get ASCII value
mov al, dl
mov ah, 0x0E ; BIOS teletype acts on character
mov bh, 0x00
mov bl, 0x07
int 0x10
What’s Left
Read this article
http://www.osdever.net/bkerndev/Docs/whatsleft.htmWhat you do next to your kernel is completely up to you. The next thing you should think of writing is a memory manager. A memory manager will allow you to grab chunks of memory so that you can dynamically allocate and free memory as you need it. Using a memory manager, you can use more complicated data structures such as linked lists and binary trees to allow for more efficient storage and manipulation of data. It's also a way of preventing applications from writing to kernel pages, which is a feature of protection.It's possible to write a VGA driver, also. Using a VGA driver, you can set up different graphics modes in your kernel, allowing higher resolutions and graphical display options such as buttons and images. If you want to go further, you could eventually look into VESA video modes for high color and higher resolutions.You could eventually write a device interface which would allow you to load or unload kernel 'modules' as you need them. Add support for filesystems and disk drives so that you can access files off disks and open applications.It's very possible that you add multitasking support and design scheduling algorithms to give certain tasks higher priority and longer time to run according to what the application is designed to run at. The multitasking system closely relies on your memory manager to give each task a separate space in memory.
If you want to follow some tutorial courses to develop a simple operating system I can suggest you some best tutorials:
Other References
To understand 8086 Assembly Language
Memory allocation in Assembly
8086 Instructions
To understand NASM
I hope you got some basic ideas about OS development.
Thanks!