feat: implement PCI subsystem and integrate uACPI support
See previous commit Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user