@@ -48,6 +48,10 @@ struct vcpu_tdx {
48
48
enum vcpu_tdx_state state ;
49
49
};
50
50
51
+ void tdh_vp_rd_failed (struct vcpu_tdx * tdx , char * uclass , u32 field , u64 err );
52
+ void tdh_vp_wr_failed (struct vcpu_tdx * tdx , char * uclass , char * op , u32 field ,
53
+ u64 val , u64 err );
54
+
51
55
static inline bool is_td (struct kvm * kvm )
52
56
{
53
57
return kvm -> arch .vm_type == KVM_X86_TDX_VM ;
@@ -69,6 +73,90 @@ static __always_inline u64 td_tdcs_exec_read64(struct kvm_tdx *kvm_tdx, u32 fiel
69
73
}
70
74
return data ;
71
75
}
76
+
77
+ static __always_inline void tdvps_vmcs_check (u32 field , u8 bits )
78
+ {
79
+ #define VMCS_ENC_ACCESS_TYPE_MASK 0x1UL
80
+ #define VMCS_ENC_ACCESS_TYPE_FULL 0x0UL
81
+ #define VMCS_ENC_ACCESS_TYPE_HIGH 0x1UL
82
+ #define VMCS_ENC_ACCESS_TYPE (field ) ((field) & VMCS_ENC_ACCESS_TYPE_MASK)
83
+
84
+ /* TDX is 64bit only. HIGH field isn't supported. */
85
+ BUILD_BUG_ON_MSG (__builtin_constant_p (field ) &&
86
+ VMCS_ENC_ACCESS_TYPE (field ) == VMCS_ENC_ACCESS_TYPE_HIGH ,
87
+ "Read/Write to TD VMCS *_HIGH fields not supported" );
88
+
89
+ BUILD_BUG_ON (bits != 16 && bits != 32 && bits != 64 );
90
+
91
+ #define VMCS_ENC_WIDTH_MASK GENMASK(14, 13)
92
+ #define VMCS_ENC_WIDTH_16BIT (0UL << 13)
93
+ #define VMCS_ENC_WIDTH_64BIT (1UL << 13)
94
+ #define VMCS_ENC_WIDTH_32BIT (2UL << 13)
95
+ #define VMCS_ENC_WIDTH_NATURAL (3UL << 13)
96
+ #define VMCS_ENC_WIDTH (field ) ((field) & VMCS_ENC_WIDTH_MASK)
97
+
98
+ /* TDX is 64bit only. i.e. natural width = 64bit. */
99
+ BUILD_BUG_ON_MSG (bits != 64 && __builtin_constant_p (field ) &&
100
+ (VMCS_ENC_WIDTH (field ) == VMCS_ENC_WIDTH_64BIT ||
101
+ VMCS_ENC_WIDTH (field ) == VMCS_ENC_WIDTH_NATURAL ),
102
+ "Invalid TD VMCS access for 64-bit field" );
103
+ BUILD_BUG_ON_MSG (bits != 32 && __builtin_constant_p (field ) &&
104
+ VMCS_ENC_WIDTH (field ) == VMCS_ENC_WIDTH_32BIT ,
105
+ "Invalid TD VMCS access for 32-bit field" );
106
+ BUILD_BUG_ON_MSG (bits != 16 && __builtin_constant_p (field ) &&
107
+ VMCS_ENC_WIDTH (field ) == VMCS_ENC_WIDTH_16BIT ,
108
+ "Invalid TD VMCS access for 16-bit field" );
109
+ }
110
+
111
+ #define TDX_BUILD_TDVPS_ACCESSORS (bits , uclass , lclass ) \
112
+ static __always_inline u##bits td_##lclass##_read##bits(struct vcpu_tdx *tdx, \
113
+ u32 field) \
114
+ { \
115
+ u64 err, data; \
116
+ \
117
+ tdvps_##lclass##_check(field, bits); \
118
+ err = tdh_vp_rd(&tdx->vp, TDVPS_##uclass(field), &data); \
119
+ if (unlikely(err)) { \
120
+ tdh_vp_rd_failed(tdx, #uclass, field, err); \
121
+ return 0; \
122
+ } \
123
+ return (u##bits)data; \
124
+ } \
125
+ static __always_inline void td_##lclass##_write##bits(struct vcpu_tdx *tdx, \
126
+ u32 field, u##bits val) \
127
+ { \
128
+ u64 err; \
129
+ \
130
+ tdvps_##lclass##_check(field, bits); \
131
+ err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), val, \
132
+ GENMASK_ULL(bits - 1, 0)); \
133
+ if (unlikely(err)) \
134
+ tdh_vp_wr_failed(tdx, #uclass, " = ", field, (u64)val, err); \
135
+ } \
136
+ static __always_inline void td_##lclass##_setbit##bits(struct vcpu_tdx *tdx, \
137
+ u32 field, u64 bit) \
138
+ { \
139
+ u64 err; \
140
+ \
141
+ tdvps_##lclass##_check(field, bits); \
142
+ err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), bit, bit); \
143
+ if (unlikely(err)) \
144
+ tdh_vp_wr_failed(tdx, #uclass, " |= ", field, bit, err); \
145
+ } \
146
+ static __always_inline void td_##lclass##_clearbit##bits(struct vcpu_tdx *tdx, \
147
+ u32 field, u64 bit) \
148
+ { \
149
+ u64 err; \
150
+ \
151
+ tdvps_##lclass##_check(field, bits); \
152
+ err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), 0, bit); \
153
+ if (unlikely(err)) \
154
+ tdh_vp_wr_failed(tdx, #uclass, " &= ~", field, bit, err);\
155
+ }
156
+
157
+ TDX_BUILD_TDVPS_ACCESSORS (16 , VMCS , vmcs );
158
+ TDX_BUILD_TDVPS_ACCESSORS (32 , VMCS , vmcs );
159
+ TDX_BUILD_TDVPS_ACCESSORS (64 , VMCS , vmcs );
72
160
#else
73
161
static inline int tdx_bringup (void ) { return 0 ; }
74
162
static inline void tdx_cleanup (void ) {}
0 commit comments