Serenity Operating System
at hosted 230 lines 6.6 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <Kernel/PCI/Access.h> 28#include <Kernel/PCI/IOAccess.h> 29 30namespace Kernel { 31namespace PCI { 32 33static Access* s_access; 34 35inline void write8(Address address, u32 field, u8 value) { Access::the().write8_field(address, field, value); } 36inline void write16(Address address, u32 field, u16 value) { Access::the().write16_field(address, field, value); } 37inline void write32(Address address, u32 field, u32 value) { Access::the().write32_field(address, field, value); } 38inline u8 read8(Address address, u32 field) { return Access::the().read8_field(address, field); } 39inline u16 read16(Address address, u32 field) { return Access::the().read16_field(address, field); } 40inline u32 read32(Address address, u32 field) { return Access::the().read32_field(address, field); } 41 42Access& Access::the() 43{ 44 if (s_access == nullptr) { 45 ASSERT_NOT_REACHED(); // We failed to initialize the PCI subsystem, so stop here! 46 } 47 return *s_access; 48} 49 50bool Access::is_initialized() 51{ 52 return (s_access != nullptr); 53} 54 55Access::Access() 56{ 57 s_access = this; 58} 59 60static u16 read_type(Address address) 61{ 62 return (read8(address, PCI_CLASS) << 8u) | read8(address, PCI_SUBCLASS); 63} 64 65void Access::enumerate_functions(int type, u8 bus, u8 slot, u8 function, Function<void(Address, ID)>& callback) 66{ 67 Address address(0, bus, slot, function); 68 if (type == -1 || type == read_type(address)) 69 callback(address, { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }); 70 if (read_type(address) == PCI_TYPE_BRIDGE) { 71 u8 secondary_bus = read8_field(address, PCI_SECONDARY_BUS); 72#ifdef PCI_DEBUG 73 klog() << "PCI: Found secondary bus: " << secondary_bus; 74#endif 75 ASSERT(secondary_bus != bus); 76 enumerate_bus(type, secondary_bus, callback); 77 } 78} 79 80void Access::enumerate_slot(int type, u8 bus, u8 slot, Function<void(Address, ID)>& callback) 81{ 82 Address address(0, bus, slot, 0); 83 if (read16_field(address, PCI_VENDOR_ID) == PCI_NONE) 84 return; 85 enumerate_functions(type, bus, slot, 0, callback); 86 if (!(read8_field(address, PCI_HEADER_TYPE) & 0x80)) 87 return; 88 for (u8 function = 1; function < 8; ++function) { 89 Address address(0, bus, slot, function); 90 if (read16_field(address, PCI_VENDOR_ID) != PCI_NONE) 91 enumerate_functions(type, bus, slot, function, callback); 92 } 93} 94 95void Access::enumerate_bus(int type, u8 bus, Function<void(Address, ID)>& callback) 96{ 97 for (u8 slot = 0; slot < 32; ++slot) 98 enumerate_slot(type, bus, slot, callback); 99} 100 101void enumerate_all(Function<void(Address, ID)> callback) 102{ 103 Access::the().enumerate_all(callback); 104} 105 106void raw_access(Address address, u32 field, size_t access_size, u32 value) 107{ 108 ASSERT(access_size != 0); 109 if (access_size == 1) { 110 write8(address, field, value); 111 return; 112 } 113 if (access_size == 2) { 114 write16(address, field, value); 115 return; 116 } 117 if (access_size == 4) { 118 write32(address, field, value); 119 return; 120 } 121 ASSERT_NOT_REACHED(); 122} 123 124ID get_id(Address address) 125{ 126 return { read16(address, PCI_VENDOR_ID), read16(address, PCI_DEVICE_ID) }; 127} 128 129void enable_interrupt_line(Address address) 130{ 131 write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) & ~(1 << 10)); 132} 133 134void disable_interrupt_line(Address address) 135{ 136 write16(address, PCI_COMMAND, read16(address, PCI_COMMAND) | 1 << 10); 137} 138 139u8 get_interrupt_line(Address address) 140{ 141 return read8(address, PCI_INTERRUPT_LINE); 142} 143 144u32 get_BAR0(Address address) 145{ 146 return read32(address, PCI_BAR0); 147} 148 149u32 get_BAR1(Address address) 150{ 151 return read32(address, PCI_BAR1); 152} 153 154u32 get_BAR2(Address address) 155{ 156 return read32(address, PCI_BAR2); 157} 158 159u32 get_BAR3(Address address) 160{ 161 return read16(address, PCI_BAR3); 162} 163 164u32 get_BAR4(Address address) 165{ 166 return read32(address, PCI_BAR4); 167} 168 169u32 get_BAR5(Address address) 170{ 171 return read32(address, PCI_BAR5); 172} 173 174u8 get_revision_id(Address address) 175{ 176 return read8(address, PCI_REVISION_ID); 177} 178 179u8 get_subclass(Address address) 180{ 181 return read8(address, PCI_SUBCLASS); 182} 183 184u8 get_class(Address address) 185{ 186 return read8(address, PCI_CLASS); 187} 188 189u16 get_subsystem_id(Address address) 190{ 191 return read16(address, PCI_SUBSYSTEM_ID); 192} 193 194u16 get_subsystem_vendor_id(Address address) 195{ 196 return read16(address, PCI_SUBSYSTEM_VENDOR_ID); 197} 198 199void enable_bus_mastering(Address address) 200{ 201 auto value = read16(address, PCI_COMMAND); 202 value |= (1 << 2); 203 value |= (1 << 0); 204 write16(address, PCI_COMMAND, value); 205} 206 207void disable_bus_mastering(Address address) 208{ 209 auto value = read16(address, PCI_COMMAND); 210 value &= ~(1 << 2); 211 value |= (1 << 0); 212 write16(address, PCI_COMMAND, value); 213} 214 215size_t get_BAR_space_size(Address address, u8 bar_number) 216{ 217 // See PCI Spec 2.3, Page 222 218 ASSERT(bar_number < 6); 219 u8 field = (PCI_BAR0 + (bar_number << 2)); 220 u32 bar_reserved = read32(address, field); 221 write32(address, field, 0xFFFFFFFF); 222 u32 space_size = read32(address, field); 223 write32(address, field, bar_reserved); 224 space_size &= 0xfffffff0; 225 space_size = (~space_size) + 1; 226 return space_size; 227} 228 229} 230}