mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 18:57:36 +00:00
Kernel: Reorganize Arch/x86 directory to Arch/x86_64 after i686 removal
No functional change.
This commit is contained in:
parent
5ff318cf3a
commit
91db482ad3
129 changed files with 482 additions and 1116 deletions
62
Kernel/Arch/x86_64/PCI/Controller/HostBridge.cpp
Normal file
62
Kernel/Arch/x86_64/PCI/Controller/HostBridge.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/PCI/Controller/HostBridge.h>
|
||||
#include <Kernel/Bus/PCI/Access.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel::PCI {
|
||||
|
||||
NonnullOwnPtr<HostBridge> HostBridge::must_create_with_io_access()
|
||||
{
|
||||
PCI::Domain domain { 0, 0, 0xff };
|
||||
return adopt_own_if_nonnull(new (nothrow) HostBridge(domain)).release_nonnull();
|
||||
}
|
||||
|
||||
HostBridge::HostBridge(PCI::Domain const& domain)
|
||||
: HostController(domain)
|
||||
{
|
||||
}
|
||||
|
||||
static u32 io_address_for_pci_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u8 field)
|
||||
{
|
||||
return 0x80000000u | (bus.value() << 16u) | (device.value() << 11u) | (function.value() << 8u) | (field & 0xfc);
|
||||
}
|
||||
|
||||
void HostBridge::write8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u8 value)
|
||||
{
|
||||
IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field));
|
||||
IO::out8(PCI::value_port + (field & 3), value);
|
||||
}
|
||||
void HostBridge::write16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u16 value)
|
||||
{
|
||||
IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field));
|
||||
IO::out16(PCI::value_port + (field & 2), value);
|
||||
}
|
||||
void HostBridge::write32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u32 value)
|
||||
{
|
||||
IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field));
|
||||
IO::out32(PCI::value_port, value);
|
||||
}
|
||||
|
||||
u8 HostBridge::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field)
|
||||
{
|
||||
IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field));
|
||||
return IO::in8(PCI::value_port + (field & 3));
|
||||
}
|
||||
u16 HostBridge::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field)
|
||||
{
|
||||
IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field));
|
||||
return IO::in16(PCI::value_port + (field & 2));
|
||||
}
|
||||
u32 HostBridge::read32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field)
|
||||
{
|
||||
IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field));
|
||||
return IO::in32(PCI::value_port);
|
||||
}
|
||||
|
||||
}
|
34
Kernel/Arch/x86_64/PCI/Controller/HostBridge.h
Normal file
34
Kernel/Arch/x86_64/PCI/Controller/HostBridge.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Bitmap.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <Kernel/Bus/PCI/Controller/HostController.h>
|
||||
#include <Kernel/Locking/Spinlock.h>
|
||||
|
||||
namespace Kernel::PCI {
|
||||
|
||||
class HostBridge : public HostController {
|
||||
public:
|
||||
static NonnullOwnPtr<HostBridge> must_create_with_io_access();
|
||||
|
||||
virtual void write8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value) override;
|
||||
virtual void write16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value) override;
|
||||
virtual void write32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value) override;
|
||||
|
||||
virtual u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||
virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||
virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||
|
||||
private:
|
||||
explicit HostBridge(PCI::Domain const&);
|
||||
};
|
||||
|
||||
}
|
168
Kernel/Arch/x86_64/PCI/IDELegacyModeController.cpp
Normal file
168
Kernel/Arch/x86_64/PCI/IDELegacyModeController.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86_64/PCI/IDELegacyModeController.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Library/LockRefPtr.h>
|
||||
#include <Kernel/Sections.h>
|
||||
#include <Kernel/Storage/ATA/ATADiskDevice.h>
|
||||
#include <Kernel/Storage/ATA/GenericIDE/Channel.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
UNMAP_AFTER_INIT NonnullLockRefPtr<PCIIDELegacyModeController> PCIIDELegacyModeController::initialize(PCI::DeviceIdentifier const& device_identifier, bool force_pio)
|
||||
{
|
||||
return adopt_lock_ref(*new PCIIDELegacyModeController(device_identifier, force_pio));
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT PCIIDELegacyModeController::PCIIDELegacyModeController(PCI::DeviceIdentifier const& device_identifier, bool force_pio)
|
||||
: PCI::Device(device_identifier.address())
|
||||
, m_prog_if(device_identifier.prog_if())
|
||||
, m_interrupt_line(device_identifier.interrupt_line())
|
||||
{
|
||||
PCI::enable_io_space(device_identifier.address());
|
||||
PCI::enable_memory_space(device_identifier.address());
|
||||
PCI::enable_bus_mastering(device_identifier.address());
|
||||
enable_pin_based_interrupts();
|
||||
initialize(force_pio);
|
||||
}
|
||||
|
||||
bool PCIIDELegacyModeController::is_pci_native_mode_enabled() const
|
||||
{
|
||||
return (m_prog_if.value() & 0x05) != 0;
|
||||
}
|
||||
|
||||
bool PCIIDELegacyModeController::is_pci_native_mode_enabled_on_primary_channel() const
|
||||
{
|
||||
return (m_prog_if.value() & 0x1) == 0x1;
|
||||
}
|
||||
|
||||
bool PCIIDELegacyModeController::is_pci_native_mode_enabled_on_secondary_channel() const
|
||||
{
|
||||
return (m_prog_if.value() & 0x4) == 0x4;
|
||||
}
|
||||
|
||||
bool PCIIDELegacyModeController::is_bus_master_capable() const
|
||||
{
|
||||
return m_prog_if.value() & (1 << 7);
|
||||
}
|
||||
|
||||
static char const* detect_controller_type(u8 programming_value)
|
||||
{
|
||||
switch (programming_value) {
|
||||
case 0x00:
|
||||
return "ISA Compatibility mode-only controller";
|
||||
case 0x05:
|
||||
return "PCI native mode-only controller";
|
||||
case 0x0A:
|
||||
return "ISA Compatibility mode controller, supports both channels switched to PCI native mode";
|
||||
case 0x0F:
|
||||
return "PCI native mode controller, supports both channels switched to ISA compatibility mode";
|
||||
case 0x80:
|
||||
return "ISA Compatibility mode-only controller, supports bus mastering";
|
||||
case 0x85:
|
||||
return "PCI native mode-only controller, supports bus mastering";
|
||||
case 0x8A:
|
||||
return "ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering";
|
||||
case 0x8F:
|
||||
return "PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering";
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void PCIIDELegacyModeController::initialize(bool force_pio)
|
||||
{
|
||||
dbgln("IDE controller @ {}: interrupt line was set to {}", pci_address(), m_interrupt_line.value());
|
||||
dbgln("IDE controller @ {}: {}", pci_address(), detect_controller_type(m_prog_if.value()));
|
||||
{
|
||||
auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1));
|
||||
dbgln("IDE controller @ {}: bus master base was set to {}", pci_address(), bus_master_base);
|
||||
}
|
||||
|
||||
auto initialize_and_enumerate = [&force_pio](IDEChannel& channel) -> void {
|
||||
{
|
||||
auto result = channel.allocate_resources_for_pci_ide_controller({}, force_pio);
|
||||
// FIXME: Propagate errors properly
|
||||
VERIFY(!result.is_error());
|
||||
}
|
||||
{
|
||||
auto result = channel.detect_connected_devices();
|
||||
// FIXME: Propagate errors properly
|
||||
VERIFY(!result.is_error());
|
||||
}
|
||||
};
|
||||
|
||||
if (!is_bus_master_capable())
|
||||
force_pio = true;
|
||||
|
||||
OwnPtr<IOWindow> primary_base_io_window;
|
||||
OwnPtr<IOWindow> primary_control_io_window;
|
||||
if (!is_pci_native_mode_enabled_on_primary_channel()) {
|
||||
primary_base_io_window = IOWindow::create_for_io_space(IOAddress(0x1F0), 8).release_value_but_fixme_should_propagate_errors();
|
||||
primary_control_io_window = IOWindow::create_for_io_space(IOAddress(0x3F6), 4).release_value_but_fixme_should_propagate_errors();
|
||||
} else {
|
||||
auto primary_base_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR0).release_value_but_fixme_should_propagate_errors();
|
||||
auto pci_primary_control_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR1).release_value_but_fixme_should_propagate_errors();
|
||||
// Note: the PCI IDE specification says we should access the IO address with an offset of 2
|
||||
// on native PCI IDE controllers.
|
||||
primary_control_io_window = pci_primary_control_io_window->create_from_io_window_with_offset(2, 4).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
VERIFY(primary_base_io_window);
|
||||
VERIFY(primary_control_io_window);
|
||||
|
||||
OwnPtr<IOWindow> secondary_base_io_window;
|
||||
OwnPtr<IOWindow> secondary_control_io_window;
|
||||
|
||||
if (!is_pci_native_mode_enabled_on_primary_channel()) {
|
||||
secondary_base_io_window = IOWindow::create_for_io_space(IOAddress(0x170), 8).release_value_but_fixme_should_propagate_errors();
|
||||
secondary_control_io_window = IOWindow::create_for_io_space(IOAddress(0x376), 4).release_value_but_fixme_should_propagate_errors();
|
||||
} else {
|
||||
secondary_base_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR2).release_value_but_fixme_should_propagate_errors();
|
||||
auto pci_secondary_control_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR3).release_value_but_fixme_should_propagate_errors();
|
||||
// Note: the PCI IDE specification says we should access the IO address with an offset of 2
|
||||
// on native PCI IDE controllers.
|
||||
secondary_control_io_window = pci_secondary_control_io_window->create_from_io_window_with_offset(2, 4).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
VERIFY(secondary_base_io_window);
|
||||
VERIFY(secondary_control_io_window);
|
||||
|
||||
auto primary_bus_master_io = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR4, 16).release_value_but_fixme_should_propagate_errors();
|
||||
auto secondary_bus_master_io = primary_bus_master_io->create_from_io_window_with_offset(8).release_value_but_fixme_should_propagate_errors();
|
||||
|
||||
// FIXME: On IOAPIC based system, this value might be completely wrong
|
||||
// On QEMU for example, it should be "u8 irq_line = 22;" to actually work.
|
||||
auto irq_line = m_interrupt_line.value();
|
||||
|
||||
if (is_pci_native_mode_enabled()) {
|
||||
VERIFY(irq_line != 0);
|
||||
}
|
||||
|
||||
auto primary_channel_io_window_group = IDEChannel::IOWindowGroup { primary_base_io_window.release_nonnull(), primary_control_io_window.release_nonnull(), move(primary_bus_master_io) };
|
||||
auto secondary_channel_io_window_group = IDEChannel::IOWindowGroup { secondary_base_io_window.release_nonnull(), secondary_control_io_window.release_nonnull(), move(secondary_bus_master_io) };
|
||||
|
||||
if (is_pci_native_mode_enabled_on_primary_channel()) {
|
||||
m_channels.append(IDEChannel::create(*this, irq_line, move(primary_channel_io_window_group), IDEChannel::ChannelType::Primary));
|
||||
} else {
|
||||
m_channels.append(IDEChannel::create(*this, move(primary_channel_io_window_group), IDEChannel::ChannelType::Primary));
|
||||
}
|
||||
initialize_and_enumerate(m_channels[0]);
|
||||
m_channels[0].enable_irq();
|
||||
|
||||
if (is_pci_native_mode_enabled_on_secondary_channel()) {
|
||||
m_channels.append(IDEChannel::create(*this, irq_line, move(secondary_channel_io_window_group), IDEChannel::ChannelType::Secondary));
|
||||
} else {
|
||||
m_channels.append(IDEChannel::create(*this, move(secondary_channel_io_window_group), IDEChannel::ChannelType::Secondary));
|
||||
}
|
||||
initialize_and_enumerate(m_channels[1]);
|
||||
m_channels[1].enable_irq();
|
||||
}
|
||||
|
||||
}
|
40
Kernel/Arch/x86_64/PCI/IDELegacyModeController.h
Normal file
40
Kernel/Arch/x86_64/PCI/IDELegacyModeController.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Library/LockRefPtr.h>
|
||||
#include <Kernel/Storage/ATA/GenericIDE/Controller.h>
|
||||
#include <Kernel/Storage/StorageDevice.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class AsyncBlockDeviceRequest;
|
||||
|
||||
class PCIIDELegacyModeController final : public IDEController
|
||||
, public PCI::Device {
|
||||
public:
|
||||
static NonnullLockRefPtr<PCIIDELegacyModeController> initialize(PCI::DeviceIdentifier const&, bool force_pio);
|
||||
|
||||
bool is_bus_master_capable() const;
|
||||
bool is_pci_native_mode_enabled() const;
|
||||
|
||||
private:
|
||||
bool is_pci_native_mode_enabled_on_primary_channel() const;
|
||||
bool is_pci_native_mode_enabled_on_secondary_channel() const;
|
||||
PCIIDELegacyModeController(PCI::DeviceIdentifier const&, bool force_pio);
|
||||
|
||||
LockRefPtr<StorageDevice> device_by_channel_and_position(u32 index) const;
|
||||
void initialize(bool force_pio);
|
||||
void detect_disks();
|
||||
|
||||
// FIXME: Find a better way to get the ProgrammingInterface
|
||||
PCI::ProgrammingInterface m_prog_if;
|
||||
PCI::InterruptLine m_interrupt_line;
|
||||
};
|
||||
}
|
93
Kernel/Arch/x86_64/PCI/Initializer.cpp
Normal file
93
Kernel/Arch/x86_64/PCI/Initializer.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/Access.h>
|
||||
#include <Kernel/Bus/PCI/Initializer.h>
|
||||
#include <Kernel/CommandLine.h>
|
||||
#include <Kernel/FileSystem/SysFS/Subsystems/Bus/PCI/BusDirectory.h>
|
||||
#include <Kernel/Firmware/ACPI/Parser.h>
|
||||
#include <Kernel/Panic.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel::PCI {
|
||||
|
||||
READONLY_AFTER_INIT bool g_pci_access_io_probe_failed;
|
||||
READONLY_AFTER_INIT bool g_pci_access_is_disabled_from_commandline;
|
||||
|
||||
static bool test_pci_io();
|
||||
|
||||
UNMAP_AFTER_INIT static PCIAccessLevel detect_optimal_access_type()
|
||||
{
|
||||
auto boot_determined = kernel_command_line().pci_access_level();
|
||||
if (!ACPI::is_enabled() || !ACPI::Parser::the()->find_table("MCFG"sv).has_value())
|
||||
return PCIAccessLevel::IOAddressing;
|
||||
|
||||
if (boot_determined != PCIAccessLevel::IOAddressing)
|
||||
return boot_determined;
|
||||
|
||||
if (!g_pci_access_io_probe_failed)
|
||||
return PCIAccessLevel::IOAddressing;
|
||||
|
||||
PANIC("No PCI bus access method detected!");
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void initialize()
|
||||
{
|
||||
g_pci_access_is_disabled_from_commandline = kernel_command_line().is_pci_disabled();
|
||||
Optional<PhysicalAddress> possible_mcfg;
|
||||
// FIXME: There are other arch-specific methods to find the memory range
|
||||
// for accessing the PCI configuration space.
|
||||
// For example, the QEMU microvm machine type might expose an FDT so we could
|
||||
// parse it to find a PCI host bridge.
|
||||
if (ACPI::is_enabled()) {
|
||||
possible_mcfg = ACPI::Parser::the()->find_table("MCFG"sv);
|
||||
g_pci_access_io_probe_failed = (!test_pci_io()) && (!possible_mcfg.has_value());
|
||||
} else {
|
||||
g_pci_access_io_probe_failed = !test_pci_io();
|
||||
}
|
||||
if (g_pci_access_is_disabled_from_commandline || g_pci_access_io_probe_failed)
|
||||
return;
|
||||
switch (detect_optimal_access_type()) {
|
||||
case PCIAccessLevel::MemoryAddressing: {
|
||||
VERIFY(possible_mcfg.has_value());
|
||||
auto success = Access::initialize_for_multiple_pci_domains(possible_mcfg.value());
|
||||
VERIFY(success);
|
||||
break;
|
||||
}
|
||||
case PCIAccessLevel::IOAddressing: {
|
||||
auto success = Access::initialize_for_one_pci_domain();
|
||||
VERIFY(success);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
PCIBusSysFSDirectory::initialize();
|
||||
|
||||
MUST(PCI::enumerate([&](DeviceIdentifier const& device_identifier) {
|
||||
dmesgln("{} {}", device_identifier.address(), device_identifier.hardware_id());
|
||||
}));
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT bool test_pci_io()
|
||||
{
|
||||
dmesgln("Testing PCI via manual probing...");
|
||||
u32 tmp = 0x80000000;
|
||||
IO::out32(PCI::address_port, tmp);
|
||||
tmp = IO::in32(PCI::address_port);
|
||||
if (tmp == 0x80000000) {
|
||||
dmesgln("PCI IO supported");
|
||||
return true;
|
||||
}
|
||||
|
||||
dmesgln("PCI IO not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue