commit 30c6c9a1bab12dd0e4eb83cd00375280196a7d9a
parent 3004d69ec284a47f85170027284c5efada78839f
Author: erai <erai@omiltem.net>
Date: Wed, 3 Apr 2024 22:48:51 -0400
interrupts
Diffstat:
M | cc1.c | | | 204 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | kernel.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();
}
}