// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2021-2022 Intel Corporation */ #undef pr_fmt #define pr_fmt(fmt) … #include <linux/cpufeature.h> #include <linux/export.h> #include <linux/io.h> #include <linux/kexec.h> #include <asm/coco.h> #include <asm/tdx.h> #include <asm/vmx.h> #include <asm/ia32.h> #include <asm/insn.h> #include <asm/insn-eval.h> #include <asm/pgtable.h> #include <asm/set_memory.h> /* MMIO direction */ #define EPT_READ … #define EPT_WRITE … /* Port I/O direction */ #define PORT_READ … #define PORT_WRITE … /* See Exit Qualification for I/O Instructions in VMX documentation */ #define VE_IS_IO_IN(e) … #define VE_GET_IO_SIZE(e) … #define VE_GET_PORT_NUM(e) … #define VE_IS_IO_STRING(e) … #define ATTR_DEBUG … #define ATTR_SEPT_VE_DISABLE … /* TDX Module call error codes */ #define TDCALL_RETURN_CODE(a) … #define TDCALL_INVALID_OPERAND … #define TDREPORT_SUBTYPE_0 … static atomic_long_t nr_shared; /* Called from __tdx_hypercall() for unrecoverable failure */ noinstr void __noreturn __tdx_hypercall_failed(void) { … } #ifdef CONFIG_KVM_GUEST long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, unsigned long p2, unsigned long p3, unsigned long p4) { … } EXPORT_SYMBOL_GPL(…); #endif /* * Used for TDX guests to make calls directly to the TD module. This * should only be used for calls that have no legitimate reason to fail * or where the kernel can not survive the call failing. */ static inline void tdcall(u64 fn, struct tdx_module_args *args) { … } /** * tdx_mcall_get_report0() - Wrapper to get TDREPORT0 (a.k.a. TDREPORT * subtype 0) using TDG.MR.REPORT TDCALL. * @reportdata: Address of the input buffer which contains user-defined * REPORTDATA to be included into TDREPORT. * @tdreport: Address of the output buffer to store TDREPORT. * * Refer to section titled "TDG.MR.REPORT leaf" in the TDX Module * v1.0 specification for more information on TDG.MR.REPORT TDCALL. * It is used in the TDX guest driver module to get the TDREPORT0. * * Return 0 on success, -EINVAL for invalid operands, or -EIO on * other TDCALL failures. */ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport) { … } EXPORT_SYMBOL_GPL(…); /** * tdx_hcall_get_quote() - Wrapper to request TD Quote using GetQuote * hypercall. * @buf: Address of the directly mapped shared kernel buffer which * contains TDREPORT. The same buffer will be used by VMM to * store the generated TD Quote output. * @size: size of the tdquote buffer (4KB-aligned). * * Refer to section titled "TDG.VP.VMCALL<GetQuote>" in the TDX GHCI * v1.0 specification for more information on GetQuote hypercall. * It is used in the TDX guest driver module to get the TD Quote. * * Return 0 on success or error code on failure. */ u64 tdx_hcall_get_quote(u8 *buf, size_t size) { … } EXPORT_SYMBOL_GPL(…); static void __noreturn tdx_panic(const char *msg) { … } static void tdx_parse_tdinfo(u64 *cc_mask) { … } /* * The TDX module spec states that #VE may be injected for a limited set of * reasons: * * - Emulation of the architectural #VE injection on EPT violation; * * - As a result of guest TD execution of a disallowed instruction, * a disallowed MSR access, or CPUID virtualization; * * - A notification to the guest TD about anomalous behavior; * * The last one is opt-in and is not used by the kernel. * * The Intel Software Developer's Manual describes cases when instruction * length field can be used in section "Information for VM Exits Due to * Instruction Execution". * * For TDX, it ultimately means GET_VEINFO provides reliable instruction length * information if #VE occurred due to instruction execution, but not for EPT * violations. */ static int ve_instr_len(struct ve_info *ve) { … } static u64 __cpuidle __halt(const bool irq_disabled) { … } static int handle_halt(struct ve_info *ve) { … } void __cpuidle tdx_safe_halt(void) { … } static int read_msr(struct pt_regs *regs, struct ve_info *ve) { … } static int write_msr(struct pt_regs *regs, struct ve_info *ve) { … } static int handle_cpuid(struct pt_regs *regs, struct ve_info *ve) { … } static bool mmio_read(int size, unsigned long addr, unsigned long *val) { … } static bool mmio_write(int size, unsigned long addr, unsigned long val) { … } static int handle_mmio(struct pt_regs *regs, struct ve_info *ve) { … } static bool handle_in(struct pt_regs *regs, int size, int port) { … } static bool handle_out(struct pt_regs *regs, int size, int port) { … } /* * Emulate I/O using hypercall. * * Assumes the IO instruction was using ax, which is enforced * by the standard io.h macros. * * Return True on success or False on failure. */ static int handle_io(struct pt_regs *regs, struct ve_info *ve) { … } /* * Early #VE exception handler. Only handles a subset of port I/O. * Intended only for earlyprintk. If failed, return false. */ __init bool tdx_early_handle_ve(struct pt_regs *regs) { … } void tdx_get_ve_info(struct ve_info *ve) { … } /* * Handle the user initiated #VE. * * On success, returns the number of bytes RIP should be incremented (>=0) * or -errno on error. */ static int virt_exception_user(struct pt_regs *regs, struct ve_info *ve) { … } static inline bool is_private_gpa(u64 gpa) { … } /* * Handle the kernel #VE. * * On success, returns the number of bytes RIP should be incremented (>=0) * or -errno on error. */ static int virt_exception_kernel(struct pt_regs *regs, struct ve_info *ve) { … } bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve) { … } static bool tdx_tlb_flush_required(bool private) { … } static bool tdx_cache_flush_required(void) { … } /* * Notify the VMM about page mapping conversion. More info about ABI * can be found in TDX Guest-Host-Communication Interface (GHCI), * section "TDG.VP.VMCALL<MapGPA>". */ static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc) { … } /* * Inform the VMM of the guest's intent for this physical page: shared with * the VMM or private to the guest. The VMM is expected to change its mapping * of the page in response. */ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) { … } static int tdx_enc_status_change_prepare(unsigned long vaddr, int numpages, bool enc) { … } static int tdx_enc_status_change_finish(unsigned long vaddr, int numpages, bool enc) { … } /* Stop new private<->shared conversions */ static void tdx_kexec_begin(void) { … } /* Walk direct mapping and convert all shared memory back to private */ static void tdx_kexec_finish(void) { … } void __init tdx_early_init(void) { … }