[PATCH] platform: generic: mips: add P8700
Anup Patel
anup at brainfault.org
Wed Feb 12 04:27:47 PST 2025
On Sat, Jan 18, 2025 at 5:46 AM Chao-ying Fu <icebergfu at gmail.com> wrote:
>
> MIPS P8700 needs extra scratch space to use in MIPS custom exception
> handler. MIPS P8700 needs to set up PMA for cacheability, when the
> corresponding PMP entry is changed. All harts are redirected to run
> from a common entry to set up necessary CSRs for all clusters, cores,
> and harts.
This is hard to review. Please break this down into small incremental patches.
Regards,
Anup
> ---
> firmware/fw_base.S | 5 +
> include/sbi/sbi_scratch.h | 12 +
> lib/sbi/riscv_asm.c | 36 +
> platform/generic/Kconfig | 4 +
> platform/generic/configs/defconfig | 1 +
> platform/generic/include/mips/board.h | 33 +
> platform/generic/include/mips/mips-cm.h | 88 ++
> platform/generic/include/mips/p8700.h | 122 +++
> platform/generic/include/mips/stw.h | 191 ++++
> platform/generic/mips/cps-vec.S | 202 ++++
> platform/generic/mips/mips,boston-p8700.dts | 353 +++++++
> platform/generic/mips/objects.mk | 7 +
> platform/generic/mips/p8700.c | 202 ++++
> platform/generic/mips/stw.S | 986 ++++++++++++++++++++
> 14 files changed, 2242 insertions(+)
> create mode 100644 platform/generic/include/mips/board.h
> create mode 100644 platform/generic/include/mips/mips-cm.h
> create mode 100644 platform/generic/include/mips/p8700.h
> create mode 100644 platform/generic/include/mips/stw.h
> create mode 100644 platform/generic/mips/cps-vec.S
> create mode 100644 platform/generic/mips/mips,boston-p8700.dts
> create mode 100644 platform/generic/mips/objects.mk
> create mode 100644 platform/generic/mips/p8700.c
> create mode 100644 platform/generic/mips/stw.S
>
> diff --git a/firmware/fw_base.S b/firmware/fw_base.S
> index d027e5e..5c804e3 100644
> --- a/firmware/fw_base.S
> +++ b/firmware/fw_base.S
> @@ -45,6 +45,11 @@
> .align 3
> .globl _start
> .globl _start_warm
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> + lla t0, mips_cps_core_entry
> + jr t0
> +#endif
> +
> _start:
> /* Find preferred boot HART id */
> MOV_3R s0, a0, s1, a1, s2, a2
> diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h
> index 0d188d1..ff8b75e 100644
> --- a/include/sbi/sbi_scratch.h
> +++ b/include/sbi/sbi_scratch.h
> @@ -44,8 +44,16 @@
> #define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__)
> /** Offset of hartindex member in sbi_scratch */
> #define SBI_SCRATCH_HARTINDEX_OFFSET (14 * __SIZEOF_POINTER__)
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> +#define MIPS_P8700_STW_SIZE 34
> +/** Offset of stw_tmp in sbi_scratch */
> +#define SBI_SCRATCH_STW_TMP_OFFSET (15 * __SIZEOF_POINTER__)
> +/** Offset of extra space in sbi_scratch */
> +#define SBI_SCRATCH_EXTRA_SPACE_OFFSET ((15 + MIPS_P8700_STW_SIZE) * __SIZEOF_POINTER__)
> +#else
> /** Offset of extra space in sbi_scratch */
> #define SBI_SCRATCH_EXTRA_SPACE_OFFSET (15 * __SIZEOF_POINTER__)
> +#endif
> /** Maximum size of sbi_scratch (4KB) */
> #define SBI_SCRATCH_SIZE (0x1000)
>
> @@ -87,6 +95,10 @@ struct sbi_scratch {
> unsigned long options;
> /** Index of the hart */
> unsigned long hartindex;
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> + /** for stw */
> + unsigned long stw_tmp[MIPS_P8700_STW_SIZE];
> +#endif
> };
>
> /**
> diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c
> index c7d75ac..ca7edbe 100644
> --- a/lib/sbi/riscv_asm.c
> +++ b/lib/sbi/riscv_asm.c
> @@ -12,6 +12,9 @@
> #include <sbi/sbi_error.h>
> #include <sbi/sbi_platform.h>
> #include <sbi/sbi_console.h>
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> +#include <mips/p8700.h>
> +#endif
>
> /* determine CPU extension, return non-zero support */
> int misa_extension_imp(char ext)
> @@ -119,6 +122,9 @@ unsigned long csr_read_num(int csr_num)
> unsigned long ret = 0;
>
> switch (csr_num) {
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> + switchcase_csr_read_16(CSR_MIPSPMACFG0, ret)
> +#endif
> switchcase_csr_read_16(CSR_PMPCFG0, ret)
> switchcase_csr_read_64(CSR_PMPADDR0, ret)
> switchcase_csr_read(CSR_MCYCLE, ret)
> @@ -199,6 +205,9 @@ void csr_write_num(int csr_num, unsigned long val)
> switchcase_csr_write_32(__csr_num + 32, __val)
>
> switch (csr_num) {
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> + switchcase_csr_write_16(CSR_MIPSPMACFG0, val)
> +#endif
> switchcase_csr_write_16(CSR_PMPCFG0, val)
> switchcase_csr_write_64(CSR_PMPADDR0, val)
> switchcase_csr_write(CSR_MCYCLE, val)
> @@ -301,6 +310,29 @@ int is_pmp_entry_mapped(unsigned long entry)
> return false;
> }
>
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> +extern unsigned long _fw_start;
> +static void pma_set(unsigned int n, unsigned long addr)
> +{
> + int pmacfg_csr, pmacfg_shift;
> + unsigned long cfgmask;
> + unsigned long pmacfg, cca;
> +
> + pmacfg_csr = (CSR_MIPSPMACFG0 + (n >> 2)) & ~1;
> + pmacfg_shift = (n & 7) << 3;
> + cfgmask = ~(0xffUL << pmacfg_shift);
> +
> + /* Read pmacfg to change cacheability */
> + pmacfg = (csr_read_num(pmacfg_csr) & cfgmask);
> + if (addr >= (unsigned long)&_fw_start)
> + cca = CCA_CACHE_ENABLE | PMA_SPECULATION;
> + else
> + cca = CCA_CACHE_DISABLE;
> + pmacfg |= ((cca << pmacfg_shift) & ~cfgmask);
> + csr_write_num(pmacfg_csr, pmacfg);
> +}
> +#endif
> +
> int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
> unsigned long log2len)
> {
> @@ -312,6 +344,10 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
> if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
> return SBI_EINVAL;
>
> +#ifdef CONFIG_PLATFORM_MIPS_P8700
> + pma_set(n, addr);
> +#endif
> +
> /* calculate PMP register and offset */
> #if __riscv_xlen == 32
> pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index 688da3f..a24d6ab 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -68,6 +68,10 @@ config PLATFORM_THEAD
> select THEAD_C9XX_PMU
> default n
>
> +config PLATFORM_MIPS_P8700
> + bool "MIPS P8700 support"
> + default n
> +
> source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
> source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
>
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index e23b38b..45fad6e 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y
> CONFIG_PLATFORM_SOPHGO_SG2042=y
> CONFIG_PLATFORM_STARFIVE_JH7110=y
> CONFIG_PLATFORM_THEAD=y
> +CONFIG_PLATFORM_MIPS_P8700=n
> CONFIG_FDT_CPPC=y
> CONFIG_FDT_CPPC_RPMI=y
> CONFIG_FDT_GPIO=y
> diff --git a/platform/generic/include/mips/board.h b/platform/generic/include/mips/board.h
> new file mode 100644
> index 0000000..6fe7b8b
> --- /dev/null
> +++ b/platform/generic/include/mips/board.h
> @@ -0,0 +1,33 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +
> +#ifndef __BOARD_H__
> +#define __BOARD_H__
> +
> +/* Please review all defines to change for your board. */
> +
> +/* Use in stw.S, p8700.c, p8700.h, mips-cm.h */
> +#define CM_BASE 0x16100000
> +
> +/* Use in mips-cm.h, p8700.c */
> +#define CLUSTERS_IN_PLATFORM 1
> +#if CLUSTERS_IN_PLATFORM > 1
> +/* Define global CM bases for cluster 0, 1, 2, and more. */
> +#define GLOBAL_CM_BASE0 0
> +#define GLOBAL_CM_BASE1 0
> +#define GLOBAL_CM_BASE2 0
> +#endif
> +
> +/* Use in stw.S */
> +#define TIMER_ADDR (CM_BASE + 0x8050)
> +
> +/* Use in cps-vec.S */
> +#define DRAM_ADDRESS 0x80000000
> +#define DRAM_SIZE 0x80000000
> +#define DRAM_PMP_ADDR ((DRAM_ADDRESS >> 2) | ((DRAM_SIZE - 1) >> 3))
> +
> +#endif
> diff --git a/platform/generic/include/mips/mips-cm.h b/platform/generic/include/mips/mips-cm.h
> new file mode 100644
> index 0000000..19b4384
> --- /dev/null
> +++ b/platform/generic/include/mips/mips-cm.h
> @@ -0,0 +1,88 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +
> +#ifndef __MIPS_CM_H__
> +#define __MIPS_CM_H__
> +
> +#include <mips/p8700.h>
> +#include <sbi/sbi_console.h>
> +
> +/* Define 1 to print out CM read and write info */
> +#define DEBUG_CM 0
> +
> +#if CLUSTERS_IN_PLATFORM > 1
> +static long GLOBAL_CM_BASE[CLUSTERS_IN_PLATFORM] = {GLOBAL_CM_BASE0, GLOBAL_CM_BASE1, GLOBAL_CM_BASE2};
> +#else
> +static long GLOBAL_CM_BASE[CLUSTERS_IN_PLATFORM] = {CM_BASE};
> +#endif
> +
> +#define CPS_ACCESSOR_R(unit, sz, base, off, name) \
> +static inline u##sz read_##unit##_##name(u32 hartid, bool local_p) \
> +{ \
> + u##sz value; \
> + long cmd_reg; \
> + int cl, co; \
> + cl = cpu_cluster(hartid); \
> + co = cpu_core(hartid); \
> + cmd_reg = (local_p ? (base) : ((base) - CM_BASE + GLOBAL_CM_BASE[cl])) \
> + + (co << CM_BASE_CORE_SHIFT) \
> + + off; \
> + if (DEBUG_CM) \
> + sbi_printf("CM READ%d cmd_reg=%lx\n", sz, cmd_reg); \
> + if (sz == 32) \
> + asm volatile("lw %0,0(%1)":"=r"(value):"r"(cmd_reg)); \
> + else if (sz == 64) \
> + asm volatile("ld %0,0(%1)":"=r"(value):"r"(cmd_reg)); \
> + asm volatile("fence"); \
> + return value; \
> +}
> +
> +#define CPS_ACCESSOR_W(unit, sz, base, off, name) \
> +static inline void write_##unit##_##name(u32 hartid, u##sz value, bool local_p) \
> +{ \
> + long cmd_reg; \
> + int cl, co; \
> + cl = cpu_cluster(hartid); \
> + co = cpu_core(hartid); \
> + cmd_reg = (local_p ? (base) : ((base) - CM_BASE + GLOBAL_CM_BASE[cl])) \
> + + (co << CM_BASE_CORE_SHIFT) \
> + + off; \
> + if (DEBUG_CM) \
> + sbi_printf("CM WRITE%d cmd_reg=%lx value=%lx\n", sz, \
> + cmd_reg, (u64)value); \
> + if (sz == 32) \
> + asm volatile("sw %0,0(%1)"::"r"(value),"r"(cmd_reg)); \
> + else if (sz == 64) \
> + asm volatile("sd %0,0(%1)"::"r"(value),"r"(cmd_reg)); \
> + asm volatile("fence"); \
> +}
> +
> +#define CPS_ACCESSOR_RW(unit, sz, base, off, name) \
> + CPS_ACCESSOR_R(unit, sz, base, off, name) \
> + CPS_ACCESSOR_W(unit, sz, base, off, name)
> +
> +#define CPC_CX_ACCESSOR_RW(sz, off, name) \
> + CPS_ACCESSOR_RW(cpc, sz, CPC_BASE, CPC_OFF_LOCAL + (off), co_##name)
> +
> +#define GCR_CX_ACCESSOR_RW(sz, off, name) \
> + CPS_ACCESSOR_RW(gcr, sz, CM_BASE, GCR_OFF_LOCAL + (off), co_##name)
> +
> +GCR_CX_ACCESSOR_RW(64, cpu_hart(hartid) << CM_BASE_HART_SHIFT, reset_base)
> +GCR_CX_ACCESSOR_RW(32, GCR_CORE_COH_EN, coherence)
> +
> +CPC_CX_ACCESSOR_RW(32, CPC_Cx_VP_RUN, vp_run)
> +CPC_CX_ACCESSOR_RW(32, CPC_Cx_VP_STOP, vp_stop)
> +CPC_CX_ACCESSOR_RW(32, CPC_Cx_CMD, cmd)
> +CPC_CX_ACCESSOR_RW(32, CPC_Cx_STAT_CONF, stat_conf)
> +
> +#define CPC_ACCESSOR_RW(sz, off, name) \
> + CPS_ACCESSOR_RW(cpc, sz, CPC_BASE, off, name)
> +
> +CPC_ACCESSOR_RW(32, CPC_PWRUP_CTL, pwrup_ctl)
> +CPC_ACCESSOR_RW(32, CPC_CM_STAT_CONF, cm_stat_conf)
> +
> +#endif
> diff --git a/platform/generic/include/mips/p8700.h b/platform/generic/include/mips/p8700.h
> new file mode 100644
> index 0000000..6aa71d9
> --- /dev/null
> +++ b/platform/generic/include/mips/p8700.h
> @@ -0,0 +1,122 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +
> +#ifndef __P8700_H__
> +#define __P8700_H__
> +
> +#include <mips/board.h>
> +
> +/* PMA */
> +#define CSR_MIPSPMACFG0 0x7e0
> +#define CSR_MIPSPMACFG1 0x7e1
> +#define CSR_MIPSPMACFG2 0x7e2
> +#define CSR_MIPSPMACFG3 0x7e3
> +#define CSR_MIPSPMACFG4 0x7e4
> +#define CSR_MIPSPMACFG5 0x7e5
> +#define CSR_MIPSPMACFG6 0x7e6
> +#define CSR_MIPSPMACFG7 0x7e7
> +#define CSR_MIPSPMACFG8 0x7e8
> +#define CSR_MIPSPMACFG9 0x7e9
> +#define CSR_MIPSPMACFG10 0x7ea
> +#define CSR_MIPSPMACFG11 0x7eb
> +#define CSR_MIPSPMACFG12 0x7ec
> +#define CSR_MIPSPMACFG13 0x7ed
> +#define CSR_MIPSPMACFG14 0x7ee
> +#define CSR_MIPSPMACFG15 0x7ef
> +
> +/* MIPS CCA */
> +#define CCA_CACHE_ENABLE 0
> +#define CCA_CACHE_DISABLE 2
> +#define PMA_SPECULATION (1 << 3)
> +
> +/* MIPS CSR */
> +#define CSR_MIPSTVEC 0x7c0
> +#define CSR_MIPSCONFIG0 0x7d0
> +#define CSR_MIPSCONFIG1 0x7d1
> +#define CSR_MIPSCONFIG2 0x7d2
> +#define CSR_MIPSCONFIG3 0x7d3
> +#define CSR_MIPSCONFIG4 0x7d4
> +#define CSR_MIPSCONFIG5 0x7d5
> +#define CSR_MIPSCONFIG6 0x7d6
> +#define CSR_MIPSCONFIG7 0x7d7
> +#define CSR_MIPSCONFIG8 0x7d8
> +#define CSR_MIPSCONFIG9 0x7d9
> +#define CSR_MIPSCONFIG10 0x7da
> +#define CSR_MIPSCONFIG11 0x7db
> +
> +#define MIPSCONFIG5_MTW 4
> +
> +#define GEN_MASK(h, l) (((1ul << ((h) + 1 - (l))) - 1) << (l))
> +#define EXT(val, mask) (((val) & (mask)) >> (__builtin_ffs(mask) - 1))
> +
> +/*
> + * We allocate the number of bits to encode clusters, cores, and harts
> + * from the original mhartid to a new dense index.
> + */
> +#define NUM_OF_BITS_FOR_CLUSTERS 4
> +#define NUM_OF_BITS_FOR_CORES 12
> +#define NUM_OF_BITS_FOR_HARTS 4
> +
> +/* mhartid field info */
> +#define MHARTID_CORE_MASK 0xff
> +#define MHARTID_CORE_SHIFT 4
> +
> +/* To get the field from new/hashed mhartid */
> +#define NEW_CLUSTER_SHIFT (NUM_OF_BITS_FOR_CORES + NUM_OF_BITS_FOR_HARTS)
> +#define NEW_CLUSTER_MASK ((1 << NUM_OF_BITS_FOR_CLUSTERS) - 1)
> +#define NEW_CORE_SHIFT NUM_OF_BITS_FOR_HARTS
> +#define NEW_CORE_MASK ((1 << NUM_OF_BITS_FOR_CORES) - 1)
> +#define NEW_HART_MASK ((1 << NUM_OF_BITS_FOR_HARTS) - 1)
> +#define cpu_cluster(i) (((i) >> NEW_CLUSTER_SHIFT) & NEW_CLUSTER_MASK)
> +#define cpu_core(i) (((i) >> NEW_CORE_SHIFT) & NEW_CORE_MASK)
> +#define cpu_hart(i) ((i) & NEW_HART_MASK)
> +
> +#define CPC_BASE (CM_BASE + 0x8000)
> +
> +#define SIZE_FOR_CPC_MTIME 0x10000 /* The size must be 2^order */
> +#define AIA_BASE (CM_BASE + 0x40000)
> +#define SIZE_FOR_AIA_M_MODE 0x20000 /* The size must be 2^order */
> +#define P8700_ALIGN 0x10000
> +
> +#define CM_BASE_HART_SHIFT 3
> +#define CM_BASE_CORE_SHIFT 8
> +#define CM_BASE_CLUSTER_SHIFT 19
> +
> +/* GCR Block offsets */
> +#define GCR_OFF_LOCAL 0x2000
> +
> +#define GCR_BASE_OFFSET 0x0008
> +#define GCR_CORE_COH_EN 0x00f8
> +#define GCR_CORE_COH_EN_EN (0x1 << 0)
> +
> +#define L2_PFT_CONTROL_OFFSET 0x0300
> +#define L2_PFT_CONTROL_B_OFFSET 0x0308
> +
> +/* CPC Block offsets */
> +#define CPC_PWRUP_CTL 0x0030
> +#define CPC_CM_STAT_CONF 0x1008
> +
> +#define CPC_OFF_LOCAL 0x2000
> +
> +#define CPC_Cx_VP_STOP 0x0020
> +#define CPC_Cx_VP_RUN 0x0028
> +#define CPC_Cx_CMD 0x0000
> +
> +#define CPC_Cx_CMD_PWRUP 0x3
> +#define CPC_Cx_CMD_RESET 0x4
> +
> +#define CPC_Cx_STAT_CONF 0x0008
> +#define CPC_Cx_STAT_CONF_SEQ_STATE GEN_MASK(22, 19)
> +#define CPC_Cx_STAT_CONF_SEQ_STATE_U5 6
> +#define CPC_Cx_STAT_CONF_SEQ_STATE_U6 7
> +
> +#define INDEXED(op, reg, idx, offset, base) \
> + li idx, offset ;\
> + add idx, idx, base ;\
> + op reg, (idx)
> +
> +#endif
> diff --git a/platform/generic/include/mips/stw.h b/platform/generic/include/mips/stw.h
> new file mode 100644
> index 0000000..bdcacc3
> --- /dev/null
> +++ b/platform/generic/include/mips/stw.h
> @@ -0,0 +1,191 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> +
> +Some lines of this code have been copied from
> +https://github.com/riscv/riscv-tests and are used in accordance with following
> +license:
> +
> +Copyright (c) 2012-2015, The Regents of the University of California (Regents).
> +All Rights Reserved.
> +
> +Redistribution and use in source and binary forms, with or without
> +modification, are permitted provided that the following conditions are met:
> +1. Redistributions of source code must retain the above copyright
> + notice, this list of conditions and the following disclaimer.
> +2. Redistributions in binary form must reproduce the above copyright
> + notice, this list of conditions and the following disclaimer in the
> + documentation and/or other materials provided with the distribution.
> +3. Neither the name of the Regents nor the
> + names of its contributors may be used to endorse or promote products
> + derived from this software without specific prior written permission.
> +
> +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
> +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
> +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
> +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
> +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
> +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> +
> +*/
> +
> +#include <sbi/sbi_scratch.h>
> +#undef MSTATUS_MPRV
> +#undef SATP_MODE_OFF
> +#undef SATP_MODE_SV32
> +#undef SATP_MODE_SV39
> +#undef SATP_MODE_SV48
> +#undef SATP_MODE_SV57
> +#undef SATP_MODE_SV64
> +#undef MSTATUS_MPV
> +
> +#define CAUSE_ILLEGAL_INST 2
> +#define CAUSE_LOAD_ACCESS 0x5
> +#define CAUSE_STORE_ACCESS 0x7
> +#define CAUSE_LOAD_PAGE_FAULT 0xd
> +#define CAUSE_STORE_PAGE_FAULT 0xf
> +#define CAUSE_GUEST_LOAD_PAGE_FAULT 21
> +#define CAUSE_GUEST_STORE_PAGE_FAULT 23
> +#define CAUSE_READ_TIME 26
> +#define CAUSE_GUEST_TLB_MISS 28
> +#define MSTATUS_MPRV 0x00020000
> +#define vsatp 0x280
> +#define mtval2 0x34b
> +#define hgatp 0x680
> +
> +#define SATP_MODE_OFF 0
> +#define SATP_MODE_SV32 1
> +#define SATP_MODE_SV39 8
> +#define SATP_MODE_SV48 9
> +#define SATP_MODE_SV57 10
> +#define SATP_MODE_SV64 11
> +#define mstatus_GVA_LSB 38
> +#define PTE_V 0x001 /* Valid */
> +#define PTE_R 0x002 /* Read */
> +#define PTE_W 0x004 /* Write */
> +#define PTE_X 0x008 /* Execute */
> +#define PTE_U 0x010 /* User */
> +#define PTE_G 0x020 /* Global */
> +#define PTE_A 0x040 /* Accessed */
> +#define PTE_D 0x080 /* Dirty */
> +#define PTE_N 0x8000000000000000 /* Napot */
> +#define PTE_RSVD 0x7fc0000000000000 /* RSVD */
> +#define mstatus_MPV_MSB 39
> +#define mstatus_MPV_LSB 39
> +#define MSTATUS_MPV ALIGN_FIELD(-1, mstatus_MPV)
> +
> +/* Return value aligned at [msb:lsb]. */
> +#define ALIGN(value, msb, lsb) (((value) & ((1 << (1 + msb - lsb)) - 1)) << lsb)
> +
> +/* Return value aligned at named field, i.e. [<field>_MSB:<field>_LSB]. */
> +#define ALIGN_FIELD(value, field) ALIGN(value, field##_MSB, field##_LSB)
> +
> +/* rd = rs[max:min] */
> +#define extract(rd, rs, max, min) ; \
> + slli rd, rs, __riscv_xlen - 1 - max ; \
> + srli rd, rd, __riscv_xlen - 1 - max + min
> +
> +/**
> + * GPR numbers of named gprs, for passing named gprs to instruction definitions.
> + */
> +#define gpr_idx_x0 0
> +#define gpr_idx_x1 1
> +#define gpr_idx_sp 2
> +#define gpr_idx_gp 3
> +#define gpr_idx_tp 4
> +#define gpr_idx_t0 5
> +#define gpr_idx_t1 6
> +#define gpr_idx_t2 7
> +#define gpr_idx_s0 8
> +#define gpr_idx_fp 8
> +#define gpr_idx_s1 9
> +#define gpr_idx_a0 10
> +#define gpr_idx_a1 11
> +#define gpr_idx_a2 12
> +#define gpr_idx_a3 13
> +#define gpr_idx_a4 14
> +#define gpr_idx_a5 15
> +#define gpr_idx_a6 16
> +#define gpr_idx_a7 17
> +#define gpr_idx_s2 18
> +#define gpr_idx_s3 19
> +#define gpr_idx_s4 20
> +#define gpr_idx_s5 21
> +#define gpr_idx_s6 22
> +#define gpr_idx_s7 23
> +#define gpr_idx_s8 24
> +#define gpr_idx_s9 25
> +#define gpr_idx_s10 26
> +#define gpr_idx_s11 27
> +#define gpr_idx_t3 28
> +#define gpr_idx_t4 29
> +#define gpr_idx_t5 30
> +#define gpr_idx_t6 31
> +
> +#define GPR_IDX(rs) _GPR_IDX(rs)
> +#define _GPR_IDX(rs) gpr_idx_##rs
> +
> +#if BIGENDIAN
> +#define IWORD(x) ; \
> + .byte (x) & 0xff ; \
> + .byte (x)>>8 & 0xff ; \
> + .byte (x)>>16 & 0xff ; \
> + .byte (x)>>24 & 0xff
> +#else
> + #define IWORD(x) .word x
> +#endif
> +
> +#define MTLBWR(rs1, level) \
> + IWORD(0b11101100000000000000000001110011 | GPR_IDX(rs1)<<15 | level<<20)
> +
> +#define MTLBWR_HG(rs1, level) \
> + IWORD(0b11101100100000000000000001110011 | GPR_IDX(rs1)<<15 | level<<20)
> +
> +#define PAUSE_ZIHINTPAUSE() \
> + IWORD(0b00000001000000000000000000001111)
> +
> +#define PAUSE_MIPS() \
> + IWORD(0b00000000010100000001000000010011)
> +
> +#if ZIHINTPAUSE
> + #define PAUSE() PAUSE_ZIHINTPAUSE()
> +#else
> + #define PAUSE() PAUSE_MIPS()
> +#endif
> +
> +#define base (15 << 3) /* This should match SBI_SCRATCH_STW_TMP_OFFSET. */
> +#if base != SBI_SCRATCH_STW_TMP_OFFSET
> + #error WRONG base for STW
> +#endif
> +#define O_tmp0 (base + (0 << 3))
> +#define O_save_x1 (base + (1 << 3))
> +#define O_satp_vsatp_scratch0 (base + (2 << 3))
> +#define O_satp_vsatp_scratch1 (base + (3 << 3))
> +#define O_satp_vsatp_scratch2 (base + (4 << 3))
> +#define O_satp_vsatp_scratch3 (base + (5 << 3))
> +#define O_satp_vsatp_scratch4 (base + (6 << 3))
> +#define O_satp_vsatp_scratch5 (base + (7 << 3))
> +#define O_satp_vsatp_scratch6 (base + (8 << 3))
> +#define O_satp_vsatp_scratch7 (base + (9 << 3))
> +#define O_satp_vsatp_scratch8 (base + (10 << 3))
> +#define O_hgatp_scratch0 (base + (11 << 3))
> +#define O_hgatp_scratch1 (base + (12 << 3))
> +#define O_hgatp_scratch2 (base + (13 << 3))
> +#define O_hgatp_scratch3 (base + (14 << 3))
> +#define O_hgatp_scratch4 (base + (15 << 3))
> +#define O_hgatp_scratch5 (base + (16 << 3))
> +#define O_amo_scratch (base + (17 << 3)) /* Points to 17 dwords */
> +
> +#ifdef __riscv_compressed
> + #define JUMP_TABLE_SHIFT 2
> + #define JUMP_TABLE_OFFSET 4
> +#else
> + #define JUMP_TABLE_SHIFT 3
> + #define JUMP_TABLE_OFFSET 8
> +#endif
> diff --git a/platform/generic/mips/cps-vec.S b/platform/generic/mips/cps-vec.S
> new file mode 100644
> index 0000000..5049532
> --- /dev/null
> +++ b/platform/generic/mips/cps-vec.S
> @@ -0,0 +1,202 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +
> +#include <sbi/riscv_encoding.h>
> +#include <mips/p8700.h>
> +
> + .text
> + .align 12
> + .globl mips_cps_core_entry
> +mips_cps_core_entry:
> + j 1f
> +
> + .align 2
> +nmi_vector:
> + j 1f
> +
> + .align 2
> +cacheerr_vector:
> + j 1f
> +
> + .align 2
> +debugexc_vector:
> + j 1f
> +
> + .align 2
> +1:
> + li x1, 0
> + li x2, 0
> + li x3, 0
> + li x4, 0
> + li x5, 0
> + li x6, 0
> + li x7, 0
> + li x8, 0
> + li x9, 0
> + li x10, 0
> + li x11, 0
> + li x12, 0
> + li x13, 0
> + li x14, 0
> + li x15, 0
> + li x16, 0
> + li x17, 0
> + li x18, 0
> + li x19, 0
> + li x20, 0
> + li x21, 0
> + li x22, 0
> + li x23, 0
> + li x24, 0
> + li x25, 0
> + li x26, 0
> + li x27, 0
> + li x28, 0
> + li x29, 0
> + li x30, 0
> + li x31, 0
> +
> + /* a0 has mhartid */
> + csrr a0, CSR_MHARTID
> +
> + /* Test mhartid lowest 4 bits */
> + andi t0, a0, 0xf
> + bnez t0, setup_pmp
> +
> + /* Cluster cl Core co Hart 0 */
> + li s0, CM_BASE
> +
> +cm_relocate_done:
> + li t0, GCR_CORE_COH_EN_EN
> +
> + /* Get core number to update CM_BASE */
> + srl t1, a0, MHARTID_CORE_SHIFT
> + andi t1, t1, MHARTID_CORE_MASK
> + sll t1, t1, CM_BASE_CORE_SHIFT
> + add s0, s0, t1
> + INDEXED(sd, t0, t1, GCR_OFF_LOCAL + GCR_CORE_COH_EN, s0)
> + fence
> +
> +setup_pmp:
> + li t0, DRAM_PMP_ADDR
> + csrw CSR_PMPADDR14, t0
> + li t0, 0x1fffffffffffffff # All from 0x0
> + csrw CSR_PMPADDR15, t0
> + li t0, ((PMP_A_NAPOT|PMP_R|PMP_W|PMP_X)<<56)|((PMP_A_NAPOT|PMP_R|PMP_W|PMP_X)<<48)
> + csrw CSR_PMPCFG2, t0
> + /* Set cacheable for pmp6, uncacheable for pmp7 */
> + li t0, (CCA_CACHE_DISABLE << 56)|(CCA_CACHE_ENABLE << 48)
> + csrw CSR_MIPSPMACFG2, t0
> + /* Reset pmpcfg0 */
> + csrw CSR_PMPCFG0, zero
> + /* Reset pmacfg0 */
> + csrw CSR_MIPSPMACFG0, zero
> + fence
> +
> +per_cluster:
> + li t0, 0xffff
> + and t0, t0, a0
> + bnez t0, per_core
> +
> + /* L2 Prefetch */
> + li t0, 0xfffff110
> + sw t0, L2_PFT_CONTROL_OFFSET(s0)
> + li t0, 0x15ff
> + sw t0, L2_PFT_CONTROL_B_OFFSET(s0)
> +
> +per_core:
> + andi t0, a0, 0xf
> + bnez t0, per_hart
> +
> + /* Enable Load Pair */
> + /* Enable Store Pair */
> + /* Enable HTW */
> + li t0, (1<<12)|(1<<13)|(1<<7)
> + csrc CSR_MIPSCONFIG7, t0
> +
> + /* Disable noRFO */
> + li t0, (1<<25)
> + csrs CSR_MIPSCONFIG7, t0
> +
> + /* Disable misaligned load/store to have misaligned address exceptions */
> + li t0, (1<<9)
> + csrs CSR_MIPSCONFIG7, t0
> +
> + /* Enable L1-D$ Prefetch */
> + li t0, 0xff
> + csrw CSR_MIPSCONFIG11, t0
> +
> + li t0, 4
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x104
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x204
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x304
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x404
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x504
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x604
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> + li t0, 0x704
> + csrs CSR_MIPSCONFIG8, t0
> + li t0, 8
> + csrs CSR_MIPSCONFIG9, t0
> + fence
> + fence.i
> +
> +per_hart:
> + /* Set up mipstvec */
> + lla t0, mipstvec_handler_stw
> + ori t0, t0, 1
> + csrw CSR_MIPSTVEC, t0
> +
> + /* Let hart 0 jump to _start */
> + beqz a0, 1f
> + lla t0, _start_warm
> + jr t0
> +1:
> + lla t0, _start
> + jr t0
> +
> diff --git a/platform/generic/mips/mips,boston-p8700.dts b/platform/generic/mips/mips,boston-p8700.dts
> new file mode 100644
> index 0000000..9e3ca2a
> --- /dev/null
> +++ b/platform/generic/mips/mips,boston-p8700.dts
> @@ -0,0 +1,353 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +
> +/dts-v1/;
> +
> +#define CM_BASE 0x16100000
> +#define APLIC_M_BASE (CM_BASE + 0x40000)
> +#define APLIC_S_BASE (CM_BASE + 0x60000)
> +#define MSWI_BASE (CM_BASE + 0x50000)
> +#define MTIMER_BASE (MSWI_BASE + 0x4000)
> +#define CPC_TIMER (CM_BASE + 0x8050)
> +
> +#define BITFILE_FREQUENCY 25000000
> +
> +/ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + model = "MIPS P8700";
> + compatible = "mips,p8700";
> +
> + chosen {
> + stdout-path = &uart0;
> + // For Qemu
> + //bootargs = "root=/dev/sda rw earlycon console=ttyS0,115200n8r";
> + // For a Boston board
> + bootargs = "root=/dev/mmcblk0p5 rw rootwait earlycon console=ttyS0,115200n8r";
> +
> + opensbi-domains {
> + compatible = "opensbi,domain,config";
> +
> + tmem: tmem {
> + compatible = "opensbi,domain,memregion";
> + base = <0x0 0x80000000>;
> + order = <31>;
> + };
> +
> + allmem: allmem {
> + compatible = "opensbi,domain,memregion";
> + base = <0x0 0x0>;
> + order = <64>;
> + };
> +
> + tdomain: trusted-domain {
> + compatible = "opensbi,domain,instance";
> + possible-harts = <&cpu0 &cpu1 &cpu2 &cpu3 &cpu4 &cpu5 &cpu6 &cpu7>;
> + regions = <&tmem 0x3f>, <&allmem 0x3f>;
> + };
> + };
> + };
> +
> + cpus {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + timebase-frequency = <BITFILE_FREQUENCY>;
> +
> + cpu0: cpu at 0 {
> + phandle = <0x00000001>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000000>;
> +
> + interrupt-controller {
> + phandle = <0x00000002>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu1: cpu at 1 {
> + phandle = <0x00000005>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000001>;
> +
> + interrupt-controller {
> + phandle = <0x00000006>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu2: cpu at 2 {
> + phandle = <0x00000007>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000010>;
> +
> + interrupt-controller {
> + phandle = <0x00000008>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu3: cpu at 3 {
> + phandle = <0x00000009>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000011>;
> +
> + interrupt-controller {
> + phandle = <0x0000000a>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu4: cpu at 4 {
> + phandle = <0x0000000b>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000020>;
> +
> + interrupt-controller {
> + phandle = <0x0000000c>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu5: cpu at 5 {
> + phandle = <0x0000000d>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000021>;
> +
> + interrupt-controller {
> + phandle = <0x0000000e>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu6: cpu at 6 {
> + phandle = <0x0000000f>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000030>;
> +
> + interrupt-controller {
> + phandle = <0x00000010>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + cpu7: cpu at 7 {
> + phandle = <0x00000011>;
> + device_type = "cpu";
> + compatible = "riscv";
> + opensbi-domain = <&tdomain>;
> + mmu-type = "riscv,sv39";
> + riscv,isa = "rv64imafdcsu";
> + status = "okay";
> + reg = <0x00000031>;
> +
> + interrupt-controller {
> + phandle = <0x00000012>;
> + compatible = "riscv,cpu-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> + };
> +
> + memory at 0 {
> + device_type = "memory";
> + reg = <0x80000000 0x80000000>;
> + };
> +
> + pci2: pci at 14000000 {
> + compatible = "xlnx,axi-pcie-host-1.00.a";
> + device_type = "pci";
> + reg = <0x14000000 0x2000000>;
> +
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> +
> + interrupt-parent = <4>;
> + interrupts = <0x00000007 0x00000004>;
> +
> + ranges = <0x02000000 0 0x16000000
> + 0x16000000 0 0x100000>;
> +
> + bus-range = <0x00 0xff>;
> +
> + interrupt-map-mask = <0 0 0 7>;
> + interrupt-map = <0 0 0 1 &pci2_intc 1>,
> + <0 0 0 2 &pci2_intc 2>,
> + <0 0 0 3 &pci2_intc 3>,
> + <0 0 0 4 &pci2_intc 4>;
> +
> + pci2_intc: interrupt-controller {
> + interrupt-controller;
> + #address-cells = <0>;
> + #interrupt-cells = <1>;
> + };
> +
> + pci2_root at 0,0,0 {
> + compatible = "pci10ee,7021", "pci-bridge";
> + reg = <0x00000000 0 0 0 0>;
> +
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> +
> + eg20t_bridge at 1,0,0 {
> + compatible = "pci8086,8800", "pci-bridge";
> + reg = <0x00010000 0 0 0 0>;
> +
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> +
> + eg20t_mac at 2,0,1 {
> + compatible = "pci8086,8802", "intel,pch-gbe";
> + reg = <0x00020100 0 0 0 0>;
> + phy-reset-gpios = <&eg20t_gpio 6 1>;
> + };
> +
> + eg20t_gpio: eg20t_gpio at 2,0,2 {
> + compatible = "pci8086,8803", "intel,eg20t-gpio";
> + reg = <0x00020200 0 0 0 0>;
> +
> + gpio-controller;
> + #gpio-cells = <2>;
> + };
> +
> + eg20t_i2c at 2,12,2 {
> + compatible = "pci8086,8817";
> + reg = <0x00026200 0 0 0 0>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + rtc at 68 {
> + compatible = "st,m41t81s";
> + reg = <0x68>;
> + };
> + };
> + };
> + };
> + };
> +
> + uart0: uart at 17ffe000 {
> + compatible = "ns16550a";
> + reg = <0x17ffe000 0x1000>;
> + reg-shift = <2>;
> + reg-io-width = <4>;
> +
> + interrupt-parent = <4>;
> + interrupts = <0x00000004 0x00000004>;
> +
> + clock-frequency = <BITFILE_FREQUENCY>;
> +
> + u-boot,dm-pre-reloc;
> + };
> +
> + lcd: lcd at 17fff000 {
> + compatible = "img,boston-lcd";
> + reg = <0x17fff000 0x8>;
> + };
> +
> + flash at 18000000 {
> + compatible = "cfi-flash";
> + reg = <0x18000000 0x8000000>;
> + bank-width = <2>;
> + };
> +
> + soc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "simple-bus";
> + ranges;
> +
> + aplic_s0 {
> + phandle = <0x00000004>;
> + #interrupt-cells = <0x00000002>;
> + compatible = "riscv,aplic";
> + interrupt-controller;
> + interrupts-extended = <2 9 6 9 8 9 10 9 12 9 14 9 16 9 18 9>;
> + reg = <APLIC_S_BASE 0x00008000>;
> + riscv,num-sources = <0x00000035>;
> + };
> +
> + aplic_m0 {
> + phandle = <0x00000003>;
> + #interrupt-cells = <0x00000002>;
> + riscv,delegate = <0x00000004 0x00000001 0x00000035>;
> + riscv,children = <0x00000004>;
> + compatible = "riscv,aplic";
> + interrupt-controller;
> + interrupts-extended = <2 11 6 11 8 11 10 11 12 11 14 11 16 11 18 11>;
> + reg = <APLIC_M_BASE 0x00008000>;
> + riscv,num-sources = <0x00000035>;
> + };
> +
> + mswi0 {
> + compatible = "riscv,aclint-mswi";
> + interrupts-extended = <2 3>, <6 3>, <8 3>, <10 3>, <12 3>, <14 3>, <16 3>, <18 3>;
> + reg = <MSWI_BASE 0x4000>;
> + interrupt-controller;
> + #interrupt-cells = <0>;
> + };
> +
> + mtimer0 {
> + compatible = "riscv,aclint-mtimer";
> + reg = <CPC_TIMER 0x8>,
> + <MTIMER_BASE 0x7ff8>;
> + interrupts-extended = <2 7>, <6 7>, <8 7>, <10 7>, <12 7>, <14 7>, <16 7>, <18 7>;
> + };
> + };
> +};
> diff --git a/platform/generic/mips/objects.mk b/platform/generic/mips/objects.mk
> new file mode 100644
> index 0000000..0254d35
> --- /dev/null
> +++ b/platform/generic/mips/objects.mk
> @@ -0,0 +1,7 @@
> +#
> +# SPDX-License-Identifier: BSD-2-Clause
> +#
> +
> +carray-platform_override_modules-$(CONFIG_PLATFORM_MIPS_P8700) += mips_p8700
> +platform-objs-$(CONFIG_PLATFORM_MIPS_P8700) += mips/p8700.o mips/stw.o mips/cps-vec.o
> +platform-dtb-$(CONFIG_PLATFORM_MIPS_P8700) += mips/mips,boston-p8700.dtb
> diff --git a/platform/generic/mips/p8700.c b/platform/generic/mips/p8700.c
> new file mode 100644
> index 0000000..1bd627f
> --- /dev/null
> +++ b/platform/generic/mips/p8700.c
> @@ -0,0 +1,202 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +
> +#include <platform_override.h>
> +#include <sbi/sbi_domain.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_hsm.h>
> +#include <sbi/sbi_timer.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <mips/p8700.h>
> +#include <mips/mips-cm.h>
> +
> +extern void mips_cps_core_entry(void);
> +
> +#if CLUSTERS_IN_PLATFORM > 1
> +static void power_up_other_cluster(u32 hartid)
> +{
> + unsigned int stat;
> + unsigned int timeout;
> + bool local_p = (cpu_cluster(current_hartid()) == cpu_cluster(hartid));
> +
> + /* Power up cluster cl core 0 hart 0 */
> + write_cpc_pwrup_ctl(hartid, 1, local_p);
> +
> + /* Wait for the CM to start up */
> + timeout = 100;
> + while (true) {
> + stat = read_cpc_cm_stat_conf(hartid, local_p);
> + stat = EXT(stat, CPC_Cx_STAT_CONF_SEQ_STATE);
> + if (stat == CPC_Cx_STAT_CONF_SEQ_STATE_U5)
> + break;
> +
> + /* Delay a little while before we start warning */
> + if (timeout) {
> + sbi_dprintf("Delay a little while before we start warning\n");
> + timeout--;
> + }
> + else {
> + sbi_printf("Waiting for cluster %u CM to power up... STAT_CONF=0x%x\n",
> + cpu_cluster(hartid), stat);
> + break;
> + }
> + }
> +}
> +#endif
> +
> +static int mips_hart_start(u32 hartid, ulong saddr)
> +{
> + unsigned int stat;
> + unsigned int timeout;
> + bool local_p = (cpu_cluster(current_hartid()) == cpu_cluster(hartid));
> +
> + /* Hart 0 is the boot hart, and we don't use the CPC cmd to start. */
> + if (hartid == 0)
> + return SBI_ENOTSUPP;
> +
> + if (cpu_hart(hartid) == 0) {
> + /* Change cluster cl core co hart 0 reset base */
> + write_gcr_co_reset_base(hartid,
> + (unsigned long)mips_cps_core_entry, local_p);
> +
> + /* Ensure its coherency is disabled */
> + write_gcr_co_coherence(hartid, 0, local_p);
> +
> + /* Start cluster cl core co hart 0 */
> + write_cpc_co_vp_run(hartid, 1 << cpu_hart(hartid), local_p);
> +
> + /* Reset cluster cl core co hart 0 */
> + write_cpc_co_cmd(hartid, CPC_Cx_CMD_RESET, local_p);
> +
> + timeout = 100;
> + while (true) {
> + stat = read_cpc_co_stat_conf(hartid, local_p);
> + stat = EXT(stat, CPC_Cx_STAT_CONF_SEQ_STATE);
> + if (stat == CPC_Cx_STAT_CONF_SEQ_STATE_U6)
> + break;
> +
> + /* Delay a little while before we start warning */
> + if (timeout) {
> + sbi_timer_mdelay(10);
> + timeout--;
> + }
> + else {
> + sbi_printf("Waiting for cluster %u core %u hart %u to start... STAT_CONF=0x%x\n",
> + cpu_cluster(hartid),
> + cpu_core(hartid), cpu_hart(hartid),
> + stat);
> + break;
> + }
> + }
> + }
> + else {
> + write_gcr_co_reset_base(hartid,
> + (unsigned long)mips_cps_core_entry, local_p);
> + write_cpc_co_vp_run(hartid, 1 << cpu_hart(hartid), local_p);
> + }
> +
> + return 0;
> +}
> +
> +static int mips_hart_stop()
> +{
> + u32 hartid = current_hartid();
> + bool local_p = (cpu_cluster(current_hartid()) == cpu_cluster(hartid));
> +
> + /* Hart 0 is the boot hart, and we don't use the CPC cmd to stop. */
> + if (hartid == 0)
> + return SBI_ENOTSUPP;
> +
> + write_cpc_co_vp_stop(hartid, 1 << cpu_hart(hartid), local_p);
> +
> + return 0;
> +}
> +
> +static const struct sbi_hsm_device mips_hsm = {
> + .name = "mips_hsm",
> + .hart_start = mips_hart_start,
> + .hart_stop = mips_hart_stop,
> +};
> +
> +static int mips_p8700_final_init(bool cold_boot, void *fdt,
> + const struct fdt_match *match)
> +{
> + if (cold_boot)
> + sbi_hsm_set_device(&mips_hsm);
> +
> + return 0;
> +}
> +
> +static int mips_p8700_early_init(bool cold_boot, const void *fdt,
> + const struct fdt_match *match)
> +{
> + int rc;
> +
> + if (cold_boot)
> + {
> +#if CLUSTERS_IN_PLATFORM > 1
> + int i;
> + /* Power up other clusters in the platform. */
> + for (i = 1; i < CLUSTERS_IN_PLATFORM; i++) {
> + power_up_other_cluster(i << NEW_CLUSTER_SHIFT);
> + }
> +#endif
> +
> + /* For the CPC mtime region, the minimum size is 0x10000. */
> + rc = sbi_domain_root_add_memrange(CM_BASE, SIZE_FOR_CPC_MTIME,
> + P8700_ALIGN,
> + (SBI_DOMAIN_MEMREGION_MMIO |
> + SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> + if (rc)
> + return rc;
> +
> + /* For the APLIC and ACLINT m-mode region */
> + rc = sbi_domain_root_add_memrange(AIA_BASE, SIZE_FOR_AIA_M_MODE,
> + P8700_ALIGN,
> + (SBI_DOMAIN_MEMREGION_MMIO |
> + SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> + if (rc)
> + return rc;
> +
> +#if CLUSTERS_IN_PLATFORM > 1
> + for (i = 0; i < CLUSTERS_IN_PLATFORM; i++) {
> + /* For the CPC mtime region, the minimum size is 0x10000. */
> + rc = sbi_domain_root_add_memrange(GLOBAL_CM_BASE[i], SIZE_FOR_CPC_MTIME,
> + P8700_ALIGN,
> + (SBI_DOMAIN_MEMREGION_MMIO |
> + SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> + if (rc)
> + return rc;
> +
> + /* For the APLIC and ACLINT m-mode region */
> + rc = sbi_domain_root_add_memrange(AIA_BASE - CM_BASE + GLOBAL_CM_BASE[i], SIZE_FOR_AIA_M_MODE,
> + P8700_ALIGN,
> + (SBI_DOMAIN_MEMREGION_MMIO |
> + SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> + if (rc)
> + return rc;
> + }
> +#endif
> + }
> +
> + return 0;
> +}
> +
> +static const struct fdt_match mips_p8700_match[] = {
> + { .compatible = "mips,p8700" },
> + { },
> +};
> +
> +const struct platform_override mips_p8700 = {
> + .match_table = mips_p8700_match,
> + .early_init = mips_p8700_early_init,
> + .final_init = mips_p8700_final_init,
> +};
> diff --git a/platform/generic/mips/stw.S b/platform/generic/mips/stw.S
> new file mode 100644
> index 0000000..098a1c5
> --- /dev/null
> +++ b/platform/generic/mips/stw.S
> @@ -0,0 +1,986 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + * This file implements MIPS custom exception handler for software table walker when hardware table
> + * walker is disabled or not available, rdtime emulation, and AMO instruction emulation.
> + */
> +
> +
> +/* Define STW_TLB_4KB to force to use 4KB pages in every level for software table walker.
> + This is for debugging only. */
> +//#define STW_TLB_4KB 1
> +
> +#include <mips/stw.h>
> +#include <mips/board.h>
> +#include <mips/p8700.h>
> +
> +#if defined(__riscv_zbb)
> +#define ZBB_PRESENT 1
> +#endif
> +
> + .text
> + .align 8
> + .globl mipstvec_handler_stw
> +mipstvec_handler_stw:
> + j mipstvec_handler_stw_not_vec ; .align 2 /* 0 */
> + j fail ; .align 2 /* 1 */
> + j illegal_inst_handler ; .align 2 /* 2 */
> + j fail ; .align 2 /* 3 */
> + j fail ; .align 2 /* 4 */
> + j htw_load_access_fault_handler ; .align 2 /* 5 */
> + j fail ; .align 2 /* 6 */
> + j fail ; .align 2 /* 7 */
> + j fail ; .align 2 /* 8 */
> + j fail ; .align 2 /* 9 */
> + j fail ; .align 2 /* 10 */
> + j fail ; .align 2 /* 11 */
> + j fail ; .align 2 /* 12 */
> + j fail ; .align 2 /* 13 */
> + j fail ; .align 2 /* 14 */
> + j fail ; .align 2 /* 15 */
> + j fail ; .align 2 /* 16 */
> + j fail ; .align 2 /* 17 */
> + j fail ; .align 2 /* 18 */
> + j fail ; .align 2 /* 19 */
> + j fail ; .align 2 /* 20 */
> + j htw_page_fault_handler ; .align 2 /* 21 */
> + j fail ; .align 2 /* 22 */
> + j fail ; .align 2 /* 23 */
> + j satp_refill_handler ; .align 2 /* 24 */
> + j satp_refill_handler ; .align 2 /* 25 */
> + j read_time_handler ; .align 2 /* 26 */
> + j satp_refill_handler ; .align 2 /* 27 */
> + j hgatp_refill_handler ; .align 2 /* 28 */
> + j hgatp_refill_handler ; .align 2 /* 29 */
> + j read_time_handler ; .align 2 /* 30 */
> + j hgatp_refill_handler ; .align 2 /* 31 */
> +
> +mipstvec_handler_stw_not_vec:
> + csrci CSR_MIPSCONFIG5, MIPSCONFIG5_MTW
> + csrrw sp, mscratch, sp // Save sp to mscratch, load mscratch to sp
> + sd x1, O_save_x1(sp) // Save x1 to memory
> + csrr x1, mcause // Read mcause
> +
> +#define _mipstvec_handler_dispatch(i) ; \
> + addi x1, x1, -i ; \
> + bnez x1, 10f ; \
> + ld x1, O_save_x1(sp) ; \
> + csrrw sp, mscratch, sp ; \
> + j mipstvec_handler_stw + 4 * i ; \
> +10: addi x1, x1, i
> +
> +#define _mipstvec_handler_dispatch_mtw(i) ; \
> + addi x1, x1, -i ; \
> + bnez x1, 10f ; \
> + ld x1, O_save_x1(sp) ; \
> + csrrw sp, mscratch, sp ; \
> + csrsi CSR_MIPSCONFIG5, MIPSCONFIG5_MTW ; \
> + j mipstvec_handler_stw + 4 * i ; \
> +10: addi x1, x1, i
> +
> + _mipstvec_handler_dispatch(2)
> + _mipstvec_handler_dispatch(20)
> + _mipstvec_handler_dispatch(21)
> + _mipstvec_handler_dispatch(23)
> + _mipstvec_handler_dispatch(24)
> + _mipstvec_handler_dispatch(25)
> + _mipstvec_handler_dispatch(26)
> + _mipstvec_handler_dispatch(27)
> + _mipstvec_handler_dispatch_mtw(28)
> + _mipstvec_handler_dispatch_mtw(29)
> + _mipstvec_handler_dispatch_mtw(30)
> + _mipstvec_handler_dispatch_mtw(31)
> + j fail
> +
> +satp_refill_handler:
> +vsatp_refill_handler:
> + csrrw sp, mscratch, sp /* sp = mscratch; mscratch = saved sp */
> + sd t0, O_satp_vsatp_scratch0(sp) /* save t0 */
> + csrrw t0, mscratch, sp /* t0 = saved sp; restore mscratch */
> + sd t0, O_satp_vsatp_scratch8(sp) /* save sp */
> + sd t1, O_satp_vsatp_scratch1(sp) /* save t1 */
> + sd t2, O_satp_vsatp_scratch2(sp) /* save t2 */
> + sd t3, O_satp_vsatp_scratch3(sp) /* save t3 */
> + sd s4, O_satp_vsatp_scratch4(sp) /* save s4 */
> + sd t5, O_satp_vsatp_scratch5(sp) /* save t5 */
> + sd t6, O_satp_vsatp_scratch6(sp) /* save t6 */
> + sd s7, O_satp_vsatp_scratch7(sp) /* save s7 */
> +
> + /* Save mstatus, mepc (not actually needed for non-vmode refill) */
> + csrr s4, mstatus
> + csrr t5, mepc
> + csrrsi t6, CSR_MIPSCONFIG5, MIPSCONFIG5_MTW /* set MTW bit */
> +
> + /* Only V can be set out of following bits for PTE to be non-leaf */
> + li s7, PTE_V | PTE_R | PTE_W | PTE_X | PTE_U | PTE_A | PTE_D | PTE_N | PTE_RSVD
> +
> +_read_xsatp:
> + /* t1 = vsatp if vmode exception (mstatus.GVA=1) else satp */
> + sll t3, s4, __riscv_xlen - 1 - mstatus_GVA_LSB
> + bgez t3, 1f
> + csrr t3, vsatp
> + j 2f
> +1: csrr t3, satp
> +2:
> +
> +_find_xsatp_mode:
> + slli t0, t3, 20 // t0 = satp.PPN << 20 (clear out MODE, ASID)
> + srli t0, t0, 8 // "a" = t0 = satp.PPN << 12 (i.e. * PAGESIZE)
> + li t1, 0 // Is this PTE global? (Need to track during walk).
> + csrr t2, mtval // va
> +
> + // Branch according to xsatp.MODE
> + srli t3, t3, 60
> + addi t3, t3, -SATP_MODE_SV39
> + beqz t3, _xsatp_Sv39_level2 // Sv39
> + addi t3, t3, SATP_MODE_SV39 - SATP_MODE_SV48
> + beqz t3, _xsatp_Sv39_level3 // Sv48
> + j fail
> +
> +_xsatp_Sv39_level3:
> + extract (t3, t2, 47, 39) // t3 = VPN[2]
> + slli t3, t3, 3 // t3 = VPN[2] * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] * PTESIZE
> + ld t0, 0(t0) // t0 = PTE
> + and t3, t0, s7
> + xori t3, t3, PTE_V
> + bnez t3, _xsatp_level3_leaf
> + andi t3, t0, PTE_G
> + or t1, t1, t3
> + extract (t0, t0, 53, 10) // t0 = PTE[53:10]
> + slli t0, t0, 12 // "a" = t0 = PTE[53:10] * PAGESIZE
> +
> +_xsatp_Sv39_level2:
> + extract (t3, t2, 38, 30) // t3 = VPN[2]
> + slli t3, t3, 3 // t3 = VPN[2] * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] * PTESIZE
> + ld t0, 0(t0) // t0 = PTE
> + and t3, t0, s7
> + xori t3, t3, PTE_V
> + bnez t3, _xsatp_level2_leaf
> + andi t3, t0, PTE_G
> + or t1, t1, t3
> + extract (t0, t0, 53, 10) // t0 = PTE[53:10]
> + slli t0, t0, 12 // "a" = t0 = PTE[53:10] * PAGESIZE
> +
> +_xsatp_Sv39_level1:
> + extract (t3, t2, 29, 21) // t3 = VPN[2]
> + slli t3, t3, 3 // t3 = VPN[2] * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] * PTESIZE
> + ld t0, 0(t0) // t0 = PTE
> + and t3, t0, s7
> + xori t3, t3, PTE_V
> + bnez t3, _xsatp_level1_leaf
> + andi t3, t0, PTE_G
> + or t1, t1, t3
> + extract (t0, t0, 53, 10) // t0 = PTE[53:10]
> + slli t0, t0, 12 // "a" = t0 = PTE[53:10] * PAGESIZE
> +
> +_xsatp_Sv39_level0:
> + extract (t3, t2, 20, 13) // t3 = VPN[2] (even page)
> + slli t3, t3, 4 // t3 = VPN[2] (even page) * 2 * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] (even page) 2 * PTESIZE
> + ld t3, 0(t0) // t3 = even PTE
> + ld t0, 8(t0) // t0 = odd PTE
> +
> +_xsatp_level0_leaf:
> + or t3, t3, t1 // global if parent table is global
> + or t0, t0, t1 // global if parent table is global
> + li t1, 0x1000 // even/odd bit
> + or t2, t2, t1 // Odd page mtval
> + csrw mtval, t2
> + MTLBWR (t0, 0) // Write odd PTE to TLB
> + csrc mtval, t1 // Even page mtval
> + MTLBWR (t3, 0) // Write even PTE to TLB
> +
> +_xsatp_mret:
> + csrw mstatus, s4 /* Restore mstatus */
> + csrw mepc, t5 /* Restore mepc */
> + csrw CSR_MIPSCONFIG5, t6 /* Restore mipsconfig5 */
> +
> + ld t0, O_satp_vsatp_scratch0(sp) /* restore t0 */
> + ld t1, O_satp_vsatp_scratch1(sp) /* restore t1 */
> + ld t2, O_satp_vsatp_scratch2(sp) /* restore t2 */
> + ld t3, O_satp_vsatp_scratch3(sp) /* restore t3 */
> + ld s4, O_satp_vsatp_scratch4(sp) /* restore s4 */
> + ld t5, O_satp_vsatp_scratch5(sp) /* restore t5 */
> + ld t6, O_satp_vsatp_scratch6(sp) /* restore t6 */
> + ld s7, O_satp_vsatp_scratch7(sp) /* restore sp */
> + ld sp, O_satp_vsatp_scratch8(sp) /* restore sp */
> +
> + mret
> +
> +_xsatp_level1_leaf:
> + or t0, t0, t1 // global if parent table is global
> +#ifdef STW_TLB_4KB
> + extract (t3, t2, 20, 12)
> + sll t3, t3, 10
> + or t0, t0, t3
> + csrw mtval, t2
> + MTLBWR (t0, 0)
> +#else
> + csrw mtval, t2
> + MTLBWR (t0, 1)
> +#endif
> + j _xsatp_mret
> +
> +_xsatp_level2_leaf:
> + or t0, t0, t1 // global if parent table is global
> +#ifdef STW_TLB_4KB
> + extract (t3, t2, 29, 12)
> + sll t3, t3, 10
> + or t0, t0, t3
> + csrw mtval, t2
> + MTLBWR (t0, 0)
> +#else
> + csrw mtval, t2
> + MTLBWR (t0, 2)
> +#endif
> + j _xsatp_mret
> +
> +_xsatp_level3_leaf:
> + or t0, t0, t1 // global if parent table is global
> +#ifdef STW_TLB_4KB
> + extract (t3, t2, 38, 12)
> + sll t3, t3, 10
> + or t0, t0, t3
> + csrw mtval, t2
> + MTLBWR (t0, 0)
> +#else
> + csrw mtval, t2
> + MTLBWR (t0, 3)
> +#endif
> + j _xsatp_mret
> +
> +hgatp_refill_handler:
> + csrrw sp, mscratch, sp /* sp = mscratch; mscratch = saved sp */
> + sd t0, O_hgatp_scratch0(sp) /* save t0 */
> + csrrw t0, mscratch, sp /* t0 = saved sp; restore mscratch */
> + sd t0, O_hgatp_scratch5(sp) /* save sp */
> + sd t1, O_hgatp_scratch1(sp) /* save t1 */
> + sd t2, O_hgatp_scratch2(sp) /* save t2 */
> + sd t3, O_hgatp_scratch3(sp) /* save t3 */
> + sd s4, O_hgatp_scratch4(sp) /* save s4 */
> +
> + /* Only V can be set out of following bits for PTE to be non-leaf */
> + li s4, PTE_V | PTE_R | PTE_W | PTE_X | PTE_U | PTE_A | PTE_D | PTE_N | PTE_RSVD
> +
> + /* set MTW=1 */
> + csrsi CSR_MIPSCONFIG5, MIPSCONFIG5_MTW
> +
> +_find_hgatp_mode:
> + csrr t3, hgatp
> + slli t0, t3, 20 // t0 = hgatp.PPN << 20 (clear out MODE, ASID)
> + srli t0, t0, 8 // "a" = t0 = hgatp.PPN << 12 (i.e. * PAGESIZE)
> + li t1, 0 // Is this PTE global? (Need to track during walk).
> + csrr t2, mtval // gpa
> +
> + // Branch according to hgatp.MODE
> + srli t3, t3, 60
> + addi t3, t3, -SATP_MODE_SV39
> + bnez t3, 1f
> + extract (t3, t2, 38, 28) // t3 = VPN[2]
> + j _hgatp_Sv39x4_level2_got_vpn2
> +1: addi t3, t3, SATP_MODE_SV39 - SATP_MODE_SV48
> + beqz t3, _hgatp_Sv39x4_level3
> + j fail
> +
> +_hgatp_Sv39x4_level3:
> + extract (t3, t2, 47, 37) // t3 = VPN[2]
> + slli t3, t3, 3 // t3 = VPN[2] * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] * PTESIZE
> + ld t0, 0(t0) // t0 = PTE
> + and t3, t0, s4
> + xori t3, t3, PTE_V
> + bnez t3, _hgatp_level3_leaf
> + andi t3, t0, PTE_G
> + or t1, t1, t3
> + extract (t0, t0, 53, 10) // t0 = PTE[53:10]
> + slli t0, t0, 12 // "a" = t0 = PTE[53:10] * PAGESIZE
> +
> +_hgatp_Sv39x4_level2:
> + extract (t3, t2, 36, 28) // t3 = VPN[2]
> +_hgatp_Sv39x4_level2_got_vpn2:
> + slli t3, t3, 3 // t3 = VPN[2] * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] * PTESIZE
> + ld t0, 0(t0) // t0 = PTE
> + and t3, t0, s4
> + xori t3, t3, PTE_V
> + bnez t3, _hgatp_level2_leaf
> + andi t3, t0, PTE_G
> + or t1, t1, t3
> + extract (t0, t0, 53, 10) // t0 = PTE[53:10]
> + slli t0, t0, 12 // "a" = t0 = PTE[53:10] * PAGESIZE
> +
> +_hgatp_Sv39x4_level1:
> + extract (t3, t2, 27, 19) // t3 = VPN[2]
> + slli t3, t3, 3 // t3 = VPN[2] * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] * PTESIZE
> + ld t0, 0(t0) // t0 = PTE
> + and t3, t0, s4
> + xori t3, t3, PTE_V
> + bnez t3, _hgatp_level1_leaf
> + andi t3, t0, PTE_G
> + or t1, t1, t3
> + extract (t0, t0, 53, 10) // t0 = PTE[53:10]
> + slli t0, t0, 12 // "a" = t0 = PTE[53:10] * PAGESIZE
> +
> +_hgatp_Sv39x4_level0:
> + extract (t3, t2, 18, 11) // t3 = VPN[2] (even page)
> + slli t3, t3, 4 // t3 = VPN[2] (even page) * 2 * PTESIZE
> + add t0, t0, t3 // t0 = a + VPN[2] (even page) 2 * PTESIZE
> + ld t2, 0(t0) // t2 = even PTE
> + ld t3, 8(t0) // t3 = odd PTE
> +
> +_hgatp_level0_leaf:
> + or t2, t2, t1 // global if parent table is global
> + or t3, t3, t1 // global if parent table is global
> + li t0, 0x0400 // even/odd bit
> + csrc mtval, t0
> + MTLBWR_HG (t2, 0)
> + csrs mtval, t0
> + MTLBWR_HG (t3, 0)
> +
> +_hgatp_mret:
> + csrci CSR_MIPSCONFIG5, MIPSCONFIG5_MTW /* Clear MTW bit */
> +
> + ld t0, O_hgatp_scratch0(sp) /* restore t0 */
> + ld t1, O_hgatp_scratch1(sp) /* restore t1 */
> + ld t2, O_hgatp_scratch2(sp) /* restore t2 */
> + ld t3, O_hgatp_scratch3(sp) /* restore t3 */
> + ld s4, O_hgatp_scratch4(sp) /* restore s4 */
> + ld sp, O_hgatp_scratch5(sp) /* restore sp */
> +
> + mret
> +
> +_hgatp_level1_leaf:
> + or t0, t0, t1 // global if parent table is global
> +#ifdef STW_TLB_4KB
> + extract (t3, t2, 20, 12)
> + sll t3, t3, 10
> + or t0, t0, t3
> + MTLBWR_HG (t0, 0)
> +#else
> + MTLBWR_HG (t0, 1)
> +#endif
> + j _hgatp_mret
> +
> +_hgatp_level2_leaf:
> + or t0, t0, t1 // global if parent table is global
> +#ifdef STW_TLB_4KB
> + extract (t3, t2, 29, 12)
> + sll t3, t3, 10
> + or t0, t0, t3
> + MTLBWR_HG (t0, 0)
> +#else
> + MTLBWR_HG (t0, 2)
> +#endif
> + j _hgatp_mret
> +
> +_hgatp_level3_leaf:
> + or t0, t0, t1 // global if parent table is global
> +#ifdef STW_TLB_4KB
> + extract (t3, t2, 38, 12)
> + sll t3, t3, 10
> + or t0, t0, t3
> + MTLBWR_HG (t0, 0)
> +#else
> + MTLBWR_HG (t0, 3)
> +#endif
> + j _hgatp_mret
> +
> +htw_load_access_fault_handler:
> +htw_hgatp_refill_handler:
> +htw_page_fault_handler:
> + j fail
> +
> +
> +
> +/********************
> + * rdtime emulation *
> + ********************/
> + .global read_time_handler
> +read_time_handler:
> + csrrw sp, mscratch, sp /* sp = mscratch; mscratch = saved sp */
> + sd x1, O_satp_vsatp_scratch0(sp) /* save sp */
> + sd x3, O_satp_vsatp_scratch1(sp) /* save x3 */
> +
> + /* Set x1 to address of function which will set rd to x3 */
> + csrr x1, mtval
> + srli x1, x1, 7 - JUMP_TABLE_SHIFT
> + andi x1, x1, 0x1f << JUMP_TABLE_SHIFT
> + lla x3, write_xr_rdtime
> + add x1, x1, x3
> +
> + /* Read the time memory mapped register */
> + lui x3, %hi(TIMER_ADDR)
> + ld x3, %lo(TIMER_ADDR)(x3)
> +
> + /* Call function which sets rd = x3 */
> + jalr x1
> +
> + /* Increment mepc to skip instruction we just emulated */
> + csrr x1, mepc
> + addi x1, x1, 4
> + csrw mepc, x1
> +
> + /* Restore gprs from memory */
> + ld x1, O_satp_vsatp_scratch0(sp) /* restore x1 */
> + ld x3, O_satp_vsatp_scratch1(sp) /* restore x3 */
> + csrrw sp, mscratch, sp
> +
> + mret
> +
> +/***************************************
> + * Custom Illegal Instruction handling *
> + ***************************************/
> +
> +illegal_inst_handler:
> + csrrw sp, mscratch, sp /* sp = mscratch; mscratch = saved sp */
> + sd x1, (O_amo_scratch + 0 * 8)(sp)
> + csrrw x1, mscratch, sp /* x1 = saved sp; restore mscratch */
> + sd x1, (O_amo_scratch + 1 * 8)(sp) /* save sp */
> + sd x3, (O_amo_scratch + 2 * 8)(sp)
> + sd x4, (O_amo_scratch + 3 * 8)(sp)
> + sd x5, (O_amo_scratch + 4 * 8)(sp)
> + sd x6, (O_amo_scratch + 5 * 8)(sp)
> + sd x7, (O_amo_scratch + 6 * 8)(sp)
> + sd x8, (O_amo_scratch + 7 * 8)(sp)
> + sd x9, (O_amo_scratch + 8 * 8)(sp)
> + sd x10, (O_amo_scratch + 9 * 8)(sp)
> +
> +// Planned register use:
> +// x1 - ra, temporary, result
> +// x2 - sp
> +// x3 - rs1 value
> +// x4 - rs2 value
> +// x5 - temporary (mtval, mtval_match)
> +// x6 - saved mepc
> +// x7 - saved mtvec
> +// x8 - saved mstatus
> +// x9 - saved mtval
> +// x10 - temporary (fail count)
> +
> + csrr x9, mtval // x9 = faulting opcode
> +
> + /* x3 = rs1 value */
> + lla x7, read_xr_amo // x7 = base address of table of read_xr funcs
> + srli x6, x9, 15 - JUMP_TABLE_SHIFT // Align rs1 idx as table offset
> + andi x6, x6, 0x1f << JUMP_TABLE_SHIFT // Isolated aligned rs1
> + add x4, x6, x7 // Apply offset to jump table
> + jalr x4 // Call func to read rs1 into x4
> + move x3, x4 // x3 = rs1 value
> +
> + /* x4 = rs2 value */
> + srli x6, x9, 20 - JUMP_TABLE_SHIFT // Align rs2 idx as table offset
> + andi x6, x6, 0x1f << JUMP_TABLE_SHIFT // Isolate aligned rs2
> + add x4, x6, x7 // Apply offset to jump table
> + jalr x4 // Call func to read rs1 into x4
> +
> + /* x6 = saved epc */
> + csrr x6, mepc // Save mepc
> +
> + /* Use a local handler for mtvec exceptions */
> + lla x1, _illegal_inst_mtvec_handler
> + csrrw x7, mtvec, x1 // x7 = saved mtvec
> +
> + /*
> + * Extract the AMO opcode match bits, write that value to t5. Each AMO
> + * instruction has a single unique value for these match bits. Since
> + * every AMO has the same value for the lower 12 bits, we xor the
> + * match value with the value of those lower 12 bits. This allows us
> + * to construct the compare value for each AMO instruction using a
> + * single LUI instruction.
> + */
> + li x1, 0b11111000000000000111000001111111
> + and x5, x9, x1
> + xori x5, x5, 0b000000101111
> +
> + li x1, 0b00000000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amoadd_w
> +
> + li x1, 0b00000000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amoadd_d
> +
> + li x1, 0b01100000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amoand_w
> +
> + li x1, 0b01100000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amoand_d
> +
> + li x1, 0b10100000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amomax_w
> +
> + li x1, 0b10100000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amomax_d
> +
> + li x1, 0b11100000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amomaxu_w
> +
> + li x1, 0b11100000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amomaxu_d
> +
> + li x1, 0b10000000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amomin_w
> +
> + li x1, 0b10000000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amomin_d
> +
> + li x1, 0b11000000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amominu_w
> +
> + li x1, 0b11000000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amominu_d
> +
> + li x1, 0b01000000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amoor_w
> +
> + li x1, 0b01000000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amoor_d
> +
> + li x1, 0b00001000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amoswap_w
> +
> + li x1, 0b00001000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amoswap_d
> +
> + li x1, 0b00100000000000000010000000000000
> + beq x5, x1, _illegal_inst_handler_amoxor_w
> +
> + li x1, 0b00100000000000000011000000000000
> + beq x5, x1, _illegal_inst_handler_amoxor_d
> +
> + j fail
> +
> +/**
> + * Input:
> + * x3 = rs1
> + * x4 = rs2
> + * Ouput:
> + * x5 = old memory value
> + *
> + * Try LR/SC while counting down from NUM_TRIES_WITHOUT_LOCK to 0.
> + * If counter reaches 0, acquire the global lock, then repeat LR/SC,
> + * counting down from NUM_TRIES_WITHOUT_LOCK + NUM_TRIES_WITH_LOCK to
> + * NUM_TRIES_WITHOUT_LOCK + 1
> + * If counter reaches NUM_TRIES_WITHOUT_LOCK + 1 then fail completely.
> + * On LR/SC success, if counter > NUM_TRIES_WITHOUT_LOCK then we had the lock,
> + * and need to release it.
> + *
> + * Pseudocode:
> + *
> + * # Wait until not locked.
> + * while locked:
> + * pass
> + *
> + * counter = NUM_TRIES_WITHOUT_LOCK
> + * while 1:
> + * value, fail = amo()
> + * if fail: # SC fail.
> + * counter -= NUM_TRIES_WITHOUT_LOCK + 1
> + * if counter == 0:
> + * fail
> + * counter += NUM_TRIES_WITHOUT_LOCK
> + * if counter == 0:
> + * get_lock()
> + * counter = NUM_TRIES_WITH_LOCK + NUM_TRIES_WITHOUT_LOCK
> + * else: # SC pass.
> + * counter -= NUM_TRIES_WITH_LOCK
> + * if counter > 0:
> + * free_lock()
> + * return
> + */
> +
> +#define NUM_TRIES_WITHOUT_LOCK 20
> +#define NUM_TRIES_WITH_LOCK 10000
> +//#define NO_AMO_EMULATION_LOCK 1
> +
> +#if NO_AMO_EMULATION_LOCK
> +#define DO_AMO(SIZE, AMO_OPERATION...) ; \
> + /* Set mstatus.MPRV = 1, x8 = saved mstatus */ ; \
> +25: li x8, MSTATUS_MPRV ; \
> + csrrs x8, mstatus, x8 ; \
> + ; \
> +30: lr.SIZE.aq x5, (x3) ; \
> + AMO_OPERATION ; \
> + sc.SIZE.aqrl x1, x1, (x3) ; \
> + beqz x1, _illegal_inst_handler_return ; \
> + j 30b
> +#else
> +#define DO_AMO(SIZE, AMO_OPERATION...) ; \
> + /* Wait until lock is clear */ ; \
> + lla x10, amo_lock ; \
> +10: lr.d x5, (x10) ; \
> + beqz x5, 20f ; \
> + PAUSE() ; \
> + j 10b ; \
> + ; \
> +20: li x10, NUM_TRIES_WITHOUT_LOCK ; \
> + ; \
> + /* Set mstatus.MPRV = 1, x8 = saved mstatus */ ; \
> +25: li x8, MSTATUS_MPRV ; \
> + csrrs x8, mstatus, x8 ; \
> + ; \
> +30: lr.SIZE.aq x5, (x3) ; \
> + AMO_OPERATION ; \
> + sc.SIZE.aqrl x1, x1, (x3) ; \
> + beqz x1, _illegal_inst_handler_return ; \
> + /* SC failed */ ; \
> + addi x10, x10, -NUM_TRIES_WITHOUT_LOCK + 1 ; \
> + bnez x10, 40f ; \
> + csrw mstatus, x8 ; \
> + j fail ; \
> +40: addi x10, x10, NUM_TRIES_WITHOUT_LOCK ; \
> + bnez x10, 30b ; \
> + ; \
> + /* Acquire lock */ ; \
> + csrw mstatus, x8 ; \
> + lla x10, amo_lock ; \
> +50: lr.d x5, (x10) ; \
> + beqz x5, 60f ; \
> + PAUSE() ; \
> + j 50b ; \
> +60: sc.d x5, sp, (x10) /* Use sp as lock value */ ; \
> + bnez x5, 50b ; \
> + ; \
> + /* Retry with lock */ ; \
> + li x10, NUM_TRIES_WITH_LOCK + NUM_TRIES_WITHOUT_LOCK ; \
> + j 25b
> +#endif /* NO_AMO_EMULATION_LOCK */
> +
> +_illegal_inst_handler_amoadd_w:
> + DO_AMO(w, addw x1, x5, x4)
> +
> +_illegal_inst_handler_amoadd_d:
> + DO_AMO(d, add x1, x5, x4)
> +
> +_illegal_inst_handler_amoand_w:
> + DO_AMO(w, and x1, x5, x4)
> +
> +_illegal_inst_handler_amoand_d:
> + DO_AMO(d, and x1, x5, x4)
> +
> +_illegal_inst_handler_amomax_w:
> + addw x4, x4, x0
> +#if ZBB_PRESENT
> + DO_AMO(w, max x1, x5, x4)
> +#else
> + DO_AMO(w,
> + move x1, x5 ;
> + bge x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amomax_d:
> +#if ZBB_PRESENT
> + DO_AMO(d, max x1, x5, x4)
> +#else
> + DO_AMO(d,
> + move x1, x5 ;
> + bge x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amomaxu_w:
> + addw x4, x4, x0
> +#if ZBB_PRESENT
> + DO_AMO(w, maxu x1, x5, x4)
> +#else
> + DO_AMO(w,
> + move x1, x5 ;
> + bgeu x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amomaxu_d:
> +#if ZBB_PRESENT
> + DO_AMO(d, maxu x1, x5, x4)
> +#else
> + DO_AMO(d,
> + move x1, x5 ;
> + bgeu x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amomin_w:
> + addw x4, x4, x0
> +#if ZBB_PRESENT
> + DO_AMO(w, min x1, x5, x4)
> +#else
> + DO_AMO(w,
> + move x1, x5 ;
> + ble x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amomin_d:
> +#if ZBB_PRESENT
> + DO_AMO(d, min x1, x5, x4)
> +#else
> + DO_AMO(d,
> + move x1, x5 ;
> + ble x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amominu_w:
> + addw x4, x4, x0
> +#if ZBB_PRESENT
> + DO_AMO(w, minu x1, x5, x4)
> +#else
> + DO_AMO(w,
> + move x1, x5 ;
> + bleu x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amominu_d:
> +#if ZBB_PRESENT
> + DO_AMO(d, minu x1, x5, x4)
> +#else
> + DO_AMO(d,
> + move x1, x5 ;
> + bleu x5, x4, 5f ;
> + move x1, x4 ;
> +5:
> + )
> +#endif
> +
> +_illegal_inst_handler_amoor_w:
> + DO_AMO(w, or x1, x5, x4)
> +
> +_illegal_inst_handler_amoor_d:
> + DO_AMO(d, or x1, x5, x4)
> +
> +_illegal_inst_handler_amoswap_w:
> + DO_AMO(w, move x1, x4)
> +
> +_illegal_inst_handler_amoswap_d:
> + DO_AMO(d, move x1, x4)
> +
> +_illegal_inst_handler_amoxor_w:
> + DO_AMO(w, xor x1, x5, x4)
> +
> +_illegal_inst_handler_amoxor_d:
> + DO_AMO(d, xor x1, x5, x4)
> +
> +_illegal_inst_handler_return:
> + csrw mstatus, x8 // Restore mstatus (undo MPRV)
> +
> +#if NO_AMO_EMULATION_LOCK
> +#else
> + /* Clear amo_lock if we had acquired it. */
> + addi x10, x10, -NUM_TRIES_WITHOUT_LOCK
> + blez x10, 10f
> + lla x10, amo_lock
> + sd x0, (x10)
> +10:
> +#endif /* NO_AMO_EMULATION_LOCK */
> +
> + /* write rd with value in x5 */
> + lla x4, write_xr_amo // x4 = base address of write_xr funcs
> + srli x3, x9, 7 - JUMP_TABLE_SHIFT // Align rd idx as table offset
> + andi x3, x3, 0x1f << JUMP_TABLE_SHIFT // Isolate aligned rd
> + add x1, x4, x3 // Apply offset to jump table
> + jalr x1 // Call func to write x5 to rd
> +
> + addi x6, x6, 4 // Saved mepc += 4 (skip emulated instruction)
> +
> +_illegal_inst_handler_mret:
> + csrw mepc, x6 // Restore mepc
> + csrw mtvec, x7 // Restore mtvec
> +
> + /* Restore working set of XRs */
> + ld x1, (O_amo_scratch + 0 * 8)(sp)
> + ld x3, (O_amo_scratch + 2 * 8)(sp)
> + ld x4, (O_amo_scratch + 3 * 8)(sp)
> + ld x5, (O_amo_scratch + 4 * 8)(sp)
> + ld x6, (O_amo_scratch + 5 * 8)(sp)
> + ld x7, (O_amo_scratch + 6 * 8)(sp)
> + ld x8, (O_amo_scratch + 7 * 8)(sp)
> + ld x9, (O_amo_scratch + 8 * 8)(sp)
> + ld x10, (O_amo_scratch + 9 * 8)(sp)
> + ld sp, (O_amo_scratch + 1 * 8)(sp) /* restore sp last */
> +
> + mret // Return
> +
> + .align 2
> +_illegal_inst_mtvec_handler:
> + /*
> + * If any exception occurs on a load/store during AMO emulation,
> + * just re-execute the original faulting AMO. This will regenerate
> + * the exception (page fault, access fault) and allow it to
> + * be handled as though from the original context
> + */
> + csrw mstatus, x8 // Restore mstatus
> +
> + csrr x5, mcause
> +
> + li x1, CAUSE_LOAD_PAGE_FAULT
> + beq x5, x1, _illegal_inst_handler_mret
> +
> + li x1, CAUSE_STORE_PAGE_FAULT
> + beq x5, x1, _illegal_inst_handler_mret
> +
> + li x1, CAUSE_GUEST_LOAD_PAGE_FAULT
> + beq x5, x1, _illegal_inst_handler_mret
> +
> + li x1, CAUSE_GUEST_STORE_PAGE_FAULT
> + beq x5, x1, _illegal_inst_handler_mret
> +
> + li x1, CAUSE_LOAD_ACCESS
> + beq x5, x1, _illegal_inst_handler_mret
> +
> + li x1, CAUSE_STORE_ACCESS
> + beq x5, x1, _illegal_inst_handler_mret
> +
> + // An unexpected exception during AMO emulation is fatal.
> + j fail
> +
> +/**
> + * This is a table of 32 functions.
> + * Calling the function read_xr_amo + rd * JUMP_TABLE_OFFSET does
> + * x4 = XR[rd]. For xrs where the value is stored in memory by the AMO handler,
> + * do x4 = MEM[address where $rd is stored], which has the equivalent effect.
> + */
> +read_xr_amo:
> + li x4, 0 ; jr ra
> + ld x4, (O_amo_scratch + 0 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 1 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 2 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 3 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 4 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 5 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 6 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 7 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 8 * 8)(sp) ; jr ra
> + ld x4, (O_amo_scratch + 9 * 8)(sp) ; jr ra
> + move x4, x11 ; jr ra
> + move x4, x12 ; jr ra
> + move x4, x13 ; jr ra
> + move x4, x14 ; jr ra
> + move x4, x15 ; jr ra
> + move x4, x16 ; jr ra
> + move x4, x17 ; jr ra
> + move x4, x18 ; jr ra
> + move x4, x19 ; jr ra
> + move x4, x20 ; jr ra
> + move x4, x21 ; jr ra
> + move x4, x22 ; jr ra
> + move x4, x23 ; jr ra
> + move x4, x24 ; jr ra
> + move x4, x25 ; jr ra
> + move x4, x26 ; jr ra
> + move x4, x27 ; jr ra
> + move x4, x28 ; jr ra
> + move x4, x29 ; jr ra
> + move x4, x30 ; jr ra
> + move x4, x31 ; jr ra
> +
> +/**
> + * This is a table of 32 functions.
> + * Calling the function write_xr_amo + rd * JUMP_TABLE_OFFSET does:
> + * XR[rd] = x5. For xrs which will be restored from memory at the end of
> + * the AMO handler, do MEM[address where $rd is stored] = x5.
> + */
> +write_xr_amo:
> + jr ra ; jr ra
> + sd x5, (O_amo_scratch + 0 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 1 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 2 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 3 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 4 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 5 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 6 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 7 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 8 * 8)(sp) ; jr ra
> + sd x5, (O_amo_scratch + 9 * 8)(sp) ; jr ra
> + move x11, x5 ; jr ra
> + move x12, x5 ; jr ra
> + move x13, x5 ; jr ra
> + move x14, x5 ; jr ra
> + move x15, x5 ; jr ra
> + move x16, x5 ; jr ra
> + move x17, x5 ; jr ra
> + move x18, x5 ; jr ra
> + move x19, x5 ; jr ra
> + move x20, x5 ; jr ra
> + move x21, x5 ; jr ra
> + move x22, x5 ; jr ra
> + move x23, x5 ; jr ra
> + move x24, x5 ; jr ra
> + move x25, x5 ; jr ra
> + move x26, x5 ; jr ra
> + move x27, x5 ; jr ra
> + move x28, x5 ; jr ra
> + move x29, x5 ; jr ra
> + move x30, x5 ; jr ra
> + move x31, x5 ; jr ra
> +
> +/**
> + * This is a table of 32 functions.
> + * Calling the function write_xr_rdtime + rd * JUMP_TABLE_OFFSET does:
> + * XR[rd] = x3. For xrs which will be restored from memory at the end of
> + * the rdtime handler, do MEM[address where $rd is stored] = x3.
> + */
> +write_xr_rdtime:
> + jr ra ; jr ra
> + sd x3, O_satp_vsatp_scratch0(sp) ; jr ra
> + j _write_xr_rdtime_x1 ; jr ra
> + sd x3, O_satp_vsatp_scratch1(sp) ; jr ra
> + move x4, x3 ; jr ra
> + move x5, x3 ; jr ra
> + move x6, x3 ; jr ra
> + move x7, x3 ; jr ra
> + move x8, x3 ; jr ra
> + move x9, x3 ; jr ra
> + move x10, x3 ; jr ra
> + move x11, x3 ; jr ra
> + move x12, x3 ; jr ra
> + move x13, x3 ; jr ra
> + move x14, x3 ; jr ra
> + move x15, x3 ; jr ra
> + move x16, x3 ; jr ra
> + move x17, x3 ; jr ra
> + move x18, x3 ; jr ra
> + move x19, x3 ; jr ra
> + move x20, x3 ; jr ra
> + move x21, x3 ; jr ra
> + move x22, x3 ; jr ra
> + move x23, x3 ; jr ra
> + move x24, x3 ; jr ra
> + move x25, x3 ; jr ra
> + move x26, x3 ; jr ra
> + move x27, x3 ; jr ra
> + move x28, x3 ; jr ra
> + move x29, x3 ; jr ra
> + move x30, x3 ; jr ra
> + move x31, x3 ; jr ra
> +_write_xr_rdtime_x1:
> + csrw mscratch, x3 ; jr ra
> +
> +fail:
> + unimp
> +
> + .section .sbss
> + .align 6
> + .type amo_lock, @object
> + .size amo_lock, 64
> +amo_lock:
> + .zero 64
> --
> 2.47.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
More information about the opensbi
mailing list