mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-09 04:15:52 +00:00
parent
4c74af274b
commit
1b7b0b2050
@ -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;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <base/exception.h>
|
||||
#include <base/stdint.h>
|
||||
#include <block/driver.h>
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -14,13 +14,9 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/semaphore.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <root/component.h>
|
||||
#include <util/xml_node.h>
|
||||
#include <block/component.h>
|
||||
|
||||
/* 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<Atapi_device *>(_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<Session_component,
|
||||
Genode::Single_client>
|
||||
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<Atapi_device *>(_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<Atapi_device *>(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<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user