nova: remap kernel cpu ids to genode cpu ids

to have a predictable order. First all CPU ids with hyper-thread id 0 are taken,
next the hyper-threads with 1 of all cores and so on.

Fixes #2163
This commit is contained in:
Alexander Boettcher 2016-11-04 13:01:09 +01:00 committed by Christian Helmuth
parent 8f4fbce2d6
commit a085b4f536
6 changed files with 148 additions and 42 deletions

View File

@ -126,6 +126,13 @@ namespace Nova {
bool has_feature_vmx() const { return feature_flags & (1 << 1); }
bool has_feature_svm() const { return feature_flags & (1 << 2); }
struct Cpu_desc {
uint8_t flags;
uint8_t thread;
uint8_t core;
uint8_t package;
} __attribute__((packed));
unsigned cpu_max() const {
return (mem_desc_offset - cpu_desc_offset) / cpu_desc_size; }
@ -139,16 +146,63 @@ namespace Nova {
return cpu_num;
}
bool is_cpu_enabled(unsigned i) const {
Cpu_desc const * cpu_desc_of_cpu(unsigned i) const {
if (i >= cpu_max())
return false;
return nullptr;
const char * cpu_desc = reinterpret_cast<const char *>(this) +
cpu_desc_offset + i * cpu_desc_size;
return (*cpu_desc) & 0x1;
unsigned long desc_addr = reinterpret_cast<unsigned long>(this) +
cpu_desc_offset + i * cpu_desc_size;
return reinterpret_cast<Cpu_desc const * const>(desc_addr);
}
bool is_cpu_enabled(unsigned i) const {
Cpu_desc const * const desc = cpu_desc_of_cpu(i);
return desc ? desc->flags & 0x1 : false;
}
/**
* Map kernel cpu ids to virtual cpu ids.
* Assign first all cores on all packages with thread 0 to virtual
* cpu id numbers, afterwards all (hyper-)threads.
*/
bool remap_cpu_ids(uint8_t *map_cpus, unsigned const boot_cpu) const {
unsigned const num_cpus = cpus();
unsigned cpu_i = 0;
/* assign boot cpu ever the virtual cpu id 0 */
Cpu_desc const * const boot = cpu_desc_of_cpu(boot_cpu);
if (!boot || !is_cpu_enabled(boot_cpu))
return false;
map_cpus[cpu_i++] = boot_cpu;
if (cpu_i >= num_cpus)
return true;
/* assign remaining cores and afterwards all threads to the ids */
for (uint8_t thread = 0; thread < 255; thread++) {
for (uint8_t package = 0; package < 255; package++) {
for (uint8_t core = 0; core < 255; core++) {
for (unsigned i = 0; i < cpu_max(); i++) {
if (i == boot_cpu || !is_cpu_enabled(i))
continue;
Cpu_desc const * const c = cpu_desc_of_cpu(i);
if (!c)
continue;
if (!(c->package == package && c->core == core &&
c->thread == thread))
continue;
map_cpus [cpu_i++] = i;
if (cpu_i >= num_cpus)
return true;
}
}
}
}
return false;
}
} __attribute__((packed));

View File

@ -23,6 +23,10 @@ namespace Genode {
class Platform : public Platform_generic
{
public:
enum { MAX_SUPPORTED_CPUS = 64};
private:
Core_mem_allocator _core_mem_alloc; /* core-accessible memory */
@ -41,6 +45,9 @@ namespace Genode {
/* available CPUs */
Affinity::Space _cpus;
/* map of virtual cpu ids in Genode to kernel cpu ids */
uint8_t map_cpu_ids[MAX_SUPPORTED_CPUS];
addr_t _map_pages(addr_t phys_page, addr_t pages);
public:
@ -88,6 +95,11 @@ namespace Genode {
*/
size_t region_alloc_size_at(void * addr) {
return (*_core_mem_alloc.virt_alloc())()->size_at(addr); }
/**
* Return kernel CPU ID for given Genode CPU
*/
unsigned kernel_cpu_id(unsigned genode_cpu_id);
};
}

View File

@ -14,7 +14,6 @@
*/
/* Genode includes */
#include <base/sleep.h>
#include <util/construct_at.h>
#include <rm_session/rm_session.h>
@ -23,6 +22,7 @@
/* core-local includes */
#include <pager.h>
#include <platform.h>
#include <platform_thread.h>
#include <imprint_badge.h>
@ -49,7 +49,7 @@ static Nova::Hip * kernel_hip()
}
/* pager activation threads storage and handling - one thread per CPU */
enum { PAGER_CPUS = 128, PAGER_STACK_SIZE = 2*4096 };
enum { PAGER_CPUS = Platform::MAX_SUPPORTED_CPUS, PAGER_STACK_SIZE = 2*4096 };
static char pager_activation_mem[sizeof (Pager_activation<PAGER_STACK_SIZE>) * PAGER_CPUS];
static Pager_activation_base * pager_threads[PAGER_CPUS];
@ -67,7 +67,7 @@ static unsigned which_cpu(Pager_activation_base * pager)
}
/* pager of boot CPU */
return Affinity::Location().xpos();
return 0;
}
@ -510,14 +510,16 @@ template <uint8_t EV>
void Exception_handlers::register_handler(Pager_object *obj, Mtd mtd,
void (* __attribute__((regparm(1))) func)(addr_t))
{
unsigned use_cpu = obj->location().xpos();
unsigned const genode_cpu_id = obj->location().xpos();
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(genode_cpu_id);
if (!kernel_hip()->is_cpu_enabled(use_cpu) || !pager_threads[use_cpu]) {
if (!kernel_hip()->is_cpu_enabled(kernel_cpu_id) ||
!pager_threads[genode_cpu_id]) {
warning("invalid CPU parameter used in pager object");
throw Region_map::Invalid_thread();
}
addr_t const ec_sel = pager_threads[use_cpu]->native_thread().ec_sel;
addr_t const ec_sel = pager_threads[genode_cpu_id]->native_thread().ec_sel;
/* compiler generates instance of exception entry if not specified */
addr_t entry = func ? (addr_t)func : (addr_t)(&_handler<EV>);
@ -604,13 +606,15 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap,
}
/* place Pager_object on specified CPU by selecting proper pager thread */
unsigned use_cpu = location.xpos();
if (!kernel_hip()->is_cpu_enabled(use_cpu) || !pager_threads[use_cpu]) {
unsigned const genode_cpu_id = location.xpos();
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(genode_cpu_id);
if (!kernel_hip()->is_cpu_enabled(kernel_cpu_id) ||
!pager_threads[genode_cpu_id]) {
warning("invalid CPU parameter used in pager object");
throw Region_map::Invalid_thread();
}
addr_t ec_sel = pager_threads[use_cpu]->native_thread().ec_sel;
addr_t ec_sel = pager_threads[genode_cpu_id]->native_thread().ec_sel;
/* create portal for page-fault handler - 14 */
_exceptions.register_handler<14>(this, Mtd::QUAL | Mtd::EIP,
@ -870,12 +874,14 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src,
addr_t Pager_object::get_oom_portal()
{
addr_t const pt_oom = sel_oom_portal();
unsigned const use_cpu = _location.xpos();
addr_t const pt_oom = sel_oom_portal();
unsigned const genode_cpu_id = _location.xpos();
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(genode_cpu_id);
if (kernel_hip()->is_cpu_enabled(use_cpu) && pager_threads[use_cpu]) {
addr_t const ec_sel = pager_threads[use_cpu]->native_thread().ec_sel;
if (kernel_hip()->is_cpu_enabled(kernel_cpu_id) &&
pager_threads[genode_cpu_id]) {
addr_t const ec_sel = pager_threads[genode_cpu_id]->native_thread().ec_sel;
uint8_t res = create_portal(pt_oom, __core_pd_sel, ec_sel, Mtd(0),
reinterpret_cast<addr_t>(_oom_handler),
this);
@ -940,8 +946,9 @@ Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory)
typedef Pager_activation<PAGER_STACK_SIZE> Pager;
Pager * pager_of_cpu = reinterpret_cast<Pager *>(&pager_activation_mem);
for (unsigned i = 0; i < kernel_hip()->cpu_max(); i++, pager_of_cpu++) {
if (!kernel_hip()->is_cpu_enabled(i))
for (unsigned i = 0; i < kernel_hip()->cpus(); i++, pager_of_cpu++) {
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(i);
if (!kernel_hip()->is_cpu_enabled(kernel_cpu_id))
continue;
pager_threads[i] = pager_of_cpu;
@ -954,13 +961,15 @@ Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory)
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* let handle pager_object of pager thread on same CPU */
unsigned use_cpu = obj->location().xpos();
if (!kernel_hip()->is_cpu_enabled(use_cpu) || !pager_threads[use_cpu]) {
unsigned const genode_cpu_id = obj->location().xpos();
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(genode_cpu_id);
if (!kernel_hip()->is_cpu_enabled(kernel_cpu_id) ||
!pager_threads[genode_cpu_id]) {
warning("invalid CPU parameter used in pager object");
return Pager_capability();
}
Native_capability pager_thread_cap =
Capability_space::import(pager_threads[use_cpu]->native_thread().ec_sel);
Capability_space::import(pager_threads[genode_cpu_id]->native_thread().ec_sel);
/* request creation of portal bind to pager thread */
Native_capability cap_session =

View File

@ -63,13 +63,6 @@ Utcb *__main_thread_utcb;
*/
extern unsigned _prog_img_beg, _prog_img_end;
extern addr_t sc_idle_base;
addr_t sc_idle_base = 0;
/**
* Capability selector of root PD
*/
@ -335,6 +328,17 @@ Platform::Platform() :
nova_die();
}
/* init genode cpu ids based on kernel cpu ids (used for syscalls) */
if (sizeof(map_cpu_ids) / sizeof(map_cpu_ids[0]) < hip->cpu_max()) {
error("number of max CPUs is larger than expected - ", hip->cpu_max(),
" vs ", sizeof(map_cpu_ids) / sizeof(map_cpu_ids[0]));
nova_die();
}
if (!hip->remap_cpu_ids(map_cpu_ids, boot_cpu())) {
error("re-ording cpu_id failed");
nova_die();
}
/* map idle SCs */
unsigned const log2cpu = log2(hip->cpu_max());
if ((1U << log2cpu) != hip->cpu_max()) {
@ -342,13 +346,13 @@ Platform::Platform() :
nova_die();
}
sc_idle_base = cap_map()->insert(log2cpu + 1);
addr_t sc_idle_base = cap_map()->insert(log2cpu + 1);
if (sc_idle_base & ((1UL << log2cpu) - 1)) {
error("unaligned sc_idle_base value ", Hex(sc_idle_base));
nova_die();
}
if(map_local(__main_thread_utcb, Obj_crd(0, log2cpu),
Obj_crd(sc_idle_base, log2cpu), true))
if (map_local(__main_thread_utcb, Obj_crd(0, log2cpu),
Obj_crd(sc_idle_base, log2cpu), true))
nova_die();
/* test reading out idle SCs */
@ -384,9 +388,18 @@ Platform::Platform() :
if (hip->has_feature_svm())
log("Hypervisor features SVM");
log("Hypervisor reports ", _cpus.width(), "x", _cpus.height(), " "
"CPU", _cpus.total() > 1 ? "s" : " ", " - boot CPU is ", boot_cpu());
"CPU", _cpus.total() > 1 ? "s" : " ");
if (!cpuid_invariant_tsc())
warning("CPU has no invariant TSC.");
log("CPU ID (genode->kernel:package:core:thread) remapping");
unsigned const cpus = hip->cpus();
for (unsigned i = 0; i < cpus; i++)
log(" remap (", i, "->", map_cpu_ids[i], ":",
hip->cpu_desc_of_cpu(map_cpu_ids[i])->package, ":",
hip->cpu_desc_of_cpu(map_cpu_ids[i])->core, ":",
hip->cpu_desc_of_cpu(map_cpu_ids[i])->thread, ") ",
boot_cpu() == map_cpu_ids[i] ? "boot cpu" : "");
}
/* initialize core allocators */
@ -653,9 +666,11 @@ Platform::Platform() :
}
/* add idle ECs to trace sources */
for (unsigned i = 0; i < hip->cpu_max(); i++) {
for (unsigned genode_cpu_id = 0; genode_cpu_id < _cpus.width(); genode_cpu_id++) {
if (!hip->is_cpu_enabled(i))
unsigned kernel_cpu_id = Platform::kernel_cpu_id(genode_cpu_id);
if (!hip->is_cpu_enabled(kernel_cpu_id))
continue;
struct Idle_trace_source : Trace::Source::Info_accessor, Trace::Control,
@ -686,14 +701,25 @@ Platform::Platform() :
};
Idle_trace_source *source = new (core_mem_alloc())
Idle_trace_source(Affinity::Location(i, 0, hip->cpu_max(), 1),
sc_idle_base + i);
Idle_trace_source(Affinity::Location(kernel_cpu_id, 0,
_cpus.width(), 1),
sc_idle_base + kernel_cpu_id);
Trace::sources().insert(source);
}
}
unsigned Platform::kernel_cpu_id(unsigned genode_cpu_id)
{
if (genode_cpu_id >= sizeof(map_cpu_ids) / sizeof(map_cpu_ids[0])) {
error("invalid genode cpu id ", genode_cpu_id);
return ~0U;
}
return map_cpu_ids[genode_cpu_id];
}
/****************************************
** Support for core memory management **
****************************************/

View File

@ -18,6 +18,7 @@
/* core includes */
#include <ipc_pager.h>
#include <platform.h>
#include <platform_thread.h>
#include <platform_pd.h>
#include <util.h>
@ -81,7 +82,8 @@ int Platform_thread::start(void *ip, void *sp)
uint8_t res;
do {
res = create_ec(_sel_ec(), _pd->pd_sel(), _location.xpos(),
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos());
res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
utcb, initial_sp, _sel_exc_base, !worker());
if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) {
_pager->assign_pd(Native_thread::INVALID_INDEX);
@ -145,7 +147,8 @@ int Platform_thread::start(void *ip, void *sp)
/* create first thread in task */
enum { THREAD_GLOBAL = true };
res = create_ec(_sel_ec(), pd_sel, _location.xpos(), pd_utcb, 0, 0,
res = create_ec(_sel_ec(), pd_sel,
platform_specific()->kernel_cpu_id(_location.xpos()), pd_utcb, 0, 0,
THREAD_GLOBAL);
if (res != NOVA_OK) {
error("create_ec returned ", res);

View File

@ -25,6 +25,7 @@
/* core includes */
#include <nova_util.h>
#include <platform.h>
#include <platform_pd.h>
using namespace Genode;
@ -102,7 +103,8 @@ void Thread::start()
/* create local EC */
enum { LOCAL_THREAD = false };
uint8_t res = create_ec(native_thread().ec_sel, pd_sel, location.xpos(),
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(location.xpos());
uint8_t res = create_ec(native_thread().ec_sel, pd_sel, kernel_cpu_id,
utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD);
if (res != NOVA_OK) {
error("create_ec returned ", res, " cpu=", location.xpos());