os

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

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+
Mas.c | 2++
Mcc1.c | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mkernel.c | 506++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mkernel.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