feat: implement PCI subsystem and integrate uACPI support

See previous commit

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-04-15 13:33:18 -04:00
parent 840210ddc0
commit cc8351bf8d
15 changed files with 785 additions and 68 deletions
-1
View File
@@ -1,7 +1,6 @@
#include "pic.h"
#include "io.h"
#include <stdbool.h>
#include <stdint.h>
#define PIC1_COMMAND_PORT 0x20
#define PIC1_DATA_PORT 0x21
+2 -1
View File
@@ -51,12 +51,13 @@ void x86_64_IRQ_Initialize(void)
log_info(MODULE, "Found %s PIC.", g_Driver->Name);
g_Driver->Initialize(PIC_REMAP_OFFSET, PIC_REMAP_OFFSET + 8, false);
// register ISR handlers for each of the 16 irq lines
for (int i = 0; i < 16; i++)
x86_64_ISR_RegisterHandler(PIC_REMAP_OFFSET + i, x86_64_IRQ_Handler);
x86_64_EnableInterrupts();
g_Driver->Unmask(0);
}
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler)
+137
View File
@@ -0,0 +1,137 @@
#include "pci.h"
#include "arch/x86_64/io.h"
#include <stdio.h>
#define PCI_CFG_ADDR 0x0CF8
#define PCI_CFG_DATA 0x0CFC
static uint32_t pci_pack_addr(pci_address_t addr, uint16_t offset)
{
return (1u << 31) |
((uint32_t)addr.bus << 16) |
((uint32_t)addr.device << 11) |
((uint32_t)addr.function << 8) |
(offset & 0xFCu);
}
uint8_t pci_read8(pci_address_t addr, uint16_t offset)
{
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
return (uint8_t)(x86_64_inl(PCI_CFG_DATA) >> ((offset & 3) * 8));
}
uint16_t pci_read16(pci_address_t addr, uint16_t offset)
{
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
return (uint16_t)(x86_64_inl(PCI_CFG_DATA) >> ((offset & 2) * 8));
}
uint32_t pci_read32(pci_address_t addr, uint16_t offset)
{
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
return x86_64_inl(PCI_CFG_DATA);
}
void pci_write8(pci_address_t addr, uint16_t offset, uint8_t val)
{
uint32_t tmp = pci_read32(addr, offset & ~3u);
uint8_t shift = (offset & 3) * 8;
tmp = (tmp & ~(0xFFu << shift)) | ((uint32_t)val << shift);
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
x86_64_outl(PCI_CFG_DATA, tmp);
}
void pci_write16(pci_address_t addr, uint16_t offset, uint16_t val)
{
uint32_t tmp = pci_read32(addr, offset & ~3u);
uint8_t shift = (offset & 2) * 8;
tmp = (tmp & ~(0xFFFFu << shift)) | ((uint32_t)val << shift);
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
x86_64_outl(PCI_CFG_DATA, tmp);
}
void pci_write32(pci_address_t addr, uint16_t offset, uint32_t val)
{
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
x86_64_outl(PCI_CFG_DATA, val);
}
static void pci_read_bars(pci_device_t* dev)
{
for (int i = 0; i < 6; i++) {
uint16_t off = 0x10 + i * 4;
dev->bar[i] = pci_read32(dev->addr, off);
// If it's a 64-bit BAR we skip the next one (simple version)
if ((dev->bar[i] & 0x7) == 0x4)
i++;
}
}
void pci_init(void)
{
printf("[PCI] Scanning bus 0...\n");
pci_print_all();
}
void pci_print_all(void)
{
for (uint8_t bus = 0; bus < 1; bus++) { // start with bus 0 only
for (uint8_t dev = 0; dev < 32; dev++) {
for (uint8_t func = 0; func < 8; func++) {
pci_address_t addr = {bus, dev, func};
uint16_t vendor = pci_read16(addr, 0x00);
if (vendor == 0xFFFF) {
if (func == 0) break; // no device
continue;
}
uint16_t device_id = pci_read16(addr, 0x02);
uint16_t class_sub = pci_read16(addr, 0x0A);
uint8_t prog_if = pci_read8 (addr, 0x09);
uint8_t revision = pci_read8 (addr, 0x08);
pci_device_t d = {
.addr = addr,
.vendor_id = vendor,
.device_id = device_id,
.class_code = class_sub,
.prog_if = prog_if,
.revision = revision,
};
pci_read_bars(&d);
printf("[PCI] %02x:%02x.%x %04x:%04x class %04x rev %02x\n",
bus, dev, func, vendor, device_id, class_sub, revision);
if (func == 0 && (pci_read8(addr, 0x0E) & 0x80) == 0)
break; // not multifunction
}
}
}
}
bool pci_find_hda(pci_device_t* out_dev)
{
// Same scan as above, but stop at first HDA device
for (uint8_t bus = 0; bus < 1; bus++) {
for (uint8_t dev = 0; dev < 32; dev++) {
for (uint8_t func = 0; func < 8; func++) {
pci_address_t addr = {bus, dev, func};
uint16_t vendor = pci_read16(addr, 0x00);
if (vendor == 0xFFFF) continue;
uint16_t class_sub = pci_read16(addr, 0x0A);
if (class_sub == (PCI_CLASS_AUDIO << 8) | PCI_SUBCLASS_HDA) {
out_dev->addr = addr;
out_dev->vendor_id = vendor;
out_dev->device_id = pci_read16(addr, 0x02);
out_dev->class_code = class_sub;
pci_read_bars(out_dev);
return true;
}
}
}
}
return false;
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint8_t bus;
uint8_t device;
uint8_t function;
} pci_address_t;
typedef struct {
pci_address_t addr;
uint16_t vendor_id;
uint16_t device_id;
uint16_t class_code; // (class << 8) | subclass
uint8_t prog_if;
uint8_t revision;
uint32_t bar[6];
bool is_multifunction;
} pci_device_t;
#define PCI_CLASS_AUDIO 0x04
#define PCI_SUBCLASS_HDA 0x03
// Read/write config space (re-uses your existing uACPI PCI code)
uint8_t pci_read8 (pci_address_t addr, uint16_t offset);
uint16_t pci_read16(pci_address_t addr, uint16_t offset);
uint32_t pci_read32(pci_address_t addr, uint16_t offset);
void pci_write8 (pci_address_t addr, uint16_t offset, uint8_t val);
void pci_write16(pci_address_t addr, uint16_t offset, uint16_t val);
void pci_write32(pci_address_t addr, uint16_t offset, uint32_t val);
// Scan and print all PCI devices
void pci_init(void);
void pci_print_all(void);
// Find first HDA controller (returns true if found)
bool pci_find_hda(pci_device_t* out_dev);
+69
View File
@@ -0,0 +1,69 @@
#include "pit.h"
#include "irq.h"
#include "io.h"
#include <stdint.h>
#include "stdio.h"
#include "e9.h"
#include "limine.h"
__attribute__((used, section(".limine_requests")))
volatile struct limine_date_at_boot_request boot_request = {
.id = LIMINE_DATE_AT_BOOT_REQUEST_ID,
.revision = 6,
};
#define PIT_BASE_FREQUENCY 1193182
#define PIT_COMMAND_PORT 0x43
#define PIT_CHANNEL0_PORT 0x40
volatile uint64_t g_Ticks = 0;
volatile uint64_t ticks = 0;
uint64_t g_Unixseconds = 0;
/* ========================= */
/* IRQ0 Handler (Timer Tick) */
/* ========================= */
void PIT_IRQ_Handler(Registers* regs)
{
(void)regs;
g_Ticks++;
ticks++;
if (ticks >= 1000) {
g_Unixseconds++;
ticks = 0;
}
// You can add scheduler / time logic here later
}
/* ========================= */
/* Initialize PIT */
/* ========================= */
void x86_64_PIT_Initialize(uint32_t frequency)
{
uint16_t divisor = (uint16_t)(PIT_BASE_FREQUENCY / frequency);
printf("PIT divisor = %u\n", divisor);
// Send command byte:
// Channel 0 | lobyte/hibyte | mode 3 (square wave) | binary
x86_64_outb(PIT_COMMAND_PORT, 0x36);
// Send divisor (low byte then high byte)
x86_64_outb(PIT_CHANNEL0_PORT, divisor & 0xFF);
x86_64_outb(PIT_CHANNEL0_PORT, (divisor >> 8) & 0xFF);
g_Unixseconds = boot_request.response->timestamp;
// Register IRQ0 handler (IRQ0 = timer)
x86_64_IRQ_RegisterHandler(0, PIT_IRQ_Handler);
}
/* ========================= */
/* Get tick count */
/* ========================= */
uint64_t PIT_GetTicks(void)
{
return g_Ticks;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
#include "irq.h"
#include "io.h"
#include <stdint.h>
#include "stdio.h"
#include "e9.h"
extern volatile uint64_t g_Ticks;
extern uint64_t g_Unixseconds;
void x86_64_PIT_Initialize(uint32_t frequency);
uint64_t PIT_GetTicks(void);
void PIT_IRQ_Handler(Registers* regs);