1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include "../cpuflags.h" |
4 | #include "../string.h" |
5 | #include "../io.h" |
6 | #include "error.h" |
7 | |
8 | #include <vdso/limits.h> |
9 | #include <uapi/asm/vmx.h> |
10 | |
11 | #include <asm/shared/tdx.h> |
12 | |
13 | /* Called from __tdx_hypercall() for unrecoverable failure */ |
14 | void __tdx_hypercall_failed(void) |
15 | { |
16 | error(m: "TDVMCALL failed. TDX module bug?" ); |
17 | } |
18 | |
19 | static inline unsigned int tdx_io_in(int size, u16 port) |
20 | { |
21 | struct tdx_module_args args = { |
22 | .r10 = TDX_HYPERCALL_STANDARD, |
23 | .r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION), |
24 | .r12 = size, |
25 | .r13 = 0, |
26 | .r14 = port, |
27 | }; |
28 | |
29 | if (__tdx_hypercall(args: &args)) |
30 | return UINT_MAX; |
31 | |
32 | return args.r11; |
33 | } |
34 | |
35 | static inline void tdx_io_out(int size, u16 port, u32 value) |
36 | { |
37 | struct tdx_module_args args = { |
38 | .r10 = TDX_HYPERCALL_STANDARD, |
39 | .r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION), |
40 | .r12 = size, |
41 | .r13 = 1, |
42 | .r14 = port, |
43 | .r15 = value, |
44 | }; |
45 | |
46 | __tdx_hypercall(args: &args); |
47 | } |
48 | |
49 | static inline u8 tdx_inb(u16 port) |
50 | { |
51 | return tdx_io_in(size: 1, port); |
52 | } |
53 | |
54 | static inline void tdx_outb(u8 value, u16 port) |
55 | { |
56 | tdx_io_out(size: 1, port, value); |
57 | } |
58 | |
59 | static inline void tdx_outw(u16 value, u16 port) |
60 | { |
61 | tdx_io_out(size: 2, port, value); |
62 | } |
63 | |
64 | void early_tdx_detect(void) |
65 | { |
66 | u32 eax, sig[3]; |
67 | |
68 | cpuid_count(TDX_CPUID_LEAF_ID, count: 0, a: &eax, b: &sig[0], c: &sig[2], d: &sig[1]); |
69 | |
70 | if (memcmp(TDX_IDENT, sig, sizeof(sig))) |
71 | return; |
72 | |
73 | /* Use hypercalls instead of I/O instructions */ |
74 | pio_ops.f_inb = tdx_inb; |
75 | pio_ops.f_outb = tdx_outb; |
76 | pio_ops.f_outw = tdx_outw; |
77 | } |
78 | |