...
This commit is contained in:
19
README.md
19
README.md
@@ -2,16 +2,29 @@
|
|||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
### Building the kernel
|
||||||
|
|
||||||
- `make`
|
- `make`
|
||||||
- `grub`
|
|
||||||
- `mtools`
|
- `mtools`
|
||||||
- `x86_64-elf-gcc`
|
- `x86_64-elf-gcc`
|
||||||
- `x86_64-elf-ld`
|
- `x86_64-elf-ld`
|
||||||
|
|
||||||
|
### Creating a disk image
|
||||||
|
|
||||||
|
- `grub`
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
### Kernel
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make
|
make kernel
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disk image
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make iso
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
@@ -19,5 +32,5 @@ make
|
|||||||
After building, run the following:
|
After building, run the following:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
qemu-system-x86_64 -cdrom .build/nub-os.iso
|
qemu-system-i386 -kernel .build/kernel
|
||||||
```
|
```
|
||||||
|
|||||||
5
grub.cfg
5
grub.cfg
@@ -1,7 +1,6 @@
|
|||||||
menuentry "nub-os" {
|
menuentry "nub-os" {
|
||||||
multiboot2 /boot/kernel
|
multiboot /boot/kernel
|
||||||
boot
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set default="nub-os"
|
set default=0
|
||||||
set timeout=0
|
set timeout=0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ SECTIONS
|
|||||||
|
|
||||||
.text BLOCK(4K) : ALIGN(4K)
|
.text BLOCK(4K) : ALIGN(4K)
|
||||||
{
|
{
|
||||||
*(.multiboot2)
|
*(.multiboot)
|
||||||
*(.text)
|
*(.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
27
makefile
27
makefile
@@ -1,16 +1,21 @@
|
|||||||
CC = x86_64-elf-gcc
|
CC = i386-elf-gcc
|
||||||
LD = x86_64-elf-ld
|
AS = i386-elf-as
|
||||||
|
LD = i386-elf-ld
|
||||||
|
|
||||||
CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23
|
CFLAGS = -m32 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
ASFLAGS =
|
||||||
|
|
||||||
SRC_C := src/kernel.c src/vga.c src/idt.c src/string.c src/keyboard.c
|
SRC_C := src/kernel.c src/string.c src/vga.c
|
||||||
SRC_ASM := src/boot.asm src/idt_stub.asm
|
SRC_ASM := src/boot.s
|
||||||
|
|
||||||
OBJ_C := $(SRC_C:src/%.c=.build/%.o)
|
OBJ_C := $(SRC_C:src/%.c=.build/%.o)
|
||||||
OBJ_ASM := $(SRC_ASM:src/%.asm=.build/%.o)
|
OBJ_ASM := $(SRC_ASM:src/%.s=.build/%.o)
|
||||||
OBJS := $(OBJ_C) $(OBJ_ASM)
|
OBJS := $(OBJ_C) $(OBJ_ASM)
|
||||||
|
|
||||||
|
kernel: .build/kernel
|
||||||
|
@echo "Kernel created at '.build/kernel'"
|
||||||
|
|
||||||
iso: .build/nub-os.iso
|
iso: .build/nub-os.iso
|
||||||
@echo "ISO created at '.build/nub-os.iso'"
|
@echo "ISO created at '.build/nub-os.iso'"
|
||||||
|
|
||||||
@@ -20,17 +25,17 @@ clean:
|
|||||||
build-dir:
|
build-dir:
|
||||||
mkdir .build 2>/dev/null || true
|
mkdir .build 2>/dev/null || true
|
||||||
|
|
||||||
.build/nub-os.iso: .build/kernel
|
.build/nub-os.iso: .build/kernel grub.cfg
|
||||||
mkdir -p .build/nub-os/boot/grub
|
mkdir -p .build/nub-os/boot/grub
|
||||||
cp grub.cfg .build/nub-os/boot/grub
|
cp grub.cfg .build/nub-os/boot/grub
|
||||||
cp .build/kernel .build/nub-os/boot/
|
cp .build/kernel .build/nub-os/boot/
|
||||||
grub-mkrescue -o .build/nub-os.iso .build/nub-os/
|
grub-mkrescue -o .build/nub-os.iso .build/nub-os/
|
||||||
|
|
||||||
.build/kernel: $(OBJS)
|
.build/kernel: $(OBJS) | linker.ld
|
||||||
$(LD) $(LDFLAGS) -T src/boot.ld -o $@ $^
|
$(LD) $(LDFLAGS) -m elf_i386 -T linker.ld -o $@ $^
|
||||||
|
|
||||||
.build/%.o: src/%.c | build-dir
|
.build/%.o: src/%.c | build-dir
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
.build/%.o: src/%.asm | build-dir
|
.build/%.o: src/%.s | build-dir
|
||||||
nasm -f elf64 -o $@ $<
|
$(AS) $(ASFLAGS) -o $@ $<
|
||||||
204
src/boot.asm
204
src/boot.asm
@@ -1,204 +0,0 @@
|
|||||||
%define MAGIC 0xe85250d6
|
|
||||||
%define ARCH 0
|
|
||||||
%define LEN header_end - header_start
|
|
||||||
%define CHECKSUM -(MAGIC + ARCH + LEN)
|
|
||||||
|
|
||||||
section .multiboot2
|
|
||||||
header_start:
|
|
||||||
align 4
|
|
||||||
dd MAGIC
|
|
||||||
dd ARCH
|
|
||||||
dd LEN
|
|
||||||
dd CHECKSUM
|
|
||||||
dw 0
|
|
||||||
dd 8
|
|
||||||
header_end:
|
|
||||||
|
|
||||||
section .bss
|
|
||||||
align 16
|
|
||||||
resb 16384
|
|
||||||
stack_top:
|
|
||||||
|
|
||||||
align 4096
|
|
||||||
pml4_table:
|
|
||||||
resb 4096
|
|
||||||
pdp_table:
|
|
||||||
resb 4096
|
|
||||||
pd_table:
|
|
||||||
resb 4096
|
|
||||||
|
|
||||||
section .text
|
|
||||||
bits 32
|
|
||||||
global _start
|
|
||||||
_start:
|
|
||||||
cli
|
|
||||||
mov esp, stack_top
|
|
||||||
|
|
||||||
; Check if CPU supports 64-bit mode
|
|
||||||
call check_multiboot
|
|
||||||
call check_cpuid
|
|
||||||
call check_long_mode
|
|
||||||
|
|
||||||
; Set up paging for 64-bit mode
|
|
||||||
call set_up_page_tables
|
|
||||||
call enable_paging
|
|
||||||
|
|
||||||
; Load GDT and jump to 64-bit mode
|
|
||||||
lgdt [gdt64.pointer]
|
|
||||||
jmp gdt64.code:long_mode_start
|
|
||||||
|
|
||||||
check_multiboot:
|
|
||||||
cmp eax, 0x36d76289
|
|
||||||
jne .no_multiboot
|
|
||||||
ret
|
|
||||||
|
|
||||||
.no_multiboot:
|
|
||||||
mov al, 'M'
|
|
||||||
jmp error
|
|
||||||
|
|
||||||
check_cpuid:
|
|
||||||
; Copy flags to eax through the stack
|
|
||||||
pushfd
|
|
||||||
pop eax
|
|
||||||
|
|
||||||
; Copy flags to ecx for a later comparison
|
|
||||||
mov ecx, eax
|
|
||||||
|
|
||||||
; Flit the cpuid bit
|
|
||||||
xor eax, 1 << 21
|
|
||||||
|
|
||||||
; Copy eax (with the flipped cpuid bit) back to flags
|
|
||||||
push eax
|
|
||||||
popfd
|
|
||||||
|
|
||||||
; Copy flags back to eax. The cpiuid bit will be flipped if cpuid is supported
|
|
||||||
pushfd
|
|
||||||
pop eax
|
|
||||||
|
|
||||||
; Restore flags from the original flags stored in ecx
|
|
||||||
push ecx
|
|
||||||
popfd
|
|
||||||
|
|
||||||
; Compare eax and ecx. If thry are equal, cpuid is not supported
|
|
||||||
cmp eax, ecx
|
|
||||||
je .no_cpuid
|
|
||||||
ret
|
|
||||||
|
|
||||||
.no_cpuid:
|
|
||||||
mov al, 'I'
|
|
||||||
jmp error
|
|
||||||
|
|
||||||
check_long_mode:
|
|
||||||
; Test if extended processor info is available
|
|
||||||
mov eax, 0x80000000
|
|
||||||
cpuid
|
|
||||||
cmp eax, 0x80000001
|
|
||||||
jb .no_long_mode
|
|
||||||
|
|
||||||
; Test if long mode is available
|
|
||||||
mov eax, 0x80000001
|
|
||||||
cpuid
|
|
||||||
test edx, 1 << 29
|
|
||||||
jz .no_long_mode
|
|
||||||
ret
|
|
||||||
|
|
||||||
.no_long_mode:
|
|
||||||
mov al, 'L'
|
|
||||||
jmp error
|
|
||||||
|
|
||||||
; todo(nub): This is copy pasted. I will research hat it does later
|
|
||||||
set_up_page_tables:
|
|
||||||
; Map first PML4 entry to PDP table
|
|
||||||
mov eax, pdp_table
|
|
||||||
or eax, 0b11 ; present + writable
|
|
||||||
mov [pml4_table], eax
|
|
||||||
|
|
||||||
; Map first PDP entry to PD table
|
|
||||||
mov eax, pd_table
|
|
||||||
or eax, 0b11 ; present + writable
|
|
||||||
mov [pdp_table], eax
|
|
||||||
|
|
||||||
; Map each PD entry to a huge 2MiB page
|
|
||||||
mov ecx, 0 ; counter variable
|
|
||||||
.map_pd_table:
|
|
||||||
; Map ecx-th PD entry to a huge page that starts at address (2MiB * ecx)
|
|
||||||
mov eax, 0x200000 ; 2MiB
|
|
||||||
mul ecx ; Start address of ecx-th page
|
|
||||||
or eax, 0b10000011 ; present + writable + huge
|
|
||||||
mov [pd_table + ecx * 8], eax ; Map ecx-th entry
|
|
||||||
|
|
||||||
inc ecx ; Increase counter
|
|
||||||
cmp ecx, 512 ; If counter == 512, the whole PD table is mapped
|
|
||||||
jne .map_pd_table ; Else map the next entry
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
; todo(nub): This is copy pasted. I will research hat it does later
|
|
||||||
enable_paging:
|
|
||||||
; Load PML4 to cr3 register (cpu uses this to access the PML4 table)
|
|
||||||
mov eax, pml4_table
|
|
||||||
mov cr3, eax
|
|
||||||
|
|
||||||
; Enable PAE-flag in cr4 (Physical Address Extension)
|
|
||||||
mov eax, cr4
|
|
||||||
or eax, 1 << 5
|
|
||||||
mov cr4, eax
|
|
||||||
|
|
||||||
; Set the long mode bit in the EFER MSR (model specific register)
|
|
||||||
mov ecx, 0xC0000080
|
|
||||||
rdmsr
|
|
||||||
or eax, 1 << 8
|
|
||||||
wrmsr
|
|
||||||
|
|
||||||
; Enable paging in the cr0 register
|
|
||||||
mov eax, cr0
|
|
||||||
or eax, 1 << 31
|
|
||||||
mov cr0, eax
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
error:
|
|
||||||
mov byte [0xb8000], '['
|
|
||||||
mov byte [0xb8002], ' '
|
|
||||||
mov byte [0xb8004], 'E'
|
|
||||||
mov byte [0xb8005], 4
|
|
||||||
mov byte [0xb8006], 'R'
|
|
||||||
mov byte [0xb8007], 4
|
|
||||||
mov byte [0xb8008], 'R'
|
|
||||||
mov byte [0xb8009], 4
|
|
||||||
mov byte [0xb800a], ' '
|
|
||||||
mov byte [0xb800c], ']'
|
|
||||||
mov byte [0xb800e], ':'
|
|
||||||
mov byte [0xb8010], ' '
|
|
||||||
mov byte [0xb8012], al
|
|
||||||
cli
|
|
||||||
.hang:
|
|
||||||
hlt
|
|
||||||
jmp .hang
|
|
||||||
|
|
||||||
section .rodata
|
|
||||||
gdt64:
|
|
||||||
dq 0
|
|
||||||
.code: equ $ - gdt64
|
|
||||||
dq (1<<43) | (1<<44) | (1<<47) | (1<<53)
|
|
||||||
.pointer:
|
|
||||||
dw $ - gdt64 - 1
|
|
||||||
dq gdt64
|
|
||||||
|
|
||||||
section .text
|
|
||||||
bits 64
|
|
||||||
long_mode_start:
|
|
||||||
mov ax, 0
|
|
||||||
mov ss, ax
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
extern kernel_main
|
|
||||||
call kernel_main
|
|
||||||
|
|
||||||
cli
|
|
||||||
.hang:
|
|
||||||
hlt
|
|
||||||
jmp .hang
|
|
||||||
37
src/boot.s
Normal file
37
src/boot.s
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
.set ALIGN, 1<<0
|
||||||
|
.set MEMINFO, 1<<1
|
||||||
|
.set FLAGS, ALIGN | MEMINFO
|
||||||
|
.set MAGIC, 0x1BADB002
|
||||||
|
.set CHECKSUM, -(MAGIC + FLAGS)
|
||||||
|
|
||||||
|
.section .multiboot
|
||||||
|
.align 4
|
||||||
|
.long MAGIC
|
||||||
|
.long FLAGS
|
||||||
|
.long CHECKSUM
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.align 16
|
||||||
|
stack_bottom:
|
||||||
|
.skip 16384
|
||||||
|
stack_top:
|
||||||
|
|
||||||
|
.set BOOTLOADER_MAGIC, 0x2BADB002
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
mov stack_top, esp
|
||||||
|
|
||||||
|
cmp eax, BOOTLOADER_MAGIC
|
||||||
|
jne hang
|
||||||
|
|
||||||
|
push ebx
|
||||||
|
call kernel_main
|
||||||
|
add esp, 4
|
||||||
|
hang:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp hang
|
||||||
24
src/kernel.c
24
src/kernel.c
@@ -1,35 +1,17 @@
|
|||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "idt.h"
|
#include "multiboot.h"
|
||||||
#include "keyboard.h"
|
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void keyboard_handler(const keyboard_event_t* event)
|
void kernel_main(multiboot_info_t* multiboot_info)
|
||||||
{
|
|
||||||
if (event->pressed && event->ascii)
|
|
||||||
{
|
|
||||||
vga_print_char(event->ascii);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_main(void)
|
|
||||||
{
|
{
|
||||||
vga_clear();
|
vga_clear();
|
||||||
vga_print_success();
|
vga_print_success();
|
||||||
vga_print(" VGA intialzied\n");
|
vga_print(" VGA intialzied\n");
|
||||||
|
|
||||||
init_idt();
|
|
||||||
vga_print_success();
|
|
||||||
vga_print(" IDT intialzied\n");
|
|
||||||
|
|
||||||
init_keyboard();
|
|
||||||
vga_print_success();
|
|
||||||
vga_print(" Keyboard driver intialzied\n");
|
|
||||||
|
|
||||||
vga_print("\nWelcome to nub OS\n");
|
vga_print("\nWelcome to nub OS\n");
|
||||||
|
|
||||||
register_keypress_handler(keyboard_handler);
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/multiboot.h
Normal file
58
src/multiboot.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct multiboot_info
|
||||||
|
{
|
||||||
|
uint32_t flags; // required
|
||||||
|
|
||||||
|
// Available if flags[0] is set
|
||||||
|
uint32_t mem_lower;
|
||||||
|
uint32_t mem_upper;
|
||||||
|
|
||||||
|
// Available if flags[1] is set
|
||||||
|
uint32_t boot_device;
|
||||||
|
|
||||||
|
// Available if flags[2] is set
|
||||||
|
uint32_t cmdline;
|
||||||
|
|
||||||
|
// Available if flags[3] is set
|
||||||
|
uint32_t mods_count;
|
||||||
|
uint32_t mods_addr;
|
||||||
|
|
||||||
|
// Available if flags[4] or flags[5] is set
|
||||||
|
uint8_t syms[16]; // 28 - 40 bytes, exact layout may differ depending on a.out or ELF
|
||||||
|
|
||||||
|
// Available if flags[6] is set
|
||||||
|
uint32_t mmap_length;
|
||||||
|
uint32_t mmap_addr;
|
||||||
|
|
||||||
|
// Available if flags[7] is set
|
||||||
|
uint32_t drives_length;
|
||||||
|
uint32_t drives_addr;
|
||||||
|
|
||||||
|
// Available if flags[8] is set
|
||||||
|
uint32_t config_table;
|
||||||
|
|
||||||
|
// Available if flags[9] is set
|
||||||
|
uint32_t boot_loader_name;
|
||||||
|
|
||||||
|
// Available if flags[10] is set
|
||||||
|
uint32_t apm_table;
|
||||||
|
|
||||||
|
// Available if flags[11] is set
|
||||||
|
uint32_t vbe_control_info;
|
||||||
|
uint32_t vbe_mode_info;
|
||||||
|
uint16_t vbe_mode;
|
||||||
|
uint16_t vbe_interface_seg;
|
||||||
|
uint16_t vbe_interface_off;
|
||||||
|
uint16_t vbe_interface_len;
|
||||||
|
|
||||||
|
// Available if flags[12] is set
|
||||||
|
uint64_t framebuffer_addr; // 64-bit for large memory addresses
|
||||||
|
uint32_t framebuffer_pitch;
|
||||||
|
uint32_t framebuffer_width;
|
||||||
|
uint32_t framebuffer_height;
|
||||||
|
uint8_t framebuffer_bpp;
|
||||||
|
uint8_t framebuffer_type;
|
||||||
|
uint8_t color_info[6]; // 110-115 bytes
|
||||||
|
} __attribute__((packed)) multiboot_info_t;
|
||||||
10
src/string.c
10
src/string.c
@@ -26,7 +26,7 @@ void reverse(char* str, size_t length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int uitoa(uint64_t value, char* buffer)
|
int uitoa(uint32_t value, char* buffer)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
@@ -47,7 +47,7 @@ int uitoa(uint64_t value, char* buffer)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int itoa(int64_t value, char* buffer)
|
int itoa(int32_t value, char* buffer)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@@ -59,16 +59,16 @@ int itoa(int64_t value, char* buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
uint64_t v;
|
uint32_t v;
|
||||||
|
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
{
|
{
|
||||||
negative = true;
|
negative = true;
|
||||||
v = (uint64_t)(-value);
|
v = (uint32_t)(-value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
v = (uint64_t)value;
|
v = (uint32_t)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (v > 0)
|
while (v > 0)
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
|
|
||||||
int strcmp(const char* a, const char* b);
|
int strcmp(const char* a, const char* b);
|
||||||
void reverse(char* str, size_t length);
|
void reverse(char* str, size_t length);
|
||||||
int uitoa(uint64_t value, char* buffer);
|
int uitoa(uint32_t value, char* buffer);
|
||||||
int itoa(int64_t value, char* buffer);
|
int itoa(int32_t value, char* buffer);
|
||||||
@@ -138,14 +138,14 @@ void vga_print_error(void)
|
|||||||
vga_print(" ]");
|
vga_print(" ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_print_uint(uint64_t value)
|
void vga_print_uint(uint32_t value)
|
||||||
{
|
{
|
||||||
char buffer[11];
|
char buffer[11];
|
||||||
uitoa(value, buffer);
|
uitoa(value, buffer);
|
||||||
vga_print(buffer);
|
vga_print(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_print_int(int64_t value)
|
void vga_print_int(int32_t value)
|
||||||
{
|
{
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
itoa(value, buffer);
|
itoa(value, buffer);
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ void vga_print_colored(const char* string, vga_color_t color);
|
|||||||
void vga_print_success(void);
|
void vga_print_success(void);
|
||||||
void vga_print_error(void);
|
void vga_print_error(void);
|
||||||
|
|
||||||
void vga_print_uint(uint64_t value);
|
void vga_print_uint(uint32_t value);
|
||||||
void vga_print_int(int64_t value);
|
void vga_print_int(int32_t value);
|
||||||
|
|
||||||
static inline vga_color_t vga_color(vga_color_t fg_color, vga_color_t bg_color)
|
static inline vga_color_t vga_color(vga_color_t fg_color, vga_color_t bg_color)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user