commit 3004d69ec284a47f85170027284c5efada78839f
parent cc8fe1a7405f48e3ca08f6559c01b4b305cc7db5
Author: erai <erai@omiltem.net>
Date: Tue, 2 Apr 2024 01:18:39 -0400
task switching
Diffstat:
M | as.c | | | 16 | +++++++++------- |
M | cc1.c | | | 337 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | kernel.c | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
3 files changed, 442 insertions(+), 9 deletions(-)
diff --git a/as.c b/as.c
@@ -69,7 +69,8 @@ enum {
OP_LLDM = 0x020f00,
OP_LTRM = 0x030f00,
- OP_MOVSRM = 0x8e,
+ OP_WRSR = 0x8e,
+ OP_RDSR = 0x8c,
OP_RET = 0xc3,
OP_CALL = 0xe8,
@@ -78,6 +79,7 @@ enum {
OP_SETCC = 0x0f90,
OP_PUSHF = 0x9c,
+ OP_POPF = 0x9d,
OP_IRET = 0xcf,
OP_IRETQ = 0x48cf,
OP_WRMSR = 0x0f30,
@@ -369,7 +371,7 @@ emit_kstart(c: *assembler) {
as_jmp(c, OP_JCC + CC_NE, hang);
// Setup an early stack
- as_modri(c, OP_MOVI, R_RSP, 0x00200000);
+ as_modri(c, OP_MOVI, R_RSP, 0x00200000); // FIXME bss
// Align stack to page
as_modri(c, OP_ANDI, R_RSP, -0x1000);
@@ -471,11 +473,11 @@ emit_kstart(c: *assembler) {
// 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_WRSR, R_ES, R_RAX);
+ as_modrr(c, OP_WRSR, R_DS, R_RAX);
+ as_modrr(c, OP_WRSR, R_FS, R_RAX);
+ as_modrr(c, OP_WRSR, R_GS, R_RAX);
+ as_modrr(c, OP_WRSR, R_SS, R_RAX);
as_modrr(c, OP_MOVE, R_RSP, R_RSP);
// Reload stack in the top half
diff --git a/cc1.c b/cc1.c
@@ -1343,6 +1343,343 @@ main(argc: int, argv: **byte, envp: **byte) {
emit_ret(c.as);
}
+ d = find(c, "ud2", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_op(c.as, OP_UD2);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "cpuid", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 16);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RDI, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 24);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RDI, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 32);
+ as_modrm(c.as, OP_LOAD, R_RDX, R_RDI, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 40);
+ as_modrm(c.as, OP_LOAD, R_RBX, R_RDI, 0, 0, 0);
+ as_op(c.as, OP_CPUID);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 16);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 24);
+ as_modrm(c.as, OP_STORE, R_RCX, R_RDI, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 32);
+ as_modrm(c.as, OP_STORE, R_RDX, R_RDI, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 40);
+ as_modrm(c.as, OP_STORE, R_RBX, R_RDI, 0, 0, 0);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "inb", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDX, R_RBP, 0, 0, 16);
+ as_op(c.as, OP_IN);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "outb", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDX, R_RBP, 0, 0, 16);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 24);
+ as_op(c.as, OP_OUT);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "rdmsr", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 16);
+ as_op(c.as, OP_RDMSR);
+ as_modri(c.as, OP_MOVI, R_RCX, 32);
+ as_modr(c.as, OP_SHLM, R_RDX);
+ as_modrr(c.as, OP_ORRM, R_RAX, R_RDX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wrmsr", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 24);
+ as_modrr(c.as, OP_MOVE, R_RDX, R_RAX);
+ as_modri(c.as, OP_MOVI, R_RCX, 32);
+ as_modr(c.as, OP_SHRM, R_RDX);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 16);
+ as_op(c.as, OP_WRMSR);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "rdcr0", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrr(c.as, OP_RDCRR, R_CR0, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wrcr0", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 16);
+ as_modrr(c.as, OP_WRCRR, R_CR0, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "rdcr2", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrr(c.as, OP_RDCRR, R_CR2, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wrcr2", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 16);
+ as_modrr(c.as, OP_WRCRR, R_CR2, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "rdcr3", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrr(c.as, OP_RDCRR, R_CR3, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wrcr3", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 16);
+ as_modrr(c.as, OP_WRCRR, R_CR3, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "rdcr4", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrr(c.as, OP_RDCRR, R_CR4, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wrcr4", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 16);
+ as_modrr(c.as, OP_WRCRR, R_CR4, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "lgdt", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_modm(c.as, OP_LGDTM, R_RAX, 0, 0, 0);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "lidt", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_modm(c.as, OP_LIDTM, R_RAX, 0, 0, 0);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "lldt", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_modr(c.as, OP_LLDTM, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "ltr", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_modr(c.as, OP_LTRM, R_RAX);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "hlt", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_op(c.as, OP_HLT);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "rdflags", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_op(c.as, OP_PUSHF);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wrflags", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_op(c.as, OP_PUSHF);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ as_op(c.as, OP_POPF);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "wbinvld", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_modm(c.as, OP_WBINVD, R_RAX, 0, 0, 0);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "invlpg", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_preamble(c.as, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16);
+ as_modm(c.as, OP_INVLPGM, R_RAX, 0, 0, 0);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "taskswitch", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+
+ as_opr(c.as, OP_PUSHR, R_RBP);
+ as_op(c.as, OP_PUSHF);
+
+ as_modrm(c.as, OP_LOAD, R_RBP, R_RSP, 0, 0, 24);
+
+ // save
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c.as, OP_STORE, R_RCX, R_RBP, 0, 0, 8);
+ as_modrm(c.as, OP_STORE, R_RDX, R_RBP, 0, 0, 16);
+ as_modrm(c.as, OP_STORE, R_RBX, R_RBP, 0, 0, 24);
+
+ // rsp
+ as_modrm(c.as, OP_LEA, R_RAX, R_RSP, 0, 0, 24);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 32);
+
+ // rbp
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RSP, 0, 0, 8);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 40);
+
+ as_modrm(c.as, OP_STORE, R_RSI, R_RBP, 0, 0, 48);
+ as_modrm(c.as, OP_STORE, R_RDI, R_RBP, 0, 0, 56);
+ as_modrm(c.as, OP_STORE, R_R8, R_RBP, 0, 0, 64);
+ as_modrm(c.as, OP_STORE, R_R9, R_RBP, 0, 0, 72);
+ as_modrm(c.as, OP_STORE, R_R10, R_RBP, 0, 0, 80);
+ as_modrm(c.as, OP_STORE, R_R11, R_RBP, 0, 0, 88);
+ as_modrm(c.as, OP_STORE, R_R12, R_RBP, 0, 0, 96);
+ as_modrm(c.as, OP_STORE, R_R13, R_RBP, 0, 0, 104);
+ as_modrm(c.as, OP_STORE, R_R14, R_RBP, 0, 0, 112);
+ as_modrm(c.as, OP_STORE, R_R15, R_RBP, 0, 0, 120);
+
+ // rip
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RSP, 0, 0, 16);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 128);
+
+ // flags
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 136);
+
+ // cs
+ as_modrr(c.as, OP_RDSR, R_CS, R_RAX);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 144);
+
+ // ss
+ as_modrr(c.as, OP_RDSR, R_SS, R_RAX);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 152);
+
+ as_modrm(c.as, OP_LOAD, R_RBP, R_RSP, 0, 0, 32);
+
+ // restore
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RBP, 0, 0, 8);
+ as_modrm(c.as, OP_LOAD, R_RDX, R_RBP, 0, 0, 16);
+ as_modrm(c.as, OP_LOAD, R_RBX, R_RBP, 0, 0, 24);
+ as_modrm(c.as, OP_LOAD, R_RSI, R_RBP, 0, 0, 48);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RBP, 0, 0, 56);
+ as_modrm(c.as, OP_LOAD, R_R8, R_RBP, 0, 0, 64);
+ as_modrm(c.as, OP_LOAD, R_R9, R_RBP, 0, 0, 72);
+ as_modrm(c.as, OP_LOAD, R_R10, R_RBP, 0, 0, 80);
+ as_modrm(c.as, OP_LOAD, R_R11, R_RBP, 0, 0, 88);
+ as_modrm(c.as, OP_LOAD, R_R12, R_RBP, 0, 0, 96);
+ as_modrm(c.as, OP_LOAD, R_R13, R_RBP, 0, 0, 104);
+ as_modrm(c.as, OP_LOAD, R_R14, R_RBP, 0, 0, 112);
+ as_modrm(c.as, OP_LOAD, R_R15, R_RBP, 0, 0, 120);
+
+ // ss
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 152);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ // rsp
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 32);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ // flags
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 136);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ // cs
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 144);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ // rip
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 128);
+ as_opr(c.as, OP_PUSHR, R_RAX);
+
+ // finish up restore
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RBP, R_RBP, 0, 0, 40);
+
+ // iretq
+ as_op(c.as, OP_IRETQ);
+ }
+
start = 0: *label;
d = find(c, "_start", 0:*byte, 0);
if (d && d.func_defined) {
diff --git a/kernel.c b/kernel.c
@@ -1,12 +1,106 @@
-// in out iretq rdmsr wrmsr wrcr rdcr lgdt lldt lidt ltr hlt cli sti syscall sysret wbinvld invlpg
+ud2();
+
+cpuid(a: *int, c: *int, d: *int, b: *int);
+
+inb(a: int): int;
+outb(a: int, x: int);
+
+rdmsr(r: int): int;
+wrmsr(r: int, x: int);
+
+rdcr0(): int;
+wrcr0(x: int);
+rdcr2(): int;
+wrcr2(x: int);
+rdcr3(): int;
+wrcr3(x: int);
+rdcr4(): int;
+wrcr4(x: int);
+
+lgdt(gdtp: int);
+lidt(idtp: int);
+lldt(s: int);
+ltr(s: int);
+
+hlt();
+
+rdflags(): int;
+wrflags(x: int);
+
+wbinvld(x: int);
+invlpg(x: int);
+
+struct regs {
+ rax: int; // 0
+ rcx: int; // 8
+ rdx: int; // 16
+ rbx: int; // 24
+ rsp: int; // 32
+ rbp: int; // 40
+ rsi: int; // 48
+ rdi: int; // 56
+ r8: int; // 64
+ r9: int; // 72
+ r10: int; // 80
+ r11: int; // 88
+ r12: int; // 96
+ r13: int; // 104
+ r14: int; // 112
+ r15: int; // 120
+ rip: int; // 128
+ rflags: int; // 136
+ cs: int; // 144
+ ss: int; // 152
+}
+
+taskswitch(save_regs: *regs, load_regs: *regs);
_start() {
+ loop {
+ ud2();
+ }
}
ru32(p: *byte): int {
return p[0]:int + (p[1]:int << 8) + (p[2]:int << 16) + (p[3]:int << 24);
}
+bootstrap(a: *regs, b: *regs) {
+ a.r15 = 15;
+ taskswitch(b, a);
+ ud2();
+}
+
_kstart(mb: *byte) {
- loop { }
+ var a: regs;
+ var b: regs;
+
+ b.rax = 1;
+ b.rcx = 2;
+ b.rdx = 3;
+ b.rbx = 4;
+ b.rsp = (-0x8000 << 16) + 1024 * 1024 * 2 - 1024 * 32 - 24;
+ b.rbp = 0;
+ b.rsi = 7;
+ b.rdi = 8;
+ b.r8 = 9;
+ b.r9 = 10;
+ b.r10 = 11;
+ b.r11 = 12;
+ b.r12 = 13;
+ b.r13 = 14;
+ b.r14 = 15;
+ b.r15 = 16;
+ b.rip = bootstrap:int;
+ b.rflags = 0;
+ b.cs = 8;
+ b.ss = 16;
+
+ (b.rsp:**regs)[1] = &a;
+ (b.rsp:**regs)[2] = &b;
+
+ taskswitch(&a, &b);
+ loop {
+ hlt();
+ }
}