commit 32131975bc5eb22715ed659bc2f199ce4bb76dd3
parent 1177ff90b29835e8d9bc8fc3ff7b2ee4f5e659d8
Author: erai <erai@omiltem.net>
Date: Tue, 9 Apr 2024 08:13:23 -0400
pci bus enumeration
Diffstat:
M | .gitignore | | | 1 | + |
M | as.c | | | 2 | ++ |
M | cc1.c | | | 53 | ++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | kernel.c | | | 506 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
M | kernel.sh | | | 4 | ++-- |
5 files changed, 546 insertions(+), 20 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,5 +1,6 @@
a.out
kernel
+disk
cc0
cc1
cc2
diff --git a/as.c b/as.c
@@ -127,8 +127,10 @@ enum {
OP_LEA = 0x8d,
OP_LOAD = 0x8b,
OP_LOADB = 0x8a,
+ OP_LOAD16 = 0x668a,
OP_STOREB = 0x88,
OP_STORE = 0x89,
+ OP_STORE16 = 0x6689,
OP_MOVE = 0x8b,
}
diff --git a/cc1.c b/cc1.c
@@ -494,8 +494,8 @@ compile_expr(c: *compiler, d: *decl, n: *node, rhs: int) {
v = find(c, d.name, n.a.s, 0);
if (v && v.var_defined) {
emit_lea(c.as, v.var_offset);
- emit_load(c.as, n.a.t);
n.a.t = v.var_type;
+ emit_load(c.as, n.a.t);
emit_call(c.as, count_args(c, n.a.t.arg));
} else {
v = find(c, n.a.s, 0:*byte, 0);
@@ -1789,6 +1789,57 @@ main(argc: int, argv: **byte, envp: **byte) {
emit_isr(c);
}
+ d = find(c, "_r32", 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_RSI, R_RBP, 0, 0, 16);
+ c.as.bits32 = 1;
+ as_modrm(c.as, OP_LOAD, R_RAX, R_RSI, 0, 0, 0);
+ c.as.bits32 = 0;
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "_w32", 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_RBP, 0, 0, 24);
+ c.as.bits32 = 1;
+ as_modrm(c.as, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
+ c.as.bits32 = 0;
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "_r16", 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_RSI, R_RBP, 0, 0, 16);
+ as_modrr(c.as, OP_XORRM, R_RAX, R_RAX);
+ c.as.bits32 = 1;
+ as_modrm(c.as, OP_LOAD16, R_RAX, R_RDI, 0, 0, 0);
+ c.as.bits32 = 0;
+ as_opr(c.as, OP_PUSHR, R_RAX);
+ emit_ret(c.as);
+ }
+
+ d = find(c, "_w16", 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_RBP, 0, 0, 24);
+ c.as.bits32 = 1;
+ as_modrm(c.as, OP_STORE16, R_RAX, R_RDI, 0, 0, 0);
+ c.as.bits32 = 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);
diff --git a/kernel.c b/kernel.c
@@ -69,9 +69,11 @@ _start() {
}
}
-ru32(p: *byte): int {
- return p[0]:int + (p[1]:int << 8) + (p[2]:int << 16) + (p[3]:int << 24);
-}
+_r32(p: *byte): int;
+_w32(p: *byte, x: int): int;
+
+_r16(p: *byte): int;
+_w16(p: *byte, x: int): int;
// FIXME a very dumb and lossy but simple serial debug
@@ -181,16 +183,42 @@ bzero(s: *byte, size: int) {
}
_isr(r: *regs) {
+ if (r.trap < 32) {
+ sputs("EX ");
+ sputd(r.trap);
+ sputs("\n");
+ }
+
if (r.trap == 2) {
sputs("NMI\n");
}
// pic end of interrupt
if (r.trap >= 32 && r.trap < 48) {
+ if (r.trap == 32) {
+ } else if (r.trap == 42) {
+ sputc('n');
+ sputc('\n');
+ } else if (r.trap == 43) {
+ // ethernet interrupt
+ sputc('e');
+ }
if (r.trap < 40) {
- outb(IO_PIC2, 0x20);
+ outb(IO_PIC1, 0x0b);
+ if inb(IO_PIC1) & (1 << (r.trap & 7)) {
+ outb(IO_PIC1, 0x20);
+ } else {
+ sputs("s\n");
+ }
+ } else {
+ outb(IO_PIC2, 0x0b);
+ if inb(IO_PIC2) & (1 << (r.trap & 7)) {
+ outb(IO_PIC2, 0x20);
+ outb(IO_PIC1, 0x20);
+ } else {
+ sputs("s\n");
+ }
}
- outb(IO_PIC1, 0x20);
}
}
@@ -250,21 +278,449 @@ bytesum(a: *byte, n: int): byte {
}
}
-find_rsdp(): int {
+ptov(p: int): *byte {
+ return (p + (-0x8000 << 16)): *byte;
+}
+
+acpi_len(p: int): int {
+ if p == 0 {
+ return 0;
+ }
+ return _r32((ptov(p):int + 4):*byte);
+}
+
+valid_table(p: int, sig: *byte): int {
+ var len: int;
+ var v: *byte;
+
+ v = ptov(p);
+
+ if memcmp(v, sig, 4) {
+ return 0;
+ }
+
+ len = acpi_len(p);
+ if len < 36 {
+ return 0;
+ }
+
+ if bytesum(v, len):int != 0 {
+ return 0;
+ }
+
+ return len;
+}
+
+find_rsdt(): int {
var p: int;
+
+ // Find the RDSP
p = 0;
loop {
if p == 0x100000 {
- break;
+ return 0;
}
- if !memcmp((((-0x8000 << 16) + p):*byte), "RSD PTR ", 8) {
- if !bytesum((((-0x8000 << 16) + p):*byte), 20) {
- return p;
+ if !memcmp(ptov(p), "RSD PTR ", 8) {
+ if !bytesum(ptov(p), 20) {
+ break;
}
}
p = p + 16;
}
- return 0;
+
+ p = _r32(ptov(p + 16));
+
+ if valid_table(p, "RSDT") == 0 {
+ return 0;
+ }
+
+ return p;
+}
+
+find_acpi(rsdt: int, sig: *byte): int {
+ var i: int;
+ var len: int;
+ var p: int;
+
+ if rsdt == 0 {
+ return 0;
+ }
+
+ i = 36;
+ len = acpi_len(rsdt);
+
+ loop {
+ if i >= len {
+ return 0;
+ }
+
+ p = _r32(ptov(rsdt + i));
+
+ if valid_table(p, sig) != 0 {
+ return p;
+ }
+
+ i = i + 4;
+ }
+}
+
+map_pci(va: *byte, pa: int): *byte {
+ var pt4p: int;
+ var pt4: *int;
+ var pt3: *int;
+ var v2: int;
+ var flags: int;
+ pt4p = rdcr3();
+ pt4 = ptov(pt4p):*int;
+ v2 = ((va: int) >> 30) & 511;
+ pt3 = ptov(pt4[511] & -4096):*int;
+ flags = 0x93;
+ pt3[v2] = (pa & -(1 << 30)) | flags;
+ pt3[v2 + 1] = ((pa + (1 << 30)) & -(1 << 30)) | flags;
+ wrcr3(pt4p);
+ return &va[pa & ((1 << 30) - 1)];
+}
+
+struct pcidev {
+ user: *void;
+ addr: *byte;
+ bus: int;
+ vid: int;
+ did: int;
+ cls: int;
+ subcls: int;
+ bar0: int;
+ bar1: int;
+ bar2: int;
+ bar3: int;
+ bar4: int;
+ bar5: int;
+ trap: *byte;
+}
+
+scan_pci(base: *byte, visit: func(dev: *pcidev), user: *void) {
+ var i: int;
+ var dev: pcidev;
+ i = 0;
+ loop {
+ if i == 256 {
+ break;
+ }
+
+ dev.user = user;
+ dev.addr = &base[i * 4096];
+ dev.bus = i;
+
+ dev.vid = (base[i * 4096 + 0]:int)
+ + (base[i * 4096 + 1]:int << 8);
+ dev.did = (base[i * 4096 + 2]:int)
+ + (base[i * 4096 + 3]:int << 8);
+ dev.cls = base[i * 4096 + 11]: int;
+ dev.subcls = base[i * 4096 + 10]: int;
+ dev.bar0 = _r32(&base[i * 4096 + 16 + 4 * 0]);
+ dev.bar1 = _r32(&base[i * 4096 + 16 + 4 * 1]);
+ dev.bar2 = _r32(&base[i * 4096 + 16 + 4 * 2]);
+ dev.bar3 = _r32(&base[i * 4096 + 16 + 4 * 3]);
+ dev.bar4 = _r32(&base[i * 4096 + 16 + 4 * 4]);
+ dev.bar5 = _r32(&base[i * 4096 + 16 + 4 * 5]);
+
+ dev.trap = &base[i * 4096 + 60];
+
+ if dev.vid == 0xffff {
+ i = i + 1;
+ continue;
+ }
+
+ visit(&dev);
+
+ i = i + 1;
+ }
+}
+
+clear_int(dev: *pcidev) {
+ *dev.trap = 0xff:byte;
+ _w16(&dev.addr[4], 0);
+}
+
+show_pcidev(dev: *pcidev) {
+ sputh(dev.bus);
+ sputc(':');
+ sputc('\t');
+ sputh(dev.vid);
+ sputc(':');
+ sputh(dev.did);
+ sputc('\t');
+ sputh(dev.cls);
+ sputc(':');
+ sputh(dev.subcls);
+ sputc('\t');
+ sputh(dev.bar0);
+ sputc('\t');
+ sputh(dev.bar1);
+ sputc('\t');
+ sputh(dev.bar2);
+ sputc('\t');
+ sputh(dev.bar3);
+ sputc('\t');
+ sputh(dev.bar4);
+ sputc('\t');
+ sputh(dev.bar5);
+ sputc('\n');
+}
+
+map_bar(va: *byte, dev: *pcidev): *byte {
+ var type: int;
+ var pa: int;
+
+ type = (dev.bar0 >> 1) & 3;
+ pa = dev.bar0 & -16;
+
+ // io bar
+ if (dev.bar0 & 1) != 0 || type == 3 {
+ return 0:*byte;
+ }
+
+ // 64 bit bar
+ if type == 1 {
+ pa = pa | (dev.bar1 << 32);
+ }
+
+ return map_pci(va, pa);
+}
+
+enum {
+ E1_TXDESCLO = 0x3800,
+ E1_TXDESCHI = 0x3804,
+ E1_TXDESCLEN = 0x3808,
+ E1_TXDESCHEAD = 0x3810,
+ E1_TXDESCTAIL = 0x3818,
+ E1_TCTRL = 0x0400,
+ E1_TIPG = 0x0410,
+
+ E1_RXDESCLO = 0x2800,
+ E1_RXDESCHI = 0x2804,
+ E1_RXDESCLEN = 0x2808,
+ E1_RXDESCHEAD = 0x2810,
+ E1_RXDESCTAIL = 0x2818,
+ E1_RCTRL = 0x0100,
+
+ E1_IMASK = 0x00d0,
+ E1_ICR = 0x00C0,
+}
+
+onesum(h: *byte, n: int): int {
+ var i: int;
+ var s: int;
+ i = 0;
+ s = 0;
+ loop {
+ if i >= n {
+ break;
+ }
+ s = s + (h[i]:int << 8) + (h[i + 1]:int);
+ s = (s & 0xffff) + ((s >> 16) & 1);
+ i = i + 2;
+ }
+ return s;
+}
+
+ip_checksum(h: *byte) {
+ var s: int;
+ h[10] = 0:byte;
+ h[11] = 0:byte;
+ s = ~onesum(h, 20);
+ h[10] = (s >> 8):byte;
+ h[11] = s:byte;
+}
+
+icmp_checksum(p: *byte) {
+ var s: int;
+ p[2] = 0: byte;
+ p[3] = 0: byte;
+ s = ~onesum(p, 8);
+ p[2] = (s >> 8):byte;
+ p[3] = s:byte;
+}
+
+init_e1000(dev: *pcidev) {
+ var flag: *int;
+ var base: *byte;
+ var mac: int;
+ var i: int;
+ var txring: *byte;
+
+ flag = dev.user: *int;
+ if *flag || dev.vid != 0x8086 || (
+ dev.did != 0x100e
+ && dev.did != 0x1539
+ ) {
+ return;
+ }
+ *flag = 1;
+ *dev.trap = 10:byte;
+
+ base = map_bar(ptov(-(1<<34)), dev);
+ if !base {
+ return;
+ }
+
+ // Enable dma
+ _w16(&dev.addr[4], 6);
+
+ // Disable interrupts
+ _w32(&base[E1_IMASK], 0);
+
+ // Clear MTA
+ i = 0;
+ loop {
+ if i == 0x80 {
+ break;
+ }
+ _w32(&base[0x5200 + 4 * i], 0);
+ i = i + 1;
+ }
+
+ // Read mac
+ mac = _r32(&base[0x5400]) + (_r32(&base[0x5404])) << 32;
+
+ txring = map_pci((-(1<<35)):*byte, 1024*1024*3);
+
+ i = 0;
+ loop {
+ if i == 16 {
+ break;
+ }
+ bzero(&txring[16*32 + 16*i], 16);
+ ((&txring[16*32 + 16*i]):*int)[0] = 1024*1024*3 + 4096 * (i + 1);
+ _w16(&txring[16*32 + 16*i + 8], 2048);
+ i = i + 1;
+ }
+
+ // Create tx descriptors
+ _w32(&base[E1_TXDESCLO], 1024*1024*3);
+ _w32(&base[E1_TXDESCHI], 0);
+ _w32(&base[E1_TXDESCLEN], 16*32);
+ _w32(&base[E1_TXDESCHEAD], 0);
+ _w32(&base[E1_TXDESCTAIL], 0);
+
+ // Create rx descriptors
+ _w32(&base[E1_RXDESCLO], 1024*1024*3+16*32);
+ _w32(&base[E1_RXDESCHI], 0);
+ _w32(&base[E1_RXDESCLEN], 16*32);
+ _w32(&base[E1_RXDESCHEAD], 0);
+ _w32(&base[E1_RXDESCTAIL], 31);
+
+ // Enable interrupts
+ _w32(&base[E1_IMASK], 0);
+
+ // Enable rx and tx
+ _w32(&base[E1_TCTRL], 0x3003f0fa);
+ _w32(&base[E1_RCTRL],
+ // Enable
+ (1 << 1)
+ // StoreBadPackets
+ + (1 << 2)
+ // UnicastPromiscuous
+ + (1 << 3)
+ // MulticastPromiscuous
+ + (1 << 4)
+ // LoobackMode
+ + (0 << 6)
+ // BroadcastAccept
+ + (1 << 15)
+ // ReceiveBufferSize
+ + (0 << 16)
+ // StripEthernetCRC
+ + (1 << 26));
+
+ // Send a packet
+ (txring:*int)[0] = 1024*1024*3 + 16*32*2;
+ _w16(&txring[8], 60);
+ txring[10] = 0:byte;
+ // ReportStatus + InsertFrameCheckSequence + EndOfPacket
+ txring[11] = ((0 << 3) + (1 << 1) + 1):byte;
+ txring[12] = 0:byte;
+ txring[13] = 0:byte;
+ txring[14] = 0:byte;
+ txring[15] = 0:byte;
+ txring[16*32*2 + 0] = (mac >> 40):byte;
+ txring[16*32*2 + 1] = (mac >> 32):byte;
+ txring[16*32*2 + 2] = (mac >> 24):byte;
+ txring[16*32*2 + 3] = (mac >> 16):byte;
+ txring[16*32*2 + 4] = (mac >> 8):byte;
+ txring[16*32*2 + 5] = mac:byte;
+ txring[16*32*2 + 6] = 0x36:byte;
+ txring[16*32*2 + 7] = 0xb9:byte;
+ txring[16*32*2 + 8] = 0x55:byte;
+ txring[16*32*2 + 9] = 0x54:byte;
+ txring[16*32*2 + 10] = 0xba:byte;
+ txring[16*32*2 + 11] = 0xcf:byte;
+ txring[16*32*2 + 12] = 0x08:byte;
+ txring[16*32*2 + 13] = 0x00:byte;
+
+ txring[16*32*2 + 14] = 0x45:byte;
+ txring[16*32*2 + 15] = 0:byte;
+ txring[16*32*2 + 16] = 0:byte;
+ txring[16*32*2 + 17] = 28:byte;
+ txring[16*32*2 + 18] = 0:byte;
+ txring[16*32*2 + 19] = 0:byte;
+ txring[16*32*2 + 20] = 0:byte;
+ txring[16*32*2 + 21] = 0:byte;
+ txring[16*32*2 + 22] = 64:byte;
+ txring[16*32*2 + 23] = 1:byte;
+ txring[16*32*2 + 24] = 0:byte;
+ txring[16*32*2 + 25] = 0:byte;
+ txring[16*32*2 + 26] = 192:byte;
+ txring[16*32*2 + 27] = 168:byte;
+ txring[16*32*2 + 28] = 32:byte;
+ txring[16*32*2 + 29] = 2:byte;
+ txring[16*32*2 + 30] = 192:byte;
+ txring[16*32*2 + 31] = 168:byte;
+ txring[16*32*2 + 32] = 32:byte;
+ txring[16*32*2 + 33] = 1:byte;
+
+ ip_checksum(&txring[16*32*2 + 14]);
+
+ txring[16*32*2 + 34] = 8:byte;
+ txring[16*32*2 + 35] = 0:byte;
+ txring[16*32*2 + 36] = 0:byte;
+ txring[16*32*2 + 37] = 0:byte;
+ txring[16*32*2 + 38] = 0:byte;
+ txring[16*32*2 + 39] = 0:byte;
+ txring[16*32*2 + 40] = 0:byte;
+
+ icmp_checksum(&txring[16*32*2 + 34]);
+
+ _w32(&base[E1_TXDESCTAIL], 1);
+ _w32(&base[E1_IMASK], (1 << 0) + (1 << 4));
+}
+
+init_nvme(dev: *pcidev) {
+ var flag: *int;
+ var base: *byte;
+
+ flag = dev.user: *int;
+ if *flag || dev.cls != 1 || dev.subcls != 8 {
+ return;
+ }
+ *flag = 1;
+ *dev.trap = 11:byte;
+
+ // Enable dma
+ _w16(&dev.addr[4], 6);
+
+ // Map bar
+ base = map_bar(ptov(-(1<<36)), dev);
+ if !base {
+ return;
+ }
+
+ sputs("nvme\n");
+
+ // setup admin ring
+ // enable interrupts
+
+
}
_kstart(mb: *byte) {
@@ -275,11 +731,15 @@ _kstart(mb: *byte) {
var idt_size: int;
var gdt: *int;
var gdt_size: int;
- var rsdp: int;
+ var rsdt: int;
+ var mcfg: int;
+ var pcip: int;
+ var pci: *byte;
+ var flag: int;
setup_serial();
- brk = ((-0x8000 << 16) + 1024 * 512 * 3);
+ brk = ptov(1024 * 512 * 3):int;
// Zero tss and add interrupt stacks
tss = brk: *int;
@@ -353,10 +813,22 @@ _kstart(mb: *byte) {
outb(IO_PIT + 0, 0x2e);
// unmask pit
- outb(IO_PIC1 + 1, 0xfe);
- outb(IO_PIC2 + 1, 0xff);
-
- rsdp = find_rsdp();
+ outb(IO_PIC1 + 1, 0xfa);
+ outb(IO_PIC2 + 1, 0xf3);
+
+ // Find ACPI tables
+ rsdt = find_rsdt();
+ mcfg = find_acpi(rsdt, "MCFG");
+
+ pcip = (ptov(mcfg + 44):*int)[0];
+ pci = map_pci(ptov(-(1<<31)), pcip);
+
+ //scan_pci(pci, show_pcidev, 0:*void);
+ scan_pci(pci, clear_int, 0:*void);
+ flag = 0;
+ scan_pci(pci, init_e1000, (&flag):*void);
+ flag = 0;
+ scan_pci(pci, init_nvme, (&flag):*void);
// Wait for interrupts
loop {
diff --git a/kernel.sh b/kernel.sh
@@ -1,3 +1,3 @@
#!/bin/bash
-# nc -l -k -j -U /tmp/s
-./bootstrap.sh && ./cc2 kernel.c -o kernel && qemu-system-x86_64 -kernel kernel -M q35 -m 1g -nographic -monitor stdio -serial chardev:sock -chardev socket,id=sock,path=/tmp/s
+truncate --size 4096 disk
+./bootstrap.sh && ./cc2 kernel.c -o kernel && qemu-system-x86_64 -kernel kernel -M q35 -m 1g -nographic -monitor stdio -serial chardev:sock -chardev socket,id=sock,path=/tmp/s -drive file=disk,if=none,id=disk,format=raw -device nvme,serial=12345678,drive=disk -device e1000,netdev=net -netdev tap,id=net,ifname=tap0,script=no,downscript=no