os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

commit 1d7fc228ae5d6168c0c54f7d6b3ff4af5fc591cb
parent dacee5fd166029c4f64c7929dc9064418c739d40
Author: erai <erai@omiltem.net>
Date:   Sat, 25 May 2024 13:24:27 -0400

basic syscall

Diffstat:
Mas.c | 17+++++++++++++++--
Mcc1.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mkernel.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 {