mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-12 21:53:28 +00:00
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:
parent
8f4fbce2d6
commit
a085b4f536
@ -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));
|
||||
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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 **
|
||||
****************************************/
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user