genode/repos/os/src/server/tz_vmm/include/block_driver.h

158 lines
3.8 KiB
C++

/*
* \brief Paravirtualized access to block devices for VMs
* \author Martin Stein
* \date 2015-10-23
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _BLOCK_DRIVER_H_
#define _BLOCK_DRIVER_H_
/* Genode includes */
#include <block_session/connection.h>
#include <base/allocator_avl.h>
/* local includes */
#include <vm_base.h>
namespace Genode {
class Xml_node;
class Block_driver;
}
class Genode::Block_driver
{
private:
/*
* Noncopyable
*/
Block_driver(Block_driver const &);
Block_driver &operator = (Block_driver const &);
using Packet_descriptor = Block::Packet_descriptor;
struct Device_function_failed : Exception { };
class Request_cache
{
private:
enum { NR_OF_ENTRIES = Block::Session::TX_QUEUE_SIZE };
struct No_matching_entry : Exception { };
struct Entry { void *pkt; void *req; } _entries[NR_OF_ENTRIES];
unsigned _find(void *packet);
void _free(unsigned id) { _entries[id].pkt = 0; }
public:
struct Full : Exception { };
Request_cache() {
for (unsigned i = 0; i < NR_OF_ENTRIES; i++) { _free(i); } }
void insert(void *pkt, void *req);
void remove(void *pkt, void **req);
};
class Device
{
public:
enum { TX_BUF_SIZE = 5 * 1024 * 1024 };
using Id = Id_space<Device>::Id;
using Name = String<64>;
private:
Request_cache _cache { };
Vm_base &_vm;
Name const _name;
unsigned const _irq;
Signal_handler<Device> _irq_handler;
Block::Connection<> _session;
Id_space<Device>::Element _id_space_elem;
Block::Session::Info const _info { _session.info() };
public:
void _handle_irq() { _vm.inject_irq(_irq); }
public:
struct Invalid : Exception { };
Device(Env &env,
Xml_node node,
Range_allocator &alloc,
Id_space<Device> &id_space,
Id id,
Vm_base &vm);
void start_irq_handling();
Request_cache &cache() { return _cache; }
Block::Connection<> &session() { return _session; }
size_t block_size() const { return _info.block_size; }
size_t block_count() const { return _info.block_count; }
bool writeable() const { return _info.writeable; }
Name const &name() const { return _name; }
unsigned irq() const { return _irq; }
};
void *_buf = nullptr;
size_t _buf_size = 0;
Id_space<Device> _devs;
unsigned _dev_count = 0;
Allocator_avl _dev_alloc;
void _buf_to_pkt(void *dst, size_t sz);
void _name(Vm_base &vm);
void _block_count(Vm_base &vm);
void _block_size(Vm_base &vm);
void _queue_size(Vm_base &vm);
void _writeable(Vm_base &vm);
void _irq(Vm_base &vm);
void _buffer(Vm_base &vm);
void _device_count(Vm_base &vm);
void _new_request(Vm_base &vm);
void _submit_request(Vm_base &vm);
void _collect_reply(Vm_base &vm);
template <typename DEV_FUNC, typename ERR_FUNC>
void _dev_apply(Device::Id id,
DEV_FUNC const &dev_func,
ERR_FUNC const &err_func)
{
try { _devs.apply<Device>(id, [&] (Device &dev) { dev_func(dev); }); }
catch (Id_space<Device>::Unknown_id) {
error("unknown block device ", id);
err_func();
}
catch (Device_function_failed) { err_func(); }
}
public:
void handle_smc(Vm_base &vm);
Block_driver(Env &env,
Xml_node config,
Allocator &alloc,
Vm_base &vm);
};
#endif /* _BLOCK_DRIVER_H_ */