2012-05-30 20:13:09 +02:00
|
|
|
/*
|
|
|
|
* \brief Protection-domain facility
|
|
|
|
* \author Martin Stein
|
2014-04-28 21:31:57 +02:00
|
|
|
* \author Stefan Kalkowski
|
2016-02-11 11:59:31 +01:00
|
|
|
* \author Sebastian Sumpf
|
2012-05-30 20:13:09 +02:00
|
|
|
* \date 2012-02-12
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2015-04-10 12:35:30 +02:00
|
|
|
* Copyright (C) 2012-2015 Genode Labs GmbH
|
2012-05-30 20:13:09 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
/* Genode includes */
|
|
|
|
#include <root/root.h>
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/* core includes */
|
|
|
|
#include <platform_pd.h>
|
2015-05-19 14:18:40 +02:00
|
|
|
#include <platform_thread.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
extern int _prog_img_beg;
|
|
|
|
extern int _prog_img_end;
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
using namespace Genode;
|
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
|
|
|
|
/**************************************
|
|
|
|
** Hw::Address_space implementation **
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
Core_mem_allocator * Hw::Address_space::_cma() {
|
|
|
|
return static_cast<Core_mem_allocator*>(platform()->core_mem_alloc()); }
|
|
|
|
|
|
|
|
|
2015-06-16 10:59:26 +02:00
|
|
|
void * Hw::Address_space::_table_alloc()
|
2015-04-10 12:35:30 +02:00
|
|
|
{
|
2015-04-28 14:07:51 +02:00
|
|
|
void * ret;
|
|
|
|
if (!_cma()->alloc_aligned(sizeof(Translation_table), (void**)&ret,
|
|
|
|
Translation_table::ALIGNM_LOG2).is_ok())
|
|
|
|
throw Root::Quota_exceeded();
|
|
|
|
return ret;
|
|
|
|
}
|
2015-04-10 12:35:30 +02:00
|
|
|
|
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
bool Hw::Address_space::insert_translation(addr_t virt, addr_t phys,
|
|
|
|
size_t size, Page_flags flags)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
for (;;) {
|
|
|
|
try {
|
|
|
|
Lock::Guard guard(_lock);
|
2015-06-16 10:59:26 +02:00
|
|
|
_tt->insert_translation(virt, phys, size, flags, _tt_alloc);
|
2015-04-28 14:07:51 +02:00
|
|
|
return true;
|
2015-06-16 10:59:26 +02:00
|
|
|
} catch(Allocator::Out_of_memory) {
|
|
|
|
flush(platform()->vm_start(), platform()->vm_size());
|
2015-04-28 14:07:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch(...) {
|
|
|
|
PERR("Invalid mapping %p -> %p (%zx)", (void*)phys, (void*)virt, size);
|
|
|
|
}
|
|
|
|
return false;
|
2015-04-10 12:35:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
void Hw::Address_space::flush(addr_t virt, size_t size)
|
|
|
|
{
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
|
|
|
|
try {
|
2015-06-16 10:59:26 +02:00
|
|
|
if (_tt) _tt->remove_translation(virt, size, _tt_alloc);
|
2015-04-28 14:07:51 +02:00
|
|
|
|
|
|
|
/* update translation caches */
|
|
|
|
Kernel::update_pd(_kernel_pd);
|
|
|
|
} catch(...) {
|
|
|
|
PERR("tried to remove invalid region!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Hw::Address_space::Address_space(Kernel::Pd* pd, Translation_table * tt,
|
2015-06-16 10:59:26 +02:00
|
|
|
Translation_table_allocator * tt_alloc)
|
|
|
|
: _tt(tt), _tt_phys(tt), _tt_alloc(tt_alloc), _kernel_pd(pd) { }
|
2015-04-28 14:07:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
Hw::Address_space::Address_space(Kernel::Pd * pd)
|
2015-06-16 10:59:26 +02:00
|
|
|
: _tt(construct_at<Translation_table>(_table_alloc())),
|
2015-04-28 14:07:51 +02:00
|
|
|
_tt_phys(reinterpret_cast<Translation_table*>(_cma()->phys_addr(_tt))),
|
2015-06-16 10:59:26 +02:00
|
|
|
_tt_alloc((new (_cma()) Table_allocator(_cma()))->alloc()),
|
2015-04-28 14:07:51 +02:00
|
|
|
_kernel_pd(pd)
|
2013-08-30 14:15:13 +02:00
|
|
|
{
|
2014-04-28 21:31:57 +02:00
|
|
|
Lock::Guard guard(_lock);
|
2015-06-16 10:59:26 +02:00
|
|
|
Kernel::mtc()->map(_tt, _tt_alloc);
|
2015-04-28 14:07:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-21 15:00:03 +02:00
|
|
|
Hw::Address_space::~Address_space()
|
|
|
|
{
|
|
|
|
flush(platform()->vm_start(), platform()->vm_size());
|
2015-06-16 10:59:26 +02:00
|
|
|
destroy(_cma(), Table_allocator::base(_tt_alloc));
|
2015-05-21 15:00:03 +02:00
|
|
|
destroy(_cma(), _tt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
/*************************************
|
|
|
|
** Capability_space implementation **
|
|
|
|
*************************************/
|
|
|
|
|
|
|
|
Capability_space::Capability_space()
|
2016-03-31 18:17:07 +02:00
|
|
|
: _slab(nullptr, &_initial_sb) { }
|
2015-05-19 14:18:40 +02:00
|
|
|
|
|
|
|
|
|
|
|
void Capability_space::upgrade_slab(Allocator &alloc)
|
|
|
|
{
|
|
|
|
for (;;) {
|
2016-03-31 18:17:07 +02:00
|
|
|
void *block = nullptr;
|
2015-12-02 12:07:20 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* On every upgrade we try allocating as many blocks as possible.
|
|
|
|
* If the underlying allocator complains that its quota is exceeded
|
|
|
|
* this is normal as we use it as indication when to exit the loop.
|
|
|
|
*/
|
2015-05-19 14:18:40 +02:00
|
|
|
if (!alloc.alloc(SLAB_SIZE, &block)) return;
|
|
|
|
_slab.insert_sb(block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
/********************************
|
|
|
|
** Platform_pd implementation **
|
|
|
|
********************************/
|
|
|
|
|
|
|
|
int Platform_pd::bind_thread(Platform_thread * t)
|
|
|
|
{
|
|
|
|
/* is this the first and therefore main thread in this PD? */
|
|
|
|
bool main_thread = !_thread_associated;
|
|
|
|
_thread_associated = true;
|
|
|
|
return t->join_pd(this, main_thread, Address_space::weak_ptr());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform_pd::unbind_thread(Platform_thread *t) {
|
|
|
|
t->join_pd(nullptr, false, Address_space::weak_ptr()); }
|
|
|
|
|
|
|
|
|
|
|
|
int Platform_pd::assign_parent(Native_capability parent)
|
|
|
|
{
|
|
|
|
if (!parent.valid()) {
|
|
|
|
PERR("parent invalid");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
_parent = parent;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-28 21:31:57 +02:00
|
|
|
|
2015-06-16 10:59:26 +02:00
|
|
|
Platform_pd::Platform_pd(Translation_table * tt,
|
|
|
|
Translation_table_allocator * alloc)
|
|
|
|
: Hw::Address_space(kernel_object(), tt, alloc),
|
2015-05-19 14:18:40 +02:00
|
|
|
Kernel_object<Kernel::Pd>(false, tt, this),
|
|
|
|
_label("core") { }
|
2015-04-28 14:07:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
Platform_pd::Platform_pd(Allocator * md_alloc, char const *label)
|
2015-05-19 14:18:40 +02:00
|
|
|
: Hw::Address_space(kernel_object()),
|
|
|
|
Kernel_object<Kernel::Pd>(true, translation_table_phys(), this),
|
2015-04-28 14:07:51 +02:00
|
|
|
_label(label)
|
|
|
|
{
|
2015-05-19 14:18:40 +02:00
|
|
|
if (!_cap.valid()) {
|
2015-04-28 14:07:51 +02:00
|
|
|
PERR("failed to create kernel object");
|
|
|
|
throw Root::Unavailable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-25 08:59:33 +02:00
|
|
|
Platform_pd::~Platform_pd()
|
|
|
|
{
|
|
|
|
/* invalidate weak pointers to this object */
|
|
|
|
Address_space::lock_for_destruction();
|
|
|
|
}
|
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
|
|
|
|
/*************************************
|
|
|
|
** Core_platform_pd implementation **
|
|
|
|
*************************************/
|
|
|
|
|
|
|
|
Translation_table * const Core_platform_pd::_table()
|
|
|
|
{
|
|
|
|
return unmanaged_singleton<Translation_table,
|
|
|
|
1 << Translation_table::ALIGNM_LOG2>();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-16 10:59:26 +02:00
|
|
|
Translation_table_allocator * const Core_platform_pd::_table_alloc()
|
2015-04-28 14:07:51 +02:00
|
|
|
{
|
2015-06-25 15:53:39 +02:00
|
|
|
constexpr size_t count = Genode::Translation_table::CORE_TRANS_TABLE_COUNT;
|
|
|
|
using Allocator = Translation_table_allocator_tpl<count>;
|
|
|
|
|
|
|
|
static Allocator * alloc = nullptr;
|
|
|
|
if (!alloc) {
|
|
|
|
void * base = (void*) Platform::core_translation_tables();
|
|
|
|
alloc = construct_at<Allocator>(base);
|
|
|
|
}
|
|
|
|
return alloc->alloc();
|
2015-04-28 14:07:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Core_platform_pd::_map(addr_t start, addr_t end, bool io_mem)
|
|
|
|
{
|
|
|
|
const Page_flags flags =
|
|
|
|
Page_flags::apply_mapping(true, io_mem ? UNCACHED : CACHED, io_mem);
|
|
|
|
|
2016-02-11 11:59:31 +01:00
|
|
|
start = trunc_page(start);
|
|
|
|
|
|
|
|
/* omitt regions before vm_start */
|
|
|
|
if (start < VIRT_ADDR_SPACE_START)
|
|
|
|
start = VIRT_ADDR_SPACE_START;
|
2015-04-28 14:07:51 +02:00
|
|
|
|
2016-02-11 11:59:31 +01:00
|
|
|
size_t size = round_page(end) - start;
|
2015-04-28 14:07:51 +02:00
|
|
|
try {
|
2015-06-16 10:59:26 +02:00
|
|
|
_table()->insert_translation(start, start, size, flags, _table_alloc());
|
2015-04-28 14:07:51 +02:00
|
|
|
} catch(Allocator::Out_of_memory) {
|
|
|
|
PERR("Translation table needs to much RAM");
|
|
|
|
} catch(...) {
|
|
|
|
PERR("Invalid mapping %p -> %p (%zx)", (void*)start,
|
|
|
|
(void*)start, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Core_platform_pd::Core_platform_pd()
|
2015-06-16 10:59:26 +02:00
|
|
|
: Platform_pd(_table(), _table_alloc())
|
2015-04-28 14:07:51 +02:00
|
|
|
{
|
|
|
|
/* map exception vector for core */
|
2015-06-16 10:59:26 +02:00
|
|
|
Kernel::mtc()->map(_table(), _table_alloc());
|
2015-04-28 14:07:51 +02:00
|
|
|
|
|
|
|
/* map core's program image */
|
|
|
|
_map((addr_t)&_prog_img_beg, (addr_t)&_prog_img_end, false);
|
|
|
|
|
2015-06-25 15:53:39 +02:00
|
|
|
/* map core's page table allocator */
|
|
|
|
_map(Platform::core_translation_tables(),
|
|
|
|
Platform::core_translation_tables() +
|
|
|
|
Platform::core_translation_tables_size(), false);
|
|
|
|
|
2015-04-28 14:07:51 +02:00
|
|
|
/* map core's mmio regions */
|
|
|
|
Native_region * r = Platform::_core_only_mmio_regions(0);
|
|
|
|
for (unsigned i = 0; r;
|
|
|
|
r = Platform::_core_only_mmio_regions(++i))
|
|
|
|
_map(r->base, r->base + r->size, true);
|
|
|
|
}
|