Serenity Operating System
at master 293 lines 9.9 kB view raw
1/* 2 * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/Bus/PCI/API.h> 8#include <Kernel/Bus/PCI/Access.h> 9#include <Kernel/Sections.h> 10 11namespace Kernel::PCI { 12 13void write8_locked(DeviceIdentifier const& identifier, PCI::RegisterOffset field, u8 value) 14{ 15 VERIFY(identifier.operation_lock().is_locked()); 16 Access::the().write8_field(identifier, to_underlying(field), value); 17} 18void write16_locked(DeviceIdentifier const& identifier, PCI::RegisterOffset field, u16 value) 19{ 20 VERIFY(identifier.operation_lock().is_locked()); 21 Access::the().write16_field(identifier, to_underlying(field), value); 22} 23void write32_locked(DeviceIdentifier const& identifier, PCI::RegisterOffset field, u32 value) 24{ 25 VERIFY(identifier.operation_lock().is_locked()); 26 Access::the().write32_field(identifier, to_underlying(field), value); 27} 28 29u8 read8_locked(DeviceIdentifier const& identifier, PCI::RegisterOffset field) 30{ 31 VERIFY(identifier.operation_lock().is_locked()); 32 return Access::the().read8_field(identifier, to_underlying(field)); 33} 34u16 read16_locked(DeviceIdentifier const& identifier, PCI::RegisterOffset field) 35{ 36 VERIFY(identifier.operation_lock().is_locked()); 37 return Access::the().read16_field(identifier, to_underlying(field)); 38} 39u32 read32_locked(DeviceIdentifier const& identifier, PCI::RegisterOffset field) 40{ 41 VERIFY(identifier.operation_lock().is_locked()); 42 return Access::the().read32_field(identifier, to_underlying(field)); 43} 44 45ErrorOr<void> enumerate(Function<void(DeviceIdentifier const&)> callback) 46{ 47 return Access::the().fast_enumerate(callback); 48} 49 50HardwareID get_hardware_id(DeviceIdentifier const& identifier) 51{ 52 SpinlockLocker locker(identifier.operation_lock()); 53 return { read16_locked(identifier, PCI::RegisterOffset::VENDOR_ID), read16_locked(identifier, PCI::RegisterOffset::DEVICE_ID) }; 54} 55 56void enable_io_space(DeviceIdentifier const& identifier) 57{ 58 SpinlockLocker locker(identifier.operation_lock()); 59 write16_locked(identifier, PCI::RegisterOffset::COMMAND, read16_locked(identifier, PCI::RegisterOffset::COMMAND) | (1 << 0)); 60} 61void disable_io_space(DeviceIdentifier const& identifier) 62{ 63 SpinlockLocker locker(identifier.operation_lock()); 64 write16_locked(identifier, PCI::RegisterOffset::COMMAND, read16_locked(identifier, PCI::RegisterOffset::COMMAND) & ~(1 << 0)); 65} 66 67void enable_memory_space(DeviceIdentifier const& identifier) 68{ 69 SpinlockLocker locker(identifier.operation_lock()); 70 write16_locked(identifier, PCI::RegisterOffset::COMMAND, read16_locked(identifier, PCI::RegisterOffset::COMMAND) | (1 << 1)); 71} 72void disable_memory_space(DeviceIdentifier const& identifier) 73{ 74 SpinlockLocker locker(identifier.operation_lock()); 75 write16_locked(identifier, PCI::RegisterOffset::COMMAND, read16_locked(identifier, PCI::RegisterOffset::COMMAND) & ~(1 << 1)); 76} 77 78bool is_io_space_enabled(DeviceIdentifier const& identifier) 79{ 80 SpinlockLocker locker(identifier.operation_lock()); 81 return (read16_locked(identifier, PCI::RegisterOffset::COMMAND) & 1) != 0; 82} 83 84void enable_interrupt_line(DeviceIdentifier const& identifier) 85{ 86 SpinlockLocker locker(identifier.operation_lock()); 87 write16_locked(identifier, PCI::RegisterOffset::COMMAND, read16_locked(identifier, PCI::RegisterOffset::COMMAND) & ~(1 << 10)); 88} 89 90void disable_interrupt_line(DeviceIdentifier const& identifier) 91{ 92 SpinlockLocker locker(identifier.operation_lock()); 93 write16_locked(identifier, PCI::RegisterOffset::COMMAND, read16_locked(identifier, PCI::RegisterOffset::COMMAND) | 1 << 10); 94} 95 96u32 get_BAR0(DeviceIdentifier const& identifier) 97{ 98 SpinlockLocker locker(identifier.operation_lock()); 99 return read32_locked(identifier, PCI::RegisterOffset::BAR0); 100} 101 102u32 get_BAR1(DeviceIdentifier const& identifier) 103{ 104 SpinlockLocker locker(identifier.operation_lock()); 105 return read32_locked(identifier, PCI::RegisterOffset::BAR1); 106} 107 108u32 get_BAR2(DeviceIdentifier const& identifier) 109{ 110 SpinlockLocker locker(identifier.operation_lock()); 111 return read32_locked(identifier, PCI::RegisterOffset::BAR2); 112} 113 114u32 get_BAR3(DeviceIdentifier const& identifier) 115{ 116 SpinlockLocker locker(identifier.operation_lock()); 117 return read32_locked(identifier, PCI::RegisterOffset::BAR3); 118} 119 120u32 get_BAR4(DeviceIdentifier const& identifier) 121{ 122 SpinlockLocker locker(identifier.operation_lock()); 123 return read32_locked(identifier, PCI::RegisterOffset::BAR4); 124} 125 126u32 get_BAR5(DeviceIdentifier const& identifier) 127{ 128 SpinlockLocker locker(identifier.operation_lock()); 129 return read32_locked(identifier, PCI::RegisterOffset::BAR5); 130} 131 132u32 get_BAR(DeviceIdentifier const& identifier, HeaderType0BaseRegister pci_bar) 133{ 134 VERIFY(to_underlying(pci_bar) <= 5); 135 switch (to_underlying(pci_bar)) { 136 case 0: 137 return get_BAR0(identifier); 138 case 1: 139 return get_BAR1(identifier); 140 case 2: 141 return get_BAR2(identifier); 142 case 3: 143 return get_BAR3(identifier); 144 case 4: 145 return get_BAR4(identifier); 146 case 5: 147 return get_BAR5(identifier); 148 default: 149 VERIFY_NOT_REACHED(); 150 } 151} 152 153BARSpaceType get_BAR_space_type(u32 pci_bar_value) 154{ 155 // Note: For IO space, bit 0 is set to 1. 156 if (pci_bar_value & (1 << 0)) 157 return BARSpaceType::IOSpace; 158 auto memory_space_type = (pci_bar_value >> 1) & 0b11; 159 switch (memory_space_type) { 160 case 0: 161 return BARSpaceType::Memory32BitSpace; 162 case 1: 163 return BARSpaceType::Memory16BitSpace; 164 case 2: 165 return BARSpaceType::Memory64BitSpace; 166 default: 167 VERIFY_NOT_REACHED(); 168 } 169} 170 171void enable_bus_mastering(DeviceIdentifier const& identifier) 172{ 173 SpinlockLocker locker(identifier.operation_lock()); 174 auto value = read16_locked(identifier, PCI::RegisterOffset::COMMAND); 175 value |= (1 << 2); 176 value |= (1 << 0); 177 write16_locked(identifier, PCI::RegisterOffset::COMMAND, value); 178} 179 180void disable_bus_mastering(DeviceIdentifier const& identifier) 181{ 182 SpinlockLocker locker(identifier.operation_lock()); 183 auto value = read16_locked(identifier, PCI::RegisterOffset::COMMAND); 184 value &= ~(1 << 2); 185 value |= (1 << 0); 186 write16_locked(identifier, PCI::RegisterOffset::COMMAND, value); 187} 188 189static void write8_offsetted(DeviceIdentifier const& identifier, u32 field, u8 value) 190{ 191 VERIFY(identifier.operation_lock().is_locked()); 192 Access::the().write8_field(identifier, field, value); 193} 194static void write16_offsetted(DeviceIdentifier const& identifier, u32 field, u16 value) 195{ 196 VERIFY(identifier.operation_lock().is_locked()); 197 Access::the().write16_field(identifier, field, value); 198} 199static void write32_offsetted(DeviceIdentifier const& identifier, u32 field, u32 value) 200{ 201 VERIFY(identifier.operation_lock().is_locked()); 202 Access::the().write32_field(identifier, field, value); 203} 204static u8 read8_offsetted(DeviceIdentifier const& identifier, u32 field) 205{ 206 VERIFY(identifier.operation_lock().is_locked()); 207 return Access::the().read8_field(identifier, field); 208} 209static u16 read16_offsetted(DeviceIdentifier const& identifier, u32 field) 210{ 211 VERIFY(identifier.operation_lock().is_locked()); 212 return Access::the().read16_field(identifier, field); 213} 214static u32 read32_offsetted(DeviceIdentifier const& identifier, u32 field) 215{ 216 VERIFY(identifier.operation_lock().is_locked()); 217 return Access::the().read32_field(identifier, field); 218} 219 220size_t get_BAR_space_size(DeviceIdentifier const& identifier, HeaderType0BaseRegister pci_bar) 221{ 222 SpinlockLocker locker(identifier.operation_lock()); 223 // See PCI Spec 2.3, Page 222 224 VERIFY(to_underlying(pci_bar) < 6); 225 u8 field = to_underlying(PCI::RegisterOffset::BAR0) + (to_underlying(pci_bar) << 2); 226 u32 bar_reserved = read32_offsetted(identifier, field); 227 write32_offsetted(identifier, field, 0xFFFFFFFF); 228 u32 space_size = read32_offsetted(identifier, field); 229 write32_offsetted(identifier, field, bar_reserved); 230 space_size &= 0xfffffff0; 231 space_size = (~space_size) + 1; 232 return space_size; 233} 234 235size_t get_expansion_rom_space_size(DeviceIdentifier const& identifier) 236{ 237 SpinlockLocker locker(identifier.operation_lock()); 238 u8 field = to_underlying(PCI::RegisterOffset::EXPANSION_ROM_POINTER); 239 u32 bar_reserved = read32_offsetted(identifier, field); 240 write32_offsetted(identifier, field, 0xFFFFFFFF); 241 u32 space_size = read32_offsetted(identifier, field); 242 write32_offsetted(identifier, field, bar_reserved); 243 space_size &= 0xfffffff0; 244 space_size = (~space_size) + 1; 245 return space_size; 246} 247 248void raw_access(DeviceIdentifier const& identifier, u32 field, size_t access_size, u32 value) 249{ 250 SpinlockLocker locker(identifier.operation_lock()); 251 VERIFY(access_size != 0); 252 if (access_size == 1) { 253 write8_offsetted(identifier, field, value); 254 return; 255 } 256 if (access_size == 2) { 257 write16_offsetted(identifier, field, value); 258 return; 259 } 260 if (access_size == 4) { 261 write32_offsetted(identifier, field, value); 262 return; 263 } 264 VERIFY_NOT_REACHED(); 265} 266 267u8 Capability::read8(size_t offset) const 268{ 269 auto& identifier = get_device_identifier(m_address); 270 SpinlockLocker locker(identifier.operation_lock()); 271 return read8_offsetted(identifier, m_ptr + offset); 272} 273 274u16 Capability::read16(size_t offset) const 275{ 276 auto& identifier = get_device_identifier(m_address); 277 SpinlockLocker locker(identifier.operation_lock()); 278 return read16_offsetted(identifier, m_ptr + offset); 279} 280 281u32 Capability::read32(size_t offset) const 282{ 283 auto& identifier = get_device_identifier(m_address); 284 SpinlockLocker locker(identifier.operation_lock()); 285 return read32_offsetted(identifier, m_ptr + offset); 286} 287 288DeviceIdentifier const& get_device_identifier(Address address) 289{ 290 return Access::the().get_device_identifier(address); 291} 292 293}