Implemented simple Multiboot1 kernel

This commit is contained in:
2024-12-29 22:02:48 +01:00
parent 84a0d49942
commit bfe67a791e
14 changed files with 488 additions and 25 deletions
+15
View File
@@ -0,0 +1,15 @@
#include "multiboot.h"
#define FLAGS (MBH_PAGE_ALIGN | MBH_GRAPH_INFO)
__attribute__ ((section(".multiboot")))
struct multiboot_header mbh = {
.magic = HEAD_MAGIC,
.flags = FLAGS,
.checksum = -(HEAD_MAGIC + FLAGS),
// We don't need the a.out format fields
.mode_type = 0,
.width = 1920,
.height = 1080,
.depth = 32,
};
+200
View File
@@ -0,0 +1,200 @@
#include "stdint.h"
#include "multiboot.h"
/* Constants */
#define COLS 80
#define ROWS 24
#define ATTR 0x0f
#define VID_MEM 0xb8000
/* Variables */
static int xpos;
static int ypos;
static uint8_t* video;
/* Forward Declarations */
void cls(void);
void itoa(char* buf, int base, int d);
void putc(int c);
void printf(const char* fmt, ...);
/* Entry Point */
void kmain(void) {
uint32_t magic, addr;
__asm__ volatile ("movl %%eax, %0; movl %%ebx, %1" : "=m"(magic), "=m"(addr));
struct multiboot_info* mbi;
video = (uint8_t*)VID_MEM;
// Clear Screen
cls();
// Didn't boot with Multiboot
if (magic != BOOT_MAGIC) {
printf("Invalid Magic Number: 0x%x\n", magic);
while (1);
}
mbi = (struct multiboot_info*)addr;
printf("flags: 0x%x\n", mbi->flags);
if (mbi->flags & MBI_MEMORY) {
printf("mem_lower: %ukB, mem_upper: %ukB\n",
mbi->mem_lower, mbi->mem_upper);
}
if (mbi->flags & MBI_BOOT_DEV) {
printf("boot_device: 0x%x\n", mbi->boot_device);
}
if (mbi->flags & MBI_CMDLINE) {
printf("cmdline: %s\n", mbi->cmdline);
}
if (mbi->flags & MBI_MODS) {
printf("mods_count: %d, mods_addr: 0x%x\n",
mbi->mods_count, mbi->mods_addr);
struct multiboot_module* mod =
(struct multiboot_module*)mbi->mods_addr;
for (size_t i = 0; i < mbi->mods_count; i++) {
printf(" start 0x%x, end: 0x%x, cmdline: %s\n",
mod->start, mod->end, mod->cmdline);
mod++;
}
}
if (mbi->flags & MBI_SYMBOLS &&
mbi->flags & MBI_ELF_HEAD) {
printf("Flag SYMBOLS and ELF HEADER are both set!\n");
while (1);
}
if (mbi->flags & MBI_MEMMAP) {
printf("mmap_addr: 0x%x, mmap_length: 0x%x\n",
mbi->mmap_addr, mbi->mmap_length);
struct multiboot_memmap* mmap =
(struct multiboot_memmap*)mbi->mmap_addr;
while ((uint32_t)mmap < mbi->mmap_addr + mbi->mmap_length) {
printf( " size: 0x%x, base: 0x%08x, "
"length: 0x%08x, type: 0x%x\n",
mmap->size, mmap->base, mmap->len, mmap->type);
mmap = (struct multiboot_memmap*)
((uint32_t)mmap + mmap->size + (sizeof(mmap->size)));
}
}
while (1);
}
void cls(void) {
for (int i = 0; i < COLS * ROWS * 2; i++) video[i] = 0;
xpos = 0;
ypos = 0;
}
void itoa(char* buf, int base, int d) {
char* p = buf;
char* p1;
char* p2;
uint32_t ud = d;
int divisor = 10;
if (base == 'd' && d < 0) {
*p++ = '-';
buf++;
ud = -d;
} else if (base == 'x') divisor = 16;
do {
int remainder = ud % divisor;
*p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
} while (ud /= divisor);
*p = 0;
p1 = buf;
p2 = p - 1;
while (p1 < p2) {
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2--;
}
}
/* Put the character C on the screen. */
void putc(int c) {
if (c == '\n' || c == '\r') {
newline:
xpos = 0;
ypos++;
if (ypos >= ROWS)
ypos = 0;
return;
}
video[(xpos + ypos * COLS) * 2] = c & 0xFF;
video[(xpos + ypos * COLS) * 2 + 1] = ATTR;
xpos++;
if (xpos >= COLS)
goto newline;
}
void printf(const char *format, ...) {
char** arg = (char**)&format;
int c;
char buf[20];
arg++;
while ((c = *format++) != 0) {
if (c != '%') {
putc (c);
continue;
}
char *p, *p2;
int pad0 = 0, pad = 0;
c = *format++;
if (c == '0') {
pad0 = 1;
c = *format++;
}
if (c >= '0' && c <= '9') {
pad = c - '0';
c = *format++;
}
switch (c) {
case 'd':
case 'u':
case 'x':
itoa(buf, c, *((int *) arg++));
p = buf;
goto string;
break;
case 's':
p = *arg++;
if (! p) p = "(null)";
string:
for (p2 = p; *p2; p2++);
for (; p2 < p + pad; p2++) putc (pad0 ? '0' : ' ');
while (*p) putc (*p++);
break;
default:
putc(*((int *) arg++));
break;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
OUTPUT_FORMAT(elf32-i386)
ENTRY(kmain)
SECTIONS {
. = 0x00100000;
/* Multiboot Header */
.multiboot ALIGN(4) : {
*(.multiboot)
}
/* Kernel Code */
.text ALIGN(4) : {
*(.text)
*(.text.*)
}
/* Read-Only Data */
.rodata ALIGN(4) : {
*(.rodata)
*(.rodata.*)
}
/* Read/Write Data */
.data ALIGN(4) : {
*(.data)
*(.data.*)
}
/* BSS Section */
.bss ALIGN(4) : {
*(COMMON)
*(.bss)
*(.bss.*)
}
/* Discarded Sections */
/DISCARD/ : {
*(.note)
*(.note.*)
*(.comment)
}
}
+19
View File
@@ -0,0 +1,19 @@
include defaults.mk
SRCS = $(shell find $(SRC) -name '**.c')
OBJS = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS))
LINKER = $(SRC)/linker.ld
OUT = $(BIN)/kernel.elf
.PHONY: all clean
all: $(OUT)
$(OUT): $(OBJS)
$(LD) $(LDFLAGS) -T $(LINKER) -o $@ $^
$(BIN)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -fr $(BIN)
+96
View File
@@ -0,0 +1,96 @@
#ifndef _MULTIBOOT_H
#define _MULTIBOOT_H
#include "stdint.h"
#define __packed __attribute__ ((packed))
#define HEAD_MAGIC 0x1BADB002
#define BOOT_MAGIC 0x2BADB002
// Multiboot Header Flags
enum {
MBH_PAGE_ALIGN = (1<<0),
MBH_MEMORY_INFO = (1<<1),
MBH_GRAPH_INFO = (1<<2),
MBH_ADDR_FIELDS = (1<<16),
};
struct multiboot_header {
uint32_t magic;
uint32_t flags;
uint32_t checksum;
uint32_t header_addr;
uint32_t load_addr;
uint32_t load_end_addr;
uint32_t bss_end_addr;
uint32_t entry_addr;
uint32_t mode_type;
uint32_t width;
uint32_t height;
uint32_t depth;
} __packed;
// Multiboot Info Flags
enum {
MBI_MEMORY = (1<<0),
MBI_BOOT_DEV = (1<<1),
MBI_CMDLINE = (1<<2),
MBI_MODS = (1<<3),
MBI_SYMBOLS = (1<<4),
MBI_ELF_HEAD = (1<<5),
MBI_MEMMAP = (1<<6),
MBI_DRIVES = (1<<7),
MBI_CONF_TAB = (1<<8),
MBI_BOOTLD_NAME = (1<<9),
MBI_APM_TABLE = (1<<10),
MBI_VBE_TABLE = (1<<11),
MBI_FB_TABLE = (1<<12),
};
struct multiboot_info {
uint32_t flags;
uint32_t mem_lower;
uint32_t mem_upper;
uint32_t boot_device;
uint32_t cmdline;
uint32_t mods_count;
uint32_t mods_addr;
uint32_t syms[4];
uint32_t mmap_length;
uint32_t mmap_addr;
uint32_t drives_length;
uint32_t drives_addr;
uint32_t config_table;
uint32_t bootloader_name;
uint32_t apm_table;
uint32_t vbe_control_info;
uint32_t vbe_mode_info;
uint32_t vbe_mode;
uint32_t vbe_interface_seg;
uint32_t vbe_interface_off;
uint32_t vbe_interface_len;
uint32_t framebuffer_addr;
uint32_t framebuffer_pitch;
uint32_t framebuffer_width;
uint32_t framebuffer_height;
uint32_t framebuffer_bpp;
uint32_t framebuffer_type;
uint32_t color_info;
} __packed;
struct multiboot_module {
uint32_t start;
uint32_t end;
uint32_t cmdline;
uint32_t __reserved;
} __packed;
struct multiboot_memmap {
uint32_t size;
uint64_t base;
uint64_t len;
uint32_t type;
} __packed;
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef _STDINT_H
#define _STDINT_H
#define NULL ((void*)0)
// Naitive width
typedef unsigned int size_t;
typedef signed int ssize_t;
// Signed ints
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
// Unsigned ints
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif