diff --git a/repos/os/run/ahci_block.run b/repos/os/run/ahci_block.run index 43d6895f63..6fdb74bd8e 100644 --- a/repos/os/run/ahci_block.run +++ b/repos/os/run/ahci_block.run @@ -1,35 +1,25 @@ assert_spec x86 -set mke2fs [installed_command mke2fs] -set dd [installed_command dd] - -# -# Build -# -set build_components { +create_boot_directory +build { core init timer + drivers/platform + drivers/acpi drivers/ahci + app/pci_decode server/report_rom app/block_tester } -source ${genode_dir}/repos/base/run/platform_drv.inc -append_platform_drv_build_components - -build $build_components - # # Build EXT2-file-system image # +set mke2fs [installed_command mke2fs] +set dd [installed_command dd] catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 } catch { exec $mke2fs -F bin/ext2.raw } -create_boot_directory - -# -# Generate config -# -set config { +install_config { @@ -45,20 +35,78 @@ set config { + - } + -append_platform_drv_config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -append config { + @@ -72,6 +120,7 @@ append config { + @@ -86,6 +135,7 @@ append config { + @@ -101,16 +151,13 @@ append config { } -install_config $config - # # Boot modules # -set boot_modules { core ld.lib.so init timer ahci_drv report_rom block_tester } - -append_platform_drv_boot_modules - -build_boot_image $boot_modules +build_boot_image { + core ld.lib.so init timer + pci_decode platform_drv report_rom acpi_drv + ahci_drv report_rom block_tester } append qemu_args " -nographic -device ahci,id=ahci -boot d " append qemu_args " -drive id=disk,file=bin/ext2.raw,format=raw,if=none -device ide-hd,drive=disk,bus=ahci.0 " diff --git a/repos/os/src/drivers/ahci/ahci.h b/repos/os/src/drivers/ahci/ahci.h index b0478ffdd9..8a11e51923 100644 --- a/repos/os/src/drivers/ahci/ahci.h +++ b/repos/os/src/drivers/ahci/ahci.h @@ -16,19 +16,18 @@ #define _AHCI__AHCI_H_ #include -#include +#include #include #include #include -#include - static bool constexpr verbose = false; namespace Ahci { + using namespace Genode; + struct Missing_controller : Exception { }; - class Platform; struct Protocol; struct Port; struct Port_base; @@ -39,47 +38,70 @@ namespace Ahci { using block_count_t = Block::block_count_t; } -class Ahci::Platform -{ - private : - - Data _data; - - protected: - - /** - * Return base address and size of HBA device registers - */ - addr_t _mmio_base() const; - - public: - - Platform(Env &env) : _data(env) { }; - - /** - * Register interrupt signal context - */ - void sigh_irq(Signal_context_capability sigh); - void ack_irq(); - - /** - * DMA - */ - Ram_dataspace_capability alloc_dma_buffer(size_t size); - void free_dma_buffer(Ram_dataspace_capability ds); - addr_t dma_addr(Ram_dataspace_capability); -}; - /** * HBA definitions */ -struct Ahci::Hba : Ahci::Platform, - Mmio +struct Ahci::Hba : private Platform::Device::Mmio { - Mmio::Delayer &_delayer; + using Platform::Device::Mmio::base; + using Index = Platform::Device::Mmio::Index; - Hba(Env &env, Mmio::Delayer &delayer) - : Platform(env), Mmio(_mmio_base()), _delayer(delayer) { } + Platform::Device::Irq _irq; + + /* + * mmio region of AHCI controller is always in BAR 5 + */ + class No_bar : Genode::Exception { }; + + Index _mmio_index(Platform::Connection &platform) + { + unsigned index = 0; + unsigned bar5 = ~0u; + + platform.update(); + + platform.with_xml([&] (Xml_node & xml) { + xml.with_optional_sub_node("device", [&] (Xml_node xml) { + xml.for_each_sub_node("io_mem", [&] (Xml_node node) { + unsigned bar = node.attribute_value("pci_bar", ~0u); + if (bar == 5) bar5 = index; + index++; + }); + }); + }); + + if (bar5 == ~0u) { + error("MMIO region of HBA (BAR 5) not found. Try adding\n" + "\n" + "to platform driver configuration."); + throw No_bar(); + } + + return { bar5 }; + } + + Hba(Platform::Device & dev, + Signal_context_capability cap, + Platform::Connection & platform) + : + Platform::Device::Mmio(dev, _mmio_index(platform)), + _irq(dev) + { + log("version: " + "major=", Hex(read()), " " + "minor=", Hex(read())); + log("command slots: ", command_slots()); + log("native command queuing: ", ncq() ? "yes" : "no"); + log("64-bit support: ", supports_64bit() ? "yes" : "no"); + + _irq.sigh(cap); + + /* enable AHCI */ + write(1); + + /* enable interrupts */ + write(1); + } /** * Host capabilites @@ -116,7 +138,7 @@ struct Ahci::Hba : Ahci::Platform, void ack_irq() { write(read()); - Platform::ack_irq(); + _irq.ack(); } /** @@ -135,16 +157,24 @@ struct Ahci::Hba : Ahci::Platform, struct Cap2 : Register<0x24, 32> { }; - void init() + bool port_implemented(unsigned port) const { - /* enable AHCI */ - write(1); - - /* enable interrupts */ - write(1); + return read() & (1u << port); } - Mmio::Delayer &delayer() { return _delayer; } + template + void handle_irq(FN const & fn) + { + unsigned port_list = read(); + while (port_list) { + unsigned port = log2(port_list); + port_list &= ~(1U << port); + fn(port); + } + + /* clear status register */ + ack_irq(); + } }; @@ -434,8 +464,10 @@ struct Ahci::Port_base : Mmio ATAPI_SIG_QEMU = 0xeb140000, /* will be fixed in Qemu */ }; - unsigned index { }; - Hba &hba; + unsigned index { }; + Platform::Connection &plat; + Hba &hba; + Mmio::Delayer &delayer; /** * Port signature @@ -445,13 +477,14 @@ struct Ahci::Port_base : Mmio static constexpr addr_t offset() { return 0x100; } static constexpr size_t size() { return 0x80; } - Port_base(unsigned index, Hba &hba) + Port_base(unsigned index, Platform::Connection &plat, Hba &hba, + Mmio::Delayer &delayer) : Mmio(hba.base() + offset() + (index * size())), - index(index), hba(hba) { } + index(index), plat(plat), hba(hba), delayer(delayer) { } bool implemented() const { - return hba.read() & (1u << index); + return hba.port_implemented(index); } bool ata() const { return read() == ATA_SIG; } @@ -488,6 +521,7 @@ struct Ahci::Port : private Port_base using Port_base::Register_set::Polling_timeout; using Port_base::index; using Port_base::hba; + using Port_base::delayer; struct Not_ready : Exception { }; @@ -507,10 +541,10 @@ struct Ahci::Port : private Port_base addr_t device_info = 0; addr_t dma_base = 0; /* physical address of DMA memory */ - Port(Protocol &protocol, Region_map &rm, Hba &hba, - unsigned index) + Port(Protocol &protocol, Region_map &rm, Platform::Connection & plat, + Hba &hba, Mmio::Delayer &delayer, unsigned index) : - Port_base(index, hba), + Port_base(index, plat, hba, delayer), protocol(protocol), rm(rm) { reset(); @@ -519,7 +553,7 @@ struct Ahci::Port : private Port_base stop(); - wait_for(hba.delayer(), Cmd::Cr::Equal(0)); + wait_for(delayer, Cmd::Cr::Equal(0)); init(); @@ -540,17 +574,17 @@ struct Ahci::Port : private Port_base { if (device_ds.valid()) { rm.detach((void *)cmd_list); - hba.free_dma_buffer(device_ds); + plat.free_dma_buffer(device_ds); } if (cmd_ds.valid()) { rm.detach((void *)cmd_table); - hba.free_dma_buffer(cmd_ds); + plat.free_dma_buffer(cmd_ds); } if (device_info_ds.valid()) { rm.detach((void*)device_info); - hba.free_dma_buffer(device_info_ds); + plat.free_dma_buffer(device_info_ds); } } @@ -679,14 +713,14 @@ struct Ahci::Port : private Port_base return; try { - wait_for(hba.delayer(), Tfd::Sts_bsy::Equal(0)); + wait_for(delayer, Tfd::Sts_bsy::Equal(0)); } catch (Polling_timeout) { error("HBA busy unable to start command processing."); return; } try { - wait_for(hba.delayer(), Tfd::Sts_drq::Equal(0)); + wait_for(delayer, Tfd::Sts_drq::Equal(0)); } catch (Polling_timeout) { error("HBA in DRQ unable to start command processing."); return; @@ -758,7 +792,7 @@ struct Ahci::Port : private Port_base throw Not_ready(); }, [&] { - hba.delayer().usleep(1000); + delayer.usleep(1000); status = read(); }, 10); } @@ -782,11 +816,11 @@ struct Ahci::Port : private Port_base warning("CMD.ST bit set during device reset --> unknown behavior"); write(1); - hba.delayer().usleep(1000); + delayer.usleep(1000); write(0); try { - wait_for(hba.delayer(), Ssts::Dec::Equal(Ssts::Dec::ESTABLISHED)); + wait_for(delayer, Ssts::Dec::Equal(Ssts::Dec::ESTABLISHED)); } catch (Polling_timeout) { warning("Port reset failed"); } @@ -846,10 +880,10 @@ struct Ahci::Port : private Port_base void setup_memory() { - device_ds = hba.alloc_dma_buffer(0x1000); + device_ds = plat.alloc_dma_buffer(0x1000, CACHED); /* command list 1K */ - addr_t phys = hba.dma_addr(device_ds); + addr_t phys = plat.dma_addr(device_ds); cmd_list = (addr_t)rm.attach(device_ds); command_list_base(phys); @@ -861,14 +895,14 @@ struct Ahci::Port : private Port_base * (FIS receive running) to clear */ write(0); - wait_for(hba.delayer(), Cmd::Fr::Equal(0)); + wait_for(delayer, Cmd::Fr::Equal(0)); fis_rcv_base(phys + 1024); /* command table */ size_t cmd_size = align_addr(cmd_slots * Command_table::size(), 12); - cmd_ds = hba.alloc_dma_buffer(cmd_size); + cmd_ds = plat.alloc_dma_buffer(cmd_size, CACHED); cmd_table = (addr_t)rm.attach(cmd_ds); - phys = hba.dma_addr(cmd_ds); + phys = plat.dma_addr(cmd_ds); /* set command table addresses in command list */ for (unsigned i = 0; i < cmd_slots; i++) { @@ -877,8 +911,8 @@ struct Ahci::Port : private Port_base } /* dataspace for device info */ - device_info_ds = hba.alloc_dma_buffer(0x1000); - device_info_dma_addr = hba.dma_addr(device_info_ds); + device_info_ds = plat.alloc_dma_buffer(0x1000, CACHED); + device_info_dma_addr = plat.dma_addr(device_info_ds); device_info = rm.attach(device_info_ds); } @@ -921,15 +955,15 @@ struct Ahci::Port : private Port_base { if (dma_base) return Ram_dataspace_capability(); - Ram_dataspace_capability dma = hba.alloc_dma_buffer(size); - dma_base = hba.dma_addr(dma); + Ram_dataspace_capability dma = plat.alloc_dma_buffer(size, CACHED); + dma_base = plat.dma_addr(dma); return dma; } void free_buffer(Ram_dataspace_capability ds) { dma_base = 0; - hba.free_dma_buffer(ds); + plat.free_dma_buffer(ds); } /********************** diff --git a/repos/os/src/drivers/ahci/ata_protocol.h b/repos/os/src/drivers/ahci/ata_protocol.h index cfd9ebc41f..88fb85424c 100644 --- a/repos/os/src/drivers/ahci/ata_protocol.h +++ b/repos/os/src/drivers/ahci/ata_protocol.h @@ -227,9 +227,9 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable table.fis.identify_device(); port.execute(0); - port.wait_for_any(port.hba.delayer(), Port::Is::Dss::Equal(1), - Port::Is::Pss::Equal(1), - Port::Is::Dhrs::Equal(1)); + port.wait_for_any(port.delayer, Port::Is::Dss::Equal(1), + Port::Is::Pss::Equal(1), + Port::Is::Dhrs::Equal(1)); _identity.construct(port.device_info); serial.construct(*_identity); diff --git a/repos/os/src/drivers/ahci/atapi_protocol.h b/repos/os/src/drivers/ahci/atapi_protocol.h index 4b0a2cbb58..e1cb346da1 100644 --- a/repos/os/src/drivers/ahci/atapi_protocol.h +++ b/repos/os/src/drivers/ahci/atapi_protocol.h @@ -93,21 +93,21 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable [&] { _start_unit(port); - port.wait_for_any(port.hba.delayer(), + port.wait_for_any(port.delayer, Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1), Port::Is::Dhrs::Equal(1)); port.ack_irq(); /* read sense */ _read_sense(port); - port.wait_for_any(port.hba.delayer(), + port.wait_for_any(port.delayer, Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1), Port::Is::Dhrs::Equal(1)); port.ack_irq(); /* test unit ready */ _test_unit_ready(port); - port.wait_for(port.hba.delayer(), Port::Is::Dhrs::Equal(1)); + port.wait_for(port.delayer, Port::Is::Dhrs::Equal(1)); port.ack_irq(); Device_fis f(port.fis_base); @@ -116,7 +116,7 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable throw Port::Polling_timeout(); _read_capacity(port); - port.wait_for_any(port.hba.delayer(), + port.wait_for_any(port.delayer, Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1), Port::Is::Dhrs::Equal(1)); port.ack_irq(); diff --git a/repos/os/src/drivers/ahci/main.cc b/repos/os/src/drivers/ahci/main.cc index 2b050b1939..b535e384a1 100644 --- a/repos/os/src/drivers/ahci/main.cc +++ b/repos/os/src/drivers/ahci/main.cc @@ -55,39 +55,30 @@ class Ahci::Driver : Noncopyable struct Timer_delayer : Mmio::Delayer, Timer::Connection { - Timer_delayer(Env &env) - : Timer::Connection(env) { } + using Timer::Connection::Connection; void usleep(uint64_t us) override { Timer::Connection::usleep(us); } } _delayer { _env }; - Hba _hba { _env, _delayer }; + Signal_handler _handler { _env.ep(), *this, &Driver::handle_irq }; + + Platform::Connection _plat { _env }; + Platform::Device _device { _plat }; + Hba _hba { _device, _handler, _plat }; Constructible _ata[MAX_PORTS]; Constructible _atapi[MAX_PORTS]; Constructible _ports[MAX_PORTS]; - Signal_handler _irq { _env.ep(), *this, &Driver::handle_irq }; - bool _enable_atapi; - - void _info() - { - log("version: " - "major=", Hex(_hba.read()), " " - "minor=", Hex(_hba.read())); - log("command slots: ", _hba.command_slots()); - log("native command queuing: ", _hba.ncq() ? "yes" : "no"); - log("64-bit support: ", _hba.supports_64bit() ? "yes" : "no"); - } + bool _enable_atapi; void _scan_ports(Region_map &rm) { - log("number of ports: ", _hba.port_count(), " pi: ", - Hex(_hba.read())); + log("number of ports: ", _hba.port_count()); for (unsigned index = 0; index < MAX_PORTS; index++) { - Port_base port(index, _hba); + Port_base port(index, _plat, _hba, _delayer); if (port.implemented() == false) continue; @@ -96,7 +87,8 @@ class Ahci::Driver : Noncopyable if (port.ata()) { try { _ata[index].construct(); - _ports[index].construct(*_ata[index], rm, _hba, index); + _ports[index].construct(*_ata[index], rm, _plat, + _hba, _delayer, index); enabled = true; } catch (...) { } @@ -104,7 +96,8 @@ class Ahci::Driver : Noncopyable } else if (port.atapi() && _enable_atapi) { try { _atapi[index].construct(); - _ports[index].construct(*_atapi[index], rm, _hba, index); + _ports[index].construct(*_atapi[index], rm, _plat, + _hba, _delayer, index); enabled = true; } catch (...) { } @@ -121,14 +114,6 @@ class Ahci::Driver : Noncopyable Driver(Env &env, Dispatch &dispatch, bool support_atapi) : _env(env), _dispatch(dispatch), _enable_atapi(support_atapi) { - _info(); - - /* register irq handler */ - _hba.sigh_irq(_irq); - - /* initialize HBA (IRQs, memory) */ - _hba.init(); - /* search for devices */ _scan_ports(env.rm()); } @@ -138,22 +123,15 @@ class Ahci::Driver : Noncopyable */ void handle_irq() { - unsigned port_list = _hba.read(); - while (port_list) { - unsigned port = log2(port_list); - port_list &= ~(1U << port); - - /* ack irq */ + _hba.handle_irq([&] (unsigned port) { if (_ports[port].constructed()) _ports[port]->handle_irq(); /* handle (pending) requests */ _dispatch.session(port); - } - - /* clear status register */ - _hba.ack_irq(); + }); } + Port &port(Session_label const &label, Session_policy const &policy) { /* try read device port number attribute */ diff --git a/repos/os/src/drivers/ahci/spec/x86/platform.cc b/repos/os/src/drivers/ahci/spec/x86/platform.cc deleted file mode 100644 index bc12cb560d..0000000000 --- a/repos/os/src/drivers/ahci/spec/x86/platform.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * \brief Driver for PCI-bus platforms - * \author Sebastian Sumpf - * \date 2020-01-20 - */ - -/* - * Copyright (C) 2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include - -Ahci::Data::Data(Env &env) - : env(env) -{ - pci_device_cap = pci.with_upgrade( - [&] () { return pci.next_device(pci_device_cap, AHCI_DEVICE, - CLASS_MASK); }); - - if (!pci_device_cap.valid()) { - throw Missing_controller(); - } - - /* construct pci client */ - pci_device.construct(pci_device_cap); - log("AHCI found (" - "vendor: ", Hex(pci_device->vendor_id()), " " - "device: ", Hex(pci_device->device_id()), " " - "class: ", Hex(pci_device->class_code()), ")"); - - /* map base address of controller */ - Io_mem_session_capability iomem_cap = pci_device->io_mem(pci_device->phys_bar_to_virt(AHCI_BASE_ID)); - iomem.construct(env.rm(), Io_mem_session_client(iomem_cap).dataspace()); - - uint16_t cmd = (uint16_t)pci_device->config_read(PCI_CMD, ::Platform::Device::ACCESS_16BIT); - cmd |= 0x2; /* respond to memory space accesses */ - cmd |= 0x4; /* enable bus master */ - _config_write(PCI_CMD, cmd, ::Platform::Device::ACCESS_16BIT); - - irq.construct(pci_device->irq(0)); -} - - -/************************ - ** Platform interface ** - ************************/ - -Genode::addr_t Ahci::Platform::_mmio_base() const -{ - return addr_t(_data.iomem->local_addr()); -} - - -void Ahci::Platform::sigh_irq(Signal_context_capability sigh) -{ - _data.irq->sigh(sigh); - ack_irq(); -} - - -void Ahci::Platform::ack_irq() { _data.irq->ack_irq(); } - - -Genode::Ram_dataspace_capability Ahci::Platform::alloc_dma_buffer(size_t size) -{ - size_t donate = size; - - return retry( - [&] () { - return retry( - [&] () { return _data.pci.alloc_dma_buffer(size, Genode::UNCACHED); }, - [&] () { _data.pci.upgrade_caps(2); }); - }, - [&] () { - _data.pci.upgrade_ram(donate); - donate = donate * 2 > size ? 4096 : donate * 2; - }); -} - - -void Ahci::Platform::free_dma_buffer(Genode::Ram_dataspace_capability ds) -{ - _data.pci.free_dma_buffer(ds); -} - - -Genode::addr_t Ahci::Platform::dma_addr(Genode::Ram_dataspace_capability ds) -{ - return _data.pci.dma_addr(ds); -} diff --git a/repos/os/src/drivers/ahci/spec/x86/platform.h b/repos/os/src/drivers/ahci/spec/x86/platform.h deleted file mode 100644 index fc5c53b110..0000000000 --- a/repos/os/src/drivers/ahci/spec/x86/platform.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _AHCI__SPEC__X86__PLATFORM_H_ -#define _AHCI__SPEC__X86__PLATFORM_H_ -/* - * \brief Driver for PCI-bus platforms - * \author Sebastian Sumpf - * \date 2020-01-20 - */ - -/* - * Copyright (C) 2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include - -namespace Ahci { - struct Data; - using namespace Genode; -} - -struct Ahci::Data -{ - enum Pci_config { - CLASS_MASS_STORAGE = 0x10000u, - SUBCLASS_AHCI = 0x600u, - CLASS_MASK = 0xffff00u, - AHCI_DEVICE = CLASS_MASS_STORAGE | SUBCLASS_AHCI, - AHCI_BASE_ID = 0x5, /* resource id of ahci base addr */ - PCI_CMD = 0x4, - }; - - Genode::Env &env; - - Platform::Connection pci { env }; - Platform::Device_capability pci_device_cap { }; - Constructible pci_device { }; - Constructible irq { }; - Constructible iomem { }; - - Data(Env &env); - - void _config_write(uint8_t op, uint16_t cmd, - Platform::Device::Access_size width) - { - size_t donate = 4096; - retry( - [&] () { - retry( - [&] () { pci_device->config_write(op, cmd, width); }, - [&] () { pci.upgrade_caps(2); }); - }, - [&] () { - pci.upgrade_ram(donate); - donate *= 2; - }); - } -}; - - -#endif /* _AHCI__SPEC__X86__PLATFORM_H_ */ diff --git a/repos/os/src/drivers/ahci/spec/x86/target.mk b/repos/os/src/drivers/ahci/spec/x86/target.mk deleted file mode 100644 index fe44856e5b..0000000000 --- a/repos/os/src/drivers/ahci/spec/x86/target.mk +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = ahci_drv -REQUIRES = x86 - -INC_DIR += $(REP_DIR)/src/drivers/ahci/spec/x86 - -include $(REP_DIR)/src/drivers/ahci/target.inc - diff --git a/repos/os/src/drivers/ahci/target.inc b/repos/os/src/drivers/ahci/target.inc deleted file mode 100644 index dee2052fcc..0000000000 --- a/repos/os/src/drivers/ahci/target.inc +++ /dev/null @@ -1,8 +0,0 @@ -SRC_CC += main.cc platform.cc -INC_DIR += $(REP_DIR)/src/drivers/ahci -LIBS += base - -CC_CXX_WARN_STRICT_CONVERSION = - -vpath platform.cc $(PRG_DIR) -vpath %.cc $(REP_DIR)/src/drivers/ahci diff --git a/repos/os/src/drivers/ahci/target.mk b/repos/os/src/drivers/ahci/target.mk new file mode 100644 index 0000000000..7d22e9a0dd --- /dev/null +++ b/repos/os/src/drivers/ahci/target.mk @@ -0,0 +1,8 @@ +TARGET = ahci_drv +SRC_CC += main.cc +INC_DIR += $(PRG_DIR) +LIBS += base + +CC_CXX_WARN_STRICT_CONVERSION = + +vpath %.cc $(PRG_DIR)