genode/repos/os/src/server/rom_block/main.cc

128 lines
3.1 KiB
C++

/*
* \brief Provide a rom-file as block device (aka loop devices)
* \author Stefan Kalkowski
* \date 2010-07-07
*/
/*
* Copyright (C) 2010-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.
*/
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/log.h>
#include <block/component.h>
#include <rom_session/connection.h>
using namespace Genode;
class Rom_block : public Block::Driver
{
private:
Env &_env;
Rom_connection _rom;
size_t _blk_sz;
Dataspace_capability _file_cap = _rom.dataspace();
addr_t _file_addr = _env.rm().attach(_file_cap);
size_t _file_sz = Dataspace_client(_file_cap).size();
size_t _blk_cnt = _file_sz / _blk_sz;
public:
using String = Genode::String<64UL>;
Rom_block(Env &env, String const &name, size_t blk_sz)
: Block::Driver(env.ram()), _env(env), _rom(env, name.string()),
_blk_sz(blk_sz) {}
/****************************
** Block-driver interface **
****************************/
size_t block_size() { return _blk_sz; }
Block::sector_t block_count() { return _blk_cnt; }
Block::Session::Operations ops()
{
Block::Session::Operations o;
o.set_operation(Block::Packet_descriptor::READ);
return o;
}
void read(Block::sector_t block_number,
size_t block_count,
char* buffer,
Block::Packet_descriptor &packet)
{
/* sanity check block number */
if (block_number + block_count > _file_sz / _blk_sz) {
warning("requested blocks ", block_number, "-",
block_number + block_count, " out of range!");
return;
}
size_t offset = (size_t) block_number * _blk_sz;
size_t size = block_count * _blk_sz;
/* copy file content to packet payload */
memcpy((void*)buffer, (void*)(_file_addr + offset), size);
ack_packet(packet);
}
};
struct Main
{
Env &env;
Heap heap { env.ram(), env.rm() };
struct Factory : Block::Driver_factory
{
Env &env;
Heap &heap;
Factory(Env &env, Heap &heap)
: env(env), heap(heap) {}
Block::Driver *create()
{
Attached_rom_dataspace config(env, "config");
Rom_block::String const file =
config.xml().attribute_value("file", Rom_block::String());
size_t const blk_sz =
config.xml().attribute_value("block_size", 512UL);
log("using file=", file, " as device with block size ", blk_sz, ".");
try {
return new (&heap) Rom_block(env, file, blk_sz);
}
catch (Rom_connection::Rom_connection_failed) {
error("cannot open file ", file); }
throw Service_denied();
}
void destroy(Block::Driver *driver) {
Genode::destroy(&heap, driver); }
} factory { env, heap };
enum { WRITEABLE = false };
Block::Root root { env.ep(), heap, env.rm(), factory, WRITEABLE };
Main(Env &env) : env(env) {
env.parent().announce(env.ep().manage(root)); }
};
void Component::construct(Genode::Env &env) { static Main server(env); }