seoul: fix disc boot

Additionally use the block session interface asynchronously to let the VM
continue execution.

Fixes #806
This commit is contained in:
Alexander Boettcher 2013-06-16 22:46:04 +02:00 committed by Norman Feske
parent b9449a4279
commit b1cb1ceaf9
2 changed files with 248 additions and 79 deletions

View File

@ -1,6 +1,7 @@
/*
* \brief Block interface
* \author Markus Partheymueller
* \author Alexander Boettcher
* \date 2012-09-15
*/
@ -25,30 +26,44 @@
#include <base/thread.h>
#include <block_session/connection.h>
#include <util/string.h>
#include <base/heap.h>
#include <base/lock.h>
/* local includes */
#include <disk.h>
#include <utcb_guard.h>
static Genode::Native_utcb utcb_backup;
/* Seoul includes */
#include <host/dma.h>
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<Vancouver_disk_signal *>(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<Genode::addr_t>(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;
}

View File

@ -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 <base/allocator_avl.h>
@ -28,33 +29,98 @@
#include <base/thread.h>
#include <block_session/connection.h>
#include <util/string.h>
#include <base/sync_allocator.h>
/* local includes */
#include <synced_motherboard.h>
/* NOVA userland includes */
#include <host/dma.h>
class Vancouver_disk;
static const bool read_only = false;
class Vancouver_disk_signal : public Genode::Signal_dispatcher<Vancouver_disk>
{
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<Vancouver_disk>(sig_rec, obj, member),
_disk_nr(disk_nr) {}
unsigned disk_nr() { return _disk_nr; }
};
class Vancouver_disk : public Genode::Thread<8192>, public StaticReceiver<Vancouver_disk>
{
private:
enum { MAX_DISKS = 16 };
/* helper class to lookup a MessageDisk object */
class Avl_entry : public Genode::Avl_node<Avl_entry>
{
private:
Genode::addr_t _key;
MessageDisk * _msg;
public:
Avl_entry(void * key, MessageDisk * msg)
: _key(reinterpret_cast<Genode::addr_t>(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, 128> MessageDisk_Slab;
typedef Genode::Synchronized_allocator<MessageDisk_Slab> MessageDisk_Slab_Sync;
typedef Genode::Tslab<DmaDescriptor, 256> DmaDesc_Slab;
typedef Genode::Synchronized_allocator<DmaDesc_Slab> 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, 128> Avl_entry_slab;
typedef Genode::Synchronized_allocator<Avl_entry_slab> Avl_entry_slab_sync;
Avl_entry_slab_sync _tslab_avl;
Genode::Avl_tree<Avl_entry> _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<Vancou
void register_host_operations(Motherboard &);
};
#endif /* _DISK_H_ */
#endif /* _VANCOUVER_DISK_H_ */