diff --git a/src/modules/driver.pci/main.cpp b/src/modules/driver.pci/main.cpp new file mode 100644 index 0000000..3d32b9b --- /dev/null +++ b/src/modules/driver.pci/main.cpp @@ -0,0 +1,185 @@ +// PhoeniX OS Stub hello module +// Copyright © 2019 Yury Popov a.k.a. PhoeniX + +#include "kernmod.hpp" + +MODDESC(name, "Driver/PCI"); +MODDESC(version, "1.0"); +MODDESC(description, "Generic PCI Driver"); +MODDESC(requirements, "port/CF8-CFF"); +MODDESC(developer, "PhoeniX"); + +static inline void putl(uint32_t l) { + char buf[11]; + int off = 10; + buf[off] = 0; + while (off == 10 || l > 0) { + buf[--off] = '0' + (l % 10); + l /= 10; + } + puts(buf + off); +} + +static inline void putx(uint32_t l) { + char buf[9]; + int off = 8; + buf[off] = 0; + while (off == 8 || l > 0) { + char c = static_cast(l & 0xF); + buf[--off] = (c < 10) ? ('0' + c) : ('a' + c - 10); + l /= 16; + c = static_cast(l & 0xF); + buf[--off] = (c < 10) ? ('0' + c) : ('a' + c - 10); + l /= 16; + } + puts(buf + off); +} + +namespace PCI { + static inline uint32_t readConfig32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t address, value; + address = 0x80000000u | + (uint32_t(bus) << 16) | + (uint32_t(slot) << 11) | + (uint32_t(func) << 8) | + (uint32_t(offset) & 0xFC); + asm volatile( + "mov $0xCF8, %%dx\n" + "outl %%eax, %%dx\n" + "add $4, %%dx\n" + "inl %%dx, %%eax" + :"=a"(value):"a"(address):"dx"); + return value; + } + struct Device { + uint16_t vendor, device; + uint16_t command, status; + uint8_t revision, prog_if, subclass, classcode; + uint8_t cache_line_size, latency_timer, header_type, bist; + union { + struct { + uint32_t bar[6]; + uint32_t cardbus_cis; + uint16_t subsystem_vendor, subsystem_id; + uint32_t rom_base; + uint8_t caps_ptr, rsvd[3+4]; + uint8_t intr_line, intr_pin, min_grant, max_latency; + } __attribute__((packed)) device; + struct { + uint32_t bar[2]; + uint8_t prim_bus_num, sec_bus_num, sub_bus_num, sec_latency_timer; + uint8_t iobase, iolimit; uint16_t sec_status; + uint16_t membase, memlim; + uint16_t pref_membase, pref_memlim; + uint32_t pref_membase_u32; + uint32_t pref_memlim_u32; + uint16_t iobase_u16, iolim_u16; + uint8_t caps_ptr, rsvd[3]; + uint32_t rom_base; + uint8_t intr_line, intr_pin; uint16_t bridgectl; + } __attribute__((packed)) pcibridge; + struct { + uint32_t cardbus_sock_exca_base; + uint8_t cap_off, rsvd; uint16_t sec_status; + uint8_t pci_bus_num, cardbus_bus_num, sub_bus_num, cardbus_lat_timer; + uint32_t membase0, memlim0; + uint32_t membase1, memlim1; + uint32_t iobase0, iolim0; + uint32_t iobase1, iolim1; + uint8_t intr_line, intr_pin, bridgectl; + uint16_t sub_device, sub_vendor; + uint32_t pccard_base; + } __attribute__((packed)) cardbusbridge; + } __attribute__((packed)) _spec; + + template static inline T read(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + return T(readConfig32(bus, slot, func, offset) >> ((offset & 0x3) * 8)); + } + static inline uint8_t getHeaderType(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, header_type)); + } + static inline uint16_t getVendorID(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, vendor)); + } + static inline uint16_t getDeviceID(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, device)); + } + static inline uint8_t getBaseClass(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, classcode)); + } + static inline uint8_t getSubClass(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, subclass)); + } + static inline uint8_t getProgIf(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, prog_if)); + } + static inline uint8_t getRevision(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, revision)); + } + static inline uint8_t getSecondaryBus(uint8_t bus, uint8_t slot, uint8_t func) { + return read(bus, slot, func, offsetof(Device, _spec.pcibridge.sec_bus_num)); + } + } __attribute__((packed)); + static void provideDevice(uint8_t bus, uint8_t device, uint8_t function) { + uint8_t baseClass = Device::getBaseClass(bus, device, function); + uint8_t subClass = Device::getSubClass(bus, device, function); + uint8_t progIf = Device::getProgIf(bus, device, function); + uint8_t rev = Device::getRevision(bus, device, function); + puts("TODO: Provide device: "); + uint16_t vendorID = Device::getVendorID(bus, device, function); + uint16_t deviceId = Device::getDeviceID(bus, device, function); + putl(bus); puts("."); putl(device); puts("."); putl(function); puts(" => "); + puts("["); putx(uint32_t(baseClass << 8) | subClass); puts("."); putx(progIf); puts("."); putx(rev); puts("]"); + putx(vendorID); puts("."); putx(deviceId); + puts("\n"); + } + static void scanBus(uint8_t bus); + static void scanFunction(uint8_t bus, uint8_t device, uint8_t function) { + uint8_t baseClass = Device::getBaseClass(bus, device, function); + uint8_t subClass = Device::getSubClass(bus, device, function); + if ((baseClass == 0x06) && (subClass == 0x04)) { + uint8_t secondaryBus = Device::getSecondaryBus(bus, device, function); + scanBus(secondaryBus); + } else { + provideDevice(bus, device, function); + } + } + static void scanDevice(uint8_t bus, uint8_t device) { + uint8_t function = 0; + uint16_t vendorID = Device::getVendorID(bus, device, function); + if (vendorID == 0xFFFF) return; + scanFunction(bus, device, function); + uint8_t headerType = Device::getHeaderType(bus, device, function); + if ((headerType & 0x80) != 0) { + for (function = 1; function < 8; function++) { + if (Device::getVendorID(bus, device, function) != 0xFFFF) { + scanFunction(bus, device, function); + } + } + } + } + static void scanBus(uint8_t bus) { + static uint64_t checked = 0; + if (checked & (1llu << bus)) return; + checked |= (1llu << bus); + for (uint8_t device = 0; device < 32; device++) { + scanDevice(bus, device); + } + } + static void scanAllBuses() { + uint8_t headerType = Device::getHeaderType(0, 0, 0); + if ((headerType & 0x80) == 0) { + scanBus(0); + } else { + for (uint8_t function = 0; function < 8; function++) { + if (Device::getVendorID(0, 0, function) != 0xFFFF) break; + scanBus(function); + } + } + } +} // namespace PCI + +void module() { + PCI::scanAllBuses(); + exit(0); +} diff --git a/src/modules/hello/module.cmake b/src/modules/driver.pci/module.cmake similarity index 100% rename from src/modules/hello/module.cmake rename to src/modules/driver.pci/module.cmake diff --git a/src/modules/hello/hello.cpp b/src/modules/hello/hello.cpp deleted file mode 100644 index e7e0a26..0000000 --- a/src/modules/hello/hello.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// PhoeniX OS Stub hello module -// Copyright © 2017 Yury Popov a.k.a. PhoeniX - -#define MODDESC(k, v) \ - extern const char \ - __attribute__((section(".module"))) \ - __attribute__((aligned(1))) \ - module_ ## k[] = v; \ - -MODDESC(name, "Test/Hello"); -MODDESC(version, "1.0"); -MODDESC(description, "Prints \"Hello, world\" text"); -MODDESC(requirements, ""); -MODDESC(developer, "PhoeniX"); - -extern "C" { void module(); void puts(const char *); void exit(int); } - -void module() { - puts("Hello, "); - puts("world!\n"); - exit(0); -}