Re: [PATCHv2 2/3] x86/tdx: Clarify RIP adjustments in #VE handler

From: Sean Christopherson
Date: Fri May 20 2022 - 14:01:59 EST


On Fri, May 20, 2022, Dave Hansen wrote:
> BTW, how do we know that all non-EPT_VIOLATION exits reasons are
> instruction execution?

The TDX module spec actually does a decent job of calling this out explicitly:

#VE may be injected by the Intel TDX module in several cases:
* Emulation of the architectural #VE injection on EPT violation, done by a
guest-side Intel TDX module flow that performs an EPT walk.
* As a result of guest TD execution of a disallowed instruction (see 10.4 above),
a disallowed MSR access (see 10.7 above), or CPUID virtualization (see 10.8 above).
* A notification to the guest TD about anomalous behavior (e.g., too many EPT
violations reported on the same TD VCPU instruction without making progress).
This kind of #VE is raised only if the guest TD enabled the specific notification
(using TDG.VM.WR to write the TDCS.NOTIFY_ENABLES field) and when a #VE can be
injected. See 16.3 for details.

The first one is (obviously) the EPT violation / MMIO case. The second is purely
instruction execution (the MSR and CPUID clauses are specific to RDMSR, WRMSR,
and CPUID)). The third I hadn't seen until now, but it's opt-in.

The main switch statement further guarantees the kernel is only going to handle
EPT violations and instruction exits at this time:

switch (ve->exit_reason) {
case EXIT_REASON_HLT:
return handle_halt();
case EXIT_REASON_MSR_READ:
return read_msr(regs);
case EXIT_REASON_MSR_WRITE:
return write_msr(regs);
case EXIT_REASON_CPUID:
return handle_cpuid(regs);
case EXIT_REASON_EPT_VIOLATION:
return handle_mmio(regs, ve);
case EXIT_REASON_IO_INSTRUCTION:
return handle_io(regs, ve->exit_qual);
default:
pr_warn("Unexpected #VE: %lld\n", ve->exit_reason);
return false;
}