forked from Bananymous/banan-os
Kernel: Implement MSI, MSI-X and interrupt reservation
This commit is contained in:
parent
56a29dc176
commit
c6130f33d7
|
@ -14,6 +14,9 @@ namespace Kernel
|
||||||
virtual void enable_irq(uint8_t) override;
|
virtual void enable_irq(uint8_t) override;
|
||||||
virtual bool is_in_service(uint8_t) override;
|
virtual bool is_in_service(uint8_t) override;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq) override;
|
||||||
|
virtual BAN::Optional<uint8_t> get_free_irq() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t read_from_local_apic(ptrdiff_t);
|
uint32_t read_from_local_apic(ptrdiff_t);
|
||||||
void write_to_local_apic(ptrdiff_t, uint32_t);
|
void write_to_local_apic(ptrdiff_t, uint32_t);
|
||||||
|
@ -54,6 +57,7 @@ namespace Kernel
|
||||||
Kernel::vaddr_t m_local_apic_vaddr = 0;
|
Kernel::vaddr_t m_local_apic_vaddr = 0;
|
||||||
BAN::Vector<IOAPIC> m_io_apics;
|
BAN::Vector<IOAPIC> m_io_apics;
|
||||||
uint8_t m_irq_overrides[0x100] {};
|
uint8_t m_irq_overrides[0x100] {};
|
||||||
|
uint8_t m_reserved_gsis[0x100 / 8] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/Errors.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define DISABLE_INTERRUPTS() asm volatile("cli")
|
#define DISABLE_INTERRUPTS() asm volatile("cli")
|
||||||
|
@ -37,6 +40,9 @@ namespace Kernel
|
||||||
static void initialize(bool force_pic);
|
static void initialize(bool force_pic);
|
||||||
static InterruptController& get();
|
static InterruptController& get();
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq) = 0;
|
||||||
|
virtual BAN::Optional<uint8_t> get_free_irq() = 0;
|
||||||
|
|
||||||
bool is_using_apic() const { return m_using_apic; }
|
bool is_using_apic() const { return m_using_apic; }
|
||||||
|
|
||||||
void enter_acpi_mode();
|
void enter_acpi_mode();
|
||||||
|
|
|
@ -79,7 +79,8 @@ namespace Kernel::PCI
|
||||||
uint16_t vendor_id() const { return m_vendor_id; }
|
uint16_t vendor_id() const { return m_vendor_id; }
|
||||||
uint16_t device_id() const { return m_device_id; }
|
uint16_t device_id() const { return m_device_id; }
|
||||||
|
|
||||||
BAN::ErrorOr<uint8_t> get_irq();
|
BAN::ErrorOr<void> reserve_irqs(uint8_t count);
|
||||||
|
uint8_t get_irq(uint8_t index);
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
|
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
|
||||||
|
|
||||||
|
@ -92,15 +93,15 @@ namespace Kernel::PCI
|
||||||
void enable_io_space();
|
void enable_io_space();
|
||||||
void disable_io_space();
|
void disable_io_space();
|
||||||
|
|
||||||
void enable_pin_interrupts();
|
|
||||||
void disable_pin_interrupts();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void enumerate_capabilites();
|
void enumerate_capabilites();
|
||||||
|
|
||||||
void set_command_bits(uint16_t mask);
|
void set_command_bits(uint16_t mask);
|
||||||
void unset_command_bits(uint16_t mask);
|
void unset_command_bits(uint16_t mask);
|
||||||
|
|
||||||
|
void enable_pin_interrupts();
|
||||||
|
void disable_pin_interrupts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uint8_t m_bus;
|
const uint8_t m_bus;
|
||||||
const uint8_t m_dev;
|
const uint8_t m_dev;
|
||||||
|
@ -114,6 +115,9 @@ namespace Kernel::PCI
|
||||||
uint16_t m_vendor_id;
|
uint16_t m_vendor_id;
|
||||||
uint16_t m_device_id;
|
uint16_t m_device_id;
|
||||||
|
|
||||||
|
uint32_t m_reserved_irqs { 0 };
|
||||||
|
uint8_t m_reserved_irq_count { 0 };
|
||||||
|
|
||||||
BAN::Optional<uint8_t> m_offset_msi;
|
BAN::Optional<uint8_t> m_offset_msi;
|
||||||
BAN::Optional<uint8_t> m_offset_msi_x;
|
BAN::Optional<uint8_t> m_offset_msi_x;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,12 +12,16 @@ namespace Kernel
|
||||||
virtual void enable_irq(uint8_t) override;
|
virtual void enable_irq(uint8_t) override;
|
||||||
virtual bool is_in_service(uint8_t) override;
|
virtual bool is_in_service(uint8_t) override;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq) override;
|
||||||
|
virtual BAN::Optional<uint8_t> get_free_irq() override;
|
||||||
|
|
||||||
static void remap();
|
static void remap();
|
||||||
static void mask_all();
|
static void mask_all();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static PIC* create();
|
static PIC* create();
|
||||||
friend class InterruptController;
|
friend class InterruptController;
|
||||||
|
uint16_t m_reserved_irqs { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,8 +223,16 @@ namespace Kernel
|
||||||
|
|
||||||
void APIC::enable_irq(uint8_t irq)
|
void APIC::enable_irq(uint8_t irq)
|
||||||
{
|
{
|
||||||
|
CriticalScope _;
|
||||||
|
|
||||||
uint32_t gsi = m_irq_overrides[irq];
|
uint32_t gsi = m_irq_overrides[irq];
|
||||||
|
|
||||||
|
{
|
||||||
|
int byte = gsi / 8;
|
||||||
|
int bit = gsi % 8;
|
||||||
|
ASSERT(m_reserved_gsis[byte] & (1 << bit));
|
||||||
|
}
|
||||||
|
|
||||||
IOAPIC* ioapic = nullptr;
|
IOAPIC* ioapic = nullptr;
|
||||||
for (IOAPIC& io : m_io_apics)
|
for (IOAPIC& io : m_io_apics)
|
||||||
{
|
{
|
||||||
|
@ -258,4 +266,67 @@ namespace Kernel
|
||||||
return isr & (1 << bit);
|
return isr & (1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> APIC::reserve_irq(uint8_t irq)
|
||||||
|
{
|
||||||
|
CriticalScope _;
|
||||||
|
|
||||||
|
uint32_t gsi = m_irq_overrides[irq];
|
||||||
|
|
||||||
|
IOAPIC* ioapic = nullptr;
|
||||||
|
for (IOAPIC& io : m_io_apics)
|
||||||
|
{
|
||||||
|
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
|
||||||
|
{
|
||||||
|
ioapic = &io;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ioapic)
|
||||||
|
{
|
||||||
|
dwarnln("Cannot enable irq {} for APIC", irq);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int byte = gsi / 8;
|
||||||
|
int bit = gsi % 8;
|
||||||
|
if (m_reserved_gsis[byte] & (1 << bit))
|
||||||
|
{
|
||||||
|
dwarnln("irq {} is already reserved", irq);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
m_reserved_gsis[byte] |= 1 << bit;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<uint8_t> APIC::get_free_irq()
|
||||||
|
{
|
||||||
|
CriticalScope _;
|
||||||
|
for (int irq = 0; irq <= 0xFF; irq++)
|
||||||
|
{
|
||||||
|
uint32_t gsi = m_irq_overrides[irq];
|
||||||
|
|
||||||
|
IOAPIC* ioapic = nullptr;
|
||||||
|
for (IOAPIC& io : m_io_apics)
|
||||||
|
{
|
||||||
|
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
|
||||||
|
{
|
||||||
|
ioapic = &io;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ioapic)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int byte = gsi / 8;
|
||||||
|
int bit = gsi % 8;
|
||||||
|
if (m_reserved_gsis[byte] & (1 << bit))
|
||||||
|
continue;
|
||||||
|
m_reserved_gsis[byte] |= 1 << bit;
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,6 +329,18 @@ namespace Kernel::Input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reserve IRQs
|
||||||
|
if (m_devices[0] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE0).is_error())
|
||||||
|
{
|
||||||
|
dwarnln("Could not reserve irq for PS/2 port 1");
|
||||||
|
m_devices[0].clear();
|
||||||
|
}
|
||||||
|
if (m_devices[1] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE1).is_error())
|
||||||
|
{
|
||||||
|
dwarnln("Could not reserve irq for PS/2 port 2");
|
||||||
|
m_devices[1].clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_devices[0] && !m_devices[1])
|
if (!m_devices[0] && !m_devices[1])
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/MMIO.h>
|
#include <kernel/MMIO.h>
|
||||||
|
@ -6,8 +7,6 @@
|
||||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||||
#include <kernel/Storage/ATA/ATAController.h>
|
#include <kernel/Storage/ATA/ATAController.h>
|
||||||
|
|
||||||
#include <lai/helpers/pci.h>
|
|
||||||
|
|
||||||
#define INVALID_VENDOR 0xFFFF
|
#define INVALID_VENDOR 0xFFFF
|
||||||
#define MULTI_FUNCTION 0x80
|
#define MULTI_FUNCTION 0x80
|
||||||
|
|
||||||
|
@ -25,13 +24,22 @@
|
||||||
#define PCI_CMD_BUS_MASTER (1 << 2)
|
#define PCI_CMD_BUS_MASTER (1 << 2)
|
||||||
#define PCI_CMD_INTERRUPT_DISABLE (1 << 10)
|
#define PCI_CMD_INTERRUPT_DISABLE (1 << 10)
|
||||||
|
|
||||||
#define DEBUG_PCI 1
|
#define DEBUG_PCI 0
|
||||||
|
|
||||||
namespace Kernel::PCI
|
namespace Kernel::PCI
|
||||||
{
|
{
|
||||||
|
|
||||||
static PCIManager* s_instance = nullptr;
|
static PCIManager* s_instance = nullptr;
|
||||||
|
|
||||||
|
struct MSIXEntry
|
||||||
|
{
|
||||||
|
uint32_t msg_addr_low;
|
||||||
|
uint32_t msg_addr_high;
|
||||||
|
uint32_t msg_data;
|
||||||
|
uint32_t vector_ctrl;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(MSIXEntry) == 16);
|
||||||
|
|
||||||
uint32_t PCIManager::read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
|
uint32_t PCIManager::read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
|
||||||
{
|
{
|
||||||
ASSERT(offset % 4 == 0);
|
ASSERT(offset % 4 == 0);
|
||||||
|
@ -421,38 +429,147 @@ namespace Kernel::PCI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<uint8_t> PCI::Device::get_irq()
|
BAN::ErrorOr<void> PCI::Device::reserve_irqs(uint8_t count)
|
||||||
{
|
{
|
||||||
|
if (m_offset_msi_x.has_value())
|
||||||
|
{
|
||||||
|
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
|
||||||
|
if (count > (msg_ctrl & 0x7FF) + 1)
|
||||||
|
{
|
||||||
|
dwarnln("MSI-X: could not allocate {} interrupts, only {} supported", count, (msg_ctrl & 0x7FF) + 1);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
msg_ctrl |= 1 << 15; // Enable
|
||||||
|
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
|
||||||
|
disable_pin_interrupts();
|
||||||
|
}
|
||||||
|
else if (m_offset_msi.has_value())
|
||||||
|
{
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
dwarnln("MSI: could not allocate {} interrupts, (currently) only {} supported", count, 1);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
|
||||||
|
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
|
||||||
|
msg_ctrl |= 1u << 0; // Enable
|
||||||
|
write_word(*m_offset_msi + 0x02, msg_ctrl);
|
||||||
|
disable_pin_interrupts();
|
||||||
|
}
|
||||||
|
else if (!InterruptController::get().is_using_apic())
|
||||||
|
{
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
dwarnln("PIC: could not allocate {} interrupts, (currently) only {} supported", count, 1);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
enable_pin_interrupts();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; m_reserved_irq_count < count; m_reserved_irq_count++)
|
||||||
|
{
|
||||||
|
auto irq = InterruptController::get().get_free_irq();
|
||||||
|
if (!irq.has_value())
|
||||||
|
{
|
||||||
|
dwarnln("Could not reserve interrupt for PCI {}:{}.{}", m_bus, m_dev, m_func);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(*irq < 32);
|
||||||
|
ASSERT(!(m_reserved_irqs & (1 << *irq)));
|
||||||
|
m_reserved_irqs |= 1 << *irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t msi_message_address()
|
||||||
|
{
|
||||||
|
return 0xFEE00000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t msi_message_data(uint8_t irq)
|
||||||
|
{
|
||||||
|
return (IRQ_VECTOR_BASE + irq) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PCI::Device::get_irq(uint8_t index)
|
||||||
|
{
|
||||||
|
ASSERT(m_offset_msi.has_value() || m_offset_msi_x.has_value() || !InterruptController::get().is_using_apic());
|
||||||
|
ASSERT(index < m_reserved_irq_count);
|
||||||
|
|
||||||
|
uint8_t count_found = 0;
|
||||||
|
uint8_t irq = 0xFF;
|
||||||
|
for (uint8_t i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
if (m_reserved_irqs & (1 << i))
|
||||||
|
count_found++;
|
||||||
|
if (count_found > index)
|
||||||
|
{
|
||||||
|
irq = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT(irq != 0xFF);
|
||||||
|
|
||||||
// Legacy PIC just uses the interrupt line field
|
// Legacy PIC just uses the interrupt line field
|
||||||
if (!InterruptController::get().is_using_apic())
|
if (!InterruptController::get().is_using_apic())
|
||||||
return read_byte(PCI_REG_IRQ_LINE);
|
|
||||||
|
|
||||||
// TODO: use MSI and MSI-X if supported
|
|
||||||
|
|
||||||
if (m_offset_msi.has_value())
|
|
||||||
{
|
{
|
||||||
|
write_byte(PCI_REG_IRQ_LINE, irq);
|
||||||
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_offset_msi_x.has_value())
|
if (m_offset_msi_x.has_value())
|
||||||
{
|
{
|
||||||
|
uint32_t dword0 = read_dword(*m_offset_msi_x);
|
||||||
|
ASSERT((dword0 & 0xFF) == 0x11);
|
||||||
|
|
||||||
|
uint32_t dword1 = read_dword(*m_offset_msi_x + 0x04);
|
||||||
|
uint32_t offset = dword1 & ~3u;
|
||||||
|
uint8_t bir = dword1 & 3u;
|
||||||
|
|
||||||
|
uint64_t msg_addr = msi_message_address();
|
||||||
|
uint32_t msg_data = msi_message_data(irq);
|
||||||
|
|
||||||
|
auto bar = MUST(allocate_bar_region(bir));
|
||||||
|
ASSERT(bar->type() == BarType::MEM);
|
||||||
|
auto& msi_x_entry = reinterpret_cast<volatile MSIXEntry*>(bar->vaddr() + offset)[index];
|
||||||
|
msi_x_entry.msg_addr_low = msg_addr & 0xFFFFFFFF;
|
||||||
|
msi_x_entry.msg_addr_high = msg_addr >> 32;;
|
||||||
|
msi_x_entry.msg_data = msg_data;
|
||||||
|
msi_x_entry.vector_ctrl = msi_x_entry.vector_ctrl & ~1u;
|
||||||
|
|
||||||
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t irq_pin = 1; irq_pin <= 4; irq_pin++)
|
if (m_offset_msi.has_value())
|
||||||
{
|
{
|
||||||
acpi_resource_t dest;
|
uint32_t dword0 = read_dword(*m_offset_msi);
|
||||||
auto err = lai_pci_route_pin(&dest, 0, m_bus, m_dev, m_func, irq_pin);
|
ASSERT((dword0 & 0xFF) == 0x05);
|
||||||
if (err != LAI_ERROR_NONE)
|
|
||||||
|
uint64_t msg_addr = msi_message_address();
|
||||||
|
uint32_t msg_data = msi_message_data(irq);
|
||||||
|
|
||||||
|
if (dword0 & (1 << 23))
|
||||||
{
|
{
|
||||||
dprintln("{}", lai_api_error_to_string(err));
|
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||||
continue;
|
write_dword(*m_offset_msi + 0x08, msg_addr >> 32);
|
||||||
|
write_word(*m_offset_msi + 0x12, msg_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||||
|
write_word(*m_offset_msi + 0x08, msg_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_byte(PCI_REG_IRQ_PIN, irq_pin);
|
return irq;
|
||||||
return dest.base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dwarnln("Could not allocate interrupt for PCI {}:{}.{}", m_bus, m_dev, m_func);
|
ASSERT_NOT_REACHED();
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCI::Device::set_command_bits(uint16_t mask)
|
void PCI::Device::set_command_bits(uint16_t mask)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <kernel/CriticalScope.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/PIC.h>
|
#include <kernel/PIC.h>
|
||||||
|
@ -70,6 +71,7 @@ namespace Kernel
|
||||||
|
|
||||||
void PIC::eoi(uint8_t irq)
|
void PIC::eoi(uint8_t irq)
|
||||||
{
|
{
|
||||||
|
ASSERT(!interrupts_enabled());
|
||||||
if (irq >= 8)
|
if (irq >= 8)
|
||||||
IO::outb(PIC2_CMD, PIC_EOI);
|
IO::outb(PIC2_CMD, PIC_EOI);
|
||||||
IO::outb(PIC1_CMD, PIC_EOI);
|
IO::outb(PIC1_CMD, PIC_EOI);
|
||||||
|
@ -77,6 +79,10 @@ namespace Kernel
|
||||||
|
|
||||||
void PIC::enable_irq(uint8_t irq)
|
void PIC::enable_irq(uint8_t irq)
|
||||||
{
|
{
|
||||||
|
CriticalScope _;
|
||||||
|
ASSERT(irq < 16);
|
||||||
|
ASSERT(m_reserved_irqs & (1 << irq));
|
||||||
|
|
||||||
uint16_t port = PIC1_DATA;
|
uint16_t port = PIC1_DATA;
|
||||||
if(irq >= 8)
|
if(irq >= 8)
|
||||||
{
|
{
|
||||||
|
@ -86,6 +92,37 @@ namespace Kernel
|
||||||
IO::outb(port, IO::inb(port) & ~(1 << irq));
|
IO::outb(port, IO::inb(port) & ~(1 << irq));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> PIC::reserve_irq(uint8_t irq)
|
||||||
|
{
|
||||||
|
if (irq >= 16)
|
||||||
|
{
|
||||||
|
dwarnln("PIC only supports 16 irqs");
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
CriticalScope _;
|
||||||
|
if (m_reserved_irqs & (1 << irq))
|
||||||
|
{
|
||||||
|
dwarnln("irq {} is already reserved", irq);
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
m_reserved_irqs |= 1 << irq;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<uint8_t> PIC::get_free_irq()
|
||||||
|
{
|
||||||
|
CriticalScope _;
|
||||||
|
for (int irq = 0; irq < 16; irq++)
|
||||||
|
{
|
||||||
|
if (m_reserved_irqs & (1 << irq))
|
||||||
|
continue;
|
||||||
|
m_reserved_irqs |= 1 << irq;
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool PIC::is_in_service(uint8_t irq)
|
bool PIC::is_in_service(uint8_t irq)
|
||||||
{
|
{
|
||||||
uint16_t port = PIC1_CMD;
|
uint16_t port = PIC1_CMD;
|
||||||
|
|
|
@ -25,8 +25,8 @@ namespace Kernel
|
||||||
|
|
||||||
// Enable interrupts and bus mastering
|
// Enable interrupts and bus mastering
|
||||||
m_pci_device.enable_bus_mastering();
|
m_pci_device.enable_bus_mastering();
|
||||||
m_pci_device.enable_pin_interrupts();
|
TRY(m_pci_device.reserve_irqs(1));
|
||||||
set_irq(TRY(m_pci_device.get_irq()));
|
set_irq(m_pci_device.get_irq(0));
|
||||||
enable_interrupt();
|
enable_interrupt();
|
||||||
abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE;
|
abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE;
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,6 @@ namespace Kernel
|
||||||
auto bus = BAN::RefPtr<ATABus>::adopt(bus_ptr);
|
auto bus = BAN::RefPtr<ATABus>::adopt(bus_ptr);
|
||||||
bus->set_irq(irq);
|
bus->set_irq(irq);
|
||||||
TRY(bus->initialize());
|
TRY(bus->initialize());
|
||||||
if (bus->m_devices.empty())
|
|
||||||
return BAN::Error::from_errno(ENODEV);
|
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ namespace Kernel
|
||||||
|
|
||||||
uint8_t prog_if = m_pci_device.read_byte(0x09);
|
uint8_t prog_if = m_pci_device.read_byte(0x09);
|
||||||
|
|
||||||
|
// FIXME: support native mode
|
||||||
|
|
||||||
if ((prog_if & ATA_PROGIF_CAN_MODIFY_PRIMARY_NATIVE) && (prog_if & ATA_PROGIF_PRIMARY_NATIVE))
|
if ((prog_if & ATA_PROGIF_CAN_MODIFY_PRIMARY_NATIVE) && (prog_if & ATA_PROGIF_PRIMARY_NATIVE))
|
||||||
{
|
{
|
||||||
prog_if &= ~ATA_PROGIF_PRIMARY_NATIVE;
|
prog_if &= ~ATA_PROGIF_PRIMARY_NATIVE;
|
||||||
|
@ -57,11 +59,16 @@ namespace Kernel
|
||||||
|
|
||||||
if (!(prog_if & ATA_PROGIF_PRIMARY_NATIVE))
|
if (!(prog_if & ATA_PROGIF_PRIMARY_NATIVE))
|
||||||
{
|
{
|
||||||
auto bus_or_error = ATABus::create(0x1F0, 0x3F6, 14);
|
if (InterruptController::get().reserve_irq(14).is_error())
|
||||||
if (bus_or_error.is_error())
|
dwarnln("Could not reserve interrupt {} for ATA device", 14);
|
||||||
dprintln("IDE ATABus: {}", bus_or_error.error());
|
|
||||||
else
|
else
|
||||||
TRY(buses.push_back(bus_or_error.release_value()));
|
{
|
||||||
|
auto bus_or_error = ATABus::create(0x1F0, 0x3F6, 14);
|
||||||
|
if (bus_or_error.is_error())
|
||||||
|
dprintln("IDE ATABus: {}", bus_or_error.error());
|
||||||
|
else
|
||||||
|
TRY(buses.push_back(bus_or_error.release_value()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -70,11 +77,16 @@ namespace Kernel
|
||||||
|
|
||||||
if (!(prog_if & ATA_PROGIF_SECONDARY_NATIVE))
|
if (!(prog_if & ATA_PROGIF_SECONDARY_NATIVE))
|
||||||
{
|
{
|
||||||
auto bus_or_error = ATABus::create(0x170, 0x376, 15);
|
if (InterruptController::get().reserve_irq(15).is_error())
|
||||||
if (bus_or_error.is_error())
|
dwarnln("Could not reserver interrupt {} for ATA device", 15);
|
||||||
dprintln("IDE ATABus: {}", bus_or_error.error());
|
|
||||||
else
|
else
|
||||||
TRY(buses.push_back(bus_or_error.release_value()));
|
{
|
||||||
|
auto bus_or_error = ATABus::create(0x170, 0x376, 15);
|
||||||
|
if (bus_or_error.is_error())
|
||||||
|
dprintln("IDE ATABus: {}", bus_or_error.error());
|
||||||
|
else
|
||||||
|
TRY(buses.push_back(bus_or_error.release_value()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -195,12 +195,14 @@ namespace Kernel
|
||||||
if (serial.port() == COM1_PORT)
|
if (serial.port() == COM1_PORT)
|
||||||
{
|
{
|
||||||
IO::outb(COM1_PORT + 1, 1);
|
IO::outb(COM1_PORT + 1, 1);
|
||||||
|
TRY(InterruptController::get().reserve_irq(COM1_IRQ));
|
||||||
tty->set_irq(COM1_IRQ);
|
tty->set_irq(COM1_IRQ);
|
||||||
tty->enable_interrupt();
|
tty->enable_interrupt();
|
||||||
}
|
}
|
||||||
else if (serial.port() == COM2_PORT)
|
else if (serial.port() == COM2_PORT)
|
||||||
{
|
{
|
||||||
IO::outb(COM2_PORT + 1, 1);
|
IO::outb(COM2_PORT + 1, 1);
|
||||||
|
TRY(InterruptController::get().reserve_irq(COM2_IRQ));
|
||||||
tty->set_irq(COM2_IRQ);
|
tty->set_irq(COM2_IRQ);
|
||||||
tty->enable_interrupt();
|
tty->enable_interrupt();
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@ namespace Kernel
|
||||||
if (irq_cap & (1 << irq))
|
if (irq_cap & (1 << irq))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
TRY(InterruptController::get().reserve_irq(irq));
|
||||||
|
|
||||||
unmapper.disable();
|
unmapper.disable();
|
||||||
|
|
||||||
|
|
|
@ -182,17 +182,19 @@ static void init2(void*)
|
||||||
SystemTimer::get().sleep(5000);
|
SystemTimer::get().sleep(5000);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Initialize empty keymap
|
||||||
|
MUST(Input::KeyboardLayout::initialize());
|
||||||
|
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||||
|
dprintln("{}", res.error());
|
||||||
|
|
||||||
|
// NOTE: PCI devices are the last ones to be initialized
|
||||||
|
// so other devices can reserve predefined interrupts
|
||||||
PCI::PCIManager::initialize();
|
PCI::PCIManager::initialize();
|
||||||
dprintln("PCI initialized");
|
dprintln("PCI initialized");
|
||||||
|
|
||||||
VirtualFileSystem::initialize(cmdline.root);
|
VirtualFileSystem::initialize(cmdline.root);
|
||||||
dprintln("VFS initialized");
|
dprintln("VFS initialized");
|
||||||
|
|
||||||
// Initialize empty keymap
|
|
||||||
MUST(Input::KeyboardLayout::initialize());
|
|
||||||
if (auto res = PS2Controller::initialize(); res.is_error())
|
|
||||||
dprintln("{}", res.error());
|
|
||||||
|
|
||||||
TTY::initialize_devices();
|
TTY::initialize_devices();
|
||||||
|
|
||||||
MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"sv));
|
MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"sv));
|
||||||
|
|
Loading…
Reference in New Issue