Added PCI device detection and a start script.

This commit is contained in:
2024-01-22 01:49:02 +01:00
parent 847bf8c84b
commit fa6dab4f88
13 changed files with 581 additions and 65 deletions

View File

@@ -1,6 +1,56 @@
#include <cstdio>
#include "drivers/pci.hpp"
#include "drivers/ps2.hpp"
namespace
{
void cmdLspci() noexcept
{
using namespace baos::pci;
std::puts("Enumerating PCI devices.");
GeneralDeviceHeader generalDeviceHeader = {};
for (const Header& header : enumerateDevices())
{
std::printf("Bus %d, Port %d, Function %d: VendorID: 0x%X, DeviceID: 0x%X, Base Class: 0x%X, Sub Class: 0x%X\n",
header.bus, header.device, header.function, header.vendorID, header.deviceID,
static_cast<unsigned>(header.baseClass), static_cast<unsigned>(header.subClass));
if (header.headerType == HeaderType::GENERAL_DEVICE && getGeneralDeviceHeader(header, generalDeviceHeader))
{
std::printf(" BAR0: 0x%X, BAR1: 0x%X, BAR2: 0x%X\n"
" BAR3: 0x%X, BAR4: 0x%X, BAR5: 0x%X\n"
" Subsystem Vendor ID: 0x%X, Subsystem ID: 0x%X\n",
generalDeviceHeader.bar0, generalDeviceHeader.bar1, generalDeviceHeader.bar2,
generalDeviceHeader.bar3, generalDeviceHeader.bar4, generalDeviceHeader.bar5,
generalDeviceHeader.subsystemVendorID, generalDeviceHeader.subsystemID);
}
}
}
void cmdShowKeys() noexcept
{
std::puts("Press CTRL-C to quit.");
while (true)
{
baos::ps2::KeyEvent event;
while (!baos::ps2::readKey(event));
std::printf(
"Key event: scancode=%s(0x%X), down=%s, repeat=%s\n",
baos::ps2::keyName(event.scancode),
static_cast<unsigned>(event.scancode),
event.down ? "true" : "false",
event.repeat ? "true" : "false"
);
if (event.scancode == baos::ps2::Scancode::C && baos::ps2::isKeyDown(baos::ps2::Scancode::LEFT_CONTROL)) {
return;
}
}
}
}
extern "C" void main()
{
@@ -11,6 +61,17 @@ extern "C" void main()
std::printf("> ");
std::getline(cmd);
cmd.pop_back(); // pop the \n
std::printf("Your command: %s\n", cmd.c_str());
if (cmd == "lspci")
{
cmdLspci();
continue;
}
else if (cmd == "show-keys")
{
cmdShowKeys();
continue;
}
std::printf("Unknown command: %s.\n", cmd.c_str());
}
}

View File

@@ -0,0 +1,126 @@
#include "drivers/pci.hpp"
#include <bit>
#include <cstring>
#include "os/port.hpp"
namespace baos::pci
{
namespace
{
inline constexpr std::uint16_t PORT_PCI_CONFIG = 0xCF8;
inline constexpr std::uint16_t PORT_PCI_DATA = 0xCFC;
std::uint32_t readConfigLine(std::uint8_t bus, std::uint8_t device, std::uint8_t func, std::uint8_t offset) noexcept
{
struct PciAddress
{
std::uint8_t registerOffset : 8 = 0;
std::uint8_t function : 3 = 0;
std::uint8_t device : 5 = 0;
std::uint8_t bus : 8 = 0;
std::uint8_t reserved : 7 = 0;
bool enable : 1 = 0;
} __attribute__((packed));
const PciAddress address = {
.registerOffset = static_cast<std::uint8_t>(offset & 0xFCu),
.function = func,
.device = device,
.bus = bus,
.enable = true
};
writePort32(PORT_PCI_CONFIG, std::bit_cast<std::uint32_t>(address));
return readPort32(PORT_PCI_DATA);
}
template<typename THeader>
bool getHeader(std::uint8_t bus, std::uint8_t device, std::uint8_t function, THeader& outHeader) noexcept
{
static_assert(sizeof(THeader) % 4 == 0);
std::uint32_t line = readConfigLine(bus, device, function, 0x0);
if (line == 0xFFFFFFFF) {
return false;
}
outHeader.bus = bus;
outHeader.device = device;
outHeader.function = function;
std::memcpy(&outHeader.vendorID, &line, 4);
for (unsigned row = 1; row < sizeof(THeader) / 4; ++row)
{
line = readConfigLine(bus, device, 0, 4 * row);
std::memcpy(reinterpret_cast<std::uint32_t*>(&outHeader.vendorID) + row, &line, 4);
}
return true;
}
void enumerateDevice(const Header& header, std::vector<Header>& outHeaders) noexcept;
void enumerateBusDevices(std::uint8_t bus, std::vector<Header>& outHeaders, std::uint8_t firstDevice = 0) noexcept
{
Header header = {};
for (std::uint8_t device = firstDevice; device < 32; ++device)
{
if (!getHeader(bus, device, 0, header)) {
continue;
}
enumerateDevice(header, outHeaders);
if (header.multiFunction)
{
for (std::uint8_t function = 1; function < 8; ++function)
{
if (!getHeader(bus, device, function, header)) {
continue;
}
enumerateDevice(header, outHeaders);
}
}
}
}
void enumerateDevice(const Header& header, std::vector<Header>& outHeaders) noexcept
{
outHeaders.push_back(header);
if (header.headerType == HeaderType::PCI_TO_PCI_BRIDGE && header.baseClass == BaseClass::BRIDGE && header.subClass == SubClass::PCI_TO_PCI_BRIDGE)
{
// get the bridge header
PCIToPCIBridgeHeader bridgeHeader = {};
if (getHeader(header.bus, header.device, header.function, bridgeHeader))
{
enumerateBusDevices(bridgeHeader.secondaryBusNumber, outHeaders);
}
}
}
}
std::vector<Header> enumerateDevices() noexcept
{
Header header = {};
if (!getHeader(0, 0, 0, header)) {
return {};
}
// also add the controller itself
std::vector<Header> headers;
headers.push_back(header);
enumerateBusDevices(0, headers, /* firstDevice = */ 1);
if (header.multiFunction)
{
for (std::uint8_t function = 1; function < 8; ++function)
{
if (!getHeader(0, 0, function, header)) {
continue;
}
headers.push_back(header);
enumerateBusDevices(function, headers);
}
}
return headers;
}
bool getGeneralDeviceHeader(std::uint8_t bus, std::uint8_t device, std::uint8_t function, GeneralDeviceHeader& outHeader) noexcept
{
return getHeader(bus, device, function, outHeader);
}
}

View File

@@ -11,22 +11,22 @@ inline constexpr std::uint8_t PIC_CFG_8086 = 0x01;
void picWriteCmd(std::uint16_t port, std::uint8_t command) noexcept
{
writePortByte(port, command);
writePort8(port, command);
}
[[nodiscard]] std::uint8_t picReadResponse(std::uint8_t port) noexcept
{
return readPortByte(port);
return readPort8(port);
}
void picWriteData(std::uint16_t port, std::uint8_t data) noexcept
{
writePortByte(port + 1, data);
writePort8(port + 1, data);
}
[[nodiscard]] std::uint8_t picReadData(std::uint16_t port) noexcept
{
return readPortByte(port + 1);
return readPort8(port + 1);
}
[[nodiscard]] std::uint16_t readPICIRQRegisters(std::uint8_t readCommand) noexcept
@@ -81,9 +81,9 @@ bool initPICs(std::uint8_t masterOffset, std::uint8_t slaveOffset) noexcept
void sendEndOfInterrupt(std::uint8_t irq) noexcept
{
if (irq >= 8) {
writePortByte(PORT_PIC2, PIC_CMD_EOI);
writePort8(PORT_PIC2, PIC_CMD_EOI);
}
writePortByte(PORT_PIC1, PIC_CMD_EOI);
writePort8(PORT_PIC1, PIC_CMD_EOI);
}
void maskIRQ(std::uint8_t irq) noexcept

View File

@@ -360,7 +360,7 @@ inline bool waitForResponse(unsigned tries = -1) noexcept
{
for (unsigned t = 0; t < tries; ++t)
{
if (readPortByte(PORT_PS2_STATUS) & FLAG_PS2_OUTPUT_FULL) {
if (readPort8(PORT_PS2_STATUS) & FLAG_PS2_OUTPUT_FULL) {
return true;
}
}
@@ -369,27 +369,27 @@ inline bool waitForResponse(unsigned tries = -1) noexcept
inline void waitForInputFree() noexcept
{
while (readPortByte(PORT_PS2_STATUS) & FLAG_PS2_INPUT_FULL);
while (readPort8(PORT_PS2_STATUS) & FLAG_PS2_INPUT_FULL);
}
inline std::uint8_t cmdWithResponse(std::uint8_t cmd) noexcept
{
writePortByte(PORT_PS2_STATUS, cmd);
writePort8(PORT_PS2_STATUS, cmd);
waitForResponse();
return readPortByte(PORT_PS2_DATA);
return readPort8(PORT_PS2_DATA);
}
inline void cmdWithData(std::uint8_t cmd, std::uint8_t data) noexcept
{
writePortByte(PORT_PS2_STATUS, cmd);
writePort8(PORT_PS2_STATUS, cmd);
waitForInputFree();
writePortByte(PORT_PS2_DATA, data);
writePort8(PORT_PS2_DATA, data);
}
inline void sendToFirstDevice(std::uint8_t cmd) noexcept
{
waitForInputFree();
writePortByte(PORT_PS2_DATA, cmd);
writePort8(PORT_PS2_DATA, cmd);
}
inline void sendToSecondDevice(std::uint8_t cmd) noexcept
@@ -401,11 +401,11 @@ inline void sendToSecondDevice(std::uint8_t cmd) noexcept
bool initialize() noexcept
{
// disable PS2
writePortByte(PORT_PS2_STATUS, PS2_CMD_DISABLE_FIRST);
writePortByte(PORT_PS2_STATUS, PS2_CMD_DISABLE_SECOND);
writePort8(PORT_PS2_STATUS, PS2_CMD_DISABLE_FIRST);
writePort8(PORT_PS2_STATUS, PS2_CMD_DISABLE_SECOND);
// flush output register
readPortByte(PORT_PS2_DATA);
readPort8(PORT_PS2_DATA);
// read configuration
std::uint8_t config = cmdWithResponse(PS2_CMD_READ_CONF_BYTE);
@@ -432,11 +432,11 @@ bool initialize() noexcept
bool dualChannel = false;
if ((config & PS2_CONFIGFLAG_CLOCK_SECOND) != 0) // it may be
{
writePortByte(PORT_PS2_STATUS, PS2_CMD_ENABLE_SECOND);
writePort8(PORT_PS2_STATUS, PS2_CMD_ENABLE_SECOND);
dualChannel = (cmdWithResponse(PS2_CMD_READ_CONF_BYTE) & PS2_CONFIGFLAG_CLOCK_SECOND) == 0;
if (dualChannel)
{
writePortByte(PORT_PS2_STATUS, PS2_CMD_DISABLE_SECOND);
writePort8(PORT_PS2_STATUS, PS2_CMD_DISABLE_SECOND);
}
}
@@ -451,9 +451,9 @@ bool initialize() noexcept
}
// enable devices
writePortByte(PORT_PS2_STATUS, PS2_CMD_ENABLE_FIRST);
writePort8(PORT_PS2_STATUS, PS2_CMD_ENABLE_FIRST);
if (dualChannel) {
writePortByte(PORT_PS2_STATUS, PS2_CMD_ENABLE_SECOND);
writePort8(PORT_PS2_STATUS, PS2_CMD_ENABLE_SECOND);
}
// enable interrupts
@@ -468,7 +468,7 @@ bool initialize() noexcept
bool firstOk = false;
while (waitForResponse(10))
{
const std::uint8_t response = readPortByte(PORT_PS2_DATA);
const std::uint8_t response = readPort8(PORT_PS2_DATA);
if (response == PS2_RESPONSE_SELFTEST_FAILED) {
return false;
}
@@ -483,7 +483,7 @@ bool initialize() noexcept
bool secondOk = false;
while (waitForResponse(10))
{
const std::uint8_t response = readPortByte(PORT_PS2_DATA);
const std::uint8_t response = readPort8(PORT_PS2_DATA);
if (response == PS2_RESPONSE_SELFTEST_FAILED) {
return false;
}
@@ -501,7 +501,7 @@ __attribute__((interrupt))
void isrKeyboard(InterruptFrame* interruptFrame) noexcept
{
(void) interruptFrame;
const std::uint8_t data = readPortByte(PORT_PS2_DATA);
const std::uint8_t data = readPort8(PORT_PS2_DATA);
if (data != 0)
{
pushKey(data);

View File

@@ -17,9 +17,9 @@ struct InterruptPrinter
void putchar(char chr) noexcept // NOLINT
{
if (chr == '\n') {
writePortByte(PORT_COM1, '\r');
writePort8(PORT_COM1, '\r');
}
writePortByte(PORT_COM1, static_cast<std::uint8_t>(chr));
writePort8(PORT_COM1, static_cast<std::uint8_t>(chr));
}
};

View File

@@ -17,21 +17,10 @@ size_t gTerminalColumn = 0;
size_t gTerminalWidth = 0;
size_t gTerminalHeight = 0;
VgaDoubleColor gTerminalColor = VgaDoubleColor();
// uint16_t* gTerminalBuffer = reinterpret_cast<uint16_t*>(0xB8000);
std::vector<VgaCharacter> gTerminalBuffer;
psf::Font gTerminalFont;
std::string gReadBuffer;
constexpr uint8_t vgaEntryColor(VgaDoubleColor color)
{
return static_cast<uint8_t>(color.foreground) | static_cast<uint8_t>(color.background) << 4;
}
constexpr uint16_t vgaEntry(const unsigned char chr, const VgaDoubleColor color)
{
return static_cast<uint16_t>(chr) | static_cast<uint16_t>(vgaEntryColor(color) << 8);
}
void newline()
{
gTerminalColumn = 0;