Commit bd3c5798 authored by Qi Hu's avatar Qi Hu Committed by Huacai Chen
Browse files

LoongArch: Add Loongson Binary Translation (LBT) extension support



Loongson Binary Translation (LBT) is used to accelerate binary translation,
which contains 4 scratch registers (scr0 to scr3), x86/ARM eflags (eflags)
and x87 fpu stack pointer (ftop).

This patch support kernel to save/restore these registers, handle the LBT
exception and maintain sigcontext.

Signed-off-by: default avatarQi Hu <huqi@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent f2091321
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -254,6 +254,9 @@ config AS_HAS_LSX_EXTENSION
config AS_HAS_LASX_EXTENSION
	def_bool $(as-instr,xvld \$xr0$(comma)\$a0$(comma)0)

config AS_HAS_LBT_EXTENSION
	def_bool $(as-instr,movscr2gr \$a0$(comma)\$scr0)

menu "Kernel type and options"

source "kernel/Kconfig.hz"
@@ -534,6 +537,18 @@ config CPU_HAS_LASX

	  If unsure, say Y.

config CPU_HAS_LBT
	bool "Support for the Loongson Binary Translation Extension"
	depends on AS_HAS_LBT_EXTENSION
	help
	  Loongson Binary Translation (LBT) introduces 4 scratch registers (SCR0
	  to SCR3), x86/ARM eflags (eflags) and x87 fpu stack pointer (ftop).
	  Enabling this option allows the kernel to allocate and switch registers
	  specific to LBT.

	  If you want to use this feature, such as the Loongson Architecture
	  Translator (LAT), say Y.

config CPU_HAS_PREFETCH
	bool
	default y
+1 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/uaccess.h>
#include <asm/fpu.h>
#include <asm/lbt.h>
#include <asm/mmu_context.h>
#include <asm/page.h>
#include <asm/ftrace.h>
+45 −6
Original line number Diff line number Diff line
@@ -42,11 +42,50 @@
	.macro fpu_save_csr thread tmp
	movfcsr2gr	\tmp, fcsr0
	stptr.w		\tmp, \thread, THREAD_FCSR
#ifdef CONFIG_CPU_HAS_LBT
	/* TM bit is always 0 if LBT not supported */
	andi		\tmp, \tmp, FPU_CSR_TM
	beqz		\tmp, 1f
	/* Save FTOP */
	x86mftop	\tmp
	stptr.w		\tmp, \thread, THREAD_FTOP
	/* Turn off TM to ensure the order of FPR in memory independent of TM */
	x86clrtm
1:
#endif
	.endm

	.macro fpu_restore_csr thread tmp
	ldptr.w	\tmp, \thread, THREAD_FCSR
	movgr2fcsr	fcsr0, \tmp
	.macro fpu_restore_csr thread tmp0 tmp1
	ldptr.w		\tmp0, \thread, THREAD_FCSR
	movgr2fcsr	fcsr0, \tmp0
#ifdef CONFIG_CPU_HAS_LBT
	/* TM bit is always 0 if LBT not supported */
	andi		\tmp0, \tmp0, FPU_CSR_TM
	beqz		\tmp0, 2f
	/* Restore FTOP */
	ldptr.w		\tmp0, \thread, THREAD_FTOP
	andi		\tmp0, \tmp0, 0x7
	la.pcrel	\tmp1, 1f
	alsl.d		\tmp1, \tmp0, \tmp1, 3
	jr		\tmp1
1:
	x86mttop	0
	b	2f
	x86mttop	1
	b	2f
	x86mttop	2
	b	2f
	x86mttop	3
	b	2f
	x86mttop	4
	b	2f
	x86mttop	5
	b	2f
	x86mttop	6
	b	2f
	x86mttop	7
2:
#endif
	.endm

	.macro fpu_save_cc thread tmp0 tmp1
@@ -246,7 +285,7 @@
	.macro	lsx_restore_all	thread tmp0 tmp1
	lsx_restore_data	\thread, \tmp0
	fpu_restore_cc		\thread, \tmp0, \tmp1
	fpu_restore_csr		\thread, \tmp0
	fpu_restore_csr		\thread, \tmp0, \tmp1
	.endm

	.macro	lsx_save_upper vd base tmp off
@@ -456,7 +495,7 @@
	.macro	lasx_restore_all thread tmp0 tmp1
	lasx_restore_data	\thread, \tmp0
	fpu_restore_cc		\thread, \tmp0, \tmp1
	fpu_restore_csr		\thread, \tmp0
	fpu_restore_csr		\thread, \tmp0, \tmp1
	.endm

	.macro	lasx_save_upper xd base tmp off
+109 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Author: Qi Hu <huqi@loongson.cn>
 *         Huacai Chen <chenhuacai@loongson.cn>
 * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
 */
#ifndef _ASM_LBT_H
#define _ASM_LBT_H

#include <asm/cpu.h>
#include <asm/current.h>
#include <asm/loongarch.h>
#include <asm/processor.h>

extern void _init_lbt(void);
extern void _save_lbt(struct loongarch_lbt *);
extern void _restore_lbt(struct loongarch_lbt *);

static inline int is_lbt_enabled(void)
{
	if (!cpu_has_lbt)
		return 0;

	return (csr_read32(LOONGARCH_CSR_EUEN) & CSR_EUEN_LBTEN) ?
		1 : 0;
}

static inline int is_lbt_owner(void)
{
	return test_thread_flag(TIF_USEDLBT);
}

#ifdef CONFIG_CPU_HAS_LBT

static inline void enable_lbt(void)
{
	if (cpu_has_lbt)
		csr_xchg32(CSR_EUEN_LBTEN, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN);
}

static inline void disable_lbt(void)
{
	if (cpu_has_lbt)
		csr_xchg32(0, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN);
}

static inline void __own_lbt(void)
{
	enable_lbt();
	set_thread_flag(TIF_USEDLBT);
	KSTK_EUEN(current) |= CSR_EUEN_LBTEN;
}

static inline void own_lbt_inatomic(int restore)
{
	if (cpu_has_lbt && !is_lbt_owner()) {
		__own_lbt();
		if (restore)
			_restore_lbt(&current->thread.lbt);
	}
}

static inline void own_lbt(int restore)
{
	preempt_disable();
	own_lbt_inatomic(restore);
	preempt_enable();
}

static inline void lose_lbt_inatomic(int save, struct task_struct *tsk)
{
	if (cpu_has_lbt && is_lbt_owner()) {
		if (save)
			_save_lbt(&tsk->thread.lbt);

		disable_lbt();
		clear_tsk_thread_flag(tsk, TIF_USEDLBT);
	}
	KSTK_EUEN(tsk) &= ~(CSR_EUEN_LBTEN);
}

static inline void lose_lbt(int save)
{
	preempt_disable();
	lose_lbt_inatomic(save, current);
	preempt_enable();
}

static inline void init_lbt(void)
{
	__own_lbt();
	_init_lbt();
}
#else
static inline void own_lbt_inatomic(int restore) {}
static inline void lose_lbt_inatomic(int save, struct task_struct *tsk) {}
static inline void init_lbt(void) {}
static inline void lose_lbt(int save) {}
#endif

static inline int thread_lbt_context_live(void)
{
	if (!cpu_has_lbt)
		return 0;

	return test_thread_flag(TIF_LBT_CTX_LIVE);
}

#endif /* _ASM_LBT_H */
+4 −0
Original line number Diff line number Diff line
@@ -1410,6 +1410,10 @@ __BUILD_CSR_OP(tlbidx)
#define FPU_CSR_RU	0x200	/* towards +Infinity */
#define FPU_CSR_RD	0x300	/* towards -Infinity */

/* Bit 6 of FPU Status Register specify the LBT TOP simulation mode */
#define FPU_CSR_TM_SHIFT	0x6
#define FPU_CSR_TM		(_ULCAST_(1) << FPU_CSR_TM_SHIFT)

#define read_fcsr(source)	\
({	\
	unsigned int __res;	\
Loading