IDELegacyModeController.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright (c) 2020-2022, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/OwnPtr.h>
  7. #include <AK/Types.h>
  8. #include <Kernel/Arch/x86/PCI/IDELegacyModeController.h>
  9. #include <Kernel/Bus/PCI/API.h>
  10. #include <Kernel/FileSystem/ProcFS.h>
  11. #include <Kernel/Library/LockRefPtr.h>
  12. #include <Kernel/Sections.h>
  13. #include <Kernel/Storage/ATA/ATADiskDevice.h>
  14. #include <Kernel/Storage/ATA/GenericIDE/Channel.h>
  15. namespace Kernel {
  16. UNMAP_AFTER_INIT NonnullLockRefPtr<PCIIDELegacyModeController> PCIIDELegacyModeController::initialize(PCI::DeviceIdentifier const& device_identifier, bool force_pio)
  17. {
  18. return adopt_lock_ref(*new PCIIDELegacyModeController(device_identifier, force_pio));
  19. }
  20. UNMAP_AFTER_INIT PCIIDELegacyModeController::PCIIDELegacyModeController(PCI::DeviceIdentifier const& device_identifier, bool force_pio)
  21. : PCI::Device(device_identifier.address())
  22. , m_prog_if(device_identifier.prog_if())
  23. , m_interrupt_line(device_identifier.interrupt_line())
  24. {
  25. PCI::enable_io_space(device_identifier.address());
  26. PCI::enable_memory_space(device_identifier.address());
  27. PCI::enable_bus_mastering(device_identifier.address());
  28. enable_pin_based_interrupts();
  29. initialize(force_pio);
  30. }
  31. bool PCIIDELegacyModeController::is_pci_native_mode_enabled() const
  32. {
  33. return (m_prog_if.value() & 0x05) != 0;
  34. }
  35. bool PCIIDELegacyModeController::is_pci_native_mode_enabled_on_primary_channel() const
  36. {
  37. return (m_prog_if.value() & 0x1) == 0x1;
  38. }
  39. bool PCIIDELegacyModeController::is_pci_native_mode_enabled_on_secondary_channel() const
  40. {
  41. return (m_prog_if.value() & 0x4) == 0x4;
  42. }
  43. bool PCIIDELegacyModeController::is_bus_master_capable() const
  44. {
  45. return m_prog_if.value() & (1 << 7);
  46. }
  47. static char const* detect_controller_type(u8 programming_value)
  48. {
  49. switch (programming_value) {
  50. case 0x00:
  51. return "ISA Compatibility mode-only controller";
  52. case 0x05:
  53. return "PCI native mode-only controller";
  54. case 0x0A:
  55. return "ISA Compatibility mode controller, supports both channels switched to PCI native mode";
  56. case 0x0F:
  57. return "PCI native mode controller, supports both channels switched to ISA compatibility mode";
  58. case 0x80:
  59. return "ISA Compatibility mode-only controller, supports bus mastering";
  60. case 0x85:
  61. return "PCI native mode-only controller, supports bus mastering";
  62. case 0x8A:
  63. return "ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering";
  64. case 0x8F:
  65. return "PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering";
  66. default:
  67. VERIFY_NOT_REACHED();
  68. }
  69. VERIFY_NOT_REACHED();
  70. }
  71. UNMAP_AFTER_INIT void PCIIDELegacyModeController::initialize(bool force_pio)
  72. {
  73. auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1));
  74. dbgln("IDE controller @ {}: bus master base was set to {}", pci_address(), bus_master_base);
  75. dbgln("IDE controller @ {}: interrupt line was set to {}", pci_address(), m_interrupt_line.value());
  76. dbgln("IDE controller @ {}: {}", pci_address(), detect_controller_type(m_prog_if.value()));
  77. dbgln("IDE controller @ {}: primary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2).in<u8>() >> 5) & 0b11));
  78. dbgln("IDE controller @ {}: secondary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2 + 8).in<u8>() >> 5) & 0b11));
  79. auto initialize_and_enumerate = [&force_pio](IDEChannel& channel) -> void {
  80. {
  81. auto result = channel.allocate_resources_for_pci_ide_controller({}, force_pio);
  82. // FIXME: Propagate errors properly
  83. VERIFY(!result.is_error());
  84. }
  85. {
  86. auto result = channel.detect_connected_devices();
  87. // FIXME: Propagate errors properly
  88. VERIFY(!result.is_error());
  89. }
  90. };
  91. if (!is_bus_master_capable())
  92. force_pio = true;
  93. auto bar0 = PCI::get_BAR0(pci_address());
  94. auto bar1 = PCI::get_BAR1(pci_address());
  95. auto bar2 = PCI::get_BAR2(pci_address());
  96. auto bar3 = PCI::get_BAR3(pci_address());
  97. auto primary_base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0 & (~1));
  98. // Note: the PCI IDE specification says we should access the IO address with an offset of 2
  99. // on native PCI IDE controllers.
  100. auto primary_control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress((bar1 & (~1)) | 2);
  101. auto secondary_base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2 & (~1));
  102. // Note: the PCI IDE specification says we should access the IO address with an offset of 2
  103. // on native PCI IDE controllers.
  104. auto secondary_control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress((bar3 & (~1)) | 2);
  105. // FIXME: On IOAPIC based system, this value might be completely wrong
  106. // On QEMU for example, it should be "u8 irq_line = 22;" to actually work.
  107. auto irq_line = m_interrupt_line.value();
  108. if (is_pci_native_mode_enabled()) {
  109. VERIFY(irq_line != 0);
  110. }
  111. if (is_pci_native_mode_enabled_on_primary_channel()) {
  112. m_channels.append(IDEChannel::create(*this, irq_line, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary));
  113. } else {
  114. m_channels.append(IDEChannel::create(*this, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary));
  115. }
  116. initialize_and_enumerate(m_channels[0]);
  117. m_channels[0].enable_irq();
  118. if (is_pci_native_mode_enabled_on_secondary_channel()) {
  119. m_channels.append(IDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
  120. } else {
  121. m_channels.append(IDEChannel::create(*this, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
  122. }
  123. initialize_and_enumerate(m_channels[1]);
  124. m_channels[1].enable_irq();
  125. }
  126. }