diff --git a/Kernel/Arch/x86/ISABus/IDEController.cpp b/Kernel/Arch/x86/ISABus/IDEController.cpp index b8b0e17e0d..190c1ddca8 100644 --- a/Kernel/Arch/x86/ISABus/IDEController.cpp +++ b/Kernel/Arch/x86/ISABus/IDEController.cpp @@ -28,10 +28,10 @@ UNMAP_AFTER_INIT ISAIDEController::ISAIDEController() UNMAP_AFTER_INIT void ISAIDEController::initialize_channels() { - auto primary_base_io = IOAddress(0x1F0); - auto primary_control_io = IOAddress(0x3F6); - auto secondary_base_io = IOAddress(0x170); - auto secondary_control_io = IOAddress(0x376); + auto primary_base_io_window = IOWindow::create_for_io_space(IOAddress(0x1F0), 8).release_value_but_fixme_should_propagate_errors(); + auto primary_control_io_window = IOWindow::create_for_io_space(IOAddress(0x3F6), 4).release_value_but_fixme_should_propagate_errors(); + auto secondary_base_io_window = IOWindow::create_for_io_space(IOAddress(0x170), 8).release_value_but_fixme_should_propagate_errors(); + auto secondary_control_io_window = IOWindow::create_for_io_space(IOAddress(0x376), 4).release_value_but_fixme_should_propagate_errors(); auto initialize_and_enumerate = [](IDEChannel& channel) -> void { { @@ -46,11 +46,14 @@ UNMAP_AFTER_INIT void ISAIDEController::initialize_channels() } }; - m_channels.append(IDEChannel::create(*this, { primary_base_io, primary_control_io }, IDEChannel::ChannelType::Primary)); + auto primary_channel_io_window_group = IDEChannel::IOWindowGroup { move(primary_base_io_window), move(primary_control_io_window) }; + auto secondary_channel_io_window_group = IDEChannel::IOWindowGroup { move(secondary_base_io_window), move(secondary_control_io_window) }; + + m_channels.append(IDEChannel::create(*this, move(primary_channel_io_window_group), IDEChannel::ChannelType::Primary)); initialize_and_enumerate(m_channels[0]); m_channels[0].enable_irq(); - m_channels.append(IDEChannel::create(*this, { secondary_base_io, secondary_control_io }, IDEChannel::ChannelType::Secondary)); + m_channels.append(IDEChannel::create(*this, move(secondary_channel_io_window_group), IDEChannel::ChannelType::Secondary)); initialize_and_enumerate(m_channels[1]); m_channels[1].enable_irq(); dbgln("ISA IDE controller detected and initialized"); diff --git a/Kernel/Arch/x86/ISABus/SerialDevice.cpp b/Kernel/Arch/x86/ISABus/SerialDevice.cpp new file mode 100644 index 0000000000..22a50d9a3d --- /dev/null +++ b/Kernel/Arch/x86/ISABus/SerialDevice.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel { + +#define SERIAL_COM1_ADDR 0x3F8 +#define SERIAL_COM2_ADDR 0x2F8 +#define SERIAL_COM3_ADDR 0x3E8 +#define SERIAL_COM4_ADDR 0x2E8 + +UNMAP_AFTER_INIT NonnullLockRefPtr SerialDevice::must_create(size_t com_number) +{ + // FIXME: This way of blindly doing release_value is really not a good thing, find + // a way to propagate errors back. + LockRefPtr serial_device; + switch (com_number) { + case 0: { + auto io_window = IOWindow::create_for_io_space(IOAddress(SERIAL_COM1_ADDR), 16).release_value_but_fixme_should_propagate_errors(); + serial_device = DeviceManagement::try_create_device(move(io_window), 64).release_value(); + break; + } + case 1: { + auto io_window = IOWindow::create_for_io_space(IOAddress(SERIAL_COM2_ADDR), 16).release_value_but_fixme_should_propagate_errors(); + serial_device = DeviceManagement::try_create_device(move(io_window), 65).release_value(); + break; + } + case 2: { + auto io_window = IOWindow::create_for_io_space(IOAddress(SERIAL_COM3_ADDR), 16).release_value_but_fixme_should_propagate_errors(); + serial_device = DeviceManagement::try_create_device(move(io_window), 66).release_value(); + break; + } + case 3: { + auto io_window = IOWindow::create_for_io_space(IOAddress(SERIAL_COM4_ADDR), 16).release_value_but_fixme_should_propagate_errors(); + serial_device = DeviceManagement::try_create_device(move(io_window), 67).release_value(); + break; + } + default: + break; + } + return serial_device.release_nonnull(); +} + +} diff --git a/Kernel/Arch/x86/PCI/IDELegacyModeController.cpp b/Kernel/Arch/x86/PCI/IDELegacyModeController.cpp index 2ac3dc0c06..5f445e9682 100644 --- a/Kernel/Arch/x86/PCI/IDELegacyModeController.cpp +++ b/Kernel/Arch/x86/PCI/IDELegacyModeController.cpp @@ -80,12 +80,12 @@ static char const* detect_controller_type(u8 programming_value) UNMAP_AFTER_INIT void PCIIDELegacyModeController::initialize(bool force_pio) { - auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1)); - dbgln("IDE controller @ {}: bus master base was set to {}", pci_address(), bus_master_base); dbgln("IDE controller @ {}: interrupt line was set to {}", pci_address(), m_interrupt_line.value()); dbgln("IDE controller @ {}: {}", pci_address(), detect_controller_type(m_prog_if.value())); - dbgln("IDE controller @ {}: primary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2).in() >> 5) & 0b11)); - dbgln("IDE controller @ {}: secondary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2 + 8).in() >> 5) & 0b11)); + { + auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1)); + dbgln("IDE controller @ {}: bus master base was set to {}", pci_address(), bus_master_base); + } auto initialize_and_enumerate = [&force_pio](IDEChannel& channel) -> void { { @@ -103,20 +103,40 @@ UNMAP_AFTER_INIT void PCIIDELegacyModeController::initialize(bool force_pio) if (!is_bus_master_capable()) force_pio = true; - auto bar0 = PCI::get_BAR0(pci_address()); - auto bar1 = PCI::get_BAR1(pci_address()); - auto bar2 = PCI::get_BAR2(pci_address()); - auto bar3 = PCI::get_BAR3(pci_address()); + OwnPtr primary_base_io_window; + OwnPtr primary_control_io_window; + if (!is_pci_native_mode_enabled_on_primary_channel()) { + primary_base_io_window = IOWindow::create_for_io_space(IOAddress(0x1F0), 8).release_value_but_fixme_should_propagate_errors(); + primary_control_io_window = IOWindow::create_for_io_space(IOAddress(0x3F6), 4).release_value_but_fixme_should_propagate_errors(); + } else { + auto primary_base_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR0).release_value_but_fixme_should_propagate_errors(); + auto pci_primary_control_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR1).release_value_but_fixme_should_propagate_errors(); + // Note: the PCI IDE specification says we should access the IO address with an offset of 2 + // on native PCI IDE controllers. + primary_control_io_window = pci_primary_control_io_window->create_from_io_window_with_offset(2, 4).release_value_but_fixme_should_propagate_errors(); + } - auto primary_base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0 & (~1)); - // Note: the PCI IDE specification says we should access the IO address with an offset of 2 - // on native PCI IDE controllers. - auto primary_control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress((bar1 & (~1)) | 2); + VERIFY(primary_base_io_window); + VERIFY(primary_control_io_window); - auto secondary_base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2 & (~1)); - // Note: the PCI IDE specification says we should access the IO address with an offset of 2 - // on native PCI IDE controllers. - auto secondary_control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress((bar3 & (~1)) | 2); + OwnPtr secondary_base_io_window; + OwnPtr secondary_control_io_window; + + if (!is_pci_native_mode_enabled_on_primary_channel()) { + secondary_base_io_window = IOWindow::create_for_io_space(IOAddress(0x170), 8).release_value_but_fixme_should_propagate_errors(); + secondary_control_io_window = IOWindow::create_for_io_space(IOAddress(0x376), 4).release_value_but_fixme_should_propagate_errors(); + } else { + secondary_base_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR2).release_value_but_fixme_should_propagate_errors(); + auto pci_secondary_control_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR3).release_value_but_fixme_should_propagate_errors(); + // Note: the PCI IDE specification says we should access the IO address with an offset of 2 + // on native PCI IDE controllers. + secondary_control_io_window = pci_secondary_control_io_window->create_from_io_window_with_offset(2, 4).release_value_but_fixme_should_propagate_errors(); + } + VERIFY(secondary_base_io_window); + VERIFY(secondary_control_io_window); + + auto primary_bus_master_io = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR4, 16).release_value_but_fixme_should_propagate_errors(); + auto secondary_bus_master_io = primary_bus_master_io->create_from_io_window_with_offset(8).release_value_but_fixme_should_propagate_errors(); // FIXME: On IOAPIC based system, this value might be completely wrong // On QEMU for example, it should be "u8 irq_line = 22;" to actually work. @@ -126,18 +146,21 @@ UNMAP_AFTER_INIT void PCIIDELegacyModeController::initialize(bool force_pio) VERIFY(irq_line != 0); } + auto primary_channel_io_window_group = IDEChannel::IOWindowGroup { primary_base_io_window.release_nonnull(), primary_control_io_window.release_nonnull(), move(primary_bus_master_io) }; + auto secondary_channel_io_window_group = IDEChannel::IOWindowGroup { secondary_base_io_window.release_nonnull(), secondary_control_io_window.release_nonnull(), move(secondary_bus_master_io) }; + if (is_pci_native_mode_enabled_on_primary_channel()) { - m_channels.append(IDEChannel::create(*this, irq_line, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); + m_channels.append(IDEChannel::create(*this, irq_line, move(primary_channel_io_window_group), IDEChannel::ChannelType::Primary)); } else { - m_channels.append(IDEChannel::create(*this, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); + m_channels.append(IDEChannel::create(*this, move(primary_channel_io_window_group), IDEChannel::ChannelType::Primary)); } initialize_and_enumerate(m_channels[0]); m_channels[0].enable_irq(); if (is_pci_native_mode_enabled_on_secondary_channel()) { - m_channels.append(IDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); + m_channels.append(IDEChannel::create(*this, irq_line, move(secondary_channel_io_window_group), IDEChannel::ChannelType::Secondary)); } else { - m_channels.append(IDEChannel::create(*this, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); + m_channels.append(IDEChannel::create(*this, move(secondary_channel_io_window_group), IDEChannel::ChannelType::Secondary)); } initialize_and_enumerate(m_channels[1]); m_channels[1].enable_irq(); diff --git a/Kernel/Bus/PCI/API.cpp b/Kernel/Bus/PCI/API.cpp index bdc308b0b9..1539c5960f 100644 --- a/Kernel/Bus/PCI/API.cpp +++ b/Kernel/Bus/PCI/API.cpp @@ -115,6 +115,24 @@ u32 get_BAR(Address address, HeaderType0BaseRegister pci_bar) } } +BARSpaceType get_BAR_space_type(u32 pci_bar_value) +{ + // Note: For IO space, bit 0 is set to 1. + if (pci_bar_value & (1 << 0)) + return BARSpaceType::IOSpace; + auto memory_space_type = (pci_bar_value >> 1) & 0b11; + switch (memory_space_type) { + case 0: + return BARSpaceType::Memory32BitSpace; + case 1: + return BARSpaceType::Memory16BitSpace; + case 2: + return BARSpaceType::Memory64BitSpace; + default: + VERIFY_NOT_REACHED(); + } +} + void enable_bus_mastering(Address address) { auto value = read16(address, PCI::RegisterOffset::COMMAND); diff --git a/Kernel/Bus/PCI/API.h b/Kernel/Bus/PCI/API.h index 92152cb171..545942deb6 100644 --- a/Kernel/Bus/PCI/API.h +++ b/Kernel/Bus/PCI/API.h @@ -33,6 +33,7 @@ u32 get_BAR4(Address); u32 get_BAR5(Address); u32 get_BAR(Address address, HeaderType0BaseRegister); size_t get_BAR_space_size(Address, HeaderType0BaseRegister); +BARSpaceType get_BAR_space_type(u32 pci_bar_value); void enable_bus_mastering(Address); void disable_bus_mastering(Address); void enable_io_space(Address); diff --git a/Kernel/Bus/PCI/Definitions.h b/Kernel/Bus/PCI/Definitions.h index 63f3eae5da..9a2437ed18 100644 --- a/Kernel/Bus/PCI/Definitions.h +++ b/Kernel/Bus/PCI/Definitions.h @@ -30,6 +30,13 @@ enum class HeaderType0BaseRegister { BAR5, }; +enum class BARSpaceType { + IOSpace, + Memory16BitSpace, + Memory32BitSpace, + Memory64BitSpace, +}; + enum class RegisterOffset { VENDOR_ID = 0x00, // word DEVICE_ID = 0x02, // word diff --git a/Kernel/Bus/USB/UHCI/UHCIController.cpp b/Kernel/Bus/USB/UHCI/UHCIController.cpp index 7fed7817b7..bb425e4743 100644 --- a/Kernel/Bus/USB/UHCI/UHCIController.cpp +++ b/Kernel/Bus/USB/UHCI/UHCIController.cpp @@ -66,7 +66,8 @@ static constexpr u16 UHCI_NUMBER_OF_FRAMES = 1024; ErrorOr> UHCIController::try_to_initialize(PCI::DeviceIdentifier const& pci_device_identifier) { // NOTE: This assumes that address is pointing to a valid UHCI controller. - auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) UHCIController(pci_device_identifier))); + auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR4)); + auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) UHCIController(pci_device_identifier, move(registers_io_window)))); TRY(controller->initialize()); return controller; } @@ -74,7 +75,7 @@ ErrorOr> UHCIController::try_to_initialize(PCI ErrorOr UHCIController::initialize() { dmesgln("UHCI: Controller found {} @ {}", PCI::get_hardware_id(pci_address()), pci_address()); - dmesgln("UHCI: I/O base {}", m_io_base); + dmesgln("UHCI: I/O base {}", m_registers_io_window); dmesgln("UHCI: Interrupt line: {}", interrupt_number()); TRY(spawn_port_process()); @@ -83,10 +84,10 @@ ErrorOr UHCIController::initialize() return start(); } -UNMAP_AFTER_INIT UHCIController::UHCIController(PCI::DeviceIdentifier const& pci_device_identifier) +UNMAP_AFTER_INIT UHCIController::UHCIController(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr registers_io_window) : PCI::Device(pci_device_identifier.address()) , IRQHandler(pci_device_identifier.interrupt_line().value()) - , m_io_base(PCI::get_BAR4(pci_address()) & ~1) + , m_registers_io_window(move(registers_io_window)) , m_schedule_lock(LockRank::None) { } diff --git a/Kernel/Bus/USB/UHCI/UHCIController.h b/Kernel/Bus/USB/UHCI/UHCIController.h index 6f1eedef51..882e54bffd 100644 --- a/Kernel/Bus/USB/UHCI/UHCIController.h +++ b/Kernel/Bus/USB/UHCI/UHCIController.h @@ -10,12 +10,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -54,25 +54,25 @@ public: ErrorOr clear_port_feature(Badge, u8, HubFeatureSelector); private: - explicit UHCIController(PCI::DeviceIdentifier const& pci_device_identifier); + UHCIController(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr registers_io_window); - u16 read_usbcmd() { return m_io_base.offset(0).in(); } - u16 read_usbsts() { return m_io_base.offset(0x2).in(); } - u16 read_usbintr() { return m_io_base.offset(0x4).in(); } - u16 read_frnum() { return m_io_base.offset(0x6).in(); } - u32 read_flbaseadd() { return m_io_base.offset(0x8).in(); } - u8 read_sofmod() { return m_io_base.offset(0xc).in(); } - u16 read_portsc1() { return m_io_base.offset(0x10).in(); } - u16 read_portsc2() { return m_io_base.offset(0x12).in(); } + u16 read_usbcmd() { return m_registers_io_window->read16(0); } + u16 read_usbsts() { return m_registers_io_window->read16(0x2); } + u16 read_usbintr() { return m_registers_io_window->read16(0x4); } + u16 read_frnum() { return m_registers_io_window->read16(0x6); } + u32 read_flbaseadd() { return m_registers_io_window->read32(0x8); } + u8 read_sofmod() { return m_registers_io_window->read8(0xc); } + u16 read_portsc1() { return m_registers_io_window->read16(0x10); } + u16 read_portsc2() { return m_registers_io_window->read16(0x12); } - void write_usbcmd(u16 value) { m_io_base.offset(0).out(value); } - void write_usbsts(u16 value) { m_io_base.offset(0x2).out(value); } - void write_usbintr(u16 value) { m_io_base.offset(0x4).out(value); } - void write_frnum(u16 value) { m_io_base.offset(0x6).out(value); } - void write_flbaseadd(u32 value) { m_io_base.offset(0x8).out(value); } - void write_sofmod(u8 value) { m_io_base.offset(0xc).out(value); } - void write_portsc1(u16 value) { m_io_base.offset(0x10).out(value); } - void write_portsc2(u16 value) { m_io_base.offset(0x12).out(value); } + void write_usbcmd(u16 value) { m_registers_io_window->write16(0, value); } + void write_usbsts(u16 value) { m_registers_io_window->write16(0x2, value); } + void write_usbintr(u16 value) { m_registers_io_window->write16(0x4, value); } + void write_frnum(u16 value) { m_registers_io_window->write16(0x6, value); } + void write_flbaseadd(u32 value) { m_registers_io_window->write32(0x8, value); } + void write_sofmod(u8 value) { m_registers_io_window->write8(0xc, value); } + void write_portsc1(u16 value) { m_registers_io_window->write16(0x10, value); } + void write_portsc2(u16 value) { m_registers_io_window->write16(0x12, value); } virtual bool handle_irq(RegisterState const&) override; @@ -93,7 +93,7 @@ private: void reset_port(u8); - IOAddress m_io_base; + NonnullOwnPtr m_registers_io_window; Spinlock m_schedule_lock; diff --git a/Kernel/Bus/USB/USBHub.cpp b/Kernel/Bus/USB/USBHub.cpp index ba3aff0237..bb80647ed2 100644 --- a/Kernel/Bus/USB/USBHub.cpp +++ b/Kernel/Bus/USB/USBHub.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Kernel::USB { diff --git a/Kernel/Bus/VirtIO/Device.cpp b/Kernel/Bus/VirtIO/Device.cpp index 1b3b3f8f8f..722b6098c1 100644 --- a/Kernel/Bus/VirtIO/Device.cpp +++ b/Kernel/Bus/VirtIO/Device.cpp @@ -90,8 +90,6 @@ UNMAP_AFTER_INIT void Device::initialize() { auto address = pci_address(); enable_bus_mastering(pci_address()); - PCI::enable_interrupt_line(pci_address()); - enable_irq(); auto capabilities = PCI::get_device_identifier(address).capabilities(); for (auto& capability : capabilities) { @@ -128,27 +126,23 @@ UNMAP_AFTER_INIT void Device::initialize() if (m_use_mmio) { for (auto& cfg : m_configs) { - auto& mapping = m_mmio[cfg.bar]; - mapping.size = PCI::get_BAR_space_size(pci_address(), static_cast(cfg.bar)); - if (!mapping.base && mapping.size) { - auto region_size_or_error = Memory::page_round_up(mapping.size); - if (region_size_or_error.is_error()) { - dbgln_if(VIRTIO_DEBUG, "{}: Failed to round up size={} to pages", m_class_name, mapping.size); - continue; - } - auto region_or_error = MM.allocate_kernel_region(PhysicalAddress(page_base_of(PCI::get_BAR(pci_address(), static_cast(cfg.bar)))), region_size_or_error.value(), "VirtIO MMIO"sv, Memory::Region::Access::ReadWrite, Memory::Region::Cacheable::No); - if (region_or_error.is_error()) { - dbgln_if(VIRTIO_DEBUG, "{}: Failed to map bar {} - (size={}) {}", m_class_name, cfg.bar, mapping.size, region_or_error.error()); - } else { - mapping.base = region_or_error.release_value(); - } - } + auto mapping_io_window = IOWindow::create_for_pci_device_bar(pci_address(), static_cast(cfg.bar)).release_value_but_fixme_should_propagate_errors(); + m_register_bases[cfg.bar] = move(mapping_io_window); } m_common_cfg = get_config(ConfigurationType::Common, 0); m_notify_cfg = get_config(ConfigurationType::Notify, 0); m_isr_cfg = get_config(ConfigurationType::ISR, 0); + } else { + auto mapping_io_window = IOWindow::create_for_pci_device_bar(pci_address(), PCI::HeaderType0BaseRegister::BAR0).release_value_but_fixme_should_propagate_errors(); + m_register_bases[0] = move(mapping_io_window); } + // Note: We enable interrupts at least after the m_register_bases[0] ptr is + // assigned with an IOWindow, to ensure that in case of getting an interrupt + // we can access registers from that IO window range. + PCI::enable_interrupt_line(pci_address()); + enable_irq(); + reset_device(); set_status_bit(DEVICE_STATUS_ACKNOWLEDGE); @@ -158,66 +152,67 @@ UNMAP_AFTER_INIT void Device::initialize() UNMAP_AFTER_INIT VirtIO::Device::Device(PCI::DeviceIdentifier const& device_identifier) : PCI::Device(device_identifier.address()) , IRQHandler(device_identifier.interrupt_line().value()) - , m_io_base(IOAddress(PCI::get_BAR0(pci_address()) & ~1)) , m_class_name(VirtIO::determine_device_class(device_identifier)) { dbgln("{}: Found @ {}", m_class_name, pci_address()); } -auto Device::mapping_for_bar(u8 bar) -> MappedMMIO& -{ - VERIFY(m_use_mmio); - return m_mmio[bar]; -} - void Device::notify_queue(u16 queue_index) { dbgln_if(VIRTIO_DEBUG, "{}: notifying about queue change at idx: {}", m_class_name, queue_index); if (!m_notify_cfg) - out(REG_QUEUE_NOTIFY, queue_index); + base_io_window().write16(REG_QUEUE_NOTIFY, queue_index); else config_write16(*m_notify_cfg, get_queue(queue_index).notify_offset() * m_notify_multiplier, queue_index); } +auto Device::mapping_for_bar(u8 bar) -> IOWindow& +{ + VERIFY(m_use_mmio); + VERIFY(m_register_bases[bar]); + return *m_register_bases[bar]; +} + u8 Device::config_read8(Configuration const& config, u32 offset) { - return mapping_for_bar(config.bar).read(config.offset + offset); + return mapping_for_bar(config.bar).read8(config.offset + offset); } u16 Device::config_read16(Configuration const& config, u32 offset) { - return mapping_for_bar(config.bar).read(config.offset + offset); + return mapping_for_bar(config.bar).read16(config.offset + offset); } u32 Device::config_read32(Configuration const& config, u32 offset) { - return mapping_for_bar(config.bar).read(config.offset + offset); + return mapping_for_bar(config.bar).read32(config.offset + offset); } void Device::config_write8(Configuration const& config, u32 offset, u8 value) { - mapping_for_bar(config.bar).write(config.offset + offset, value); + mapping_for_bar(config.bar).write8(config.offset + offset, value); } void Device::config_write16(Configuration const& config, u32 offset, u16 value) { - mapping_for_bar(config.bar).write(config.offset + offset, value); + mapping_for_bar(config.bar).write16(config.offset + offset, value); } void Device::config_write32(Configuration const& config, u32 offset, u32 value) { - mapping_for_bar(config.bar).write(config.offset + offset, value); + mapping_for_bar(config.bar).write32(config.offset + offset, value); } void Device::config_write64(Configuration const& config, u32 offset, u64 value) { - mapping_for_bar(config.bar).write(config.offset + offset, value); + mapping_for_bar(config.bar).write32(config.offset + offset, (u32)(value & 0xFFFFFFFF)); + mapping_for_bar(config.bar).write32(config.offset + offset + 4, (u32)(value >> 32)); } u8 Device::read_status_bits() { if (!m_common_cfg) - return in(REG_DEVICE_STATUS); + return base_io_window().read8(REG_DEVICE_STATUS); return config_read8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS); } @@ -225,7 +220,7 @@ void Device::mask_status_bits(u8 status_mask) { m_status &= status_mask; if (!m_common_cfg) - out(REG_DEVICE_STATUS, m_status); + base_io_window().write8(REG_DEVICE_STATUS, m_status); else config_write8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS, m_status); } @@ -234,7 +229,7 @@ void Device::set_status_bit(u8 status_bit) { m_status |= status_bit; if (!m_common_cfg) - out(REG_DEVICE_STATUS, m_status); + base_io_window().write8(REG_DEVICE_STATUS, m_status); else config_write8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS, m_status); } @@ -242,7 +237,7 @@ void Device::set_status_bit(u8 status_bit) u64 Device::get_device_features() { if (!m_common_cfg) - return in(REG_DEVICE_FEATURES); + return base_io_window().read32(REG_DEVICE_FEATURES); config_write32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE_SELECT, 0); auto lower_bits = config_read32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE); config_write32(*m_common_cfg, COMMON_CFG_DEVICE_FEATURE_SELECT, 1); @@ -250,6 +245,12 @@ u64 Device::get_device_features() return upper_bits | lower_bits; } +IOWindow& Device::base_io_window() +{ + VERIFY(m_register_bases[0]); + return *m_register_bases[0]; +} + bool Device::accept_device_features(u64 device_features, u64 accepted_features) { VERIFY(!m_did_accept_features); @@ -277,7 +278,7 @@ bool Device::accept_device_features(u64 device_features, u64 accepted_features) dbgln_if(VIRTIO_DEBUG, "{}: Accepted features: {}", m_class_name, accepted_features); if (!m_common_cfg) { - out(REG_GUEST_FEATURES, accepted_features); + base_io_window().write32(REG_GUEST_FEATURES, accepted_features); } else { config_write32(*m_common_cfg, COMMON_CFG_DRIVER_FEATURE_SELECT, 0); config_write32(*m_common_cfg, COMMON_CFG_DRIVER_FEATURE, accepted_features); @@ -399,7 +400,7 @@ void Device::finish_init() u8 Device::isr_status() { if (!m_isr_cfg) - return in(REG_ISR_STATUS); + return base_io_window().read8(REG_ISR_STATUS); return config_read8(*m_isr_cfg, 0); } diff --git a/Kernel/Bus/VirtIO/Device.h b/Kernel/Bus/VirtIO/Device.h index 3c8fe360bc..e185f7a171 100644 --- a/Kernel/Bus/VirtIO/Device.h +++ b/Kernel/Bus/VirtIO/Device.h @@ -7,10 +7,10 @@ #pragma once #include -#include #include #include #include +#include #include #include @@ -94,30 +94,6 @@ public: protected: virtual StringView class_name() const { return "VirtIO::Device"sv; } explicit Device(PCI::DeviceIdentifier const&); - struct MappedMMIO { - OwnPtr base; - size_t size { 0 }; - - template - T read(u32 offset) const - { - if (!base) - return 0; - VERIFY(size >= sizeof(T)); - VERIFY(offset + sizeof(T) <= size); - return *(volatile T*)(base->vaddr().offset(offset).get()); - } - - template - void write(u32 offset, T value) - { - if (!base) - return; - VERIFY(size >= sizeof(T)); - VERIFY(offset + sizeof(T) <= size); - *(volatile T*)(base->vaddr().offset(offset).get()) = value; - } - }; Configuration const* get_config(ConfigurationType cfg_type, u32 index = 0) const { @@ -156,7 +132,7 @@ protected: void config_write32(Configuration const&, u32, u32); void config_write64(Configuration const&, u32, u64); - auto mapping_for_bar(u8) -> MappedMMIO&; + auto mapping_for_bar(u8) -> IOWindow&; u8 read_status_bits(); void mask_status_bits(u8 status_mask); @@ -203,18 +179,6 @@ protected: virtual void handle_queue_update(u16 queue_index) = 0; private: - template - void out(u16 address, T value) - { - m_io_base.offset(address).out(value); - } - - template - T in(u16 address) - { - return m_io_base.offset(address).in(); - } - bool accept_device_features(u64 device_features, u64 accepted_features); bool setup_queue(u16 queue_index); @@ -232,8 +196,8 @@ private: Configuration const* m_notify_cfg { nullptr }; // Cached due to high usage Configuration const* m_isr_cfg { nullptr }; // Cached due to high usage - IOAddress m_io_base; - MappedMMIO m_mmio[6]; + IOWindow& base_io_window(); + Array, 6> m_register_bases; StringView const m_class_name; diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 73661b8f9d..777086cf6f 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -84,6 +84,7 @@ set(KERNEL_SOURCES Graphics/VirtIOGPU/Console.cpp Graphics/VirtIOGPU/GPU3DDevice.cpp Graphics/VirtIOGPU/GraphicsAdapter.cpp + IOWindow.cpp SanCov.cpp Storage/ATA/AHCI/Controller.cpp Storage/ATA/AHCI/Port.cpp @@ -336,6 +337,7 @@ if ("${SERENITY_ARCH}" STREQUAL "i686" OR "${SERENITY_ARCH}" STREQUAL "x86_64") Arch/x86/ISABus/HID/VMWareMouseDevice.cpp Arch/x86/ISABus/I8042Controller.cpp Arch/x86/ISABus/IDEController.cpp + Arch/x86/ISABus/SerialDevice.cpp Arch/x86/PCI/Controller/HostBridge.cpp Arch/x86/PCI/IDELegacyModeController.cpp Arch/x86/PCI/Initializer.cpp diff --git a/Kernel/Devices/Audio/AC97.cpp b/Kernel/Devices/Audio/AC97.cpp index 7b7346979a..5ba2a33bba 100644 --- a/Kernel/Devices/Audio/AC97.cpp +++ b/Kernel/Devices/Audio/AC97.cpp @@ -23,18 +23,24 @@ static constexpr u16 pcm_sample_rate_maximum = 48000; UNMAP_AFTER_INIT ErrorOr> AC97::try_create(PCI::DeviceIdentifier const& pci_device_identifier) { - auto ac97 = adopt_nonnull_lock_ref_or_enomem(new (nothrow) AC97(pci_device_identifier)); + auto mixer_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); + auto bus_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR1)); + + auto pcm_out_channel_io_window = TRY(bus_io_window->create_from_io_window_with_offset(NativeAudioBusChannel::PCMOutChannel)); + auto pcm_out_channel = TRY(AC97Channel::create_with_parent_pci_device(pci_device_identifier.address(), "PCMOut"sv, move(pcm_out_channel_io_window))); + + auto ac97 = adopt_nonnull_lock_ref_or_enomem(new (nothrow) AC97(pci_device_identifier, move(pcm_out_channel), move(mixer_io_window), move(bus_io_window))); if (!ac97.is_error()) TRY(ac97.value()->initialize()); return ac97; } -UNMAP_AFTER_INIT AC97::AC97(PCI::DeviceIdentifier const& pci_device_identifier) +UNMAP_AFTER_INIT AC97::AC97(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr pcm_out_channel, NonnullOwnPtr mixer_io_window, NonnullOwnPtr bus_io_window) : PCI::Device(pci_device_identifier.address()) , IRQHandler(pci_device_identifier.interrupt_line().value()) - , m_io_mixer_base(PCI::get_BAR0(pci_address()) & ~1) - , m_io_bus_base(PCI::get_BAR1(pci_address()) & ~1) - , m_pcm_out_channel(channel("PCMOut"sv, NativeAudioBusChannel::PCMOutChannel)) + , m_mixer_io_window(move(mixer_io_window)) + , m_bus_io_window(move(bus_io_window)) + , m_pcm_out_channel(move(pcm_out_channel)) { } @@ -42,8 +48,7 @@ UNMAP_AFTER_INIT AC97::~AC97() = default; bool AC97::handle_irq(RegisterState const&) { - auto pcm_out_status_register = m_pcm_out_channel.reg(AC97Channel::Register::Status); - auto pcm_out_status = pcm_out_status_register.in(); + auto pcm_out_status = m_pcm_out_channel->io_window().read16(AC97Channel::Register::Status); dbgln_if(AC97_DEBUG, "AC97 @ {}: interrupt received - status: {:#05b}", pci_address(), pcm_out_status); bool is_dma_halted = (pcm_out_status & AudioStatusRegisterFlag::DMAControllerHalted) > 0; @@ -60,11 +65,11 @@ bool AC97::handle_irq(RegisterState const&) pcm_out_status = AudioStatusRegisterFlag::LastValidBufferCompletionInterrupt | AudioStatusRegisterFlag::BufferCompletionInterruptStatus | AudioStatusRegisterFlag::FIFOError; - pcm_out_status_register.out(pcm_out_status); + m_pcm_out_channel->io_window().write16(AC97Channel::Register::Status, pcm_out_status); if (is_dma_halted) { VERIFY(current_equals_last_valid); - m_pcm_out_channel.handle_dma_stopped(); + m_pcm_out_channel->handle_dma_stopped(); } if (!m_irq_queue.is_empty()) @@ -75,34 +80,33 @@ bool AC97::handle_irq(RegisterState const&) UNMAP_AFTER_INIT ErrorOr AC97::initialize() { - dbgln_if(AC97_DEBUG, "AC97 @ {}: mixer base: {:#04x}", pci_address(), m_io_mixer_base.get()); - dbgln_if(AC97_DEBUG, "AC97 @ {}: bus base: {:#04x}", pci_address(), m_io_bus_base.get()); + dbgln_if(AC97_DEBUG, "AC97 @ {}: mixer base: {:#04x}", pci_address(), m_mixer_io_window); + dbgln_if(AC97_DEBUG, "AC97 @ {}: bus base: {:#04x}", pci_address(), m_bus_io_window); // Read out AC'97 codec revision and vendor - auto extended_audio_id = m_io_mixer_base.offset(NativeAudioMixerRegister::ExtendedAudioID).in(); + auto extended_audio_id = m_mixer_io_window->read16(NativeAudioMixerRegister::ExtendedAudioID); m_codec_revision = static_cast(((extended_audio_id & ExtendedAudioMask::Revision) >> 10) & 0b11); dbgln_if(AC97_DEBUG, "AC97 @ {}: codec revision {:#02b}", pci_address(), to_underlying(m_codec_revision)); if (m_codec_revision == AC97Revision::Reserved) return ENOTSUP; // Report vendor / device ID - u32 vendor_id = m_io_mixer_base.offset(NativeAudioMixerRegister::VendorID1).in() << 16 | m_io_mixer_base.offset(NativeAudioMixerRegister::VendorID2).in(); + u32 vendor_id = m_mixer_io_window->read16(NativeAudioMixerRegister::VendorID1) << 16 | m_mixer_io_window->read16(NativeAudioMixerRegister::VendorID2); dbgln("AC97 @ {}: Vendor ID: {:#8x}", pci_address(), vendor_id); // Bus cold reset, enable interrupts enable_pin_based_interrupts(); PCI::enable_bus_mastering(pci_address()); - auto control = m_io_bus_base.offset(NativeAudioBusRegister::GlobalControl).in(); + auto control = m_bus_io_window->read32(NativeAudioBusRegister::GlobalControl); control |= GlobalControlFlag::GPIInterruptEnable; control |= GlobalControlFlag::AC97ColdReset; - m_io_bus_base.offset(NativeAudioBusRegister::GlobalControl).out(control); + m_bus_io_window->write32(NativeAudioBusRegister::GlobalControl, control); // Reset mixer - m_io_mixer_base.offset(NativeAudioMixerRegister::Reset).out(1); + m_mixer_io_window->write16(NativeAudioMixerRegister::Reset, 1); // Enable variable and double rate PCM audio if supported - auto extended_audio_status_control_register = m_io_mixer_base.offset(NativeAudioMixerRegister::ExtendedAudioStatusControl); - auto extended_audio_status = extended_audio_status_control_register.in(); + auto extended_audio_status = m_mixer_io_window->read16(NativeAudioMixerRegister::ExtendedAudioStatusControl); if ((extended_audio_id & ExtendedAudioMask::VariableRatePCMAudio) > 0) { extended_audio_status |= ExtendedAudioStatusControlFlag::VariableRateAudio; m_variable_rate_pcm_supported = true; @@ -113,7 +117,7 @@ UNMAP_AFTER_INIT ErrorOr AC97::initialize() extended_audio_status |= ExtendedAudioStatusControlFlag::DoubleRateAudio; m_double_rate_pcm_enabled = true; } - extended_audio_status_control_register.out(extended_audio_status); + m_mixer_io_window->write16(NativeAudioMixerRegister::ExtendedAudioStatusControl, extended_audio_status); TRY(set_pcm_output_sample_rate(m_variable_rate_pcm_supported ? pcm_default_sample_rate : pcm_fixed_sample_rate)); @@ -121,7 +125,7 @@ UNMAP_AFTER_INIT ErrorOr AC97::initialize() set_master_output_volume(0, 0, Muted::No); set_pcm_output_volume(0, 0, Muted::No); - m_pcm_out_channel.reset(); + m_pcm_out_channel->reset(); enable_irq(); return {}; } @@ -131,7 +135,7 @@ void AC97::set_master_output_volume(u8 left_channel, u8 right_channel, Muted mut u16 volume_value = ((right_channel & 63) << 0) | ((left_channel & 63) << 8) | ((mute == Muted::Yes ? 1 : 0) << 15); - m_io_mixer_base.offset(NativeAudioMixerRegister::SetMasterOutputVolume).out(volume_value); + m_mixer_io_window->write16(NativeAudioMixerRegister::SetMasterOutputVolume, volume_value); } ErrorOr AC97::set_pcm_output_sample_rate(u32 sample_rate) @@ -146,15 +150,14 @@ ErrorOr AC97::set_pcm_output_sample_rate(u32 sample_rate) if (shifted_sample_rate < pcm_sample_rate_minimum || shifted_sample_rate > pcm_sample_rate_maximum) return ENOTSUP; - auto pcm_front_dac_rate_register = m_io_mixer_base.offset(NativeAudioMixerRegister::PCMFrontDACRate); - pcm_front_dac_rate_register.out(shifted_sample_rate); - m_sample_rate = static_cast(pcm_front_dac_rate_register.in()) << double_rate_shift; + m_mixer_io_window->write16(NativeAudioMixerRegister::PCMFrontDACRate, shifted_sample_rate); + m_sample_rate = static_cast(m_mixer_io_window->read16(NativeAudioMixerRegister::PCMFrontDACRate)) << double_rate_shift; dbgln("AC97 @ {}: PCM front DAC rate set to {} Hz", pci_address(), m_sample_rate); // Setting the sample rate stops a running DMA engine, so restart it - if (m_pcm_out_channel.dma_running()) - m_pcm_out_channel.start_dma(); + if (m_pcm_out_channel->dma_running()) + m_pcm_out_channel->start_dma(); return {}; } @@ -164,7 +167,7 @@ void AC97::set_pcm_output_volume(u8 left_channel, u8 right_channel, Muted mute) u16 volume_value = ((right_channel & 31) << 0) | ((left_channel & 31) << 8) | ((mute == Muted::Yes ? 1 : 0) << 15); - m_io_mixer_base.offset(NativeAudioMixerRegister::SetPCMOutputVolume).out(volume_value); + m_mixer_io_window->write16(NativeAudioMixerRegister::SetPCMOutputVolume, volume_value); } LockRefPtr AC97::audio_channel(u32 index) const @@ -226,14 +229,14 @@ ErrorOr AC97::write_single_buffer(UserOrKernelBuffer const& data, size_t o // Block until we can write into an unused buffer cli(); do { - auto pcm_out_status = m_pcm_out_channel.reg(AC97Channel::Register::Status).in(); - auto current_index = m_pcm_out_channel.reg(AC97Channel::Register::CurrentIndexValue).in(); - int last_valid_index = m_pcm_out_channel.reg(AC97Channel::Register::LastValidIndex).in(); + auto pcm_out_status = m_pcm_out_channel->io_window().read16(AC97Channel::Register::Status); + auto current_index = m_pcm_out_channel->io_window().read8(AC97Channel::Register::CurrentIndexValue); + int last_valid_index = m_pcm_out_channel->io_window().read8(AC97Channel::Register::LastValidIndex); auto head_distance = last_valid_index - current_index; if (head_distance < 0) head_distance += buffer_descriptor_list_max_entries; - if (m_pcm_out_channel.dma_running()) + if (m_pcm_out_channel->dma_running()) ++head_distance; // Current index has _passed_ last valid index - move our list index up @@ -248,7 +251,7 @@ ErrorOr AC97::write_single_buffer(UserOrKernelBuffer const& data, size_t o dbgln_if(AC97_DEBUG, "AC97 @ {}: waiting on interrupt - status: {:#05b} CI: {} LVI: {}", pci_address(), pcm_out_status, current_index, last_valid_index); m_irq_queue.wait_forever("AC97"sv); - } while (m_pcm_out_channel.dma_running()); + } while (m_pcm_out_channel->dma_running()); sti(); // Copy data from userspace into one of our buffers @@ -262,10 +265,10 @@ ErrorOr AC97::write_single_buffer(UserOrKernelBuffer const& data, size_t o list_entry->control_and_length = number_of_samples | BufferDescriptorListEntryFlags::InterruptOnCompletion; auto buffer_address = static_cast(m_buffer_descriptor_list->physical_page(0)->paddr().get()); - m_pcm_out_channel.set_last_valid_index(buffer_address, m_buffer_descriptor_list_index); + m_pcm_out_channel->set_last_valid_index(buffer_address, m_buffer_descriptor_list_index); - if (!m_pcm_out_channel.dma_running()) - m_pcm_out_channel.start_dma(); + if (!m_pcm_out_channel->dma_running()) + m_pcm_out_channel->start_dma(); m_output_buffer_page_index = (m_output_buffer_page_index + 1) % m_output_buffer_page_count; m_buffer_descriptor_list_index = (m_buffer_descriptor_list_index + 1) % buffer_descriptor_list_max_entries; @@ -273,25 +276,29 @@ ErrorOr AC97::write_single_buffer(UserOrKernelBuffer const& data, size_t o return {}; } +ErrorOr> AC97::AC97Channel::create_with_parent_pci_device(PCI::Address pci_device_address, StringView name, NonnullOwnPtr channel_io_base) +{ + return adopt_nonnull_own_or_enomem(new (nothrow) AC97::AC97Channel(pci_device_address, name, move(channel_io_base))); +} + void AC97::AC97Channel::handle_dma_stopped() { - dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: DMA engine has stopped", m_device.pci_address(), name()); + dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: DMA engine has stopped", m_device_pci_address, name()); m_dma_running.with([this](auto& dma_running) { // NOTE: QEMU might send spurious interrupts while we're not running, so we don't want to panic here. if (!dma_running) - dbgln("AC97 @ {}: received DMA interrupt while it wasn't running", m_device.pci_address()); + dbgln("AC97 @ {}: received DMA interrupt while it wasn't running", m_device_pci_address); dma_running = false; }); } void AC97::AC97Channel::reset() { - dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: resetting", m_device.pci_address(), name()); + dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: resetting", m_device_pci_address, name()); - auto control_register = reg(Register::Control); - control_register.out(AudioControlRegisterFlag::ResetRegisters); + m_channel_io_window->write8(Register::Control, AudioControlRegisterFlag::ResetRegisters); - while ((control_register.in() & AudioControlRegisterFlag::ResetRegisters) > 0) + while ((m_channel_io_window->read8(Register::Control) & AudioControlRegisterFlag::ResetRegisters) > 0) microseconds_delay(50); m_dma_running.with([](auto& dma_running) { @@ -301,22 +308,21 @@ void AC97::AC97Channel::reset() void AC97::AC97Channel::set_last_valid_index(u32 buffer_address, u8 last_valid_index) { - dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: setting buffer address: {:#x} LVI: {}", m_device.pci_address(), name(), buffer_address, last_valid_index); + dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: setting buffer address: {:#x} LVI: {}", m_device_pci_address, name(), buffer_address, last_valid_index); - reg(Register::BufferDescriptorListBaseAddress).out(buffer_address); - reg(Register::LastValidIndex).out(last_valid_index); + m_channel_io_window->write32(Register::BufferDescriptorListBaseAddress, buffer_address); + m_channel_io_window->write8(Register::LastValidIndex, last_valid_index); } void AC97::AC97Channel::start_dma() { - dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: starting DMA engine", m_device.pci_address(), name()); + dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: starting DMA engine", m_device_pci_address, name()); - auto control_register = reg(Register::Control); - auto control = control_register.in(); + auto control = m_channel_io_window->read8(Register::Control); control |= AudioControlRegisterFlag::RunPauseBusMaster; control |= AudioControlRegisterFlag::FIFOErrorInterruptEnable; control |= AudioControlRegisterFlag::InterruptOnCompletionEnable; - control_register.out(control); + m_channel_io_window->write8(Register::Control, control); m_dma_running.with([](auto& dma_running) { dma_running = true; diff --git a/Kernel/Devices/Audio/AC97.h b/Kernel/Devices/Audio/AC97.h index 31655ecd45..9ad53a8d18 100644 --- a/Kernel/Devices/Audio/AC97.h +++ b/Kernel/Devices/Audio/AC97.h @@ -7,11 +7,11 @@ #pragma once #include -#include #include #include #include #include +#include #include #include @@ -123,12 +123,7 @@ private: Control = 0x0b, }; - AC97Channel(AC97& device, StringView name, IOAddress channel_base) - : m_channel_base(channel_base) - , m_device(device) - , m_name(name) - { - } + static ErrorOr> create_with_parent_pci_device(PCI::Address pci_device_address, StringView name, NonnullOwnPtr channel_io_base); bool dma_running() const { @@ -136,24 +131,31 @@ private: } void handle_dma_stopped(); StringView name() const { return m_name; } - IOAddress reg(Register reg) const { return m_channel_base.offset(reg); } void reset(); void set_last_valid_index(u32 buffer_address, u8 last_valid_index); void start_dma(); + IOWindow& io_window() { return *m_channel_io_window; } + private: - IOAddress m_channel_base; - AC97& m_device; + AC97Channel(PCI::Address pci_device_address, StringView name, NonnullOwnPtr channel_io_base) + : m_channel_io_window(move(channel_io_base)) + , m_device_pci_address(pci_device_address) + , m_name(name) + { + } + + NonnullOwnPtr m_channel_io_window; + PCI::Address m_device_pci_address; SpinlockProtected m_dma_running { LockRank::None, false }; StringView m_name; }; - explicit AC97(PCI::DeviceIdentifier const&); + AC97(PCI::DeviceIdentifier const&, NonnullOwnPtr pcm_out_channel, NonnullOwnPtr mixer_io_window, NonnullOwnPtr bus_io_window); // ^IRQHandler virtual bool handle_irq(RegisterState const&) override; - AC97Channel channel(StringView name, NativeAudioBusChannel channel) { return AC97Channel(*this, name, m_io_bus_base.offset(channel)); } ErrorOr initialize(); void set_master_output_volume(u8, u8, Muted); ErrorOr set_pcm_output_sample_rate(u32); @@ -171,13 +173,13 @@ private: u8 m_buffer_descriptor_list_index { 0 }; AC97Revision m_codec_revision { AC97Revision::Revision21OrEarlier }; bool m_double_rate_pcm_enabled { false }; - IOAddress m_io_mixer_base; - IOAddress m_io_bus_base; + NonnullOwnPtr m_mixer_io_window; + NonnullOwnPtr m_bus_io_window; WaitQueue m_irq_queue; OwnPtr m_output_buffer; u8 m_output_buffer_page_count { 4 }; u8 m_output_buffer_page_index { 0 }; - AC97Channel m_pcm_out_channel; + NonnullOwnPtr m_pcm_out_channel; u32 m_sample_rate { 0 }; bool m_variable_rate_pcm_supported { false }; LockRefPtr m_audio_channel; diff --git a/Kernel/Devices/PCISerialDevice.cpp b/Kernel/Devices/PCISerialDevice.cpp index 32c5905dd6..c649dc37ab 100644 --- a/Kernel/Devices/PCISerialDevice.cpp +++ b/Kernel/Devices/PCISerialDevice.cpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace Kernel { @@ -20,10 +21,12 @@ UNMAP_AFTER_INIT void PCISerialDevice::detect() if (board_definition.device_id != device_identifier.hardware_id()) continue; - auto bar_base = PCI::get_BAR(device_identifier.address(), static_cast(board_definition.pci_bar)) & ~1; - auto port_base = IOAddress(bar_base + board_definition.first_offset); + auto registers_io_window = IOWindow::create_for_pci_device_bar(device_identifier, static_cast(board_definition.pci_bar)).release_value_but_fixme_should_propagate_errors(); + auto first_offset_registers_io_window = registers_io_window->create_from_io_window_with_offset(board_definition.first_offset).release_value_but_fixme_should_propagate_errors(); + for (size_t i = 0; i < board_definition.port_count; i++) { - auto serial_device = new SerialDevice(port_base.offset(board_definition.port_size * i), current_device_minor++); + auto port_registers_io_window = first_offset_registers_io_window->create_from_io_window_with_offset(board_definition.port_size * i).release_value_but_fixme_should_propagate_errors(); + auto serial_device = new SerialDevice(move(port_registers_io_window), current_device_minor++); if (board_definition.baud_rate != SerialDevice::Baud::Baud38400) // non-default baud serial_device->set_baud(board_definition.baud_rate); diff --git a/Kernel/Devices/SerialDevice.cpp b/Kernel/Devices/SerialDevice.cpp index b32b5a79dc..ea5ac24cf3 100644 --- a/Kernel/Devices/SerialDevice.cpp +++ b/Kernel/Devices/SerialDevice.cpp @@ -5,49 +5,16 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include #include #include +#include #include namespace Kernel { -#define SERIAL_COM1_ADDR 0x3F8 -#define SERIAL_COM2_ADDR 0x2F8 -#define SERIAL_COM3_ADDR 0x3E8 -#define SERIAL_COM4_ADDR 0x2E8 - -UNMAP_AFTER_INIT NonnullLockRefPtr SerialDevice::must_create(size_t com_number) -{ - // FIXME: This way of blindly doing release_value is really not a good thing, find - // a way to propagate errors back. - LockRefPtr serial_device; - switch (com_number) { - case 0: { - serial_device = DeviceManagement::try_create_device(IOAddress(SERIAL_COM1_ADDR), 64).release_value(); - break; - } - case 1: { - serial_device = DeviceManagement::try_create_device(IOAddress(SERIAL_COM2_ADDR), 65).release_value(); - break; - } - case 2: { - serial_device = DeviceManagement::try_create_device(IOAddress(SERIAL_COM3_ADDR), 66).release_value(); - break; - } - case 3: { - serial_device = DeviceManagement::try_create_device(IOAddress(SERIAL_COM4_ADDR), 67).release_value(); - break; - } - default: - break; - } - return serial_device.release_nonnull(); -} - -UNMAP_AFTER_INIT SerialDevice::SerialDevice(IOAddress base_addr, unsigned minor) +UNMAP_AFTER_INIT SerialDevice::SerialDevice(NonnullOwnPtr registers_io_window, unsigned minor) : CharacterDevice(4, minor) - , m_base_addr(base_addr) + , m_registers_io_window(move(registers_io_window)) { initialize(); } @@ -70,7 +37,7 @@ ErrorOr SerialDevice::read(OpenFileDescription&, u64, UserOrKernelBuffer return buffer.write_buffered<128>(size, [&](Bytes bytes) { for (auto& byte : bytes) - byte = m_base_addr.in(); + byte = m_registers_io_window->read8(0); return bytes.size(); }); } @@ -102,9 +69,9 @@ void SerialDevice::put_char(char ch) ; if (ch == '\n' && !m_last_put_char_was_carriage_return) - m_base_addr.out('\r'); + m_registers_io_window->write8(0, '\r'); - m_base_addr.out(ch); + m_registers_io_window->write8(0, ch); m_last_put_char_was_carriage_return = (ch == '\r'); } @@ -122,24 +89,23 @@ UNMAP_AFTER_INIT void SerialDevice::set_interrupts(bool interrupt_enable) { m_interrupt_enable = interrupt_enable; - m_base_addr.offset(1).out(interrupt_enable); + m_registers_io_window->write8(1, interrupt_enable); } void SerialDevice::set_baud(Baud baud) { m_baud = baud; - m_base_addr.offset(3).out(m_base_addr.offset(3).in() | 0x80); // turn on DLAB - m_base_addr.out(((u8)(baud)) & 0xff); // lower half of divisor - m_base_addr.offset(1).out(((u8)(baud)) >> 2); // upper half of divisor - m_base_addr.offset(3).out(m_base_addr.offset(3).in() & 0x7f); // turn off DLAB + m_registers_io_window->write8(3, m_registers_io_window->read8(3) | 0x80); // turn on DLAB + m_registers_io_window->write8(0, ((u8)(baud)) & 0xff); // lower half of divisor + m_registers_io_window->write8(1, ((u8)(baud)) >> 2); // lower half of divisor + m_registers_io_window->write8(3, m_registers_io_window->read8(3) & 0x7f); // turn off DLAB } void SerialDevice::set_fifo_control(u8 fifo_control) { m_fifo_control = fifo_control; - - m_base_addr.offset(2).out(fifo_control); + m_registers_io_window->write8(2, fifo_control); } void SerialDevice::set_line_control(ParitySelect parity_select, StopBits stop_bits, WordLength word_length) @@ -148,26 +114,26 @@ void SerialDevice::set_line_control(ParitySelect parity_select, StopBits stop_bi m_stop_bits = stop_bits; m_word_length = word_length; - m_base_addr.offset(3).out((m_base_addr.offset(3).in() & ~0x3f) | parity_select | stop_bits | word_length); + m_registers_io_window->write8(3, (m_registers_io_window->read8(3) & ~0x3f) | parity_select | stop_bits | word_length); } void SerialDevice::set_break_enable(bool break_enable) { m_break_enable = break_enable; - m_base_addr.offset(3).out(m_base_addr.offset(3).in() & (break_enable ? 0xff : 0xbf)); + m_registers_io_window->write8(3, m_registers_io_window->read8(3) & (break_enable ? 0xff : 0xbf)); } void SerialDevice::set_modem_control(u8 modem_control) { m_modem_control = modem_control; - m_base_addr.offset(4).out(modem_control); + m_registers_io_window->write8(4, modem_control); } u8 SerialDevice::get_line_status() const { - return m_base_addr.offset(5).in(); + return m_registers_io_window->read8(5); } } diff --git a/Kernel/Devices/SerialDevice.h b/Kernel/Devices/SerialDevice.h index ef724522f5..11448aca61 100644 --- a/Kernel/Devices/SerialDevice.h +++ b/Kernel/Devices/SerialDevice.h @@ -6,8 +6,8 @@ #pragma once -#include #include +#include namespace Kernel { @@ -104,7 +104,7 @@ public: }; private: - SerialDevice(IOAddress base_addr, unsigned minor); + SerialDevice(NonnullOwnPtr registers_io_window, unsigned minor); friend class PCISerialDevice; @@ -120,7 +120,7 @@ private: void set_modem_control(u8 modem_control); u8 get_line_status() const; - IOAddress m_base_addr; + mutable NonnullOwnPtr m_registers_io_window; bool m_interrupt_enable { false }; u8 m_fifo_control { 0 }; Baud m_baud { Baud38400 }; diff --git a/Kernel/Firmware/ACPI/Parser.cpp b/Kernel/Firmware/ACPI/Parser.cpp index 0afc5ce03d..b9cd91f41a 100644 --- a/Kernel/Firmware/ACPI/Parser.cpp +++ b/Kernel/Firmware/ACPI/Parser.cpp @@ -7,10 +7,13 @@ */ #include +#include #include #include #include -#include +#if ARCH(I386) || ARCH(X86_64) +# include +#endif #include #include #include @@ -216,6 +219,7 @@ void Parser::access_generic_address(Structures::GenericAddressStructure const& s { switch ((GenericAddressStructure::AddressSpace)structure.address_space) { case GenericAddressStructure::AddressSpace::SystemIO: { +#if ARCH(I386) || ARCH(X86_64) IOAddress address(structure.address); dbgln("ACPI: Sending value {:x} to {}", value, address); switch (structure.access_size) { @@ -236,6 +240,7 @@ void Parser::access_generic_address(Structures::GenericAddressStructure const& s address.out(value, (8 << (structure.access_size - 1))); break; } +#endif return; } case GenericAddressStructure::AddressSpace::SystemMemory: { diff --git a/Kernel/Graphics/VMWare/GraphicsAdapter.cpp b/Kernel/Graphics/VMWare/GraphicsAdapter.cpp index a7a7b19646..ceddafb8ef 100644 --- a/Kernel/Graphics/VMWare/GraphicsAdapter.cpp +++ b/Kernel/Graphics/VMWare/GraphicsAdapter.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -27,29 +28,30 @@ UNMAP_AFTER_INIT LockRefPtr VMWareGraphicsAdapter::try_in // Note: We only support VMWare SVGA II adapter if (id.device_id != 0x0405) return {}; - auto adapter = MUST(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VMWareGraphicsAdapter(pci_device_identifier))); + auto registers_io_window = MUST(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); + auto adapter = MUST(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VMWareGraphicsAdapter(pci_device_identifier, move(registers_io_window)))); MUST(adapter->initialize_adapter()); return adapter; } -UNMAP_AFTER_INIT VMWareGraphicsAdapter::VMWareGraphicsAdapter(PCI::DeviceIdentifier const& pci_device_identifier) +UNMAP_AFTER_INIT VMWareGraphicsAdapter::VMWareGraphicsAdapter(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr registers_io_window) : PCI::Device(pci_device_identifier.address()) - , m_io_registers_base(PCI::get_BAR0(pci_device_identifier.address()) & 0xfffffff0) + , m_registers_io_window(move(registers_io_window)) { - dbgln("VMWare SVGA @ {}, {}", pci_device_identifier.address(), m_io_registers_base); + dbgln("VMWare SVGA @ {}, {}", pci_device_identifier.address(), m_registers_io_window); } u32 VMWareGraphicsAdapter::read_io_register(VMWareDisplayRegistersOffset register_offset) const { SpinlockLocker locker(m_io_access_lock); - m_io_registers_base.out(to_underlying(register_offset)); - return m_io_registers_base.offset(1).in(); + m_registers_io_window->write32(0, to_underlying(register_offset)); + return m_registers_io_window->read32_unaligned(1); } void VMWareGraphicsAdapter::write_io_register(VMWareDisplayRegistersOffset register_offset, u32 value) { SpinlockLocker locker(m_io_access_lock); - m_io_registers_base.out(to_underlying(register_offset)); - m_io_registers_base.offset(1).out(value); + m_registers_io_window->write32(0, to_underlying(register_offset)); + m_registers_io_window->write32_unaligned(1, value); } UNMAP_AFTER_INIT ErrorOr VMWareGraphicsAdapter::negotiate_device_version() diff --git a/Kernel/Graphics/VMWare/GraphicsAdapter.h b/Kernel/Graphics/VMWare/GraphicsAdapter.h index 8872e992a9..ae27a30d25 100644 --- a/Kernel/Graphics/VMWare/GraphicsAdapter.h +++ b/Kernel/Graphics/VMWare/GraphicsAdapter.h @@ -7,10 +7,10 @@ #pragma once #include -#include #include #include #include +#include #include #include #include @@ -46,11 +46,11 @@ private: void print_svga_capabilities() const; void modeset_primary_screen_resolution(size_t width, size_t height); - explicit VMWareGraphicsAdapter(PCI::DeviceIdentifier const&); + VMWareGraphicsAdapter(PCI::DeviceIdentifier const&, NonnullOwnPtr registers_io_window); Memory::TypedMapping m_fifo_registers; LockRefPtr m_display_connector; - const IOAddress m_io_registers_base; + mutable NonnullOwnPtr m_registers_io_window; mutable Spinlock m_io_access_lock { LockRank::None }; mutable RecursiveSpinlock m_operation_lock { LockRank::None }; }; diff --git a/Kernel/IOWindow.cpp b/Kernel/IOWindow.cpp new file mode 100644 index 0000000000..fd0920d78c --- /dev/null +++ b/Kernel/IOWindow.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Kernel { + +#if ARCH(I386) || ARCH(X86_64) +ErrorOr> IOWindow::create_for_io_space(IOAddress address, u64 space_length) +{ + VERIFY(!Checked::addition_would_overflow(address.get(), space_length)); + auto io_address_range = TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOAddressData(address.get(), space_length))); + return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(io_address_range)))); +} + +IOWindow::IOWindow(NonnullOwnPtr io_range) + : m_space_type(SpaceType::IO) + , m_io_range(move(io_range)) +{ +} +#endif + +ErrorOr> IOWindow::create_from_io_window_with_offset(u64 offset, u64 space_length) +{ +#if ARCH(I386) || ARCH(X86_64) + if (m_space_type == SpaceType::IO) { + VERIFY(m_io_range); + if (Checked::addition_would_overflow(m_io_range->address(), space_length)) + return Error::from_errno(EOVERFLOW); + auto io_address_range = TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOAddressData(as_io_address().offset(offset).get(), space_length))); + return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(io_address_range)))); + } +#endif + VERIFY(space_type() == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + +// Note: x86-IA32 is the only 32 bit CPU architecture currently being supported and +// probably will be the only such in the foreseeable future. +#if ARCH(I386) + if (Checked::addition_would_overflow(m_memory_mapped_range->paddr.get(), offset)) + return Error::from_errno(EOVERFLOW); + if (Checked::addition_would_overflow(m_memory_mapped_range->paddr.get() + offset, space_length)) + return Error::from_errno(EOVERFLOW); +#else + if (Checked::addition_would_overflow(m_memory_mapped_range->paddr.get(), offset)) + return Error::from_errno(EOVERFLOW); + if (Checked::addition_would_overflow(m_memory_mapped_range->paddr.get() + offset, space_length)) + return Error::from_errno(EOVERFLOW); +#endif + + auto memory_mapped_range = TRY(Memory::adopt_new_nonnull_own_typed_mapping(m_memory_mapped_range->paddr.offset(offset), space_length, Memory::Region::Access::ReadWrite)); + return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(memory_mapped_range)))); +} + +ErrorOr> IOWindow::create_from_io_window_with_offset(u64 offset) +{ + +#if ARCH(I386) || ARCH(X86_64) + if (m_space_type == SpaceType::IO) { + VERIFY(m_io_range); + VERIFY(m_io_range->space_length() >= offset); + return create_from_io_window_with_offset(offset, m_io_range->space_length() - offset); + } +#endif + VERIFY(space_type() == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + VERIFY(m_memory_mapped_range->length >= offset); + return create_from_io_window_with_offset(offset, m_memory_mapped_range->length - offset); +} + +ErrorOr> IOWindow::create_for_pci_device_bar(PCI::Address const& pci_address, PCI::HeaderType0BaseRegister pci_bar, u64 space_length) +{ + u64 pci_bar_value = PCI::get_BAR(pci_address, pci_bar); + auto pci_bar_space_type = PCI::get_BAR_space_type(pci_bar_value); + if (pci_bar_space_type == PCI::BARSpaceType::Memory64BitSpace) { + // FIXME: In theory, BAR5 cannot be assigned to 64 bit as it is the last one... + // however, there might be 64 bit BAR5 for real bare metal hardware, so remove this + // if it makes a problem. + if (pci_bar == PCI::HeaderType0BaseRegister::BAR5) { + return Error::from_errno(EINVAL); + } + u64 next_pci_bar_value = PCI::get_BAR(pci_address, static_cast(to_underlying(pci_bar) + 1)); + pci_bar_value |= next_pci_bar_value << 32; + } + + auto pci_bar_space_size = PCI::get_BAR_space_size(pci_address, pci_bar); + if (pci_bar_space_size < space_length) + return Error::from_errno(EIO); + + if (pci_bar_space_type == PCI::BARSpaceType::IOSpace) { +#if ARCH(I386) || ARCH(X86_64) + if (Checked::addition_would_overflow(pci_bar_value, space_length)) + return Error::from_errno(EOVERFLOW); + auto io_address_range = TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOAddressData((pci_bar_value & 0xfffffffc), space_length))); + return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(io_address_range)))); +#else + // Note: For non-x86 platforms, IO PCI BARs are simply not useable. + return Error::from_errno(ENOTSUP); +#endif + } + + if (pci_bar_space_type == PCI::BARSpaceType::Memory32BitSpace && Checked::addition_would_overflow(pci_bar_value, space_length)) + return Error::from_errno(EOVERFLOW); + if (pci_bar_space_type == PCI::BARSpaceType::Memory16BitSpace && Checked::addition_would_overflow(pci_bar_value, space_length)) + return Error::from_errno(EOVERFLOW); + if (pci_bar_space_type == PCI::BARSpaceType::Memory64BitSpace && Checked::addition_would_overflow(pci_bar_value, space_length)) + return Error::from_errno(EOVERFLOW); + auto memory_mapped_range = TRY(Memory::adopt_new_nonnull_own_typed_mapping(PhysicalAddress(pci_bar_value & 0xfffffff0), space_length, Memory::Region::Access::ReadWrite)); + return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(memory_mapped_range)))); +} + +ErrorOr> IOWindow::create_for_pci_device_bar(PCI::Address const& pci_address, PCI::HeaderType0BaseRegister pci_bar) +{ + u64 pci_bar_space_size = PCI::get_BAR_space_size(pci_address, pci_bar); + return create_for_pci_device_bar(pci_address, pci_bar, pci_bar_space_size); +} + +ErrorOr> IOWindow::create_for_pci_device_bar(PCI::DeviceIdentifier const& pci_device_identifier, PCI::HeaderType0BaseRegister pci_bar) +{ + u64 pci_bar_space_size = PCI::get_BAR_space_size(pci_device_identifier.address(), pci_bar); + return create_for_pci_device_bar(pci_device_identifier.address(), pci_bar, pci_bar_space_size); +} + +ErrorOr> IOWindow::create_for_pci_device_bar(PCI::DeviceIdentifier const& pci_device_identifier, PCI::HeaderType0BaseRegister pci_bar, u64 space_length) +{ + return create_for_pci_device_bar(pci_device_identifier.address(), pci_bar, space_length); +} + +IOWindow::IOWindow(NonnullOwnPtr> memory_mapped_range) + : m_space_type(SpaceType::Memory) + , m_memory_mapped_range(move(memory_mapped_range)) +{ +} + +IOWindow::~IOWindow() = default; + +bool IOWindow::is_access_aligned(u64 offset, size_t byte_size_access) const +{ + return (offset % byte_size_access) == 0; +} + +bool IOWindow::is_access_in_range(u64 offset, size_t byte_size_access) const +{ + if (Checked::addition_would_overflow(offset, byte_size_access)) + return false; +#if ARCH(I386) || ARCH(X86_64) + if (m_space_type == SpaceType::IO) { + VERIFY(m_io_range); + VERIFY(!Checked::addition_would_overflow(m_io_range->address(), m_io_range->space_length())); + // To understand how we treat IO address space with the corresponding calculation, the Intel Software Developer manual + // helps us to understand the layout of the IO address space - + // + // Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture, 16.3 I/O ADDRESS SPACE, page 16-1 wrote: + // Any two consecutive 8-bit ports can be treated as a 16-bit port, and any four consecutive ports can be a 32-bit port. + // In this manner, the processor can transfer 8, 16, or 32 bits to or from a device in the I/O address space. + // Like words in memory, 16-bit ports should be aligned to even addresses (0, 2, 4, ...) so that all 16 bits can be transferred in a single bus cycle. + // Likewise, 32-bit ports should be aligned to addresses that are multiples of four (0, 4, 8, ...). + // The processor supports data transfers to unaligned ports, but there is a performance penalty because one or more + // extra bus cycle must be used. + return (m_io_range->address() + m_io_range->space_length()) >= (offset + byte_size_access); + } +#endif + VERIFY(space_type() == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + VERIFY(!Checked::addition_would_overflow(m_memory_mapped_range->offset, m_memory_mapped_range->length)); + return (m_memory_mapped_range->offset + m_memory_mapped_range->length) >= (offset + byte_size_access); +} + +u8 IOWindow::read8(u64 offset) +{ + VERIFY(is_access_in_range(offset, sizeof(u8))); + u8 data { 0 }; + in(offset, data); + return data; +} +u16 IOWindow::read16(u64 offset) +{ + // Note: Although it might be OK to allow unaligned access on regular memory, + // for memory mapped IO access, it should always be considered a bug. + // The same goes for port mapped IO access, because in x86 unaligned access to ports + // is possible but there's a performance penalty. + VERIFY(is_access_in_range(offset, sizeof(u16))); + VERIFY(is_access_aligned(offset, sizeof(u16))); + u16 data { 0 }; + in(offset, data); + return data; +} +u32 IOWindow::read32(u64 offset) +{ + // Note: Although it might be OK to allow unaligned access on regular memory, + // for memory mapped IO access, it should always be considered a bug. + // The same goes for port mapped IO access, because in x86 unaligned access to ports + // is possible but there's a performance penalty. + VERIFY(is_access_in_range(offset, sizeof(u32))); + VERIFY(is_access_aligned(offset, sizeof(u32))); + u32 data { 0 }; + in(offset, data); + return data; +} + +void IOWindow::write8(u64 offset, u8 data) +{ + VERIFY(is_access_in_range(offset, sizeof(u8))); + out(offset, data); +} +void IOWindow::write16(u64 offset, u16 data) +{ + // Note: Although it might be OK to allow unaligned access on regular memory, + // for memory mapped IO access, it should always be considered a bug. + // The same goes for port mapped IO access, because in x86 unaligned access to ports + // is possible but there's a performance penalty. + VERIFY(is_access_in_range(offset, sizeof(u16))); + VERIFY(is_access_aligned(offset, sizeof(u16))); + out(offset, data); +} +void IOWindow::write32(u64 offset, u32 data) +{ + // Note: Although it might be OK to allow unaligned access on regular memory, + // for memory mapped IO access, it should always be considered a bug. + // The same goes for port mapped IO access, because in x86 unaligned access to ports + // is possible but there's a performance penalty. + VERIFY(is_access_in_range(offset, sizeof(u32))); + VERIFY(is_access_aligned(offset, sizeof(u32))); + out(offset, data); +} + +void IOWindow::write32_unaligned(u64 offset, u32 data) +{ + // Note: We only verify that we access IO in the expected range. + // Note: for port mapped IO access, because in x86 unaligned access to ports + // is possible but there's a performance penalty, we can still allow that to happen. + // However, it should be noted that most cases should not use unaligned access + // to hardware IO, so this is a valid case in emulators or hypervisors only. + // Note: Using this for memory mapped IO will fail for unaligned access, because + // there's no valid use case for it (yet). + VERIFY(space_type() != SpaceType::Memory); + VERIFY(is_access_in_range(offset, sizeof(u32))); + out(offset, data); +} + +u32 IOWindow::read32_unaligned(u64 offset) +{ + // Note: We only verify that we access IO in the expected range. + // Note: for port mapped IO access, because in x86 unaligned access to ports + // is possible but there's a performance penalty, we can still allow that to happen. + // However, it should be noted that most cases should not use unaligned access + // to hardware IO, so this is a valid case in emulators or hypervisors only. + // Note: Using this for memory mapped IO will fail for unaligned access, because + // there's no valid use case for it (yet). + VERIFY(space_type() != SpaceType::Memory); + VERIFY(is_access_in_range(offset, sizeof(u32))); + u32 data { 0 }; + in(offset, data); + return data; +} + +PhysicalAddress IOWindow::as_physical_memory_address() const +{ + VERIFY(space_type() == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + return m_memory_mapped_range->paddr; +} + +u8 volatile* IOWindow::as_memory_address_pointer() +{ + VERIFY(space_type() == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + return m_memory_mapped_range->ptr(); +} + +#if ARCH(I386) || ARCH(X86_64) +IOAddress IOWindow::as_io_address() const +{ + VERIFY(space_type() == SpaceType::IO); + VERIFY(m_io_range); + return IOAddress(m_io_range->address()); +} +#endif + +} diff --git a/Kernel/IOWindow.h b/Kernel/IOWindow.h new file mode 100644 index 0000000000..89927f2b01 --- /dev/null +++ b/Kernel/IOWindow.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#if ARCH(I386) || ARCH(X86_64) +# include +#endif +#include +#include +#include + +namespace Kernel { + +class IOWindow { +public: + enum class SpaceType { +#if ARCH(I386) || ARCH(X86_64) + IO, +#endif + Memory, + }; + + SpaceType space_type() const { return m_space_type; } + + template + void write(); + +#if ARCH(I386) || ARCH(X86_64) + static ErrorOr> create_for_io_space(IOAddress, u64 space_length); +#endif + static ErrorOr> create_for_pci_device_bar(PCI::DeviceIdentifier const&, PCI::HeaderType0BaseRegister, u64 space_length); + static ErrorOr> create_for_pci_device_bar(PCI::DeviceIdentifier const&, PCI::HeaderType0BaseRegister); + + static ErrorOr> create_for_pci_device_bar(PCI::Address const&, PCI::HeaderType0BaseRegister, u64 space_length); + static ErrorOr> create_for_pci_device_bar(PCI::Address const&, PCI::HeaderType0BaseRegister); + + ErrorOr> create_from_io_window_with_offset(u64 offset, u64 space_length); + ErrorOr> create_from_io_window_with_offset(u64 offset); + + bool is_access_valid(u64 offset, size_t byte_size_access) const; + + u8 read8(u64 offset); + u16 read16(u64 offset); + u32 read32(u64 offset); + + void write8(u64 offset, u8); + void write16(u64 offset, u16); + void write32(u64 offset, u32); + + // Note: These methods are useful in exceptional cases where we need to do unaligned + // access. This mostly happens on emulators and hypervisors (such as VMWare) because they don't enforce aligned access + // to IO and sometimes even require such access, so we have to use these functions. + void write32_unaligned(u64 offset, u32); + u32 read32_unaligned(u64 offset); + + bool operator==(IOWindow const& other) const = delete; + bool operator!=(IOWindow const& other) const = delete; + bool operator>(IOWindow const& other) const = delete; + bool operator>=(IOWindow const& other) const = delete; + bool operator<(IOWindow const& other) const = delete; + bool operator<=(IOWindow const& other) const = delete; + + ~IOWindow(); + + PhysicalAddress as_physical_memory_address() const; +#if ARCH(I386) || ARCH(X86_64) + IOAddress as_io_address() const; +#endif + +private: + explicit IOWindow(NonnullOwnPtr>); + + u8 volatile* as_memory_address_pointer(); + +#if ARCH(I386) || ARCH(X86_64) + struct IOAddressData { + public: + IOAddressData(u64 address, u64 space_length) + : m_address(address) + , m_space_length(space_length) + { + } + u64 address() const { return m_address; } + u64 space_length() const { return m_space_length; } + + private: + u64 m_address { 0 }; + u64 m_space_length { 0 }; + }; + + explicit IOWindow(NonnullOwnPtr); +#endif + + bool is_access_in_range(u64 offset, size_t byte_size_access) const; + bool is_access_aligned(u64 offset, size_t byte_size_access) const; + + template + ALWAYS_INLINE void in(u64 start_offset, T& data) + { +#if ARCH(I386) || ARCH(X86_64) + if (m_space_type == SpaceType::IO) { + data = as_io_address().offset(start_offset).in(); + return; + } +#endif + VERIFY(m_space_type == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + // Note: For memory-mapped IO we simply never allow unaligned access as it + // can cause problems with strict bare metal hardware. For example, some XHCI USB controllers + // might completely lock up because of an unaligned memory access to their registers. + VERIFY((start_offset % sizeof(T)) == 0); + data = *(volatile T*)(as_memory_address_pointer() + start_offset); + } + + template + ALWAYS_INLINE void out(u64 start_offset, T value) + { +#if ARCH(I386) || ARCH(X86_64) + if (m_space_type == SpaceType::IO) { + VERIFY(m_io_range); + as_io_address().offset(start_offset).out(value); + return; + } +#endif + VERIFY(m_space_type == SpaceType::Memory); + VERIFY(m_memory_mapped_range); + // Note: For memory-mapped IO we simply never allow unaligned access as it + // can cause problems with strict bare metal hardware. For example, some XHCI USB controllers + // might completely lock up because of an unaligned memory access to their registers. + VERIFY((start_offset % sizeof(T)) == 0); + *(volatile T*)(as_memory_address_pointer() + start_offset) = value; + } + + SpaceType m_space_type { SpaceType::Memory }; + + OwnPtr> m_memory_mapped_range; + +#if ARCH(I386) || ARCH(X86_64) + OwnPtr m_io_range; +#endif +}; + +} + +template<> +struct AK::Formatter : AK::Formatter { + ErrorOr format(FormatBuilder& builder, Kernel::IOWindow const& value) + { +#if ARCH(I386) || ARCH(X86_64) + if (value.space_type() == Kernel::IOWindow::SpaceType::IO) + return Formatter::format(builder, "{}"sv, value.as_io_address()); +#endif + VERIFY(value.space_type() == Kernel::IOWindow::SpaceType::Memory); + return Formatter::format(builder, "Memory {}"sv, value.as_physical_memory_address()); + } +}; diff --git a/Kernel/Memory/TypedMapping.h b/Kernel/Memory/TypedMapping.h index 033d346473..4412357579 100644 --- a/Kernel/Memory/TypedMapping.h +++ b/Kernel/Memory/TypedMapping.h @@ -23,7 +23,9 @@ struct TypedMapping { const T& operator*() const { return *ptr(); } T& operator*() { return *ptr(); } OwnPtr region; + PhysicalAddress paddr; size_t offset { 0 }; + size_t length { 0 }; }; template @@ -34,6 +36,8 @@ static ErrorOr>> adopt_new_nonnull_own_typed_mappi auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) Memory::TypedMapping())); table->region = move(region); table->offset = paddr.offset_in_page(); + table->paddr = paddr; + table->length = length; return table; } @@ -44,6 +48,8 @@ static ErrorOr> map_typed(PhysicalAddress paddr, size_t length, auto mapping_length = TRY(page_round_up(paddr.offset_in_page() + length)); table.region = TRY(MM.allocate_kernel_region(paddr.page_base(), mapping_length, {}, access)); table.offset = paddr.offset_in_page(); + table.paddr = paddr; + table.length = length; return table; } diff --git a/Kernel/Net/Intel/E1000ENetworkAdapter.cpp b/Kernel/Net/Intel/E1000ENetworkAdapter.cpp index beb210381b..cdbf1fab46 100644 --- a/Kernel/Net/Intel/E1000ENetworkAdapter.cpp +++ b/Kernel/Net/Intel/E1000ENetworkAdapter.cpp @@ -192,7 +192,8 @@ UNMAP_AFTER_INIT LockRefPtr E1000ENetworkAdapter::try_to_i auto interface_name_or_error = NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier); if (interface_name_or_error.is_error()) return {}; - auto adapter = adopt_lock_ref_if_nonnull(new (nothrow) E1000ENetworkAdapter(pci_device_identifier.address(), irq, interface_name_or_error.release_value())); + auto registers_io_window = IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0).release_value_but_fixme_should_propagate_errors(); + auto adapter = adopt_lock_ref_if_nonnull(new (nothrow) E1000ENetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), interface_name_or_error.release_value())); if (!adapter) return {}; if (adapter->initialize()) @@ -203,21 +204,9 @@ UNMAP_AFTER_INIT LockRefPtr E1000ENetworkAdapter::try_to_i UNMAP_AFTER_INIT bool E1000ENetworkAdapter::initialize() { dmesgln("E1000e: Found @ {}", pci_address()); - - m_io_base = IOAddress(PCI::get_BAR2(pci_address()) & ~1); - enable_bus_mastering(pci_address()); - size_t mmio_base_size = PCI::get_BAR_space_size(pci_address(), PCI::HeaderType0BaseRegister::BAR0); - auto region_or_error = MM.allocate_kernel_region(PhysicalAddress(page_base_of(PCI::get_BAR0(pci_address()))), Memory::page_round_up(mmio_base_size).release_value_but_fixme_should_propagate_errors(), "E1000e MMIO"sv, Memory::Region::Access::ReadWrite, Memory::Region::Cacheable::No); - if (region_or_error.is_error()) - return false; - m_mmio_region = region_or_error.release_value(); - m_mmio_base = m_mmio_region->vaddr(); - m_use_mmio = true; - dmesgln("E1000e: port base: {}", m_io_base); - dmesgln("E1000e: MMIO base: {}", PhysicalAddress(PCI::get_BAR0(pci_address()) & 0xfffffffc)); - dmesgln("E1000e: MMIO base size: {} bytes", mmio_base_size); + dmesgln("E1000e: IO base: {}", m_registers_io_window); dmesgln("E1000e: Interrupt line: {}", interrupt_number()); detect_eeprom(); dmesgln("E1000e: Has EEPROM? {}", m_has_eeprom); @@ -233,8 +222,8 @@ UNMAP_AFTER_INIT bool E1000ENetworkAdapter::initialize() return true; } -UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr interface_name) - : E1000NetworkAdapter(address, irq, move(interface_name)) +UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) + : E1000NetworkAdapter(address, irq, move(registers_io_window), move(interface_name)) { } diff --git a/Kernel/Net/Intel/E1000ENetworkAdapter.h b/Kernel/Net/Intel/E1000ENetworkAdapter.h index ce679dfbba..64ef266401 100644 --- a/Kernel/Net/Intel/E1000ENetworkAdapter.h +++ b/Kernel/Net/Intel/E1000ENetworkAdapter.h @@ -8,9 +8,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -30,7 +30,7 @@ public: virtual StringView purpose() const override { return class_name(); } private: - E1000ENetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr); + E1000ENetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr); virtual StringView class_name() const override { return "E1000ENetworkAdapter"sv; } diff --git a/Kernel/Net/Intel/E1000NetworkAdapter.cpp b/Kernel/Net/Intel/E1000NetworkAdapter.cpp index 7ea0fe6379..18fd59ac8e 100644 --- a/Kernel/Net/Intel/E1000NetworkAdapter.cpp +++ b/Kernel/Net/Intel/E1000NetworkAdapter.cpp @@ -170,7 +170,8 @@ UNMAP_AFTER_INIT LockRefPtr E1000NetworkAdapter::try_to_ini auto interface_name_or_error = NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier); if (interface_name_or_error.is_error()) return {}; - auto adapter = adopt_lock_ref_if_nonnull(new (nothrow) E1000NetworkAdapter(pci_device_identifier.address(), irq, interface_name_or_error.release_value())); + auto registers_io_window = IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0).release_value_but_fixme_should_propagate_errors(); + auto adapter = adopt_lock_ref_if_nonnull(new (nothrow) E1000NetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), interface_name_or_error.release_value())); if (!adapter) return {}; if (adapter->initialize()) @@ -197,18 +198,7 @@ UNMAP_AFTER_INIT bool E1000NetworkAdapter::initialize() dmesgln("E1000: Found @ {}", pci_address()); enable_bus_mastering(pci_address()); - m_io_base = IOAddress(PCI::get_BAR1(pci_address()) & ~1); - - size_t mmio_base_size = PCI::get_BAR_space_size(pci_address(), PCI::HeaderType0BaseRegister::BAR0); - auto region_or_error = MM.allocate_kernel_region(PhysicalAddress(page_base_of(PCI::get_BAR0(pci_address()))), Memory::page_round_up(mmio_base_size).release_value_but_fixme_should_propagate_errors(), "E1000 MMIO"sv, Memory::Region::Access::ReadWrite, Memory::Region::Cacheable::No); - if (region_or_error.is_error()) - return false; - m_mmio_region = region_or_error.release_value(); - m_mmio_base = m_mmio_region->vaddr(); - m_use_mmio = true; - dmesgln("E1000: port base: {}", m_io_base); - dmesgln("E1000: MMIO base: {}", PhysicalAddress(PCI::get_BAR0(pci_address()) & 0xfffffffc)); - dmesgln("E1000: MMIO base size: {} bytes", mmio_base_size); + dmesgln("E1000: IO base: {}", m_registers_io_window); dmesgln("E1000: Interrupt line: {}", interrupt_number()); detect_eeprom(); dmesgln("E1000: Has EEPROM? {}", m_has_eeprom); @@ -227,10 +217,11 @@ UNMAP_AFTER_INIT bool E1000NetworkAdapter::initialize() return true; } -UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr interface_name) +UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) : NetworkAdapter(move(interface_name)) , PCI::Device(address) , IRQHandler(irq) + , m_registers_io_window(move(registers_io_window)) , m_rx_descriptors_region(MM.allocate_contiguous_kernel_region(Memory::page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors).release_value_but_fixme_should_propagate_errors(), "E1000 RX Descriptors"sv, Memory::Region::Access::ReadWrite).release_value()) , m_tx_descriptors_region(MM.allocate_contiguous_kernel_region(Memory::page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors).release_value_but_fixme_should_propagate_errors(), "E1000 TX Descriptors"sv, Memory::Region::Access::ReadWrite).release_value()) { @@ -369,58 +360,37 @@ UNMAP_AFTER_INIT void E1000NetworkAdapter::initialize_tx_descriptors() void E1000NetworkAdapter::out8(u16 address, u8 data) { dbgln_if(E1000_DEBUG, "E1000: OUT8 {:#02x} @ {:#04x}", data, address); - if (m_use_mmio) { - auto* ptr = (u8 volatile*)(m_mmio_base.get() + address); - *ptr = data; - return; - } - m_io_base.offset(address).out(data); + m_registers_io_window->write8(address, data); } void E1000NetworkAdapter::out16(u16 address, u16 data) { dbgln_if(E1000_DEBUG, "E1000: OUT16 {:#04x} @ {:#04x}", data, address); - if (m_use_mmio) { - auto* ptr = (u16 volatile*)(m_mmio_base.get() + address); - *ptr = data; - return; - } - m_io_base.offset(address).out(data); + m_registers_io_window->write16(address, data); } void E1000NetworkAdapter::out32(u16 address, u32 data) { dbgln_if(E1000_DEBUG, "E1000: OUT32 {:#08x} @ {:#04x}", data, address); - if (m_use_mmio) { - auto* ptr = (u32 volatile*)(m_mmio_base.get() + address); - *ptr = data; - return; - } - m_io_base.offset(address).out(data); + m_registers_io_window->write32(address, data); } u8 E1000NetworkAdapter::in8(u16 address) { dbgln_if(E1000_DEBUG, "E1000: IN8 @ {:#04x}", address); - if (m_use_mmio) - return *(u8 volatile*)(m_mmio_base.get() + address); - return m_io_base.offset(address).in(); + return m_registers_io_window->read8(address); } u16 E1000NetworkAdapter::in16(u16 address) { dbgln_if(E1000_DEBUG, "E1000: IN16 @ {:#04x}", address); - if (m_use_mmio) - return *(u16 volatile*)(m_mmio_base.get() + address); - return m_io_base.offset(address).in(); + return m_registers_io_window->read16(address); } u32 E1000NetworkAdapter::in32(u16 address) { dbgln_if(E1000_DEBUG, "E1000: IN32 @ {:#04x}", address); - if (m_use_mmio) - return *(u32 volatile*)(m_mmio_base.get() + address); - return m_io_base.offset(address).in(); + return m_registers_io_window->read32(address); } void E1000NetworkAdapter::send_raw(ReadonlyBytes payload) diff --git a/Kernel/Net/Intel/E1000NetworkAdapter.h b/Kernel/Net/Intel/E1000NetworkAdapter.h index f4d5c775e5..3f40733fbf 100644 --- a/Kernel/Net/Intel/E1000NetworkAdapter.h +++ b/Kernel/Net/Intel/E1000NetworkAdapter.h @@ -7,9 +7,9 @@ #pragma once #include -#include #include #include +#include #include #include #include @@ -37,7 +37,7 @@ protected: void setup_interrupts(); void setup_link(); - E1000NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr); + E1000NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr); virtual bool handle_irq(RegisterState const&) override; virtual StringView class_name() const override { return "E1000NetworkAdapter"sv; } @@ -82,17 +82,15 @@ protected: static constexpr size_t number_of_rx_descriptors = 256; static constexpr size_t number_of_tx_descriptors = 256; - IOAddress m_io_base; - VirtualAddress m_mmio_base; + NonnullOwnPtr m_registers_io_window; + OwnPtr m_rx_descriptors_region; OwnPtr m_tx_descriptors_region; OwnPtr m_rx_buffer_region; OwnPtr m_tx_buffer_region; Array m_rx_buffers; Array m_tx_buffers; - OwnPtr m_mmio_region; bool m_has_eeprom { false }; - bool m_use_mmio { false }; bool m_link_up { false }; EntropySource m_entropy_source; diff --git a/Kernel/Net/NE2000/NetworkAdapter.cpp b/Kernel/Net/NE2000/NetworkAdapter.cpp index 14bbc9ca7c..30dd731c3d 100644 --- a/Kernel/Net/NE2000/NetworkAdapter.cpp +++ b/Kernel/Net/NE2000/NetworkAdapter.cpp @@ -5,9 +5,9 @@ */ #include -#include #include #include +#include #include #include #include @@ -162,18 +162,19 @@ UNMAP_AFTER_INIT LockRefPtr NE2000NetworkAdapter::try_to_i auto interface_name_or_error = NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier); if (interface_name_or_error.is_error()) return {}; - return adopt_lock_ref_if_nonnull(new (nothrow) NE2000NetworkAdapter(pci_device_identifier.address(), irq, interface_name_or_error.release_value())); + auto registers_io_window = MUST(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); + return adopt_lock_ref_if_nonnull(new (nothrow) NE2000NetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), interface_name_or_error.release_value())); } -UNMAP_AFTER_INIT NE2000NetworkAdapter::NE2000NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr interface_name) +UNMAP_AFTER_INIT NE2000NetworkAdapter::NE2000NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) : NetworkAdapter(move(interface_name)) , PCI::Device(address) , IRQHandler(irq) - , m_io_base(PCI::get_BAR0(pci_address()) & ~3) + , m_registers_io_window(move(registers_io_window)) { dmesgln("NE2000: Found @ {}", pci_address()); - dmesgln("NE2000: Port base: {}", m_io_base); + dmesgln("NE2000: Port base: {}", m_registers_io_window); dmesgln("NE2000: Interrupt line: {}", interrupt_number()); int ram_errors = ram_test(); @@ -237,7 +238,6 @@ bool NE2000NetworkAdapter::handle_irq(RegisterState const&) UNMAP_AFTER_INIT int NE2000NetworkAdapter::ram_test() { - IOAddress io(PCI::get_BAR0(pci_address()) & ~3); int errors = 0; out8(REG_RW_COMMAND, BIT_COMMAND_DMA_ABORT | BIT_COMMAND_STOP); @@ -454,23 +454,22 @@ void NE2000NetworkAdapter::receive() void NE2000NetworkAdapter::out8(u16 address, u8 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write8(address, data); } void NE2000NetworkAdapter::out16(u16 address, u16 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write16(address, data); } u8 NE2000NetworkAdapter::in8(u16 address) { - u8 data = m_io_base.offset(address).in(); - return data; + return m_registers_io_window->read8(address); } u16 NE2000NetworkAdapter::in16(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read16(address); } } diff --git a/Kernel/Net/NE2000/NetworkAdapter.h b/Kernel/Net/NE2000/NetworkAdapter.h index 18f5f92b2d..1460da1614 100644 --- a/Kernel/Net/NE2000/NetworkAdapter.h +++ b/Kernel/Net/NE2000/NetworkAdapter.h @@ -7,9 +7,9 @@ #pragma once #include -#include #include #include +#include #include #include #include @@ -41,7 +41,7 @@ public: virtual StringView purpose() const override { return class_name(); } private: - NE2000NetworkAdapter(PCI::Address, u8, NonnullOwnPtr); + NE2000NetworkAdapter(PCI::Address, u8, NonnullOwnPtr registers_io_window, NonnullOwnPtr); virtual bool handle_irq(RegisterState const&) override; virtual StringView class_name() const override { return "NE2000NetworkAdapter"sv; } @@ -58,7 +58,7 @@ private: u8 in8(u16 address); u16 in16(u16 address); - IOAddress m_io_base; + NonnullOwnPtr m_registers_io_window; int m_ring_read_ptr; u8 m_interrupt_line { 0 }; diff --git a/Kernel/Net/NetworkingManagement.cpp b/Kernel/Net/NetworkingManagement.cpp index ca3892e62d..e3fe772bf6 100644 --- a/Kernel/Net/NetworkingManagement.cpp +++ b/Kernel/Net/NetworkingManagement.cpp @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/Kernel/Net/Realtek/RTL8139NetworkAdapter.cpp b/Kernel/Net/Realtek/RTL8139NetworkAdapter.cpp index b66496aca1..da87dfa8ba 100644 --- a/Kernel/Net/Realtek/RTL8139NetworkAdapter.cpp +++ b/Kernel/Net/Realtek/RTL8139NetworkAdapter.cpp @@ -5,7 +5,6 @@ */ #include -#include #include #include #include @@ -123,14 +122,15 @@ UNMAP_AFTER_INIT LockRefPtr RTL8139NetworkAdapter::try_to auto interface_name_or_error = NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier); if (interface_name_or_error.is_error()) return {}; - return adopt_lock_ref_if_nonnull(new (nothrow) RTL8139NetworkAdapter(pci_device_identifier.address(), irq, interface_name_or_error.release_value())); + auto registers_io_window = MUST(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); + return adopt_lock_ref_if_nonnull(new (nothrow) RTL8139NetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), interface_name_or_error.release_value())); } -UNMAP_AFTER_INIT RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr interface_name) +UNMAP_AFTER_INIT RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) : NetworkAdapter(move(interface_name)) , PCI::Device(address) , IRQHandler(irq) - , m_io_base(PCI::get_BAR0(pci_address()) & ~1) + , m_registers_io_window(move(registers_io_window)) , m_rx_buffer(MM.allocate_contiguous_kernel_region(Memory::page_round_up(RX_BUFFER_SIZE + PACKET_SIZE_MAX).release_value_but_fixme_should_propagate_errors(), "RTL8139 RX"sv, Memory::Region::Access::ReadWrite).release_value()) , m_packet_buffer(MM.allocate_contiguous_kernel_region(Memory::page_round_up(PACKET_SIZE_MAX).release_value_but_fixme_should_propagate_errors(), "RTL8139 Packet buffer"sv, Memory::Region::Access::ReadWrite).release_value()) { @@ -140,7 +140,7 @@ UNMAP_AFTER_INIT RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address addre enable_bus_mastering(pci_address()); - dmesgln("RTL8139: I/O port base: {}", m_io_base); + dmesgln("RTL8139: I/O port base: {}", m_registers_io_window); dmesgln("RTL8139: Interrupt line: {}", interrupt_number()); // we add space to account for overhang from the last packet - the rtl8139 @@ -349,32 +349,32 @@ void RTL8139NetworkAdapter::receive() void RTL8139NetworkAdapter::out8(u16 address, u8 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write8(address, data); } void RTL8139NetworkAdapter::out16(u16 address, u16 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write16(address, data); } void RTL8139NetworkAdapter::out32(u16 address, u32 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write32(address, data); } u8 RTL8139NetworkAdapter::in8(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read8(address); } u16 RTL8139NetworkAdapter::in16(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read16(address); } u32 RTL8139NetworkAdapter::in32(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read32(address); } bool RTL8139NetworkAdapter::link_full_duplex() diff --git a/Kernel/Net/Realtek/RTL8139NetworkAdapter.h b/Kernel/Net/Realtek/RTL8139NetworkAdapter.h index 506590a962..72d82f08af 100644 --- a/Kernel/Net/Realtek/RTL8139NetworkAdapter.h +++ b/Kernel/Net/Realtek/RTL8139NetworkAdapter.h @@ -7,9 +7,9 @@ #pragma once #include -#include #include #include +#include #include #include #include @@ -34,7 +34,7 @@ public: virtual StringView purpose() const override { return class_name(); } private: - RTL8139NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr); + RTL8139NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr); virtual bool handle_irq(RegisterState const&) override; virtual StringView class_name() const override { return "RTL8139NetworkAdapter"sv; } @@ -50,7 +50,7 @@ private: u16 in16(u16 address); u32 in32(u16 address); - IOAddress m_io_base; + NonnullOwnPtr m_registers_io_window; u8 m_interrupt_line { 0 }; OwnPtr m_rx_buffer; u16 m_rx_buffer_offset { 0 }; diff --git a/Kernel/Net/Realtek/RTL8168NetworkAdapter.cpp b/Kernel/Net/Realtek/RTL8168NetworkAdapter.cpp index d8317a9be5..85ce6b437b 100644 --- a/Kernel/Net/Realtek/RTL8168NetworkAdapter.cpp +++ b/Kernel/Net/Realtek/RTL8168NetworkAdapter.cpp @@ -193,7 +193,8 @@ UNMAP_AFTER_INIT LockRefPtr RTL8168NetworkAdapter::try_to auto interface_name_or_error = NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier); if (interface_name_or_error.is_error()) return {}; - return adopt_lock_ref_if_nonnull(new (nothrow) RTL8168NetworkAdapter(pci_device_identifier.address(), irq, interface_name_or_error.release_value())); + auto registers_io_window = MUST(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); + return adopt_lock_ref_if_nonnull(new (nothrow) RTL8168NetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), interface_name_or_error.release_value())); } bool RTL8168NetworkAdapter::determine_supported_version() const @@ -241,16 +242,16 @@ bool RTL8168NetworkAdapter::determine_supported_version() const } } -UNMAP_AFTER_INIT RTL8168NetworkAdapter::RTL8168NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr interface_name) +UNMAP_AFTER_INIT RTL8168NetworkAdapter::RTL8168NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) : NetworkAdapter(move(interface_name)) , PCI::Device(address) , IRQHandler(irq) - , m_io_base(PCI::get_BAR0(pci_address()) & ~1) + , m_registers_io_window(move(registers_io_window)) , m_rx_descriptors_region(MM.allocate_contiguous_kernel_region(Memory::page_round_up(sizeof(TXDescriptor) * (number_of_rx_descriptors + 1)).release_value_but_fixme_should_propagate_errors(), "RTL8168 RX"sv, Memory::Region::Access::ReadWrite).release_value()) , m_tx_descriptors_region(MM.allocate_contiguous_kernel_region(Memory::page_round_up(sizeof(RXDescriptor) * (number_of_tx_descriptors + 1)).release_value_but_fixme_should_propagate_errors(), "RTL8168 TX"sv, Memory::Region::Access::ReadWrite).release_value()) { dmesgln("RTL8168: Found @ {}", pci_address()); - dmesgln("RTL8168: I/O port base: {}", m_io_base); + dmesgln("RTL8168: I/O port base: {}", m_registers_io_window); identify_chip_version(); dmesgln("RTL8168: Version detected - {} ({}{})", possible_device_name(), (u8)m_version, m_version_uncertain ? "?" : ""); @@ -1258,39 +1259,39 @@ void RTL8168NetworkAdapter::receive() void RTL8168NetworkAdapter::out8(u16 address, u8 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write8(address, data); } void RTL8168NetworkAdapter::out16(u16 address, u16 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write16(address, data); } void RTL8168NetworkAdapter::out32(u16 address, u32 data) { - m_io_base.offset(address).out(data); + m_registers_io_window->write32(address, data); } void RTL8168NetworkAdapter::out64(u16 address, u64 data) { // ORDER MATTERS: Some NICs require the high part of the address to be written first - m_io_base.offset(address + 4).out((u32)(data >> 32)); - m_io_base.offset(address).out((u32)(data & 0xFFFFFFFF)); + m_registers_io_window->write32(address + 4, (u32)(data >> 32)); + m_registers_io_window->write32(address, (u32)(data & 0xFFFFFFFF)); } u8 RTL8168NetworkAdapter::in8(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read8(address); } u16 RTL8168NetworkAdapter::in16(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read16(address); } u32 RTL8168NetworkAdapter::in32(u16 address) { - return m_io_base.offset(address).in(); + return m_registers_io_window->read32(address); } void RTL8168NetworkAdapter::phy_out(u8 address, u16 data) diff --git a/Kernel/Net/Realtek/RTL8168NetworkAdapter.h b/Kernel/Net/Realtek/RTL8168NetworkAdapter.h index 9eb9ed6c19..a0ca643c2b 100644 --- a/Kernel/Net/Realtek/RTL8168NetworkAdapter.h +++ b/Kernel/Net/Realtek/RTL8168NetworkAdapter.h @@ -8,9 +8,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -38,7 +38,7 @@ private: static constexpr size_t number_of_rx_descriptors = 64; static constexpr size_t number_of_tx_descriptors = 16; - RTL8168NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr); + RTL8168NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr); virtual bool handle_irq(RegisterState const&) override; virtual StringView class_name() const override { return "RTL8168NetworkAdapter"sv; } @@ -199,7 +199,7 @@ private: ChipVersion m_version { ChipVersion::Unknown }; bool m_version_uncertain { true }; - IOAddress m_io_base; + NonnullOwnPtr m_registers_io_window; u32 m_ocp_base_address { 0 }; OwnPtr m_rx_descriptors_region; NonnullOwnPtrVector m_rx_buffers_regions; diff --git a/Kernel/Storage/ATA/GenericIDE/Channel.cpp b/Kernel/Storage/ATA/GenericIDE/Channel.cpp index c003e30b75..06750e9679 100644 --- a/Kernel/Storage/ATA/GenericIDE/Channel.cpp +++ b/Kernel/Storage/ATA/GenericIDE/Channel.cpp @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -24,16 +24,16 @@ namespace Kernel { #define PATA_PRIMARY_IRQ 14 #define PATA_SECONDARY_IRQ 15 -UNMAP_AFTER_INIT NonnullLockRefPtr IDEChannel::create(IDEController const& controller, IOAddressGroup io_group, ChannelType type) +UNMAP_AFTER_INIT NonnullLockRefPtr IDEChannel::create(IDEController const& controller, IOWindowGroup io_window_group, ChannelType type) { auto ata_identify_data_buffer = KBuffer::try_create_with_size("ATA Identify Page"sv, 4096, Memory::Region::Access::ReadWrite, AllocationStrategy::AllocateNow).release_value(); - return adopt_lock_ref(*new IDEChannel(controller, io_group, type, move(ata_identify_data_buffer))); + return adopt_lock_ref(*new IDEChannel(controller, move(io_window_group), type, move(ata_identify_data_buffer))); } -UNMAP_AFTER_INIT NonnullLockRefPtr IDEChannel::create(IDEController const& controller, u8 irq, IOAddressGroup io_group, ChannelType type) +UNMAP_AFTER_INIT NonnullLockRefPtr IDEChannel::create(IDEController const& controller, u8 irq, IOWindowGroup io_window_group, ChannelType type) { auto ata_identify_data_buffer = KBuffer::try_create_with_size("ATA Identify Page"sv, 4096, Memory::Region::Access::ReadWrite, AllocationStrategy::AllocateNow).release_value(); - return adopt_lock_ref(*new IDEChannel(controller, irq, io_group, type, move(ata_identify_data_buffer))); + return adopt_lock_ref(*new IDEChannel(controller, irq, move(io_window_group), type, move(ata_identify_data_buffer))); } StringView IDEChannel::channel_type_string() const @@ -47,10 +47,10 @@ bool IDEChannel::select_device_and_wait_until_not_busy(DeviceType device_type, s { microseconds_delay(20); u8 slave = device_type == DeviceType::Slave; - m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(0xA0 | (slave << 4)); // First, we need to select the drive itself + m_io_window_group.io_window().write8(ATA_REG_HDDEVSEL, 0xA0 | (slave << 4)); // First, we need to select the drive itself microseconds_delay(20); size_t time_elapsed = 0; - while (m_io_group.control_base().in() & ATA_SR_BSY && time_elapsed <= milliseconds_timeout) { + while (m_io_window_group.control_window().read8(0) & ATA_SR_BSY && time_elapsed <= milliseconds_timeout) { microseconds_delay(1000); time_elapsed++; } @@ -62,13 +62,13 @@ ErrorOr IDEChannel::port_phy_reset() MutexLocker locker(m_lock); SpinlockLocker hard_locker(m_hard_lock); // reset the channel - u8 device_control = m_io_group.control_base().in(); + u8 device_control = m_io_window_group.control_window().read8(0); // Wait 30 milliseconds microseconds_delay(30000); - m_io_group.control_base().out(device_control | (1 << 2)); + m_io_window_group.control_window().write8(0, device_control | (1 << 2)); // Wait 30 milliseconds microseconds_delay(30000); - m_io_group.control_base().out(device_control); + m_io_window_group.control_window().write8(0, device_control); // Wait up to 30 seconds before failing if (!select_device_and_wait_until_not_busy(DeviceType::Master, 30000)) { dbgln("IDEChannel: reset failed, busy flag on master stuck"); @@ -95,16 +95,16 @@ ErrorOr IDEChannel::allocate_resources_for_isa_ide_controller(Badge IDEChannel::allocate_resources(bool force_pio) { - dbgln_if(PATA_DEBUG, "IDEChannel: {} IO base: {}", channel_type_string(), m_io_group.io_base()); - dbgln_if(PATA_DEBUG, "IDEChannel: {} control base: {}", channel_type_string(), m_io_group.control_base()); - if (m_io_group.bus_master_base().has_value()) - dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_group.bus_master_base().value()); + dbgln_if(PATA_DEBUG, "IDEChannel: {} IO base: {}", channel_type_string(), m_io_window_group.io_window()); + dbgln_if(PATA_DEBUG, "IDEChannel: {} control base: {}", channel_type_string(), m_io_window_group.control_window()); + if (m_io_window_group.bus_master_window()) + dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_window_group.bus_master_window()); else dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base disabled", channel_type_string()); if (!force_pio) { m_dma_enabled = true; - VERIFY(m_io_group.bus_master_base().has_value()); + VERIFY(m_io_window_group.bus_master_window()); // Let's try to set up DMA transfers. m_prdt_region = TRY(MM.allocate_dma_buffer_page("IDE PRDT"sv, Memory::Region::Access::ReadWrite, m_prdt_page)); @@ -115,24 +115,24 @@ UNMAP_AFTER_INIT ErrorOr IDEChannel::allocate_resources(bool force_pio) prdt().end_of_table = 0x8000; // clear bus master interrupt status - m_io_group.bus_master_base().value().offset(2).out(m_io_group.bus_master_base().value().offset(2).in() | 4); + m_io_window_group.bus_master_window()->write8(2, m_io_window_group.bus_master_window()->read8(2) | 4); } return {}; } -UNMAP_AFTER_INIT IDEChannel::IDEChannel(IDEController const& controller, u8 irq, IOAddressGroup io_group, ChannelType type, NonnullOwnPtr ata_identify_data_buffer) +UNMAP_AFTER_INIT IDEChannel::IDEChannel(IDEController const& controller, u8 irq, IOWindowGroup io_group, ChannelType type, NonnullOwnPtr ata_identify_data_buffer) : ATAPort(controller, (type == ChannelType::Primary ? 0 : 1), move(ata_identify_data_buffer)) , IRQHandler(irq) , m_channel_type(type) - , m_io_group(io_group) + , m_io_window_group(move(io_group)) { } -UNMAP_AFTER_INIT IDEChannel::IDEChannel(IDEController const& controller, IOAddressGroup io_group, ChannelType type, NonnullOwnPtr ata_identify_data_buffer) +UNMAP_AFTER_INIT IDEChannel::IDEChannel(IDEController const& controller, IOWindowGroup io_group, ChannelType type, NonnullOwnPtr ata_identify_data_buffer) : ATAPort(controller, (type == ChannelType::Primary ? 0 : 1), move(ata_identify_data_buffer)) , IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ) , m_channel_type(type) - , m_io_group(io_group) + , m_io_window_group(move(io_group)) { } @@ -149,36 +149,37 @@ bool IDEChannel::handle_irq(RegisterState const&) ErrorOr IDEChannel::stop_busmastering() { VERIFY(m_lock.is_locked()); - VERIFY(m_io_group.bus_master_base().has_value()); - m_io_group.bus_master_base().value().out(0); + VERIFY(m_io_window_group.bus_master_window()); + m_io_window_group.bus_master_window()->write8(0, 0); return {}; } ErrorOr IDEChannel::start_busmastering(TransactionDirection direction) { VERIFY(m_lock.is_locked()); - VERIFY(m_io_group.bus_master_base().has_value()); - m_io_group.bus_master_base().value().out(direction != TransactionDirection::Write ? 0x9 : 0x1); + VERIFY(m_io_window_group.bus_master_window()); + m_io_window_group.bus_master_window()->write8(0, (direction != TransactionDirection::Write ? 0x9 : 0x1)); return {}; } ErrorOr IDEChannel::force_busmastering_status_clean() { VERIFY(m_lock.is_locked()); - VERIFY(m_io_group.bus_master_base().has_value()); - m_io_group.bus_master_base().value().offset(2).out(m_io_group.bus_master_base().value().offset(2).in() | 4); + VERIFY(m_io_window_group.bus_master_window()); + m_io_window_group.bus_master_window()->write8(2, m_io_window_group.bus_master_window()->read8(2) | 4); return {}; } ErrorOr IDEChannel::busmastering_status() { - VERIFY(m_io_group.bus_master_base().has_value()); - return m_io_group.bus_master_base().value().offset(2).in(); + VERIFY(m_io_window_group.bus_master_window()); + return m_io_window_group.bus_master_window()->read8(2); } ErrorOr IDEChannel::prepare_transaction_with_busmastering(TransactionDirection direction, PhysicalAddress prdt_buffer) { VERIFY(m_lock.is_locked()); - m_io_group.bus_master_base().value().offset(4).out(prdt_buffer.get()); - m_io_group.bus_master_base().value().out(direction != TransactionDirection::Write ? 0x8 : 0); + m_io_window_group.bus_master_window()->write32(4, prdt_buffer.get()); + m_io_window_group.bus_master_window()->write8(0, direction != TransactionDirection::Write ? 0x8 : 0); + // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. - m_io_group.bus_master_base().value().offset(2).out(m_io_group.bus_master_base().value().offset(2).in() | 0x6); + m_io_window_group.bus_master_window()->write8(2, m_io_window_group.bus_master_window()->read8(2) | 0x6); return {}; } ErrorOr IDEChannel::initiate_transaction(TransactionDirection) @@ -190,29 +191,29 @@ ErrorOr IDEChannel::initiate_transaction(TransactionDirection) ErrorOr IDEChannel::task_file_status() { VERIFY(m_lock.is_locked()); - return m_io_group.control_base().in(); + return m_io_window_group.control_window().read8(0); } ErrorOr IDEChannel::task_file_error() { VERIFY(m_lock.is_locked()); - return m_io_group.io_base().offset(ATA_REG_ERROR).in(); + return m_io_window_group.io_window().read8(ATA_REG_ERROR); } ErrorOr IDEChannel::detect_presence_on_selected_device() { VERIFY(m_lock.is_locked()); - m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0x55); - m_io_group.io_base().offset(ATA_REG_LBA0).out(0xAA); + m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, 0x55); + m_io_window_group.io_window().write8(ATA_REG_LBA0, 0xAA); - m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0xAA); - m_io_group.io_base().offset(ATA_REG_LBA0).out(0x55); + m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, 0xAA); + m_io_window_group.io_window().write8(ATA_REG_LBA0, 0x55); - m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0x55); - m_io_group.io_base().offset(ATA_REG_LBA0).out(0xAA); + m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, 0x55); + m_io_window_group.io_window().write8(ATA_REG_LBA0, 0xAA); - auto nsectors_value = m_io_group.io_base().offset(ATA_REG_SECCOUNT0).in(); - auto lba0 = m_io_group.io_base().offset(ATA_REG_LBA0).in(); + auto nsectors_value = m_io_window_group.io_window().read8(ATA_REG_SECCOUNT0); + auto lba0 = m_io_window_group.io_window().read8(ATA_REG_LBA0); if (lba0 == 0xAA && nsectors_value == 0x55) return true; @@ -222,7 +223,7 @@ ErrorOr IDEChannel::detect_presence_on_selected_device() ErrorOr IDEChannel::wait_if_busy_until_timeout(size_t timeout_in_milliseconds) { size_t time_elapsed = 0; - while (m_io_group.control_base().in() & ATA_SR_BSY && time_elapsed <= timeout_in_milliseconds) { + while (m_io_window_group.control_window().read8(0) & ATA_SR_BSY && time_elapsed <= timeout_in_milliseconds) { microseconds_delay(1000); time_elapsed++; } @@ -234,7 +235,7 @@ ErrorOr IDEChannel::wait_if_busy_until_timeout(size_t timeout_in_milliseco ErrorOr IDEChannel::force_clear_interrupts() { VERIFY(m_lock.is_locked()); - m_io_group.io_base().offset(ATA_REG_STATUS).in(); + m_io_window_group.io_window().read8(ATA_REG_STATUS); return {}; } @@ -250,21 +251,21 @@ ErrorOr IDEChannel::load_taskfile_into_registers(ATAPort::TaskFile const& } // Note: Preserve the selected drive, always use LBA addressing - auto driver_register = ((m_io_group.io_base().offset(ATA_REG_HDDEVSEL).in() & (1 << 4)) | (head | (1 << 5) | (1 << 6))); - m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(driver_register); + auto driver_register = ((m_io_window_group.io_window().read8(ATA_REG_HDDEVSEL) & (1 << 4)) | (head | (1 << 5) | (1 << 6))); + m_io_window_group.io_window().write8(ATA_REG_HDDEVSEL, driver_register); microseconds_delay(50); if (lba_mode == LBAMode::FortyEightBit) { - m_io_group.io_base().offset(ATA_REG_SECCOUNT1).out((task_file.count >> 8) & 0xFF); - m_io_group.io_base().offset(ATA_REG_LBA3).out(task_file.lba_high[0]); - m_io_group.io_base().offset(ATA_REG_LBA4).out(task_file.lba_high[1]); - m_io_group.io_base().offset(ATA_REG_LBA5).out(task_file.lba_high[2]); + m_io_window_group.io_window().write8(ATA_REG_SECCOUNT1, (task_file.count >> 8) & 0xFF); + m_io_window_group.io_window().write8(ATA_REG_LBA3, task_file.lba_high[0]); + m_io_window_group.io_window().write8(ATA_REG_LBA4, task_file.lba_high[1]); + m_io_window_group.io_window().write8(ATA_REG_LBA5, task_file.lba_high[2]); } - m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(task_file.count & 0xFF); - m_io_group.io_base().offset(ATA_REG_LBA0).out(task_file.lba_low[0]); - m_io_group.io_base().offset(ATA_REG_LBA1).out(task_file.lba_low[1]); - m_io_group.io_base().offset(ATA_REG_LBA2).out(task_file.lba_low[2]); + m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, task_file.count & 0xFF); + m_io_window_group.io_window().write8(ATA_REG_LBA0, task_file.lba_low[0]); + m_io_window_group.io_window().write8(ATA_REG_LBA1, task_file.lba_low[1]); + m_io_window_group.io_window().write8(ATA_REG_LBA2, task_file.lba_low[2]); // FIXME: Set a timeout here? size_t time_elapsed = 0; @@ -272,13 +273,13 @@ ErrorOr IDEChannel::load_taskfile_into_registers(ATAPort::TaskFile const& if (time_elapsed > completion_timeout_in_milliseconds) return Error::from_errno(EBUSY); // FIXME: Use task_file_status method - auto status = m_io_group.control_base().in(); + auto status = m_io_window_group.control_window().read8(0); if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; microseconds_delay(1000); time_elapsed++; } - m_io_group.io_base().offset(ATA_REG_COMMAND).out(task_file.command); + m_io_window_group.io_window().write8(ATA_REG_COMMAND, task_file.command); return {}; } @@ -288,7 +289,7 @@ ErrorOr IDEChannel::device_select(size_t device_index) if (device_index > 1) return Error::from_errno(EINVAL); microseconds_delay(20); - m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(0xA0 | ((device_index) << 4)); + m_io_window_group.io_window().write8(ATA_REG_HDDEVSEL, (0xA0 | ((device_index) << 4))); microseconds_delay(20); return {}; } @@ -296,14 +297,14 @@ ErrorOr IDEChannel::device_select(size_t device_index) ErrorOr IDEChannel::enable_interrupts() { VERIFY(m_lock.is_locked()); - m_io_group.control_base().out(0); + m_io_window_group.control_window().write8(0, 0); m_interrupts_enabled = true; return {}; } ErrorOr IDEChannel::disable_interrupts() { VERIFY(m_lock.is_locked()); - m_io_group.control_base().out(1 << 1); + m_io_window_group.control_window().write8(0, 1 << 1); m_interrupts_enabled = false; return {}; } @@ -313,7 +314,7 @@ ErrorOr IDEChannel::read_pio_data_to_buffer(UserOrKernelBuffer& buffer, si VERIFY(m_lock.is_locked()); VERIFY(words_count == 256); for (u32 i = 0; i < 256; ++i) { - u16 data = m_io_group.io_base().offset(ATA_REG_DATA).in(); + u16 data = m_io_window_group.io_window().read16(ATA_REG_DATA); // FIXME: Don't assume 512 bytes sector TRY(buffer.write(&data, block_offset * 512 + (i * 2), 2)); } @@ -327,7 +328,7 @@ ErrorOr IDEChannel::write_pio_data_from_buffer(UserOrKernelBuffer const& b u16 buf; // FIXME: Don't assume 512 bytes sector TRY(buffer.read(&buf, block_offset * 512 + (i * 2), 2)); - IO::out16(m_io_group.io_base().offset(ATA_REG_DATA).get(), buf); + m_io_window_group.io_window().write16(ATA_REG_DATA, buf); } return {}; } diff --git a/Kernel/Storage/ATA/GenericIDE/Channel.h b/Kernel/Storage/ATA/GenericIDE/Channel.h index 8199d92119..0b968d6d86 100644 --- a/Kernel/Storage/ATA/GenericIDE/Channel.h +++ b/Kernel/Storage/ATA/GenericIDE/Channel.h @@ -18,8 +18,8 @@ #pragma once #include -#include #include +#include #include #include #include @@ -56,57 +56,40 @@ public: Slave, }; - struct IOAddressGroup { - IOAddressGroup(IOAddress io_base, IOAddress control_base, IOAddress bus_master_base) - : m_io_base(io_base) - , m_control_base(control_base) - , m_bus_master_base(bus_master_base) + struct IOWindowGroup { + IOWindowGroup(NonnullOwnPtr io_window, NonnullOwnPtr control_window, NonnullOwnPtr m_bus_master_window) + : m_io_window(move(io_window)) + , m_control_window(move(control_window)) + , m_bus_master_window(move(m_bus_master_window)) { } - IOAddressGroup(IOAddress io_base, IOAddress control_base, Optional bus_master_base) - : m_io_base(io_base) - , m_control_base(control_base) - , m_bus_master_base(bus_master_base) + IOWindowGroup(NonnullOwnPtr io_window, NonnullOwnPtr control_window) + : m_io_window(move(io_window)) + , m_control_window(move(control_window)) { } - IOAddressGroup(IOAddress io_base, IOAddress control_base) - : m_io_base(io_base) - , m_control_base(control_base) - , m_bus_master_base() - { - } - - IOAddressGroup(IOAddressGroup const& other, IOAddress bus_master_base) - : m_io_base(other.io_base()) - , m_control_base(other.control_base()) - , m_bus_master_base(bus_master_base) - { - } - - IOAddressGroup(IOAddressGroup const&) = default; - // Disable default implementations that would use surprising integer promotion. - bool operator==(IOAddressGroup const&) const = delete; - bool operator<=(IOAddressGroup const&) const = delete; - bool operator>=(IOAddressGroup const&) const = delete; - bool operator<(IOAddressGroup const&) const = delete; - bool operator>(IOAddressGroup const&) const = delete; + bool operator==(IOWindowGroup const&) const = delete; + bool operator<=(IOWindowGroup const&) const = delete; + bool operator>=(IOWindowGroup const&) const = delete; + bool operator<(IOWindowGroup const&) const = delete; + bool operator>(IOWindowGroup const&) const = delete; - IOAddress io_base() const { return m_io_base; }; - IOAddress control_base() const { return m_control_base; } - Optional bus_master_base() const { return m_bus_master_base; } + IOWindow& io_window() const { return *m_io_window; }; + IOWindow& control_window() const { return *m_control_window; } + IOWindow* bus_master_window() const { return m_bus_master_window.ptr(); } private: - IOAddress m_io_base; - IOAddress m_control_base; - Optional m_bus_master_base; + mutable NonnullOwnPtr m_io_window; + mutable NonnullOwnPtr m_control_window; + mutable OwnPtr m_bus_master_window; }; public: - static NonnullLockRefPtr create(IDEController const&, IOAddressGroup, ChannelType type); - static NonnullLockRefPtr create(IDEController const&, u8 irq, IOAddressGroup, ChannelType type); + static NonnullLockRefPtr create(IDEController const&, IOWindowGroup, ChannelType type); + static NonnullLockRefPtr create(IDEController const&, u8 irq, IOWindowGroup, ChannelType type); virtual ~IDEChannel() override; @@ -157,8 +140,8 @@ private: virtual ErrorOr read_pio_data_to_buffer(UserOrKernelBuffer&, size_t block_offset, size_t words_count) override; virtual ErrorOr write_pio_data_from_buffer(UserOrKernelBuffer const&, size_t block_offset, size_t words_count) override; - IDEChannel(IDEController const&, IOAddressGroup, ChannelType type, NonnullOwnPtr ata_identify_data_buffer); - IDEChannel(IDEController const&, u8 irq, IOAddressGroup, ChannelType type, NonnullOwnPtr ata_identify_data_buffer); + IDEChannel(IDEController const&, IOWindowGroup, ChannelType type, NonnullOwnPtr ata_identify_data_buffer); + IDEChannel(IDEController const&, u8 irq, IOWindowGroup, ChannelType type, NonnullOwnPtr ata_identify_data_buffer); //^ IRQHandler virtual bool handle_irq(RegisterState const&) override; @@ -168,6 +151,6 @@ private: bool m_dma_enabled { false }; bool m_interrupts_enabled { true }; - IOAddressGroup m_io_group; + IOWindowGroup m_io_window_group; }; }