From edf9e71e2a7b6b89775c29cf28c19c6b89992c25 Mon Sep 17 00:00:00 2001 From: aqua Date: Mon, 28 Mar 2022 20:03:38 +0300 Subject: Initial commit x86 kernel that prints a hello world message to com1 --- src/boot.h | 24 ++++++++++++++++++++++++ src/kernel.c | 24 ++++++++++++++++++++++++ src/mem.h | 4 ++++ src/mem/vmm.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/mmap.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/mmap.h | 7 +++++++ src/multiboot2.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+) create mode 100644 src/boot.h create mode 100644 src/kernel.c create mode 100644 src/mem.h create mode 100644 src/mem/vmm.c create mode 100644 src/mmap.c create mode 100644 src/mmap.h create mode 100644 src/multiboot2.c (limited to 'src') diff --git a/src/boot.h b/src/boot.h new file mode 100644 index 0000000..56ff219 --- /dev/null +++ b/src/boot.h @@ -0,0 +1,24 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + // kernel command line + char cmdline[64]; + + // memory map + unsigned bitmap[1024 * 32]; + + // module + unsigned module_start; + unsigned module_end; + char module_cmdline[64]; +} boot_info_t; + +_Static_assert((1024 * 32 * sizeof(unsigned) * 8) == (1024 * 1024)); + +#ifdef __cplusplus +} +#endif diff --git a/src/kernel.c b/src/kernel.c new file mode 100644 index 0000000..b84d7ee --- /dev/null +++ b/src/kernel.c @@ -0,0 +1,24 @@ +#include "mem.h" + +#include +#include + +#include "devices/uart_16550.h" +#include "devices/vga.h" + +void kmain() { + gdt_install(); + + if (uart_init(COM1) != 0) printf("UART self-test failed.\r\n"); + + printf("hello %s world\n", "kernel"); + + vga_init(vmm_map(0xb8000, 0xc03ff000)); + + alloc4M(); + char *c = (char *)0xc0700000; + if (*c == 0) printf("c is 0\r\n"); + + while (1) + ; +} diff --git a/src/mem.h b/src/mem.h new file mode 100644 index 0000000..e06dd21 --- /dev/null +++ b/src/mem.h @@ -0,0 +1,4 @@ +#pragma once + +unsigned int vmm_map(unsigned int paddr, unsigned int vaddr); +void alloc4M(); diff --git a/src/mem/vmm.c b/src/mem/vmm.c new file mode 100644 index 0000000..431f0df --- /dev/null +++ b/src/mem/vmm.c @@ -0,0 +1,49 @@ +#include "../mem.h" +#include "paging.h" + +extern struct DirectoryEntry k_pagedir[1024]; +extern struct TableEntry k_ptable0x300[1024]; + +extern const unsigned MULTIBOOT_SIZE; +extern const unsigned VADDR_BASE; + +unsigned +to_vaddr(unsigned paddr) +{ + return paddr + (unsigned)&VADDR_BASE - (unsigned)&MULTIBOOT_SIZE; +} + +unsigned int +vmm_map(unsigned int paddr, unsigned int vaddr) +{ + if (paddr & 0xfff || vaddr & 0xfff) return 0; + + const unsigned table_idx = vaddr >> 22; // high 10 bits + const unsigned entry_idx = (vaddr >> 12) & 0x3ff; // low 10 bits + + if (k_pagedir[table_idx].present == 0) return 0; + struct TableEntry *table = (struct TableEntry *)to_vaddr(k_pagedir[table_idx].address << 12); + + table[entry_idx].address = paddr >> 12; + table[entry_idx].present = 1; + table[entry_idx].writeable = 1; + + return vaddr; +} + +void +alloc4M() +{ + // enable pse in cr4 + asm volatile(R"( + movl %cr4, %eax + orl $0x10, %eax + movl %eax, %cr4 +)"); + + struct DirectoryEntry4MB *directory = (struct DirectoryEntry4MB *)&k_pagedir[0x301]; + directory->address_low = 0x1; + directory->present = 1; + directory->writeable = 1; + directory->pagesize = 1; +} diff --git a/src/mmap.c b/src/mmap.c new file mode 100644 index 0000000..3fe35b5 --- /dev/null +++ b/src/mmap.c @@ -0,0 +1,45 @@ +#include "mmap.h" +#ifdef DEBUG +#include +#endif + +__attribute__((section(".multiboot.text"))) unsigned +multiboot2_mmap(const struct multiboot_mmap_entry entries[], unsigned entry_count, unsigned bitmap[1024 * 32]) +{ + // clear out the bitmap + for (unsigned i = 0; i < 1024 * 32; ++i) bitmap[i] = 0; + unsigned avail_frames = 0; + + // loop through all the mmap_entry structures where type is MULTIBOOT_MEMORY_AVAILABLE + for (unsigned i = 0; i < entry_count; ++i) { + if (entries[i].type != MULTIBOOT_MEMORY_AVAILABLE) continue; + + // number of frames in this entry + unsigned n_frames = entries[i].len / 4096; + avail_frames += n_frames; + +#ifdef DEBUG + printf("mmap_entry: 0x%16llx\tlen=%12llu\t%d frames (%d blocks + %d)\n", entries[i].addr, entries[i].len, n_frames, + n_frames / 32, n_frames % 32); +#endif + + // the bitmap is an array of blocks, each holding 32 (2^5) values + unsigned table_idx = (entries[i].addr >> 17); // get the upper 15 bits + + while (n_frames != 0) { + if (n_frames >= 32) { + bitmap[table_idx] = 0xffffffff; + table_idx++; + n_frames -= 32; + } + else { + unsigned block = bitmap[table_idx]; + for (unsigned l = 0; l < n_frames; ++l) block |= (1 << l); + bitmap[table_idx] = block; + n_frames = 0; + } + } + } + + return avail_frames; +} diff --git a/src/mmap.h b/src/mmap.h new file mode 100644 index 0000000..13f40f2 --- /dev/null +++ b/src/mmap.h @@ -0,0 +1,7 @@ +#pragma once + +#include "boot.h" +#include + +__attribute__((section(".multiboot.text"))) unsigned multiboot2_mmap(const struct multiboot_mmap_entry entries[], + unsigned entry_count, unsigned bitmap[1024 * 32]); diff --git a/src/multiboot2.c b/src/multiboot2.c new file mode 100644 index 0000000..d3e4175 --- /dev/null +++ b/src/multiboot2.c @@ -0,0 +1,49 @@ +#include "mmap.h" + +#define ADDR(x) ((unsigned)&x - 0xc0000000 + 0x2000) + +boot_info_t info __attribute__((section(".init"))); + +__attribute__((section(".multiboot.text"))) void +multiboot_strncpy(char *dest, const char *src, unsigned n) +{ + for (unsigned i = 0; i < n && src[i] != '\0'; ++i) dest[i] = src[i]; +} + +__attribute__((section(".multiboot.text"))) void +multiboot2_module(struct multiboot_tag_module *tag, boot_info_t *info) +{ + info->module_start = tag->mod_start; + info->module_end = tag->mod_end; + multiboot_strncpy(info->module_cmdline, tag->cmdline, 64); +} + +/** + * parse multiboot2 structures + */ +__attribute__((section(".multiboot.text"))) void +__multiboot2(multiboot_uint32_t addr) +{ + boot_info_t *__info = (boot_info_t *)ADDR(info); + + struct multiboot_tag *tag; + for (tag = (struct multiboot_tag *)(addr + 8); tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_tag *)((multiboot_uint8_t *)tag + ((tag->size + 7u) & ~7u))) { + + switch (tag->type) { + case MULTIBOOT_TAG_TYPE_CMDLINE: + multiboot_strncpy(__info->cmdline, ((struct multiboot_tag_string *)tag)->string, 64); + break; + case MULTIBOOT_TAG_TYPE_MODULE: + multiboot2_module((struct multiboot_tag_module *)tag, __info); + break; + case MULTIBOOT_TAG_TYPE_MMAP: + multiboot2_mmap(((struct multiboot_tag_mmap *)tag)->entries, + ((struct multiboot_tag_mmap *)tag)->size / ((struct multiboot_tag_mmap *)tag)->entry_size, + __info->bitmap); + break; + default: + break; + } // switch + } // for +} -- cgit v1.2.1