1#include <asm/tdx.h>
2#include <asm/pgtable.h>
3
4static 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(pg_level);
8	u64 tdcall_rcx;
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 = 0;
26		break;
27	case PG_LEVEL_2M:
28		page_size = 1;
29		break;
30	case PG_LEVEL_1G:
31		page_size = 2;
32		break;
33	default:
34		return 0;
35	}
36
37	tdcall_rcx = start | page_size;
38	if (__tdx_module_call(TDX_ACCEPT_PAGE, tdcall_rcx, 0, 0, 0, NULL))
39		return 0;
40
41	return accept_size;
42}
43
44bool tdx_accept_memory(phys_addr_t start, phys_addr_t end)
45{
46	/*
47	 * For shared->private conversion, accept the page using
48	 * TDX_ACCEPT_PAGE 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_1G);
61		if (!accept_size)
62			accept_size = try_accept_one(start, len, PG_LEVEL_2M);
63		if (!accept_size)
64			accept_size = try_accept_one(start, len, PG_LEVEL_4K);
65		if (!accept_size)
66			return false;
67		start += accept_size;
68	}
69
70	return true;
71}
72