os

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

commit 30c6c9a1bab12dd0e4eb83cd00375280196a7d9a
parent 3004d69ec284a47f85170027284c5efada78839f
Author: erai <erai@omiltem.net>
Date:   Wed,  3 Apr 2024 22:48:51 -0400

interrupts

Diffstat:
Mcc1.c | 204++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mkernel.c | 261++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 429 insertions(+), 36 deletions(-)

diff --git a/cc1.c b/cc1.c @@ -1283,6 +1283,135 @@ next_decl(c: *compiler, d: *decl): *decl { } } +emit_isr(c: *compiler) { + var d: *decl; + var out: *label; + var i: int; + + out = mklabel(c.as); + + i = 0; + loop { + if i == 256 { + break; + } + reserve(c.as, 16); + if i == 8 || i == 10 || i == 11 || i == 12 + || i == 13 || i == 14 || i == 17 || i == 21 + || i == 29 || i == 30 { + as_emit(c.as, 0x90); + as_emit(c.as, 0x90); + } else { + as_emit(c.as, 0x6a); + as_emit(c.as, 0x00); + } + as_emit(c.as, 0x68); + as_emit(c.as, i); + as_emit(c.as, 0x00); + as_emit(c.as, 0x00); + as_emit(c.as, 0x00); + as_emit(c.as, 0xe9); + as_emit(c.as, 0x00); + as_emit(c.as, 0x00); + as_emit(c.as, 0x00); + as_emit(c.as, 0x00); + addfixup(c.as, out); + as_emit(c.as, 0x90); + as_emit(c.as, 0x90); + as_emit(c.as, 0x90); + as_emit(c.as, 0x90); + i = i + 1; + } + + fixup_label(c.as, out); + + // save regs + as_modri(c.as, OP_SUBI, R_RSP, 176); + as_modrm(c.as, OP_STORE, R_RBP, R_RSP, 0, 0, 40); + as_modrr(c.as, OP_MOVE, R_RBP, R_RSP); + as_opr(c.as, OP_PUSHR, R_RBP); + + 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); + 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); + + // trap + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 0); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 160); + // err + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 0); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 168); + // rip + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 16); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 128); + // cs + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 24); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 144); + // flags + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 32); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 136); + // rsp + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 40); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 32); + // ss + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 48); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 152); + + d = find(c, "_isr", 0:*byte, 1); + if (d.func_defined && d.func_label.fixed) { + as_jmp(c.as, OP_CALL, d.func_label); + } + + // rip + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 128); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 16); + // cs + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 144); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 24); + // flags + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 136); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 32); + // rsp + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 32); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 40); + // ss + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 152); + as_modrm(c.as, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 48); + + // restore regs + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 0); + 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); + + as_modrm(c.as, OP_LOAD, R_RBP, R_RBP, 0, 0, 40); + + as_modri(c.as, OP_ADDI, R_RSP, 176 + 3 * 8); + + as_op(c.as, OP_IRETQ); +} + main(argc: int, argv: **byte, envp: **byte) { var a: alloc; var c: *compiler; @@ -1505,8 +1634,14 @@ main(argc: int, argv: **byte, envp: **byte) { if (d.func_defined && !d.func_label.fixed) { fixup_label(c.as, d.func_label); emit_preamble(c.as, 0, 0); + as_modri(c.as, OP_SUBI, R_RSP, 16); + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 24); + as_modri(c.as, OP_SUBI, R_RAX, 1); + as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 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_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 2); + as_modm(c.as, OP_LGDTM, R_RSP, 0, 0, 0); + as_modri(c.as, OP_ADDI, R_RSP, 16); as_opr(c.as, OP_PUSHR, R_RAX); emit_ret(c.as); } @@ -1515,8 +1650,14 @@ main(argc: int, argv: **byte, envp: **byte) { if (d.func_defined && !d.func_label.fixed) { fixup_label(c.as, d.func_label); emit_preamble(c.as, 0, 0); + as_modri(c.as, OP_SUBI, R_RSP, 16); + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 24); + as_modri(c.as, OP_SUBI, R_RAX, 1); + as_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 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_modrm(c.as, OP_STORE, R_RAX, R_RSP, 0, 0, 2); + as_modm(c.as, OP_LIDTM, R_RSP, 0, 0, 0); + as_modri(c.as, OP_ADDI, R_RSP, 16); as_opr(c.as, OP_PUSHR, R_RAX); emit_ret(c.as); } @@ -1541,6 +1682,41 @@ main(argc: int, argv: **byte, envp: **byte) { emit_ret(c.as); } + d = find(c, "lseg", 0:*byte, 1); + if (d.func_defined && !d.func_label.fixed) { + fixup_label(c.as, d.func_label); + emit_preamble(c.as, 0, 0); + // es ds fs gs + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 24); + as_modrr(c.as, OP_WRSR, R_ES, R_RAX); + as_modrr(c.as, OP_WRSR, R_DS, R_RAX); + as_modrr(c.as, OP_WRSR, R_FS, R_RAX); + as_modrr(c.as, OP_WRSR, R_GS, R_RAX); + // ss + as_opr(c.as, OP_PUSHR, R_RAX); + // rsp + as_opr(c.as, OP_PUSHR, R_RBP); + // flags + as_op(c.as, OP_PUSHF); + // cs + as_modrm(c.as, OP_LOAD, R_RAX, R_RBP, 0, 0, 16); + as_opr(c.as, OP_PUSHR, R_RAX); + // rip + as_op(c.as, OP_CALL); + as_emit(c.as, 5); + as_emit(c.as, 0); + as_emit(c.as, 0); + as_emit(c.as, 0); + as_op(c.as, OP_JMP); + as_emit(c.as, 2); + as_emit(c.as, 0); + as_emit(c.as, 0); + as_emit(c.as, 0); + as_op(c.as, OP_IRETQ); + 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); @@ -1550,6 +1726,24 @@ main(argc: int, argv: **byte, envp: **byte) { emit_ret(c.as); } + d = find(c, "cli", 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_CLI); + as_opr(c.as, OP_PUSHR, R_RAX); + emit_ret(c.as); + } + + d = find(c, "sti", 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_STI); + 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); @@ -1589,6 +1783,12 @@ main(argc: int, argv: **byte, envp: **byte) { emit_ret(c.as); } + d = find(c, "_isr0", 0:*byte, 1); + if (d.func_defined && !d.func_label.fixed) { + fixup_label(c.as, d.func_label); + emit_isr(c); + } + d = find(c, "taskswitch", 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 @@ -17,19 +17,24 @@ wrcr3(x: int); rdcr4(): int; wrcr4(x: int); -lgdt(gdtp: int); -lidt(idtp: int); +lgdt(base: *int, size: int); +lidt(base: *int, size: int); lldt(s: int); ltr(s: int); +lseg(cs: int, ds: int); hlt(); +cli(); +sti(); rdflags(): int; wrflags(x: int); wbinvld(x: int); invlpg(x: int); +_isr0(); + struct regs { rax: int; // 0 rcx: int; // 8 @@ -51,6 +56,9 @@ struct regs { rflags: int; // 136 cs: int; // 144 ss: int; // 152 + trap: int; // 160 + err: int; // 168 + // 176 } taskswitch(save_regs: *regs, load_regs: *regs); @@ -65,42 +73,227 @@ 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(); +// FIXME a very dumb and lossy but simple serial debug + +enum { + IO_COM0 = 0x3f8, + IO_PIC1 = 0x20, + IO_PIC2 = 0xa0, + IO_PIT = 0x40, +} + +setup_serial() { + outb(IO_COM0 + 1, 0x00); + outb(IO_COM0 + 3, 0x80); + outb(IO_COM0 + 0, 0x03); + outb(IO_COM0 + 1, 0x00); + outb(IO_COM0 + 3, 0x03); + outb(IO_COM0 + 2, 0xc7); + outb(IO_COM0 + 4, 0x0f); + + outb(IO_COM0, 0x1b); + outb(IO_COM0, '['); + outb(IO_COM0, 'H'); + + outb(IO_COM0, 0x1b); + outb(IO_COM0, '['); + outb(IO_COM0, 'J'); +} + +sputc(c: int) { + outb(IO_COM0, c); +} + +sputs(s: *byte) { + var i: int; + i = 0; + loop { + if !s[i] { + break; + } + sputc(s[i]:int); + i = i + 1; + } +} + +sputd(x: int) { + var d: int; + if x < 0 { + d = -(x % -10); + x = x / -10; + sputc('-'); + if x { + sputd(x); + } + sputc('0' + d); + } else { + d = x % 10; + x = x / 10; + if x { + sputd(x); + } + sputc('0' + d); + } +} + +sputh(x: int) { + var d: int; + d = x & 15; + x = x >> 4; + if x { + sputh(x); + } + sputc("0123456789abcdef"[d]:int); +} + +gdt_tss(s: *int, base: int, size: int, access: int, flags: int) { + s[0] = (((base & ~0xffff) << 32) + + ((flags & 0xf) << 52) + + (((size - 1) & 0xf0000) << 32) + + ((access & 0xff) << 40) + + ((base & 0xff0000) << 16) + + ((base & 0xffff) << 16) + + ((size - 1) & 0xffff)); + s[1] = base >> 32; +} + +idt_gate(s: *int, offset: int, dpl: int, ist: int) { + s[0] = (((offset & ~0xffff) << 32) + + (1 << 47) + + ((dpl & 3) << 45) + + (0x0e << 40) + + ((ist & 7) << 32) + + (8 << 16) + + (offset & 0xffff)); + s[1] = offset >> 32; +} + +bzero(s: *byte, size: int) { + var i: int; + i = 0; + loop { + if i == size { + break; + } + s[i] = 0:byte; + i = i + 1; + } +} + +_isr(r: *regs) { + // pic end of interrupt + if (r.trap >= 32 && r.trap < 48) { + if (r.trap < 40) { + outb(IO_PIC2, 0x20); + } + outb(IO_PIC1, 0x20); + } +} + +fill_idt(s: *int) { + var i: int; + var ist: int; + loop { + if i == 256 { + break; + } + if i == 2 { + ist = 2; + } else { + ist = 1; + } + idt_gate(&s[i * 2], _isr0:int + i * 16, 0, ist); + i = i + 1; + } } _kstart(mb: *byte) { - 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); + var brk: int; + var tss: *int; + var tss_size: int; + var idt: *int; + var idt_size: int; + var gdt: *int; + var gdt_size: int; + + setup_serial(); + + brk = ((-0x8000 << 16) + 1024 * 512 * 3); + + // Zero tss and add interrupt stacks + tss = brk: *int; + tss_size = 104; + brk = brk + tss_size; + bzero(tss: *byte, tss_size); + + // Fill idt with interrupt gates + idt = brk: *int; + idt_size = 4096; + brk = brk + idt_size; + fill_idt(idt); + + gdt = brk: *int; + gdt_size = 8 * 5; + + // Null segment + gdt[0] = 0; + // Kernel code segment + gdt[1] = 0x00209800 << 32; + // Kernel data segment + gdt[2] = 0x00009200 << 32; + // Task segment + gdt_tss(&gdt[3], tss: int, tss_size, 0x89, 0); + + // Load gdt idt tss and segments + lgdt(gdt, gdt_size); + lseg(8, 16); + lldt(0); + ltr(24); + lidt(idt, idt_size); + + // interrupt stack + brk = (brk + 4095) & -4096; + brk = brk + 64 * 1024; + ((tss:int + 0x24):*int)[0] = brk; + ((tss:int + 0x04):*int)[0] = brk; + + // nmi stack + brk = (brk + 4095) & -4096; + brk = brk + 64 * 1024; + ((tss:int + 0x2c):*int)[0] = brk; + + // mask pic + outb(IO_PIC1 + 1, 0xff); + outb(IO_PIC2 + 1, 0xff); + + // initialize pic + outb(IO_PIC1, 0x11); + outb(IO_PIC2, 0x11); + + // pic offset + outb(IO_PIC1 + 1, 32); + outb(IO_PIC2 + 1, 40); + + // pic cascade + outb(IO_PIC1 + 1, 4); + outb(IO_PIC2 + 1, 2); + + // pic 8086 mode + outb(IO_PIC1 + 1, 32); + outb(IO_PIC2 + 1, 40); + + // 100 hz pit + outb(IO_PIT + 3, 0x36); + outb(IO_PIT + 0, 0x9b); + outb(IO_PIT + 0, 0x2e); + + // unmask pit + outb(IO_PIC1 + 1, 0xfe); + outb(IO_PIC2 + 1, 0xff); + + // Wait for interrupts loop { + sti(); hlt(); } }