Serenity Operating System
at master 273 lines 11 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/ByteReader.h> 8#include <AK/Error.h> 9#include <AK/HashTable.h> 10#if ARCH(X86_64) 11# include <Kernel/Arch/x86_64/PCI/Controller/HostBridge.h> 12#endif 13#include <Kernel/Bus/PCI/Access.h> 14#include <Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h> 15#include <Kernel/Bus/PCI/Initializer.h> 16#include <Kernel/Debug.h> 17#include <Kernel/Firmware/ACPI/Definitions.h> 18#include <Kernel/Memory/MemoryManager.h> 19#include <Kernel/Memory/Region.h> 20#include <Kernel/Memory/TypedMapping.h> 21#include <Kernel/Sections.h> 22 23namespace Kernel::PCI { 24 25#define PCI_MMIO_CONFIG_SPACE_SIZE 4096 26 27static Access* s_access; 28 29Access& Access::the() 30{ 31 if (s_access == nullptr) { 32 VERIFY_NOT_REACHED(); // We failed to initialize the PCI subsystem, so stop here! 33 } 34 return *s_access; 35} 36 37bool Access::is_initialized() 38{ 39 return (s_access != nullptr); 40} 41 42bool Access::is_hardware_disabled() 43{ 44 return g_pci_access_io_probe_failed; 45} 46 47bool Access::is_disabled() 48{ 49 return g_pci_access_is_disabled_from_commandline || g_pci_access_io_probe_failed; 50} 51 52UNMAP_AFTER_INIT bool Access::find_and_register_pci_host_bridges_from_acpi_mcfg_table(PhysicalAddress mcfg_table) 53{ 54 u32 length = 0; 55 u8 revision = 0; 56 { 57 auto mapped_mcfg_table_or_error = Memory::map_typed<ACPI::Structures::SDTHeader>(mcfg_table); 58 if (mapped_mcfg_table_or_error.is_error()) { 59 dbgln("Failed to map MCFG table"); 60 return false; 61 } 62 auto mapped_mcfg_table = mapped_mcfg_table_or_error.release_value(); 63 length = mapped_mcfg_table->length; 64 revision = mapped_mcfg_table->revision; 65 } 66 67 if (length == sizeof(ACPI::Structures::SDTHeader)) 68 return false; 69 70 dbgln("PCI: MCFG, length: {}, revision: {}", length, revision); 71 72 if (Checked<size_t>::addition_would_overflow(length, PAGE_SIZE)) { 73 dbgln("Overflow when adding extra page to allocation of length {}", length); 74 return false; 75 } 76 length += PAGE_SIZE; 77 auto region_size_or_error = Memory::page_round_up(length); 78 if (region_size_or_error.is_error()) { 79 dbgln("Failed to round up length of {} to pages", length); 80 return false; 81 } 82 auto mcfg_region_or_error = MM.allocate_kernel_region(mcfg_table.page_base(), region_size_or_error.value(), "PCI Parsing MCFG"sv, Memory::Region::Access::ReadWrite); 83 if (mcfg_region_or_error.is_error()) 84 return false; 85 auto& mcfg = *(ACPI::Structures::MCFG*)mcfg_region_or_error.value()->vaddr().offset(mcfg_table.offset_in_page()).as_ptr(); 86 dbgln_if(PCI_DEBUG, "PCI: Checking MCFG @ {}, {}", VirtualAddress(&mcfg), mcfg_table); 87 for (u32 index = 0; index < ((mcfg.header.length - sizeof(ACPI::Structures::MCFG)) / sizeof(ACPI::Structures::PCI_MMIO_Descriptor)); index++) { 88 u8 start_bus = mcfg.descriptors[index].start_pci_bus; 89 u8 end_bus = mcfg.descriptors[index].end_pci_bus; 90 u64 start_addr = mcfg.descriptors[index].base_addr; 91 92 Domain pci_domain { index, start_bus, end_bus }; 93 dmesgln("PCI: New PCI domain @ {}, PCI buses ({}-{})", PhysicalAddress { start_addr }, start_bus, end_bus); 94 auto host_bridge = MemoryBackedHostBridge::must_create(pci_domain, PhysicalAddress { start_addr }); 95 add_host_controller(move(host_bridge)); 96 } 97 98 return true; 99} 100 101UNMAP_AFTER_INIT bool Access::initialize_for_multiple_pci_domains(PhysicalAddress mcfg_table) 102{ 103 VERIFY(!Access::is_initialized()); 104 auto* access = new Access(); 105 if (!access->find_and_register_pci_host_bridges_from_acpi_mcfg_table(mcfg_table)) 106 return false; 107 access->rescan_hardware(); 108 dbgln_if(PCI_DEBUG, "PCI: access for multiple PCI domain initialised."); 109 return true; 110} 111 112#if ARCH(X86_64) 113UNMAP_AFTER_INIT bool Access::initialize_for_one_pci_domain() 114{ 115 VERIFY(!Access::is_initialized()); 116 auto* access = new Access(); 117 auto host_bridge = HostBridge::must_create_with_io_access(); 118 access->add_host_controller(move(host_bridge)); 119 access->rescan_hardware(); 120 dbgln_if(PCI_DEBUG, "PCI: access for one PCI domain initialised."); 121 return true; 122} 123#endif 124 125ErrorOr<void> Access::add_host_controller_and_scan_for_devices(NonnullOwnPtr<HostController> controller) 126{ 127 SpinlockLocker locker(m_access_lock); 128 SpinlockLocker scan_locker(m_scan_lock); 129 auto domain_number = controller->domain_number(); 130 131 VERIFY(!m_host_controllers.contains(domain_number)); 132 // Note: We need to register the new controller as soon as possible, and 133 // definitely before enumerating devices behind that. 134 m_host_controllers.set(domain_number, move(controller)); 135 ErrorOr<void> error_or_void {}; 136 m_host_controllers.get(domain_number).value()->enumerate_attached_devices([&](EnumerableDeviceIdentifier const& device_identifier) -> IterationDecision { 137 auto device_identifier_or_error = DeviceIdentifier::from_enumerable_identifier(device_identifier); 138 if (device_identifier_or_error.is_error()) { 139 error_or_void = device_identifier_or_error.release_error(); 140 return IterationDecision::Break; 141 } 142 m_device_identifiers.append(device_identifier_or_error.release_value()); 143 return IterationDecision::Continue; 144 }); 145 return {}; 146} 147 148UNMAP_AFTER_INIT void Access::add_host_controller(NonnullOwnPtr<HostController> controller) 149{ 150 auto domain_number = controller->domain_number(); 151 m_host_controllers.set(domain_number, move(controller)); 152} 153 154UNMAP_AFTER_INIT Access::Access() 155{ 156 s_access = this; 157} 158 159UNMAP_AFTER_INIT void Access::rescan_hardware() 160{ 161 SpinlockLocker locker(m_access_lock); 162 SpinlockLocker scan_locker(m_scan_lock); 163 VERIFY(m_device_identifiers.is_empty()); 164 ErrorOr<void> error_or_void {}; 165 for (auto it = m_host_controllers.begin(); it != m_host_controllers.end(); ++it) { 166 (*it).value->enumerate_attached_devices([this, &error_or_void](EnumerableDeviceIdentifier device_identifier) -> IterationDecision { 167 auto device_identifier_or_error = DeviceIdentifier::from_enumerable_identifier(device_identifier); 168 if (device_identifier_or_error.is_error()) { 169 error_or_void = device_identifier_or_error.release_error(); 170 return IterationDecision::Break; 171 } 172 m_device_identifiers.append(device_identifier_or_error.release_value()); 173 return IterationDecision::Continue; 174 }); 175 } 176 if (error_or_void.is_error()) { 177 dmesgln("Failed during PCI Access::rescan_hardware due to {}", error_or_void.error()); 178 VERIFY_NOT_REACHED(); 179 } 180} 181 182ErrorOr<void> Access::fast_enumerate(Function<void(DeviceIdentifier const&)>& callback) const 183{ 184 // Note: We hold the m_access_lock for a brief moment just to ensure we get 185 // a complete Vector in case someone wants to mutate it. 186 Vector<NonnullRefPtr<DeviceIdentifier>> device_identifiers; 187 { 188 SpinlockLocker locker(m_access_lock); 189 VERIFY(!m_device_identifiers.is_empty()); 190 TRY(device_identifiers.try_extend(m_device_identifiers)); 191 } 192 for (auto const& device_identifier : device_identifiers) { 193 callback(device_identifier); 194 } 195 return {}; 196} 197 198DeviceIdentifier const& Access::get_device_identifier(Address address) const 199{ 200 for (auto& device_identifier : m_device_identifiers) { 201 auto device_address = device_identifier->address(); 202 if (device_address.domain() == address.domain() 203 && device_address.bus() == address.bus() 204 && device_address.device() == address.device() 205 && device_address.function() == address.function()) { 206 return device_identifier; 207 } 208 } 209 VERIFY_NOT_REACHED(); 210} 211 212void Access::write8_field(DeviceIdentifier const& identifier, u32 field, u8 value) 213{ 214 VERIFY(identifier.operation_lock().is_locked()); 215 SpinlockLocker locker(m_access_lock); 216 VERIFY(m_host_controllers.contains(identifier.address().domain())); 217 auto& controller = *m_host_controllers.get(identifier.address().domain()).value(); 218 controller.write8_field(identifier.address().bus(), identifier.address().device(), identifier.address().function(), field, value); 219} 220void Access::write16_field(DeviceIdentifier const& identifier, u32 field, u16 value) 221{ 222 VERIFY(identifier.operation_lock().is_locked()); 223 SpinlockLocker locker(m_access_lock); 224 VERIFY(m_host_controllers.contains(identifier.address().domain())); 225 auto& controller = *m_host_controllers.get(identifier.address().domain()).value(); 226 controller.write16_field(identifier.address().bus(), identifier.address().device(), identifier.address().function(), field, value); 227} 228void Access::write32_field(DeviceIdentifier const& identifier, u32 field, u32 value) 229{ 230 VERIFY(identifier.operation_lock().is_locked()); 231 SpinlockLocker locker(m_access_lock); 232 VERIFY(m_host_controllers.contains(identifier.address().domain())); 233 auto& controller = *m_host_controllers.get(identifier.address().domain()).value(); 234 controller.write32_field(identifier.address().bus(), identifier.address().device(), identifier.address().function(), field, value); 235} 236 237u8 Access::read8_field(DeviceIdentifier const& identifier, RegisterOffset field) 238{ 239 VERIFY(identifier.operation_lock().is_locked()); 240 return read8_field(identifier, to_underlying(field)); 241} 242u16 Access::read16_field(DeviceIdentifier const& identifier, RegisterOffset field) 243{ 244 VERIFY(identifier.operation_lock().is_locked()); 245 return read16_field(identifier, to_underlying(field)); 246} 247 248u8 Access::read8_field(DeviceIdentifier const& identifier, u32 field) 249{ 250 VERIFY(identifier.operation_lock().is_locked()); 251 SpinlockLocker locker(m_access_lock); 252 VERIFY(m_host_controllers.contains(identifier.address().domain())); 253 auto& controller = *m_host_controllers.get(identifier.address().domain()).value(); 254 return controller.read8_field(identifier.address().bus(), identifier.address().device(), identifier.address().function(), field); 255} 256u16 Access::read16_field(DeviceIdentifier const& identifier, u32 field) 257{ 258 VERIFY(identifier.operation_lock().is_locked()); 259 SpinlockLocker locker(m_access_lock); 260 VERIFY(m_host_controllers.contains(identifier.address().domain())); 261 auto& controller = *m_host_controllers.get(identifier.address().domain()).value(); 262 return controller.read16_field(identifier.address().bus(), identifier.address().device(), identifier.address().function(), field); 263} 264u32 Access::read32_field(DeviceIdentifier const& identifier, u32 field) 265{ 266 VERIFY(identifier.operation_lock().is_locked()); 267 SpinlockLocker locker(m_access_lock); 268 VERIFY(m_host_controllers.contains(identifier.address().domain())); 269 auto& controller = *m_host_controllers.get(identifier.address().domain()).value(); 270 return controller.read32_field(identifier.address().bus(), identifier.address().device(), identifier.address().function(), field); 271} 272 273}