Skip to content

Commit 69f6ed1

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/fpu: Provide infrastructure for KVM FPU cleanup
For the upcoming AMX support it's necessary to do a proper integration with KVM. Currently KVM allocates two FPU structs which are used for saving the user state of the vCPU thread and restoring the guest state when entering vcpu_run() and doing the reverse operation before leaving vcpu_run(). With the new fpstate mechanism this can be reduced to one extra buffer by swapping the fpstate pointer in current::thread::fpu. This makes the upcoming support for AMX and XFD simpler because then fpstate information (features, sizes, xfd) are always consistent and it does not require any nasty workarounds. Provide: - An allocator which initializes the state properly - A replacement for the existing FPU swap mechanim Aside of the reduced memory footprint, this also makes state switching more efficient when TIF_FPU_NEED_LOAD is set. It does not require a memcpy as the state is already correct in the to be swapped out fpstate. The existing interfaces will be removed once KVM is converted over. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 75c52da commit 69f6ed1

File tree

2 files changed

+92
-6
lines changed

2 files changed

+92
-6
lines changed

arch/x86/include/asm/fpu/api.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,22 @@ extern void fpu_init_fpstate_user(struct fpu *fpu);
135135
extern void fpstate_clear_xstate_component(struct fpstate *fps, unsigned int xfeature);
136136

137137
/* KVM specific functions */
138+
extern bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu);
139+
extern void fpu_free_guest_fpstate(struct fpu_guest *gfpu);
140+
extern int fpu_swap_kvm_fpstate(struct fpu_guest *gfpu, bool enter_guest);
138141
extern void fpu_swap_kvm_fpu(struct fpu *save, struct fpu *rstor, u64 restore_mask);
139142

140143
extern int fpu_copy_kvm_uabi_to_fpstate(struct fpu *fpu, const void *buf, u64 xcr0, u32 *pkru);
141144
extern void fpu_copy_fpstate_to_kvm_uabi(struct fpu *fpu, void *buf, unsigned int size, u32 pkru);
142145

146+
static inline void fpstate_set_confidential(struct fpu_guest *gfpu)
147+
{
148+
gfpu->fpstate->is_confidential = true;
149+
}
150+
151+
static inline bool fpstate_is_confidential(struct fpu_guest *gfpu)
152+
{
153+
return gfpu->fpstate->is_confidential;
154+
}
155+
143156
#endif /* _ASM_X86_FPU_API_H */

arch/x86/kernel/fpu/core.c

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,75 @@ void fpu_reset_from_exception_fixup(void)
176176
}
177177

178178
#if IS_ENABLED(CONFIG_KVM)
179+
static void __fpstate_reset(struct fpstate *fpstate);
180+
181+
bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
182+
{
183+
struct fpstate *fpstate;
184+
unsigned int size;
185+
186+
size = fpu_user_cfg.default_size + ALIGN(offsetof(struct fpstate, regs), 64);
187+
fpstate = vzalloc(size);
188+
if (!fpstate)
189+
return false;
190+
191+
__fpstate_reset(fpstate);
192+
fpstate_init_user(fpstate);
193+
fpstate->is_valloc = true;
194+
fpstate->is_guest = true;
195+
196+
gfpu->fpstate = fpstate;
197+
return true;
198+
}
199+
EXPORT_SYMBOL_GPL(fpu_alloc_guest_fpstate);
200+
201+
void fpu_free_guest_fpstate(struct fpu_guest *gfpu)
202+
{
203+
struct fpstate *fps = gfpu->fpstate;
204+
205+
if (!fps)
206+
return;
207+
208+
if (WARN_ON_ONCE(!fps->is_valloc || !fps->is_guest || fps->in_use))
209+
return;
210+
211+
gfpu->fpstate = NULL;
212+
vfree(fps);
213+
}
214+
EXPORT_SYMBOL_GPL(fpu_free_guest_fpstate);
215+
216+
int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest)
217+
{
218+
struct fpstate *guest_fps = guest_fpu->fpstate;
219+
struct fpu *fpu = &current->thread.fpu;
220+
struct fpstate *cur_fps = fpu->fpstate;
221+
222+
fpregs_lock();
223+
if (!cur_fps->is_confidential && !test_thread_flag(TIF_NEED_FPU_LOAD))
224+
save_fpregs_to_fpstate(fpu);
225+
226+
/* Swap fpstate */
227+
if (enter_guest) {
228+
fpu->__task_fpstate = cur_fps;
229+
fpu->fpstate = guest_fps;
230+
guest_fps->in_use = true;
231+
} else {
232+
guest_fps->in_use = false;
233+
fpu->fpstate = fpu->__task_fpstate;
234+
fpu->__task_fpstate = NULL;
235+
}
236+
237+
cur_fps = fpu->fpstate;
238+
239+
if (!cur_fps->is_confidential)
240+
restore_fpregs_from_fpstate(cur_fps, XFEATURE_MASK_FPSTATE);
241+
242+
fpregs_mark_activate();
243+
fpregs_unlock();
244+
return 0;
245+
}
246+
EXPORT_SYMBOL_GPL(fpu_swap_kvm_fpstate);
247+
179248
void fpu_swap_kvm_fpu(struct fpu *save, struct fpu *rstor, u64 restore_mask)
180249
{
181250
fpregs_lock();
@@ -352,16 +421,20 @@ void fpstate_init_user(struct fpstate *fpstate)
352421
fpstate_init_fstate(fpstate);
353422
}
354423

424+
static void __fpstate_reset(struct fpstate *fpstate)
425+
{
426+
/* Initialize sizes and feature masks */
427+
fpstate->size = fpu_kernel_cfg.default_size;
428+
fpstate->user_size = fpu_user_cfg.default_size;
429+
fpstate->xfeatures = fpu_kernel_cfg.default_features;
430+
fpstate->user_xfeatures = fpu_user_cfg.default_features;
431+
}
432+
355433
void fpstate_reset(struct fpu *fpu)
356434
{
357435
/* Set the fpstate pointer to the default fpstate */
358436
fpu->fpstate = &fpu->__fpstate;
359-
360-
/* Initialize sizes and feature masks */
361-
fpu->fpstate->size = fpu_kernel_cfg.default_size;
362-
fpu->fpstate->user_size = fpu_user_cfg.default_size;
363-
fpu->fpstate->xfeatures = fpu_kernel_cfg.default_features;
364-
fpu->fpstate->user_xfeatures = fpu_user_cfg.default_features;
437+
__fpstate_reset(fpu->fpstate);
365438
}
366439

367440
#if IS_ENABLED(CONFIG_KVM)

0 commit comments

Comments
 (0)