Skip to content

Commit baf7d90

Browse files
yakuizhaoacrnsi
authored andcommitted
HV: Refine the usage of monitor/mwait to avoid the possible lockup
Based on SDM Vol2 the monitor uses the RAX register to setup the address monitored by HW. The mwait uses the rax/rcx as the hints that the process will enter. It is incorrect that the same value is used for monitor/mwait. The ecx in mwait specifies the optional externsions. At the same time it needs to check whether the the value of monitored addr is already expected before entering mwait. Otherwise it will have possible lockup. V1->V2: Add the asm wrappper of monitor/mwait to avoid the mixed usage of inline assembly in wait_sync_change v2-v3: Remove the unnecessary line break in asm_monitor/asm_mwait. Follow Fei's comment to remove the mwait ecx hint setting that treats the interrupt as break event. It only needs to check whether the value of psync_change is already expected. Tracked-On: #3442 Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Reviewed-by: Yin Fengwei <fengwei.yin@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
1 parent 11cf9a4 commit baf7d90

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed

hypervisor/arch/x86/cpu.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -423,21 +423,29 @@ static void print_hv_banner(void)
423423
printf(boot_msg);
424424
}
425425

426+
static
427+
inline void asm_monitor(volatile const uint64_t *addr, uint64_t ecx, uint64_t edx)
428+
{
429+
asm volatile("monitor\n" : : "a" (addr), "c" (ecx), "d" (edx));
430+
}
431+
432+
static
433+
inline void asm_mwait(uint64_t eax, uint64_t ecx)
434+
{
435+
asm volatile("mwait\n" : : "a" (eax), "c" (ecx));
436+
}
437+
426438
/* wait until *sync == wake_sync */
427-
void wait_sync_change(uint64_t *sync, uint64_t wake_sync)
439+
void wait_sync_change(volatile const uint64_t *sync, uint64_t wake_sync)
428440
{
429441
if (has_monitor_cap()) {
430442
/* Wait for the event to be set using monitor/mwait */
431-
asm volatile ("1: cmpq %%rbx,(%%rax)\n"
432-
" je 2f\n"
433-
" monitor\n"
434-
" mwait\n"
435-
" jmp 1b\n"
436-
"2:\n"
437-
:
438-
: "a" (sync), "d"(0), "c"(0),
439-
"b"(wake_sync)
440-
: "cc");
443+
while ((*sync) != wake_sync) {
444+
asm_monitor(sync, 0UL, 0UL);
445+
if ((*sync) != wake_sync) {
446+
asm_mwait(0UL, 0UL);
447+
}
448+
}
441449
} else {
442450
/* Wait for the event to be set using pause */
443451
asm volatile ("1: cmpq %%rbx,(%%rax)\n"

hypervisor/include/arch/x86/cpu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ void init_pcpu_post(uint16_t pcpu_id);
270270
bool start_pcpus(uint64_t mask);
271271
void wait_pcpus_offline(uint64_t mask);
272272
void stop_pcpus(void);
273-
void wait_sync_change(uint64_t *sync, uint64_t wake_sync);
273+
void wait_sync_change(volatile const uint64_t *sync, uint64_t wake_sync);
274274

275275
#define CPU_SEG_READ(seg, result_ptr) \
276276
{ \

0 commit comments

Comments
 (0)