162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci#ifndef _ASM_X86_GSSEG_H
362306a36Sopenharmony_ci#define _ASM_X86_GSSEG_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/types.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/asm.h>
862306a36Sopenharmony_ci#include <asm/cpufeature.h>
962306a36Sopenharmony_ci#include <asm/alternative.h>
1062306a36Sopenharmony_ci#include <asm/processor.h>
1162306a36Sopenharmony_ci#include <asm/nops.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifdef CONFIG_X86_64
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciextern asmlinkage void asm_load_gs_index(u16 selector);
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Replace with "lkgs %di" once binutils support LKGS instruction */
1862306a36Sopenharmony_ci#define LKGS_DI _ASM_BYTES(0xf2,0x0f,0x00,0xf7)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic inline void native_lkgs(unsigned int selector)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	u16 sel = selector;
2362306a36Sopenharmony_ci	asm_inline volatile("1: " LKGS_DI
2462306a36Sopenharmony_ci			    _ASM_EXTABLE_TYPE_REG(1b, 1b, EX_TYPE_ZERO_REG, %k[sel])
2562306a36Sopenharmony_ci			    : [sel] "+D" (sel));
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic inline void native_load_gs_index(unsigned int selector)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	if (cpu_feature_enabled(X86_FEATURE_LKGS)) {
3162306a36Sopenharmony_ci		native_lkgs(selector);
3262306a36Sopenharmony_ci	} else {
3362306a36Sopenharmony_ci		unsigned long flags;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci		local_irq_save(flags);
3662306a36Sopenharmony_ci		asm_load_gs_index(selector);
3762306a36Sopenharmony_ci		local_irq_restore(flags);
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#endif /* CONFIG_X86_64 */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic inline void __init lkgs_init(void)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
4662306a36Sopenharmony_ci#ifdef CONFIG_X86_64
4762306a36Sopenharmony_ci	if (cpu_feature_enabled(X86_FEATURE_LKGS))
4862306a36Sopenharmony_ci		pv_ops.cpu.load_gs_index = native_lkgs;
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci#endif
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#ifndef CONFIG_PARAVIRT_XXL
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline void load_gs_index(unsigned int selector)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci#ifdef CONFIG_X86_64
5862306a36Sopenharmony_ci	native_load_gs_index(selector);
5962306a36Sopenharmony_ci#else
6062306a36Sopenharmony_ci	loadsegment(gs, selector);
6162306a36Sopenharmony_ci#endif
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#endif /* CONFIG_PARAVIRT_XXL */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#endif /* _ASM_X86_GSSEG_H */
67