mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-09-05 19:00:16 +00:00
efi-stub: reset all APs after entering guest mode
In current hv implementation, we assume all AP have no context before jumping into guest mode. But this is not true in all UEFI bios. BIOS could have enabled all (or some of) APs at first. These APs could stay in a run loop or wait for a semaphore. But after hv takes over control from efi-stub, all of these AP environments will be simply dropped because we don't support AP context save/restore for now. As a result, BSP's ExitBootService will hang forver because it's waiting for AP in its way (by waiting for a semaphore for example), unfortunately APs are now in the context that hv provides in which they usually stay in idle loop. To fix the issue above, we could have two solutions: 1. Save AP's runtime context before entering hv and restore context after hv jumps back. 2. After hv jumps back, reset all the APs in the UEFI way, so the previous context will be thrown away and a fresh new starts. Moreover this new one is under virtualization. Currently, we adopt the second one by disabling all the APs before virtualization and then enabling them after hv jumps back. A reset will be triggered. And this is guaranteed by UEFI MP Service protocol. Tracked-On: #2435 Signed-off-by: Tw <wei.tan@intel.com> Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include "boot.h"
|
||||
#include "acrn_common.h"
|
||||
#include "uefi.h"
|
||||
#include "MpService.h"
|
||||
|
||||
EFI_SYSTEM_TABLE *sys_table;
|
||||
EFI_BOOT_SERVICES *boot;
|
||||
@@ -45,6 +46,47 @@ char *cmdline = NULL;
|
||||
extern const uint64_t guest_entry;
|
||||
static UINT64 hv_hpa;
|
||||
|
||||
static void
|
||||
enable_disable_all_ap(BOOLEAN enable)
|
||||
{
|
||||
EFI_MP_SERVICES_PROTOCOL *mp = NULL;
|
||||
EFI_STATUS err;
|
||||
EFI_GUID mp_guid = EFI_MP_SERVICES_PROTOCOL_GUID;
|
||||
UINTN n_proc, n_enabled_proc, bsp, i;
|
||||
|
||||
err = uefi_call_wrapper(boot->LocateProtocol, 3, &mp_guid, NULL, (void **)&mp);
|
||||
if (err != EFI_SUCCESS) {
|
||||
Print(L"Unable to locate MP service protocol: %r, skip %s all AP\n",
|
||||
err, enable ? "enable" : "disable");
|
||||
return;
|
||||
}
|
||||
|
||||
err = uefi_call_wrapper(mp->GetNumberOfProcessors, 3, mp, &n_proc, &n_enabled_proc);
|
||||
if (err != EFI_SUCCESS) {
|
||||
Print(L"failed to GetNumberOfProcessors: %r\n", err);
|
||||
return;
|
||||
}
|
||||
Print(L"detected %d processes, %d enabled\n", n_proc, n_enabled_proc);
|
||||
|
||||
err = uefi_call_wrapper(mp->WhoAmI, 2, mp, &bsp);
|
||||
if (err != EFI_SUCCESS) {
|
||||
Print(L"failed to WhoAmI: %r\n", err);
|
||||
return;
|
||||
}
|
||||
Print(L"current on process %d\n", bsp);
|
||||
|
||||
for (i = 0; i < n_proc; i++) {
|
||||
if (i == bsp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
err = uefi_call_wrapper(mp->EnableDisableAP, 4, mp, i, enable, NULL);
|
||||
if (err != EFI_SUCCESS) {
|
||||
Print(L"failed to %s AP%d: %r\n", enable ? "enable" : "disable", i, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hv_jump(EFI_PHYSICAL_ADDRESS hv_start,
|
||||
struct multiboot_info *mbi, struct efi_context *efi_ctx)
|
||||
{
|
||||
@@ -325,6 +367,9 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table)
|
||||
if (CheckCrc(sys_table->Hdr.HeaderSize, &sys_table->Hdr) != TRUE)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
/* make sure only bsp is enable before entering hv */
|
||||
enable_disable_all_ap(FALSE);
|
||||
|
||||
err = handle_protocol(image, &LoadedImageProtocol, (void **)&info);
|
||||
if (err != EFI_SUCCESS)
|
||||
goto failed;
|
||||
@@ -388,6 +433,12 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table)
|
||||
if (err != EFI_SUCCESS)
|
||||
goto failed;
|
||||
|
||||
/*
|
||||
* enable all AP here will reset all APs,
|
||||
* so acrn can handle their ctx from now on.
|
||||
*/
|
||||
enable_disable_all_ap(TRUE);
|
||||
|
||||
/* load and start the default bootloader */
|
||||
path = FileDevicePath(info->DeviceHandle, bootloader_name);
|
||||
if (!path)
|
||||
|
Reference in New Issue
Block a user