mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-13 04:38:20 +00:00
committed by
Christian Helmuth
parent
1bea312ba2
commit
d3d4381128
@ -569,7 +569,7 @@ namespace Nova {
|
|||||||
struct Item {
|
struct Item {
|
||||||
mword_t crd;
|
mword_t crd;
|
||||||
mword_t hotspot;
|
mword_t hotspot;
|
||||||
bool is_del() { return hotspot & 0x1; }
|
bool is_del() const { return hotspot & 0x1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
@ -71,7 +71,7 @@ inline void request_signal_sm_cap(Genode::Native_capability const &cap,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void delegate_vcpu_portals(Genode::Native_capability const &cap,
|
inline void translate_remote_pager(Genode::Native_capability const &cap,
|
||||||
Genode::addr_t const sel)
|
Genode::addr_t const sel)
|
||||||
{
|
{
|
||||||
Genode::Thread * myself = Genode::Thread::myself();
|
Genode::Thread * myself = Genode::Thread::myself();
|
||||||
@ -84,34 +84,22 @@ inline void delegate_vcpu_portals(Genode::Native_capability const &cap,
|
|||||||
|
|
||||||
Genode::uint8_t res = Nova::NOVA_OK;
|
Genode::uint8_t res = Nova::NOVA_OK;
|
||||||
enum {
|
enum {
|
||||||
TRANSLATE = true, THIS_PD = false, NON_GUEST = false, HOTSPOT = 0,
|
TRANSLATE = true, THIS_PD = false, NON_GUEST = false, HOTSPOT = 0
|
||||||
TRANSFER_ITEMS = 1U << (Nova::NUM_INITIAL_VCPU_PT_LOG2 - 1)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* prepare translation items for every portal separately */
|
/* translate one item */
|
||||||
for (unsigned half = 0; !res && half < 2; half++) {
|
utcb->msg[0] = 0xaffe;
|
||||||
/* translate half of portals - due to size constraints on 64bit */
|
|
||||||
utcb->msg[0] = half;
|
|
||||||
utcb->set_msg_word(1);
|
utcb->set_msg_word(1);
|
||||||
/* add one translate item per portal */
|
|
||||||
for (unsigned i = 0; !res && i < TRANSFER_ITEMS; i++) {
|
|
||||||
Nova::Obj_crd obj_crd(sel + half * TRANSFER_ITEMS + i, 0);
|
|
||||||
|
|
||||||
if (!utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST,
|
|
||||||
TRANSLATE))
|
|
||||||
res = 0xff;
|
|
||||||
}
|
|
||||||
if (res != Nova::NOVA_OK)
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
Nova::Obj_crd obj_crd(sel, 0);
|
||||||
|
if (utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST, TRANSLATE))
|
||||||
/* trigger the translation */
|
/* trigger the translation */
|
||||||
res = Nova::call(cap.local_name());
|
res = Nova::call(cap.local_name());
|
||||||
}
|
|
||||||
|
|
||||||
/* restore original receive window */
|
/* restore original receive window */
|
||||||
utcb->crd_rcv = orig_crd;
|
utcb->crd_rcv = orig_crd;
|
||||||
|
|
||||||
if (res)
|
if (res != Nova::NOVA_OK)
|
||||||
Genode::error("setting exception portals for vCPU failed res=", res);
|
Genode::error("setting exception portals for vCPU failed res=", res);
|
||||||
}
|
}
|
||||||
#endif /* _INCLUDE__NOVA__UTIL_H_ */
|
#endif /* _INCLUDE__NOVA__UTIL_H_ */
|
||||||
|
@ -75,7 +75,6 @@ namespace Genode {
|
|||||||
addr_t _initial_esp;
|
addr_t _initial_esp;
|
||||||
addr_t _initial_eip;
|
addr_t _initial_eip;
|
||||||
addr_t _client_exc_pt_sel;
|
addr_t _client_exc_pt_sel;
|
||||||
addr_t _client_exc_vcpu;
|
|
||||||
|
|
||||||
Lock _state_lock;
|
Lock _state_lock;
|
||||||
|
|
||||||
@ -121,7 +120,8 @@ namespace Genode {
|
|||||||
Affinity::Location const _location;
|
Affinity::Location const _location;
|
||||||
Exception_handlers _exceptions;
|
Exception_handlers _exceptions;
|
||||||
|
|
||||||
addr_t _pd;
|
addr_t _pd_target;
|
||||||
|
addr_t _pd_source;
|
||||||
|
|
||||||
void _copy_state_from_utcb(Nova::Utcb * utcb);
|
void _copy_state_from_utcb(Nova::Utcb * utcb);
|
||||||
void _copy_state_to_utcb(Nova::Utcb * utcb);
|
void _copy_state_to_utcb(Nova::Utcb * utcb);
|
||||||
@ -179,8 +179,15 @@ namespace Genode {
|
|||||||
/**
|
/**
|
||||||
* Assign PD selector to PD
|
* Assign PD selector to PD
|
||||||
*/
|
*/
|
||||||
void assign_pd(addr_t pd_sel) { _pd = pd_sel; }
|
void assign_pd(addr_t pd_sel)
|
||||||
addr_t pd_sel() const { return _pd; }
|
{
|
||||||
|
if (_pd_target == _pd_source)
|
||||||
|
_pd_source = pd_sel;
|
||||||
|
|
||||||
|
_pd_target = pd_sel;
|
||||||
|
}
|
||||||
|
addr_t pd_sel() const { return _pd_target; }
|
||||||
|
addr_t pd_source() const { return _pd_source; }
|
||||||
|
|
||||||
void exception(uint8_t exit_id);
|
void exception(uint8_t exit_id);
|
||||||
|
|
||||||
@ -188,7 +195,6 @@ namespace Genode {
|
|||||||
* Return base of initial portal window
|
* Return base of initial portal window
|
||||||
*/
|
*/
|
||||||
addr_t exc_pt_sel_client() { return _client_exc_pt_sel; }
|
addr_t exc_pt_sel_client() { return _client_exc_pt_sel; }
|
||||||
addr_t exc_pt_vcpu() { return _client_exc_vcpu; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set initial stack pointer used by the startup handler
|
* Set initial stack pointer used by the startup handler
|
||||||
@ -324,14 +330,6 @@ namespace Genode {
|
|||||||
*/
|
*/
|
||||||
void cleanup_call();
|
void cleanup_call();
|
||||||
|
|
||||||
/**
|
|
||||||
* Open receive window for initial portals for vCPU.
|
|
||||||
*/
|
|
||||||
void prepare_vCPU_portals()
|
|
||||||
{
|
|
||||||
_client_exc_vcpu = cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Portal called by thread that causes a out of memory in kernel.
|
* Portal called by thread that causes a out of memory in kernel.
|
||||||
*/
|
*/
|
||||||
@ -412,6 +410,7 @@ namespace Genode {
|
|||||||
* constructor.
|
* constructor.
|
||||||
*/
|
*/
|
||||||
void ep(Pager_entrypoint *ep) { _ep = ep; }
|
void ep(Pager_entrypoint *ep) { _ep = ep; }
|
||||||
|
Pager_entrypoint *ep() { return _ep; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread interface
|
* Thread interface
|
||||||
|
@ -301,32 +301,20 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
|
|||||||
addr_t const event = utcb->msg[0];
|
addr_t const event = utcb->msg[0];
|
||||||
addr_t const logcount = utcb->msg[1];
|
addr_t const logcount = utcb->msg[1];
|
||||||
|
|
||||||
/* check for translated vCPU portals */
|
/* check for translated pager portals - required for vCPU in remote PDs */
|
||||||
unsigned const items_count = 1U << (Nova::NUM_INITIAL_VCPU_PT_LOG2 - 1);
|
if (utcb->msg_items() == 1 && utcb->msg_words() == 1 && event == 0xaffe) {
|
||||||
|
|
||||||
if ((obj->_client_exc_vcpu != Native_thread::INVALID_INDEX) &&
|
Nova::Utcb::Item const * const item = utcb->get_item(0);
|
||||||
(utcb->msg_items() == items_count) &&
|
Nova::Crd const cap(item->crd);
|
||||||
(utcb->msg_words() == 1 && (event == 0UL || event == 1UL))) {
|
|
||||||
/* check all translated item and remap if valid */
|
|
||||||
for (unsigned i = 0; i < items_count; i++) {
|
|
||||||
Nova::Utcb::Item * item = utcb->get_item(i);
|
|
||||||
|
|
||||||
if (!item)
|
/* valid item which got translated ? */
|
||||||
break;
|
if (!cap.is_null() && !item->is_del()) {
|
||||||
|
using Pool = Object_pool<Pager_object>;
|
||||||
Nova::Crd cap(item->crd);
|
pager_threads[0]->ep()->Pool::apply(cap.base(),
|
||||||
|
[&] (Pager_object *source) {
|
||||||
if (cap.is_null() || item->is_del())
|
/* set source PD (VMM) where vCPU exception portals are */
|
||||||
continue;
|
obj->_pd_source = source->pd_sel();
|
||||||
|
});
|
||||||
/**
|
|
||||||
* Remap portal to dense packed region - required for vCPU running
|
|
||||||
* in separate PD (non-colocated case)
|
|
||||||
*/
|
|
||||||
Obj_crd snd(cap.base(), 0);
|
|
||||||
Obj_crd rcv(obj->_client_exc_vcpu + event * items_count + i, 0);
|
|
||||||
if (map_local(utcb, snd, rcv))
|
|
||||||
warning("could not remap vCPU portal ", Hex(i));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,10 +579,11 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap,
|
|||||||
_badge(badge),
|
_badge(badge),
|
||||||
_selectors(cap_map()->insert(2)),
|
_selectors(cap_map()->insert(2)),
|
||||||
_client_exc_pt_sel(cap_map()->insert(NUM_INITIAL_PT_LOG2)),
|
_client_exc_pt_sel(cap_map()->insert(NUM_INITIAL_PT_LOG2)),
|
||||||
_client_exc_vcpu(Native_thread::INVALID_INDEX),
|
|
||||||
_cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap),
|
_cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap),
|
||||||
_location(location),
|
_location(location),
|
||||||
_exceptions(this)
|
_exceptions(this),
|
||||||
|
_pd_target(Native_thread::INVALID_INDEX),
|
||||||
|
_pd_source(Native_thread::INVALID_INDEX)
|
||||||
{
|
{
|
||||||
uint8_t res;
|
uint8_t res;
|
||||||
|
|
||||||
@ -681,15 +670,9 @@ Pager_object::~Pager_object()
|
|||||||
revoke(Obj_crd(_selectors, 2));
|
revoke(Obj_crd(_selectors, 2));
|
||||||
cap_map()->remove(_selectors, 2, false);
|
cap_map()->remove(_selectors, 2, false);
|
||||||
cap_map()->remove(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2, false);
|
cap_map()->remove(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2, false);
|
||||||
|
|
||||||
if (_client_exc_vcpu == Native_thread::INVALID_INDEX)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* revoke vCPU exception portals */
|
|
||||||
revoke(Obj_crd(_client_exc_vcpu, NUM_INITIAL_VCPU_PT_LOG2));
|
|
||||||
cap_map()->remove(_client_exc_vcpu, NUM_INITIAL_VCPU_PT_LOG2, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t Pager_object::handle_oom(addr_t transfer_from,
|
uint8_t Pager_object::handle_oom(addr_t transfer_from,
|
||||||
char const * src_pd, char const * src_thread,
|
char const * src_pd, char const * src_thread,
|
||||||
enum Pager_object::Policy policy)
|
enum Pager_object::Policy policy)
|
||||||
|
@ -62,8 +62,17 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pager->pd_sel() != Native_thread::INVALID_INDEX) {
|
||||||
|
error("thread already started");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utcb * const utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb());
|
||||||
|
addr_t const pts = vcpu() ? NUM_INITIAL_VCPU_PT_LOG2
|
||||||
|
: NUM_INITIAL_PT_LOG2;
|
||||||
|
|
||||||
addr_t const pt_oom = _pager->get_oom_portal();
|
addr_t const pt_oom = _pager->get_oom_portal();
|
||||||
if (!pt_oom || map_local((Utcb *)Thread::myself()->utcb(),
|
if (!pt_oom || map_local(utcb,
|
||||||
Obj_crd(pt_oom, 0), Obj_crd(_sel_pt_oom(), 0))) {
|
Obj_crd(pt_oom, 0), Obj_crd(_sel_pt_oom(), 0))) {
|
||||||
error("setup of out-of-memory notification portal - failed");
|
error("setup of out-of-memory notification portal - failed");
|
||||||
return -8;
|
return -8;
|
||||||
@ -71,7 +80,7 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
|
|
||||||
if (!main_thread()) {
|
if (!main_thread()) {
|
||||||
addr_t const initial_sp = reinterpret_cast<addr_t>(sp);
|
addr_t const initial_sp = reinterpret_cast<addr_t>(sp);
|
||||||
addr_t const utcb = vcpu() ? 0 : round_page(initial_sp);
|
addr_t const utcb_addr = vcpu() ? 0 : round_page(initial_sp);
|
||||||
|
|
||||||
if (_sel_exc_base == Native_thread::INVALID_INDEX) {
|
if (_sel_exc_base == Native_thread::INVALID_INDEX) {
|
||||||
error("exception base not specified");
|
error("exception base not specified");
|
||||||
@ -80,11 +89,27 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
|
|
||||||
_pager->assign_pd(_pd->pd_sel());
|
_pager->assign_pd(_pd->pd_sel());
|
||||||
|
|
||||||
|
/* second++ vcpu case which runs in other pd than VMM */
|
||||||
|
if (vcpu() && _pager->pd_sel() != _pager->pd_source()) {
|
||||||
|
Obj_crd const source_initial_caps(_sel_exc_base, pts);
|
||||||
|
Obj_crd const target_initial_caps(_sel_exc_base, pts);
|
||||||
|
|
||||||
|
/* asynchronously map capabilities */
|
||||||
|
utcb->set_msg_word(0);
|
||||||
|
if (!utcb->append_item(source_initial_caps, 0))
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
uint8_t res = Nova::delegate(_pager->pd_source(), _pager->pd_sel(),
|
||||||
|
target_initial_caps);
|
||||||
|
if (res != NOVA_OK)
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t res;
|
uint8_t res;
|
||||||
do {
|
do {
|
||||||
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_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,
|
res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
|
||||||
utcb, initial_sp, _sel_exc_base, !worker());
|
utcb_addr, initial_sp, _sel_exc_base, !worker());
|
||||||
if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) {
|
if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) {
|
||||||
_pager->assign_pd(Native_thread::INVALID_INDEX);
|
_pager->assign_pd(Native_thread::INVALID_INDEX);
|
||||||
error("creation of new thread failed ", res);
|
error("creation of new thread failed ", res);
|
||||||
@ -104,24 +129,31 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_sel_exc_base != Native_thread::INVALID_INDEX) {
|
if (!vcpu() && _sel_exc_base != Native_thread::INVALID_INDEX) {
|
||||||
error("thread already started");
|
error("thread already started");
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t pd_utcb = 0;
|
addr_t pd_utcb = 0;
|
||||||
_sel_exc_base = vcpu() ? _pager->exc_pt_vcpu() : _pager->exc_pt_sel_client();
|
Obj_crd initial_pts;
|
||||||
|
|
||||||
if (!vcpu()) {
|
if (!vcpu()) {
|
||||||
|
_sel_exc_base = _pager->exc_pt_sel_client();
|
||||||
|
|
||||||
pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size();
|
pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size();
|
||||||
|
|
||||||
|
addr_t const rights = Obj_crd::RIGHT_EC_RECALL |
|
||||||
|
Obj_crd::RIGHT_PT_CTRL | Obj_crd::RIGHT_PT_CALL |
|
||||||
|
Obj_crd::RIGHT_SM_UP | Obj_crd::RIGHT_SM_DOWN;
|
||||||
|
initial_pts = Obj_crd(_sel_exc_base, pts, rights);
|
||||||
|
|
||||||
addr_t remap_src[] = { _pd->parent_pt_sel(),
|
addr_t remap_src[] = { _pd->parent_pt_sel(),
|
||||||
(unsigned long)_pager->Object_pool<Pager_object>::Entry::cap().local_name() };
|
(unsigned long)_pager->Object_pool<Pager_object>::Entry::cap().local_name() };
|
||||||
addr_t remap_dst[] = { PT_SEL_PARENT, PT_SEL_MAIN_PAGER };
|
addr_t remap_dst[] = { PT_SEL_PARENT, PT_SEL_MAIN_PAGER };
|
||||||
|
|
||||||
/* remap exception portals for first thread */
|
/* remap exception portals for first thread */
|
||||||
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
|
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
|
||||||
if (map_local((Utcb *)Thread::myself()->utcb(),
|
if (map_local(utcb,
|
||||||
Obj_crd(remap_src[i], 0),
|
Obj_crd(remap_src[i], 0),
|
||||||
Obj_crd(_sel_exc_base + remap_dst[i], 0)))
|
Obj_crd(_sel_exc_base + remap_dst[i], 0)))
|
||||||
return -6;
|
return -6;
|
||||||
@ -130,16 +162,12 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
|
|
||||||
/* create task */
|
/* create task */
|
||||||
addr_t const pd_sel = cap_map()->insert();
|
addr_t const pd_sel = cap_map()->insert();
|
||||||
addr_t const rights = Obj_crd::RIGHT_EC_RECALL |
|
|
||||||
Obj_crd::RIGHT_PT_CTRL | Obj_crd::RIGHT_PT_CALL |
|
|
||||||
Obj_crd::RIGHT_SM_UP | Obj_crd::RIGHT_SM_DOWN;
|
|
||||||
unsigned pts = vcpu() ? NUM_INITIAL_VCPU_PT_LOG2 : NUM_INITIAL_PT_LOG2;
|
|
||||||
|
|
||||||
enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 };
|
enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 };
|
||||||
Obj_crd initial_pts(_sel_exc_base, pts, rights);
|
|
||||||
uint8_t res = create_pd(pd_sel, platform_specific()->core_pd_sel(),
|
uint8_t res = create_pd(pd_sel, platform_specific()->core_pd_sel(),
|
||||||
initial_pts,
|
initial_pts,
|
||||||
KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE, UPPER_LIMIT_PAGES);
|
KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE,
|
||||||
|
UPPER_LIMIT_PAGES);
|
||||||
if (res != NOVA_OK) {
|
if (res != NOVA_OK) {
|
||||||
error("create_pd returned ", res);
|
error("create_pd returned ", res);
|
||||||
goto cleanup_pd;
|
goto cleanup_pd;
|
||||||
@ -148,7 +176,8 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
/* create first thread in task */
|
/* create first thread in task */
|
||||||
enum { THREAD_GLOBAL = true };
|
enum { THREAD_GLOBAL = true };
|
||||||
res = create_ec(_sel_ec(), pd_sel,
|
res = create_ec(_sel_ec(), pd_sel,
|
||||||
platform_specific()->kernel_cpu_id(_location.xpos()), pd_utcb, 0, 0,
|
platform_specific()->kernel_cpu_id(_location.xpos()),
|
||||||
|
pd_utcb, 0, 0,
|
||||||
THREAD_GLOBAL);
|
THREAD_GLOBAL);
|
||||||
if (res != NOVA_OK) {
|
if (res != NOVA_OK) {
|
||||||
error("create_ec returned ", res);
|
error("create_ec returned ", res);
|
||||||
@ -165,11 +194,25 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
_pager->initial_esp((addr_t)sp);
|
_pager->initial_esp((addr_t)sp);
|
||||||
_pager->assign_pd(pd_sel);
|
_pager->assign_pd(pd_sel);
|
||||||
|
|
||||||
|
if (vcpu() && _pager->pd_sel() != _pager->pd_source()) {
|
||||||
|
Obj_crd const source_initial_caps(_sel_exc_base, pts);
|
||||||
|
Obj_crd const target_initial_caps(0, pts);
|
||||||
|
|
||||||
|
/* asynchronously map capabilities */
|
||||||
|
utcb->set_msg_word(0);
|
||||||
|
res = utcb->append_item(source_initial_caps, 0);
|
||||||
|
if (res)
|
||||||
|
res = Nova::delegate(_pager->pd_source(), _pager->pd_sel(),
|
||||||
|
target_initial_caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == NOVA_OK) {
|
||||||
do {
|
do {
|
||||||
/* let the thread run */
|
/* let the thread run */
|
||||||
res = create_sc(_sel_sc(), pd_sel, _sel_ec(),
|
res = create_sc(_sel_sc(), pd_sel, _sel_ec(),
|
||||||
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
|
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
|
||||||
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom());
|
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom());
|
||||||
|
}
|
||||||
|
|
||||||
if (res != NOVA_OK) {
|
if (res != NOVA_OK) {
|
||||||
/*
|
/*
|
||||||
@ -184,7 +227,8 @@ int Platform_thread::start(void *ip, void *sp)
|
|||||||
|
|
||||||
error("create_sc returned ", res);
|
error("create_sc returned ", res);
|
||||||
goto cleanup_ec;
|
goto cleanup_ec;
|
||||||
} else
|
}
|
||||||
|
|
||||||
_features |= SC_CREATED;
|
_features |= SC_CREATED;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -262,7 +306,7 @@ void Platform_thread::state(Thread_state s)
|
|||||||
* s.is_vcpu If true it will run as vCPU,
|
* s.is_vcpu If true it will run as vCPU,
|
||||||
* otherwise it will be a thread.
|
* otherwise it will be a thread.
|
||||||
*/
|
*/
|
||||||
if (!main_thread())
|
if (!main_thread() || s.vcpu)
|
||||||
_sel_exc_base = s.sel_exc_base;
|
_sel_exc_base = s.sel_exc_base;
|
||||||
|
|
||||||
if (!s.global_thread)
|
if (!s.global_thread)
|
||||||
@ -273,9 +317,6 @@ void Platform_thread::state(Thread_state s)
|
|||||||
|
|
||||||
_features |= VCPU;
|
_features |= VCPU;
|
||||||
|
|
||||||
if (main_thread() && _pager)
|
|
||||||
_pager->prepare_vCPU_portals();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (!_pager) throw Cpu_thread::State_access_failed();
|
if (!_pager) throw Cpu_thread::State_access_failed();
|
||||||
|
@ -48,7 +48,7 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Genode::Pd_connection _pd_session;
|
Genode::Capability<Genode::Pd_session> _pd_cap;
|
||||||
Genode::Affinity::Location _location;
|
Genode::Affinity::Location _location;
|
||||||
Genode::Cpu_session *_cpu_session;
|
Genode::Cpu_session *_cpu_session;
|
||||||
|
|
||||||
@ -58,9 +58,10 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
|||||||
|
|
||||||
Vcpu_other_pd(Cpu_session * cpu_session,
|
Vcpu_other_pd(Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
|
Genode::Capability<Genode::Pd_session> pd_cap,
|
||||||
Genode::size_t = 0 /* stack_size */)
|
Genode::size_t = 0 /* stack_size */)
|
||||||
:
|
:
|
||||||
_pd_session("VM"), _location(location), _cpu_session(cpu_session),
|
_pd_cap(pd_cap), _location(location), _cpu_session(cpu_session),
|
||||||
_exc_pt_sel(Genode::cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2))
|
_exc_pt_sel(Genode::cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -69,12 +70,12 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
Thread_capability vcpu_vm =
|
Thread_capability vcpu_vm =
|
||||||
_cpu_session->create_thread(_pd_session, "vCPU",
|
_cpu_session->create_thread(_pd_cap, "vCPU",
|
||||||
_location, Cpu_session::Weight());
|
_location, Cpu_session::Weight());
|
||||||
|
|
||||||
/* tell parent that this will be a vCPU */
|
/* tell parent that this will be a vCPU */
|
||||||
Thread_state state;
|
Thread_state state;
|
||||||
state.sel_exc_base = Native_thread::INVALID_INDEX;
|
state.sel_exc_base = _exc_pt_sel;
|
||||||
state.vcpu = true;
|
state.vcpu = true;
|
||||||
|
|
||||||
Cpu_thread_client cpu_thread(vcpu_vm);
|
Cpu_thread_client cpu_thread(vcpu_vm);
|
||||||
@ -88,10 +89,11 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
|||||||
Native_capability pager_cap = native_cpu.pager_cap(vcpu_vm);
|
Native_capability pager_cap = native_cpu.pager_cap(vcpu_vm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delegate parent the vCPU exception portals required during PD
|
* Translate pager cap of current executing thread, which is used
|
||||||
* creation.
|
* to lookup current PD - required during PD creation.
|
||||||
*/
|
*/
|
||||||
delegate_vcpu_portals(pager_cap, exc_base());
|
translate_remote_pager(pager_cap,
|
||||||
|
Thread::myself()->native_thread().ec_sel + 1);
|
||||||
|
|
||||||
/* start vCPU in separate PD */
|
/* start vCPU in separate PD */
|
||||||
cpu_thread.start(0, 0);
|
cpu_thread.start(0, 0);
|
||||||
@ -101,6 +103,9 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
|||||||
* SM cap - see Vcpu_dispatcher->sel_sm_ec description
|
* SM cap - see Vcpu_dispatcher->sel_sm_ec description
|
||||||
*/
|
*/
|
||||||
request_native_ec_cap(pager_cap, sel_ec);
|
request_native_ec_cap(pager_cap, sel_ec);
|
||||||
|
|
||||||
|
/* request creation of SC to let vCPU run */
|
||||||
|
cpu_thread.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
Genode::addr_t exc_base() { return _exc_pt_sel; }
|
Genode::addr_t exc_base() { return _exc_pt_sel; }
|
||||||
@ -115,6 +120,7 @@ class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread
|
|||||||
|
|
||||||
Vcpu_same_pd(Cpu_session * cpu_session,
|
Vcpu_same_pd(Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
|
Genode::Capability<Genode::Pd_session>,
|
||||||
Genode::size_t stack_size)
|
Genode::size_t stack_size)
|
||||||
:
|
:
|
||||||
Thread(WEIGHT, "vCPU", stack_size, Type::NORMAL, cpu_session, location)
|
Thread(WEIGHT, "vCPU", stack_size, Type::NORMAL, cpu_session, location)
|
||||||
|
@ -34,9 +34,9 @@ append qemu_args " -m 512 "
|
|||||||
append qemu_args " -cpu phenom "
|
append qemu_args " -cpu phenom "
|
||||||
append qemu_args " -nographic "
|
append qemu_args " -nographic "
|
||||||
|
|
||||||
run_genode_until {.*VMM: vcpu_s_1 _svm_startup called.*\n} 30
|
run_genode_until {.*VMM: vcpu_s_1 _vcpu_startup called.*\n} 30
|
||||||
run_genode_until {.*VMM: vcpu_s_2 _svm_startup called.*\n} 10 [output_spawn_id]
|
run_genode_until {.*VMM: vcpu_s_2 _vcpu_startup called.*\n} 10 [output_spawn_id]
|
||||||
run_genode_until {.*VMM: vcpu_o_1 _svm_startup called.*\n} 10 [output_spawn_id]
|
run_genode_until {.*VMM: vcpu_o_1 _vcpu_startup called.*\n} 10 [output_spawn_id]
|
||||||
run_genode_until {.*VMM: vcpu_o_2 _svm_startup called.*\n} 10 [output_spawn_id]
|
run_genode_until {.*VMM: vcpu_o_2 _vcpu_startup called.*\n} 10 [output_spawn_id]
|
||||||
|
|
||||||
puts "Test succeeded"
|
puts "Test succeeded"
|
||||||
|
@ -862,6 +862,7 @@ class Machine : public StaticReceiver<Machine>
|
|||||||
Guest_memory &_guest_memory;
|
Guest_memory &_guest_memory;
|
||||||
Boot_module_provider &_boot_modules;
|
Boot_module_provider &_boot_modules;
|
||||||
Alarm_thread *_alarm_thread;
|
Alarm_thread *_alarm_thread;
|
||||||
|
Genode::Pd_connection *_pd_vcpus = nullptr;
|
||||||
|
|
||||||
bool _alloc_fb_mem; /* For detecting FB alloc message */
|
bool _alloc_fb_mem; /* For detecting FB alloc message */
|
||||||
bool _colocate_vm_vmm;
|
bool _colocate_vm_vmm;
|
||||||
@ -949,9 +950,13 @@ class Machine : public StaticReceiver<Machine>
|
|||||||
|
|
||||||
Vmm::Vcpu_thread * vcpu_thread;
|
Vmm::Vcpu_thread * vcpu_thread;
|
||||||
if (_colocate_vm_vmm)
|
if (_colocate_vm_vmm)
|
||||||
vcpu_thread = new Vmm::Vcpu_same_pd(cpu_session, location, Vcpu_dispatcher::STACK_SIZE);
|
vcpu_thread = new Vmm::Vcpu_same_pd(cpu_session, location, _env.pd_session_cap(), Vcpu_dispatcher::STACK_SIZE);
|
||||||
else
|
else {
|
||||||
vcpu_thread = new Vmm::Vcpu_other_pd(cpu_session, location);
|
if (!_pd_vcpus)
|
||||||
|
_pd_vcpus = new Genode::Pd_connection("VM");
|
||||||
|
|
||||||
|
vcpu_thread = new Vmm::Vcpu_other_pd(cpu_session, location, *_pd_vcpus);
|
||||||
|
}
|
||||||
|
|
||||||
Vcpu_dispatcher *vcpu_dispatcher =
|
Vcpu_dispatcher *vcpu_dispatcher =
|
||||||
new Vcpu_dispatcher(_motherboard_lock,
|
new Vcpu_dispatcher(_motherboard_lock,
|
||||||
|
@ -46,21 +46,23 @@ class Vcpu_dispatcher : public Vmm::Vcpu_dispatcher<Genode::Thread>
|
|||||||
** Virtualization event handlers **
|
** Virtualization event handlers **
|
||||||
***********************************/
|
***********************************/
|
||||||
|
|
||||||
void _svm_startup()
|
void _vcpu_startup()
|
||||||
{
|
{
|
||||||
Vmm::log(name(), " _svm_startup called");
|
Vmm::log(name(), " ", __func__, " called");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Type { SVM, VTX };
|
enum Type { SVM, VTX };
|
||||||
|
|
||||||
Vcpu_dispatcher(Genode::Env &env, Type type, char const * name)
|
Vcpu_dispatcher(Genode::Env &env, Type type, char const * name,
|
||||||
|
Genode::Capability<Genode::Pd_session> pd_cap)
|
||||||
:
|
:
|
||||||
Vmm::Vcpu_dispatcher<Genode::Thread>(env, STACK_SIZE, &env.cpu(),
|
Vmm::Vcpu_dispatcher<Genode::Thread>(env, STACK_SIZE, &env.cpu(),
|
||||||
Genode::Affinity::Location(),
|
Genode::Affinity::Location(),
|
||||||
name),
|
name),
|
||||||
_vcpu_thread(&env.cpu(), Genode::Affinity::Location(), STACK_SIZE)
|
_vcpu_thread(&env.cpu(), Genode::Affinity::Location(), pd_cap,
|
||||||
|
STACK_SIZE)
|
||||||
{
|
{
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
@ -73,7 +75,7 @@ class Vcpu_dispatcher : public Vmm::Vcpu_dispatcher<Genode::Thread>
|
|||||||
|
|
||||||
/* register virtualization event handlers */
|
/* register virtualization event handlers */
|
||||||
if (type == SVM) {
|
if (type == SVM) {
|
||||||
_register_handler<0xfe, &This::_svm_startup>
|
_register_handler<0xfe, &This::_vcpu_startup>
|
||||||
(exc_base, mtd_all);
|
(exc_base, mtd_all);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +89,12 @@ void Component::construct(Genode::Env &env)
|
|||||||
{
|
{
|
||||||
typedef Vcpu_dispatcher<Vmm::Vcpu_same_pd> Vcpu_s;
|
typedef Vcpu_dispatcher<Vmm::Vcpu_same_pd> Vcpu_s;
|
||||||
|
|
||||||
static Vcpu_s vcpu_s_1(env, Vcpu_s::SVM, "vcpu_s_1");
|
static Vcpu_s vcpu_s_1(env, Vcpu_s::SVM, "vcpu_s_1", env.pd_session_cap());
|
||||||
static Vcpu_s vcpu_s_2(env, Vcpu_s::SVM, "vcpu_s_2");
|
static Vcpu_s vcpu_s_2(env, Vcpu_s::SVM, "vcpu_s_2", env.pd_session_cap());
|
||||||
|
|
||||||
typedef Vcpu_dispatcher<Vmm::Vcpu_other_pd> Vcpu_o;
|
typedef Vcpu_dispatcher<Vmm::Vcpu_other_pd> Vcpu_o;
|
||||||
|
|
||||||
static Vcpu_o vcpu_o_1(env, Vcpu_o::SVM, "vcpu_o_1");
|
static Genode::Pd_connection remote_pd("VM");
|
||||||
static Vcpu_o vcpu_o_2(env, Vcpu_o::SVM, "vcpu_o_2");
|
static Vcpu_o vcpu_o_1(env, Vcpu_o::SVM, "vcpu_o_1", remote_pd);
|
||||||
|
static Vcpu_o vcpu_o_2(env, Vcpu_o::SVM, "vcpu_o_2", remote_pd);
|
||||||
}
|
}
|
||||||
|
@ -299,19 +299,21 @@ bool create_emt_vcpu(pthread_t * pthread, size_t stack,
|
|||||||
if (!hip->has_feature_vmx() && !hip->has_feature_svm())
|
if (!hip->has_feature_vmx() && !hip->has_feature_svm())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
static Genode::Pd_connection pd_vcpus("VM");
|
||||||
|
|
||||||
Vcpu_handler *vcpu_handler = 0;
|
Vcpu_handler *vcpu_handler = 0;
|
||||||
|
|
||||||
if (hip->has_feature_vmx())
|
if (hip->has_feature_vmx())
|
||||||
vcpu_handler = new (0x10) Vcpu_handler_vmx(genode_env(),
|
vcpu_handler = new (0x10) Vcpu_handler_vmx(genode_env(),
|
||||||
stack, attr, start_routine,
|
stack, attr, start_routine,
|
||||||
arg, cpu_session, location,
|
arg, cpu_session, location,
|
||||||
cpu_id, name);
|
cpu_id, name, pd_vcpus);
|
||||||
|
|
||||||
if (hip->has_feature_svm())
|
if (hip->has_feature_svm())
|
||||||
vcpu_handler = new (0x10) Vcpu_handler_svm(genode_env(),
|
vcpu_handler = new (0x10) Vcpu_handler_svm(genode_env(),
|
||||||
stack, attr, start_routine,
|
stack, attr, start_routine,
|
||||||
arg, cpu_session, location,
|
arg, cpu_session, location,
|
||||||
cpu_id, name);
|
cpu_id, name, pd_vcpus);
|
||||||
|
|
||||||
Assert(!(reinterpret_cast<unsigned long>(vcpu_handler) & 0xf));
|
Assert(!(reinterpret_cast<unsigned long>(vcpu_handler) & 0xf));
|
||||||
|
|
||||||
|
@ -762,12 +762,13 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
|||||||
void *(*start_routine) (void *), void *arg,
|
void *(*start_routine) (void *), void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name)
|
unsigned int cpu_id, const char * name,
|
||||||
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vmm::Vcpu_dispatcher<pthread>(env, stack_size, cpu_session, location,
|
Vmm::Vcpu_dispatcher<pthread>(env, stack_size, cpu_session, location,
|
||||||
attr ? *attr : 0, start_routine, arg,
|
attr ? *attr : 0, start_routine, arg,
|
||||||
name),
|
name),
|
||||||
_vcpu(cpu_session, location),
|
_vcpu(cpu_session, location, pd_vcpu),
|
||||||
_ec_sel(Genode::cap_map()->insert()),
|
_ec_sel(Genode::cap_map()->insert()),
|
||||||
_irq_win(false),
|
_irq_win(false),
|
||||||
_cpu_id(cpu_id)
|
_cpu_id(cpu_id)
|
||||||
|
@ -88,10 +88,11 @@ class Vcpu_handler_svm : public Vcpu_handler
|
|||||||
void *(*start_routine) (void *), void *arg,
|
void *(*start_routine) (void *), void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name)
|
unsigned int cpu_id, const char * name,
|
||||||
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
||||||
location, cpu_id, name)
|
location, cpu_id, name, pd_vcpu)
|
||||||
{
|
{
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
|
@ -162,10 +162,11 @@ class Vcpu_handler_vmx : public Vcpu_handler
|
|||||||
void *(*start_routine) (void *), void *arg,
|
void *(*start_routine) (void *), void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name)
|
unsigned int cpu_id, const char * name,
|
||||||
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
||||||
location, cpu_id, name)
|
location, cpu_id, name, pd_vcpu)
|
||||||
{
|
{
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
|
@ -560,19 +560,21 @@ bool create_emt_vcpu(pthread_t * pthread, ::size_t stack,
|
|||||||
if (!hip->has_feature_vmx() && !hip->has_feature_svm())
|
if (!hip->has_feature_vmx() && !hip->has_feature_svm())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
static Genode::Pd_connection pd_vcpus("VM");
|
||||||
|
|
||||||
Vcpu_handler *vcpu_handler = 0;
|
Vcpu_handler *vcpu_handler = 0;
|
||||||
|
|
||||||
if (hip->has_feature_vmx())
|
if (hip->has_feature_vmx())
|
||||||
vcpu_handler = new (0x10) Vcpu_handler_vmx(genode_env(),
|
vcpu_handler = new (0x10) Vcpu_handler_vmx(genode_env(),
|
||||||
stack, attr, start_routine,
|
stack, attr, start_routine,
|
||||||
arg, cpu_session, location,
|
arg, cpu_session, location,
|
||||||
cpu_id, name);
|
cpu_id, name, pd_vcpus);
|
||||||
|
|
||||||
if (hip->has_feature_svm())
|
if (hip->has_feature_svm())
|
||||||
vcpu_handler = new (0x10) Vcpu_handler_svm(genode_env(),
|
vcpu_handler = new (0x10) Vcpu_handler_svm(genode_env(),
|
||||||
stack, attr, start_routine,
|
stack, attr, start_routine,
|
||||||
arg, cpu_session, location,
|
arg, cpu_session, location,
|
||||||
cpu_id, name);
|
cpu_id, name, pd_vcpus);
|
||||||
|
|
||||||
Assert(!(reinterpret_cast<unsigned long>(vcpu_handler) & 0xf));
|
Assert(!(reinterpret_cast<unsigned long>(vcpu_handler) & 0xf));
|
||||||
|
|
||||||
|
@ -765,12 +765,13 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
|||||||
void *(*start_routine) (void *), void *arg,
|
void *(*start_routine) (void *), void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name)
|
unsigned int cpu_id, const char * name,
|
||||||
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vmm::Vcpu_dispatcher<pthread>(env, stack_size, cpu_session, location,
|
Vmm::Vcpu_dispatcher<pthread>(env, stack_size, cpu_session, location,
|
||||||
attr ? *attr : 0, start_routine, arg,
|
attr ? *attr : 0, start_routine, arg,
|
||||||
name),
|
name),
|
||||||
_vcpu(cpu_session, location),
|
_vcpu(cpu_session, location, pd_vcpu),
|
||||||
_ec_sel(Genode::cap_map()->insert()),
|
_ec_sel(Genode::cap_map()->insert()),
|
||||||
_irq_win(false),
|
_irq_win(false),
|
||||||
_cpu_id(cpu_id)
|
_cpu_id(cpu_id)
|
||||||
|
@ -88,10 +88,11 @@ class Vcpu_handler_svm : public Vcpu_handler
|
|||||||
void *(*start_routine) (void *), void *arg,
|
void *(*start_routine) (void *), void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name)
|
unsigned int cpu_id, const char * name,
|
||||||
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
||||||
location, cpu_id, name)
|
location, cpu_id, name, pd_vcpu)
|
||||||
{
|
{
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
|
@ -170,10 +170,11 @@ class Vcpu_handler_vmx : public Vcpu_handler
|
|||||||
void *(*start_routine) (void *), void *arg,
|
void *(*start_routine) (void *), void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name)
|
unsigned int cpu_id, const char * name,
|
||||||
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
Vcpu_handler(env, stack_size, attr, start_routine, arg, cpu_session,
|
||||||
location, cpu_id, name)
|
location, cpu_id, name, pd_vcpu)
|
||||||
{
|
{
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user