commit 92825b9131c1ccd10573c818406529b277a9cc41
parent a778d9116e59ca832d2d6d3b8bef32ee651e2513
Author: erai <erai@omiltem.net>
Date: Thu, 28 Mar 2024 21:51:27 -0400
multiboot bootstrap
Diffstat:
M | as.c | | | 238 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
M | cc1.c | | | 11 | ++++++++++- |
A | kernel.c | | | 9 | +++++++++ |
3 files changed, 251 insertions(+), 7 deletions(-)
diff --git a/as.c b/as.c
@@ -16,6 +16,22 @@ enum {
R_R14,
R_R15,
R_RIP,
+
+ R_ES = 0,
+ R_CS = 1,
+ R_SS = 2,
+ R_DS = 3,
+ R_FS = 4,
+ R_GS = 5,
+
+ R_CR0 = 0,
+ R_CR1 = 1,
+ R_CR2 = 2,
+ R_CR3 = 3,
+ R_CR4 = 4,
+ R_CR5 = 5,
+ R_CR6 = 6,
+ R_CR7 = 7,
}
enum {
@@ -38,7 +54,21 @@ enum {
}
enum {
+ OP_CLD = 0xfc,
+ OP_CLI = 0xfa,
+ OP_STI = 0xfb,
+ OP_CPUID = 0x0fa2,
+ OP_IN = 0xec,
+ OP_OUT = 0xee,
+ OP_HLT = 0xf4,
OP_NOP = 0x90,
+ OP_WBINVD = 0x0f09,
+
+ OP_INVLPGM = 0x070f01,
+ OP_LLDM = 0x020f00,
+ OP_LTRM = 0x030f00,
+
+ OP_MOVSRM = 0x8e,
OP_RET = 0xc3,
OP_CALL = 0xe8,
@@ -50,8 +80,12 @@ enum {
OP_IRET = 0xcf,
OP_IRETQ = 0x48cf,
OP_WRMSR = 0x0f30,
- OP_WRCRM = 0x0f20,
+ OP_RDMSR = 0x0f32,
+ OP_RDCRR = 0x0f20,
+ OP_WRCRR = 0x0f22,
OP_LGDTM = 0x020f01,
+ OP_LIDTM = 0x030f01,
+ OP_LLDTM = 0x020f00,
OP_ICALLM = 0x0200ff,
@@ -64,9 +98,14 @@ enum {
OP_TESTRM = 0x85,
OP_SUBRM = 0x2b,
OP_ADDRM = 0x03,
+ OP_ADCRM = 0x13,
OP_XORRM = 0x33,
- OP_ADDI = 0x0081,
+ OP_ANDI = 0x040081,
+ OP_ADDI = 0x000081,
+ OP_SUBI = 0x050081,
+ OP_ORI = 0x010081,
+ OP_CMPI = 0x070081,
OP_IMULM = 0x0400f7,
OP_IDIVM = 0x0700f7,
@@ -77,6 +116,7 @@ enum {
OP_POPR = 0x58,
+ OP_MOVI = 0x00c7,
OP_MOVABS = 0xb8,
OP_SYSCALL = 0x0f05,
@@ -114,6 +154,7 @@ struct assembler {
at: int;
text: *chunk;
text_end: *chunk;
+ bits32: int;
}
setup_assembler(a: *alloc): *assembler {
@@ -124,6 +165,7 @@ setup_assembler(a: *alloc): *assembler {
c.at = 0;
c.text = 0:*chunk;
c.text_end = 0:*chunk;
+ c.bits32 = 0;
return c;
}
@@ -307,9 +349,188 @@ emit_pop(c: *assembler, n: int) {
as_modri(c, OP_ADDI, R_RSP, n << 3);
}
-emit_preamble(c: *assembler, n: int, start: int) {
+emit_kstart(c: *assembler) {
+ var hang: *label;
+ var loop_top: *label;
+ var do_iret: *label;
+ var do_ret: *label;
+ var done: *label;
+
+ c.bits32 = 1;
+
+ hang = mklabel(c);
+ loop_top = mklabel(c);
+ do_iret = mklabel(c);
+ do_ret = mklabel(c);
+ done = mklabel(c);
+
+ // Check for valid multiboot magic
+ as_modri(c, OP_MOVI, R_RDX, 0x2badb002);
+ as_modrr(c, OP_CMPRM, R_RAX, R_RDX);
+ as_jmp(c, OP_JCC + CC_NE, hang);
+
+ // Setup an early stack
+ as_modri(c, OP_MOVI, R_RSP, 0x00080000);
+
+ // Allocate space for the gdt
+ as_modri(c, OP_SUBI, R_RSP, 64);
+ as_modrr(c, OP_MOVE, R_RBP, R_RSP);
+
+ // Align stack to page
+ as_modri(c, OP_ANDI, R_RSP, -0x1000);
+
+ // Null Segment
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 8);
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 12);
+
+ // Kernel code segment
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 16);
+ as_modri(c, OP_MOVI, R_RAX, 0x00209800);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 20);
+
+ // Kernel data segment
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 24);
+ as_modri(c, OP_MOVI, R_RAX, 0x00009200);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 28);
+
+ // Load gdt
+ as_modri(c, OP_MOVI, R_RAX, 23);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c, OP_LEA, R_RAX, R_RBP, 0, 0, 8);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 2);
+ as_modm(c, OP_LGDTM, R_RBP, 0, 0, 0);
+
+ // Load null lldt
+ as_modri(c, OP_MOVI, R_RAX, 0);
+ as_modr(c, OP_LLDTM, R_RAX);
+
+ // Load null idt
+ as_modm(c, OP_LIDTM, R_RBP, 0, 0, 8);
+
+ // pt1 -> physical
+ as_modri(c, OP_MOVI, R_RAX, 3);
+ as_modri(c, OP_MOVI, R_RDX, 0);
+ as_modri(c, OP_MOVI, R_RDI, 0);
+ as_modri(c, OP_SUBI, R_RSP, 0x1000);
+ fixup_label(c, loop_top);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, R_RDI, 1, 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, R_RDI, 1, 4);
+ as_modri(c, OP_ADDI, R_RAX, 0x1000);
+ as_modri(c, OP_ADDI, R_RDI, 8);
+ as_modri(c, OP_CMPI, R_RDI, 0x1000);
+ as_jmp(c, OP_JCC + CC_NE, loop_top);
+
+ // pt2 -> pt1
+ as_modrr(c, OP_MOVE, R_RAX, R_RSP);
+ as_modri(c, OP_SUBI, R_RSP, 0x1000);
+ as_modri(c, OP_ORI, R_RAX, 3);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
+
+ // pt3 -> pt2
+ as_modrr(c, OP_MOVE, R_RAX, R_RSP);
+ as_modri(c, OP_SUBI, R_RSP, 0x1000);
+ as_modri(c, OP_ORI, R_RAX, 3);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 510 * 8 + 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 510 * 8 + 4);
+
+ // pt4 -> pt3
+ as_modrr(c, OP_MOVE, R_RAX, R_RSP);
+ as_modri(c, OP_SUBI, R_RSP, 0x1000);
+ as_modri(c, OP_ORI, R_RAX, 3);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 511 * 8 + 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 511 * 8 + 4);
+
+ // Load page table pt4
+ as_modrr(c, OP_WRCRR, R_CR3, R_RSP);
+
+ // Enable pae
+ as_modri(c, OP_MOVI, R_RAX, 0xa0);
+ as_modrr(c, OP_WRCRR, R_CR4, R_RAX);
+
+ // Enable long mode
+ as_modri(c, OP_MOVI, R_RCX, (-1 << 32) + (0xc0 << 24) + 0x000080);
+ as_op(c, OP_RDMSR);
+ as_modri(c, OP_ORI, R_RAX, 0x100);
+ as_op(c, OP_WRMSR);
+
+ // Enable paging
+ as_modrr(c, OP_RDCRR, R_CR0, R_RAX);
+ as_modri(c, OP_ORI, R_RAX, (-0x8000 << 16) | (0x0001));
+ as_modrr(c, OP_WRCRR, R_CR0, R_RAX);
+
+ // flags
+ as_modri(c, OP_MOVI, R_RAX, 0);
+ as_opr(c, OP_PUSHR, R_RAX);
+ // cs
+ as_modri(c, OP_MOVI, R_RAX, 8);
+ as_opr(c, OP_PUSHR, R_RAX);
+ // pointer
+ as_jmp(c, OP_CALL, do_iret);
+
+ c.bits32 = 0;
+
+ // Jump to top half
+ as_jmp(c, OP_CALL, do_ret);
+
+ // Reload the gdt in the top half
+ as_modri(c, OP_ORI, R_RBP, (-0x8000 << 16));
+ as_modri(c, OP_MOVI, R_RAX, 23);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c, OP_LEA, R_RAX, R_RBP, 0, 0, 8);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 2);
+ as_modm(c, OP_LGDTM, R_RBP, 0, 0, 0);
+
+ // Reload segments
+ as_modri(c, OP_MOVI, R_RAX, 16);
+ as_modrr(c, OP_MOVSRM, R_ES, R_RAX);
+ as_modrr(c, OP_MOVSRM, R_DS, R_RAX);
+ as_modrr(c, OP_MOVSRM, R_FS, R_RAX);
+ as_modrr(c, OP_MOVSRM, R_GS, R_RAX);
+ as_modrr(c, OP_MOVSRM, R_SS, R_RAX);
+ as_modrr(c, OP_MOVE, R_RSP, R_RSP);
+
+ // Reload stack in the top half
+ as_modri(c, OP_ORI, R_RSP, (-0x8000 << 16));
+
+ // Setup a call frame for _kstart
+ as_jmp(c, OP_JMP, done);
+
+ // hlt forever
+ fixup_label(c, hang);
+ as_op(c, OP_CLI);
+ as_op(c, OP_HLT);
+ as_jmp(c, OP_JMP, hang);
+
+ // iret to long mode
+ fixup_label(c, do_iret);
+ as_op(c, OP_IRET);
+
+ // ret to top half
+ fixup_label(c, do_ret);
+ as_opr(c, OP_POPR, R_RAX);
+ as_modri(c, OP_ORI, R_RAX, (-0x8000 << 16));
+ as_opr(c, OP_PUSHR, R_RAX);
+ as_op(c, OP_RET);
+
+ // Setup a call frame for _kstart
+ fixup_label(c, done);
+ as_modrr(c, OP_XORRM, R_RBP, R_RBP);
+ as_opr(c, OP_PUSHR, R_RBX);
+ as_opr(c, OP_PUSHR, R_RBP);
+}
+
+emit_preamble(c: *assembler, n: int, pragma: int) {
var i: int;
- if (start) {
+ if (pragma == 1) {
as_modrr(c, OP_XORRM, R_RBP, R_RBP);
as_modrm(c, OP_LOAD, R_RDI, R_RSP, 0, 0, 0);
as_modrm(c, OP_LEA, R_RSI, R_RSP, 0, 0, 8);
@@ -318,6 +539,8 @@ emit_preamble(c: *assembler, n: int, start: int) {
as_opr(c, OP_PUSHR, R_RSI);
as_opr(c, OP_PUSHR, R_RDI);
as_opr(c, OP_PUSHR, R_RBP);
+ } else if (pragma > 1) {
+ emit_kstart(c);
}
as_opr(c, OP_PUSHR, R_RBP);
as_modrr(c, OP_MOVE, R_RBP, R_RSP);
@@ -843,6 +1066,9 @@ as_emit(a: *assembler, b: int) {
as_rex(a: *assembler, op: int, r: int, i: int, b: int) {
var w: int;
+ if a.bits32 {
+ return;
+ }
w = 0x08;
if op == OP_LOADB || op == OP_STOREB {
w = 0;
@@ -1026,14 +1252,14 @@ as_modrm(a: *assembler, op: int, r: int, b: int, i: int, s: int, d: int) {
// modrm /op
as_modm(a: *assembler, op: int, b: int, i: int, s: int, d: int) {
- as_modrm(a, op & 0xff, op >> 8, b, i, s, d);
+ as_modrm(a, op & 0xffff, op >> 16, b, i, s, d);
}
as_modri(a: *assembler, op: int, r: int, x: int) {
if x < -(1 << 31) || x >= (1 << 31) {
die("immediate too large");
}
- as_modrr(a, op & 0xff, op >> 8, r);
+ as_modrr(a, op & 0xffff, op >> 16, r);
as_emit(a, x);
as_emit(a, x >> 8);
as_emit(a, x >> 16);
diff --git a/cc1.c b/cc1.c
@@ -303,6 +303,7 @@ compile_func(c: *compiler, d: *decl) {
var t: *type;
var offset: int;
var n: *node;
+ var pragma: int;
if (!d.func_def) {
return;
@@ -335,10 +336,18 @@ compile_func(c: *compiler, d: *decl) {
// Hoist locals
offset = hoist_locals(c, d, d.func_def.b, 0);
+ if (!strcmp(d.name, "_start")) {
+ pragma = 1;
+ } else if (!strcmp(d.name, "_kstart")) {
+ pragma = 2;
+ } else {
+ pragma = 0;
+ }
+
// Compile the function body
emit_str(c.as, d.name);
fixup_label(c.as, d.func_label);
- emit_preamble(c.as, offset, !strcmp(d.name, "_start"));
+ emit_preamble(c.as, offset, pragma);
compile_stmt(c, d, d.func_def.b, 0:*label, 0:*label);
emit_num(c.as, 0);
emit_ret(c.as);
diff --git a/kernel.c b/kernel.c
@@ -0,0 +1,9 @@
+// in out iretq rdmsr wrmsr wrcr rdcr lgdt lldt lidt ltr hlt cli sti syscall sysret wbinvld invlpg
+
+_start() {
+ loop { }
+}
+
+_kstart(mbinfo: *void) {
+ loop { }
+}