162306a36Sopenharmony_ci#include <asm/tdx.h>
262306a36Sopenharmony_ci#include <asm/pgtable.h>
362306a36Sopenharmony_ci
462306a36Sopenharmony_cistatic unsigned long try_accept_one(phys_addr_t start, unsigned long len,
562306a36Sopenharmony_ci				    enum pg_level pg_level)
662306a36Sopenharmony_ci{
762306a36Sopenharmony_ci	unsigned long accept_size = page_level_size(pg_level);
862306a36Sopenharmony_ci	u64 tdcall_rcx;
962306a36Sopenharmony_ci	u8 page_size;
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci	if (!IS_ALIGNED(start, accept_size))
1262306a36Sopenharmony_ci		return 0;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	if (len < accept_size)
1562306a36Sopenharmony_ci		return 0;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	/*
1862306a36Sopenharmony_ci	 * Pass the page physical address to the TDX module to accept the
1962306a36Sopenharmony_ci	 * pending, private page.
2062306a36Sopenharmony_ci	 *
2162306a36Sopenharmony_ci	 * Bits 2:0 of RCX encode page size: 0 - 4K, 1 - 2M, 2 - 1G.
2262306a36Sopenharmony_ci	 */
2362306a36Sopenharmony_ci	switch (pg_level) {
2462306a36Sopenharmony_ci	case PG_LEVEL_4K:
2562306a36Sopenharmony_ci		page_size = 0;
2662306a36Sopenharmony_ci		break;
2762306a36Sopenharmony_ci	case PG_LEVEL_2M:
2862306a36Sopenharmony_ci		page_size = 1;
2962306a36Sopenharmony_ci		break;
3062306a36Sopenharmony_ci	case PG_LEVEL_1G:
3162306a36Sopenharmony_ci		page_size = 2;
3262306a36Sopenharmony_ci		break;
3362306a36Sopenharmony_ci	default:
3462306a36Sopenharmony_ci		return 0;
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	tdcall_rcx = start | page_size;
3862306a36Sopenharmony_ci	if (__tdx_module_call(TDX_ACCEPT_PAGE, tdcall_rcx, 0, 0, 0, NULL))
3962306a36Sopenharmony_ci		return 0;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	return accept_size;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cibool tdx_accept_memory(phys_addr_t start, phys_addr_t end)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	/*
4762306a36Sopenharmony_ci	 * For shared->private conversion, accept the page using
4862306a36Sopenharmony_ci	 * TDX_ACCEPT_PAGE TDX module call.
4962306a36Sopenharmony_ci	 */
5062306a36Sopenharmony_ci	while (start < end) {
5162306a36Sopenharmony_ci		unsigned long len = end - start;
5262306a36Sopenharmony_ci		unsigned long accept_size;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		/*
5562306a36Sopenharmony_ci		 * Try larger accepts first. It gives chance to VMM to keep
5662306a36Sopenharmony_ci		 * 1G/2M Secure EPT entries where possible and speeds up
5762306a36Sopenharmony_ci		 * process by cutting number of hypercalls (if successful).
5862306a36Sopenharmony_ci		 */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		accept_size = try_accept_one(start, len, PG_LEVEL_1G);
6162306a36Sopenharmony_ci		if (!accept_size)
6262306a36Sopenharmony_ci			accept_size = try_accept_one(start, len, PG_LEVEL_2M);
6362306a36Sopenharmony_ci		if (!accept_size)
6462306a36Sopenharmony_ci			accept_size = try_accept_one(start, len, PG_LEVEL_4K);
6562306a36Sopenharmony_ci		if (!accept_size)
6662306a36Sopenharmony_ci			return false;
6762306a36Sopenharmony_ci		start += accept_size;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return true;
7162306a36Sopenharmony_ci}
72