| #include <asm/tdx.h> |
| #include <asm/pgtable.h> |
| |
| static unsigned long try_accept_one(phys_addr_t start, unsigned long len, |
| enum pg_level pg_level) |
| { |
| unsigned long accept_size = page_level_size(pg_level); |
| u64 tdcall_rcx; |
| u8 page_size; |
| |
| if (!IS_ALIGNED(start, accept_size)) |
| return 0; |
| |
| if (len < accept_size) |
| return 0; |
| |
| /* |
| * Pass the page physical address to the TDX module to accept the |
| * pending, private page. |
| * |
| * Bits 2:0 of RCX encode page size: 0 - 4K, 1 - 2M, 2 - 1G. |
| */ |
| switch (pg_level) { |
| case PG_LEVEL_4K: |
| page_size = 0; |
| break; |
| case PG_LEVEL_2M: |
| page_size = 1; |
| break; |
| case PG_LEVEL_1G: |
| page_size = 2; |
| break; |
| default: |
| return 0; |
| } |
| |
| tdcall_rcx = start | page_size; |
| if (__tdx_module_call(TDX_ACCEPT_PAGE, tdcall_rcx, 0, 0, 0, NULL)) |
| return 0; |
| |
| return accept_size; |
| } |
| |
| bool tdx_accept_memory(phys_addr_t start, phys_addr_t end) |
| { |
| /* |
| * For shared->private conversion, accept the page using |
| * TDX_ACCEPT_PAGE TDX module call. |
| */ |
| while (start < end) { |
| unsigned long len = end - start; |
| unsigned long accept_size; |
| |
| /* |
| * Try larger accepts first. It gives chance to VMM to keep |
| * 1G/2M Secure EPT entries where possible and speeds up |
| * process by cutting number of hypercalls (if successful). |
| */ |
| |
| accept_size = try_accept_one(start, len, PG_LEVEL_1G); |
| if (!accept_size) |
| accept_size = try_accept_one(start, len, PG_LEVEL_2M); |
| if (!accept_size) |
| accept_size = try_accept_one(start, len, PG_LEVEL_4K); |
| if (!accept_size) |
| return false; |
| start += accept_size; |
| } |
| |
| return true; |
| } |