genode/repos/base-hw/include/base/native_types.h
Stefan Kalkowski 60ba210a6b hw: reference count capabilities in UTCBs
When capabilities are delegated to components, they are added to the UTCB of the
target thread. Before the thread is able to take out the capability id out of
the UTCB and adapt the user-level capability reference counter, it might happen
that another thread of the same component deletes the same capability because
its user-level reference counter reached zero. If the kernel then destroys the
capability, before the same capability id is taken out of all UTCBs, an
inconsitent view in the component is the result.  To keep an consistent view in
the multi-threading scenario, the kernel now counts how often it puts a
capability into a UTCB. The threads on the other hand hint the kernel when they
took capabilities out of the UTCB, so the kernel can decrement the counter
again. Only when the counter is zero, capabilities can get destructed.

Fix #1623
2015-12-10 13:16:25 +01:00

200 lines
4.1 KiB
C++

/*
* \brief Basic Genode types
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-01-02
*/
/*
* Copyright (C) 2012-2015 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 _BASE__NATIVE_TYPES_H_
#define _BASE__NATIVE_TYPES_H_
/* Genode includes */
#include <kernel/log.h>
#include <base/native_capability.h>
#include <base/ipc_msgbuf.h>
namespace Genode
{
class Platform_thread;
class Native_thread;
using Native_thread_id = Kernel::capid_t;
typedef int Native_connection_state;
/**
* Information that a thread creator hands out to a new thread
*/
class Start_info;
/**
* Coherent address region
*/
struct Native_region;
struct Native_config;
struct Native_pd_args { };
/**
* Get the the minimal supported page-size log 2
*/
constexpr size_t get_page_size_log2() { return 12; }
/**
* Get the the minimal supported page-size
*/
constexpr size_t get_page_size() { return 1 << get_page_size_log2(); }
/**
* Memory region that is exclusive to every thread and known by the kernel
*/
class Native_utcb;
}
struct Genode::Native_thread
{
Platform_thread * platform_thread;
Native_capability cap;
};
/**
* Coherent address region
*/
struct Genode::Native_region
{
addr_t base;
size_t size;
};
struct Genode::Native_config
{
/**
* Thread-context area configuration.
*/
static constexpr addr_t context_area_virtual_base() {
return 0xe0000000UL; }
static constexpr addr_t context_area_virtual_size() {
return 0x10000000UL; }
/**
* Size of virtual address region holding the context of one thread
*/
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
};
class Genode::Native_utcb
{
public:
enum { MAX_CAP_ARGS = Msgbuf_base::MAX_CAP_ARGS};
enum Offsets { THREAD_MYSELF, PARENT, UTCB_DATASPACE };
private:
Kernel::capid_t _caps[MAX_CAP_ARGS]; /* capability buffer */
size_t _cap_cnt = 0; /* capability counter */
size_t _size = 0; /* bytes to transfer */
uint8_t _buf[get_page_size() - sizeof(_caps) -
sizeof(_cap_cnt) - sizeof(_size)];
public:
Native_utcb& operator= (const Native_utcb &o)
{
_cap_cnt = 0;
_size = o._size;
memcpy(_buf, o._buf, _size);
return *this;
}
/**
* Set the destination capability id (server object identity)
*/
void destination(Kernel::capid_t id) {
*reinterpret_cast<long*>(_buf) = id; }
/**
* Return the count of capabilities in the UTCB
*/
size_t cap_cnt() { return _cap_cnt; }
/**
* Set the count of capabilities in the UTCB
*/
void cap_cnt(size_t cnt) { _cap_cnt = cnt; }
/**
* Return the start address of the payload data
*/
void const * base() const { return &_buf; }
/**
* Copy data from the message buffer 'o' to this UTCB
*/
void copy_from(Msgbuf_base &o, size_t size)
{
_size = size;
_cap_cnt = o._snd_cap_cnt;
for (unsigned i = 0; i < _cap_cnt; i++)
_caps[i] = o._caps[i].dst();
memcpy(_buf, o.buf, min(_size, o._size));
}
/**
* Copy data from this UTCB to the message buffer 'o'
*/
void copy_to(Msgbuf_base &o)
{
o._snd_cap_cnt = _cap_cnt;
for (unsigned i = 0; i < _cap_cnt; i++) {
o._caps[i] = _caps[i];
if (o._caps[i].valid()) Kernel::ack_cap(o._caps[i].dst());
}
memcpy(o.buf, _buf, min(_size, o._size));
}
/**
* Return the capability id at index 'i'
*/
Kernel::capid_t cap_get(unsigned i) {
return (i < _cap_cnt) ? _caps[i] : Kernel::cap_id_invalid(); }
/**
* Set the capability id 'cap_id' at the next index
*/
void cap_add(Kernel::capid_t cap_id) {
if (_cap_cnt < MAX_CAP_ARGS) _caps[_cap_cnt++] = cap_id; }
};
namespace Genode
{
static constexpr addr_t VIRT_ADDR_SPACE_START = 0x1000;
static constexpr size_t VIRT_ADDR_SPACE_SIZE = 0xfffef000;
static constexpr Native_utcb * utcb_main_thread()
{
return (Native_utcb *)
((VIRT_ADDR_SPACE_START + VIRT_ADDR_SPACE_SIZE - sizeof(Native_utcb))
& ~(get_page_size() - 1));
}
}
#endif /* _BASE__NATIVE_TYPES_H_ */