ram_blk: transition to the new base API

In addition to modernizing the component now also supports using
empty RAM dataspace as backing store.

For example to use an ISO file the component has to be configured
as follows:

! <config file="image.iso" block_size="2048"/>

To use a empty RAM dataspace that is 256MiB large and has a block
size of 4KiB the configuration looks like this:

! <config size="256M" block_size="4096"/>

Either 'size' or 'file' has to specified. If both are declared the
'file' attribute is soley evaluated.

Issue #1987.

Fixes #2031.
This commit is contained in:
Josef Söntgen 2016-07-05 11:40:26 +02:00 committed by Norman Feske
parent a5dd3fa1e9
commit c25c4e3411
3 changed files with 135 additions and 71 deletions

View File

@ -1,6 +1,14 @@
RAM loop device is an implementation of the block-session interface RAM block device is an implementation of the block-session interface
running as a client of a RAM session. It exports the requested ROM file as a running as a client of a RAM session. It either populates the RAM dataspace
block device, similiar to loop devices known in Linux. The example shows how by using a ROM dataspace, similiar to loop devices. For example to use
to choose the right ROM file in its configuration and how to configure the exported block size. an ISO file the component has to be configured as follows:
! <config file="image.iso" block_size="2048"/> ! <config file="image.iso" block_size="2048"/>
To use a empty RAM dataspace that is 256MiB large and has a block size
of 4KiB the configuration looks like this:
! <config size="256M" block_size="4096"/>
Either 'size' or 'file' has to specified. If both are declared the 'file'
attribute is soley evaluated.

View File

@ -1,58 +1,64 @@
/* /*
* \brief Provide a rom-file as writable block device (aka loop devices) * \brief Provide a RAM dataspace as writable block device
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2010-07-07 * \date 2010-07-07
*/ */
/* /*
* Copyright (C) 2010-2013 Genode Labs GmbH * Copyright (C) 2010-2016 Genode Labs GmbH
* *
* This file is part of the Genode OS framework, which is distributed * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/attached_ram_dataspace.h>
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/exception.h> #include <base/exception.h>
#include <base/printf.h> #include <base/heap.h>
#include <os/attached_ram_dataspace.h> #include <base/log.h>
#include <os/attached_rom_dataspace.h>
#include <os/config.h>
#include <os/server.h>
#include <rom_session/connection.h>
#include <block/component.h> #include <block/component.h>
#include <block/driver.h> #include <block/driver.h>
using namespace Genode; using namespace Genode;
class Ram_blk : public Block::Driver class Ram_blk : public Block::Driver
{ {
private: private:
Attached_rom_dataspace _rom_ds; Env &_env;
size_t _file_sz; /* file size */ Allocator *_alloc { nullptr };
size_t _blk_sz; /* block size */
size_t _blk_cnt; /* block count */
Attached_ram_dataspace _file_ds; /* copy of rom file */
addr_t _file_addr; /* start address of attached file */
void _io(Block::sector_t block_number, Attached_rom_dataspace *_rom_ds { nullptr };
size_t block_count, size_t _size;
char* buffer, size_t _block_size;
size_t _block_count;
Attached_ram_dataspace _ram_ds;
addr_t _ram_addr;
void _io(Block::sector_t block_number,
size_t block_count,
char* buffer,
Block::Packet_descriptor &packet, Block::Packet_descriptor &packet,
bool read) bool read)
{ {
/* sanity check block number */ /* sanity check block number */
if (block_number + block_count > _file_sz / _blk_sz) { if (block_number + block_count > _block_count) {
PWRN("requested blocks %lld-%lld out of range!", Genode::warning("requested blocks ", block_number, "-",
block_number, block_number + block_count); block_number + block_count," out of range!");
return; return;
} }
size_t offset = (size_t) block_number * _blk_sz; size_t offset = (size_t) block_number * _block_size;
size_t size = block_count * _blk_sz; size_t size = block_count * _block_size;
void *src = read ? (void *)(_file_addr + offset) : (void *)buffer; void *src = read ? (void *)(_ram_addr + offset) : (void *)buffer;
void *dst = read ? (void *)buffer : (void *)(_file_addr + offset); void *dst = read ? (void *)buffer : (void *)(_ram_addr + offset);
/* copy file content to packet payload */ /* copy file content to packet payload */
memcpy(dst, src, size); memcpy(dst, src, size);
@ -61,24 +67,46 @@ class Ram_blk : public Block::Driver
public: public:
Ram_blk(const char *name, size_t blk_sz) /**
: _rom_ds(name), * Construct populated RAM dataspace
_file_sz(_rom_ds.size()), */
_blk_sz(blk_sz), Ram_blk(Env &env, Allocator &alloc,
_blk_cnt(_file_sz/_blk_sz), const char *name, size_t block_size)
_file_ds(env()->ram_session(), _file_sz), :
_file_addr((addr_t)_file_ds.local_addr<addr_t>()) _env(env), _alloc(&alloc),
_rom_ds(new (_alloc) Attached_rom_dataspace(_env, name)),
_size(_rom_ds->size()),
_block_size(block_size),
_block_count(_size/_block_size),
_ram_ds(_env.ram(), _env.rm(), _size),
_ram_addr((addr_t)_ram_ds.local_addr<addr_t>())
{ {
memcpy(_file_ds.local_addr<void>(), _rom_ds.local_addr<void>(), _file_sz); /* populate backing store from file */
memcpy(_ram_ds.local_addr<void>(), _rom_ds->local_addr<void>(), _size);
} }
/**
* Construct empty RAM dataspace
*/
Ram_blk(Env &env, size_t size, size_t block_size)
:
_env(env),
_size(size),
_block_size(block_size),
_block_count(_size/_block_size),
_ram_ds(_env.ram(), _env.rm(), _size),
_ram_addr((addr_t)_ram_ds.local_addr<addr_t>())
{ }
~Ram_blk() { destroy(_alloc, _rom_ds); }
/**************************** /****************************
** Block-driver interface ** ** Block-driver interface **
****************************/ ****************************/
Genode::size_t block_size() { return _blk_sz; } size_t block_size() { return _block_size; }
Block::sector_t block_count() { return _blk_cnt; } Block::sector_t block_count() { return _block_count; }
Block::Session::Operations ops() Block::Session::Operations ops()
{ {
@ -97,7 +125,7 @@ class Ram_blk : public Block::Driver
} }
void write(Block::sector_t block_number, void write(Block::sector_t block_number,
Genode::size_t block_count, size_t block_count,
const char * buffer, const char * buffer,
Block::Packet_descriptor &packet) Block::Packet_descriptor &packet)
{ {
@ -108,50 +136,78 @@ class Ram_blk : public Block::Driver
struct Main struct Main
{ {
Server::Entrypoint &ep; Env &env;
Heap heap { env.ram(), env.rm() };
Attached_rom_dataspace config_rom { env, "config" };
struct Factory : Block::Driver_factory struct Factory : Block::Driver_factory
{ {
Env &env;
Allocator &alloc;
bool use_file { false };
char file[64];
size_t size { 0 };
size_t block_size { 512 };
Factory(Env &env, Allocator &alloc,
Xml_node config)
: env(env), alloc(alloc)
{
use_file = config.has_attribute("file");
if (use_file) {
config.attribute("file").value(file, sizeof(file));
} else {
try {
Genode::Number_of_bytes bytes;
config.attribute("size").value(&bytes);
size = bytes;
} catch (...) {
error("neither file nor size attribute specified");
throw Exception();
}
}
block_size = config.attribute_value("block_size", block_size);
}
Block::Driver *create() Block::Driver *create()
{ {
char file[64];
size_t blk_sz = 512;
try { try {
config()->xml_node().attribute("file").value(file, sizeof(file)); if (use_file) {
config()->xml_node().attribute("block_size").value(&blk_sz); Genode::log("Creating RAM-basd block device populated by file='",
(char const*)file, "' with block size ", block_size);
return new (&alloc) Ram_blk(env, alloc, file, block_size);
} else {
Genode::log("Creating RAM-based block device with size ",
size, " and block size ", block_size);
return new (&alloc) Ram_blk(env, size, block_size);
}
} catch (...) {
throw Root::Unavailable();
} }
catch (...) { }
PINF("Using file=%s as device with block size %zd.", file, blk_sz);
try {
return new (Genode::env()->heap()) Ram_blk(file, blk_sz);
} catch(Rom_connection::Rom_connection_failed) {
PERR("Cannot open file %s.", file);
}
throw Root::Unavailable();
} }
void destroy(Block::Driver *driver) { void destroy(Block::Driver *driver) {
Genode::destroy(env()->heap(), driver); } Genode::destroy(&alloc, driver); }
} factory; } factory { env, heap, config_rom.xml() };
Block::Root root; Block::Root root { env.ep(), &heap, factory };
Main(Server::Entrypoint &ep) Main(Env &env) : env(env)
: ep(ep), root(ep, Genode::env()->heap(), factory) { {
Genode::env()->parent()->announce(ep.manage(root)); } env.parent().announce(env.ep().manage(root));
}
}; };
/************ /***************
** Server ** ** Component **
************/ ***************/
namespace Server { namespace Component {
char const *name() { return "rom_blk_ep"; } Genode::size_t stack_size() { return 2*1024*sizeof(long); }
size_t stack_size() { return 2*1024*sizeof(long); } void construct(Genode::Env &env) { static Main server(env); }
void construct(Entrypoint &ep) { static Main server(ep); }
} }

View File

@ -1,3 +1,3 @@
TARGET = ram_blk TARGET = ram_blk
SRC_CC = main.cc SRC_CC = main.cc
LIBS = base config server LIBS = base config