Skip to content

Commit e414b10

Browse files
kaihuanghansendc
authored andcommitted
x86/virt/tdx: Use precalculated TDVPR page physical address
All of the x86 KVM guest types (VMX, SEV and TDX) do some special context tracking when entering guests. This means that the actual guest entry sequence must be noinstr. Part of entering a TDX guest is passing a physical address to the TDX module. Right now, that physical address is stored as a 'struct page' and converted to a physical address at guest entry. That page=>phys conversion can be complicated, can vary greatly based on kernel config, and it is definitely _not_ a noinstr path today. There have been a number of tinkering approaches to try and fix this up, but they all fall down due to some part of the page=>phys conversion infrastructure not being noinstr friendly. Precalculate the page=>phys conversion and store it in the existing 'tdx_vp' structure. Use the new field at every site that needs a tdvpr physical address. Remove the now redundant tdx_tdvpr_pa(). Remove the __flatten remnant from the tinkering. Note that only one user of the new field is actually noinstr. All others can use page_to_phys(). But, they might as well save the effort since there is a pre-calculated value sitting there for them. [ dhansen: rewrite all the text ] Signed-off-by: Kai Huang <kai.huang@intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Kiryl Shutsemau <kas@kernel.org> Tested-by: Farrah Chen <farrah.chen@intel.com>
1 parent 61221d0 commit e414b10

3 files changed

Lines changed: 19 additions & 13 deletions

File tree

arch/x86/include/asm/tdx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ struct tdx_td {
171171
struct tdx_vp {
172172
/* TDVP root page */
173173
struct page *tdvpr_page;
174+
/* precalculated page_to_phys(tdvpr_page) for use in noinstr code */
175+
phys_addr_t tdvpr_pa;
174176

175177
/* TD vCPU control structure: */
176178
struct page **tdcx_pages;

arch/x86/kvm/vmx/tdx.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,7 @@ void tdx_vcpu_free(struct kvm_vcpu *vcpu)
852852
if (tdx->vp.tdvpr_page) {
853853
tdx_reclaim_control_page(tdx->vp.tdvpr_page);
854854
tdx->vp.tdvpr_page = 0;
855+
tdx->vp.tdvpr_pa = 0;
855856
}
856857

857858
tdx->state = VCPU_TD_STATE_UNINITIALIZED;
@@ -2931,6 +2932,13 @@ static int tdx_td_vcpu_init(struct kvm_vcpu *vcpu, u64 vcpu_rcx)
29312932
return -ENOMEM;
29322933
tdx->vp.tdvpr_page = page;
29332934

2935+
/*
2936+
* page_to_phys() does not work in 'noinstr' code, like guest
2937+
* entry via tdh_vp_enter(). Precalculate and store it instead
2938+
* of doing it at runtime later.
2939+
*/
2940+
tdx->vp.tdvpr_pa = page_to_phys(tdx->vp.tdvpr_page);
2941+
29342942
tdx->vp.tdcx_pages = kcalloc(kvm_tdx->td.tdcx_nr_pages, sizeof(*tdx->vp.tdcx_pages),
29352943
GFP_KERNEL);
29362944
if (!tdx->vp.tdcx_pages) {
@@ -2993,6 +3001,7 @@ static int tdx_td_vcpu_init(struct kvm_vcpu *vcpu, u64 vcpu_rcx)
29933001
if (tdx->vp.tdvpr_page)
29943002
__free_page(tdx->vp.tdvpr_page);
29953003
tdx->vp.tdvpr_page = 0;
3004+
tdx->vp.tdvpr_pa = 0;
29963005

29973006
return ret;
29983007
}

arch/x86/virt/vmx/tdx/tdx.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,11 +1504,6 @@ static inline u64 tdx_tdr_pa(struct tdx_td *td)
15041504
return page_to_phys(td->tdr_page);
15051505
}
15061506

1507-
static inline u64 tdx_tdvpr_pa(struct tdx_vp *td)
1508-
{
1509-
return page_to_phys(td->tdvpr_page);
1510-
}
1511-
15121507
/*
15131508
* The TDX module exposes a CLFLUSH_BEFORE_ALLOC bit to specify whether
15141509
* a CLFLUSH of pages is required before handing them to the TDX module.
@@ -1520,9 +1515,9 @@ static void tdx_clflush_page(struct page *page)
15201515
clflush_cache_range(page_to_virt(page), PAGE_SIZE);
15211516
}
15221517

1523-
noinstr __flatten u64 tdh_vp_enter(struct tdx_vp *td, struct tdx_module_args *args)
1518+
noinstr u64 tdh_vp_enter(struct tdx_vp *td, struct tdx_module_args *args)
15241519
{
1525-
args->rcx = tdx_tdvpr_pa(td);
1520+
args->rcx = td->tdvpr_pa;
15261521

15271522
return __seamcall_dirty_cache(__seamcall_saved_ret, TDH_VP_ENTER, args);
15281523
}
@@ -1583,7 +1578,7 @@ u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page)
15831578
{
15841579
struct tdx_module_args args = {
15851580
.rcx = page_to_phys(tdcx_page),
1586-
.rdx = tdx_tdvpr_pa(vp),
1581+
.rdx = vp->tdvpr_pa,
15871582
};
15881583

15891584
tdx_clflush_page(tdcx_page);
@@ -1652,7 +1647,7 @@ EXPORT_SYMBOL_GPL(tdh_mng_create);
16521647
u64 tdh_vp_create(struct tdx_td *td, struct tdx_vp *vp)
16531648
{
16541649
struct tdx_module_args args = {
1655-
.rcx = tdx_tdvpr_pa(vp),
1650+
.rcx = vp->tdvpr_pa,
16561651
.rdx = tdx_tdr_pa(td),
16571652
};
16581653

@@ -1708,7 +1703,7 @@ EXPORT_SYMBOL_GPL(tdh_mr_finalize);
17081703
u64 tdh_vp_flush(struct tdx_vp *vp)
17091704
{
17101705
struct tdx_module_args args = {
1711-
.rcx = tdx_tdvpr_pa(vp),
1706+
.rcx = vp->tdvpr_pa,
17121707
};
17131708

17141709
return seamcall(TDH_VP_FLUSH, &args);
@@ -1754,7 +1749,7 @@ EXPORT_SYMBOL_GPL(tdh_mng_init);
17541749
u64 tdh_vp_rd(struct tdx_vp *vp, u64 field, u64 *data)
17551750
{
17561751
struct tdx_module_args args = {
1757-
.rcx = tdx_tdvpr_pa(vp),
1752+
.rcx = vp->tdvpr_pa,
17581753
.rdx = field,
17591754
};
17601755
u64 ret;
@@ -1771,7 +1766,7 @@ EXPORT_SYMBOL_GPL(tdh_vp_rd);
17711766
u64 tdh_vp_wr(struct tdx_vp *vp, u64 field, u64 data, u64 mask)
17721767
{
17731768
struct tdx_module_args args = {
1774-
.rcx = tdx_tdvpr_pa(vp),
1769+
.rcx = vp->tdvpr_pa,
17751770
.rdx = field,
17761771
.r8 = data,
17771772
.r9 = mask,
@@ -1784,7 +1779,7 @@ EXPORT_SYMBOL_GPL(tdh_vp_wr);
17841779
u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid)
17851780
{
17861781
struct tdx_module_args args = {
1787-
.rcx = tdx_tdvpr_pa(vp),
1782+
.rcx = vp->tdvpr_pa,
17881783
.rdx = initial_rcx,
17891784
.r8 = x2apicid,
17901785
};

0 commit comments

Comments
 (0)