diff --git a/ports/src/vancouver/disk.cc b/ports/src/vancouver/disk.cc
index 46a4e81bb3..f0076ed4d5 100644
--- a/ports/src/vancouver/disk.cc
+++ b/ports/src/vancouver/disk.cc
@@ -1,6 +1,7 @@
/*
* \brief Block interface
* \author Markus Partheymueller
+ * \author Alexander Boettcher
* \date 2012-09-15
*/
@@ -25,30 +26,44 @@
#include
#include
#include
+#include
+#include
/* local includes */
#include
#include
-static Genode::Native_utcb utcb_backup;
+/* Seoul includes */
+#include
+
+static Genode::Signal_receiver* disk_receiver()
+{
+ static Genode::Signal_receiver receiver;
+ return &receiver;
+}
+
+
+static Genode::Heap * disk_heap() {
+ using namespace Genode;
+ static Heap heap(env()->ram_session(), env()->rm_session(), 4096);
+ return &heap;
+}
Vancouver_disk::Vancouver_disk(Synced_motherboard &mb,
char * backing_store_base,
char * backing_store_fb_base)
:
- _startup_lock(Genode::Lock::LOCKED),
_motherboard(mb), _backing_store_base(backing_store_base),
- _backing_store_fb_base(backing_store_fb_base)
+ _backing_store_fb_base(backing_store_fb_base),
+ _tslab_msg(disk_heap()), _tslab_dma(disk_heap()), _tslab_avl(disk_heap())
{
/* initialize struct with 0 size */
for (int i=0; i < MAX_DISKS; i++) {
_diskcon[i].blk_size = 0;
}
- start();
- /* shake hands with disk thread */
- _startup_lock.lock();
+ start();
}
@@ -62,12 +77,96 @@ void Vancouver_disk::entry()
{
Logging::printf("Hello, this is Vancouver_disk.\n");
- _startup_lock.unlock();
+ while (true) {
+ Genode::Signal signal = disk_receiver()->wait_for_signal();
+ Vancouver_disk_signal * disk_source =
+ reinterpret_cast(signal.context());
+
+ this->_signal_dispatch_entry(disk_source->disk_nr());
+ }
+}
+
+
+void Vancouver_disk::_signal_dispatch_entry(unsigned disknr)
+{
+ Block::Session::Tx::Source *source = _diskcon[disknr].blk_con->tx();
+
+ while (source->ack_avail())
+ {
+ Block::Packet_descriptor packet = source->get_acked_packet();
+ char * source_addr = source->packet_content(packet);
+
+ /* find the corresponding MessageDisk object */
+ Avl_entry * obj = 0;
+ {
+ Genode::Lock::Guard lock_guard(_lookup_msg_lock);
+ obj = _lookup_msg.first();
+ if (obj)
+ obj = obj->find(reinterpret_cast(source_addr));
+
+ if (!obj) {
+ PWRN("Unknown MessageDisk object - drop ack of block session");
+ continue;
+ }
+
+ /* remove helper object */
+ _lookup_msg.remove(obj);
+ }
+ /* got the MessageDisk object */
+ MessageDisk * msg = obj->msg();
+ /* delete helper object */
+ destroy(&_tslab_avl, obj);
+
+ /* go ahead and tell VMM about new block event */
+ if (!packet.succeeded() ||
+ !(packet.operation() == Block::Packet_descriptor::Opcode::READ ||
+ packet.operation() == Block::Packet_descriptor::Opcode::WRITE)) {
+
+ PDBG("Getting block failed !");
+
+ MessageDiskCommit mdc(disknr, msg->usertag,
+ MessageDisk::DISK_STATUS_DEVICE);
+ _motherboard()->bus_diskcommit.send(mdc);
+
+ } else {
+
+ if (packet.operation() == Block::Packet_descriptor::Opcode::READ) {
+
+ unsigned long long sector = msg->sector;
+ sector = (sector-packet.block_number()) * _diskcon[disknr].blk_size;
+
+ for (unsigned i = 0; i < msg->dmacount; i++) {
+ char * dma_addr = _backing_store_base +
+ msg->dma[i].byteoffset + msg->physoffset;
+
+ // check for bounds
+ if (dma_addr >= _backing_store_fb_base ||
+ dma_addr < _backing_store_base) {
+ PERR("dma bounds violation");
+ } else
+ memcpy(dma_addr, source_addr + sector,
+ msg->dma[i].bytecount);
+
+ sector += msg->dma[i].bytecount;
+ }
+
+ destroy(&_tslab_dma, msg->dma);
+ msg->dma = 0;
+ }
+
+ MessageDiskCommit mdc (disknr, msg->usertag, MessageDisk::DISK_OK);
+ _motherboard()->bus_diskcommit.send(mdc);
+ }
+
+ source->release_packet(packet);
+ destroy(&_tslab_msg, msg);
+ }
}
bool Vancouver_disk::receive(MessageDisk &msg)
{
+ static Genode::Native_utcb utcb_backup;
Utcb_guard guard(utcb_backup);
if (msg.disknr >= MAX_DISKS)
@@ -83,17 +182,26 @@ bool Vancouver_disk::receive(MessageDisk &msg)
if (!_diskcon[msg.disknr].blk_size) {
try {
- Genode::Allocator_avl * block_alloc = new Genode::Allocator_avl(Genode::env()->heap());
- _diskcon[msg.disknr].blk_con = new Block::Connection(block_alloc, 4*512*1024, label);
+ Genode::Allocator_avl * block_alloc =
+ new Genode::Allocator_avl(disk_heap());
+
+ _diskcon[msg.disknr].blk_con =
+ new Block::Connection(block_alloc, 4*512*1024, label);
+ _diskcon[msg.disknr].dispatcher =
+ new Vancouver_disk_signal(*disk_receiver(), *this,
+ &Vancouver_disk::_signal_dispatch_entry,
+ msg.disknr);
+
+ _diskcon[msg.disknr].blk_con->tx_channel()->sigh_ack_avail(
+ *_diskcon[msg.disknr].dispatcher);
} catch (...) {
/* there is none. */
return false;
}
- _diskcon[msg.disknr].blk_con->info(
- &_diskcon[msg.disknr].blk_cnt,
- &_diskcon[msg.disknr].blk_size,
- &_diskcon[msg.disknr].ops);
+ _diskcon[msg.disknr].blk_con->info(&_diskcon[msg.disknr].blk_cnt,
+ &_diskcon[msg.disknr].blk_size,
+ &_diskcon[msg.disknr].ops);
Logging::printf("Got info: %lu blocks (%u B), ops (R: %x, W:%x)\n ",
_diskcon[msg.disknr].blk_cnt,
@@ -105,10 +213,11 @@ bool Vancouver_disk::receive(MessageDisk &msg)
Block::Session::Tx::Source *source = _diskcon[msg.disknr].blk_con->tx();
+ msg.error = MessageDisk::DISK_OK;
+
switch (msg.type) {
case MessageDisk::DISK_GET_PARAMS:
{
- msg.error = MessageDisk::DISK_OK;
msg.params->flags = DiskParameter::FLAG_HARDDISK;
msg.params->sectors = _diskcon[msg.disknr].blk_cnt;
msg.params->sectorsize = _diskcon[msg.disknr].blk_size;
@@ -120,9 +229,9 @@ bool Vancouver_disk::receive(MessageDisk &msg)
case MessageDisk::DISK_READ:
case MessageDisk::DISK_WRITE:
{
- bool read = (msg.type == MessageDisk::DISK_READ);
+ bool write = (msg.type == MessageDisk::DISK_WRITE);
- if (!read && !_diskcon[msg.disknr].ops.supported(Block::Packet_descriptor::WRITE)) {
+ if (write && !_diskcon[msg.disknr].ops.supported(Block::Packet_descriptor::WRITE)) {
MessageDiskCommit ro(msg.disknr, msg.usertag,
MessageDisk::DISK_STATUS_DEVICE);
_motherboard()->bus_diskcommit.send(ro);
@@ -132,80 +241,74 @@ bool Vancouver_disk::receive(MessageDisk &msg)
unsigned long long sector = msg.sector;
unsigned long total = DmaDescriptor::sum_length(msg.dmacount, msg.dma);
unsigned long blocks = total/_diskcon[msg.disknr].blk_size;
+ unsigned const blk_size = _diskcon[msg.disknr].blk_size;
- if (blocks*_diskcon[msg.disknr].blk_size < total)
- blocks++;
+ if (blocks * blk_size < total) blocks++;
Block::Session::Tx::Source *source = _diskcon[msg.disknr].blk_con->tx();
- Block::Packet_descriptor
- p(source->alloc_packet(blocks*_diskcon[msg.disknr].blk_size),
- (read) ? Block::Packet_descriptor::READ
- : Block::Packet_descriptor::WRITE,
- sector,
- blocks);
+ Block::Packet_descriptor packet;
- if (read) {
- source->submit_packet(p);
- p = source->get_acked_packet();
+ /* save original msg, required when we get acknowledgements */
+ MessageDisk * msg_cpy = 0;
+ try {
+ msg_cpy = new (&_tslab_msg) MessageDisk(msg);
+
+ packet = Block::Packet_descriptor(
+ source->alloc_packet(blocks * blk_size),
+ (write) ? Block::Packet_descriptor::WRITE
+ : Block::Packet_descriptor::READ,
+ sector, blocks);
+ } catch (...) {
+ if (msg_cpy)
+ destroy(&_tslab_msg, msg_cpy);
+ Logging::printf("could not allocate disk block elements\n");
+ return false;
}
- if (!read || p.succeeded()) {
- char * source_addr = source->packet_content(p);
+ char * source_addr = source->packet_content(packet);
+ {
+ Genode::Lock::Guard lock_guard(_lookup_msg_lock);
+ _lookup_msg.insert(new (&_tslab_avl) Avl_entry(source_addr,
+ msg_cpy));
+ }
- sector = (sector-p.block_number())*_diskcon[msg.disknr].blk_size;
+ /* copy DMA descriptors for read requests - they may change */
+ if (!write) {
+ msg_cpy->dma = new (&_tslab_dma) DmaDescriptor[msg_cpy->dmacount];
+ for (unsigned i = 0; i < msg_cpy->dmacount; i++)
+ memcpy(msg_cpy->dma + i, msg.dma + i, sizeof(DmaDescriptor));
+ }
- for (int i=0; i< msg.dmacount; i++) {
- char * dma_addr = (char *) (msg.dma[i].byteoffset + msg.physoffset
- + _backing_store_base);
- /* check for bounds */
- if (dma_addr >= _backing_store_fb_base
- || dma_addr < _backing_store_base)
- return false;
+ /* for write operation */
+ source_addr += (sector - packet.block_number()) * blk_size;
- if (read)
- memcpy(dma_addr, source_addr+sector, msg.dma[i].bytecount);
- else
- memcpy(source_addr+sector, dma_addr, msg.dma[i].bytecount);
+ /* check bounds for read and write operations */
+ for (unsigned i = 0; i < msg_cpy->dmacount; i++) {
+ char * dma_addr = _backing_store_base + msg_cpy->dma[i].byteoffset
+ + msg_cpy->physoffset;
- sector += msg.dma[i].bytecount;
+ /* check for bounds */
+ if (dma_addr >= _backing_store_fb_base ||
+ dma_addr < _backing_store_base) {
+ /* drop allocated objects not needed in error case */
+ if (write)
+ destroy(&_tslab_dma, msg_cpy->dma);
+ destroy(&_tslab_msg, msg_cpy);
+ source->release_packet(packet);
+ return false;
}
- if (!read) {
- source->submit_packet(p);
- p = source->get_acked_packet();
- if (!p.succeeded()) {
- Logging::printf("Operation failed.\n");
- {
- MessageDiskCommit commit(msg.disknr, msg.usertag,
- MessageDisk::DISK_STATUS_DEVICE);
- _motherboard()->bus_diskcommit.send(commit);
- break;
- }
- }
- }
-
- {
- MessageDiskCommit commit(msg.disknr, msg.usertag,
- MessageDisk::DISK_OK);
- _motherboard()->bus_diskcommit.send(commit);
- }
- } else {
-
- Logging::printf("Operation failed.\n");
- {
- MessageDiskCommit commit(msg.disknr, msg.usertag,
- MessageDisk::DISK_STATUS_DEVICE);
- _motherboard()->bus_diskcommit.send(commit);
+ if (write) {
+ memcpy(source_addr, dma_addr, msg.dma[i].bytecount);
+ source_addr += msg.dma[i].bytecount;
}
}
- source->release_packet(p);
+ source->submit_packet(packet);
}
break;
-
default:
-
Logging::printf("Got MessageDisk type %x\n", msg.type);
return false;
}
diff --git a/ports/src/vancouver/disk.h b/ports/src/vancouver/disk.h
index 3551a58d5a..fa579a2369 100644
--- a/ports/src/vancouver/disk.h
+++ b/ports/src/vancouver/disk.h
@@ -1,6 +1,7 @@
/*
* \brief Block interface
* \author Markus Partheymueller
+ * \author Alexander Boettcher
* \date 2012-09-15
*/
@@ -18,8 +19,8 @@
* conditions of the GNU General Public License version 2.
*/
-#ifndef _DISK_H_
-#define _DISK_H_
+#ifndef _VANCOUVER_DISK_H_
+#define _VANCOUVER_DISK_H_
/* Genode includes */
#include
@@ -28,33 +29,98 @@
#include
#include
#include
+#include
/* local includes */
#include
-/* NOVA userland includes */
-#include
+class Vancouver_disk;
-static const bool read_only = false;
+class Vancouver_disk_signal : public Genode::Signal_dispatcher
+{
+ private:
+
+ unsigned _disk_nr;
+
+ public:
+
+ Vancouver_disk_signal(Genode::Signal_receiver &sig_rec,
+ Vancouver_disk &obj,
+ void (Vancouver_disk::*member)(unsigned),
+ unsigned disk_nr)
+ : Genode::Signal_dispatcher(sig_rec, obj, member),
+ _disk_nr(disk_nr) {}
+
+ unsigned disk_nr() { return _disk_nr; }
+};
class Vancouver_disk : public Genode::Thread<8192>, public StaticReceiver
{
private:
- enum { MAX_DISKS = 16 };
+ /* helper class to lookup a MessageDisk object */
+ class Avl_entry : public Genode::Avl_node
+ {
+
+ private:
+
+ Genode::addr_t _key;
+ MessageDisk * _msg;
+
+ public:
+
+ Avl_entry(void * key, MessageDisk * msg)
+ : _key(reinterpret_cast(key)), _msg(msg) { }
+
+ bool higher(Avl_entry *e) { return e->_key > _key; }
+
+ Avl_entry *find(Genode::addr_t ptr)
+ {
+ if (ptr == _key) return this;
+ Avl_entry *obj = this->child(ptr > _key);
+ return obj ? obj->find(ptr) : 0;
+ }
+
+ MessageDisk * msg() { return _msg; }
+ };
+
+ /* block session used by disk models of VMM */
+ enum { MAX_DISKS = 4 };
struct {
Block::Connection *blk_con;
Block::Session::Operations ops;
Genode::size_t blk_size;
Genode::size_t blk_cnt;
+ Vancouver_disk_signal *dispatcher;
} _diskcon[MAX_DISKS];
- Genode::Lock _startup_lock;
Synced_motherboard &_motherboard;
char *_backing_store_base;
char *_backing_store_fb_base;
+ /* slabs for temporary holding DMADescriptor and MessageDisk objects */
+ typedef Genode::Tslab MessageDisk_Slab;
+ typedef Genode::Synchronized_allocator MessageDisk_Slab_Sync;
+
+ typedef Genode::Tslab DmaDesc_Slab;
+ typedef Genode::Synchronized_allocator DmaDesc_Slab_Sync;
+
+ MessageDisk_Slab_Sync _tslab_msg;
+ DmaDesc_Slab_Sync _tslab_dma;
+
+ /* Structure to find back the MessageDisk object out of a Block Ack */
+ typedef Genode::Tslab Avl_entry_slab;
+ typedef Genode::Synchronized_allocator Avl_entry_slab_sync;
+
+ Avl_entry_slab_sync _tslab_avl;
+
+ Genode::Avl_tree _lookup_msg;
+ Genode::Lock _lookup_msg_lock;
+
+ /* entry function if signal must be dispatched */
+ void _signal_dispatch_entry(unsigned);
+
public:
/**
@@ -73,4 +139,4 @@ class Vancouver_disk : public Genode::Thread<8192>, public StaticReceiver