/* * The `native_machine_emergency_restart` function from `reboot.c` writes * to the physical address 0x472 to indicate the type of reboot for the * firmware. We cannot have that in VSM as the memory composition might * be more generic, and such write effectively corrupts the memory thus * making diagnostics harder at the very least.
*/ staticvoid __noreturn hv_vtl_emergency_restart(void)
{ /* * Cause a triple fault and the immediate reset. Here the code does not run * on the top of any firmware, whereby cannot reach out to its services. * The inifinite loop is for the improbable case that the triple fault does * not work and have to preserve the state intact for debugging.
*/ for (;;) {
idt_invalidate();
__asm__ __volatile__("int3");
}
}
/* * The only way to restart in the VTL mode is to triple fault as the kernel runs * as firmware.
*/ staticvoid __noreturn hv_vtl_restart(char __maybe_unused *cmd)
{
hv_vtl_emergency_restart();
}
void __init hv_vtl_init_platform(void)
{ /* * This function is a no-op if the VTL mode is not enabled. * If it is, this function runs if and only the kernel boots in * VTL2 which the x86 hv initialization path makes sure of.
*/
pr_info("Linux runs in Hyper-V Virtual Trust Level %d\n", ms_hyperv.vtl);
/* * The x86_64 Linux kernel follows the 16-bit -> 32-bit -> 64-bit * mode transition sequence after waking up an AP with SIPI whose * vector points to the 16-bit AP startup trampoline code. Here in * VTL2, we can't perform that sequence as the AP has to start in * the 64-bit mode. * * To make this happen, we tell the hypervisor to load a valid 64-bit * context (most of which is just magic numbers from the CPU manual) * so that AP jumps right to the 64-bit entry of the kernel, and the * control registers are loaded with values that let the AP fetch the * code and data and carry on with work it gets assigned.
*/
status = hv_do_hypercall(HVCALL_ENABLE_VP_VTL, input, NULL);
if (!hv_result_success(status) &&
hv_result(status) != HV_STATUS_VTL_ALREADY_ENABLED) {
pr_err("HVCALL_ENABLE_VP_VTL failed for VP : %d ! [Err: %#llx\n]",
target_vp_index, status);
ret = -EINVAL; goto free_lock;
}
status = hv_do_hypercall(HVCALL_START_VP, input, NULL);
if (!hv_result_success(status)) {
pr_err("HVCALL_START_VP failed for VP : %d ! [Err: %#llx]\n",
target_vp_index, status);
ret = -EINVAL;
}
free_lock:
local_irq_restore(irq_flags);
return ret;
}
staticint hv_vtl_wakeup_secondary_cpu(u32 apicid, unsignedlong start_eip, unsignedintcpu)
{ int vp_index;
pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid);
vp_index = hv_apicid_to_vp_index(apicid);
if (vp_index < 0) {
pr_err("Couldn't find CPU with APIC ID %d\n", apicid); return -EINVAL;
} if (vp_index > ms_hyperv.max_vp_index) {
pr_err("Invalid CPU id %d for APIC ID %d\n", vp_index, apicid); return -EINVAL;
}
int __init hv_vtl_early_init(void)
{
machine_ops.emergency_restart = hv_vtl_emergency_restart;
machine_ops.restart = hv_vtl_restart;
/* * `boot_cpu_has` returns the runtime feature support, * and here is the earliest it can be used.
*/ if (cpu_feature_enabled(X86_FEATURE_XSAVE))
panic("XSAVE has to be disabled as it is not supported by this module.\n" "Please add 'noxsave' to the kernel command line.\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.