aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMarvin Borner2021-04-29 14:36:40 +0200
committerMarvin Borner2021-04-29 14:36:40 +0200
commitf8e47b6b0c0578c52d82c0e243620361b87a4abe (patch)
treee42d898d299b7aa10c8f266d347b4fda5a5967f3 /kernel
parent04104fc051d44f4f9b3328f29b4be91fa4060f34 (diff)
Multiboot/Grub progress
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/drivers/cpu.c15
-rw-r--r--kernel/drivers/gdt.c96
-rw-r--r--kernel/features/mm.c43
-rw-r--r--kernel/features/proc.c1
-rw-r--r--kernel/inc/cpu.h2
-rw-r--r--kernel/inc/gdt.h60
-rw-r--r--kernel/inc/mm.h3
-rw-r--r--kernel/inc/multiboot.h9
-rw-r--r--kernel/inc/proc.h5
-rw-r--r--kernel/main.c7
-rw-r--r--kernel/multiboot.c36
12 files changed, 216 insertions, 62 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index e51469d..8296e02 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -5,6 +5,7 @@ COBJS = entry_asm.o \
multiboot.o \
drivers/interrupts.o \
drivers/interrupts_asm.o \
+ drivers/gdt.o \
drivers/cpu.o \
drivers/serial.o \
drivers/pci.o \
diff --git a/kernel/drivers/cpu.c b/kernel/drivers/cpu.c
index 2c86008..5d53bef 100644
--- a/kernel/drivers/cpu.c
+++ b/kernel/drivers/cpu.c
@@ -91,21 +91,6 @@ void fpu_restore(void)
__asm__ volatile("fxrstor (%0)" ::"r"(fpu_state));
}
-void tss_set_stack(u32 ss, u32 esp)
-{
- UNUSED(ss);
- UNUSED(esp);
- return;
- /* assert(tss_entry && ss && esp); */
- /* struct { */
- /* u32 prev; */
- /* u32 esp0; */
- /* u32 ss0; */
- /* } *tss = (void *)tss_entry; */
- /* tss->esp0 = esp; */
- /* tss->ss0 = ss; */
-}
-
CLEAR static struct cpuid cpuid(u32 code)
{
u32 a, b, c, d;
diff --git a/kernel/drivers/gdt.c b/kernel/drivers/gdt.c
new file mode 100644
index 0000000..73db111
--- /dev/null
+++ b/kernel/drivers/gdt.c
@@ -0,0 +1,96 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#include <assert.h>
+#include <def.h>
+#include <gdt.h>
+#include <mem.h>
+
+static struct gdt_entry gdt[6] = { 0 };
+static struct tss_entry tss = { 0 };
+
+PROTECTED static struct gdt_ptr gp = { 0 };
+
+CLEAR static void gdt_set_gate(u32 num, u32 base, u32 limit, u8 access, u8 gran)
+{
+ // Set descriptor base address
+ gdt[num].base_low = (u16)(base & 0xffff);
+ gdt[num].base_middle = (u8)((base >> 16) & 0xff);
+ gdt[num].base_high = (u8)((base >> 24) & 0xff);
+ gdt[num].limit_low = (u16)(limit & 0xffff);
+
+ // Set granularity and access flags
+ gdt[num].granularity = (u8)((limit >> 16) & 0x0f);
+ gdt[num].granularity |= (gran & 0xf0);
+ gdt[num].access = access;
+}
+
+CLEAR static void tss_write(u32 num, u16 ss0, u32 esp0)
+{
+ u32 base = (u32)&tss;
+ u32 limit = base + sizeof(tss);
+
+ gdt_set_gate(num, base, limit, 0xe9, 0x00);
+
+ memset(&tss, 0, sizeof(tss));
+
+ tss.ss0 = ss0;
+ tss.esp0 = esp0;
+ tss.cs = 0x0b;
+ tss.ss = tss.ds = tss.es = tss.fs = tss.gs = 0x13;
+}
+
+CLEAR static void tss_flush(void)
+{
+ __asm__ volatile("ltr %0" ::"r"((u16)0x2b));
+}
+
+CLEAR static void gdt_flush(void)
+{
+ __asm__ volatile("lgdt %0" ::"m"(gp) : "memory");
+}
+
+void tss_set_stack(u32 ss, u32 esp)
+{
+ assert(ss && esp);
+ tss.esp0 = esp;
+ tss.ss0 = ss;
+}
+
+CLEAR void gdt_install(void)
+{
+ // Set GDT pointer and limit
+ gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
+ gp.base = &gdt;
+
+ // NULL descriptor
+ gdt_set_gate(0, 0, 0, 0, 0);
+
+ // Code segment
+ gdt_set_gate(1, 0, 0xffffffff, 0x9a, 0xcf);
+
+ // Data segment
+ gdt_set_gate(2, 0, 0xffffffff, 0x92, 0xcf);
+
+ // User mode code segment
+ gdt_set_gate(3, 0, 0xffffffff, 0xfa, 0xcf);
+
+ // User mode data segment
+ gdt_set_gate(4, 0, 0xffffffff, 0xf2, 0xcf);
+
+ // Write TSS
+ tss_write(5, GDT_SUPER_DATA_OFFSET, STACK_START);
+
+ // Remove old GDT and install the new changes!
+ gdt_flush();
+ tss_flush();
+
+ __asm__ volatile("mov %%ax, %%ds\n"
+ "mov %%ax, %%es\n"
+ "mov %%ax, %%fs\n"
+ "mov %%ax, %%gs\n"
+ "mov %%ax, %%ss\n" ::"a"(GDT_SUPER_DATA_OFFSET)
+ : "memory");
+
+ __asm__ volatile("ljmpl $" STRINGIFY(GDT_SUPER_CODE_OFFSET) ", $code\n"
+ "code:\n");
+}
diff --git a/kernel/features/mm.c b/kernel/features/mm.c
index 39a6316..9dd425e 100644
--- a/kernel/features/mm.c
+++ b/kernel/features/mm.c
@@ -8,6 +8,7 @@
#include <fb.h>
#include <mem.h>
#include <mm.h>
+#include <multiboot.h>
#include <print.h>
#include <rand.h>
@@ -133,7 +134,12 @@ static void physical_page_set_free(u32 address)
memory[page / 8] &= ~(1 << (page % 8));
}
-static void physical_set_used(struct memory_range range)
+CLEAR void physical_set_total(u32 total)
+{
+ memory_total = total;
+}
+
+void physical_set_used(struct memory_range range)
{
assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size));
@@ -146,7 +152,7 @@ static void physical_set_used(struct memory_range range)
}
}
-static void physical_set_free(struct memory_range range)
+void physical_set_free(struct memory_range range)
{
assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size));
@@ -721,29 +727,7 @@ void memory_user_hook(void)
CLEAR void memory_install(void)
{
- struct mem_info *mem_info = NULL;
- struct vid_info *vid_info = NULL;
-
- for (struct mmap_boot *p = mem_info->start; (u32)(p - mem_info->start) < mem_info->size;
- p++) {
- if (p->hbase || !p->acpi || !p->type)
- continue;
-
- u32 size = p->lsize;
- if (p->hsize)
- size = U32_MAX - p->lbase;
-
- /* printf("Memory region: %x-%x\n", p->lbase, p->lbase + size); */
- if (p->type == MEMORY_AVAILABLE) {
- physical_set_free(memory_range_around(p->lbase, size));
- memory_total += size;
- } else if (p->type == MEMORY_DEFECT) {
- printf("Defect memory at 0x%x-0x%x!\n", p->lbase, p->lbase + size);
- physical_set_used(memory_range_around(p->lbase, size));
- } else {
- physical_set_used(memory_range_around(p->lbase, size));
- }
- }
+ multiboot_mmap();
for (u32 i = 0; i < PAGE_KERNEL_COUNT; i++) {
union page_dir_entry *dir_entry = &kernel_dir.entries[i];
@@ -757,7 +741,7 @@ CLEAR void memory_install(void)
printf("Detected memory: %dKiB (%dMiB)\n", memory_total >> 10, memory_total >> 20);
// Set first MiB 'used' (bootloader(s), VESA tables, memory maps, ...)
- physical_set_used(memory_range(0, 0x00100000));
+ //physical_set_used(memory_range(0, 0x00100000));
// Map kernel
memory_map_identity(&kernel_dir, kernel_ro_memory_range(), MEMORY_READONLY);
@@ -772,13 +756,10 @@ CLEAR void memory_install(void)
memory_map_identity(&kernel_dir, memory_range(STACK_START, PAGE_SIZE), MEMORY_READONLY);
// Map framebuffer
- memory_map_identity(&kernel_dir, memory_range_around((u32)vid_info->vbe, 0x1000),
- MEMORY_NONE);
+ /* memory_map_identity(&kernel_dir, memory_range_around((u32)vid_info->vbe, 0x1000), */
+ /* MEMORY_NONE); */
/* fb_map_buffer(virtual_kernel_dir(), vid_info); */
- // Map TSS
- //memory_map_identity(&kernel_dir, memory_range_around(boot->tss, 0x1000), MEMORY_NONE);
-
// Unmap NULL byte/page
struct memory_range zero = memory_range(0, PAGE_SIZE);
virtual_free(&kernel_dir, zero);
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
index 70f2efc..6812c72 100644
--- a/kernel/features/proc.c
+++ b/kernel/features/proc.c
@@ -5,6 +5,7 @@
#include <cpu.h>
#include <errno.h>
#include <fs.h>
+#include <gdt.h>
#include <load.h>
#include <mem.h>
#include <mm.h>
diff --git a/kernel/inc/cpu.h b/kernel/inc/cpu.h
index 3d29e4f..7ac6074 100644
--- a/kernel/inc/cpu.h
+++ b/kernel/inc/cpu.h
@@ -32,8 +32,6 @@ void cr3_set(u32 cr3);
u32 cr4_get(void);
void cr4_set(u32 cr4);
-void tss_set_stack(u32 ss, u32 esp);
-
void clac(void);
void stac(void);
diff --git a/kernel/inc/gdt.h b/kernel/inc/gdt.h
new file mode 100644
index 0000000..06388a9
--- /dev/null
+++ b/kernel/inc/gdt.h
@@ -0,0 +1,60 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#ifndef GDT_H
+#define GDT_H
+
+#include <def.h>
+
+#define GDT_SUPER_CODE_OFFSET 0x08 // Super (kernel) code segment offset in GDT
+#define GDT_SUPER_DATA_OFFSET 0x10 // Super (kernel) data segment offset in GDT
+#define GDT_USER_CODE_OFFSET 0x1b // User code segment offset in GDT (with ring3 mask)
+#define GDT_USER_DATA_OFFSET 0x23 // User data segment offset in GDT (with ring3 mask)
+
+struct gdt_entry {
+ u16 limit_low;
+ u16 base_low;
+ u8 base_middle;
+ u8 access;
+ u8 granularity;
+ u8 base_high;
+} PACKED;
+
+struct gdt_ptr {
+ u16 limit;
+ void *base;
+} PACKED;
+
+struct tss_entry {
+ u32 prev_tss;
+ u32 esp0;
+ u32 ss0;
+ u32 esp1;
+ u32 ss1;
+ u32 esp2;
+ u32 ss2;
+ u32 cr3;
+ u32 eip;
+ u32 eflags;
+ u32 eax;
+ u32 ecx;
+ u32 edx;
+ u32 ebx;
+ u32 esp;
+ u32 ebp;
+ u32 esi;
+ u32 edi;
+ u32 es;
+ u32 cs;
+ u32 ss;
+ u32 ds;
+ u32 fs;
+ u32 gs;
+ u32 ldt;
+ u16 trap;
+ u16 iomap_base;
+} PACKED;
+
+void gdt_install(void);
+void tss_set_stack(u32 ss, u32 esp);
+
+#endif
diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h
index 1652695..a33d9d1 100644
--- a/kernel/inc/mm.h
+++ b/kernel/inc/mm.h
@@ -27,6 +27,9 @@ void page_fault_handler(struct regs *r) NONNULL;
struct memory_range physical_alloc(u32 size);
void physical_free(struct memory_range range);
+void physical_set_used(struct memory_range range);
+void physical_set_free(struct memory_range range);
+void physical_set_total(u32 total);
/**
* Virtual
diff --git a/kernel/inc/multiboot.h b/kernel/inc/multiboot.h
index f9851fb..839ade7 100644
--- a/kernel/inc/multiboot.h
+++ b/kernel/inc/multiboot.h
@@ -104,9 +104,11 @@ struct multiboot_info {
};
struct multiboot_mmap_entry {
- u32 size;
- u64 addr;
- u64 len;
+ u32 struct_size;
+ u32 addr;
+ u32 addr_high;
+ u32 len;
+ u32 len_high;
u32 type;
} PACKED;
@@ -119,6 +121,7 @@ struct multiboot_mod_list {
u32 pad;
};
+void multiboot_mmap(void);
void multiboot_init(u32 magic, u32 addr);
#endif
diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h
index 877e53e..e74286c 100644
--- a/kernel/inc/proc.h
+++ b/kernel/inc/proc.h
@@ -15,11 +15,6 @@
#define EFLAGS_ALWAYS 0x2 // Always one
#define EFLAGS_INTERRUPTS 0x200 // Enable interrupts
-#define GDT_SUPER_CODE_OFFSET 0x08 // Super (kernel) code segment offset in GDT
-#define GDT_SUPER_DATA_OFFSET 0x10 // Super (kernel) data segment offset in GDT
-#define GDT_USER_CODE_OFFSET 0x1b // User code segment offset in GDT (with ring3 mask)
-#define GDT_USER_DATA_OFFSET 0x23 // User data segment offset in GDT (with ring3 mask)
-
#define RING(regs) ((regs->cs) & 3)
enum proc_priv { PROC_PRIV_NONE, PROC_PRIV_ROOT, PROC_PRIV_KERNEL };
diff --git a/kernel/main.c b/kernel/main.c
index e0e544b..37dd2da 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -3,6 +3,7 @@
#include <boot.h>
#include <cpu.h>
#include <fs.h>
+#include <gdt.h>
#include <ide.h>
#include <interrupts.h>
#include <io.h>
@@ -26,11 +27,11 @@ int kernel_main(u32 magic, u32 addr)
// Serial connection
serial_install();
serial_print("\nKernel was compiled at " __TIME__ " on " __DATE__ "\n");
- serial_print("Serial connected. LOOPING!\n");
+ serial_print("Serial connected!\n");
+
+ gdt_install();
multiboot_init(magic, addr);
- while (1)
- ;
memory_install();
memory_switch_dir(virtual_kernel_dir());
diff --git a/kernel/multiboot.c b/kernel/multiboot.c
index eafe4c5..a9a0c75 100644
--- a/kernel/multiboot.c
+++ b/kernel/multiboot.c
@@ -2,16 +2,46 @@
#include <assert.h>
#include <def.h>
+#include <mm.h>
#include <multiboot.h>
-static struct multiboot_info *info = NULL;
+PROTECTED static struct multiboot_info *info = NULL;
-void multiboot_init(u32 magic, u32 addr)
+CLEAR void multiboot_init(u32 magic, u32 addr)
{
assert(magic == MULTIBOOT_MAGIC);
info = (void *)addr;
if (info->flags & MULTIBOOT_INFO_CMDLINE) {
- printf("CMDLINE: '%s'\n", info->cmdline);
+ // TODO: Do something useful with grub cmdline?
+ /* printf("CMDLINE: '%s'\n", info->cmdline); */
}
}
+
+CLEAR void multiboot_mmap(void)
+{
+ assert(info->flags & MULTIBOOT_INFO_MEMORY);
+
+ struct multiboot_mmap_entry *mmap = (void *)info->mmap_addr;
+ u32 length = info->mmap_length;
+ u32 count = length / sizeof(*mmap);
+
+ u32 total = 0;
+
+ for (u32 i = 0; i < count; i++) {
+ /* printf("Memory region 0x%x-0x%x\n", mmap->addr, mmap->addr + mmap->len); */
+ if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
+ total += mmap->len;
+ physical_set_free(memory_range_around(mmap->addr, mmap->len));
+ } else if (mmap->type == MULTIBOOT_MEMORY_BADRAM) {
+ printf("Defect memory at 0x%x-0x%x\n", mmap->addr, mmap->addr + mmap->len);
+ physical_set_used(memory_range_around(mmap->addr, mmap->len));
+ } else {
+ physical_set_used(memory_range_around(mmap->addr, mmap->len));
+ }
+
+ mmap++;
+ }
+
+ physical_set_total(total);
+}