diff mbox series

[02/11] MIPS: use virtual addresses from xkphys for MIPS64

Message ID 20231004161038.2818327-3-gregory.clement@bootlin.com (mailing list archive)
State Superseded
Headers show
Series Add support for the Mobileye EyeQ5 SoC | expand

Commit Message

Gregory CLEMENT Oct. 4, 2023, 4:10 p.m. UTC
From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>

Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
to trivially map first 1/2 GByte of physical memory. This memory
used to run kernel. This mean, one should have memory installed
in this area in order for Linux to work.

Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
to use virtual addresses from the XKPHYS segment for both cached
and uncached access. XKPHYS allows to access 2^48 bytes of
memory, thus allowing kernel to work with any memory
configuration.

MIPS CPU sets KX bit in the CP0 status register at reset
if RESET_BASE_MODE (BIT 1) set in the GCR_CL_RESET_BASE.

Reset vector should fit into 32-bit. If reset vector put outside of
KSEG1, BIT(1) should be set in this value.

IRQ handler for CPU updated to generate 64-bit address for jump

Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
---
 arch/mips/Kconfig                 | 15 +++++++++++++
 arch/mips/Makefile                |  4 ++++
 arch/mips/generic/Platform        |  5 +++++
 arch/mips/include/asm/addrspace.h | 12 ++++++++--
 arch/mips/include/asm/mips-cm.h   |  1 +
 arch/mips/include/asm/page.h      | 10 +++++++++
 arch/mips/include/asm/vga.h       |  4 ++++
 arch/mips/kernel/cps-vec.S        |  8 +++++++
 arch/mips/kernel/genex.S          | 14 ++++++++++++
 arch/mips/kernel/smp-cps.c        | 37 +++++++++++++++++++++++--------
 arch/mips/kernel/traps.c          | 32 +++++++++++++++++++++++---
 arch/mips/lib/uncached.c          | 10 +++++++++
 arch/mips/mm/init.c               |  4 ++--
 13 files changed, 140 insertions(+), 16 deletions(-)

Comments

Thomas Bogendoerfer Oct. 12, 2023, 3:34 p.m. UTC | #1
On Wed, Oct 04, 2023 at 06:10:29PM +0200, Gregory CLEMENT wrote:
> From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
> 
> Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
> to trivially map first 1/2 GByte of physical memory. This memory
> used to run kernel. This mean, one should have memory installed
> in this area in order for Linux to work.
> 
> Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
> to use virtual addresses from the XKPHYS segment for both cached
> and uncached access. XKPHYS allows to access 2^48 bytes of
> memory, thus allowing kernel to work with any memory
> configuration.

IMHO it doesn't make sense to introduce an option for a generic
kernel, which then renders the generic kernel useless on all
platforms other then yours.

Please don't use generic, but setup a new platform for it. Hopefully
we can get rid all of the weirdness in this patch.

Thomas.
Jiaxun Yang Oct. 22, 2023, 11:39 a.m. UTC | #2
在2023年10月4日十月 下午5:10,Gregory CLEMENT写道:
> From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>
> Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
> to trivially map first 1/2 GByte of physical memory. This memory
> used to run kernel. This mean, one should have memory installed
> in this area in order for Linux to work.
>
> Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
> to use virtual addresses from the XKPHYS segment for both cached
> and uncached access. XKPHYS allows to access 2^48 bytes of
> memory, thus allowing kernel to work with any memory
> configuration.
>
> MIPS CPU sets KX bit in the CP0 status register at reset
> if RESET_BASE_MODE (BIT 1) set in the GCR_CL_RESET_BASE.
>
> Reset vector should fit into 32-bit. If reset vector put outside of
> KSEG1, BIT(1) should be set in this value.
>
> IRQ handler for CPU updated to generate 64-bit address for jump

Please use existing KBUILD_SYM32 symbol.

Thanks
- Jiaxun

>
> Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
> Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
> ---
>  arch/mips/Kconfig                 | 15 +++++++++++++
>  arch/mips/Makefile                |  4 ++++
>  arch/mips/generic/Platform        |  5 +++++
>  arch/mips/include/asm/addrspace.h | 12 ++++++++--
>  arch/mips/include/asm/mips-cm.h   |  1 +
>  arch/mips/include/asm/page.h      | 10 +++++++++
>  arch/mips/include/asm/vga.h       |  4 ++++
>  arch/mips/kernel/cps-vec.S        |  8 +++++++
>  arch/mips/kernel/genex.S          | 14 ++++++++++++
>  arch/mips/kernel/smp-cps.c        | 37 +++++++++++++++++++++++--------
>  arch/mips/kernel/traps.c          | 32 +++++++++++++++++++++++---
>  arch/mips/lib/uncached.c          | 10 +++++++++
>  arch/mips/mm/init.c               |  4 ++--
>  13 files changed, 140 insertions(+), 16 deletions(-)
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index bc8421859006..92832bbcca5d 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -2026,6 +2026,21 @@ config 64BIT
> 
>  endchoice
> 
> +config USE_XKPHYS
> +	bool "use virtual address from XKPHYS"
> +	depends on 64BIT
> +	default n
> +	help
> +	 By default, MIPS uses 32-bit compatible segments KSEG0 and KSEG1
> +	 to trivially map first 1/2 GByte of physical memory. This mean,
> +	 one should have memory installed in this area in order for Linux to
> +	 work. With this option selected, kernel uses virtual addresses from
> +	 the XKPHYS segment for both cached and uncached access. XKPHYS allows
> +	 to access 2^48 bytes of memory, thus allowing to work with any memory
> +	 configuration.
> +
> +	 Say N if not sure
> +
>  config MIPS_VA_BITS_48
>  	bool "48 bits virtual memory"
>  	depends on 64BIT
> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
> index f49807e1f19b..544ee8427cab 100644
> --- a/arch/mips/Makefile
> +++ b/arch/mips/Makefile
> @@ -303,6 +303,10 @@ ifdef CONFIG_64BIT
>      endif
>    endif
> 
> +  ifdef CONFIG_USE_XKPHYS
> +      KBUILD_SYM32 = n
> +  endif
> +
>    ifeq ($(KBUILD_SYM32), y)
>      cflags-$(KBUILD_SYM32) += -msym32 -DKBUILD_64BIT_SYM32
>    else
> diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
> index 0c03623f3897..2be9947814ad 100644
> --- a/arch/mips/generic/Platform
> +++ b/arch/mips/generic/Platform
> @@ -12,7 +12,12 @@
>  cflags-$(CONFIG_MACH_INGENIC_SOC)	+= 
> -I$(srctree)/arch/mips/include/asm/mach-ingenic
>  cflags-$(CONFIG_MIPS_GENERIC)	+= 
> -I$(srctree)/arch/mips/include/asm/mach-generic
> 
> +ifndef (CONFIG_USE_XKPHYS)
>  load-$(CONFIG_MIPS_GENERIC)	+= 0xffffffff80100000
> +else
> +load-$(CONFIG_MIPS_GENERIC)	+= 0xa800000080100000
> +endif
> +
>  all-$(CONFIG_MIPS_GENERIC)	+= vmlinux.gz.itb
> 
>  its-y					:= vmlinux.its.S
> diff --git a/arch/mips/include/asm/addrspace.h 
> b/arch/mips/include/asm/addrspace.h
> index 59a48c60a065..8dc500d8e66d 100644
> --- a/arch/mips/include/asm/addrspace.h
> +++ b/arch/mips/include/asm/addrspace.h
> @@ -65,10 +65,15 @@
>  #define XKSSEG			_CONST64_(0x4000000000000000)
>  #define XKPHYS			_CONST64_(0x8000000000000000)
>  #define XKSEG			_CONST64_(0xc000000000000000)
> +#if !defined(CONFIG_USE_XKPHYS)
>  #define CKSEG0			_CONST64_(0xffffffff80000000)
>  #define CKSEG1			_CONST64_(0xffffffffa0000000)
>  #define CKSSEG			_CONST64_(0xffffffffc0000000)
>  #define CKSEG3			_CONST64_(0xffffffffe0000000)
> +#else
> +#define CKSEG0			XKPHYS_CM_CACHED
> +#define CKSEG1			XKPHYS_CM_UNCACHED
> +#endif /* !defined(CONFIG_USE_XKPHYS) */
> 
>  #define CKSEG0ADDR(a)		(CPHYSADDR(a) | CKSEG0)
>  #define CKSEG1ADDR(a)		(CPHYSADDR(a) | CKSEG1)
> @@ -126,8 +131,11 @@
>  #define PHYS_TO_XKSEG_UNCACHED(p)	PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p))
>  #define PHYS_TO_XKSEG_CACHED(p)		PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p))
>  #define XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK)
> -#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS | (_ACAST64_(cm) << 59) | (a))
> -
> +#define XKPHYS_CM(cm)			(XKPHYS | (_ACAST64_(cm) << 59))
> +#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS_CM(cm) | (a))
> +#define XKPHYS_CM_CACHED		(XKPHYS_CM(K_CALG_COH_SHAREABLE))
> +#define XKPHYS_CM_UNCACHED		(XKPHYS_CM(K_CALG_UNCACHED))
> +#define IS_XKPHYS(a)			(((a) >> 62) == 2)
>  /*
>   * The ultimate limited of the 64-bit MIPS architecture:  2 bits for selecting
>   * the region, 3 bits for the CCA mode.  This leaves 59 bits of which the
> diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
> index 23c67c0871b1..15d8d69de455 100644
> --- a/arch/mips/include/asm/mips-cm.h
> +++ b/arch/mips/include/asm/mips-cm.h
> @@ -311,6 +311,7 @@ GCR_CX_ACCESSOR_RW(32, 0x018, other)
>  /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */
>  GCR_CX_ACCESSOR_RW(32, 0x020, reset_base)
>  #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE		GENMASK(31, 12)
> +#define CM_GCR_Cx_RESET_BASE_MODE		BIT(1)
> 
>  /* GCR_Cx_ID - Identify the current core */
>  GCR_CX_ACCESSOR_RO(32, 0x028, id)
> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> index 5978a8dfb917..53b8306da571 100644
> --- a/arch/mips/include/asm/page.h
> +++ b/arch/mips/include/asm/page.h
> @@ -176,7 +176,11 @@ static inline unsigned long ___pa(unsigned long x)
>  		 * the compatibility segements ckseg0 or ckseg1, or it may
>  		 * be in xkphys.
>  		 */
> +#if defined(CONFIG_USE_XKPHYS)
> +		return XPHYSADDR(x);
> +#else
>  		return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
> +#endif
>  	}
> 
>  	if (!IS_ENABLED(CONFIG_EVA)) {
> @@ -196,7 +200,11 @@ static inline unsigned long ___pa(unsigned long x)
>  	return x - PAGE_OFFSET + PHYS_OFFSET;
>  }
>  #define __pa(x)		___pa((unsigned long)(x))
> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
> +#define __va(x)		((void *)PHYS_TO_XKSEG_CACHED(x))
> +#else
>  #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
> +#endif
>  #include <asm/io.h>
> 
>  /*
> @@ -239,6 +247,8 @@ static inline unsigned long kaslr_offset(void)
>  	return __kaslr_offset;
>  }
> 
> +#define UNCAC_ADDR(addr)       (UNCAC_BASE + __pa(addr))
> +
>  #include <asm-generic/memory_model.h>
>  #include <asm-generic/getorder.h>
> 
> diff --git a/arch/mips/include/asm/vga.h b/arch/mips/include/asm/vga.h
> index 0136e0366698..e338e57d0784 100644
> --- a/arch/mips/include/asm/vga.h
> +++ b/arch/mips/include/asm/vga.h
> @@ -16,7 +16,11 @@
>   *	access the videoram directly without any black magic.
>   */
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +#define VGA_MAP_MEM(x, s)	UNCAC_ADDR(0x10000000L + (unsigned long)(x))
> +#else
>  #define VGA_MAP_MEM(x, s)	CKSEG1ADDR(0x10000000L + (unsigned long)(x))
> +#endif
> 
>  #define vga_readb(x)	(*(x))
>  #define vga_writeb(x, y)	(*(y) = (x))
> diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
> index 64ecfdac6580..541f31a43a7f 100644
> --- a/arch/mips/kernel/cps-vec.S
> +++ b/arch/mips/kernel/cps-vec.S
> @@ -554,7 +554,11 @@ LEAF(mips_cps_cache_init)
>  	mul	t1, t1, t0
>  	mul	t1, t1, t2
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +	PTR_LI	a0, XKPHYS_CM_CACHED
> +#else
>  	li	a0, CKSEG0
> +#endif
>  	PTR_ADD	a1, a0, t1
>  1:	cache	Index_Store_Tag_I, 0(a0)
>  	PTR_ADD	a0, a0, t0
> @@ -581,7 +585,11 @@ icache_done:
>  	mul	t1, t1, t0
>  	mul	t1, t1, t2
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +	PTR_LI	a0, XKPHYS_CM_CACHED
> +#else
>  	li	a0, CKSEG0
> +#endif
>  	PTR_ADDU a1, a0, t1
>  	PTR_SUBU a1, a1, t0
>  1:	cache	Index_Store_Tag_D, 0(a0)
> diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
> index b6de8e88c1bd..a002058e1838 100644
> --- a/arch/mips/kernel/genex.S
> +++ b/arch/mips/kernel/genex.S
> @@ -272,11 +272,25 @@ NESTED(except_vec_vi, 0, sp)
>  	.set	push
>  	.set	noreorder
>  	PTR_LA	v1, except_vec_vi_handler
> +#if defined(CONFIG_USE_XKPHYS)
> +FEXPORT(except_vec_vi_63_48)
> +	lui	v0, 0		/* Patched - bits 63:48 */
> +FEXPORT(except_vec_vi_47_32)
> +	ori	v0, 0		/* Patched - bits 47:32 */
> +	dsll	v0, v0, 0x10
> +FEXPORT(except_vec_vi_31_16)
> +	ori	v0, 0		/* Patched - bits 31:16 */
> +	dsll	v0, v0, 0x10
> +	jr	v1
> +FEXPORT(except_vec_vi_15_0)
> +	ori	v0, 0		/* Patched - bits 15:0 */
> +#else /* defined(CONFIG_USE_XKPHYS) */
>  FEXPORT(except_vec_vi_lui)
>  	lui	v0, 0		/* Patched */
>  	jr	v1
>  FEXPORT(except_vec_vi_ori)
>  	 ori	v0, 0		/* Patched */
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  	.set	pop
>  	END(except_vec_vi)
>  EXPORT(except_vec_vi_end)
> diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
> index dd55d59b88db..47e76722a306 100644
> --- a/arch/mips/kernel/smp-cps.c
> +++ b/arch/mips/kernel/smp-cps.c
> @@ -34,10 +34,33 @@ static unsigned __init core_vpe_count(unsigned int 
> cluster, unsigned core)
>  	return min(smp_max_threads, mips_cps_numvps(cluster, core));
>  }
> 
> +/**
> + * plat_core_entry - query reset vector for NMI/reset
> + *
> + * Returns low 32 bits of the reset vector
> + *
> + * This is used to fill 2 registers:
> + * - BEV Base (GCR_BEV_BASE) Offset: 0x0680
> + * - VP Local Reset Exception Base (GCR_CL_RESET_BASE,GCR_CO_RESET_BASE)
> + *   Offset: 0x0020 (0x2020 relative to GCR_BASE_ADDR)
> + *
> + * In both registers, BIT(1) should be set in case it uses address in XKPHYS
> + * (as opposed to KSEG1). This bit defined as CM_GCR_Cx_RESET_BASE_MODE,
> + * using it unconditionally because for GCR_BEV_BASE its value is the same
> + */
> +static u32 plat_core_entry(void)
> +{
> +#if defined(CONFIG_USE_XKPHYS)
> +	return (UNCAC_ADDR(mips_cps_core_entry) & 0xffffffff)
> +			| CM_GCR_Cx_RESET_BASE_MODE;
> +#else
> +	return CKSEG1ADDR((unsigned long)mips_cps_core_entry);
> +#endif
> +}
> +
>  static void __init cps_smp_setup(void)
>  {
>  	unsigned int nclusters, ncores, nvpes, core_vpes;
> -	unsigned long core_entry;
>  	int cl, c, v;
> 
>  	/* Detect & record VPE topology */
> @@ -94,10 +117,8 @@ static void __init cps_smp_setup(void)
>  	/* Make core 0 coherent with everything */
>  	write_gcr_cl_coherence(0xff);
> 
> -	if (mips_cm_revision() >= CM_REV_CM3) {
> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
> -		write_gcr_bev_base(core_entry);
> -	}
> +	if (mips_cm_revision() >= CM_REV_CM3)
> +		write_gcr_bev_base(plat_core_entry());
> 
>  #ifdef CONFIG_MIPS_MT_FPAFF
>  	/* If we have an FPU, enroll ourselves in the FPU-full mask */
> @@ -213,7 +234,7 @@ static void boot_core(unsigned int core, unsigned 
> int vpe_id)
>  	mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
> 
>  	/* Set its reset vector */
> -	write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
> +	write_gcr_co_reset_base(plat_core_entry());
> 
>  	/* Ensure its coherency is disabled */
>  	write_gcr_co_coherence(0);
> @@ -290,7 +311,6 @@ static int cps_boot_secondary(int cpu, struct 
> task_struct *idle)
>  	unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
>  	struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
>  	struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
> -	unsigned long core_entry;
>  	unsigned int remote;
>  	int err;
> 
> @@ -314,8 +334,7 @@ static int cps_boot_secondary(int cpu, struct 
> task_struct *idle)
> 
>  	if (cpu_has_vp) {
>  		mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
> -		write_gcr_co_reset_base(core_entry);
> +		write_gcr_co_reset_base(plat_core_entry());
>  		mips_cm_unlock_other();
>  	}
> 
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index 246c6a6b0261..875594843626 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -2091,11 +2091,20 @@ static void *set_vi_srs_handler(int n, 
> vi_handler_t addr, int srs)
>  		 * If no shadow set is selected then use the default handler
>  		 * that does normal register saving and standard interrupt exit
>  		 */
> -		extern const u8 except_vec_vi[], except_vec_vi_lui[];
> -		extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
> +		extern const u8 except_vec_vi[], except_vec_vi_end[];
>  		extern const u8 rollback_except_vec_vi[];
>  		const u8 *vec_start = using_rollback_handler() ?
>  				      rollback_except_vec_vi : except_vec_vi;
> +		const int handler_len = except_vec_vi_end - vec_start;
> +#if defined(CONFIG_USE_XKPHYS)
> +		extern const u8 except_vec_vi_63_48[], except_vec_vi_47_32[];
> +		extern const u8 except_vec_vi_31_16[], except_vec_vi_15_0[];
> +		const int offset_63_48 = except_vec_vi_63_48 - vec_start;
> +		const int offset_47_32 = except_vec_vi_47_32 - vec_start;
> +		const int offset_31_16 = except_vec_vi_31_16 - vec_start;
> +		const int offset_15_0  = except_vec_vi_15_0  - vec_start;
> +#else /* defined(CONFIG_USE_XKPHYS) */
> +		extern const u8 except_vec_vi_lui[], except_vec_vi_ori[];
>  #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
>  		const int lui_offset = except_vec_vi_lui - vec_start + 2;
>  		const int ori_offset = except_vec_vi_ori - vec_start + 2;
> @@ -2103,7 +2112,7 @@ static void *set_vi_srs_handler(int n, 
> vi_handler_t addr, int srs)
>  		const int lui_offset = except_vec_vi_lui - vec_start;
>  		const int ori_offset = except_vec_vi_ori - vec_start;
>  #endif
> -		const int handler_len = except_vec_vi_end - vec_start;
> +#endif /* defined(CONFIG_USE_XKPHYS) */
> 
>  		if (handler_len > VECTORSPACING) {
>  			/*
> @@ -2119,10 +2128,21 @@ static void *set_vi_srs_handler(int n, 
> vi_handler_t addr, int srs)
>  #else
>  				handler_len);
>  #endif
> +#if defined(CONFIG_USE_XKPHYS)
> +		h = (u16 *)(b + offset_63_48);
> +		*h = (handler >> 48) & 0xffff;
> +		h = (u16 *)(b + offset_47_32);
> +		*h = (handler >> 32) & 0xffff;
> +		h = (u16 *)(b + offset_31_16);
> +		*h = (handler >> 16) & 0xffff;
> +		h = (u16 *)(b + offset_15_0);
> +		*h = (handler >> 0) & 0xffff;
> +#else /* defined(CONFIG_USE_XKPHYS) */
>  		h = (u16 *)(b + lui_offset);
>  		*h = (handler >> 16) & 0xffff;
>  		h = (u16 *)(b + ori_offset);
>  		*h = (handler & 0xffff);
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  		local_flush_icache_range((unsigned long)b,
>  					 (unsigned long)(b+handler_len));
>  	}
> @@ -2332,7 +2352,11 @@ static const char panic_null_cerr[] =
>  void set_uncached_handler(unsigned long offset, void *addr,
>  	unsigned long size)
>  {
> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
> +	unsigned long uncached_ebase = UNCAC_ADDR(ebase);
> +#else
>  	unsigned long uncached_ebase = CKSEG1ADDR(ebase);
> +#endif
> 
>  	if (!addr)
>  		panic(panic_null_cerr);
> @@ -2384,9 +2408,11 @@ void __init trap_init(void)
>  		 * EVA is special though as it allows segments to be rearranged
>  		 * and to become uncached during cache error handling.
>  		 */
> +#if !defined(CONFIG_USE_XKPHYS)
>  		if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000))
>  			ebase = CKSEG0ADDR(ebase_pa);
>  		else
> +#endif
>  			ebase = (unsigned long)phys_to_virt(ebase_pa);
>  	}
> 
> diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
> index f80a67c092b6..8a78348a2dd7 100644
> --- a/arch/mips/lib/uncached.c
> +++ b/arch/mips/lib/uncached.c
> @@ -44,6 +44,10 @@ unsigned long run_uncached(void *func)
> 
>  	__asm__("move %0, $sp" : "=r" (sp));
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +	if (IS_XKPHYS(sp))
> +		usp = UNCAC_ADDR(sp);
> +#else /* defined(CONFIG_USE_XKPHYS) */
>  	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
>  		usp = CKSEG1ADDR(sp);
>  #ifdef CONFIG_64BIT
> @@ -52,10 +56,15 @@ unsigned long run_uncached(void *func)
>  		usp = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>  				     XKPHYS_TO_PHYS((long long)sp));
>  #endif
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  	else {
>  		BUG();
>  		usp = sp;
>  	}
> +#if defined(CONFIG_USE_XKPHYS)
> +	if (IS_XKPHYS(lfunc))
> +		ufunc = UNCAC_ADDR(lfunc);
> +#else /* defined(CONFIG_USE_XKPHYS) */
>  	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
>  		ufunc = CKSEG1ADDR(lfunc);
>  #ifdef CONFIG_64BIT
> @@ -64,6 +73,7 @@ unsigned long run_uncached(void *func)
>  		ufunc = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>  				       XKPHYS_TO_PHYS((long long)lfunc));
>  #endif
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  	else {
>  		BUG();
>  		ufunc = lfunc;
> diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
> index 5dcb525a8995..eb57283ec4e0 100644
> --- a/arch/mips/mm/init.c
> +++ b/arch/mips/mm/init.c
> @@ -427,7 +427,7 @@ void __init paging_init(void)
>  	free_area_init(max_zone_pfns);
>  }
> 
> -#ifdef CONFIG_64BIT
> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>  static struct kcore_list kcore_kseg0;
>  #endif
> 
> @@ -470,7 +470,7 @@ void __init mem_init(void)
>  	setup_zero_pages();	/* Setup zeroed pages.  */
>  	mem_init_free_highmem();
> 
> -#ifdef CONFIG_64BIT
> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>  	if ((unsigned long) &_text > (unsigned long) CKSEG0)
>  		/* The -4 is a hack so that user tools don't have to handle
>  		   the overflow.  */
> -- 
> 2.40.1
Jiaxun Yang Oct. 22, 2023, 11:52 a.m. UTC | #3
在2023年10月12日十月 下午4:34,Thomas Bogendoerfer写道:
> On Wed, Oct 04, 2023 at 06:10:29PM +0200, Gregory CLEMENT wrote:
>> From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>> 
>> Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
>> to trivially map first 1/2 GByte of physical memory. This memory
>> used to run kernel. This mean, one should have memory installed
>> in this area in order for Linux to work.
>> 
>> Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
>> to use virtual addresses from the XKPHYS segment for both cached
>> and uncached access. XKPHYS allows to access 2^48 bytes of
>> memory, thus allowing kernel to work with any memory
>> configuration.
>
> IMHO it doesn't make sense to introduce an option for a generic
> kernel, which then renders the generic kernel useless on all
> platforms other then yours.

Actually it won't. Many 64bit platforms do support load kernel to
XKPHYS, including boston and Loongson64, so it's still a generic
function.

IMO this patch won't break support for any generic platform.

>
> Please don't use generic, but setup a new platform for it. Hopefully
> we can get rid all of the weirdness in this patch.

Perhaps better to introduce a Kconfig option to allow manipulation of
kernel load address.

Thanks
- Jiaxun

>
> Thomas.
>
> -- 
> Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
> good idea.                                                [ RFC1925, 2.3 ]
Jiaxun Yang Oct. 22, 2023, 4:42 p.m. UTC | #4
在2023年10月4日十月 下午5:10,Gregory CLEMENT写道:
> From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>
> Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
> to trivially map first 1/2 GByte of physical memory. This memory
> used to run kernel. This mean, one should have memory installed
> in this area in order for Linux to work.
>
> Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
> to use virtual addresses from the XKPHYS segment for both cached
> and uncached access. XKPHYS allows to access 2^48 bytes of
> memory, thus allowing kernel to work with any memory
> configuration.
>
> MIPS CPU sets KX bit in the CP0 status register at reset
> if RESET_BASE_MODE (BIT 1) set in the GCR_CL_RESET_BASE.
>
> Reset vector should fit into 32-bit. If reset vector put outside of
> KSEG1, BIT(1) should be set in this value.
>
> IRQ handler for CPU updated to generate 64-bit address for jump

So I just spend some time to review and test this patch on QEMU,
comments below:

>
> Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
> Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
> ---
>  arch/mips/Kconfig                 | 15 +++++++++++++
>  arch/mips/Makefile                |  4 ++++
>  arch/mips/generic/Platform        |  5 +++++
>  arch/mips/include/asm/addrspace.h | 12 ++++++++--
>  arch/mips/include/asm/mips-cm.h   |  1 +
>  arch/mips/include/asm/page.h      | 10 +++++++++
>  arch/mips/include/asm/vga.h       |  4 ++++
>  arch/mips/kernel/cps-vec.S        |  8 +++++++
>  arch/mips/kernel/genex.S          | 14 ++++++++++++
>  arch/mips/kernel/smp-cps.c        | 37 +++++++++++++++++++++++--------
>  arch/mips/kernel/traps.c          | 32 +++++++++++++++++++++++---
>  arch/mips/lib/uncached.c          | 10 +++++++++
>  arch/mips/mm/init.c               |  4 ++--
>  13 files changed, 140 insertions(+), 16 deletions(-)
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index bc8421859006..92832bbcca5d 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -2026,6 +2026,21 @@ config 64BIT
> 
>  endchoice
> 
> +config USE_XKPHYS
> +	bool "use virtual address from XKPHYS"
> +	depends on 64BIT
> +	default n
> +	help
> +	 By default, MIPS uses 32-bit compatible segments KSEG0 and KSEG1
> +	 to trivially map first 1/2 GByte of physical memory. This mean,
> +	 one should have memory installed in this area in order for Linux to
> +	 work. With this option selected, kernel uses virtual addresses from
> +	 the XKPHYS segment for both cached and uncached access. XKPHYS allows
> +	 to access 2^48 bytes of memory, thus allowing to work with any memory
> +	 configuration.
> +
> +	 Say N if not sure
> +
>  config MIPS_VA_BITS_48
>  	bool "48 bits virtual memory"
>  	depends on 64BIT
> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
> index f49807e1f19b..544ee8427cab 100644
> --- a/arch/mips/Makefile
> +++ b/arch/mips/Makefile
> @@ -303,6 +303,10 @@ ifdef CONFIG_64BIT
>      endif
>    endif
> 
> +  ifdef CONFIG_USE_XKPHYS
> +      KBUILD_SYM32 = n
> +  endif
> +
>    ifeq ($(KBUILD_SYM32), y)
>      cflags-$(KBUILD_SYM32) += -msym32 -DKBUILD_64BIT_SYM32
>    else
> diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
> index 0c03623f3897..2be9947814ad 100644
> --- a/arch/mips/generic/Platform
> +++ b/arch/mips/generic/Platform
> @@ -12,7 +12,12 @@
>  cflags-$(CONFIG_MACH_INGENIC_SOC)	+= 
> -I$(srctree)/arch/mips/include/asm/mach-ingenic
>  cflags-$(CONFIG_MIPS_GENERIC)	+= 
> -I$(srctree)/arch/mips/include/asm/mach-generic
> 
> +ifndef (CONFIG_USE_XKPHYS)
>  load-$(CONFIG_MIPS_GENERIC)	+= 0xffffffff80100000
> +else
> +load-$(CONFIG_MIPS_GENERIC)	+= 0xa800000080100000
> +endif

Better to make load address configurable.

> +
>  all-$(CONFIG_MIPS_GENERIC)	+= vmlinux.gz.itb
> 
>  its-y					:= vmlinux.its.S
> diff --git a/arch/mips/include/asm/addrspace.h 
> b/arch/mips/include/asm/addrspace.h
> index 59a48c60a065..8dc500d8e66d 100644
> --- a/arch/mips/include/asm/addrspace.h
> +++ b/arch/mips/include/asm/addrspace.h
> @@ -65,10 +65,15 @@
>  #define XKSSEG			_CONST64_(0x4000000000000000)
>  #define XKPHYS			_CONST64_(0x8000000000000000)
>  #define XKSEG			_CONST64_(0xc000000000000000)
> +#if !defined(CONFIG_USE_XKPHYS)
>  #define CKSEG0			_CONST64_(0xffffffff80000000)
>  #define CKSEG1			_CONST64_(0xffffffffa0000000)
>  #define CKSSEG			_CONST64_(0xffffffffc0000000)
>  #define CKSEG3			_CONST64_(0xffffffffe0000000)
> +#else
> +#define CKSEG0			XKPHYS_CM_CACHED
> +#define CKSEG1			XKPHYS_CM_UNCACHED
> +#endif /* !defined(CONFIG_USE_XKPHYS) */
> 
>  #define CKSEG0ADDR(a)		(CPHYSADDR(a) | CKSEG0)
>  #define CKSEG1ADDR(a)		(CPHYSADDR(a) | CKSEG1)
> @@ -126,8 +131,11 @@
>  #define PHYS_TO_XKSEG_UNCACHED(p)	PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p))
>  #define PHYS_TO_XKSEG_CACHED(p)		PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p))
>  #define XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK)
> -#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS | (_ACAST64_(cm) << 59) | (a))
> -
> +#define XKPHYS_CM(cm)			(XKPHYS | (_ACAST64_(cm) << 59))
> +#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS_CM(cm) | (a))
> +#define XKPHYS_CM_CACHED		(XKPHYS_CM(K_CALG_COH_SHAREABLE))
> +#define XKPHYS_CM_UNCACHED		(XKPHYS_CM(K_CALG_UNCACHED))
> +#define IS_XKPHYS(a)			(((a) >> 62) == 2)
>  /*
>   * The ultimate limited of the 64-bit MIPS architecture:  2 bits for selecting
>   * the region, 3 bits for the CCA mode.  This leaves 59 bits of which the
> diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
> index 23c67c0871b1..15d8d69de455 100644
> --- a/arch/mips/include/asm/mips-cm.h
> +++ b/arch/mips/include/asm/mips-cm.h
> @@ -311,6 +311,7 @@ GCR_CX_ACCESSOR_RW(32, 0x018, other)
>  /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */
>  GCR_CX_ACCESSOR_RW(32, 0x020, reset_base)
>  #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE		GENMASK(31, 12)
> +#define CM_GCR_Cx_RESET_BASE_MODE		BIT(1)
> 
>  /* GCR_Cx_ID - Identify the current core */
>  GCR_CX_ACCESSOR_RO(32, 0x028, id)
> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> index 5978a8dfb917..53b8306da571 100644
> --- a/arch/mips/include/asm/page.h
> +++ b/arch/mips/include/asm/page.h
> @@ -176,7 +176,11 @@ static inline unsigned long ___pa(unsigned long x)
>  		 * the compatibility segements ckseg0 or ckseg1, or it may
>  		 * be in xkphys.
>  		 */
> +#if defined(CONFIG_USE_XKPHYS)
> +		return XPHYSADDR(x);
> +#else
>  		return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
> +#endif

Dangerous, there might be some code passing KSEG0/1 address to __pa, so
we should not disregard it.

>  	}
> 
>  	if (!IS_ENABLED(CONFIG_EVA)) {
> @@ -196,7 +200,11 @@ static inline unsigned long ___pa(unsigned long x)
>  	return x - PAGE_OFFSET + PHYS_OFFSET;
>  }
>  #define __pa(x)		___pa((unsigned long)(x))
> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
> +#define __va(x)		((void *)PHYS_TO_XKSEG_CACHED(x))
> +#else
>  #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
> +#endif

PAGE_OFFSET resolves to CAC_BASE anyway, so unnecessary.

>  #include <asm/io.h>
> 
>  /*
> @@ -239,6 +247,8 @@ static inline unsigned long kaslr_offset(void)
>  	return __kaslr_offset;
>  }
> 
> +#define UNCAC_ADDR(addr)       (UNCAC_BASE + __pa(addr))
> +
>  #include <asm-generic/memory_model.h>
>  #include <asm-generic/getorder.h>
> 
> diff --git a/arch/mips/include/asm/vga.h b/arch/mips/include/asm/vga.h
> index 0136e0366698..e338e57d0784 100644
> --- a/arch/mips/include/asm/vga.h
> +++ b/arch/mips/include/asm/vga.h
> @@ -16,7 +16,11 @@
>   *	access the videoram directly without any black magic.
>   */
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +#define VGA_MAP_MEM(x, s)	UNCAC_ADDR(0x10000000L + (unsigned long)(x))
> +#else
>  #define VGA_MAP_MEM(x, s)	CKSEG1ADDR(0x10000000L + (unsigned long)(x))
> +#endif

VGA_MAP_MEM intends to work on some really legacy systems, it won't break
your platform, so better leave it as is.

> 
>  #define vga_readb(x)	(*(x))
>  #define vga_writeb(x, y)	(*(y) = (x))
> diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
> index 64ecfdac6580..541f31a43a7f 100644
> --- a/arch/mips/kernel/cps-vec.S
> +++ b/arch/mips/kernel/cps-vec.S
> @@ -554,7 +554,11 @@ LEAF(mips_cps_cache_init)
>  	mul	t1, t1, t0
>  	mul	t1, t1, t2
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +	PTR_LI	a0, XKPHYS_CM_CACHED
> +#else
>  	li	a0, CKSEG0
> +#endif

Unnecessary, KSEG0 address here are just for matching cache ways,
so there is no difference to use KSEG0 or XKPHYS.

If you are using XKPHYS here you must extarct CCA from bootinfo
or CP0 as it may varies on different systems.

>  	PTR_ADD	a1, a0, t1
>  1:	cache	Index_Store_Tag_I, 0(a0)
>  	PTR_ADD	a0, a0, t0
> @@ -581,7 +585,11 @@ icache_done:
>  	mul	t1, t1, t0
>  	mul	t1, t1, t2
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +	PTR_LI	a0, XKPHYS_CM_CACHED
> +#else

Ditto.

>  	li	a0, CKSEG0
> +#endif
>  	PTR_ADDU a1, a0, t1
>  	PTR_SUBU a1, a1, t0
>  1:	cache	Index_Store_Tag_D, 0(a0)
> diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
> index b6de8e88c1bd..a002058e1838 100644
> --- a/arch/mips/kernel/genex.S
> +++ b/arch/mips/kernel/genex.S
> @@ -272,11 +272,25 @@ NESTED(except_vec_vi, 0, sp)
>  	.set	push
>  	.set	noreorder
>  	PTR_LA	v1, except_vec_vi_handler
> +#if defined(CONFIG_USE_XKPHYS)
> +FEXPORT(except_vec_vi_63_48)
> +	lui	v0, 0		/* Patched - bits 63:48 */
> +FEXPORT(except_vec_vi_47_32)
> +	ori	v0, 0		/* Patched - bits 47:32 */
> +	dsll	v0, v0, 0x10
> +FEXPORT(except_vec_vi_31_16)
> +	ori	v0, 0		/* Patched - bits 31:16 */
> +	dsll	v0, v0, 0x10
> +	jr	v1
> +FEXPORT(except_vec_vi_15_0)
> +	ori	v0, 0		/* Patched - bits 15:0 */
> +#else /* defined(CONFIG_USE_XKPHYS) */
>  FEXPORT(except_vec_vi_lui)
>  	lui	v0, 0		/* Patched */
>  	jr	v1
>  FEXPORT(except_vec_vi_ori)
>  	 ori	v0, 0		/* Patched */
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  	.set	pop
>  	END(except_vec_vi)
>  EXPORT(except_vec_vi_end)
> diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
> index dd55d59b88db..47e76722a306 100644
> --- a/arch/mips/kernel/smp-cps.c
> +++ b/arch/mips/kernel/smp-cps.c
> @@ -34,10 +34,33 @@ static unsigned __init core_vpe_count(unsigned int 
> cluster, unsigned core)
>  	return min(smp_max_threads, mips_cps_numvps(cluster, core));
>  }
> 
> +/**
> + * plat_core_entry - query reset vector for NMI/reset
> + *
> + * Returns low 32 bits of the reset vector
> + *
> + * This is used to fill 2 registers:
> + * - BEV Base (GCR_BEV_BASE) Offset: 0x0680
> + * - VP Local Reset Exception Base (GCR_CL_RESET_BASE,GCR_CO_RESET_BASE)
> + *   Offset: 0x0020 (0x2020 relative to GCR_BASE_ADDR)
> + *
> + * In both registers, BIT(1) should be set in case it uses address in XKPHYS
> + * (as opposed to KSEG1). This bit defined as CM_GCR_Cx_RESET_BASE_MODE,
> + * using it unconditionally because for GCR_BEV_BASE its value is the same
> + */
> +static u32 plat_core_entry(void)
> +{
> +#if defined(CONFIG_USE_XKPHYS)
> +	return (UNCAC_ADDR(mips_cps_core_entry) & 0xffffffff)
> +			| CM_GCR_Cx_RESET_BASE_MODE;
> +#else
> +	return CKSEG1ADDR((unsigned long)mips_cps_core_entry);
> +#endif

This is a CM3 feature, so perhaps we should handle it in a general
way.

> +}
> +
>  static void __init cps_smp_setup(void)
>  {
>  	unsigned int nclusters, ncores, nvpes, core_vpes;
> -	unsigned long core_entry;
>  	int cl, c, v;
> 
>  	/* Detect & record VPE topology */
> @@ -94,10 +117,8 @@ static void __init cps_smp_setup(void)
>  	/* Make core 0 coherent with everything */
>  	write_gcr_cl_coherence(0xff);
> 
> -	if (mips_cm_revision() >= CM_REV_CM3) {
> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
> -		write_gcr_bev_base(core_entry);
> -	}
> +	if (mips_cm_revision() >= CM_REV_CM3)
> +		write_gcr_bev_base(plat_core_entry());
> 
>  #ifdef CONFIG_MIPS_MT_FPAFF
>  	/* If we have an FPU, enroll ourselves in the FPU-full mask */
> @@ -213,7 +234,7 @@ static void boot_core(unsigned int core, unsigned 
> int vpe_id)
>  	mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
> 
>  	/* Set its reset vector */
> -	write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
> +	write_gcr_co_reset_base(plat_core_entry());
> 
>  	/* Ensure its coherency is disabled */
>  	write_gcr_co_coherence(0);
> @@ -290,7 +311,6 @@ static int cps_boot_secondary(int cpu, struct 
> task_struct *idle)
>  	unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
>  	struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
>  	struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
> -	unsigned long core_entry;
>  	unsigned int remote;
>  	int err;
> 
> @@ -314,8 +334,7 @@ static int cps_boot_secondary(int cpu, struct 
> task_struct *idle)
> 
>  	if (cpu_has_vp) {
>  		mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
> -		write_gcr_co_reset_base(core_entry);
> +		write_gcr_co_reset_base(plat_core_entry());
>  		mips_cm_unlock_other();
>  	}
> 
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index 246c6a6b0261..875594843626 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -2091,11 +2091,20 @@ static void *set_vi_srs_handler(int n, 
> vi_handler_t addr, int srs)
>  		 * If no shadow set is selected then use the default handler
>  		 * that does normal register saving and standard interrupt exit
>  		 */
> -		extern const u8 except_vec_vi[], except_vec_vi_lui[];
> -		extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
> +		extern const u8 except_vec_vi[], except_vec_vi_end[];
>  		extern const u8 rollback_except_vec_vi[];
>  		const u8 *vec_start = using_rollback_handler() ?
>  				      rollback_except_vec_vi : except_vec_vi;
> +		const int handler_len = except_vec_vi_end - vec_start;
> +#if defined(CONFIG_USE_XKPHYS)
> +		extern const u8 except_vec_vi_63_48[], except_vec_vi_47_32[];
> +		extern const u8 except_vec_vi_31_16[], except_vec_vi_15_0[];
> +		const int offset_63_48 = except_vec_vi_63_48 - vec_start;
> +		const int offset_47_32 = except_vec_vi_47_32 - vec_start;
> +		const int offset_31_16 = except_vec_vi_31_16 - vec_start;
> +		const int offset_15_0  = except_vec_vi_15_0  - vec_start;
> +#else /* defined(CONFIG_USE_XKPHYS) */
> +		extern const u8 except_vec_vi_lui[], except_vec_vi_ori[];
>  #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
>  		const int lui_offset = except_vec_vi_lui - vec_start + 2;
>  		const int ori_offset = except_vec_vi_ori - vec_start + 2;
> @@ -2103,7 +2112,7 @@ static void *set_vi_srs_handler(int n, 
> vi_handler_t addr, int srs)
>  		const int lui_offset = except_vec_vi_lui - vec_start;
>  		const int ori_offset = except_vec_vi_ori - vec_start;
>  #endif
> -		const int handler_len = except_vec_vi_end - vec_start;
> +#endif /* defined(CONFIG_USE_XKPHYS) */
> 
>  		if (handler_len > VECTORSPACING) {
>  			/*
> @@ -2119,10 +2128,21 @@ static void *set_vi_srs_handler(int n, 
> vi_handler_t addr, int srs)
>  #else
>  				handler_len);
>  #endif
> +#if defined(CONFIG_USE_XKPHYS)
> +		h = (u16 *)(b + offset_63_48);
> +		*h = (handler >> 48) & 0xffff;
> +		h = (u16 *)(b + offset_47_32);
> +		*h = (handler >> 32) & 0xffff;
> +		h = (u16 *)(b + offset_31_16);
> +		*h = (handler >> 16) & 0xffff;
> +		h = (u16 *)(b + offset_15_0);
> +		*h = (handler >> 0) & 0xffff;
> +#else /* defined(CONFIG_USE_XKPHYS) */
>  		h = (u16 *)(b + lui_offset);
>  		*h = (handler >> 16) & 0xffff;
>  		h = (u16 *)(b + ori_offset);
>  		*h = (handler & 0xffff);
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  		local_flush_icache_range((unsigned long)b,
>  					 (unsigned long)(b+handler_len));
>  	}
> @@ -2332,7 +2352,11 @@ static const char panic_null_cerr[] =
>  void set_uncached_handler(unsigned long offset, void *addr,
>  	unsigned long size)
>  {
> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
> +	unsigned long uncached_ebase = UNCAC_ADDR(ebase);
> +#else
>  	unsigned long uncached_ebase = CKSEG1ADDR(ebase);
> +#endif
> 
>  	if (!addr)
>  		panic(panic_null_cerr);
> @@ -2384,9 +2408,11 @@ void __init trap_init(void)
>  		 * EVA is special though as it allows segments to be rearranged
>  		 * and to become uncached during cache error handling.
>  		 */
> +#if !defined(CONFIG_USE_XKPHYS)
>  		if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000))
>  			ebase = CKSEG0ADDR(ebase_pa);
>  		else
> +#endif
>  			ebase = (unsigned long)phys_to_virt(ebase_pa);
>  	}
> 
> diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
> index f80a67c092b6..8a78348a2dd7 100644
> --- a/arch/mips/lib/uncached.c
> +++ b/arch/mips/lib/uncached.c
> @@ -44,6 +44,10 @@ unsigned long run_uncached(void *func)
> 
>  	__asm__("move %0, $sp" : "=r" (sp));
> 
> +#if defined(CONFIG_USE_XKPHYS)
> +	if (IS_XKPHYS(sp))
> +		usp = UNCAC_ADDR(sp);

Unnecessary, the else if later is actually handling XKPHYS sp.

> +#else /* defined(CONFIG_USE_XKPHYS) */
>  	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
>  		usp = CKSEG1ADDR(sp);
>  #ifdef CONFIG_64BIT
> @@ -52,10 +56,15 @@ unsigned long run_uncached(void *func)
>  		usp = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>  				     XKPHYS_TO_PHYS((long long)sp));
>  #endif
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  	else {
>  		BUG();
>  		usp = sp;
>  	}
> +#if defined(CONFIG_USE_XKPHYS)
> +	if (IS_XKPHYS(lfunc))
> +		ufunc = UNCAC_ADDR(lfunc);

ditto.

> +#else /* defined(CONFIG_USE_XKPHYS) */
>  	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
>  		ufunc = CKSEG1ADDR(lfunc);
>  #ifdef CONFIG_64BIT
> @@ -64,6 +73,7 @@ unsigned long run_uncached(void *func)
>  		ufunc = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>  				       XKPHYS_TO_PHYS((long long)lfunc));
>  #endif
> +#endif /* defined(CONFIG_USE_XKPHYS) */
>  	else {
>  		BUG();
>  		ufunc = lfunc;
> diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
> index 5dcb525a8995..eb57283ec4e0 100644
> --- a/arch/mips/mm/init.c
> +++ b/arch/mips/mm/init.c
> @@ -427,7 +427,7 @@ void __init paging_init(void)
>  	free_area_init(max_zone_pfns);
>  }
> 
> -#ifdef CONFIG_64BIT
> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>  static struct kcore_list kcore_kseg0;
>  #endif
> 
> @@ -470,7 +470,7 @@ void __init mem_init(void)
>  	setup_zero_pages();	/* Setup zeroed pages.  */
>  	mem_init_free_highmem();
> 
> -#ifdef CONFIG_64BIT
> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>  	if ((unsigned long) &_text > (unsigned long) CKSEG0)
>  		/* The -4 is a hack so that user tools don't have to handle
>  		   the overflow.  */
> -- 
> 2.40.1

Thanks.
Gregory CLEMENT Oct. 23, 2023, 3:45 p.m. UTC | #5
Hello Jiaxun,

> 在2023年10月4日十月 下午5:10,Gregory CLEMENT写道:
>> From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>>
>> Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
>> to trivially map first 1/2 GByte of physical memory. This memory
>> used to run kernel. This mean, one should have memory installed
>> in this area in order for Linux to work.
>>
>> Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
>> to use virtual addresses from the XKPHYS segment for both cached
>> and uncached access. XKPHYS allows to access 2^48 bytes of
>> memory, thus allowing kernel to work with any memory
>> configuration.
>>
>> MIPS CPU sets KX bit in the CP0 status register at reset
>> if RESET_BASE_MODE (BIT 1) set in the GCR_CL_RESET_BASE.
>>
>> Reset vector should fit into 32-bit. If reset vector put outside of
>> KSEG1, BIT(1) should be set in this value.
>>
>> IRQ handler for CPU updated to generate 64-bit address for jump
>
> Please use existing KBUILD_SYM32 symbol.

Could you add more detail ?

Where do you think KBUILD_SYM32 symbol should be used ?

Gregory


>
> Thanks
> - Jiaxun
>
>>
>> Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>> Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
>> ---
>>  arch/mips/Kconfig                 | 15 +++++++++++++
>>  arch/mips/Makefile                |  4 ++++
>>  arch/mips/generic/Platform        |  5 +++++
>>  arch/mips/include/asm/addrspace.h | 12 ++++++++--
>>  arch/mips/include/asm/mips-cm.h   |  1 +
>>  arch/mips/include/asm/page.h      | 10 +++++++++
>>  arch/mips/include/asm/vga.h       |  4 ++++
>>  arch/mips/kernel/cps-vec.S        |  8 +++++++
>>  arch/mips/kernel/genex.S          | 14 ++++++++++++
>>  arch/mips/kernel/smp-cps.c        | 37 +++++++++++++++++++++++--------
>>  arch/mips/kernel/traps.c          | 32 +++++++++++++++++++++++---
>>  arch/mips/lib/uncached.c          | 10 +++++++++
>>  arch/mips/mm/init.c               |  4 ++--
>>  13 files changed, 140 insertions(+), 16 deletions(-)
>>
>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>> index bc8421859006..92832bbcca5d 100644
>> --- a/arch/mips/Kconfig
>> +++ b/arch/mips/Kconfig
>> @@ -2026,6 +2026,21 @@ config 64BIT
>> 
>>  endchoice
>> 
>> +config USE_XKPHYS
>> +	bool "use virtual address from XKPHYS"
>> +	depends on 64BIT
>> +	default n
>> +	help
>> +	 By default, MIPS uses 32-bit compatible segments KSEG0 and KSEG1
>> +	 to trivially map first 1/2 GByte of physical memory. This mean,
>> +	 one should have memory installed in this area in order for Linux to
>> +	 work. With this option selected, kernel uses virtual addresses from
>> +	 the XKPHYS segment for both cached and uncached access. XKPHYS allows
>> +	 to access 2^48 bytes of memory, thus allowing to work with any memory
>> +	 configuration.
>> +
>> +	 Say N if not sure
>> +
>>  config MIPS_VA_BITS_48
>>  	bool "48 bits virtual memory"
>>  	depends on 64BIT
>> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
>> index f49807e1f19b..544ee8427cab 100644
>> --- a/arch/mips/Makefile
>> +++ b/arch/mips/Makefile
>> @@ -303,6 +303,10 @@ ifdef CONFIG_64BIT
>>      endif
>>    endif
>> 
>> +  ifdef CONFIG_USE_XKPHYS
>> +      KBUILD_SYM32 = n
>> +  endif
>> +
>>    ifeq ($(KBUILD_SYM32), y)
>>      cflags-$(KBUILD_SYM32) += -msym32 -DKBUILD_64BIT_SYM32
>>    else
>> diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
>> index 0c03623f3897..2be9947814ad 100644
>> --- a/arch/mips/generic/Platform
>> +++ b/arch/mips/generic/Platform
>> @@ -12,7 +12,12 @@
>>  cflags-$(CONFIG_MACH_INGENIC_SOC)	+= 
>> -I$(srctree)/arch/mips/include/asm/mach-ingenic
>>  cflags-$(CONFIG_MIPS_GENERIC)	+= 
>> -I$(srctree)/arch/mips/include/asm/mach-generic
>> 
>> +ifndef (CONFIG_USE_XKPHYS)
>>  load-$(CONFIG_MIPS_GENERIC)	+= 0xffffffff80100000
>> +else
>> +load-$(CONFIG_MIPS_GENERIC)	+= 0xa800000080100000
>> +endif
>> +
>>  all-$(CONFIG_MIPS_GENERIC)	+= vmlinux.gz.itb
>> 
>>  its-y					:= vmlinux.its.S
>> diff --git a/arch/mips/include/asm/addrspace.h 
>> b/arch/mips/include/asm/addrspace.h
>> index 59a48c60a065..8dc500d8e66d 100644
>> --- a/arch/mips/include/asm/addrspace.h
>> +++ b/arch/mips/include/asm/addrspace.h
>> @@ -65,10 +65,15 @@
>>  #define XKSSEG			_CONST64_(0x4000000000000000)
>>  #define XKPHYS			_CONST64_(0x8000000000000000)
>>  #define XKSEG			_CONST64_(0xc000000000000000)
>> +#if !defined(CONFIG_USE_XKPHYS)
>>  #define CKSEG0			_CONST64_(0xffffffff80000000)
>>  #define CKSEG1			_CONST64_(0xffffffffa0000000)
>>  #define CKSSEG			_CONST64_(0xffffffffc0000000)
>>  #define CKSEG3			_CONST64_(0xffffffffe0000000)
>> +#else
>> +#define CKSEG0			XKPHYS_CM_CACHED
>> +#define CKSEG1			XKPHYS_CM_UNCACHED
>> +#endif /* !defined(CONFIG_USE_XKPHYS) */
>> 
>>  #define CKSEG0ADDR(a)		(CPHYSADDR(a) | CKSEG0)
>>  #define CKSEG1ADDR(a)		(CPHYSADDR(a) | CKSEG1)
>> @@ -126,8 +131,11 @@
>>  #define PHYS_TO_XKSEG_UNCACHED(p)	PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p))
>>  #define PHYS_TO_XKSEG_CACHED(p)		PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p))
>>  #define XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK)
>> -#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS | (_ACAST64_(cm) << 59) | (a))
>> -
>> +#define XKPHYS_CM(cm)			(XKPHYS | (_ACAST64_(cm) << 59))
>> +#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS_CM(cm) | (a))
>> +#define XKPHYS_CM_CACHED		(XKPHYS_CM(K_CALG_COH_SHAREABLE))
>> +#define XKPHYS_CM_UNCACHED		(XKPHYS_CM(K_CALG_UNCACHED))
>> +#define IS_XKPHYS(a)			(((a) >> 62) == 2)
>>  /*
>>   * The ultimate limited of the 64-bit MIPS architecture:  2 bits for selecting
>>   * the region, 3 bits for the CCA mode.  This leaves 59 bits of which the
>> diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
>> index 23c67c0871b1..15d8d69de455 100644
>> --- a/arch/mips/include/asm/mips-cm.h
>> +++ b/arch/mips/include/asm/mips-cm.h
>> @@ -311,6 +311,7 @@ GCR_CX_ACCESSOR_RW(32, 0x018, other)
>>  /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */
>>  GCR_CX_ACCESSOR_RW(32, 0x020, reset_base)
>>  #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE		GENMASK(31, 12)
>> +#define CM_GCR_Cx_RESET_BASE_MODE		BIT(1)
>> 
>>  /* GCR_Cx_ID - Identify the current core */
>>  GCR_CX_ACCESSOR_RO(32, 0x028, id)
>> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
>> index 5978a8dfb917..53b8306da571 100644
>> --- a/arch/mips/include/asm/page.h
>> +++ b/arch/mips/include/asm/page.h
>> @@ -176,7 +176,11 @@ static inline unsigned long ___pa(unsigned long x)
>>  		 * the compatibility segements ckseg0 or ckseg1, or it may
>>  		 * be in xkphys.
>>  		 */
>> +#if defined(CONFIG_USE_XKPHYS)
>> +		return XPHYSADDR(x);
>> +#else
>>  		return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
>> +#endif
>>  	}
>> 
>>  	if (!IS_ENABLED(CONFIG_EVA)) {
>> @@ -196,7 +200,11 @@ static inline unsigned long ___pa(unsigned long x)
>>  	return x - PAGE_OFFSET + PHYS_OFFSET;
>>  }
>>  #define __pa(x)		___pa((unsigned long)(x))
>> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
>> +#define __va(x)		((void *)PHYS_TO_XKSEG_CACHED(x))
>> +#else
>>  #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
>> +#endif
>>  #include <asm/io.h>
>> 
>>  /*
>> @@ -239,6 +247,8 @@ static inline unsigned long kaslr_offset(void)
>>  	return __kaslr_offset;
>>  }
>> 
>> +#define UNCAC_ADDR(addr)       (UNCAC_BASE + __pa(addr))
>> +
>>  #include <asm-generic/memory_model.h>
>>  #include <asm-generic/getorder.h>
>> 
>> diff --git a/arch/mips/include/asm/vga.h b/arch/mips/include/asm/vga.h
>> index 0136e0366698..e338e57d0784 100644
>> --- a/arch/mips/include/asm/vga.h
>> +++ b/arch/mips/include/asm/vga.h
>> @@ -16,7 +16,11 @@
>>   *	access the videoram directly without any black magic.
>>   */
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +#define VGA_MAP_MEM(x, s)	UNCAC_ADDR(0x10000000L + (unsigned long)(x))
>> +#else
>>  #define VGA_MAP_MEM(x, s)	CKSEG1ADDR(0x10000000L + (unsigned long)(x))
>> +#endif
>> 
>>  #define vga_readb(x)	(*(x))
>>  #define vga_writeb(x, y)	(*(y) = (x))
>> diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
>> index 64ecfdac6580..541f31a43a7f 100644
>> --- a/arch/mips/kernel/cps-vec.S
>> +++ b/arch/mips/kernel/cps-vec.S
>> @@ -554,7 +554,11 @@ LEAF(mips_cps_cache_init)
>>  	mul	t1, t1, t0
>>  	mul	t1, t1, t2
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	PTR_LI	a0, XKPHYS_CM_CACHED
>> +#else
>>  	li	a0, CKSEG0
>> +#endif
>>  	PTR_ADD	a1, a0, t1
>>  1:	cache	Index_Store_Tag_I, 0(a0)
>>  	PTR_ADD	a0, a0, t0
>> @@ -581,7 +585,11 @@ icache_done:
>>  	mul	t1, t1, t0
>>  	mul	t1, t1, t2
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	PTR_LI	a0, XKPHYS_CM_CACHED
>> +#else
>>  	li	a0, CKSEG0
>> +#endif
>>  	PTR_ADDU a1, a0, t1
>>  	PTR_SUBU a1, a1, t0
>>  1:	cache	Index_Store_Tag_D, 0(a0)
>> diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
>> index b6de8e88c1bd..a002058e1838 100644
>> --- a/arch/mips/kernel/genex.S
>> +++ b/arch/mips/kernel/genex.S
>> @@ -272,11 +272,25 @@ NESTED(except_vec_vi, 0, sp)
>>  	.set	push
>>  	.set	noreorder
>>  	PTR_LA	v1, except_vec_vi_handler
>> +#if defined(CONFIG_USE_XKPHYS)
>> +FEXPORT(except_vec_vi_63_48)
>> +	lui	v0, 0		/* Patched - bits 63:48 */
>> +FEXPORT(except_vec_vi_47_32)
>> +	ori	v0, 0		/* Patched - bits 47:32 */
>> +	dsll	v0, v0, 0x10
>> +FEXPORT(except_vec_vi_31_16)
>> +	ori	v0, 0		/* Patched - bits 31:16 */
>> +	dsll	v0, v0, 0x10
>> +	jr	v1
>> +FEXPORT(except_vec_vi_15_0)
>> +	ori	v0, 0		/* Patched - bits 15:0 */
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  FEXPORT(except_vec_vi_lui)
>>  	lui	v0, 0		/* Patched */
>>  	jr	v1
>>  FEXPORT(except_vec_vi_ori)
>>  	 ori	v0, 0		/* Patched */
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  	.set	pop
>>  	END(except_vec_vi)
>>  EXPORT(except_vec_vi_end)
>> diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
>> index dd55d59b88db..47e76722a306 100644
>> --- a/arch/mips/kernel/smp-cps.c
>> +++ b/arch/mips/kernel/smp-cps.c
>> @@ -34,10 +34,33 @@ static unsigned __init core_vpe_count(unsigned int 
>> cluster, unsigned core)
>>  	return min(smp_max_threads, mips_cps_numvps(cluster, core));
>>  }
>> 
>> +/**
>> + * plat_core_entry - query reset vector for NMI/reset
>> + *
>> + * Returns low 32 bits of the reset vector
>> + *
>> + * This is used to fill 2 registers:
>> + * - BEV Base (GCR_BEV_BASE) Offset: 0x0680
>> + * - VP Local Reset Exception Base (GCR_CL_RESET_BASE,GCR_CO_RESET_BASE)
>> + *   Offset: 0x0020 (0x2020 relative to GCR_BASE_ADDR)
>> + *
>> + * In both registers, BIT(1) should be set in case it uses address in XKPHYS
>> + * (as opposed to KSEG1). This bit defined as CM_GCR_Cx_RESET_BASE_MODE,
>> + * using it unconditionally because for GCR_BEV_BASE its value is the same
>> + */
>> +static u32 plat_core_entry(void)
>> +{
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	return (UNCAC_ADDR(mips_cps_core_entry) & 0xffffffff)
>> +			| CM_GCR_Cx_RESET_BASE_MODE;
>> +#else
>> +	return CKSEG1ADDR((unsigned long)mips_cps_core_entry);
>> +#endif
>> +}
>> +
>>  static void __init cps_smp_setup(void)
>>  {
>>  	unsigned int nclusters, ncores, nvpes, core_vpes;
>> -	unsigned long core_entry;
>>  	int cl, c, v;
>> 
>>  	/* Detect & record VPE topology */
>> @@ -94,10 +117,8 @@ static void __init cps_smp_setup(void)
>>  	/* Make core 0 coherent with everything */
>>  	write_gcr_cl_coherence(0xff);
>> 
>> -	if (mips_cm_revision() >= CM_REV_CM3) {
>> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
>> -		write_gcr_bev_base(core_entry);
>> -	}
>> +	if (mips_cm_revision() >= CM_REV_CM3)
>> +		write_gcr_bev_base(plat_core_entry());
>> 
>>  #ifdef CONFIG_MIPS_MT_FPAFF
>>  	/* If we have an FPU, enroll ourselves in the FPU-full mask */
>> @@ -213,7 +234,7 @@ static void boot_core(unsigned int core, unsigned 
>> int vpe_id)
>>  	mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
>> 
>>  	/* Set its reset vector */
>> -	write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
>> +	write_gcr_co_reset_base(plat_core_entry());
>> 
>>  	/* Ensure its coherency is disabled */
>>  	write_gcr_co_coherence(0);
>> @@ -290,7 +311,6 @@ static int cps_boot_secondary(int cpu, struct 
>> task_struct *idle)
>>  	unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
>>  	struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
>>  	struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
>> -	unsigned long core_entry;
>>  	unsigned int remote;
>>  	int err;
>> 
>> @@ -314,8 +334,7 @@ static int cps_boot_secondary(int cpu, struct 
>> task_struct *idle)
>> 
>>  	if (cpu_has_vp) {
>>  		mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
>> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
>> -		write_gcr_co_reset_base(core_entry);
>> +		write_gcr_co_reset_base(plat_core_entry());
>>  		mips_cm_unlock_other();
>>  	}
>> 
>> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
>> index 246c6a6b0261..875594843626 100644
>> --- a/arch/mips/kernel/traps.c
>> +++ b/arch/mips/kernel/traps.c
>> @@ -2091,11 +2091,20 @@ static void *set_vi_srs_handler(int n, 
>> vi_handler_t addr, int srs)
>>  		 * If no shadow set is selected then use the default handler
>>  		 * that does normal register saving and standard interrupt exit
>>  		 */
>> -		extern const u8 except_vec_vi[], except_vec_vi_lui[];
>> -		extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
>> +		extern const u8 except_vec_vi[], except_vec_vi_end[];
>>  		extern const u8 rollback_except_vec_vi[];
>>  		const u8 *vec_start = using_rollback_handler() ?
>>  				      rollback_except_vec_vi : except_vec_vi;
>> +		const int handler_len = except_vec_vi_end - vec_start;
>> +#if defined(CONFIG_USE_XKPHYS)
>> +		extern const u8 except_vec_vi_63_48[], except_vec_vi_47_32[];
>> +		extern const u8 except_vec_vi_31_16[], except_vec_vi_15_0[];
>> +		const int offset_63_48 = except_vec_vi_63_48 - vec_start;
>> +		const int offset_47_32 = except_vec_vi_47_32 - vec_start;
>> +		const int offset_31_16 = except_vec_vi_31_16 - vec_start;
>> +		const int offset_15_0  = except_vec_vi_15_0  - vec_start;
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>> +		extern const u8 except_vec_vi_lui[], except_vec_vi_ori[];
>>  #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
>>  		const int lui_offset = except_vec_vi_lui - vec_start + 2;
>>  		const int ori_offset = except_vec_vi_ori - vec_start + 2;
>> @@ -2103,7 +2112,7 @@ static void *set_vi_srs_handler(int n, 
>> vi_handler_t addr, int srs)
>>  		const int lui_offset = except_vec_vi_lui - vec_start;
>>  		const int ori_offset = except_vec_vi_ori - vec_start;
>>  #endif
>> -		const int handler_len = except_vec_vi_end - vec_start;
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>> 
>>  		if (handler_len > VECTORSPACING) {
>>  			/*
>> @@ -2119,10 +2128,21 @@ static void *set_vi_srs_handler(int n, 
>> vi_handler_t addr, int srs)
>>  #else
>>  				handler_len);
>>  #endif
>> +#if defined(CONFIG_USE_XKPHYS)
>> +		h = (u16 *)(b + offset_63_48);
>> +		*h = (handler >> 48) & 0xffff;
>> +		h = (u16 *)(b + offset_47_32);
>> +		*h = (handler >> 32) & 0xffff;
>> +		h = (u16 *)(b + offset_31_16);
>> +		*h = (handler >> 16) & 0xffff;
>> +		h = (u16 *)(b + offset_15_0);
>> +		*h = (handler >> 0) & 0xffff;
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  		h = (u16 *)(b + lui_offset);
>>  		*h = (handler >> 16) & 0xffff;
>>  		h = (u16 *)(b + ori_offset);
>>  		*h = (handler & 0xffff);
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  		local_flush_icache_range((unsigned long)b,
>>  					 (unsigned long)(b+handler_len));
>>  	}
>> @@ -2332,7 +2352,11 @@ static const char panic_null_cerr[] =
>>  void set_uncached_handler(unsigned long offset, void *addr,
>>  	unsigned long size)
>>  {
>> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
>> +	unsigned long uncached_ebase = UNCAC_ADDR(ebase);
>> +#else
>>  	unsigned long uncached_ebase = CKSEG1ADDR(ebase);
>> +#endif
>> 
>>  	if (!addr)
>>  		panic(panic_null_cerr);
>> @@ -2384,9 +2408,11 @@ void __init trap_init(void)
>>  		 * EVA is special though as it allows segments to be rearranged
>>  		 * and to become uncached during cache error handling.
>>  		 */
>> +#if !defined(CONFIG_USE_XKPHYS)
>>  		if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000))
>>  			ebase = CKSEG0ADDR(ebase_pa);
>>  		else
>> +#endif
>>  			ebase = (unsigned long)phys_to_virt(ebase_pa);
>>  	}
>> 
>> diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
>> index f80a67c092b6..8a78348a2dd7 100644
>> --- a/arch/mips/lib/uncached.c
>> +++ b/arch/mips/lib/uncached.c
>> @@ -44,6 +44,10 @@ unsigned long run_uncached(void *func)
>> 
>>  	__asm__("move %0, $sp" : "=r" (sp));
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	if (IS_XKPHYS(sp))
>> +		usp = UNCAC_ADDR(sp);
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
>>  		usp = CKSEG1ADDR(sp);
>>  #ifdef CONFIG_64BIT
>> @@ -52,10 +56,15 @@ unsigned long run_uncached(void *func)
>>  		usp = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>>  				     XKPHYS_TO_PHYS((long long)sp));
>>  #endif
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  	else {
>>  		BUG();
>>  		usp = sp;
>>  	}
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	if (IS_XKPHYS(lfunc))
>> +		ufunc = UNCAC_ADDR(lfunc);
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
>>  		ufunc = CKSEG1ADDR(lfunc);
>>  #ifdef CONFIG_64BIT
>> @@ -64,6 +73,7 @@ unsigned long run_uncached(void *func)
>>  		ufunc = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>>  				       XKPHYS_TO_PHYS((long long)lfunc));
>>  #endif
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  	else {
>>  		BUG();
>>  		ufunc = lfunc;
>> diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
>> index 5dcb525a8995..eb57283ec4e0 100644
>> --- a/arch/mips/mm/init.c
>> +++ b/arch/mips/mm/init.c
>> @@ -427,7 +427,7 @@ void __init paging_init(void)
>>  	free_area_init(max_zone_pfns);
>>  }
>> 
>> -#ifdef CONFIG_64BIT
>> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>>  static struct kcore_list kcore_kseg0;
>>  #endif
>> 
>> @@ -470,7 +470,7 @@ void __init mem_init(void)
>>  	setup_zero_pages();	/* Setup zeroed pages.  */
>>  	mem_init_free_highmem();
>> 
>> -#ifdef CONFIG_64BIT
>> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>>  	if ((unsigned long) &_text > (unsigned long) CKSEG0)
>>  		/* The -4 is a hack so that user tools don't have to handle
>>  		   the overflow.  */
>> -- 
>> 2.40.1
>
> -- 
> - Jiaxun
Gregory CLEMENT Oct. 24, 2023, 4:08 p.m. UTC | #6
"Jiaxun Yang" <jiaxun.yang@flygoat.com> writes:

> 在2023年10月4日十月 下午5:10,Gregory CLEMENT写道:
>> From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>>
>> Now 64-bit MIPS uses 32-bit compatible segments KSEG0 and KSEG1
>> to trivially map first 1/2 GByte of physical memory. This memory
>> used to run kernel. This mean, one should have memory installed
>> in this area in order for Linux to work.
>>
>> Kconfig CONFIG_USE_XKPHYS introduced; it adds support for kernel
>> to use virtual addresses from the XKPHYS segment for both cached
>> and uncached access. XKPHYS allows to access 2^48 bytes of
>> memory, thus allowing kernel to work with any memory
>> configuration.
>>
>> MIPS CPU sets KX bit in the CP0 status register at reset
>> if RESET_BASE_MODE (BIT 1) set in the GCR_CL_RESET_BASE.
>>
>> Reset vector should fit into 32-bit. If reset vector put outside of
>> KSEG1, BIT(1) should be set in this value.
>>
>> IRQ handler for CPU updated to generate 64-bit address for jump
>
> So I just spend some time to review and test this patch on QEMU,
> comments below:

Thanks for your time.

>
>>
>> Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
>> Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
>> ---
>>  arch/mips/Kconfig                 | 15 +++++++++++++
>>  arch/mips/Makefile                |  4 ++++
>>  arch/mips/generic/Platform        |  5 +++++
>>  arch/mips/include/asm/addrspace.h | 12 ++++++++--
>>  arch/mips/include/asm/mips-cm.h   |  1 +
>>  arch/mips/include/asm/page.h      | 10 +++++++++
>>  arch/mips/include/asm/vga.h       |  4 ++++
>>  arch/mips/kernel/cps-vec.S        |  8 +++++++
>>  arch/mips/kernel/genex.S          | 14 ++++++++++++
>>  arch/mips/kernel/smp-cps.c        | 37 +++++++++++++++++++++++--------
>>  arch/mips/kernel/traps.c          | 32 +++++++++++++++++++++++---
>>  arch/mips/lib/uncached.c          | 10 +++++++++
>>  arch/mips/mm/init.c               |  4 ++--
>>  13 files changed, 140 insertions(+), 16 deletions(-)
>>
>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>> index bc8421859006..92832bbcca5d 100644
>> --- a/arch/mips/Kconfig
>> +++ b/arch/mips/Kconfig
>> @@ -2026,6 +2026,21 @@ config 64BIT
>> 
>>  endchoice
>> 
>> +config USE_XKPHYS
>> +	bool "use virtual address from XKPHYS"
>> +	depends on 64BIT
>> +	default n
>> +	help
>> +	 By default, MIPS uses 32-bit compatible segments KSEG0 and KSEG1
>> +	 to trivially map first 1/2 GByte of physical memory. This mean,
>> +	 one should have memory installed in this area in order for Linux to
>> +	 work. With this option selected, kernel uses virtual addresses from
>> +	 the XKPHYS segment for both cached and uncached access. XKPHYS allows
>> +	 to access 2^48 bytes of memory, thus allowing to work with any memory
>> +	 configuration.
>> +
>> +	 Say N if not sure
>> +
>>  config MIPS_VA_BITS_48
>>  	bool "48 bits virtual memory"
>>  	depends on 64BIT
>> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
>> index f49807e1f19b..544ee8427cab 100644
>> --- a/arch/mips/Makefile
>> +++ b/arch/mips/Makefile
>> @@ -303,6 +303,10 @@ ifdef CONFIG_64BIT
>>      endif
>>    endif
>> 
>> +  ifdef CONFIG_USE_XKPHYS
>> +      KBUILD_SYM32 = n
>> +  endif
>> +
>>    ifeq ($(KBUILD_SYM32), y)
>>      cflags-$(KBUILD_SYM32) += -msym32 -DKBUILD_64BIT_SYM32
>>    else
>> diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
>> index 0c03623f3897..2be9947814ad 100644
>> --- a/arch/mips/generic/Platform
>> +++ b/arch/mips/generic/Platform
>> @@ -12,7 +12,12 @@
>>  cflags-$(CONFIG_MACH_INGENIC_SOC)	+= 
>> -I$(srctree)/arch/mips/include/asm/mach-ingenic
>>  cflags-$(CONFIG_MIPS_GENERIC)	+= 
>> -I$(srctree)/arch/mips/include/asm/mach-generic
>> 
>> +ifndef (CONFIG_USE_XKPHYS)
>>  load-$(CONFIG_MIPS_GENERIC)	+= 0xffffffff80100000
>> +else
>> +load-$(CONFIG_MIPS_GENERIC)	+= 0xa800000080100000
>> +endif
>
> Better to make load address configurable.

OK I prepared a patch for it.

>
>> +
>>  all-$(CONFIG_MIPS_GENERIC)	+= vmlinux.gz.itb
>> 
>>  its-y					:= vmlinux.its.S
>> diff --git a/arch/mips/include/asm/addrspace.h 
>> b/arch/mips/include/asm/addrspace.h
>> index 59a48c60a065..8dc500d8e66d 100644
>> --- a/arch/mips/include/asm/addrspace.h
>> +++ b/arch/mips/include/asm/addrspace.h
>> @@ -65,10 +65,15 @@
>>  #define XKSSEG			_CONST64_(0x4000000000000000)
>>  #define XKPHYS			_CONST64_(0x8000000000000000)
>>  #define XKSEG			_CONST64_(0xc000000000000000)
>> +#if !defined(CONFIG_USE_XKPHYS)
>>  #define CKSEG0			_CONST64_(0xffffffff80000000)
>>  #define CKSEG1			_CONST64_(0xffffffffa0000000)
>>  #define CKSSEG			_CONST64_(0xffffffffc0000000)
>>  #define CKSEG3			_CONST64_(0xffffffffe0000000)
>> +#else
>> +#define CKSEG0			XKPHYS_CM_CACHED
>> +#define CKSEG1			XKPHYS_CM_UNCACHED
>> +#endif /* !defined(CONFIG_USE_XKPHYS) */
>> 
>>  #define CKSEG0ADDR(a)		(CPHYSADDR(a) | CKSEG0)
>>  #define CKSEG1ADDR(a)		(CPHYSADDR(a) | CKSEG1)
>> @@ -126,8 +131,11 @@
>>  #define PHYS_TO_XKSEG_UNCACHED(p)	PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p))
>>  #define PHYS_TO_XKSEG_CACHED(p)		PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p))
>>  #define XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK)
>> -#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS | (_ACAST64_(cm) << 59) | (a))
>> -
>> +#define XKPHYS_CM(cm)			(XKPHYS | (_ACAST64_(cm) << 59))
>> +#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS_CM(cm) | (a))
>> +#define XKPHYS_CM_CACHED		(XKPHYS_CM(K_CALG_COH_SHAREABLE))
>> +#define XKPHYS_CM_UNCACHED		(XKPHYS_CM(K_CALG_UNCACHED))
>> +#define IS_XKPHYS(a)			(((a) >> 62) == 2)
>>  /*
>>   * The ultimate limited of the 64-bit MIPS architecture:  2 bits for selecting
>>   * the region, 3 bits for the CCA mode.  This leaves 59 bits of which the
>> diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
>> index 23c67c0871b1..15d8d69de455 100644
>> --- a/arch/mips/include/asm/mips-cm.h 
>> +++ b/arch/mips/include/asm/mips-cm.h
>> @@ -311,6 +311,7 @@ GCR_CX_ACCESSOR_RW(32, 0x018, other)
>>  /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */
>>  GCR_CX_ACCESSOR_RW(32, 0x020, reset_base)
>>  #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE		GENMASK(31, 12)
>> +#define CM_GCR_Cx_RESET_BASE_MODE		BIT(1)
>> 
>>  /* GCR_Cx_ID - Identify the current core */
>>  GCR_CX_ACCESSOR_RO(32, 0x028, id)
>> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
>> index 5978a8dfb917..53b8306da571 100644
>> --- a/arch/mips/include/asm/page.h
>> +++ b/arch/mips/include/asm/page.h
>> @@ -176,7 +176,11 @@ static inline unsigned long ___pa(unsigned long x)
>>  		 * the compatibility segements ckseg0 or ckseg1, or it may
>>  		 * be in xkphys.
>>  		 */
>> +#if defined(CONFIG_USE_XKPHYS)
>> +		return XPHYSADDR(x);
>> +#else
>>  		return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
>> +#endif
>
> Dangerous, there might be some code passing KSEG0/1 address to __pa, so
> we should not disregard it.

I don't see any code doing it, but to be safe I will remove it.

>
>>  	}
>> 
>>  	if (!IS_ENABLED(CONFIG_EVA)) {
>> @@ -196,7 +200,11 @@ static inline unsigned long ___pa(unsigned long x)
>>  	return x - PAGE_OFFSET + PHYS_OFFSET;
>>  }
>>  #define __pa(x)		___pa((unsigned long)(x))
>> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
>> +#define __va(x)		((void *)PHYS_TO_XKSEG_CACHED(x))
>> +#else
>>  #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
>> +#endif
>
> PAGE_OFFSET resolves to CAC_BASE anyway, so unnecessary.

OK, there was a lot of indirection but in the end it almost the same
indeed.

Gregory

>
>>  #include <asm/io.h>
>> 
>>  /*
>> @@ -239,6 +247,8 @@ static inline unsigned long kaslr_offset(void)
>>  	return __kaslr_offset;
>>  }
>> 
>> +#define UNCAC_ADDR(addr)       (UNCAC_BASE + __pa(addr))
>> +
>>  #include <asm-generic/memory_model.h>
>>  #include <asm-generic/getorder.h>
>> 
>> diff --git a/arch/mips/include/asm/vga.h b/arch/mips/include/asm/vga.h
>> index 0136e0366698..e338e57d0784 100644
>> --- a/arch/mips/include/asm/vga.h
>> +++ b/arch/mips/include/asm/vga.h
>> @@ -16,7 +16,11 @@
>>   *	access the videoram directly without any black magic.
>>   */
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +#define VGA_MAP_MEM(x, s)	UNCAC_ADDR(0x10000000L + (unsigned long)(x))
>> +#else
>>  #define VGA_MAP_MEM(x, s)	CKSEG1ADDR(0x10000000L + (unsigned long)(x))
>> +#endif
>
> VGA_MAP_MEM intends to work on some really legacy systems, it won't break
> your platform, so better leave it as is.

OK maybe I will still put a comment here.

>
>> 
>>  #define vga_readb(x)	(*(x))
>>  #define vga_writeb(x, y)	(*(y) = (x))
>> diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
>> index 64ecfdac6580..541f31a43a7f 100644
>> --- a/arch/mips/kernel/cps-vec.S
>> +++ b/arch/mips/kernel/cps-vec.S
>> @@ -554,7 +554,11 @@ LEAF(mips_cps_cache_init)
>>  	mul	t1, t1, t0
>>  	mul	t1, t1, t2
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	PTR_LI	a0, XKPHYS_CM_CACHED
>> +#else
>>  	li	a0, CKSEG0
>> +#endif
>
> Unnecessary, KSEG0 address here are just for matching cache ways,
> so there is no difference to use KSEG0 or XKPHYS.
>
> If you are using XKPHYS here you must extarct CCA from bootinfo
> or CP0 as it may varies on different systems.
>
>>  	PTR_ADD	a1, a0, t1
>>  1:	cache	Index_Store_Tag_I, 0(a0)
>>  	PTR_ADD	a0, a0, t0
>> @@ -581,7 +585,11 @@ icache_done:
>>  	mul	t1, t1, t0
>>  	mul	t1, t1, t2
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	PTR_LI	a0, XKPHYS_CM_CACHED
>> +#else
>
> Ditto.
>
>>  	li	a0, CKSEG0
>> +#endif
>>  	PTR_ADDU a1, a0, t1
>>  	PTR_SUBU a1, a1, t0
>>  1:	cache	Index_Store_Tag_D, 0(a0)
>> diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
>> index b6de8e88c1bd..a002058e1838 100644
>> --- a/arch/mips/kernel/genex.S
>> +++ b/arch/mips/kernel/genex.S
>> @@ -272,11 +272,25 @@ NESTED(except_vec_vi, 0, sp)
>>  	.set	push
>>  	.set	noreorder
>>  	PTR_LA	v1, except_vec_vi_handler
>> +#if defined(CONFIG_USE_XKPHYS)
>> +FEXPORT(except_vec_vi_63_48)
>> +	lui	v0, 0		/* Patched - bits 63:48 */
>> +FEXPORT(except_vec_vi_47_32)
>> +	ori	v0, 0		/* Patched - bits 47:32 */
>> +	dsll	v0, v0, 0x10
>> +FEXPORT(except_vec_vi_31_16)
>> +	ori	v0, 0		/* Patched - bits 31:16 */
>> +	dsll	v0, v0, 0x10
>> +	jr	v1
>> +FEXPORT(except_vec_vi_15_0)
>> +	ori	v0, 0		/* Patched - bits 15:0 */
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  FEXPORT(except_vec_vi_lui)
>>  	lui	v0, 0		/* Patched */
>>  	jr	v1
>>  FEXPORT(except_vec_vi_ori)
>>  	 ori	v0, 0		/* Patched */
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  	.set	pop
>>  	END(except_vec_vi)
>>  EXPORT(except_vec_vi_end)
>> diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
>> index dd55d59b88db..47e76722a306 100644
>> --- a/arch/mips/kernel/smp-cps.c
>> +++ b/arch/mips/kernel/smp-cps.c
>> @@ -34,10 +34,33 @@ static unsigned __init core_vpe_count(unsigned int 
>> cluster, unsigned core)
>>  	return min(smp_max_threads, mips_cps_numvps(cluster, core));
>>  }
>> 
>> +/**
>> + * plat_core_entry - query reset vector for NMI/reset
>> + *
>> + * Returns low 32 bits of the reset vector
>> + *
>> + * This is used to fill 2 registers:
>> + * - BEV Base (GCR_BEV_BASE) Offset: 0x0680
>> + * - VP Local Reset Exception Base (GCR_CL_RESET_BASE,GCR_CO_RESET_BASE)
>> + *   Offset: 0x0020 (0x2020 relative to GCR_BASE_ADDR)
>> + *
>> + * In both registers, BIT(1) should be set in case it uses address in XKPHYS
>> + * (as opposed to KSEG1). This bit defined as CM_GCR_Cx_RESET_BASE_MODE,
>> + * using it unconditionally because for GCR_BEV_BASE its value is the same
>> + */
>> +static u32 plat_core_entry(void)
>> +{
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	return (UNCAC_ADDR(mips_cps_core_entry) & 0xffffffff)
>> +			| CM_GCR_Cx_RESET_BASE_MODE;
>> +#else
>> +	return CKSEG1ADDR((unsigned long)mips_cps_core_entry);
>> +#endif
>
> This is a CM3 feature, so perhaps we should handle it in a general
> way.
>
>> +}
>> +
>>  static void __init cps_smp_setup(void)
>>  {
>>  	unsigned int nclusters, ncores, nvpes, core_vpes;
>> -	unsigned long core_entry;
>>  	int cl, c, v;
>> 
>>  	/* Detect & record VPE topology */
>> @@ -94,10 +117,8 @@ static void __init cps_smp_setup(void)
>>  	/* Make core 0 coherent with everything */
>>  	write_gcr_cl_coherence(0xff);
>> 
>> -	if (mips_cm_revision() >= CM_REV_CM3) {
>> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
>> -		write_gcr_bev_base(core_entry);
>> -	}
>> +	if (mips_cm_revision() >= CM_REV_CM3)
>> +		write_gcr_bev_base(plat_core_entry());
>> 
>>  #ifdef CONFIG_MIPS_MT_FPAFF
>>  	/* If we have an FPU, enroll ourselves in the FPU-full mask */
>> @@ -213,7 +234,7 @@ static void boot_core(unsigned int core, unsigned 
>> int vpe_id)
>>  	mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
>> 
>>  	/* Set its reset vector */
>> -	write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
>> +	write_gcr_co_reset_base(plat_core_entry());
>> 
>>  	/* Ensure its coherency is disabled */
>>  	write_gcr_co_coherence(0);
>> @@ -290,7 +311,6 @@ static int cps_boot_secondary(int cpu, struct 
>> task_struct *idle)
>>  	unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
>>  	struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
>>  	struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
>> -	unsigned long core_entry;
>>  	unsigned int remote;
>>  	int err;
>> 
>> @@ -314,8 +334,7 @@ static int cps_boot_secondary(int cpu, struct 
>> task_struct *idle)
>> 
>>  	if (cpu_has_vp) {
>>  		mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
>> -		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
>> -		write_gcr_co_reset_base(core_entry);
>> +		write_gcr_co_reset_base(plat_core_entry());
>>  		mips_cm_unlock_other();
>>  	}
>> 
>> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
>> index 246c6a6b0261..875594843626 100644
>> --- a/arch/mips/kernel/traps.c
>> +++ b/arch/mips/kernel/traps.c
>> @@ -2091,11 +2091,20 @@ static void *set_vi_srs_handler(int n, 
>> vi_handler_t addr, int srs)
>>  		 * If no shadow set is selected then use the default handler
>>  		 * that does normal register saving and standard interrupt exit
>>  		 */
>> -		extern const u8 except_vec_vi[], except_vec_vi_lui[];
>> -		extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
>> +		extern const u8 except_vec_vi[], except_vec_vi_end[];
>>  		extern const u8 rollback_except_vec_vi[];
>>  		const u8 *vec_start = using_rollback_handler() ?
>>  				      rollback_except_vec_vi : except_vec_vi;
>> +		const int handler_len = except_vec_vi_end - vec_start;
>> +#if defined(CONFIG_USE_XKPHYS)
>> +		extern const u8 except_vec_vi_63_48[], except_vec_vi_47_32[];
>> +		extern const u8 except_vec_vi_31_16[], except_vec_vi_15_0[];
>> +		const int offset_63_48 = except_vec_vi_63_48 - vec_start;
>> +		const int offset_47_32 = except_vec_vi_47_32 - vec_start;
>> +		const int offset_31_16 = except_vec_vi_31_16 - vec_start;
>> +		const int offset_15_0  = except_vec_vi_15_0  - vec_start;
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>> +		extern const u8 except_vec_vi_lui[], except_vec_vi_ori[];
>>  #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
>>  		const int lui_offset = except_vec_vi_lui - vec_start + 2;
>>  		const int ori_offset = except_vec_vi_ori - vec_start + 2;
>> @@ -2103,7 +2112,7 @@ static void *set_vi_srs_handler(int n, 
>> vi_handler_t addr, int srs)
>>  		const int lui_offset = except_vec_vi_lui - vec_start;
>>  		const int ori_offset = except_vec_vi_ori - vec_start;
>>  #endif
>> -		const int handler_len = except_vec_vi_end - vec_start;
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>> 
>>  		if (handler_len > VECTORSPACING) {
>>  			/*
>> @@ -2119,10 +2128,21 @@ static void *set_vi_srs_handler(int n, 
>> vi_handler_t addr, int srs)
>>  #else
>>  				handler_len);
>>  #endif
>> +#if defined(CONFIG_USE_XKPHYS)
>> +		h = (u16 *)(b + offset_63_48);
>> +		*h = (handler >> 48) & 0xffff;
>> +		h = (u16 *)(b + offset_47_32);
>> +		*h = (handler >> 32) & 0xffff;
>> +		h = (u16 *)(b + offset_31_16);
>> +		*h = (handler >> 16) & 0xffff;
>> +		h = (u16 *)(b + offset_15_0);
>> +		*h = (handler >> 0) & 0xffff;
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  		h = (u16 *)(b + lui_offset);
>>  		*h = (handler >> 16) & 0xffff;
>>  		h = (u16 *)(b + ori_offset);
>>  		*h = (handler & 0xffff);
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  		local_flush_icache_range((unsigned long)b,
>>  					 (unsigned long)(b+handler_len));
>>  	}
>> @@ -2332,7 +2352,11 @@ static const char panic_null_cerr[] =
>>  void set_uncached_handler(unsigned long offset, void *addr,
>>  	unsigned long size)
>>  {
>> +#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
>> +	unsigned long uncached_ebase = UNCAC_ADDR(ebase);
>> +#else
>>  	unsigned long uncached_ebase = CKSEG1ADDR(ebase);
>> +#endif
>> 
>>  	if (!addr)
>>  		panic(panic_null_cerr);
>> @@ -2384,9 +2408,11 @@ void __init trap_init(void)
>>  		 * EVA is special though as it allows segments to be rearranged
>>  		 * and to become uncached during cache error handling.
>>  		 */
>> +#if !defined(CONFIG_USE_XKPHYS)
>>  		if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000))
>>  			ebase = CKSEG0ADDR(ebase_pa);
>>  		else
>> +#endif
>>  			ebase = (unsigned long)phys_to_virt(ebase_pa);
>>  	}
>> 
>> diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
>> index f80a67c092b6..8a78348a2dd7 100644
>> --- a/arch/mips/lib/uncached.c
>> +++ b/arch/mips/lib/uncached.c
>> @@ -44,6 +44,10 @@ unsigned long run_uncached(void *func)
>> 
>>  	__asm__("move %0, $sp" : "=r" (sp));
>> 
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	if (IS_XKPHYS(sp))
>> +		usp = UNCAC_ADDR(sp);
>
> Unnecessary, the else if later is actually handling XKPHYS sp.
>
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
>>  		usp = CKSEG1ADDR(sp);
>>  #ifdef CONFIG_64BIT
>> @@ -52,10 +56,15 @@ unsigned long run_uncached(void *func)
>>  		usp = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>>  				     XKPHYS_TO_PHYS((long long)sp));
>>  #endif
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  	else {
>>  		BUG();
>>  		usp = sp;
>>  	}
>> +#if defined(CONFIG_USE_XKPHYS)
>> +	if (IS_XKPHYS(lfunc))
>> +		ufunc = UNCAC_ADDR(lfunc);
>
> ditto.
>
>> +#else /* defined(CONFIG_USE_XKPHYS) */
>>  	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
>>  		ufunc = CKSEG1ADDR(lfunc);
>>  #ifdef CONFIG_64BIT
>> @@ -64,6 +73,7 @@ unsigned long run_uncached(void *func)
>>  		ufunc = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
>>  				       XKPHYS_TO_PHYS((long long)lfunc));
>>  #endif
>> +#endif /* defined(CONFIG_USE_XKPHYS) */
>>  	else {
>>  		BUG();
>>  		ufunc = lfunc;
>> diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
>> index 5dcb525a8995..eb57283ec4e0 100644
>> --- a/arch/mips/mm/init.c
>> +++ b/arch/mips/mm/init.c
>> @@ -427,7 +427,7 @@ void __init paging_init(void)
>>  	free_area_init(max_zone_pfns);
>>  }
>> 
>> -#ifdef CONFIG_64BIT
>> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>>  static struct kcore_list kcore_kseg0;
>>  #endif
>> 
>> @@ -470,7 +470,7 @@ void __init mem_init(void)
>>  	setup_zero_pages();	/* Setup zeroed pages.  */
>>  	mem_init_free_highmem();
>> 
>> -#ifdef CONFIG_64BIT
>> +#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
>>  	if ((unsigned long) &_text > (unsigned long) CKSEG0)
>>  		/* The -4 is a hack so that user tools don't have to handle
>>  		   the overflow.  */
>> -- 
>> 2.40.1
>
> Thanks.
>
> -- 
> - Jiaxun
diff mbox series

Patch

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index bc8421859006..92832bbcca5d 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2026,6 +2026,21 @@  config 64BIT
 
 endchoice
 
+config USE_XKPHYS
+	bool "use virtual address from XKPHYS"
+	depends on 64BIT
+	default n
+	help
+	 By default, MIPS uses 32-bit compatible segments KSEG0 and KSEG1
+	 to trivially map first 1/2 GByte of physical memory. This mean,
+	 one should have memory installed in this area in order for Linux to
+	 work. With this option selected, kernel uses virtual addresses from
+	 the XKPHYS segment for both cached and uncached access. XKPHYS allows
+	 to access 2^48 bytes of memory, thus allowing to work with any memory
+	 configuration.
+
+	 Say N if not sure
+
 config MIPS_VA_BITS_48
 	bool "48 bits virtual memory"
 	depends on 64BIT
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index f49807e1f19b..544ee8427cab 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -303,6 +303,10 @@  ifdef CONFIG_64BIT
     endif
   endif
 
+  ifdef CONFIG_USE_XKPHYS
+      KBUILD_SYM32 = n
+  endif
+
   ifeq ($(KBUILD_SYM32), y)
     cflags-$(KBUILD_SYM32) += -msym32 -DKBUILD_64BIT_SYM32
   else
diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
index 0c03623f3897..2be9947814ad 100644
--- a/arch/mips/generic/Platform
+++ b/arch/mips/generic/Platform
@@ -12,7 +12,12 @@ 
 cflags-$(CONFIG_MACH_INGENIC_SOC)	+= -I$(srctree)/arch/mips/include/asm/mach-ingenic
 cflags-$(CONFIG_MIPS_GENERIC)	+= -I$(srctree)/arch/mips/include/asm/mach-generic
 
+ifndef (CONFIG_USE_XKPHYS)
 load-$(CONFIG_MIPS_GENERIC)	+= 0xffffffff80100000
+else
+load-$(CONFIG_MIPS_GENERIC)	+= 0xa800000080100000
+endif
+
 all-$(CONFIG_MIPS_GENERIC)	+= vmlinux.gz.itb
 
 its-y					:= vmlinux.its.S
diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h
index 59a48c60a065..8dc500d8e66d 100644
--- a/arch/mips/include/asm/addrspace.h
+++ b/arch/mips/include/asm/addrspace.h
@@ -65,10 +65,15 @@ 
 #define XKSSEG			_CONST64_(0x4000000000000000)
 #define XKPHYS			_CONST64_(0x8000000000000000)
 #define XKSEG			_CONST64_(0xc000000000000000)
+#if !defined(CONFIG_USE_XKPHYS)
 #define CKSEG0			_CONST64_(0xffffffff80000000)
 #define CKSEG1			_CONST64_(0xffffffffa0000000)
 #define CKSSEG			_CONST64_(0xffffffffc0000000)
 #define CKSEG3			_CONST64_(0xffffffffe0000000)
+#else
+#define CKSEG0			XKPHYS_CM_CACHED
+#define CKSEG1			XKPHYS_CM_UNCACHED
+#endif /* !defined(CONFIG_USE_XKPHYS) */
 
 #define CKSEG0ADDR(a)		(CPHYSADDR(a) | CKSEG0)
 #define CKSEG1ADDR(a)		(CPHYSADDR(a) | CKSEG1)
@@ -126,8 +131,11 @@ 
 #define PHYS_TO_XKSEG_UNCACHED(p)	PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p))
 #define PHYS_TO_XKSEG_CACHED(p)		PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p))
 #define XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK)
-#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS | (_ACAST64_(cm) << 59) | (a))
-
+#define XKPHYS_CM(cm)			(XKPHYS | (_ACAST64_(cm) << 59))
+#define PHYS_TO_XKPHYS(cm, a)		(XKPHYS_CM(cm) | (a))
+#define XKPHYS_CM_CACHED		(XKPHYS_CM(K_CALG_COH_SHAREABLE))
+#define XKPHYS_CM_UNCACHED		(XKPHYS_CM(K_CALG_UNCACHED))
+#define IS_XKPHYS(a)			(((a) >> 62) == 2)
 /*
  * The ultimate limited of the 64-bit MIPS architecture:  2 bits for selecting
  * the region, 3 bits for the CCA mode.  This leaves 59 bits of which the
diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
index 23c67c0871b1..15d8d69de455 100644
--- a/arch/mips/include/asm/mips-cm.h
+++ b/arch/mips/include/asm/mips-cm.h
@@ -311,6 +311,7 @@  GCR_CX_ACCESSOR_RW(32, 0x018, other)
 /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */
 GCR_CX_ACCESSOR_RW(32, 0x020, reset_base)
 #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE		GENMASK(31, 12)
+#define CM_GCR_Cx_RESET_BASE_MODE		BIT(1)
 
 /* GCR_Cx_ID - Identify the current core */
 GCR_CX_ACCESSOR_RO(32, 0x028, id)
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 5978a8dfb917..53b8306da571 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -176,7 +176,11 @@  static inline unsigned long ___pa(unsigned long x)
 		 * the compatibility segements ckseg0 or ckseg1, or it may
 		 * be in xkphys.
 		 */
+#if defined(CONFIG_USE_XKPHYS)
+		return XPHYSADDR(x);
+#else
 		return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
+#endif
 	}
 
 	if (!IS_ENABLED(CONFIG_EVA)) {
@@ -196,7 +200,11 @@  static inline unsigned long ___pa(unsigned long x)
 	return x - PAGE_OFFSET + PHYS_OFFSET;
 }
 #define __pa(x)		___pa((unsigned long)(x))
+#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
+#define __va(x)		((void *)PHYS_TO_XKSEG_CACHED(x))
+#else
 #define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+#endif
 #include <asm/io.h>
 
 /*
@@ -239,6 +247,8 @@  static inline unsigned long kaslr_offset(void)
 	return __kaslr_offset;
 }
 
+#define UNCAC_ADDR(addr)       (UNCAC_BASE + __pa(addr))
+
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
diff --git a/arch/mips/include/asm/vga.h b/arch/mips/include/asm/vga.h
index 0136e0366698..e338e57d0784 100644
--- a/arch/mips/include/asm/vga.h
+++ b/arch/mips/include/asm/vga.h
@@ -16,7 +16,11 @@ 
  *	access the videoram directly without any black magic.
  */
 
+#if defined(CONFIG_USE_XKPHYS)
+#define VGA_MAP_MEM(x, s)	UNCAC_ADDR(0x10000000L + (unsigned long)(x))
+#else
 #define VGA_MAP_MEM(x, s)	CKSEG1ADDR(0x10000000L + (unsigned long)(x))
+#endif
 
 #define vga_readb(x)	(*(x))
 #define vga_writeb(x, y)	(*(y) = (x))
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
index 64ecfdac6580..541f31a43a7f 100644
--- a/arch/mips/kernel/cps-vec.S
+++ b/arch/mips/kernel/cps-vec.S
@@ -554,7 +554,11 @@  LEAF(mips_cps_cache_init)
 	mul	t1, t1, t0
 	mul	t1, t1, t2
 
+#if defined(CONFIG_USE_XKPHYS)
+	PTR_LI	a0, XKPHYS_CM_CACHED
+#else
 	li	a0, CKSEG0
+#endif
 	PTR_ADD	a1, a0, t1
 1:	cache	Index_Store_Tag_I, 0(a0)
 	PTR_ADD	a0, a0, t0
@@ -581,7 +585,11 @@  icache_done:
 	mul	t1, t1, t0
 	mul	t1, t1, t2
 
+#if defined(CONFIG_USE_XKPHYS)
+	PTR_LI	a0, XKPHYS_CM_CACHED
+#else
 	li	a0, CKSEG0
+#endif
 	PTR_ADDU a1, a0, t1
 	PTR_SUBU a1, a1, t0
 1:	cache	Index_Store_Tag_D, 0(a0)
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index b6de8e88c1bd..a002058e1838 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -272,11 +272,25 @@  NESTED(except_vec_vi, 0, sp)
 	.set	push
 	.set	noreorder
 	PTR_LA	v1, except_vec_vi_handler
+#if defined(CONFIG_USE_XKPHYS)
+FEXPORT(except_vec_vi_63_48)
+	lui	v0, 0		/* Patched - bits 63:48 */
+FEXPORT(except_vec_vi_47_32)
+	ori	v0, 0		/* Patched - bits 47:32 */
+	dsll	v0, v0, 0x10
+FEXPORT(except_vec_vi_31_16)
+	ori	v0, 0		/* Patched - bits 31:16 */
+	dsll	v0, v0, 0x10
+	jr	v1
+FEXPORT(except_vec_vi_15_0)
+	ori	v0, 0		/* Patched - bits 15:0 */
+#else /* defined(CONFIG_USE_XKPHYS) */
 FEXPORT(except_vec_vi_lui)
 	lui	v0, 0		/* Patched */
 	jr	v1
 FEXPORT(except_vec_vi_ori)
 	 ori	v0, 0		/* Patched */
+#endif /* defined(CONFIG_USE_XKPHYS) */
 	.set	pop
 	END(except_vec_vi)
 EXPORT(except_vec_vi_end)
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
index dd55d59b88db..47e76722a306 100644
--- a/arch/mips/kernel/smp-cps.c
+++ b/arch/mips/kernel/smp-cps.c
@@ -34,10 +34,33 @@  static unsigned __init core_vpe_count(unsigned int cluster, unsigned core)
 	return min(smp_max_threads, mips_cps_numvps(cluster, core));
 }
 
+/**
+ * plat_core_entry - query reset vector for NMI/reset
+ *
+ * Returns low 32 bits of the reset vector
+ *
+ * This is used to fill 2 registers:
+ * - BEV Base (GCR_BEV_BASE) Offset: 0x0680
+ * - VP Local Reset Exception Base (GCR_CL_RESET_BASE,GCR_CO_RESET_BASE)
+ *   Offset: 0x0020 (0x2020 relative to GCR_BASE_ADDR)
+ *
+ * In both registers, BIT(1) should be set in case it uses address in XKPHYS
+ * (as opposed to KSEG1). This bit defined as CM_GCR_Cx_RESET_BASE_MODE,
+ * using it unconditionally because for GCR_BEV_BASE its value is the same
+ */
+static u32 plat_core_entry(void)
+{
+#if defined(CONFIG_USE_XKPHYS)
+	return (UNCAC_ADDR(mips_cps_core_entry) & 0xffffffff)
+			| CM_GCR_Cx_RESET_BASE_MODE;
+#else
+	return CKSEG1ADDR((unsigned long)mips_cps_core_entry);
+#endif
+}
+
 static void __init cps_smp_setup(void)
 {
 	unsigned int nclusters, ncores, nvpes, core_vpes;
-	unsigned long core_entry;
 	int cl, c, v;
 
 	/* Detect & record VPE topology */
@@ -94,10 +117,8 @@  static void __init cps_smp_setup(void)
 	/* Make core 0 coherent with everything */
 	write_gcr_cl_coherence(0xff);
 
-	if (mips_cm_revision() >= CM_REV_CM3) {
-		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
-		write_gcr_bev_base(core_entry);
-	}
+	if (mips_cm_revision() >= CM_REV_CM3)
+		write_gcr_bev_base(plat_core_entry());
 
 #ifdef CONFIG_MIPS_MT_FPAFF
 	/* If we have an FPU, enroll ourselves in the FPU-full mask */
@@ -213,7 +234,7 @@  static void boot_core(unsigned int core, unsigned int vpe_id)
 	mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
 
 	/* Set its reset vector */
-	write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
+	write_gcr_co_reset_base(plat_core_entry());
 
 	/* Ensure its coherency is disabled */
 	write_gcr_co_coherence(0);
@@ -290,7 +311,6 @@  static int cps_boot_secondary(int cpu, struct task_struct *idle)
 	unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
 	struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
 	struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
-	unsigned long core_entry;
 	unsigned int remote;
 	int err;
 
@@ -314,8 +334,7 @@  static int cps_boot_secondary(int cpu, struct task_struct *idle)
 
 	if (cpu_has_vp) {
 		mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
-		core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
-		write_gcr_co_reset_base(core_entry);
+		write_gcr_co_reset_base(plat_core_entry());
 		mips_cm_unlock_other();
 	}
 
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 246c6a6b0261..875594843626 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -2091,11 +2091,20 @@  static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
 		 * If no shadow set is selected then use the default handler
 		 * that does normal register saving and standard interrupt exit
 		 */
-		extern const u8 except_vec_vi[], except_vec_vi_lui[];
-		extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
+		extern const u8 except_vec_vi[], except_vec_vi_end[];
 		extern const u8 rollback_except_vec_vi[];
 		const u8 *vec_start = using_rollback_handler() ?
 				      rollback_except_vec_vi : except_vec_vi;
+		const int handler_len = except_vec_vi_end - vec_start;
+#if defined(CONFIG_USE_XKPHYS)
+		extern const u8 except_vec_vi_63_48[], except_vec_vi_47_32[];
+		extern const u8 except_vec_vi_31_16[], except_vec_vi_15_0[];
+		const int offset_63_48 = except_vec_vi_63_48 - vec_start;
+		const int offset_47_32 = except_vec_vi_47_32 - vec_start;
+		const int offset_31_16 = except_vec_vi_31_16 - vec_start;
+		const int offset_15_0  = except_vec_vi_15_0  - vec_start;
+#else /* defined(CONFIG_USE_XKPHYS) */
+		extern const u8 except_vec_vi_lui[], except_vec_vi_ori[];
 #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
 		const int lui_offset = except_vec_vi_lui - vec_start + 2;
 		const int ori_offset = except_vec_vi_ori - vec_start + 2;
@@ -2103,7 +2112,7 @@  static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
 		const int lui_offset = except_vec_vi_lui - vec_start;
 		const int ori_offset = except_vec_vi_ori - vec_start;
 #endif
-		const int handler_len = except_vec_vi_end - vec_start;
+#endif /* defined(CONFIG_USE_XKPHYS) */
 
 		if (handler_len > VECTORSPACING) {
 			/*
@@ -2119,10 +2128,21 @@  static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
 #else
 				handler_len);
 #endif
+#if defined(CONFIG_USE_XKPHYS)
+		h = (u16 *)(b + offset_63_48);
+		*h = (handler >> 48) & 0xffff;
+		h = (u16 *)(b + offset_47_32);
+		*h = (handler >> 32) & 0xffff;
+		h = (u16 *)(b + offset_31_16);
+		*h = (handler >> 16) & 0xffff;
+		h = (u16 *)(b + offset_15_0);
+		*h = (handler >> 0) & 0xffff;
+#else /* defined(CONFIG_USE_XKPHYS) */
 		h = (u16 *)(b + lui_offset);
 		*h = (handler >> 16) & 0xffff;
 		h = (u16 *)(b + ori_offset);
 		*h = (handler & 0xffff);
+#endif /* defined(CONFIG_USE_XKPHYS) */
 		local_flush_icache_range((unsigned long)b,
 					 (unsigned long)(b+handler_len));
 	}
@@ -2332,7 +2352,11 @@  static const char panic_null_cerr[] =
 void set_uncached_handler(unsigned long offset, void *addr,
 	unsigned long size)
 {
+#if IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_USE_XKPHYS)
+	unsigned long uncached_ebase = UNCAC_ADDR(ebase);
+#else
 	unsigned long uncached_ebase = CKSEG1ADDR(ebase);
+#endif
 
 	if (!addr)
 		panic(panic_null_cerr);
@@ -2384,9 +2408,11 @@  void __init trap_init(void)
 		 * EVA is special though as it allows segments to be rearranged
 		 * and to become uncached during cache error handling.
 		 */
+#if !defined(CONFIG_USE_XKPHYS)
 		if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000))
 			ebase = CKSEG0ADDR(ebase_pa);
 		else
+#endif
 			ebase = (unsigned long)phys_to_virt(ebase_pa);
 	}
 
diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
index f80a67c092b6..8a78348a2dd7 100644
--- a/arch/mips/lib/uncached.c
+++ b/arch/mips/lib/uncached.c
@@ -44,6 +44,10 @@  unsigned long run_uncached(void *func)
 
 	__asm__("move %0, $sp" : "=r" (sp));
 
+#if defined(CONFIG_USE_XKPHYS)
+	if (IS_XKPHYS(sp))
+		usp = UNCAC_ADDR(sp);
+#else /* defined(CONFIG_USE_XKPHYS) */
 	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
 		usp = CKSEG1ADDR(sp);
 #ifdef CONFIG_64BIT
@@ -52,10 +56,15 @@  unsigned long run_uncached(void *func)
 		usp = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
 				     XKPHYS_TO_PHYS((long long)sp));
 #endif
+#endif /* defined(CONFIG_USE_XKPHYS) */
 	else {
 		BUG();
 		usp = sp;
 	}
+#if defined(CONFIG_USE_XKPHYS)
+	if (IS_XKPHYS(lfunc))
+		ufunc = UNCAC_ADDR(lfunc);
+#else /* defined(CONFIG_USE_XKPHYS) */
 	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
 		ufunc = CKSEG1ADDR(lfunc);
 #ifdef CONFIG_64BIT
@@ -64,6 +73,7 @@  unsigned long run_uncached(void *func)
 		ufunc = PHYS_TO_XKPHYS(K_CALG_UNCACHED,
 				       XKPHYS_TO_PHYS((long long)lfunc));
 #endif
+#endif /* defined(CONFIG_USE_XKPHYS) */
 	else {
 		BUG();
 		ufunc = lfunc;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 5dcb525a8995..eb57283ec4e0 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -427,7 +427,7 @@  void __init paging_init(void)
 	free_area_init(max_zone_pfns);
 }
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
 static struct kcore_list kcore_kseg0;
 #endif
 
@@ -470,7 +470,7 @@  void __init mem_init(void)
 	setup_zero_pages();	/* Setup zeroed pages.  */
 	mem_init_free_highmem();
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && !defined(CONFIG_USE_XKPHYS)
 	if ((unsigned long) &_text > (unsigned long) CKSEG0)
 		/* The -4 is a hack so that user tools don't have to handle
 		   the overflow.  */