Unverified Commit 800149a7 authored by Vincent Chen's avatar Vincent Chen Committed by Palmer Dabbelt
Browse files

riscv: sifive: Apply errata "cip-453" patch



Add sign extension to the $badaddr before addressing the instruction page
fault and instruction access fault to workaround the issue "cip-453".

To avoid affecting the existing code sequence, this patch will creates two
trampolines to add sign extension to the $badaddr. By the "alternative"
mechanism, these two trampolines will replace the original exception
handler of instruction page fault and instruction access fault in the
excp_vect_table. In this case, only the specific SiFive CPU core jumps to
the do_page_fault and do_trap_insn_fault through these two trampolines.
Other CPUs are not affected.

Signed-off-by: default avatarVincent Chen <vincent.chen@sifive.com>
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent 1a0e5dbd
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -19,4 +19,15 @@ config ERRATA_SIFIVE

	  Otherwise, please say "N" here to avoid unnecessary overhead.

config ERRATA_SIFIVE_CIP_453
	bool "Apply SiFive errata CIP-453"
	depends on ERRATA_SIFIVE
	default y
	help
	  This will apply the SiFive CIP-453 errata to add sign extension
	  to the $badaddr when exception type is instruction page fault
	  and instruction access fault.

	  If you don't know what to do here, say "Y".

endmenu
+1 −0
Original line number Diff line number Diff line
obj-y += errata_cip_453.o
obj-y += errata.o
+20 −0
Original line number Diff line number Diff line
@@ -16,6 +16,26 @@ struct errata_info_t {
	bool (*check_func)(unsigned long  arch_id, unsigned long impid);
};

static bool errata_cip_453_check_func(unsigned long  arch_id, unsigned long impid)
{
	/*
	 * Affected cores:
	 * Architecture ID: 0x8000000000000007
	 * Implement ID: 0x20181004 <= impid <= 0x20191105
	 */
	if (arch_id != 0x8000000000000007 ||
	    (impid < 0x20181004 || impid > 0x20191105))
		return false;
	return true;
}

static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
	{
		.name = "cip-453",
		.check_func = errata_cip_453_check_func
	},
};

static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
{
	int idx;
+38 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2021 SiFive
 */

#include <linux/linkage.h>
#include <asm/asm.h>
#include <asm/asm-offsets.h>
#include <asm/alternative.h>

.macro ADD_SIGN_EXT pt_reg badaddr tmp_reg
	REG_L \badaddr, PT_BADADDR(\pt_reg)
	li \tmp_reg,1
	slli \tmp_reg,\tmp_reg,0x26
	and \tmp_reg,\tmp_reg,\badaddr
	beqz \tmp_reg, 1f
	li \tmp_reg,-1
	slli \tmp_reg,\tmp_reg,0x27
	or \badaddr,\tmp_reg,\badaddr
	REG_S \badaddr, PT_BADADDR(\pt_reg)
1:
.endm

ENTRY(sifive_cip_453_page_fault_trp)
	ADD_SIGN_EXT a0, t0, t1
#ifdef CONFIG_MMU
	la t0, do_page_fault
#else
	la t0, do_trap_unknown
#endif
	jr t0
END(sifive_cip_453_page_fault_trp)

ENTRY(sifive_cip_453_insn_fault_trp)
	ADD_SIGN_EXT a0, t0, t1
	la t0, do_trap_insn_fault
	jr t0
END(sifive_cip_453_insn_fault_trp)
+20 −1
Original line number Diff line number Diff line
@@ -5,8 +5,27 @@
#ifndef ASM_ERRATA_LIST_H
#define ASM_ERRATA_LIST_H

#include <asm/alternative.h>
#include <asm/vendorid_list.h>

#ifdef CONFIG_ERRATA_SIFIVE
#define	ERRATA_SIFIVE_NUMBER 0
#define	ERRATA_SIFIVE_CIP_453 0
#define	ERRATA_SIFIVE_NUMBER 1
#endif

#ifdef __ASSEMBLY__

#define ALT_INSN_FAULT(x)						\
ALTERNATIVE(__stringify(RISCV_PTR do_trap_insn_fault),			\
	    __stringify(RISCV_PTR sifive_cip_453_insn_fault_trp),	\
	    SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453,			\
	    CONFIG_ERRATA_SIFIVE_CIP_453)

#define ALT_PAGE_FAULT(x)						\
ALTERNATIVE(__stringify(RISCV_PTR do_page_fault),			\
	    __stringify(RISCV_PTR sifive_cip_453_page_fault_trp),	\
	    SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453,			\
	    CONFIG_ERRATA_SIFIVE_CIP_453)
#endif /* __ASSEMBLY__ */

#endif
Loading