diff --git a/kernel/Makefile b/kernel/Makefile index 743522f..02ceafe 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -70,7 +70,7 @@ SRCFILES += $(call GRABSRC, \ vmm \ pci \ pci/ata \ - pci/qemu_pci_serial \ + pci/serial \ cjob \ ) diff --git a/kernel/pci/ata/ata.c b/kernel/pci/ata/ata.c index 80912df..4c25076 100644 --- a/kernel/pci/ata/ata.c +++ b/kernel/pci/ata/ata.c @@ -5,6 +5,8 @@ #include "storedev/atasd.h" #include "kprintf.h" +#define TAG "ata" + #define ATA_PROBE(STRING, IOBASE, CTRLBASE, S_OR_M) \ ps = ata_probesize_bytes((IOBASE), (CTRLBASE), (S_OR_M)); \ if (ps > 0) { \ @@ -27,28 +29,34 @@ void pci_ata_init(void) { PciDev dev = pci_getdev(0x8086, 0x7010, -1); - - uint16_t iobase, ctrlbase; - uint64_t ps; - uint32_t bar0 = pci_read32(dev, PCI_BAR0); - uint32_t bar1 = pci_read32(dev, PCI_BAR1); - uint32_t bar2 = pci_read32(dev, PCI_BAR2); - uint32_t bar3 = pci_read32(dev, PCI_BAR3); + static const char *progif_msg[] = { + [0x00] = "ISA Compatibility mode-only controller", + [0x05] = "PCI native mode-only controller", + [0x0A] = "ISA Compatibility mode controller, supports both channels switched to PCI native mode", + [0x0F] = "PCI native mode controller, supports both channels switched to ISA compatibility mode", + [0x80] = "ISA Compatibility mode-only controller, supports bus mastering", + [0x85] = "PCI native mode-only controller, supports bus mastering", + [0x8A] = "ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering", + [0x8F] = "PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering", + }; - LOG("pci", "ATA bar0=0x%x, bar1=0x%x, bar2=0x%x, bar3=0x%x\n", bar0, bar1, bar2, bar3); + uint8_t progif = pci_read8(dev, PCI_PROGIF); + LOG("pci/"TAG, "progif=0x%02x\n", progif); + LOG("pci/"TAG, "DESCRIPTION: %s\n", progif_msg[progif]); - iobase = (bar0 & 0xFFFFFFFC) + ATA_PRIM_IO * (!bar0); - ctrlbase = (bar1 & 0xFFFFFFFC) + ATA_PRIM_CTRL * (!bar1); - LOG("pci", "ATA CHANNEL PRIM: iobase=0x%x, ctrlbase=0x%x\n", iobase, ctrlbase); - if (!bar0 || !bar1) LOG("pci", "falling back to ISA\n"); - ATA_PROBE("atasd0m", iobase, ctrlbase, ATA_MASTER); - ATA_PROBE("atasd0s", iobase, ctrlbase, ATA_SLAVE); - - iobase = (bar2 & 0xFFFFFFFC) + ATA_SCND_IO * (!bar2); - ctrlbase = (bar3 & 0xFFFFFFFC) + ATA_SCND_CTRL * (!bar3); - LOG("pci", "ATA CHANNEL SCND: iobase=0x%x, ctrlbase=0x%x\n", iobase, ctrlbase); - if (!bar2 || !bar3) LOG("pci", "falling back to ISA\n"); - ATA_PROBE("atasd1m", iobase, ctrlbase, ATA_MASTER); - ATA_PROBE("atasd2s", iobase, ctrlbase, ATA_SLAVE); + switch (progif) { + case 0x80: { + uint64_t ps; + + ATA_PROBE("atasd0m", ATA_PRIM_IO, ATA_PRIM_CTRL, ATA_MASTER); + ATA_PROBE("atasd0s", ATA_PRIM_IO, ATA_PRIM_CTRL, ATA_SLAVE); + + ATA_PROBE("atasd1m", ATA_SCND_IO, ATA_SCND_CTRL, ATA_MASTER); + ATA_PROBE("atasd2s", ATA_SCND_IO, ATA_SCND_CTRL, ATA_SLAVE); + } break; + default: + LOG("pci/"TAG, "Unsupported progif=0x%02x\n", progif); + break; + } } diff --git a/kernel/pci/pci.c b/kernel/pci/pci.c index fdda4b1..790d680 100644 --- a/kernel/pci/pci.c +++ b/kernel/pci/pci.c @@ -2,7 +2,7 @@ #include #include "pci/pci.h" #include "pci/ata/ata.h" -#include "pci/qemu_pci_serial/qemu_pci_serial.h" +#include "pci/serial/serial.h" #include "io/io.h" #include "std/string.h" #include "util/util.h" @@ -55,6 +55,37 @@ void pci_write8(PciDev dev, uint32_t field, uint8_t v) { io_out8(PCI_CFG_DATA, v); } +void pci_readbar(PciDev dev, uint32_t bar, uint32_t *addr, uint32_t *mask) { + *addr = pci_read32(dev, bar); + pci_write32(dev, bar, 0xffffffff); + *mask = pci_read32(dev, bar); + pci_write32(dev, bar, *addr); +} + +void pci_getbar(PciDev dev, PciBar *bar, uint32_t barid) { + uint32_t addrlo; + uint32_t masklo; + pci_readbar(dev, barid, &addrlo, &masklo); + + if (addrlo & PCI_BAR_IO) { + bar->x.io.iobase = (uint16_t)(addrlo & ~0x3); + bar->size = (uint16_t)(~(masklo & ~0x3) + 1); + bar->flags = (addrlo & 0x3); + } else if (addrlo & PCI_BAR_MEM32) { + bar->x.mem.addr = (uint64_t)(addrlo & ~0xF); + bar->size = ~(masklo & ~0xF) + 1; + bar->flags = (addrlo & 0xF); + } else if (addrlo & PCI_BAR_MEM64) { + uint32_t addrhi; + uint32_t maskhi; + pci_readbar(dev, barid+4, &addrhi, &maskhi); + + bar->x.mem.addr = (uint64_t)(((uint64_t)addrhi << 32) | (addrlo & ~0xF)); + bar->size = ~(((uint64_t)maskhi << 32) | (masklo & ~0xF)) + 1; + bar->flags = (addrlo & 0xF); + } +} + uint32_t pci_devtype(PciDev dev) { uint32_t a = pci_read8(dev, PCI_CLASS) << 8; uint32_t b = pci_read8(dev, PCI_SUBCLASS); @@ -162,7 +193,7 @@ PciDev pci_getdev(uint16_t vendorid, uint16_t deviceid, int devtype) { PciInitFn PCI_INIT_ARRAY[PCI_INIT_ARRAY_MAX] = { &pci_ata_init, - &pci_qemu_pci_serial_init, + &pci_serial_init, }; void pci_init_devs(void) { diff --git a/kernel/pci/pci.h b/kernel/pci/pci.h index d38f2e8..ea65944 100644 --- a/kernel/pci/pci.h +++ b/kernel/pci/pci.h @@ -3,6 +3,7 @@ #include #include +#include "kprintf.h" typedef union { uint32_t bits; @@ -17,6 +18,23 @@ typedef union { }; } PciDev; +typedef struct { + uint16_t iobase; +} PciBarIo; + +typedef struct { + uint64_t addr; +} PciBarMem; + +typedef struct { + union { + PciBarIo io; + PciBarMem mem; + } x; + uint64_t size; + uint32_t flags; +} PciBar; + #define PCI_CFG_ADDR 0xCF8 #define PCI_CFG_DATA 0xCFC @@ -48,7 +66,10 @@ typedef union { #define PCI_DEV_PER_BUS 32 #define PCI_FN_PER_DEV 32 -#define PCI_BAR_IOBASE(bar) ((bar) & 0xFFFFFFFC) +#define PCI_BAR_IO 0x01 +#define PCI_BAR_MEM32 0x02 +#define PCI_BAR_MEM64 0x04 +#define PCI_BAR_PREFETCH 0x08 uint32_t pci_read32(PciDev dev, uint32_t field); uint16_t pci_read16(PciDev dev, uint32_t field); @@ -56,6 +77,8 @@ uint8_t pci_read8(PciDev dev, uint32_t field); void pci_write32(PciDev dev, uint32_t field, uint32_t v); void pci_write16(PciDev dev, uint32_t field, uint16_t v); void pci_write8(PciDev dev, uint32_t field, uint8_t v); +void pci_readbar(PciDev dev, uint32_t bar, uint32_t *addr, uint32_t *mask); +void pci_getbar(PciDev dev, PciBar *bar, uint32_t barid); uint32_t pci_devtype(PciDev dev); uint32_t pci_scndrybus(PciDev dev); uint32_t pci_isend(PciDev dev); @@ -74,4 +97,13 @@ void pci_init(void); typedef void (*PciInitFn)(void); extern PciInitFn PCI_INIT_ARRAY[PCI_INIT_ARRAY_MAX]; +#define PCI_LOG_BAR(tag_, bar_, num) \ + LOG("pci/"tag_, "BAR%d: type=%s flags=0x%08x,size=0x%016x,resource=0x%016x\n", \ + num, \ + (bar_).flags & PCI_BAR_IO ? "I/O" : ((bar_).flags & PCI_BAR_MEM32 ? "MEM32" : "MEM64"), \ + (bar_).flags, \ + (bar_).size, \ + (bar_).flags & PCI_BAR_IO ? (bar_).x.io.iobase : (bar_).x.mem.addr \ + ); + #endif // PCI_PCI_H_ diff --git a/kernel/pci/qemu_pci_serial/qemu_pci_serial.c b/kernel/pci/qemu_pci_serial/qemu_pci_serial.c deleted file mode 100644 index 91bcaf8..0000000 --- a/kernel/pci/qemu_pci_serial/qemu_pci_serial.c +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include "pci/pci.h" -#include "pci/qemu_pci_serial/qemu_pci_serial.h" -#include "io/io.h" -#include "sysdefs/dev.h" -#include "util/util.h" -#include "dev/dev.h" -#include "cjob/cjob.h" -#include "proc/proc.h" -#include "errors.h" -#include "hshtb.h" -#include "kprintf.h" - -static QemuPciSerialDev QEMU_PCI_SERIAL_DEV; - -// https://wiki.osdev.org/Serial_Ports - -void _serial_init(uint16_t iobase) { - io_out8(iobase+1, 0x00); - io_out8(iobase+3, 0x80); - io_out8(iobase+0, 0x03); - io_out8(iobase+1, 0x00); - io_out8(iobase+3, 0x03); - io_out8(iobase+2, 0xC7); - io_out8(iobase+4, 0x0B); - io_out8(iobase+4, 0x1E); - io_out8(iobase+0, 0xAE); - - if (io_in8(iobase+0) != 0xAE) { - ERR("pci", "QEMU_PCI_SERIAL serial is faulty!\n"); - return; - } - - io_out8(iobase+4, 0x0F); -} - -int _serial_recvready(uint16_t iobase) { - return io_in8(iobase+5) & 1; -} - -uint8_t _serial_recvb(uint16_t iobase) { - return io_in8(iobase); -} - -int _serial_sendready(uint16_t iobase) { - return io_in8(iobase+5) & 0x20; -} - -void _serial_sendb(uint16_t iobase, uint8_t b) { - io_out8(iobase, b); -} - -int32_t qemu_pci_serial_dev_sendb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { - (void)len; (void)pid; - - QemuPciSerialDev *qpsd = dev->extra; - - if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) { - return E_DEVLOCKED; - } - - _serial_sendb(qpsd->iobase, buffer[0]); - - return E_OK; -} - -int32_t qemu_pci_serial_dev_sendready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { - (void)buffer; (void)len; (void)pid; - - QemuPciSerialDev *qpsd = dev->extra; - - if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) { - return E_DEVLOCKED; - } - - return _serial_sendready(qpsd->iobase); -} - -int32_t qemu_pci_serial_dev_recvb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { - (void)buffer; (void)len; (void)pid; - - QemuPciSerialDev *qpsd = dev->extra; - - if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) { - return E_DEVLOCKED; - } - - return _serial_recvb(qpsd->iobase); -} - -int32_t qemu_pci_serial_dev_recvready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { - (void)buffer; (void)len; (void)pid; - - QemuPciSerialDev *qpsd = dev->extra; - - if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) { - return E_DEVLOCKED; - } - - return _serial_recvready(qpsd->iobase); -} - -int32_t qemu_pci_serial_dev_lock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { - (void)buffer; (void)len; (void)pid; - - QemuPciSerialDev *qpsd = dev->extra; - - if (qpsd->lockstate == (int)pid) { - return E_OK; - } - - if (qpsd->lockstate == -1) { - qpsd->lockstate = (int)pid; - return E_OK; - } - return E_DEVLOCKED; -} - -int32_t qemu_pci_serial_dev_unlock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { - (void)buffer; (void)len; (void)pid; - - QemuPciSerialDev *qpsd = dev->extra; - - if (qpsd->lockstate == (int)pid) { - qpsd->lockstate = -1; - return E_OK; - } - return E_DEVNOTYOURLOCK; -} - -void pci_qemu_pci_serial_gc_cjob(void *arg) { - Dev *dev = arg; - - QemuPciSerialDev *qpsd; - - spinlock_acquire(&dev->spinlock); - qpsd = dev->extra; - uint64_t pid = qpsd->lockstate; - spinlock_release(&dev->spinlock); - - Proc *proc = NULL; - spinlock_acquire(&PROCS.spinlock); - LL_FINDPROP(PROCS.procs, proc, pid, pid); - spinlock_release(&PROCS.spinlock); - - if (proc == NULL) { - spinlock_acquire(&dev->spinlock); - qpsd = dev->extra; - qpsd->lockstate = -1; - spinlock_release(&dev->spinlock); - } -} - -void pci_qemu_pci_serial_init(void) { - PciDev dev = pci_getdev(0x1B36, 0x0002, -1); - if (!dev.bits) { - return; - } - - uint32_t bar0 = pci_read32(dev, PCI_BAR0); - - LOG("pci", "QEMU_PCI_SERIAL bar0=0x%x\n", bar0); - - uint16_t iobase = PCI_BAR_IOBASE(bar0); - LOG("pci", "QEMU_PCI_SERIAL iobase=0x%x\n", iobase); - - QEMU_PCI_SERIAL_DEV.iobase = iobase; - QEMU_PCI_SERIAL_DEV.lockstate = -1; - - Dev *serialdev = NULL; - HSHTB_ALLOC(DEVTABLE.devs, ident, "serialdev", serialdev); - serialdev->fns[0] = &qemu_pci_serial_dev_sendb; - serialdev->fns[1] = &qemu_pci_serial_dev_sendready; - serialdev->fns[2] = &qemu_pci_serial_dev_recvb; - serialdev->fns[3] = &qemu_pci_serial_dev_recvready; - serialdev->fns[4] = &qemu_pci_serial_dev_lock; - serialdev->fns[5] = &qemu_pci_serial_dev_unlock; - spinlock_init(&serialdev->spinlock); - serialdev->extra = &QEMU_PCI_SERIAL_DEV; - - cjob_register(&pci_qemu_pci_serial_gc_cjob, serialdev); - - _serial_init(QEMU_PCI_SERIAL_DEV.iobase); -} - diff --git a/kernel/pci/qemu_pci_serial/qemu_pci_serial.h b/kernel/pci/qemu_pci_serial/qemu_pci_serial.h deleted file mode 100644 index cc183eb..0000000 --- a/kernel/pci/qemu_pci_serial/qemu_pci_serial.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef PCI_QEMU_PCI_SERIAL_QEMU_PCI_SERIAL_H_ -#define PCI_QEMU_PCI_SERIAL_QEMU_PCI_SERIAL_H_ - -#include -#include - -typedef struct { - uint16_t iobase; - int lockstate; -} QemuPciSerialDev; - -void pci_qemu_pci_serial_init(void); - -#endif // PCI_QEMU_PCI_SERIAL_QEMU_PCI_SERIAL_H_ diff --git a/kernel/pci/serial/serial.c b/kernel/pci/serial/serial.c new file mode 100644 index 0000000..ee0ac84 --- /dev/null +++ b/kernel/pci/serial/serial.c @@ -0,0 +1,212 @@ +#include +#include +#include "pci/pci.h" +#include "pci/serial/serial.h" +#include "io/io.h" +#include "sysdefs/dev.h" +#include "util/util.h" +#include "dev/dev.h" +#include "cjob/cjob.h" +#include "proc/proc.h" +#include "errors.h" +#include "hshtb.h" +#include "kprintf.h" + +#define TAG "serial" + +static PciSerialDev PCI_SERIAL_DEV; + +// https://wiki.osdev.org/Serial_Ports + +void _serial_init(uint16_t iobase) { + io_out8(iobase+1, 0x00); + io_out8(iobase+3, 0x80); + io_out8(iobase+0, 0x03); + io_out8(iobase+1, 0x00); + io_out8(iobase+3, 0x03); + io_out8(iobase+2, 0xC7); + io_out8(iobase+4, 0x0B); + io_out8(iobase+4, 0x1E); + io_out8(iobase+0, 0xAE); + + if (io_in8(iobase+0) != 0xAE) { + ERR("pci/"TAG, "serial is faulty!\n"); + return; + } + + io_out8(iobase+4, 0x0F); +} + +int _serial_recvready(uint16_t iobase) { + return io_in8(iobase+5) & 1; +} + +uint8_t _serial_recvb(uint16_t iobase) { + return io_in8(iobase); +} + +int _serial_sendready(uint16_t iobase) { + return io_in8(iobase+5) & 0x20; +} + +void _serial_sendb(uint16_t iobase, uint8_t b) { + io_out8(iobase, b); +} + +int32_t pci_serial_dev_sendb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { + (void)len; (void)pid; + + PciSerialDev *psd = dev->extra; + + if (psd->lockstate != -1 && psd->lockstate != (int)pid) { + return E_DEVLOCKED; + } + + _serial_sendb(psd->iobase, buffer[0]); + + return E_OK; +} + +int32_t pci_serial_dev_sendready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { + (void)buffer; (void)len; (void)pid; + + PciSerialDev *psd = dev->extra; + + if (psd->lockstate != -1 && psd->lockstate != (int)pid) { + return E_DEVLOCKED; + } + + return _serial_sendready(psd->iobase); +} + +int32_t pci_serial_dev_recvb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { + (void)buffer; (void)len; (void)pid; + + PciSerialDev *psd = dev->extra; + + if (psd->lockstate != -1 && psd->lockstate != (int)pid) { + return E_DEVLOCKED; + } + + return _serial_recvb(psd->iobase); +} + +int32_t pci_serial_dev_recvready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { + (void)buffer; (void)len; (void)pid; + + PciSerialDev *psd = dev->extra; + + if (psd->lockstate != -1 && psd->lockstate != (int)pid) { + return E_DEVLOCKED; + } + + return _serial_recvready(psd->iobase); +} + +int32_t pci_serial_dev_lock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { + (void)buffer; (void)len; (void)pid; + + PciSerialDev *psd = dev->extra; + + if (psd->lockstate == (int)pid) { + return E_OK; + } + + if (psd->lockstate == -1) { + psd->lockstate = (int)pid; + return E_OK; + } + return E_DEVLOCKED; +} + +int32_t pci_serial_dev_unlock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { + (void)buffer; (void)len; (void)pid; + + PciSerialDev *psd = dev->extra; + + if (psd->lockstate == (int)pid) { + psd->lockstate = -1; + return E_OK; + } + return E_DEVNOTYOURLOCK; +} + +void pci_serial_gc_cjob(void *arg) { + Dev *dev = arg; + + PciSerialDev *psd; + + spinlock_acquire(&dev->spinlock); + psd = dev->extra; + uint64_t pid = psd->lockstate; + spinlock_release(&dev->spinlock); + + Proc *proc = NULL; + spinlock_acquire(&PROCS.spinlock); + LL_FINDPROP(PROCS.procs, proc, pid, pid); + spinlock_release(&PROCS.spinlock); + + if (proc == NULL) { + spinlock_acquire(&dev->spinlock); + psd = dev->extra; + psd->lockstate = -1; + spinlock_release(&dev->spinlock); + } +} + +void pci_serial_init(void) { + PciDev dev = pci_getdev(0x1B36, 0x0002, -1); + if (!dev.bits) { + return; + } + + static const char *progif_msg[] = { + [0x00] = "8250-Compatible (Generic XT)", + [0x01] = "16450-Compatible", + [0x02] = "16550-Compatible", + [0x03] = "16650-Compatible", + [0x04] = "16750-Compatible", + [0x05] = "16850-Compatible", + [0x06] = "16950-Compatible", + }; + + uint8_t progif = pci_read8(dev, PCI_PROGIF); + LOG("pci/"TAG, "progif=0x%02x\n", progif); + LOG("pci/"TAG, "DESCRIPTION: %s\n", progif_msg[progif]); + + switch (progif) { + case 0x02: { + PciBar bar0; + pci_getbar(dev, &bar0, PCI_BAR0); + + PCI_LOG_BAR(TAG, bar0, 0); + + if (!(bar0.flags & PCI_BAR_IO)) { + ERR("pci/"TAG, "expected BAR0 to be an I/O BAR\n"); + return; + } + + PCI_SERIAL_DEV.iobase = bar0.x.io.iobase; + PCI_SERIAL_DEV.lockstate = -1; + + Dev *serialdev = NULL; + HSHTB_ALLOC(DEVTABLE.devs, ident, "serialdev", serialdev); + serialdev->fns[0] = &pci_serial_dev_sendb; + serialdev->fns[1] = &pci_serial_dev_sendready; + serialdev->fns[2] = &pci_serial_dev_recvb; + serialdev->fns[3] = &pci_serial_dev_recvready; + serialdev->fns[4] = &pci_serial_dev_lock; + serialdev->fns[5] = &pci_serial_dev_unlock; + spinlock_init(&serialdev->spinlock); + serialdev->extra = &PCI_SERIAL_DEV; + + cjob_register(&pci_serial_gc_cjob, serialdev); + + _serial_init(PCI_SERIAL_DEV.iobase); + } break; + default: + LOG("pci/"TAG, "Unsupported progif=0x%02x\n", progif); + break; + } +} + diff --git a/kernel/pci/serial/serial.h b/kernel/pci/serial/serial.h new file mode 100644 index 0000000..a38e2b2 --- /dev/null +++ b/kernel/pci/serial/serial.h @@ -0,0 +1,14 @@ +#ifndef PCI_SERIAL_SERIAL_H_ +#define PCI_SERIAL_SERIAL_H_ + +#include +#include + +typedef struct { + uint16_t iobase; + int lockstate; +} PciSerialDev; + +void pci_serial_init(void); + +#endif // PCI_SERIAL_SERIAL_H_ diff --git a/run/qemu-x86_64-hdd.sh b/run/qemu-x86_64-hdd.sh index 79c0255..3a351d8 100755 --- a/run/qemu-x86_64-hdd.sh +++ b/run/qemu-x86_64-hdd.sh @@ -6,6 +6,6 @@ qemu-system-x86_64 \ -machine pc \ -m 4G \ -boot d \ - -hda disk.hdd \ + -drive file=disk.hdd,format=raw,if=ide \ -device pci-serial,chardev=char0 -chardev stdio,id=char0 \ $@