mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 20:42:56 +01:00
With this patch, the loader installs an optional client-provided fault handler as default CPU exception handler and RM fault handler for all CPU and RM sessions of the loaded subsystem. This way, loader clients become able to respond to failures occuring within the subsystem. The new feature is provided via the added 'Loader::fault_handler' RPC function. The 'run/failsafe' test covers two cases related to the loader, which are faults produced by the immediate child of the loader and faults produced by indirect children.
405 lines
9.6 KiB
C++
405 lines
9.6 KiB
C++
/*
|
|
* \brief Loader service
|
|
* \author Norman Feske
|
|
* \date 2012-04-17
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2010-2012 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/env.h>
|
|
#include <base/heap.h>
|
|
#include <base/rpc_server.h>
|
|
#include <base/signal.h>
|
|
#include <base/sleep.h>
|
|
#include <loader_session/loader_session.h>
|
|
#include <cap_session/connection.h>
|
|
#include <nitpicker_view/capability.h>
|
|
#include <root/component.h>
|
|
|
|
/* local includes */
|
|
#include <child.h>
|
|
#include <nitpicker.h>
|
|
#include <ram_session_client_guard.h>
|
|
#include <rom.h>
|
|
|
|
|
|
namespace Loader {
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
class Session_component : public Rpc_object<Session>
|
|
{
|
|
private:
|
|
|
|
struct Local_rom_service : Service
|
|
{
|
|
Rpc_entrypoint &_ep;
|
|
Allocator &_md_alloc;
|
|
Parent_service _parent_rom_service;
|
|
Rom_module_registry &_rom_modules;
|
|
Lock _lock;
|
|
List<Rom_session_component> _rom_sessions;
|
|
|
|
void _close(Rom_session_component *rom)
|
|
{
|
|
_ep.dissolve(rom);
|
|
destroy(&_md_alloc, rom);
|
|
_rom_sessions.remove(rom);
|
|
}
|
|
|
|
Local_rom_service(Rpc_entrypoint &ep,
|
|
Allocator &md_alloc,
|
|
Rom_module_registry &rom_modules)
|
|
:
|
|
Service("virtual_rom"),
|
|
_ep(ep),
|
|
_md_alloc(md_alloc),
|
|
_parent_rom_service(Rom_session::service_name()),
|
|
_rom_modules(rom_modules)
|
|
{ }
|
|
|
|
~Local_rom_service()
|
|
{
|
|
Lock::Guard guard(_lock);
|
|
|
|
while (_rom_sessions.first()) {
|
|
_close(_rom_sessions.first()); }
|
|
}
|
|
|
|
Genode::Session_capability session(const char *args)
|
|
{
|
|
/* try to find ROM module at local ROM service */
|
|
try {
|
|
Lock::Guard guard(_lock);
|
|
|
|
char name[Session::Name::MAX_SIZE];
|
|
|
|
/* extract filename from session arguments */
|
|
Arg_string::find_arg(args, "filename")
|
|
.string(name, sizeof(name), "");
|
|
|
|
Rom_module &module = _rom_modules.lookup_and_lock(name);
|
|
|
|
Rom_session_component *rom = new (&_md_alloc)
|
|
Rom_session_component(module);
|
|
|
|
_rom_sessions.insert(rom);
|
|
|
|
return _ep.manage(rom);
|
|
|
|
} catch (...) { }
|
|
|
|
/* fall back to parent_rom_service */
|
|
return _parent_rom_service.session(args);
|
|
}
|
|
|
|
void close(Session_capability session)
|
|
{
|
|
Lock::Guard guard(_lock);
|
|
|
|
Rpc_object_base *rom = _ep.obj_by_cap(session);
|
|
|
|
Rom_session_component *component =
|
|
dynamic_cast<Rom_session_component *>(rom);
|
|
|
|
if (component) {
|
|
_close(component);
|
|
return;
|
|
}
|
|
|
|
_parent_rom_service.close(session);
|
|
}
|
|
|
|
void upgrade(Session_capability session, const char *) { }
|
|
};
|
|
|
|
/**
|
|
* Common base class of 'Local_cpu_service' and 'Local_rm_service'
|
|
*/
|
|
struct Intercepted_parent_service : Service
|
|
{
|
|
Signal_context_capability fault_sigh;
|
|
|
|
Intercepted_parent_service(char const *name) : Service(name) { }
|
|
|
|
void close(Session_capability session)
|
|
{
|
|
env()->parent()->close(session);
|
|
}
|
|
|
|
void upgrade(Session_capability session, const char *) { }
|
|
};
|
|
|
|
/**
|
|
* Intercept CPU session requests to install default exception
|
|
* handler
|
|
*/
|
|
struct Local_cpu_service : Intercepted_parent_service
|
|
{
|
|
Local_cpu_service() : Intercepted_parent_service("CPU") { }
|
|
|
|
Genode::Session_capability session(const char *args)
|
|
{
|
|
Capability<Cpu_session> cap = env()->parent()->session<Cpu_session>(args);
|
|
Cpu_session_client(cap).exception_handler(Thread_capability(), fault_sigh);
|
|
return cap;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Intercept RM session requests to install default fault handler
|
|
*/
|
|
struct Local_rm_service : Intercepted_parent_service
|
|
{
|
|
Local_rm_service() : Intercepted_parent_service("RM") { }
|
|
|
|
Genode::Session_capability session(const char *args)
|
|
{
|
|
Capability<Rm_session> cap = env()->parent()->session<Rm_session>(args);
|
|
Rm_session_client(cap).fault_handler(fault_sigh);
|
|
return cap;
|
|
}
|
|
};
|
|
|
|
struct Local_nitpicker_service : Service
|
|
{
|
|
Rpc_entrypoint &ep;
|
|
Allocator &_md_alloc;
|
|
|
|
Signal_context_capability view_ready_sigh;
|
|
|
|
Nitpicker::Session_component *open_session;
|
|
|
|
Local_nitpicker_service(Rpc_entrypoint &ep,
|
|
Allocator &md_alloc)
|
|
:
|
|
Service("virtual_nitpicker"),
|
|
ep(ep),
|
|
_md_alloc(md_alloc),
|
|
open_session(0)
|
|
{ }
|
|
|
|
~Local_nitpicker_service()
|
|
{
|
|
if (!open_session)
|
|
return;
|
|
|
|
ep.dissolve(open_session);
|
|
destroy(&_md_alloc, open_session);
|
|
}
|
|
|
|
Genode::Session_capability session(const char *args)
|
|
{
|
|
if (open_session)
|
|
throw Unavailable();
|
|
|
|
open_session = new (&_md_alloc)
|
|
Nitpicker::Session_component(ep, view_ready_sigh, args);
|
|
|
|
return ep.manage(open_session);
|
|
}
|
|
|
|
void upgrade(Genode::Session_capability session, const char *) { }
|
|
};
|
|
|
|
enum { STACK_SIZE = 2*4096 };
|
|
|
|
size_t _ram_quota;
|
|
Ram_session_client_guard _ram_session_client;
|
|
Heap _md_alloc;
|
|
size_t _subsystem_ram_quota_limit;
|
|
int _width, _height;
|
|
Rpc_entrypoint _ep;
|
|
Service_registry _parent_services;
|
|
Rom_module_registry _rom_modules;
|
|
Local_rom_service _rom_service;
|
|
Local_cpu_service _cpu_service;
|
|
Local_rm_service _rm_service;
|
|
Local_nitpicker_service _nitpicker_service;
|
|
Signal_context_capability _fault_sigh;
|
|
Child *_child;
|
|
|
|
/**
|
|
* Return virtual nitpicker session component
|
|
*/
|
|
Nitpicker::Session_component *_virtual_nitpicker_session()
|
|
{
|
|
if (!_nitpicker_service.open_session)
|
|
throw View_does_not_exist();
|
|
|
|
return _nitpicker_service.open_session;
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Session_component(size_t quota, Ram_session &ram, Cap_session &cap)
|
|
:
|
|
_ram_quota(quota),
|
|
_ram_session_client(env()->ram_session_cap(), _ram_quota),
|
|
_md_alloc(&_ram_session_client, env()->rm_session()),
|
|
_subsystem_ram_quota_limit(0),
|
|
_width(-1), _height(-1),
|
|
_ep(&cap, STACK_SIZE, "session_ep"),
|
|
_rom_modules(_ram_session_client, _md_alloc),
|
|
_rom_service(_ep, _md_alloc, _rom_modules),
|
|
_nitpicker_service(_ep, _md_alloc),
|
|
_child(0)
|
|
{ }
|
|
|
|
~Session_component()
|
|
{
|
|
if (_child)
|
|
destroy(&_md_alloc, _child);
|
|
}
|
|
|
|
|
|
/******************************
|
|
** Loader session interface **
|
|
******************************/
|
|
|
|
Dataspace_capability alloc_rom_module(Name const &name, size_t size)
|
|
{
|
|
return _rom_modules.alloc_rom_module(name.string(), size);
|
|
}
|
|
|
|
void commit_rom_module(Name const &name)
|
|
{
|
|
try {
|
|
_rom_modules.commit_rom_module(name.string()); }
|
|
catch (Rom_module_registry::Lookup_failed) {
|
|
throw Rom_module_does_not_exist(); }
|
|
}
|
|
|
|
void ram_quota(size_t quantum)
|
|
{
|
|
_subsystem_ram_quota_limit = quantum;
|
|
}
|
|
|
|
void constrain_geometry(int width, int height)
|
|
{
|
|
_width = width, _height = height;
|
|
}
|
|
|
|
void view_ready_sigh(Signal_context_capability sigh)
|
|
{
|
|
_nitpicker_service.view_ready_sigh = sigh;
|
|
}
|
|
|
|
void fault_sigh(Signal_context_capability sigh)
|
|
{
|
|
/*
|
|
* CPU exception handler for CPU sessions originating from the
|
|
* subsystem.
|
|
*/
|
|
_cpu_service.fault_sigh = sigh;
|
|
|
|
/*
|
|
* RM fault handler for RM sessions originating from the
|
|
* subsystem.
|
|
*/
|
|
_rm_service.fault_sigh = sigh;
|
|
|
|
/*
|
|
* CPU exception and RM fault handler for the immediate child.
|
|
*/
|
|
_fault_sigh = sigh;
|
|
}
|
|
|
|
void start(Name const &binary_name, Name const &label,
|
|
Genode::Native_pd_args const &pd_args)
|
|
{
|
|
if (_child) {
|
|
PWRN("cannot start subsystem twice");
|
|
return;
|
|
}
|
|
|
|
size_t const ram_quota = (_subsystem_ram_quota_limit > 0) ?
|
|
min(_subsystem_ram_quota_limit, _ram_session_client.avail()) :
|
|
_ram_session_client.avail();
|
|
|
|
try {
|
|
_child = new (&_md_alloc)
|
|
Child(binary_name.string(), label.string(),
|
|
pd_args, _ep, _ram_session_client,
|
|
ram_quota, _parent_services, _rom_service,
|
|
_cpu_service, _rm_service, _nitpicker_service,
|
|
_fault_sigh, _width, _height);
|
|
}
|
|
catch (Genode::Parent::Service_denied) {
|
|
throw Rom_module_does_not_exist(); }
|
|
}
|
|
|
|
Nitpicker::View_capability view()
|
|
{
|
|
return _virtual_nitpicker_session()->loader_view();
|
|
}
|
|
|
|
View_geometry view_geometry()
|
|
{
|
|
return _virtual_nitpicker_session()->loader_view_geometry();
|
|
}
|
|
};
|
|
|
|
|
|
class Root : public Root_component<Session_component>
|
|
{
|
|
private:
|
|
|
|
Ram_session &_ram;
|
|
Cap_session &_cap;
|
|
|
|
protected:
|
|
|
|
Session_component *_create_session(const char *args)
|
|
{
|
|
size_t quota =
|
|
Arg_string::find_arg(args, "ram_quota").long_value(0);
|
|
|
|
return new (md_alloc()) Session_component(quota, _ram, _cap);
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param session_ep entry point for managing ram session objects
|
|
* \param md_alloc meta-data allocator to be used by root
|
|
* component
|
|
*/
|
|
Root(Rpc_entrypoint &session_ep, Allocator &md_alloc,
|
|
Ram_session &ram, Cap_session &cap)
|
|
:
|
|
Root_component<Session_component>(&session_ep, &md_alloc),
|
|
_ram(ram), _cap(cap)
|
|
{ }
|
|
};
|
|
}
|
|
|
|
|
|
int main()
|
|
{
|
|
using namespace Genode;
|
|
|
|
enum { STACK_SIZE = 8*1024 };
|
|
static Cap_connection cap;
|
|
static Rpc_entrypoint ep(&cap, STACK_SIZE, "loader_ep");
|
|
|
|
static Loader::Root root(ep, *env()->heap(), *env()->ram_session(), cap);
|
|
|
|
env()->parent()->announce(ep.manage(&root));
|
|
|
|
sleep_forever();
|
|
return 0;
|
|
}
|