1 | #include <asm/tdx.h> |
2 | #include <asm/pgtable.h> |
3 | |
4 | static unsigned long try_accept_one(phys_addr_t start, unsigned long len, |
5 | enum pg_level pg_level) |
6 | { |
7 | unsigned long accept_size = page_level_size(level: pg_level); |
8 | struct tdx_module_args args = {}; |
9 | u8 page_size; |
10 | |
11 | if (!IS_ALIGNED(start, accept_size)) |
12 | return 0; |
13 | |
14 | if (len < accept_size) |
15 | return 0; |
16 | |
17 | /* |
18 | * Pass the page physical address to the TDX module to accept the |
19 | * pending, private page. |
20 | * |
21 | * Bits 2:0 of RCX encode page size: 0 - 4K, 1 - 2M, 2 - 1G. |
22 | */ |
23 | switch (pg_level) { |
24 | case PG_LEVEL_4K: |
25 | page_size = TDX_PS_4K; |
26 | break; |
27 | case PG_LEVEL_2M: |
28 | page_size = TDX_PS_2M; |
29 | break; |
30 | case PG_LEVEL_1G: |
31 | page_size = TDX_PS_1G; |
32 | break; |
33 | default: |
34 | return 0; |
35 | } |
36 | |
37 | args.rcx = start | page_size; |
38 | if (__tdcall(TDG_MEM_PAGE_ACCEPT, args: &args)) |
39 | return 0; |
40 | |
41 | return accept_size; |
42 | } |
43 | |
44 | bool tdx_accept_memory(phys_addr_t start, phys_addr_t end) |
45 | { |
46 | /* |
47 | * For shared->private conversion, accept the page using |
48 | * TDG_MEM_PAGE_ACCEPT TDX module call. |
49 | */ |
50 | while (start < end) { |
51 | unsigned long len = end - start; |
52 | unsigned long accept_size; |
53 | |
54 | /* |
55 | * Try larger accepts first. It gives chance to VMM to keep |
56 | * 1G/2M Secure EPT entries where possible and speeds up |
57 | * process by cutting number of hypercalls (if successful). |
58 | */ |
59 | |
60 | accept_size = try_accept_one(start, len, pg_level: PG_LEVEL_1G); |
61 | if (!accept_size) |
62 | accept_size = try_accept_one(start, len, pg_level: PG_LEVEL_2M); |
63 | if (!accept_size) |
64 | accept_size = try_accept_one(start, len, pg_level: PG_LEVEL_4K); |
65 | if (!accept_size) |
66 | return false; |
67 | start += accept_size; |
68 | } |
69 | |
70 | return true; |
71 | } |
72 | |
73 | noinstr u64 __tdx_hypercall(struct tdx_module_args *args) |
74 | { |
75 | /* |
76 | * For TDVMCALL explicitly set RCX to the bitmap of shared registers. |
77 | * The caller isn't expected to set @args->rcx anyway. |
78 | */ |
79 | args->rcx = TDVMCALL_EXPOSE_REGS_MASK; |
80 | |
81 | /* |
82 | * Failure of __tdcall_saved_ret() indicates a failure of the TDVMCALL |
83 | * mechanism itself and that something has gone horribly wrong with |
84 | * the TDX module. __tdx_hypercall_failed() never returns. |
85 | */ |
86 | if (__tdcall_saved_ret(TDG_VP_VMCALL, args)) |
87 | __tdx_hypercall_failed(); |
88 | |
89 | /* TDVMCALL leaf return code is in R10 */ |
90 | return args->r10; |
91 | } |
92 | |