IOAccess.cpp 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Bus/PCI/IOAccess.h>
  7. #include <Kernel/Debug.h>
  8. #include <Kernel/IO.h>
  9. #include <Kernel/Sections.h>
  10. namespace Kernel {
  11. namespace PCI {
  12. UNMAP_AFTER_INIT void IOAccess::initialize()
  13. {
  14. if (!Access::is_initialized()) {
  15. new IOAccess();
  16. dbgln_if(PCI_DEBUG, "PCI: IO access initialised.");
  17. }
  18. }
  19. UNMAP_AFTER_INIT IOAccess::IOAccess()
  20. {
  21. dmesgln("PCI: Using I/O instructions for PCI configuration space access");
  22. enumerate_hardware([&](const Address& address, ID id) {
  23. m_physical_ids.append({ address, id, get_capabilities(address) });
  24. });
  25. }
  26. u8 IOAccess::read8_field(Address address, u32 field)
  27. {
  28. dbgln_if(PCI_DEBUG, "PCI: IO Reading 8-bit field {:#08x} for {}", field, address);
  29. return Access::early_read8_field(address, field);
  30. }
  31. u16 IOAccess::read16_field(Address address, u32 field)
  32. {
  33. dbgln_if(PCI_DEBUG, "PCI: IO Reading 16-bit field {:#08x} for {}", field, address);
  34. return Access::early_read16_field(address, field);
  35. }
  36. u32 IOAccess::read32_field(Address address, u32 field)
  37. {
  38. dbgln_if(PCI_DEBUG, "PCI: IO Reading 32-bit field {:#08x} for {}", field, address);
  39. return Access::early_read32_field(address, field);
  40. }
  41. void IOAccess::write8_field(Address address, u32 field, u8 value)
  42. {
  43. dbgln_if(PCI_DEBUG, "PCI: IO Writing to 8-bit field {:#08x}, value={:#02x} for {}", field, value, address);
  44. IO::out32(PCI_ADDRESS_PORT, address.io_address_for_field(field));
  45. IO::out8(PCI_VALUE_PORT + (field & 3), value);
  46. }
  47. void IOAccess::write16_field(Address address, u32 field, u16 value)
  48. {
  49. dbgln_if(PCI_DEBUG, "PCI: IO Writing to 16-bit field {:#08x}, value={:#02x} for {}", field, value, address);
  50. IO::out32(PCI_ADDRESS_PORT, address.io_address_for_field(field));
  51. IO::out16(PCI_VALUE_PORT + (field & 2), value);
  52. }
  53. void IOAccess::write32_field(Address address, u32 field, u32 value)
  54. {
  55. dbgln_if(PCI_DEBUG, "PCI: IO Writing to 32-bit field {:#08x}, value={:#02x} for {}", field, value, address);
  56. IO::out32(PCI_ADDRESS_PORT, address.io_address_for_field(field));
  57. IO::out32(PCI_VALUE_PORT, value);
  58. }
  59. void IOAccess::enumerate_hardware(Function<void(Address, ID)> callback)
  60. {
  61. dbgln_if(PCI_DEBUG, "PCI: IO enumerating hardware");
  62. // First scan bus 0. Find any device on that bus, and if it's a PCI-to-PCI
  63. // bridge, recursively scan it too.
  64. m_enumerated_buses.set(0, true);
  65. enumerate_bus(-1, 0, callback, true);
  66. // Handle Multiple PCI host bridges on slot 0, device 0.
  67. // If we happen to miss some PCI buses because they are not reachable through
  68. // recursive PCI-to-PCI bridges starting from bus 0, we might find them here.
  69. if ((read8_field(Address(), PCI_HEADER_TYPE) & 0x80) != 0) {
  70. for (int bus = 1; bus < 256; ++bus) {
  71. if (read16_field(Address(0, 0, 0, bus), PCI_VENDOR_ID) == PCI_NONE)
  72. continue;
  73. if (read16_field(Address(0, 0, 0, bus), PCI_CLASS) != 0x6)
  74. continue;
  75. if (m_enumerated_buses.get(bus))
  76. continue;
  77. enumerate_bus(-1, bus, callback, false);
  78. m_enumerated_buses.set(bus, true);
  79. }
  80. }
  81. }
  82. }
  83. }