mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
seoul: fix disc boot
Additionally use the block session interface asynchronously to let the VM continue execution. Fixes #806
This commit is contained in:
parent
b9449a4279
commit
b1cb1ceaf9
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user