genode/os/src/server/loader/child.h
Norman Feske ecdbdef8ee Loader: reflect faults to client
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.
2013-01-07 16:31:27 +01:00

208 lines
6.1 KiB
C++

/*
* \brief Loader child interface
* \author Christian Prochaska
* \author Norman Feske
* \date 2009-10-05
*/
/*
* Copyright (C) 2009-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.
*/
#ifndef _CHILD_H_
#define _CHILD_H_
/* Genode includes */
#include <base/child.h>
#include <util/arg_string.h>
#include <init/child_policy.h>
#include <ram_session/connection.h>
#include <cpu_session/connection.h>
namespace Loader {
using namespace Genode;
class Child : public Child_policy
{
private:
struct Label {
char string[Session::Name::MAX_SIZE];
Label(char const *l) { strncpy(string, l, sizeof(string)); }
} _label;
Native_pd_args _pd_args;
Rpc_entrypoint &_ep;
struct Resources
{
Ram_connection ram;
Cpu_connection cpu;
Rm_connection rm;
Resources(char const *label,
Ram_session_client &ram_session_client,
size_t ram_quota,
Signal_context_capability fault_sigh)
: ram(label), cpu(label)
{
/* deduce session costs from usable ram quota */
size_t session_donations = Rm_connection::RAM_QUOTA +
Cpu_connection::RAM_QUOTA +
Ram_connection::RAM_QUOTA;
if (ram_quota > session_donations)
ram_quota -= session_donations;
else ram_quota = 0;
ram.ref_account(ram_session_client);
ram_session_client.transfer_quota(ram.cap(), ram_quota);
/*
* Install CPU exception and RM fault handler assigned by
* the loader client via 'Loader_session::fault_handler'.
*/
cpu.exception_handler(Thread_capability(), fault_sigh);
rm.fault_handler(fault_sigh);
}
} _resources;
Service_registry &_parent_services;
Service &_local_nitpicker_service;
Service &_local_rom_service;
Service &_local_cpu_service;
Service &_local_rm_service;
Rom_session_client _binary_rom_session;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_pd_args _pd_args_policy;
int _max_width, _max_height;
Genode::Child _child;
Rom_session_capability _rom_session(char const *name)
{
try {
char args[Session::Name::MAX_SIZE];
snprintf(args, sizeof(args), "ram_quota=4K, filename=\"%s\"", name);
return static_cap_cast<Rom_session>(_local_rom_service.session(args));
} catch (Genode::Parent::Service_denied) {
PERR("Lookup for ROM module \"%s\" failed", name);
throw;
}
}
public:
Child(char const *binary_name,
char const *label,
Native_pd_args const &pd_args,
Rpc_entrypoint &ep,
Ram_session_client &ram_session_client,
size_t ram_quota,
Service_registry &parent_services,
Service &local_rom_service,
Service &local_cpu_service,
Service &local_rm_service,
Service &local_nitpicker_service,
Signal_context_capability fault_sigh,
int max_width,
int max_height)
:
_label(label),
_pd_args(pd_args),
_ep(ep),
_resources(_label.string, ram_session_client, ram_quota, fault_sigh),
_parent_services(parent_services),
_local_nitpicker_service(local_nitpicker_service),
_local_rom_service(local_rom_service),
_local_cpu_service(local_cpu_service),
_local_rm_service(local_rm_service),
_binary_rom_session(_rom_session(binary_name)),
_binary_policy("binary", _binary_rom_session.dataspace(), &_ep),
_labeling_policy(_label.string),
_pd_args_policy(&_pd_args),
_max_width(max_width), _max_height(max_height),
_child(_binary_rom_session.dataspace(),
_resources.ram.cap(), _resources.cpu.cap(),
_resources.rm.cap(), &_ep, this)
{ }
~Child()
{
_local_rom_service.close(_binary_rom_session);
}
/****************************
** Child-policy interface **
****************************/
char const *name() const { return _label.string; }
Native_pd_args const *pd_args() const { return &_pd_args; }
void filter_session_args(char const *service, char *args, size_t args_len)
{
_labeling_policy.filter_session_args(service, args, args_len);
_pd_args_policy. filter_session_args(service, args, args_len);
if (!strcmp(service, "Nitpicker")) {
/*
* Restrict the child's framebuffer size to the maximum
* size given by the client.
*/
if (_max_width > -1) {
int fb_width = Arg_string::find_arg(args, "fb_width" ).long_value(_max_width);
if (!Arg_string::set_arg(args, args_len, "fb_width",
min(fb_width, _max_width))) {
PERR("could not set fb_width argument");
}
}
if (_max_height > -1) {
int fb_height = Arg_string::find_arg(args, "fb_height" ).long_value(_max_height);
if (!Arg_string::set_arg(args, args_len, "fb_height",
min(fb_height, _max_height))) {
PERR("could not set fb_height argument");
}
}
}
}
Service *resolve_session_request(const char *name,
const char *args)
{
Service *service = 0;
if ((service = _binary_policy.resolve_session_request(name, args)))
return service;
if (!strcmp(name, "Nitpicker")) return &_local_nitpicker_service;
if (!strcmp(name, "ROM")) return &_local_rom_service;
if (!strcmp(name, "CPU")) return &_local_cpu_service;
if (!strcmp(name, "RM")) return &_local_rm_service;
/* populate session-local parent service registry on demand */
service = _parent_services.find(name);
if (!service) {
service = new (env()->heap()) Parent_service(name);
_parent_services.insert(service);
}
return service;
}
};
}
#endif /* _CHILD_H_ */