commit 1d7fc228ae5d6168c0c54f7d6b3ff4af5fc591cb
parent dacee5fd166029c4f64c7929dc9064418c739d40
Author: erai <erai@omiltem.net>
Date: Sat, 25 May 2024 13:24:27 -0400
basic syscall
Diffstat:
M | as.c | | | 17 | +++++++++++++++-- |
M | cc1.c | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | kernel.c | | | 68 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
3 files changed, 188 insertions(+), 9 deletions(-)
diff --git a/as.c b/as.c
@@ -130,6 +130,7 @@ enum {
OP_MOVABS = 0xb8,
OP_SYSCALL = 0x0f05,
+ OP_SYSRET = 0x0f07,
OP_LEA = 0x8d,
OP_LOAD = 0x8b,
@@ -387,7 +388,7 @@ emit_kstart(c: *assembler) {
// pt3 -> 1g
as_modri(c, OP_SUBI, R_RSP, 0x1000);
- as_modri(c, OP_MOVI, R_RAX, 0x83);
+ as_modri(c, OP_MOVI, R_RAX, 0x87);
as_modri(c, OP_MOVI, R_RDX, 0);
as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
@@ -397,7 +398,7 @@ emit_kstart(c: *assembler) {
// 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_modri(c, OP_ORI, R_RAX, 7);
as_modri(c, OP_MOVI, R_RDX, 0);
as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
@@ -1129,6 +1130,18 @@ as_modr(a: *assembler, op: int, b: int) {
as_modrr(a, op & 0xffff, op >> 16, b);
}
+// modrm + disp
+as_modra(a: *assembler, op: int, r: int, d: int) {
+ as_rex(a, op, r, 0, 0);
+ as_op(a, op);
+ as_emit(a, ((r << 3) & 0x38) + R_RSP);
+ as_emit(a, (R_RSP << 3) + R_RBP);
+ as_emit(a, d);
+ as_emit(a, d >> 8);
+ as_emit(a, d >> 16);
+ as_emit(a, d >> 24);
+}
+
// modrm + sib + disp
as_modrm(a: *assembler, op: int, r: int, b: int, i: int, s: int, d: int) {
var sib: int;
diff --git a/cc1.c b/cc1.c
@@ -1283,6 +1283,112 @@ next_decl(c: *compiler, d: *decl): *decl {
}
}
+emit_ssr(c: *compiler) {
+ var d: *decl;
+ var v: *decl;
+
+ v = find(c, "global", "_save", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no _save");
+ }
+
+ as_emit(c.as, OP_GS);
+ as_modra(c.as, OP_STORE, R_RSP, v.member_offset);
+
+ v = find(c, "global", "curtask", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no global.curtask");
+ }
+
+ as_emit(c.as, OP_GS);
+ as_modra(c.as, OP_LOAD, R_RSP, v.member_offset);
+
+ v = find(c, "task", "stack", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no task.stack");
+ }
+
+ as_modrm(c.as, OP_LOAD, R_RSP, R_RSP, 0, 0, v.member_offset);
+ as_modri(c.as, OP_ADDI, R_RSP, 4096 - 176);
+
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c.as, OP_STORE, R_RDX, R_RSP, 0, 0, 16);
+ as_modrm(c.as, OP_STORE, R_RBX, R_RSP, 0, 0, 24);
+ as_modrm(c.as, OP_STORE, R_RBP, R_RSP, 0, 0, 40);
+ as_modrm(c.as, OP_STORE, R_RSI, R_RSP, 0, 0, 48);
+ as_modrm(c.as, OP_STORE, R_RDI, R_RSP, 0, 0, 56);
+ as_modrm(c.as, OP_STORE, R_R8, R_RSP, 0, 0, 64);
+ as_modrm(c.as, OP_STORE, R_R9, R_RSP, 0, 0, 72);
+ as_modrm(c.as, OP_STORE, R_R10, R_RSP, 0, 0, 80);
+ as_modrm(c.as, OP_STORE, R_R12, R_RSP, 0, 0, 96);
+ as_modrm(c.as, OP_STORE, R_R13, R_RSP, 0, 0, 104);
+ as_modrm(c.as, OP_STORE, R_R14, R_RSP, 0, 0, 112);
+ as_modrm(c.as, OP_STORE, R_R15, R_RSP, 0, 0, 120);
+ as_modrm(c.as, OP_STORE, R_RCX, R_RSP, 0, 0, 128);
+ as_modrm(c.as, OP_STORE, R_R11, R_RSP, 0, 0, 136);
+
+ as_modrr(c.as, OP_XORRM, R_RAX, R_RAX);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 8);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 88);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 160);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 168);
+
+ as_modri(c.as, OP_MOVI, R_RAX, 43);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 144);
+ as_modri(c.as, OP_MOVI, R_RAX, 35);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 152);
+
+ v = find(c, "global", "_save", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no _save");
+ }
+
+ as_emit(c.as, OP_GS);
+ as_modra(c.as, OP_LOAD, R_RAX, v.member_offset);
+ as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 32);
+ as_modrr(c.as, OP_MOVE, R_RAX, R_RSP);
+
+ as_modrr(c.as, OP_XORRM, R_RBP, R_RBP);
+ as_opr(c.as, OP_PUSHR, R_RBP);
+ as_opr(c.as, OP_PUSHR, R_RBP);
+ as_modrr(c.as, OP_MOVE, R_RBP, R_RSP);
+
+ as_opr(c.as, OP_PUSHR, R_RAX);
+
+ as_op(c.as, OP_STI);
+
+ d = find(c, "_ssr", 0:*byte, 1);
+ if (d.func_defined && d.func_label.fixed) {
+ as_jmp(c.as, OP_CALL, d.func_label);
+ }
+
+ as_op(c.as, OP_CLI);
+
+ as_modri(c.as, OP_ADDI, R_RSP, 3 * 8);
+
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c.as, OP_LOAD, R_RDX, R_RSP, 0, 0, 16);
+ as_modrm(c.as, OP_LOAD, R_RBX, R_RSP, 0, 0, 24);
+ as_modrm(c.as, OP_LOAD, R_RBP, R_RSP, 0, 0, 40);
+ as_modrm(c.as, OP_LOAD, R_RSI, R_RSP, 0, 0, 48);
+ as_modrm(c.as, OP_LOAD, R_RDI, R_RSP, 0, 0, 56);
+ as_modrm(c.as, OP_LOAD, R_R8, R_RSP, 0, 0, 64);
+ as_modrm(c.as, OP_LOAD, R_R9, R_RSP, 0, 0, 72);
+ as_modrm(c.as, OP_LOAD, R_R10, R_RSP, 0, 0, 80);
+ as_modrm(c.as, OP_LOAD, R_R12, R_RSP, 0, 0, 96);
+ as_modrm(c.as, OP_LOAD, R_R13, R_RSP, 0, 0, 104);
+ as_modrm(c.as, OP_LOAD, R_R14, R_RSP, 0, 0, 112);
+ as_modrm(c.as, OP_LOAD, R_R15, R_RSP, 0, 0, 120);
+
+ as_modrm(c.as, OP_LOAD, R_RCX, R_RSP, 0, 0, 128);
+ as_modrm(c.as, OP_LOAD, R_R11, R_RSP, 0, 0, 136);
+
+ as_modrm(c.as, OP_LOAD, R_RSP, R_RSP, 0, 0, 32);
+
+ as_rex(c.as, OP_SYSRET, 0, 0, 0);
+ as_op(c.as, OP_SYSRET);
+}
+
emit_isr(c: *compiler) {
var d: *decl;
var out: *label;
@@ -1827,6 +1933,12 @@ main(argc: int, argv: **byte, envp: **byte) {
emit_ret(c.as);
}
+ d = find(c, "_ssr0", 0:*byte, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.as, d.func_label);
+ emit_ssr(c);
+ }
+
d = find(c, "_isr0", 0:*byte, 1);
if (d.func_defined && !d.func_label.fixed) {
fixup_label(c.as, d.func_label);
diff --git a/kernel.c b/kernel.c
@@ -1,5 +1,7 @@
ud2();
+syscall(n: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int): int;
+
cpuid(a: *int, c: *int, d: *int, b: *int);
inb(a: int): int;
@@ -40,6 +42,7 @@ wbinvld(x: int);
invlpg(x: int);
_isr0();
+_ssr0();
_rgs(x: int): int;
@@ -556,7 +559,7 @@ map_pci(pa: int): *byte {
pt4 = ptov(pt4p):*int;
v2 = ((va: int) >> 30) & 511;
pt3 = ptov(pt4[511] & -4096):*int;
- flags = 0x93;
+ flags = 0x97;
pt3[v2] = (pa & -(1 << 30)) | flags;
pt3[v2 + 1] = ((pa + (1 << 30)) & -(1 << 30)) | flags;
wrcr3(pt4p);
@@ -865,6 +868,7 @@ struct task {
prev: *task;
name: *byte;
stack: *byte;
+ ustack: *byte;
dead: int;
f: (func(t: *task));
a: *void;
@@ -893,6 +897,7 @@ struct global {
rng: int;
curtask: *task;
dead: *task;
+ _save: int;
}
struct free_page {
@@ -1133,7 +1138,7 @@ direct_map(brk: *int) {
pt3p = (pt3:int) & ((1 << 31) - 1);
i = (va >> 39) & 511;
- pt4[i] = pt3p | 0x003;
+ pt4[i] = pt3p | 0x007;
loop {
if pa == map_size || n == 0 {
@@ -1141,7 +1146,7 @@ direct_map(brk: *int) {
}
i = (va >> 30) & 511;
- pt3[i] = pa | 0x083;
+ pt3[i] = pa | 0x087;
va = va + page_size;
pa = pa + page_size;
@@ -3234,6 +3239,7 @@ schedule() {
prev.next = next;
next.prev = prev;
free(dead.stack);
+ free(dead.ustack);
free(dead:*byte);
}
global.curtask = next;
@@ -3501,6 +3507,7 @@ spawn(f: (func(t: *task)), name: *byte, a: *void): *task {
t = alloc():*task;
bzero(t:*byte, sizeof(*t));
t.stack = alloc();
+ t.ustack = alloc();
t.name = name;
t.regs.rsp = (t.stack:int) + 4096;
t.regs.rip = _tstart:int;
@@ -3520,6 +3527,38 @@ spawn(f: (func(t: *task)), name: *byte, a: *void): *task {
return t;
}
+_ssr(r: *regs) {
+ if r.rax == 60 {
+ kputs("exit\n");
+ task_exit();
+ } else {
+ r.rax = -1;
+ }
+}
+
+user() {
+ syscall(1, 2, 3, 4, 5, 6, 7);
+}
+
+_ustart() {
+ user();
+ loop {
+ syscall(60, 0, 0, 0, 0, 0, 0);
+ }
+}
+
+task_user(t: *task) {
+ var r: regs;
+ bzero((&r):*byte, sizeof(r));
+ r.rflags = 0x200;
+ r.rip = _ustart:int;
+ r.cs = 40 | 3;
+ r.rsp = t.ustack:int + 4096;
+ r.ss = 32 | 3;
+ cli();
+ taskswitch(&t.regs, &r);
+}
+
_kstart(mb: int) {
var global: global;
var task: task;
@@ -3631,7 +3670,7 @@ _kstart(mb: int) {
fill_idt(idt);
gdt = brk: *int;
- gdt_size = 8 * 7;
+ gdt_size = 8 * 9;
// Null segment
gdt[0] = 0;
@@ -3640,20 +3679,33 @@ _kstart(mb: int) {
// Kernel data segment
gdt[2] = 0x00009200 << 32;
// User code segment
- gdt[3] = 0x0020f800 << 32;
+ gdt[3] = 0x0020fa00 << 32;
// User data segment
gdt[4] = 0x0000f200 << 32;
+ // User code segment
+ gdt[5] = 0x0020fa00 << 32;
+ // User data segment
+ gdt[6] = 0x0000f200 << 32;
// Task segment
- gdt_tss(&gdt[5], tss: int, tss_size, 0x89, 0);
+ gdt_tss(&gdt[7], tss: int, tss_size, 0x89, 0);
// Load gdt idt tss and segments
lgdt(gdt, gdt_size);
lseg(8, 16);
wrmsr((0xc000 << 16) + 0x0101, global.ptr:int);
lldt(0);
- ltr(5 * 8);
+ ltr(7 * 8);
lidt(idt, idt_size);
+ // STAR
+ wrmsr((0xc000 << 16) + 0x0081, ((24 + 3) << 48) | (8 << 32));
+ // LSTAR
+ wrmsr((0xc000 << 16) + 0x0082, (_ssr0): int);
+ // FMASK
+ wrmsr((0xc000 << 16) + 0x0084, -1);
+ // EFER
+ wrmsr((0xc000 << 16) + 0x0080, rdmsr((0xc000 << 16) + 0x0080) | 1);
+
// interrupt stack
brk = (brk + 4095) & -4096;
brk = brk + 64 * 1024;
@@ -3738,6 +3790,8 @@ _kstart(mb: int) {
tcp_listen(22, tcp_ssh);
+ spawn(task_user, "init", 0:*void);
+
// Wait for interrupts
kputs("zzz\n");
loop {