Skip to content

Commit

Permalink
Kernel/PCI: Simplify the entire subsystem
Browse files Browse the repository at this point in the history
A couple of things were changed:
1. Semantic changes - PCI segments are now called PCI domains, to better
match what they are really. It's also the name that Linux gave, and it
seems that Wikipedia also uses this name.
We also remove PCI::ChangeableAddress, because it was used in the past
but now it's no longer being used.
2. There are no WindowedMMIOAccess or MMIOAccess classes anymore, as
they made a bunch of unnecessary complexity. Instead, Windowed access is
removed entirely (this was tested, but never was benchmarked), so we are
left with IO access and memory access options. The memory access option
is essentially mapping the PCI bus (from the chosen PCI domain), to
virtual memory as-is. This means that unless needed, at any time, there
is only one PCI bus being mapped, and this is changed if access to
another PCI bus in the same PCI domain is needed. For now, we don't
support mapping of different PCI buses from different PCI domains at the
same time, because basically it's still a non-issue for most machines
out there.
2. OOM-safety is increased, especially when constructing the Access
object. It means that we pre-allocating any needed resources, and we try
to find PCI domains (if requested to initialize memory access) after we
attempt to construct the Access object, so it's possible to fail at this
point "gracefully".
3. All PCI API functions are now separated into a different header file,
which means only "clients" of the PCI subsystem API will need to include
that header file.
4. Functional changes - we only allow now to enumerate the bus after
a hardware scan. This means that the old method "enumerate_hardware"
is removed, so, when initializing an Access object, the initializing
function must call rescan on it to force it to find devices. This makes
it possible to fail rescan, and also to defer it after construction from
both OOM-safety terms and hotplug capabilities.
  • Loading branch information
supercomputer7 authored and awesomekling committed Sep 7, 2021
1 parent d137833 commit 25ea746
Show file tree
Hide file tree
Showing 39 changed files with 871 additions and 1,086 deletions.
2 changes: 1 addition & 1 deletion Kernel/ACPI/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <Kernel/ACPI/Parser.h>
#include <Kernel/Arch/PC/BIOS.h>
#include <Kernel/Arch/x86/InterruptDisabler.h>
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Debug.h>
#include <Kernel/IO.h>
#include <Kernel/Memory/TypedMapping.h>
Expand Down
231 changes: 231 additions & 0 deletions Kernel/Bus/PCI/API.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
/*
* Copyright (c) 2021, Liav A. <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/Sections.h>

namespace Kernel::PCI {

void write8(Address address, u32 field, u8 value) { Access::the().write8_field(address, field, value); }
void write16(Address address, u32 field, u16 value) { Access::the().write16_field(address, field, value); }
void write32(Address address, u32 field, u32 value) { Access::the().write32_field(address, field, value); }
u8 read8(Address address, u32 field) { return Access::the().read8_field(address, field); }
u16 read16(Address address, u32 field) { return Access::the().read16_field(address, field); }
u32 read32(Address address, u32 field) { return Access::the().read32_field(address, field); }

void enumerate(Function<void(Address, ID)> callback)
{
Access::the().fast_enumerate(callback);
}

PhysicalID get_physical_id(Address address)
{
return Access::the().get_physical_id(address);
}

ID get_id(Address address)
{
return { read16(address, PCI_VENDOR_ID), read16(address, PCI_DEVICE_ID) };
}

void enable_io_space(Address address)
{
write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) | (1 << 0));
}
void disable_io_space(Address address)
{
write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) & ~(1 << 0));
}

void enable_memory_space(Address address)
{
write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) | (1 << 1));
}
void disable_memory_space(Address address)
{
write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) & ~(1 << 1));
}
bool is_io_space_enabled(Address address)
{
return (read16(address, PCI_COMMAND) & 1) != 0;
}

void enable_interrupt_line(Address address)
{
write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) & ~(1 << 10));
}

void disable_interrupt_line(Address address)
{
write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) | 1 << 10);
}

u8 get_interrupt_line(Address address)
{
return read8(address, PCI_INTERRUPT_LINE);
}

u32 get_BAR0(Address address)
{
return read32(address, PCI_BAR0);
}

u32 get_BAR1(Address address)
{
return read32(address, PCI_BAR1);
}

u32 get_BAR2(Address address)
{
return read32(address, PCI_BAR2);
}

u32 get_BAR3(Address address)
{
return read16(address, PCI_BAR3);
}

u32 get_BAR4(Address address)
{
return read32(address, PCI_BAR4);
}

u32 get_BAR5(Address address)
{
return read32(address, PCI_BAR5);
}

u32 get_BAR(Address address, u8 bar)
{
VERIFY(bar <= 5);
switch (bar) {
case 0:
return get_BAR0(address);
case 1:
return get_BAR1(address);
case 2:
return get_BAR2(address);
case 3:
return get_BAR3(address);
case 4:
return get_BAR4(address);
case 5:
return get_BAR5(address);
default:
VERIFY_NOT_REACHED();
}
}

u8 get_revision_id(Address address)
{
return read8(address, PCI_REVISION_ID);
}

u8 get_subclass(Address address)
{
return read8(address, PCI_SUBCLASS);
}

u8 get_class(Address address)
{
return read8(address, PCI_CLASS);
}

u8 get_programming_interface(Address address)
{
return read8(address, PCI_PROG_IF);
}

u16 get_subsystem_id(Address address)
{
return read16(address, PCI_SUBSYSTEM_ID);
}

u16 get_subsystem_vendor_id(Address address)
{
return read16(address, PCI_SUBSYSTEM_VENDOR_ID);
}

void enable_bus_mastering(Address address)
{
auto value = read16(address, PCI_COMMAND);
value |= (1 << 2);
value |= (1 << 0);
write16(address, PCI_COMMAND, value);
}

void disable_bus_mastering(Address address)
{
auto value = read16(address, PCI_COMMAND);
value &= ~(1 << 2);
value |= (1 << 0);
write16(address, PCI_COMMAND, value);
}

size_t get_BAR_space_size(Address address, u8 bar_number)
{
// See PCI Spec 2.3, Page 222
VERIFY(bar_number < 6);
u8 field = (PCI_BAR0 + (bar_number << 2));
u32 bar_reserved = read32(address, field);
write32(address, field, 0xFFFFFFFF);
u32 space_size = read32(address, field);
write32(address, field, bar_reserved);
space_size &= 0xfffffff0;
space_size = (~space_size) + 1;
return space_size;
}

void raw_access(Address address, u32 field, size_t access_size, u32 value)
{
VERIFY(access_size != 0);
if (access_size == 1) {
write8(address, field, value);
return;
}
if (access_size == 2) {
write16(address, field, value);
return;
}
if (access_size == 4) {
write32(address, field, value);
return;
}
VERIFY_NOT_REACHED();
}

u8 Capability::read8(u32 field) const
{
return PCI::read8(m_address, m_ptr + field);
}

u16 Capability::read16(u32 field) const
{
return PCI::read16(m_address, m_ptr + field);
}

u32 Capability::read32(u32 field) const
{
return PCI::read32(m_address, m_ptr + field);
}

void Capability::write8(u32 field, u8 value)
{
PCI::write8(m_address, m_ptr + field, value);
}

void Capability::write16(u32 field, u16 value)
{
PCI::write16(m_address, m_ptr + field, value);
}

void Capability::write32(u32 field, u32 value)
{
PCI::write32(m_address, m_ptr + field, value);
}

}
49 changes: 49 additions & 0 deletions Kernel/Bus/PCI/API.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2021, Liav A. <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <Kernel/Bus/PCI/Definitions.h>

namespace Kernel::PCI {

void write8(Address address, u32 field, u8 value);
void write16(Address address, u32 field, u16 value);
void write32(Address address, u32 field, u32 value);
u8 read8(Address address, u32 field);
u16 read16(Address address, u32 field);
u32 read32(Address address, u32 field);

ID get_id(PCI::Address);
bool is_io_space_enabled(Address);
void enumerate(Function<void(Address, ID)> callback);
void enable_interrupt_line(Address);
void disable_interrupt_line(Address);
u8 get_interrupt_line(Address);
void raw_access(Address, u32, size_t, u32);
u32 get_BAR0(Address);
u32 get_BAR1(Address);
u32 get_BAR2(Address);
u32 get_BAR3(Address);
u32 get_BAR4(Address);
u32 get_BAR5(Address);
u32 get_BAR(Address address, u8 bar);
u8 get_revision_id(Address);
u8 get_programming_interface(Address);
u8 get_subclass(Address);
u8 get_class(Address);
u16 get_subsystem_id(Address);
u16 get_subsystem_vendor_id(Address);
size_t get_BAR_space_size(Address, u8);
void enable_bus_mastering(Address);
void disable_bus_mastering(Address);
void enable_io_space(Address);
void disable_io_space(Address);
void enable_memory_space(Address);
void disable_memory_space(Address);
PhysicalID get_physical_id(Address address);

}
Loading

0 comments on commit 25ea746

Please sign in to comment.