[amd64] basic init

This commit is contained in:
Mark
2019-03-23 13:12:50 +02:00
parent f77bcef38e
commit 4d27fcac0b
23 changed files with 561 additions and 8 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ export O?=$(abspath build)
include conf/make/none.mk
include conf/make/$(ARCH).mk
all: mkdirs _doc $(TARGETS)
all: mkdirs $(TARGETS)
clean:
@rm -rf $(O)
+22 -6
View File
@@ -1,15 +1,31 @@
all:
### Kernel build
OBJS+=$(O)/arch/amd64/entry.o
DEFINES+=-DARCH_AMD64
OBJS+=$(O)/arch/amd64/kernel.o \
$(O)/arch/amd64/mm/pool.o \
$(O)/arch/amd64/mm/mm.o \
$(O)/arch/amd64/hw/rs232.o \
$(O)/arch/amd64/hw/gdt.o \
$(O)/arch/amd64/hw/gdt_s.o
kernel_OBJS=$(O)/arch/amd64/entry.o \
$(OBJS)
kernel_LINKER=$(S)/arch/amd64/link.ld
kernel_LDFLAGS=-nostdlib -T$(kernel_LINKER)
kernel_CFLAGS=-ffreestanding -I$(S)
kernel_CFLAGS=-ffreestanding -I$(S) $(DEFINES) $(CFLAGS)
DIRS+=$(O)/arch/amd64/mm \
$(O)/arch/amd64/hw
$(O)/kernel.elf: $(OBJS) $(kernel_LINKER)
$(CROSSLD) $(kernel_LDFLAGS) -o $@ $(OBJS)
$(O)/kernel.elf: $(kernel_OBJS) $(kernel_LINKER)
@printf " LD\t%s\n" $@
@$(CROSSLD) $(kernel_LDFLAGS) -o $@ $(kernel_OBJS)
$(O)/arch/amd64/%.o: $(S)/arch/amd64/%.S
$(CROSSCC) $(kernel_CFLAGS) -c -o $@ $<
$(O)/%.o: $(S)/%.S
@printf " AS\t%s\n" $@
@$(CROSSCC) $(kernel_CFLAGS) -c -o $@ $<
$(O)/%.o: $(S)/%.c
@printf " CC\t%s\n" $@
@$(CROSSCC) $(kernel_CFLAGS) -c -o $@ $<
### Kernel loader build
TARGETS+=$(O)/loader.elf $(O)/kernel.elf
+9 -1
View File
@@ -1,3 +1,11 @@
HEADERS=$(shell find $(S) -name "*.h")
OBJS+=
CFLAGS+=-Wall \
-Wextra \
-Werror \
-Wno-unused-parameter
DIRS+=$(O)/sys
OBJS+=$(O)/sys/mem.o \
$(O)/sys/string.o \
$(O)/sys/debug.o
+12
View File
@@ -1,5 +1,17 @@
.section .text
.global _start
_start:
cli
movabsq $kernel_stack_top, %rsp
call kernel_main
1:
cli
hlt
jmp 1b
.section .bss
kernel_stack_bottom:
.skip 65536
kernel_stack_top:
+44
View File
@@ -0,0 +1,44 @@
#include "gdt.h"
extern void amd64_reload_segs(void);
#define AMD64_GDT_SIZE 3
#define GDT_ACC_AC (1 << 0)
#define GDT_ACC_RW (1 << 1)
#define GDT_ACC_DC (1 << 2)
#define GDT_ACC_EX (1 << 3)
#define GDT_ACC_S (1 << 4)
#define GDT_ACC_R0 (0 << 5)
#define GDT_ACC_R1 (1 << 5)
#define GDT_ACC_R2 (2 << 5)
#define GDT_ACC_R3 (3 << 5)
#define GDT_ACC_PR (1 << 7)
#define GDT_FLG_LONG (1 << 5)
#define GDT_FLG_SZ (1 << 6)
#define GDT_FLG_GR (1 << 7)
static amd64_gdt_entry_t gdt[AMD64_GDT_SIZE];
static amd64_gdt_ptr_t gdtr;
static void amd64_gdt_set(int idx, uint32_t base, uint32_t limit, uint8_t flags, uint8_t access) {
gdt[idx].base_lo = base & 0xFFFF;
gdt[idx].base_mi = (base >> 16) & 0xFF;
gdt[idx].base_hi = (base >> 24) & 0xFF;
gdt[idx].access = access;
gdt[idx].flags = (flags & 0xF0) | ((limit >> 16) & 0xF);
gdt[idx].limit_lo = limit & 0xFFFF;
}
void amd64_gdt_init(void) {
gdtr.size = sizeof(gdt) - 1;
gdtr.offset = (uintptr_t) gdt;
amd64_gdt_set(0, 0, 0, 0, 0);
amd64_gdt_set(1, 0, 0, GDT_FLG_LONG, GDT_ACC_PR | GDT_ACC_R0 | GDT_ACC_EX | GDT_ACC_S | GDT_ACC_RW);
amd64_gdt_set(2, 0, 0, 0, GDT_ACC_PR | GDT_ACC_R0 | GDT_ACC_S | GDT_ACC_RW);
asm volatile ("lea gdtr(%rip), %rax; lgdt (%rax)");
amd64_reload_segs();
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef struct {
uint16_t limit_lo;
uint16_t base_lo;
uint8_t base_mi;
uint8_t access;
uint8_t flags;
uint8_t base_hi;
} amd64_gdt_entry_t;
typedef struct {
uint16_t size;
uintptr_t offset;
} __attribute__((packed)) amd64_gdt_ptr_t;
void amd64_gdt_init(void);
+21
View File
@@ -0,0 +1,21 @@
.section .text
.global amd64_reload_segs
amd64_reload_segs:
cli
movabsq $.jmpbuf, %rax
rex.w ljmp *(%rax)
.reload_data:
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
ret
.jmpbuf:
.quad .reload_data
.word 0x08
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
static inline void outb(uint16_t addr, uint8_t v) {
asm volatile("outb %0, %1"::"a"(v), "Nd"(addr));
}
static inline uint8_t inb(uint16_t addr) {
uint8_t v;
asm volatile("inb %1, %0":"=a"(v):"Nd"(addr));
return v;
}
static inline void outl(uint16_t addr, uint32_t v) {
asm volatile("outl %0, %1"::"a"(v), "Nd"(addr));
}
static inline uint32_t inl(uint16_t addr) {
uint32_t v;
asm volatile("inl %1, %0":"=a"(v):"Nd"(addr));
return v;
}
static inline void io_wait(void) {
asm volatile("jmp 1f\n\t"
"1:jmp 2f\n\t"
"2:" );
}
+11
View File
@@ -0,0 +1,11 @@
#include "rs232.h"
#include "io.h"
void rs232_init(uint16_t port) {
// Do nothing yet
}
void rs232_send(uint16_t port, char v) {
while (!(inb(port + 5) & 0x20)) {}
outb(port, v);
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <stdint.h>
#define RS232_COM0 0x3F8
void rs232_init(uint16_t port);
void rs232_send(uint16_t port, char c);
char rs232_recv(uint16_t port);
+11
View File
@@ -0,0 +1,11 @@
#include "sys/mm.h"
#include "sys/debug.h"
#include "arch/amd64/hw/gdt.h"
void kernel_main(void) {
kdebug("Booting\n");
// Memory management
amd64_mm_init();
amd64_gdt_init();
}
+1
View File
@@ -25,6 +25,7 @@ SECTIONS {
.data ALIGN(4K) : AT(ADDR(.data) - _kernel_base)
{
*(.data)
*(.data.rel.local)
}
.bss ALIGN(4K) : AT(ADDR(.bss) - _kernel_base)
+6
View File
@@ -3,6 +3,10 @@
/// The place where the kernel pages are virtually mapped to
#define KERNEL_VIRT_BASE 0xFFFFFF0000000000
/// amd64 standard states that addresses' upper bits are copies of the 47th bit, so these need to be
/// stripped down to only 48 bits
#define AMD64_MM_MASK(a) ((uintptr_t) (a) & 0xFFFFFFFFFFFF)
/// Page map level 4
typedef uint64_t *mm_pml4_t;
/// Page directory pointer table
@@ -14,3 +18,5 @@ typedef uint64_t *mm_pagetab_t;
/// Virtual memory space
typedef mm_pml4_t mm_space_t;
void amd64_mm_init(void);
+28
View File
@@ -0,0 +1,28 @@
#include "sys/mem.h"
#include "sys/debug.h"
#include "sys/mm.h"
mm_space_t mm_kernel;
void amd64_mm_init(void) {
kdebug("Memory manager init\n");
// Physical memory at this point:
// 0x000000 - 0x400000 - Used by kernel and info passed from the loader
// Virtual memory:
// Lower 1GiB mapped to itself for loader access
// 0xFFFFFF0000000000 (1GiB) is mapped to 0 for kernel access
// XXX: assuming nothing important is there
uint64_t *pml4 = (uint64_t *) (0x200000 - 0x1000);
uint64_t *pdpt = (uint64_t *) (0x200000 - 0x2000);
memset((void *) (0x200000 - 2 * 0x1000), 0, 0x1000 * 2);
// 0xFFFFFF0000000000 -> 0 (1GiB) mapping
pml4[AMD64_MM_MASK(KERNEL_VIRT_BASE) >> 39] = (uint64_t) pdpt | 1 | 2;
pdpt[(AMD64_MM_MASK(KERNEL_VIRT_BASE) >> 30) & 0x1FF] = 1 | 2 | (1 << 7);
// Load the new table
asm volatile ("mov %0, %%cr3"::"a"(pml4):"memory");
}
+14
View File
@@ -0,0 +1,14 @@
#include "pool.h"
#include "sys/mem.h"
static struct {
uint64_t track[512];
uintptr_t start;
size_t size;
} amd64_mm_pool;
void amd64_mm_pool_init(uintptr_t begin, size_t size) {
amd64_mm_pool.start = begin;
amd64_mm_pool.size = size;
memset(amd64_mm_pool.track, 0, 512 * sizeof(uint64_t));
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
/// Initialize the paging structure allocation pool
void amd64_mm_pool_init(uintptr_t base, size_t size);
/// Allocate a paging structure
uint64_t *amd64_mm_pool_alloc(void);
/// Free a paging structure
void amd64_mm_pool_free(uint64_t *obj);
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#define __weak __attribute__((weak))
+254
View File
@@ -0,0 +1,254 @@
#include "debug.h"
#include "string.h"
#include <stdint.h>
#include "sys/attr.h"
#if defined(ARCH_AMD64)
#include "arch/amd64/hw/rs232.h"
#endif
static const char *s_debug_xs_set0 = "0123456789abcdef";
static const char *s_debug_xs_set1 = "0123456789ABCDEF";
// TODO: make debugc a __weak function of a character
void debugc(int level, char c) {
#if defined(ARCH_AMD64)
rs232_send(RS232_COM0, c);
#endif
}
void debugs(int level, const char *s) {
char c;
while ((c = *(s++))) {
debugc(level, c);
}
}
static void debugspl(int level, const char *s, char p, size_t c) {
size_t l = strlen(s);
for (size_t i = l; i < c; ++i) {
debugc(level, p);
}
debugs(level, s);
}
static void debugspr(int level, const char *s, char p, size_t c) {
size_t l = strlen(s);
debugs(level, s);
for (size_t i = l; i < c; ++i) {
debugc(level, p);
}
}
static void debugsp(int level, const char *s, char padc, int padl) {
if (padl > 0) {
debugspl(level, s, padc, padl);
} else {
debugspr(level, s, padc, -padl);
}
}
void debug_ds(int64_t x, char *res, int s, int sz) {
if (!x) {
res[0] = '0';
res[1] = 0;
return;
}
int c;
uint64_t v;
if (sz) {
if (s && x < 0) {
v = (uint64_t) -x;
} else {
s = 0;
v = (uint64_t) x;
}
} else {
if (s && ((int32_t) x) < 0) {
v = (uint64_t) -((int32_t) x);
} else {
s = 0;
v = (uint64_t) x;
}
}
c = 0;
while (v) {
res[c++] = '0' + v % 10;
v /= 10;
}
if (s) {
res[c++] = '-';
}
res[c] = 0;
for (int i = 0, j = c - 1; i < j; ++i, --j) {
res[i] ^= res[j];
res[j] ^= res[i];
res[i] ^= res[j];
}
}
void debug_xs(uint64_t v, char *res, const char *set) {
if (!v) {
res[0] = '0';
res[1] = 0;
return;
}
int c = 0;
while (v) {
res[c++] = set[v & 0xF];
v >>= 4;
}
res[c] = 0;
for (int i = 0, j = c - 1; i < j; ++i, --j) {
res[i] ^= res[j];
res[j] ^= res[i];
res[i] ^= res[j];
}
}
void debugf(int level, const char *f, ...) {
va_list args;
va_start(args, f);
debugfv(level, f, args);
va_end(args);
}
void debugfv(int level, const char *fmt, va_list args) {
char c;
union {
const char *v_string;
char v_char;
int32_t v_int32;
uint32_t v_uint32;
int64_t v_int64;
uint64_t v_uint64;
uintptr_t v_ptr;
} value;
char buf[64];
char padc;
int padn;
int padd;
while ((c = *fmt)) {
switch (c) {
case '%':
c = *(++fmt);
padc = ' ';
padd = 1;
padn = 0;
if (c == '0') {
padc = c;
}
if (c == '-') {
padd = -1;
c = *(++fmt);
}
while (c >= '0' && c <= '9') {
padn *= 10;
padn += padd * (int) (c - '0');
c = *(++fmt);
}
switch (c) {
case 'l':
c = *(++fmt);
switch (c) {
case 'd':
value.v_int64 = va_arg(args, int64_t);
debug_ds(value.v_int64, buf, 1, 1);
debugsp(level, buf, padc, padn);
break;
case 'u':
value.v_uint64 = va_arg(args, uint64_t);
debug_ds(value.v_uint64, buf, 0, 1);
debugsp(level, buf, padc, padn);
break;
case 'x':
value.v_uint64 = va_arg(args, uint64_t);
debug_xs(value.v_uint64, buf, s_debug_xs_set0);
debugsp(level, buf, padc, padn);
break;
case 'X':
value.v_uint64 = va_arg(args, uint64_t);
debug_xs(value.v_uint64, buf, s_debug_xs_set1);
debugsp(level, buf, padc, padn);
break;
case 'p':
value.v_uint64 = va_arg(args, uint64_t);
debugc(level, '0');
debugc(level, 'x');
debug_xs(value.v_uint64, buf, s_debug_xs_set0);
debugspl(level, buf, '0', sizeof(uint64_t) * 2);
break;
default:
debugc(level, '%');
debugc(level, 'l');
debugc(level, c);
break;
}
break;
case 'c':
// char is promoted to int
value.v_char = va_arg(args, int);
debugc(level, value.v_char);
break;
case 'd':
value.v_int64 = va_arg(args, int32_t);
debug_ds(value.v_int64 & 0xFFFFFFFF, buf, 1, 0);
debugsp(level, buf, padc, padn);
break;
case 'u':
value.v_uint64 = va_arg(args, uint32_t);
debug_ds(value.v_uint64 & 0xFFFFFFFF, buf, 0, 0);
debugsp(level, buf, padc, padn);
break;
case 'x':
value.v_uint64 = va_arg(args, uint32_t);
debug_xs(value.v_uint64 & 0xFFFFFFFF, buf, s_debug_xs_set0);
debugsp(level, buf, padc, padn);
break;
case 'X':
value.v_uint64 = va_arg(args, uint32_t);
debug_xs(value.v_uint64 & 0xFFFFFFFF, buf, s_debug_xs_set1);
debugsp(level, buf, padc, padn);
break;
case 'p':
value.v_ptr = va_arg(args, uintptr_t);
debugc(level, '0');
debugc(level, 'x');
debug_xs(value.v_ptr, buf, s_debug_xs_set0);
debugspl(level, buf, '0', sizeof(uintptr_t) * 2);
break;
case 's':
value.v_string = va_arg(args, const char *);
debugsp(level, value.v_string ? value.v_string : "(null)", padc, padn);
break;
default:
debugc(level, '%');
debugc(level, c);
break;
}
break;
default:
debugc(level, c);
break;
}
++fmt;
}
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#define DEBUG_DEFAULT 0
#define DEBUG_INFO 1
#define DEBUG_WARN 2
#define DEBUG_ERROR 3
#define DEBUG_FATAL 4
#define DEBUG_OUT_SERIAL 0
#define DEBUG_OUT_DISP 1
#define kdebug(f, ...) debugf(DEBUG_DEFAULT, "[%s] " f, __func__, ##__VA_ARGS__)
#define kinfo(f, ...) debugf(DEBUG_INFO, "[%s] " f, __func__, ##__VA_ARGS__)
#define kwarn(f, ...) debugf(DEBUG_WARN, "[%s] " f, __func__, ##__VA_ARGS__)
#define kerror(f, ...) debugf(DEBUG_ERROR, "[%s] " f, __func__, ##__VA_ARGS__)
#define kfatal(f, ...) debugf(DEBUG_FATAL, "[%s] " f, __func__, ##__VA_ARGS__)
#define kprint(l, f, ...) debugf(l, "[%s] " f, __func__, ##__VA_ARGS__)
void debugc(int level, char c);
void debugs(int level, const char *s);
void debug_xs(uint64_t v, char *res, const char *set);
void debug_ds(int64_t x, char *res, int s, int sz);
void debug_init(void);
void debugf(int level, const char *fmt, ...);
void debugfv(int level, const char *fmt, va_list args);
void debug_dump(int level, const void *block, size_t count);
+8
View File
@@ -0,0 +1,8 @@
#include "mem.h"
void *memset(void *blk, int v, size_t sz) {
for (size_t i = 0; i < sz; ++i) {
((char *) blk)[i] = v;
}
return blk;
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
void *memset(void *blk, int v, size_t sz);
+9
View File
@@ -0,0 +1,9 @@
#include "string.h"
size_t strlen(const char *a) {
size_t s = 0;
while (*a++) {
++s;
}
return s;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include <stddef.h>
size_t strlen(const char *s);