From 1b7b0b2050dcd10a7a6902d78c81b4363d833959 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Thu, 28 Nov 2013 12:45:20 +0100 Subject: [PATCH] atapi_drv: use generic block component/driver Ref #966 --- os/src/drivers/atapi/ata_device.cc | 55 ++++-- os/src/drivers/atapi/ata_device.h | 97 +++++----- os/src/drivers/atapi/atapi_device.cc | 31 +++- os/src/drivers/atapi/main.cc | 262 ++++----------------------- 4 files changed, 150 insertions(+), 295 deletions(-) diff --git a/os/src/drivers/atapi/ata_device.cc b/os/src/drivers/atapi/ata_device.cc index 7f8dfa099b..0f164a41bf 100644 --- a/os/src/drivers/atapi/ata_device.cc +++ b/os/src/drivers/atapi/ata_device.cc @@ -148,26 +148,30 @@ void Ata::Device::read_capacity() } -void Ata::Device::read(unsigned long block_nr, - unsigned long count, off_t offset) { +void Ata::Device::_read(Genode::size_t block_nr, + Genode::size_t count, + char *buffer, + bool dma) +{ + Genode::size_t offset = 0; while (count > 0) { - unsigned long c = count > 255 ? 255 : count; + Genode::size_t c = count > 255 ? 255 : count; - if (dma_enabled()) { + if (dma) { if (verbose) - PDBG("DMA read: block %lu, c %lu, offset: %08lx, base: %08lx", - block_nr, c, offset, _base_addr); + PDBG("DMA read: block %zu, c %zu, buffer: %p", + block_nr, c, (void*)(buffer + offset)); if (!_lba48) { if (dma_pci_lba28(dev_num(), CMD_READ_DMA, 0, c, block_nr, - (unsigned char *)(_base_addr + offset), c)) + (unsigned char*)(buffer + offset), c)) throw Io_error(); } else { if (dma_pci_lba48(dev_num(), CMD_READ_DMA_EXT, 0, c, 0, block_nr, - (unsigned char *)(_base_addr + offset), c)) + (unsigned char*)(buffer + offset), c)) throw Io_error(); } @@ -176,11 +180,11 @@ void Ata::Device::read(unsigned long block_nr, if (!_lba48) { if (reg_pio_data_in_lba28(dev_num(), CMD_READ_SECTORS, 0, c, block_nr, - (unsigned char *)(_base_addr + offset), c, 0)) + (unsigned char*)(buffer + offset), c, 0)) throw Io_error(); } else { if (reg_pio_data_in_lba48(dev_num(), CMD_READ_SECTORS_EXT, 0, c, 0, block_nr, - (unsigned char *)(_base_addr + offset), c, 0)) + (unsigned char*)(buffer + offset), c, 0)) throw Io_error(); } } @@ -192,27 +196,31 @@ void Ata::Device::read(unsigned long block_nr, } -void Ata::Device::write(unsigned long block_nr, - unsigned long count, off_t offset) { +void Ata::Device::_write(Genode::size_t block_nr, + Genode::size_t count, + char const *buffer, + bool dma) +{ + Genode::size_t offset = 0; while (count > 0) { - unsigned long c = count > 255 ? 255 : count; + Genode::size_t c = count > 255 ? 255 : count; - if (dma_enabled()) { + if (dma) { if (verbose) - PDBG("DMA read: block %lu, c %lu, offset: %08lx, base: %08lx", - block_nr, c, offset, _base_addr); + PDBG("DMA read: block %zu, c %zu, buffer: %p", + block_nr, c, (void*)(buffer + offset)); if (!_lba48) { if (dma_pci_lba28(dev_num(), CMD_WRITE_DMA, 0, c, block_nr, - (unsigned char *)(_base_addr + offset), c)) + (unsigned char*)(buffer + offset), c)) throw Io_error(); } else { if (dma_pci_lba48(dev_num(), CMD_WRITE_DMA_EXT, 0, c, 0, block_nr, - (unsigned char *)(_base_addr + offset), c)) + (unsigned char*)(buffer + offset), c)) throw Io_error(); } @@ -221,11 +229,11 @@ void Ata::Device::write(unsigned long block_nr, if (!_lba48) { if (reg_pio_data_out_lba28(dev_num(), CMD_WRITE_SECTORS, 0, c, block_nr, - (unsigned char *)(_base_addr + offset), c, 0)) + (unsigned char*)(buffer + offset), c, 0)) throw Io_error(); } else { if (reg_pio_data_out_lba48(dev_num(), CMD_WRITE_SECTORS_EXT, 0, c, 0, block_nr, - (unsigned char *)(_base_addr + offset), c, 0)) + (unsigned char*)(buffer + offset), c, 0)) throw Io_error(); } } @@ -300,3 +308,10 @@ Ata::Device * Ata::Device::probe_legacy(int search_type) } +Block::Session::Operations Ata::Device::ops() +{ + Block::Session::Operations o; + o.set_operation(Block::Packet_descriptor::READ); + o.set_operation(Block::Packet_descriptor::WRITE); + return o; +} diff --git a/os/src/drivers/atapi/ata_device.h b/os/src/drivers/atapi/ata_device.h index 2592efaf19..d59fe81fdc 100644 --- a/os/src/drivers/atapi/ata_device.h +++ b/os/src/drivers/atapi/ata_device.h @@ -16,6 +16,7 @@ #include #include +#include namespace Genode { class Io_port_session; @@ -26,7 +27,7 @@ namespace Ata { class Bus_master; - class Device + class Device : public Block::Driver { /* I/O back end may access private data (see io.cc) */ @@ -44,7 +45,6 @@ namespace Ata { unsigned _block_start; unsigned _block_end; unsigned _block_size; - Genode::addr_t _base_addr; bool _lba48; bool _host_protected_area; @@ -61,9 +61,20 @@ namespace Ata { Genode::Irq_connection *irq() { return _irq; } Genode::Io_port_session *io() { return _pio; } + virtual void _read(Genode::size_t block_number, + Genode::size_t block_count, + char *out_buffer, + bool dma); + virtual void _write(Genode::size_t block_number, + Genode::size_t block_count, + char const *buffer, + bool dma); public: + class Exception : public ::Genode::Exception { }; + class Io_error : public Exception { }; + /** * Constructor * @@ -90,54 +101,46 @@ namespace Ata { */ static Device * probe_legacy(int search_type); - /** - * Return number of blocks - */ - unsigned block_count() { return _block_end - _block_start + 1; } - - /** - * Return actual block size in bytes - */ - unsigned block_size() { return _block_size; } - /** * Read block size and block count (from device), * updates block_count and block_size */ virtual void read_capacity(); - /** - * Read one or more blocks from the device - * - * \param block_nr Block number to read - * \param count Number of blocks to read - * \param offset Offset in I/O buffer - */ - virtual void read(unsigned long block_nr, - unsigned long count, Genode::off_t offset); - /** - * Write one or more blocks to the device - * - * \param block_nr Block number to read - * \param count Number of blocks to read - * \param offset Offset in I/O buffer - */ - virtual void write(unsigned long block_nr, - unsigned long count, Genode::off_t offset); + /******************************* + ** Block::Driver interface ** + *******************************/ - /** - * Set I/O buffer base address - */ - void set_base_addr(Genode::addr_t addr) { _base_addr = addr; } + Genode::size_t block_count() { + return _block_end - _block_start + 1; } + Genode::size_t block_size() { return _block_size; } + + virtual Block::Session::Operations ops(); + + void read(Genode::size_t block_number, + Genode::size_t block_count, + char *buffer) { + _read(block_number, block_count, buffer, false); } + void write(Genode::size_t block_number, + Genode::size_t block_count, + char const *buffer) { + _write(block_number, block_count, buffer, false); } + void read_dma(Genode::size_t block_number, + Genode::size_t block_count, + Genode::addr_t phys) { + _read(block_number, block_count, (char*)phys, true); } + void write_dma(Genode::size_t block_number, + Genode::size_t block_count, + Genode::addr_t phys) { + _write(block_number, block_count, (char*)phys, true); } - /** - * Return true if DMA is enabled by device - */ bool dma_enabled() { return _dma; } - class Exception : public ::Genode::Exception { }; - class Io_error : public Exception { }; + Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) { + return Genode::env()->ram_session()->alloc(size, false); } + + void sync() {} }; @@ -146,17 +149,23 @@ namespace Ata { private: int read_sense(unsigned char *sense, int length); + void read_capacity(); + + void _read(Genode::size_t block_number, + Genode::size_t block_count, + char *out_buffer, + bool dma); + void _write(Genode::size_t block_number, + Genode::size_t block_count, + char const *buffer, + bool dma); public: Atapi_device(unsigned base_cmd, unsigned base_ctrl); - void read_capacity(); - void read(unsigned long block_nr, - unsigned long count, Genode::off_t offset); bool test_unit_ready(int level = 0); - void write(unsigned long block_nr, - unsigned long count, Genode::off_t offset); + Block::Session::Operations ops(); }; } #endif diff --git a/os/src/drivers/atapi/atapi_device.cc b/os/src/drivers/atapi/atapi_device.cc index 986dbd682e..989dcb6a3b 100644 --- a/os/src/drivers/atapi/atapi_device.cc +++ b/os/src/drivers/atapi/atapi_device.cc @@ -101,8 +101,10 @@ void Atapi_device::read_capacity() } -void Atapi_device::read(unsigned long block_nr, unsigned long count, - off_t offset) +void Atapi_device::_read(Genode::size_t block_nr, + Genode::size_t count, + char *buffer, + bool dma) { unsigned char cmd[12]; memset(cmd, 0, 12); @@ -124,20 +126,31 @@ void Atapi_device::read(unsigned long block_nr, unsigned long count, cmd[7] = (count >> 8) & 0xff; cmd[8] = count & 0xff; - if (dma_enabled()) { + if (dma) { if (verbose) - PDBG("DMA read: block %lu, count %lu, offset: %08lx, base: %08lx", - block_nr, count, offset, _base_addr); + PDBG("DMA read: block %zu, count %zu, buffer: %p", + block_nr, count, (void*)buffer); if (dma_pci_packet(dev_num(), 12, cmd, 0, count * _block_size, - (unsigned char*)(_base_addr + offset))) + (unsigned char*)buffer)) throw Io_error(); } else { if (reg_packet(dev_num(), 12, cmd, 0, count * _block_size, - (unsigned char*)(_base_addr + offset))) + (unsigned char*)buffer)) throw Io_error(); } } -void Atapi_device::write(unsigned long block_nr, unsigned long count, - off_t offset) { throw Io_error(); } + +void Atapi_device::_write(Genode::size_t block_number, + Genode::size_t block_count, + char const *buffer, + bool dma) { throw Io_error(); } + + +Block::Session::Operations Atapi_device::ops() +{ + Block::Session::Operations o; + o.set_operation(Block::Packet_descriptor::READ); + return o; +} diff --git a/os/src/drivers/atapi/main.cc b/os/src/drivers/atapi/main.cc index 7bf621b19e..e4cfa38881 100644 --- a/os/src/drivers/atapi/main.cc +++ b/os/src/drivers/atapi/main.cc @@ -14,13 +14,9 @@ /* Genode includes */ #include -#include -#include -#include #include #include -#include -#include +#include /* local includes */ #include "ata_device.h" @@ -29,231 +25,45 @@ using namespace Genode; using namespace Ata; -namespace Block { +struct Factory : Block::Driver_factory +{ + Ata::Device *device; - class Session_component : public Session_rpc_object + Factory() : device(0) { - private: + /* determine if we probe for ATA or ATAPI */ + bool ata = false; + try { + ata = config()->xml_node().attribute("ata").has_value("yes"); + } catch (...) {} - class Tx_thread : public Genode::Thread<8192> - { - private: + int type = ata ? REG_CONFIG_TYPE_ATA : REG_CONFIG_TYPE_ATAPI; - Session_component *_session; + /* + * Probe for ATA(PI) device, but only once + */ + device = Ata::Device::probe_legacy(type); + device->read_capacity(); + } - public: - - Tx_thread(Session_component *session) - : Thread("block_session_tx"), _session(session) { } - - void entry() - { - using namespace Genode; - - Session_component::Tx::Sink *tx_sink = _session->tx_sink(); - Block::Packet_descriptor packet; - - _session->tx_ready(); - - /* handle requests */ - while (true) { - - /* blocking-get packet from client */ - packet = tx_sink->get_packet(); - if (!packet.valid()) { - PWRN("received invalid packet"); - continue; - } - - packet.succeeded(false); - - switch (packet.operation()) { - - case Block::Packet_descriptor::READ: - - try { - _session->device()->read(packet.block_number(), - packet.block_count(), - packet.offset()); - packet.succeeded(true); - } - catch (Ata::Device::Io_error) { - PWRN("Io error!"); - } - break; - - case Block::Packet_descriptor::WRITE: - try { - _session->device()->write(packet.block_number(), - packet.block_count(), - packet.offset()); - packet.succeeded(true); - } - catch (Ata::Device::Io_error) { - PWRN("Io error!"); - } - break; - - default: - PWRN("received invalid packet"); - continue; - } - - /* acknowledge packet to the client */ - if (!tx_sink->ready_to_ack()) - PDBG("need to wait until ready-for-ack"); - tx_sink->acknowledge_packet(packet); - } - } - }; - - private: - - Genode::Dataspace_capability _tx_ds; /* buffer for tx channel */ - Genode::Semaphore _startup_sema; /* thread startup sync */ - Tx_thread _tx_thread; - Ata::Device *_device; - - public: - - /** - * Constructor - * - * \param tx_ds dataspace used for tx channel - * \param ep entry point used for packet stream - */ - Session_component(Genode::Dataspace_capability tx_ds, - Genode::Rpc_entrypoint &ep, - Ata::Device *device) - : Session_rpc_object(tx_ds, ep), _tx_ds(tx_ds), - _startup_sema(0), _tx_thread(this), _device(device) - { - /* - * Determine I/O-buffer address. Map for LBA, - * use physical address for DMA - */ - addr_t base; - if (!_device->dma_enabled()) { - base = env()->rm_session()->attach(tx_ds); - } - else { - Genode::Dataspace_client client(tx_ds); - base = client.phys_addr(); - } - - _device->set_base_addr(base); - - _tx_thread.start(); - _startup_sema.down(); - } - - void info(Genode::size_t *blk_count, Genode::size_t *blk_size, - Operations *ops) - { - _device->read_capacity(); - *blk_count = _device->block_count(); - *blk_size = _device->block_size(); - ops->set_operation(Packet_descriptor::READ); - - if (!(dynamic_cast(_device))) - ops->set_operation(Packet_descriptor::WRITE); - } - - void sync() {} - - Ata::Device* device() { return _device; }; - - /** - * Signal indicating that transmit thread is ready - */ - void tx_ready() { _startup_sema.up(); } - }; - - /* - * Shortcut for single-client root component - */ - typedef Genode::Root_component - Root_component; - - /** - * Root component, handling new session requests - */ - class Root : public Root_component + Block::Driver *create() { - private: + if (!device) { + PERR("No device present"); + throw Root::Unavailable(); + } - Genode::Rpc_entrypoint &_ep; - Ata::Device *_device; - - protected: - - /** - * Always returns the singleton block-session component - */ - Session_component *_create_session(const char *args) - { - using namespace Genode; - - Genode::size_t ram_quota = - Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); - Genode::size_t tx_buf_size = - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); - - /* delete ram quota by the memory needed for the session */ - Genode::size_t session_size = max((Genode::size_t)4096, - sizeof(Session_component) - + sizeof(Allocator_avl)); - if (ram_quota < session_size) - throw Root::Quota_exceeded(); - - /* - * Check if donated ram quota suffices for both - * communication buffers. Also check both sizes separately - * to handle a possible overflow of the sum of both sizes. - */ - if (tx_buf_size > ram_quota - session_size) { - PERR("insufficient 'ram_quota', got %zd, need %zd", - ram_quota, tx_buf_size + session_size); - throw Root::Quota_exceeded(); - } - - /* determine if we probe for ATA or ATAPI */ - bool probe_ata = false; - try { - probe_ata = Genode::config()->xml_node().attribute("ata").has_value("yes"); } - catch (...) {} - - int type = probe_ata ? REG_CONFIG_TYPE_ATA : REG_CONFIG_TYPE_ATAPI; - - /* - * Probe for ATA(PI) device, but only once - */ - if (!_device) - _device = Ata::Device::probe_legacy(type); - - if (!_device) { - PERR("No device present"); - throw Root::Unavailable(); - } - - if (Atapi_device *atapi_device = dynamic_cast(_device)) - if (!atapi_device->test_unit_ready()) { - PERR("No disc present"); - throw Root::Unavailable(); - } - - return new (md_alloc()) - Session_component(env()->ram_session()->alloc(tx_buf_size), _ep, _device); + if (Atapi_device *atapi_device = dynamic_cast(device)) + if (!atapi_device->test_unit_ready()) { + PERR("No disc present"); + throw Root::Unavailable(); } - public: + return device; + } - Root(Genode::Rpc_entrypoint *session_ep, - Genode::Allocator *md_alloc) - : Root_component(session_ep, md_alloc), _ep(*session_ep), _device(0) { } - }; -} + void destroy(Block::Driver *driver) { } +}; int main() @@ -262,8 +72,16 @@ int main() static Cap_connection cap; static Rpc_entrypoint ep(&cap, STACK_SIZE, "atapi_ep"); - static Block::Root block_root(&ep, env()->heap()); + static Signal_receiver receiver; + static Factory driver_factory; + static Block::Root block_root(&ep, env()->heap(), driver_factory, receiver); + env()->parent()->announce(ep.manage(&block_root)); - sleep_forever(); + + while (true) { + Signal s = receiver.wait_for_signal(); + static_cast(s.context())->dispatch(s.num()); + } + return 0; }