In this article, we will start with a simple x86 kernel that can be booted using GRUB. This kernel will print a message on the screen and then halt!
One-does-not-kernel
It is surprisingly easy to write a basic kernel by oneself. But how does an x86 machine actually start up? Before diving into writing a kernel, it's essential to understand what happens from the moment the machine boots until the kernel takes control.
When the x86 CPU powers on, it starts executing code at address [0xFFFFFFF0], which is the last 16 bytes of the 32-bit address space. This location contains a jump instruction that directs the CPU to the BIOS code located in memory. The BIOS then checks the boot device sequence for a bootable device by looking for a specific magic number. Once found, it loads the first sector (512 bytes) of the bootable device into physical memory at [0x7C00] and jumps to that address to begin execution. This piece of code is commonly known as a bootloader.
The bootloader is responsible for loading the kernel into memory, typically at [0x100000], which is the starting address for most x86 kernels. Now, let's look at the tools required for building such a kernel:
- An x86 architecture computer
- Linux operating system
- NASM assembler
- GCC compiler
- LD (GNU linker)
- GRUB bootloader
You can find the source code for this project on my GitHub: [mkernel](https://github.com/yourusername/mkernel).
Writing the Kernel Entry in Assembly
Although we prefer to work in C, some assembly is necessary to set up the kernel entry point. We'll write a small x86 assembly snippet that calls our C code and halts the CPU afterward. To ensure the assembly code becomes the entry point, we use a linker script to specify that the binary should be loaded at [0x100000].
Here's the assembly code:
```nasm
; kernel.asm
bits 32
section .text
global start
extern kmain
start:
cli ; Disable interrupts
call kmain
hlt ; Halt the CPU
```
The `bits 32` directive tells NASM to generate 32-bit code. The `section .text` defines the code segment. The `global start` makes the symbol `start` visible to the linker, while `extern kmain` declares that `kmain` is defined elsewhere.
Implementing the Kernel in C
The `kmain()` function is called from the assembly code. Here's what it does:
```c
void kmain(void) {
char *str = "my first kernel";
char *vidptr = (char *)0xB8000; // Video memory starts here
unsigned int i = 0, j = 0;
// Clear the screen
while (j < 80 * 25 * 2) {
vidptr[j] = ' ';
vidptr[j + 1] = 0x07; // Light grey on black
j += 2;
}
j = 0;
// Print the string
while (str[j] != '\0') {
vidptr[i] = str[j];
vidptr[i + 1] = 0x07;
++j;
i += 2;
}
}
```
This code clears the screen by writing spaces with the attribute byte `0x07` (light grey on black), then prints the string "my first kernel" at the top-left corner of the screen.
Linker Script
To link the object files correctly, we use a linker script:
```ld
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS {
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
```
This script ensures the kernel is placed at address [0x100000], where GRUB expects it to be.
GRUB and Multiboot
For GRUB to recognize the kernel, it must include a multiboot header in the first 8KB of the file. The header must contain a magic number, flags, and a checksum. Here's the updated assembly code with the multiboot header:
```nasm
; kernel.asm
bits 32
section .text
align 4
dd 0x1BADB002 ; Magic number
dd 0x00 ; Flags
dd -(0x1BADB002 + 0x00) ; Checksum
global start
extern kmain
start:
cli
call kmain
hlt
```
Compiling the Kernel
Now, let's compile and link the kernel:
```bash
nasm -f elf32 kernel.asm -o kasm.o
gcc -m32 -c kernel.c -o kc.o
ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o
```
Configuring GRUB
After compiling, rename the kernel to something like `kernel-701`, place it in `/boot`, and update your GRUB configuration (`grub.cfg`) with an entry like:
```cfg
title myKernel
root (hd0,0)
kernel /boot/kernel-701 ro
```
If you see a `hiddenmenu` line, remove it. Reboot, and you should see your kernel in the GRUB menu.
Testing the Kernel
Upon booting, the kernel will display "my first kernel" on the screen. If everything works, you've successfully created a simple x86 kernel!
PS:
- It’s recommended to develop and test kernels in a virtual machine.
- For GRUB2, the configuration might differ slightly.
- You can also test the kernel using QEMU with the command: `qemu-system-i386 -kernel kernel`.
The Digit LED Display is one type of display screen. By inputting relative current to its different pins, it will light up, so as to display all the parameters that can be represented by numbers, such as time, date, temperature, etc.
Because of its low price and simple use, it is widely used in electrical appliances, especially in the field of household appliances, such as air conditioners, water heaters, refrigerators, etc. Most water heaters use Digit LED Display, and other household appliances also use LCD and fluorescent screens.
led display,different color ,wide usage ,High intensity and reliability
Wuxi Ark Technology Electronic Co.,Ltd. , https://www.arkledcn.com