2022-04-06 02:29:21 +03:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
#include "../cpuflags.h"
|
|
|
|
#include "../string.h"
|
2022-04-06 02:29:25 +03:00
|
|
|
#include "../io.h"
|
|
|
|
#include "error.h"
|
|
|
|
|
|
|
|
#include <vdso/limits.h>
|
|
|
|
#include <uapi/asm/vmx.h>
|
2022-04-06 02:29:21 +03:00
|
|
|
|
|
|
|
#include <asm/shared/tdx.h>
|
|
|
|
|
2022-04-06 02:29:25 +03:00
|
|
|
/* Called from __tdx_hypercall() for unrecoverable failure */
|
|
|
|
void __tdx_hypercall_failed(void)
|
|
|
|
{
|
|
|
|
error("TDVMCALL failed. TDX module bug?");
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int tdx_io_in(int size, u16 port)
|
|
|
|
{
|
2023-08-15 23:02:03 +12:00
|
|
|
struct tdx_module_args args = {
|
2022-04-06 02:29:25 +03:00
|
|
|
.r10 = TDX_HYPERCALL_STANDARD,
|
2023-05-05 15:03:32 +03:00
|
|
|
.r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION),
|
2022-04-06 02:29:25 +03:00
|
|
|
.r12 = size,
|
|
|
|
.r13 = 0,
|
|
|
|
.r14 = port,
|
|
|
|
};
|
|
|
|
|
x86/tdx: Make TDX_HYPERCALL asm similar to TDX_MODULE_CALL
Now the 'struct tdx_hypercall_args' and 'struct tdx_module_args' are
almost the same, and the TDX_HYPERCALL and TDX_MODULE_CALL asm macro
share similar code pattern too. The __tdx_hypercall() and __tdcall()
should be unified to use the same assembly code.
As a preparation to unify them, simplify the TDX_HYPERCALL to make it
more like the TDX_MODULE_CALL.
The TDX_HYPERCALL takes the pointer of 'struct tdx_hypercall_args' as
function call argument, and does below extra things comparing to the
TDX_MODULE_CALL:
1) It sets RAX to 0 (TDG.VP.VMCALL leaf) internally;
2) It sets RCX to the (fixed) bitmap of shared registers internally;
3) It calls __tdx_hypercall_failed() internally (and panics) when the
TDCALL instruction itself fails;
4) After TDCALL, it moves R10 to RAX to return the return code of the
VMCALL leaf, regardless the '\ret' asm macro argument;
Firstly, change the TDX_HYPERCALL to take the same function call
arguments as the TDX_MODULE_CALL does: TDCALL leaf ID, and the pointer
to 'struct tdx_module_args'. Then 1) and 2) can be moved to the
caller:
- TDG.VP.VMCALL leaf ID can be passed via the function call argument;
- 'struct tdx_module_args' is 'struct tdx_hypercall_args' + RCX, thus
the bitmap of shared registers can be passed via RCX in the
structure.
Secondly, to move 3) and 4) out of assembly, make the TDX_HYPERCALL
always save output registers to the structure. The caller then can:
- Call __tdx_hypercall_failed() when TDX_HYPERCALL returns error;
- Return R10 in the structure as the return code of the VMCALL leaf;
With above changes, change the asm function from __tdx_hypercall() to
__tdcall_hypercall(), and reimplement __tdx_hypercall() as the C wrapper
of it. This avoids having to add another wrapper of __tdx_hypercall()
(_tdx_hypercall() is already taken).
The __tdcall_hypercall() will be replaced with a __tdcall() variant
using TDX_MODULE_CALL in a later commit as the final goal is to have one
assembly to handle both TDCALL and TDVMCALL.
Currently, the __tdx_hypercall() asm is in '.noinstr.text'. To keep
this unchanged, annotate __tdx_hypercall(), which is a C function now,
as 'noinstr'.
Remove the __tdx_hypercall_ret() as __tdx_hypercall() already does so.
Implement __tdx_hypercall() in tdx-shared.c so it can be shared with the
compressed code.
Opportunistically fix a checkpatch error complaining using space around
parenthesis '(' and ')' while moving the bitmap of shared registers to
<asm/shared/tdx.h>.
[ dhansen: quash new calls of __tdx_hypercall_ret() that showed up ]
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Kai Huang <kai.huang@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/0cbf25e7aee3256288045023a31f65f0cef90af4.1692096753.git.kai.huang%40intel.com
2023-08-15 23:02:01 +12:00
|
|
|
if (__tdx_hypercall(&args))
|
2022-04-06 02:29:25 +03:00
|
|
|
return UINT_MAX;
|
|
|
|
|
|
|
|
return args.r11;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void tdx_io_out(int size, u16 port, u32 value)
|
|
|
|
{
|
2023-08-15 23:02:03 +12:00
|
|
|
struct tdx_module_args args = {
|
2022-04-06 02:29:25 +03:00
|
|
|
.r10 = TDX_HYPERCALL_STANDARD,
|
2023-05-05 15:03:32 +03:00
|
|
|
.r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION),
|
2022-04-06 02:29:25 +03:00
|
|
|
.r12 = size,
|
|
|
|
.r13 = 1,
|
|
|
|
.r14 = port,
|
|
|
|
.r15 = value,
|
|
|
|
};
|
|
|
|
|
2023-03-21 03:35:11 +03:00
|
|
|
__tdx_hypercall(&args);
|
2022-04-06 02:29:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 tdx_inb(u16 port)
|
|
|
|
{
|
|
|
|
return tdx_io_in(1, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void tdx_outb(u8 value, u16 port)
|
|
|
|
{
|
|
|
|
tdx_io_out(1, port, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void tdx_outw(u16 value, u16 port)
|
|
|
|
{
|
|
|
|
tdx_io_out(2, port, value);
|
|
|
|
}
|
|
|
|
|
2022-04-06 02:29:21 +03:00
|
|
|
void early_tdx_detect(void)
|
|
|
|
{
|
|
|
|
u32 eax, sig[3];
|
|
|
|
|
|
|
|
cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax, &sig[0], &sig[2], &sig[1]);
|
|
|
|
|
|
|
|
if (memcmp(TDX_IDENT, sig, sizeof(sig)))
|
|
|
|
return;
|
2022-04-06 02:29:25 +03:00
|
|
|
|
|
|
|
/* Use hypercalls instead of I/O instructions */
|
|
|
|
pio_ops.f_inb = tdx_inb;
|
|
|
|
pio_ops.f_outb = tdx_outb;
|
|
|
|
pio_ops.f_outw = tdx_outw;
|
2022-04-06 02:29:21 +03:00
|
|
|
}
|