245 lines
4.9 KiB
C++
245 lines
4.9 KiB
C++
/*
|
|
* \brief ROM service exposed to the loaded subsystem
|
|
* \author Norman Feske
|
|
* \date 2012-04-17
|
|
*/
|
|
|
|
#ifndef _ROM_H_
|
|
#define _ROM_H_
|
|
|
|
//#include <util/string.h>
|
|
#include <rom_session/rom_session.h>
|
|
#include <base/rpc_server.h>
|
|
#include <os/attached_ram_dataspace.h>
|
|
|
|
namespace Genode {
|
|
|
|
class Rom_module : public List<Rom_module>::Element
|
|
{
|
|
private:
|
|
|
|
enum { MAX_NAME_LEN = 64 };
|
|
char _name[MAX_NAME_LEN];
|
|
|
|
Ram_session &_ram;
|
|
Attached_ram_dataspace _fg;
|
|
Attached_ram_dataspace _bg;
|
|
|
|
bool _bg_has_pending_data;
|
|
|
|
Signal_context_capability _sigh;
|
|
|
|
Lock _lock;
|
|
|
|
public:
|
|
|
|
Rom_module(char const *name, Ram_session &ram_session)
|
|
:
|
|
_ram(ram_session),
|
|
_fg(&_ram, 0), _bg(&_ram, 0),
|
|
_bg_has_pending_data(false),
|
|
_lock(Lock::LOCKED)
|
|
{
|
|
strncpy(_name, name, sizeof(_name));
|
|
}
|
|
|
|
bool has_name(char const *name) const
|
|
{
|
|
return strcmp(_name, name) == 0;
|
|
}
|
|
|
|
void lock() { _lock.lock(); }
|
|
void unlock() { _lock.unlock(); }
|
|
|
|
/**
|
|
* Return dataspace as handed out to loader session
|
|
*
|
|
* The loader session submits the data into the ROM module into
|
|
* the background dataspace. Once it is ready, the 'commit_bg()'
|
|
* function is called.
|
|
*/
|
|
Dataspace_capability bg_dataspace(size_t size)
|
|
{
|
|
/* let background buffer grow if needed */
|
|
if (_bg.size() < size)
|
|
_bg.realloc(&_ram, size);
|
|
|
|
return _bg.cap();
|
|
}
|
|
|
|
/**
|
|
* Return dataspace as handed out to ROM session client
|
|
*/
|
|
Rom_dataspace_capability fg_dataspace()
|
|
{
|
|
if (!_fg.size() && !_bg_has_pending_data) {
|
|
PERR("Error: no data loaded");
|
|
return Rom_dataspace_capability();
|
|
}
|
|
|
|
/*
|
|
* Keep foreground if no background exists. Otherwise, use
|
|
* old background as new foreground.
|
|
*/
|
|
if (_bg_has_pending_data) {
|
|
_fg.swap(_bg);
|
|
_bg_has_pending_data = false;
|
|
}
|
|
|
|
Dataspace_capability ds_cap = _fg.cap();
|
|
return static_cap_cast<Rom_dataspace>(ds_cap);
|
|
}
|
|
|
|
/**
|
|
* Set signal handler to inform about ROM module updates
|
|
*
|
|
* This function is indirectly called by the ROM session client.
|
|
*/
|
|
void sigh(Signal_context_capability sigh) { _sigh = sigh; }
|
|
|
|
/**
|
|
* Commit data contained in background dataspace
|
|
*
|
|
* This function is indirectly called by the loader session.
|
|
*/
|
|
void commit_bg()
|
|
{
|
|
_bg_has_pending_data = true;
|
|
|
|
if (_sigh.valid())
|
|
Signal_transmitter(_sigh).submit();
|
|
}
|
|
};
|
|
|
|
|
|
struct Rom_module_lock_guard
|
|
{
|
|
Rom_module &rom;
|
|
|
|
Rom_module_lock_guard(Rom_module &rom) : rom(rom) { }
|
|
|
|
~Rom_module_lock_guard() { rom.unlock(); }
|
|
};
|
|
|
|
|
|
class Rom_module_registry
|
|
{
|
|
private:
|
|
|
|
Lock _lock;
|
|
Ram_session &_ram_session;
|
|
Allocator &_md_alloc;
|
|
List<Rom_module> _list;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Exception type
|
|
*/
|
|
class Lookup_failed { };
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param ram_session RAM session used as backing store for
|
|
* module data
|
|
* \param md_alloc backing store for ROM module meta data
|
|
*/
|
|
Rom_module_registry(Ram_session &ram_session, Allocator &md_alloc)
|
|
:
|
|
_ram_session(ram_session), _md_alloc(md_alloc)
|
|
{ }
|
|
|
|
~Rom_module_registry()
|
|
{
|
|
Lock::Guard guard(_lock);
|
|
|
|
while (_list.first()) {
|
|
Rom_module *rom = _list.first();
|
|
rom->lock();
|
|
_list.remove(rom);
|
|
destroy(&_md_alloc, rom);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lookup ROM module by name
|
|
*
|
|
* \throw Lookup_failed
|
|
*/
|
|
Rom_module &lookup_and_lock(char const *name)
|
|
{
|
|
Lock::Guard guard(_lock);
|
|
|
|
Rom_module *curr = _list.first();
|
|
for (; curr; curr = curr->next()) {
|
|
if (curr->has_name(name)) {
|
|
curr->lock();
|
|
return *curr;
|
|
}
|
|
}
|
|
throw Lookup_failed();
|
|
}
|
|
|
|
Dataspace_capability alloc_rom_module(char const *name, size_t size)
|
|
{
|
|
try {
|
|
Rom_module &module = lookup_and_lock(name);
|
|
Rom_module_lock_guard guard(module);
|
|
return module.bg_dataspace(size);
|
|
}
|
|
catch (Lookup_failed) {
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
Rom_module *module = new (&_md_alloc)
|
|
Rom_module(name, _ram_session);
|
|
|
|
Rom_module_lock_guard module_guard(*module);
|
|
|
|
_list.insert(module);
|
|
|
|
return module->bg_dataspace(size);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \throw Lookup_failed
|
|
*/
|
|
void commit_rom_module(char const *name)
|
|
{
|
|
Rom_module &rom_module = lookup_and_lock(name);
|
|
rom_module.commit_bg();
|
|
rom_module.unlock();
|
|
}
|
|
};
|
|
|
|
|
|
class Rom_session_component : public Rpc_object<Rom_session>,
|
|
public List<Rom_session_component>::Element
|
|
{
|
|
private:
|
|
|
|
Rom_module &_rom_module;
|
|
|
|
public:
|
|
|
|
Rom_session_component(Rom_module &rom_module)
|
|
: _rom_module(rom_module) { }
|
|
|
|
Rom_dataspace_capability dataspace()
|
|
{
|
|
Rom_module_lock_guard guard(_rom_module);
|
|
return _rom_module.fg_dataspace();
|
|
}
|
|
|
|
void sigh(Signal_context_capability sigh)
|
|
{
|
|
Rom_module_lock_guard guard(_rom_module);
|
|
_rom_module.sigh(sigh);
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif /* _ROM_H_ */
|