Module Name:    src
Committed By:   skrll
Date:           Mon Jun 12 19:04:14 UTC 2023

Modified Files:
        src/sys/arch/riscv/conf: files.riscv
        src/sys/arch/riscv/fdt: cpu_fdt.c intc_fdt.c riscv_platform.c
        src/sys/arch/riscv/include: cpu.h db_machdep.h intr.h machdep.h pmap.h
        src/sys/arch/riscv/riscv: clock_machdep.c cpu.c cpu_subr.c
            db_interface.c db_machdep.c genassym.cf interrupt.c locore.S
            pmap_machdep.c riscv_machdep.c spl.S
Added Files:
        src/sys/arch/riscv/fdt: riscv_fdtvar.h
        src/sys/arch/riscv/riscv: ipifuncs.c riscv_tlb.c

Log Message:
risc-v: MULTIPROCESSOR support

Add MULTIPROCESSOR support for RISC-V, but leave disabled for the moment
as it's not 100% stable.

Some other improvements to spl and cpu identification / reporting.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/riscv/conf/files.riscv
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/riscv/fdt/cpu_fdt.c \
    src/sys/arch/riscv/fdt/intc_fdt.c src/sys/arch/riscv/fdt/riscv_platform.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/riscv/fdt/riscv_fdtvar.h
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/riscv/include/cpu.h
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/riscv/include/db_machdep.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/riscv/include/intr.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/riscv/include/machdep.h
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/riscv/include/pmap.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/riscv/riscv/clock_machdep.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/riscv/riscv/cpu.c \
    src/sys/arch/riscv/riscv/interrupt.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/riscv/riscv/cpu_subr.c \
    src/sys/arch/riscv/riscv/db_interface.c
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/riscv/riscv/db_machdep.c
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/riscv/riscv/genassym.cf
cvs rdiff -u -r0 -r1.1 src/sys/arch/riscv/riscv/ipifuncs.c \
    src/sys/arch/riscv/riscv/riscv_tlb.c
cvs rdiff -u -r1.41 -r1.42 src/sys/arch/riscv/riscv/locore.S
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/riscv/riscv/pmap_machdep.c
cvs rdiff -u -r1.28 -r1.29 src/sys/arch/riscv/riscv/riscv_machdep.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/riscv/riscv/spl.S

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/riscv/conf/files.riscv
diff -u src/sys/arch/riscv/conf/files.riscv:1.12 src/sys/arch/riscv/conf/files.riscv:1.13
--- src/sys/arch/riscv/conf/files.riscv:1.12	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/conf/files.riscv	Mon Jun 12 19:04:13 2023
@@ -1,4 +1,4 @@
-#	$NetBSD: files.riscv,v 1.12 2023/05/07 12:41:48 skrll Exp $
+#	$NetBSD: files.riscv,v 1.13 2023/06/12 19:04:13 skrll Exp $
 #
 
 maxpartitions	16
@@ -43,6 +43,7 @@ file	arch/riscv/riscv/kobj_machdep.c		mo
 file	arch/riscv/riscv/pmap_machdep.c
 file	arch/riscv/riscv/process_machdep.c
 file	arch/riscv/riscv/procfs_machdep.c	procfs
+file	arch/riscv/riscv/riscv_tlb.c
 file	arch/riscv/riscv/riscv_generic_dma.c
 file	arch/riscv/riscv/riscv_machdep.c
 file	arch/riscv/riscv/sbi.c			# SBI
@@ -63,6 +64,7 @@ file	kern/subr_disk_mbr.c			disk
 file	uvm/pmap/pmap.c
 file	uvm/pmap/pmap_devmap.c
 file	uvm/pmap/pmap_segtab.c
+file	uvm/pmap/pmap_synci.c
 file	uvm/pmap/pmap_tlb.c
 
 device  plic

Index: src/sys/arch/riscv/fdt/cpu_fdt.c
diff -u src/sys/arch/riscv/fdt/cpu_fdt.c:1.1 src/sys/arch/riscv/fdt/cpu_fdt.c:1.2
--- src/sys/arch/riscv/fdt/cpu_fdt.c:1.1	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/fdt/cpu_fdt.c	Mon Jun 12 19:04:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu_fdt.c,v 1.1 2023/05/07 12:41:48 skrll Exp $ */
+/* $NetBSD: cpu_fdt.c,v 1.2 2023/06/12 19:04:13 skrll Exp $ */
 
 /*-
  * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca>
@@ -29,13 +29,167 @@
 #include "opt_multiprocessor.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.1 2023/05/07 12:41:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.2 2023/06/12 19:04:13 skrll Exp $");
 
 #include <sys/param.h>
+#include <sys/cpu.h>
 
 #include <dev/fdt/fdtvar.h>
 
+#include <riscv/cpufunc.h>
 #include <riscv/cpuvar.h>
+#include <riscv/machdep.h>
+#include <riscv/sbi.h>
+
+#include <riscv/fdt/riscv_fdtvar.h>
+
+
+#ifdef MULTIPROCESSOR
+static bool
+riscv_fdt_cpu_okay(const int child)
+{
+	const char *s;
+
+	s = fdtbus_get_string(child, "device_type");
+	if (!s || strcmp(s, "cpu") != 0)
+		return false;
+
+	s = fdtbus_get_string(child, "status");
+	if (s) {
+		if (strcmp(s, "okay") == 0)
+			return true;
+		if (strcmp(s, "disabled") == 0)
+			return false;
+		return false;
+	} else {
+		return true;
+	}
+}
+#endif /* MULTIPROCESSOR */
+
+void
+riscv_fdt_cpu_bootstrap(void)
+{
+#ifdef MULTIPROCESSOR
+
+	const int cpus = OF_finddevice("/cpus");
+	if (cpus == -1) {
+		aprint_error("%s: no /cpus node found\n", __func__);
+		riscv_cpu_max = 1;
+		return;
+	}
+
+	/* Count harts and add hart IDs to to cpu_hartid array */
+	size_t cpuindex = 1;
+	for (int child = OF_child(cpus); child; child = OF_peer(child)) {
+		if (!riscv_fdt_cpu_okay(child))
+			continue;
+
+		riscv_cpu_max++;
+
+		uint64_t reg;
+		if (fdtbus_get_reg64(child, 0, &reg, NULL) != 0)
+			continue;
+
+		const cpuid_t hartid = reg;
+
+		struct sbiret sbiret = sbi_hart_get_status(hartid);
+		switch (sbiret.error) {
+		case SBI_ERR_INVALID_PARAM:
+			aprint_error("Unknown hart id %lx", hartid);
+			continue;
+		case SBI_SUCCESS:
+			break;
+		default:
+			aprint_error("Unexpected error (%ld) from get_status",
+			    sbiret.error);
+		}
+
+		/* Assume the BP is the only one started. */
+		if (sbiret.value == SBI_HART_STARTED) {
+			if (cpu_hartid[0] != -1) {
+				panic("more than 1 hart started");
+			}
+			cpu_hartid[0] = hartid;
+			continue;
+		}
+
+		KASSERT(cpuindex < MAXCPUS);
+		cpu_hartid[cpuindex] = hartid;
+		cpu_dcache_wb_range((vaddr_t)&cpu_hartid[cpuindex],
+		    sizeof(cpu_hartid[cpuindex]));
+
+		cpuindex++;
+	}
+#endif
+}
+int
+riscv_fdt_cpu_mpstart(void)
+{
+	int ret = 0;
+#ifdef MULTIPROCESSOR
+	const int cpus = OF_finddevice("/cpus");
+	if (cpus == -1) {
+		aprint_error("%s: no /cpus node found\n", __func__);
+		return 0;
+	}
+
+	// riscv_fdt_cpu_bootstrap put the boot hart id in cpu_hartid[0]
+	const cpuid_t bp_hartid = cpu_hartid[0];
+
+	/* BootAPs */
+	size_t cpuindex = 1;
+	for (int child = OF_child(cpus); child; child = OF_peer(child)) {
+		if (!riscv_fdt_cpu_okay(child))
+			continue;
+
+		uint64_t reg;
+		if (fdtbus_get_reg64(child, 0, &reg, NULL) != 0)
+			continue;
+
+		cpuid_t hartid = reg;
+
+		if (hartid == bp_hartid)
+			continue;		/* BP already started */
+
+		const paddr_t entry = KERN_VTOPHYS(cpu_mpstart);
+		struct sbiret sbiret = sbi_hart_start(hartid, entry, 0);
+		switch (sbiret.error) {
+		case SBI_SUCCESS:
+			break;
+		case SBI_ERR_INVALID_ADDRESS:
+			break;
+		case SBI_ERR_INVALID_PARAM:
+			break;
+		case SBI_ERR_ALREADY_AVAILABLE:
+			break;
+		case SBI_ERR_FAILED:
+			break;
+		default:
+			aprint_error("%s: failed to enable CPU %#lx\n",
+			    __func__, hartid);
+		}
+
+		size_t i;
+		/* Wait for AP to start */
+		for (i = 0x10000000; i > 0; i--) {
+			if (cpu_hatched_p(cpuindex))
+				break;
+		}
+
+		if (i == 0) {
+			ret++;
+			aprint_error("cpu%zu: WARNING: AP failed to start\n",
+			    cpuindex);
+		}
+
+		cpuindex++;
+	}
+#else
+	aprint_normal("%s: kernel compiled without MULTIPROCESSOR\n", __func__);
+#endif /* MULTIPROCESSOR */
+	return ret;
+}
 
 static int
 cpu_fdt_match(device_t parent, cfdata_t cf, void *aux)
Index: src/sys/arch/riscv/fdt/intc_fdt.c
diff -u src/sys/arch/riscv/fdt/intc_fdt.c:1.1 src/sys/arch/riscv/fdt/intc_fdt.c:1.2
--- src/sys/arch/riscv/fdt/intc_fdt.c:1.1	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/fdt/intc_fdt.c	Mon Jun 12 19:04:13 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: intc_fdt.c,v 1.1 2023/05/07 12:41:48 skrll Exp $	*/
+/*	$NetBSD: intc_fdt.c,v 1.2 2023/06/12 19:04:13 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2023 The NetBSD Foundation, Inc.
@@ -29,8 +29,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_multiprocessor.h"
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intc_fdt.c,v 1.1 2023/05/07 12:41:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intc_fdt.c,v 1.2 2023/06/12 19:04:13 skrll Exp $");
 
 #include <sys/param.h>
 
@@ -237,42 +239,59 @@ static void
 intc_intr_handler(struct trapframe *tf, register_t epc, register_t status,
     register_t cause)
 {
+	const int ppl = splhigh();
 	struct cpu_info * const ci = curcpu();
-	const int source = CAUSE_CODE(cause);
+	unsigned long pending;
+	int ipl;
 
 	KASSERT(CAUSE_INTERRUPT_P(cause));
 
 	struct intc_fdt_softc * const sc = intc_sc;
 
 	ci->ci_intr_depth++;
-	struct intc_irq *irq = sc->sc_irq[source];
-	KASSERTMSG(irq != NULL, "source %d\n", source);
-	if (irq) {
-		struct intc_irqhandler *iih;
-
-		bool mpsafe = (irq->intr_istflags & IST_MPSAFE) != 0;
-		struct clockframe cf = {
-			.cf_epc = epc,
-			.cf_status = status,
-			.cf_intr_depth = ci->ci_intr_depth
-		};
-
-		if (!mpsafe) {
-			KERNEL_LOCK(1, NULL);
-		}
-
-		TAILQ_FOREACH(iih, &irq->intr_handlers, ih_next) {
-			int handled =
-			    iih->ih_fn(iih->ih_arg ? iih->ih_arg : &cf);
-			if (handled)
-				break;
-		}
+	ci->ci_data.cpu_nintr++;
 
-		if (!mpsafe) {
-			KERNEL_UNLOCK_ONE(NULL);
+	while (ppl < (ipl = splintr(&pending))) {
+		if (pending == 0)
+			continue;
+
+		splx(ipl);
+
+		int source = ffs(pending) - 1;
+		struct intc_irq *irq = sc->sc_irq[source];
+		KASSERTMSG(irq != NULL, "source %d\n", source);
+
+		if (irq) {
+			struct intc_irqhandler *iih;
+
+			bool mpsafe =
+			    source != IRQ_SUPERVISOR_EXTERNAL ||
+			    (irq->intr_istflags & IST_MPSAFE) != 0;
+			struct clockframe cf = {
+				.cf_epc = epc,
+				.cf_status = status,
+				.cf_intr_depth = ci->ci_intr_depth
+			};
+
+			if (!mpsafe) {
+				KERNEL_LOCK(1, NULL);
+			}
+
+			TAILQ_FOREACH(iih, &irq->intr_handlers, ih_next) {
+				int handled =
+				    iih->ih_fn(iih->ih_arg ? iih->ih_arg : &cf);
+				if (handled)
+					break;
+			}
+
+			if (!mpsafe) {
+				KERNEL_UNLOCK_ONE(NULL);
+			}
 		}
+		splhigh();
 	}
 	ci->ci_intr_depth--;
+	splx(ppl);
 }
 
 
Index: src/sys/arch/riscv/fdt/riscv_platform.c
diff -u src/sys/arch/riscv/fdt/riscv_platform.c:1.1 src/sys/arch/riscv/fdt/riscv_platform.c:1.2
--- src/sys/arch/riscv/fdt/riscv_platform.c:1.1	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/fdt/riscv_platform.c	Mon Jun 12 19:04:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: riscv_platform.c,v 1.1 2023/05/07 12:41:48 skrll Exp $ */
+/* $NetBSD: riscv_platform.c,v 1.2 2023/06/12 19:04:13 skrll Exp $ */
 
 /*-
  * Copyright (c) 2023 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: riscv_platform.c,v 1.1 2023/05/07 12:41:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: riscv_platform.c,v 1.2 2023/06/12 19:04:13 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -47,6 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: riscv_platfo
 #include <uvm/uvm_extern.h>
 #include <uvm/pmap/pmap_devmap.h>
 
+#include <riscv/fdt/riscv_fdtvar.h>
 
 static const struct pmap_devmap *
 riscv_platform_devmap(void)
@@ -74,12 +75,6 @@ riscv_platform_devmap(void)
 }
 
 
-static void
-riscv_platform_bootstrap(void)
-{
-}
-
-
 static u_int
 riscv_platform_uart_freq(void)
 {
@@ -88,8 +83,9 @@ riscv_platform_uart_freq(void)
 
 static const struct fdt_platform riscv_platform = {
 	.fp_devmap = riscv_platform_devmap,
-	.fp_bootstrap = riscv_platform_bootstrap,
+	.fp_bootstrap = riscv_fdt_cpu_bootstrap,
 	.fp_uart_freq = riscv_platform_uart_freq,
+	.fp_mpstart = riscv_fdt_cpu_mpstart,
 };
 
 FDT_PLATFORM(rv, FDT_PLATFORM_DEFAULT, &riscv_platform);

Index: src/sys/arch/riscv/include/cpu.h
diff -u src/sys/arch/riscv/include/cpu.h:1.11 src/sys/arch/riscv/include/cpu.h:1.12
--- src/sys/arch/riscv/include/cpu.h:1.11	Thu May 25 06:17:18 2023
+++ src/sys/arch/riscv/include/cpu.h	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.11 2023/05/25 06:17:18 skrll Exp $ */
+/* $NetBSD: cpu.h,v 1.12 2023/06/12 19:04:14 skrll Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -63,14 +63,15 @@ struct cpu_info {
 	struct evcnt ci_ev_timer;
 	struct evcnt ci_ev_timer_missed;
 
+	u_long ci_cpu_freq;		/* CPU frequency */
 	int ci_mtx_oldspl;
 	int ci_mtx_count;
-
-	int ci_want_resched;
 	int ci_cpl;
-	u_int ci_softints;
 	volatile u_int ci_intr_depth;
 
+	int ci_want_resched __aligned(COHERENCY_UNIT);
+	u_int ci_softints;
+
 	tlb_asid_t ci_pmap_asid_cur;
 
 	union pmap_segtab *ci_pmap_user_segtab;
@@ -81,6 +82,33 @@ struct cpu_info {
 	struct evcnt ci_ev_fpu_saves;
 	struct evcnt ci_ev_fpu_loads;
 	struct evcnt ci_ev_fpu_reenables;
+
+	struct pmap_tlb_info *ci_tlb_info;
+
+#ifdef MULTIPROCESSOR
+
+	volatile u_long ci_flags;
+	volatile u_long ci_request_ipis;
+					/* bitmask of IPIs requested */
+	u_long ci_active_ipis;	/* bitmask of IPIs being serviced */
+
+	struct evcnt ci_evcnt_all_ipis;	/* aggregated IPI counter */
+	struct evcnt ci_evcnt_per_ipi[NIPIS];	/* individual IPI counters */
+	struct evcnt ci_evcnt_synci_onproc_rqst;
+	struct evcnt ci_evcnt_synci_deferred_rqst;
+	struct evcnt ci_evcnt_synci_ipi_rqst;
+
+#define	CPUF_PRIMARY	__BIT(0)		/* CPU is primary CPU */
+#define	CPUF_PRESENT	__BIT(1)		/* CPU is present */
+#define	CPUF_RUNNING	__BIT(2)		/* CPU is running */
+#define	CPUF_PAUSED	__BIT(3)		/* CPU is paused */
+#define	CPUF_USERPMAP	__BIT(4)		/* CPU has a user pmap activated */
+	kcpuset_t *ci_shootdowncpus;
+	kcpuset_t *ci_multicastcpus;
+	kcpuset_t *ci_watchcpus;
+	kcpuset_t *ci_ddbcpus;
+#endif
+
 #if defined(GPROF) && defined(MULTIPROCESSOR)
 	struct gmonparam *ci_gmon;	/* MI per-cpu GPROF */
 #endif
@@ -90,9 +118,62 @@ struct cpu_info {
 
 #ifdef _KERNEL
 
+extern struct cpu_info *cpu_info[];
 extern struct cpu_info cpu_info_store[];
 
-// This is also in <sys/lwp.h>
+
+#ifdef MULTIPROCESSOR
+extern u_int riscv_cpu_max;
+extern cpuid_t cpu_hartid[];
+
+void cpu_hatch(struct cpu_info *);
+
+void cpu_init_secondary_processor(int);
+void cpu_boot_secondary_processors(void);
+void cpu_mpstart(void);
+bool cpu_hatched_p(u_int);
+
+void cpu_clr_mbox(int);
+void cpu_set_hatched(int);
+
+
+void	cpu_halt(void);
+void	cpu_halt_others(void);
+bool	cpu_is_paused(cpuid_t);
+void	cpu_pause(void);
+void	cpu_pause_others(void);
+void	cpu_resume(cpuid_t);
+void	cpu_resume_others(void);
+void	cpu_debug_dump(void);
+
+extern kcpuset_t *cpus_running;
+extern kcpuset_t *cpus_hatched;
+extern kcpuset_t *cpus_paused;
+extern kcpuset_t *cpus_resumed;
+extern kcpuset_t *cpus_halted;
+
+/*
+ * definitions of cpu-dependent requirements
+ * referenced in generic code
+ */
+
+/*
+ * Send an inter-processor interrupt to each other CPU (excludes curcpu())
+ */
+void cpu_broadcast_ipi(int);
+
+/*
+ * Send an inter-processor interrupt to CPUs in kcpuset (excludes curcpu())
+ */
+void cpu_multicast_ipi(const kcpuset_t *, int);
+
+/*
+ * Send an inter-processor interrupt to another CPU.
+ */
+int cpu_send_ipi(struct cpu_info *, int);
+
+#endif
+
 struct lwp;
 static inline struct cpu_info *lwp_getcpu(struct lwp *);
 
@@ -118,9 +199,14 @@ void	cpu_boot_secondary_processors(void)
 
 #define CPU_INFO_ITERATOR	cpuid_t
 #ifdef MULTIPROCESSOR
-#define CPU_INFO_FOREACH(cii, ci) \
-	(cii) = 0; ((ci) = cpu_infos[cii]) != NULL; (cii)++
+#define	CPU_IS_PRIMARY(ci)	((ci)->ci_flags & CPUF_PRIMARY)
+#define	CPU_INFO_FOREACH(cii, ci)		\
+    cii = 0, ci = &cpu_info_store[0]; 		\
+    ci != NULL; 				\
+    cii++, ncpu ? (ci = cpu_infos[cii]) 	\
+		: (ci = NULL)
 #else
+#define CPU_IS_PRIMARY(ci)	true
 #define CPU_INFO_FOREACH(cii, ci) \
 	(cii) = 0, (ci) = curcpu(); (cii) == 0; (cii)++
 #endif

Index: src/sys/arch/riscv/include/db_machdep.h
diff -u src/sys/arch/riscv/include/db_machdep.h:1.7 src/sys/arch/riscv/include/db_machdep.h:1.8
--- src/sys/arch/riscv/include/db_machdep.h:1.7	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/include/db_machdep.h	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: db_machdep.h,v 1.7 2023/05/07 12:41:48 skrll Exp $ */
+/* $NetBSD: db_machdep.h,v 1.8 2023/06/12 19:04:14 skrll Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -43,7 +43,8 @@ typedef	long		db_expr_t;	/* expression -
 
 typedef struct trapframe db_regs_t;
 
-extern const uint32_t cpu_Debugger_insn[1];
+extern const uint32_t cpu_Debugger_insn[];
+extern const uint32_t cpu_Debugger_ret[];
 extern db_regs_t ddb_regs;
 #define	DDB_REGS	(&ddb_regs)
 
@@ -57,7 +58,7 @@ extern db_regs_t ddb_regs;
 /* Similar to PC_ADVANCE(), except only advance on cpu_Debugger()'s bpt */
 #define	PC_BREAK_ADVANCE(tf) do {				\
 	if ((tf)->tf_pc == (register_t)cpu_Debugger_insn)	\
-		(tf)->tf_pc += BKPT_SIZE;			\
+		(tf)->tf_pc = (register_t)cpu_Debugger_ret;	\
 } while(0)
 
 #define	BKPT_ADDR(addr)		(addr)			/* breakpoint address */

Index: src/sys/arch/riscv/include/intr.h
diff -u src/sys/arch/riscv/include/intr.h:1.3 src/sys/arch/riscv/include/intr.h:1.4
--- src/sys/arch/riscv/include/intr.h:1.3	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/include/intr.h	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.h,v 1.3 2023/05/07 12:41:48 skrll Exp $ */
+/* $NetBSD: intr.h,v 1.4 2023/06/12 19:04:14 skrll Exp $ */
 
 /*-
  * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
@@ -137,7 +137,7 @@ int	splraise(int);
 void	splx(int);
 void	splx_noprof(int);
 void	spl0(void);
-int	splintr(uint32_t *);
+int	splintr(unsigned long *);
 
 void	softint_deliver(void);
 
@@ -148,7 +148,9 @@ struct cpu_info;
 #define DISABLE_INTERRUPTS()	csr_sstatus_clear(SR_SIE)
 
 void	ipi_init(struct cpu_info *);
-void	ipi_process(struct cpu_info *, uint64_t);
+void	ipi_process(struct cpu_info *, unsigned long);
+
+int	riscv_ipi_intr(void *arg);
 
 /*
  * These make no sense *NOT* to be inlined.

Index: src/sys/arch/riscv/include/machdep.h
diff -u src/sys/arch/riscv/include/machdep.h:1.4 src/sys/arch/riscv/include/machdep.h:1.5
--- src/sys/arch/riscv/include/machdep.h:1.4	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/include/machdep.h	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.h,v 1.4 2023/05/07 12:41:48 skrll Exp $	*/
+/*	$NetBSD: machdep.h,v 1.5 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
 #define _RISCV_MACHDEP_H_
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.h,v 1.4 2023/05/07 12:41:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.h,v 1.5 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/proc.h>
 #include <sys/lwp.h>
@@ -68,14 +68,15 @@ paddr_t	init_mmu(paddr_t);
 void	init_riscv(register_t, paddr_t);
 
 void	riscv_timer_frequency_set(uint32_t);	// which header?
+uint32_t
+	riscv_timer_frequency_get(void);	// which header?
 void	riscv_timer_register(void (*timerfn)(void));
 void	riscv_intr_set_handler(void (*intr_handler)(struct trapframe *,
 	    register_t, register_t, register_t));
 
+void	riscv_timer_init(void);
 int	riscv_timer_intr(void *arg);
 
-void	cpus_fdt_md_attach(device_t, device_t, void *);
-
 void    pt_dump(void (*)(const char *, ...));
 
 

Index: src/sys/arch/riscv/include/pmap.h
diff -u src/sys/arch/riscv/include/pmap.h:1.17 src/sys/arch/riscv/include/pmap.h:1.18
--- src/sys/arch/riscv/include/pmap.h:1.17	Mon May  8 08:07:36 2023
+++ src/sys/arch/riscv/include/pmap.h	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.17 2023/05/08 08:07:36 skrll Exp $ */
+/* $NetBSD: pmap.h,v 1.18 2023/06/12 19:04:14 skrll Exp $ */
 
 /*
  * Copyright (c) 2014, 2019, 2021 The NetBSD Foundation, Inc.
@@ -80,7 +80,7 @@
 #define	KERNEL_PID	0
 
 #define	PMAP_HWPAGEWALKER		1
-#define	PMAP_TLB_MAX			1
+#define	PMAP_TLB_MAX			MAXCPUS
 #ifdef _LP64
 #define	PMAP_INVALID_PDETAB_ADDRESS	((pmap_pdetab_t *)(VM_MIN_KERNEL_ADDRESS - PAGE_SIZE))
 #define	PMAP_INVALID_SEGTAB_ADDRESS	((pmap_segtab_t *)(VM_MIN_KERNEL_ADDRESS - PAGE_SIZE))
@@ -90,6 +90,8 @@
 #endif
 #define	PMAP_TLB_NUM_PIDS		(__SHIFTOUT_MASK(SATP_ASID) + 1)
 #define	PMAP_TLB_BITMAP_LENGTH          PMAP_TLB_NUM_PIDS
+// Should use SBI TLB ops
+#define	PMAP_TLB_NEED_SHOOTDOWN		1
 #define	PMAP_TLB_FLUSH_ASID_ON_RESET	false
 
 #define	pmap_phys_address(x)		(x)
@@ -113,6 +115,7 @@ pmap_procwr(struct proc *p, vaddr_t va, 
 #include <uvm/pmap/tlb.h>
 #include <uvm/pmap/pmap_devmap.h>
 #include <uvm/pmap/pmap_tlb.h>
+#include <uvm/pmap/pmap_synci.h>
 
 #define	PMAP_GROWKERNEL
 #define	PMAP_STEAL_MEMORY
@@ -124,21 +127,32 @@ struct pmap_md {
 	paddr_t md_ppn;
 };
 
+static inline void
+pmap_md_icache_sync_all(void)
+{
+}
+
+static inline void
+pmap_md_icache_sync_range_index(vaddr_t va, vsize_t size)
+{
+}
+
 struct vm_page *
-	pmap_md_alloc_poolpage(int flags);
+	pmap_md_alloc_poolpage(int);
 vaddr_t	pmap_md_map_poolpage(paddr_t, vsize_t);
 void	pmap_md_unmap_poolpage(vaddr_t, vsize_t);
+
 bool	pmap_md_direct_mapped_vaddr_p(vaddr_t);
-bool	pmap_md_io_vaddr_p(vaddr_t);
 paddr_t	pmap_md_direct_mapped_vaddr_to_paddr(vaddr_t);
 vaddr_t	pmap_md_direct_map_paddr(paddr_t);
 void	pmap_md_init(void);
-
-void	pmap_md_xtab_activate(struct pmap *, struct lwp *);
-void	pmap_md_xtab_deactivate(struct pmap *);
+bool	pmap_md_io_vaddr_p(vaddr_t);
+bool	pmap_md_ok_to_steal_p(const uvm_physseg_t, size_t);
 void	pmap_md_pdetab_init(struct pmap *);
 void	pmap_md_pdetab_fini(struct pmap *);
-bool	pmap_md_ok_to_steal_p(const uvm_physseg_t, size_t);
+void	pmap_md_tlb_info_attach(struct pmap_tlb_info *, struct cpu_info *);
+void	pmap_md_xtab_activate(struct pmap *, struct lwp *);
+void	pmap_md_xtab_deactivate(struct pmap *);
 
 void	pmap_bootstrap(vaddr_t, vaddr_t);
 

Index: src/sys/arch/riscv/riscv/clock_machdep.c
diff -u src/sys/arch/riscv/riscv/clock_machdep.c:1.4 src/sys/arch/riscv/riscv/clock_machdep.c:1.5
--- src/sys/arch/riscv/riscv/clock_machdep.c:1.4	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/riscv/clock_machdep.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: clock_machdep.c,v 1.4 2023/05/07 12:41:48 skrll Exp $	*/
+/*	$NetBSD: clock_machdep.c,v 1.5 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__RCSID("$NetBSD: clock_machdep.c,v 1.4 2023/05/07 12:41:48 skrll Exp $");
+__RCSID("$NetBSD: clock_machdep.c,v 1.5 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -42,8 +42,6 @@ __RCSID("$NetBSD: clock_machdep.c,v 1.4 
 #include <machine/sbi.h>
 #include <machine/sysreg.h>
 
-static void riscv_timer_init(void);
-
 static void (*_riscv_timer_init)(void) = riscv_timer_init;
 
 static uint32_t timer_frequency;
@@ -70,6 +68,11 @@ riscv_timer_frequency_set(uint32_t freq)
 	timer_ticks_per_hz = freq / hz;
 }
 
+uint32_t
+riscv_timer_frequency_get(void)
+{
+	return timer_frequency;
+}
 
 void
 riscv_timer_register(void (*timerfn)(void))
@@ -82,22 +85,22 @@ riscv_timer_register(void (*timerfn)(voi
 	_riscv_timer_init = timerfn;
 }
 
-static void
+void
 riscv_timer_init(void)
 {
 	struct cpu_info * const ci = curcpu();
 
-	uint64_t next;
-
 	ci->ci_lastintr = csr_time_read();
-	next = ci->ci_lastintr + timer_ticks_per_hz;
+	uint64_t next = ci->ci_lastintr + timer_ticks_per_hz;
 	ci->ci_lastintr_scheduled = next;
 
 	sbi_set_timer(next);		/* schedule next timer interrupt */
 	csr_sie_set(SIE_STIE);		/* enable supervisor timer intr */
 
-	tc.tc_frequency = timer_frequency;
-	tc_init(&tc);
+	if (cpu_index(ci) == 0) {
+		tc.tc_frequency = timer_frequency;
+		tc_init(&tc);
+	}
 }
 
 

Index: src/sys/arch/riscv/riscv/cpu.c
diff -u src/sys/arch/riscv/riscv/cpu.c:1.1 src/sys/arch/riscv/riscv/cpu.c:1.2
--- src/sys/arch/riscv/riscv/cpu.c:1.1	Sun May  7 12:41:48 2023
+++ src/sys/arch/riscv/riscv/cpu.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.c,v 1.1 2023/05/07 12:41:48 skrll Exp $	*/
+/*	$NetBSD: cpu.c,v 1.2 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2023 The NetBSD Foundation, Inc.
@@ -29,17 +29,23 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_multiprocessor.h"
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.1 2023/05/07 12:41:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.2 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
 
 #include <sys/cpu.h>
 #include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/reboot.h>
 #include <sys/sysctl.h>
 
 #include <riscv/cpu.h>
 #include <riscv/cpuvar.h>
+#include <riscv/machdep.h>
+#include <riscv/sbi.h>
 
 #ifdef MULTIPROCESSOR
 #define NCPUINFO	MAXCPUS
@@ -59,6 +65,35 @@ void (*cpu_sdcache_wb_range)(vaddr_t, pa
 u_int   riscv_dcache_align = CACHE_LINE_SIZE;
 u_int   riscv_dcache_align_mask = CACHE_LINE_SIZE - 1;
 
+#define CPU_VENDOR_SIFIVE	0x489
+
+#define CPU_ARCH_7SERIES	0x8000000000000007
+
+struct cpu_arch {
+	uint64_t	 ca_id;
+	const char	*ca_name;
+};
+
+struct cpu_arch cpu_arch_sifive[] = {
+    {
+	.ca_id = CPU_ARCH_7SERIES,
+	.ca_name = "7-Series Processor (E7, S7, U7 series)",
+    },
+    { },	// terminator
+};
+
+struct cpu_vendor {
+	uint32_t	 	 cv_id;
+	const char		*cv_name;
+	struct cpu_arch		*cv_arch;
+} cpu_vendors[] = {
+    {
+	.cv_id = CPU_VENDOR_SIFIVE,
+	.cv_name = "SiFive",
+	.cv_arch = cpu_arch_sifive,
+    },
+};
+
 /*
  * Our exported cpu_info structs; these will be first used by the
  * secondary cpus as part of cpu_mpstart and the hatching process.
@@ -66,7 +101,12 @@ u_int   riscv_dcache_align_mask = CACHE_
 struct cpu_info cpu_info_store[NCPUINFO] = {
 	[0] = {
 		.ci_cpl = IPL_HIGH,
-		.ci_curlwp = &lwp0
+		.ci_curlwp = &lwp0,
+		.ci_cpl = IPL_HIGH,
+#ifdef MULTIPROCESSOR
+		.ci_tlb_info = &pmap_tlb0_info,
+		.ci_flags = CPUF_PRIMARY | CPUF_PRESENT | CPUF_RUNNING,
+#endif
 	}
 };
 
@@ -91,11 +131,57 @@ cpu_setup_sysctl(device_t dv, struct cpu
 }
 
 
+static void
+cpu_identify(device_t self, struct cpu_info *ci)
+{
+	const register_t mvendorid = sbi_get_mvendorid().value;
+	const register_t marchid = sbi_get_marchid().value;
+	const uint32_t mimpid = sbi_get_mimpid().value;
+	struct cpu_arch *cv_arch = NULL;
+	const char *cv_name = NULL;
+	const char *ca_name = NULL;
+	char vendor[128];
+	char arch[128];
+
+	for (size_t i = 0; i < __arraycount(cpu_vendors); i++) {
+		if (mvendorid == cpu_vendors[i].cv_id) {
+			cv_name = cpu_vendors[i].cv_name;
+			cv_arch = cpu_vendors[i].cv_arch;
+			break;
+		}
+	}
+
+	if (cv_arch != NULL) {
+		for (size_t i = 0; cv_arch[i].ca_name != NULL; i++) {
+			if (marchid == cv_arch[i].ca_id) {
+				ca_name = cv_arch[i].ca_name;
+				break;
+			}
+		}
+	}
+
+	if (cv_name == NULL) {
+		snprintf(vendor, sizeof(vendor), "vendor %" PRIxREGISTER, mvendorid);
+		cv_name = vendor;
+	}
+	if (ca_name == NULL) {
+		snprintf(arch, sizeof(arch), "arch %" PRIxREGISTER, marchid);
+		ca_name = arch;
+	}
+
+	aprint_naive("\n");
+	aprint_normal(": %s %s imp. %" PRIx32 "\n", cv_name, ca_name, mimpid);
+        aprint_verbose_dev(ci->ci_dev,
+	    "vendor 0x%" PRIxREGISTER " arch. %" PRIxREGISTER " imp. %" PRIx32 "\n",
+	    mvendorid, marchid, mimpid);
+}
+
+
 void
 cpu_attach(device_t dv, cpuid_t id)
 {
-	struct cpu_info *ci = NULL;
 	const int unit = device_unit(dv);
+	struct cpu_info *ci;
 
 	if (unit == 0) {
 		ci = curcpu();
@@ -115,7 +201,6 @@ cpu_attach(device_t dv, cpuid_t id)
 		ci->ci_cpuid = id;
 		/* ci_cpuid is stored by own cpus when hatching */
 
-		cpu_info[ncpu] = ci;
 		if (cpu_hatched_p(unit) == 0) {
 			ci->ci_dev = dv;
 			device_set_private(dv, ci);
@@ -134,16 +219,26 @@ cpu_attach(device_t dv, cpuid_t id)
 
 	ci->ci_dev = dv;
 	device_set_private(dv, ci);
-	aprint_naive("\n");
-	aprint_normal("\n");
-	cpu_setup_sysctl(dv, ci);
+
+	cpu_identify(dv, ci);
 
 #ifdef MULTIPROCESSOR
+	kcpuset_create(&ci->ci_shootdowncpus, true);
+
+	ipi_init(ci);
+
+	kcpuset_create(&ci->ci_multicastcpus, true);
+	kcpuset_create(&ci->ci_watchcpus, true);
+	kcpuset_create(&ci->ci_ddbcpus, true);
+
 	if (unit != 0) {
 		mi_cpu_attach(ci);
-		pmap_tlb_info_attach(&pmap_tlb0_info, ci);
+		struct pmap_tlb_info *ti = kmem_zalloc(sizeof(*ti), KM_SLEEP);
+		pmap_tlb_info_init(ti);
+		pmap_tlb_info_attach(ti, ci);
 	}
 #endif /* MULTIPROCESSOR */
+	cpu_setup_sysctl(dv, ci);
 
 	if (unit != 0) {
 	    return;
@@ -160,10 +255,11 @@ cpu_attach(device_t dv, cpuid_t id)
 void __noasan
 cpu_init_secondary_processor(int cpuindex)
 {
-#if 0
-    struct cpu_info * ci = &cpu_info_store[cpuindex];
-#endif
+	cpu_set_hatched(cpuindex);
 
+	/*
+	 * return to assembly to wait for cpu_boot_secondary_processors
+	 */
 }
 
 
@@ -175,5 +271,18 @@ void
 cpu_hatch(struct cpu_info *ci)
 {
 	KASSERT(curcpu() == ci);
+
+	ci->ci_cpu_freq = riscv_timer_frequency_get();
+
+	riscv_timer_init();
+
+	/*
+	 * clear my bit of the mailbox to tell cpu_boot_secondary_processors().
+	 * Consider that if there are cpu0, 1, 2, 3, and cpu2 is unresponsive,
+	 * ci_index for each would be cpu0=0, cpu1=1, cpu2=undef, cpu3=2.
+	 * therefore we have to use device_unit instead of ci_index for mbox.
+	 */
+
+	cpu_clr_mbox(device_unit(ci->ci_dev));
 }
 #endif /* MULTIPROCESSOR */
Index: src/sys/arch/riscv/riscv/interrupt.c
diff -u src/sys/arch/riscv/riscv/interrupt.c:1.1 src/sys/arch/riscv/riscv/interrupt.c:1.2
--- src/sys/arch/riscv/riscv/interrupt.c:1.1	Sun May  7 12:41:49 2023
+++ src/sys/arch/riscv/riscv/interrupt.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: interrupt.c,v 1.1 2023/05/07 12:41:49 skrll Exp $	*/
+/*	$NetBSD: interrupt.c,v 1.2 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -29,9 +29,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_multiprocessor.h"
+
 #include <sys/cdefs.h>
 
-__RCSID("$NetBSD: interrupt.c,v 1.1 2023/05/07 12:41:49 skrll Exp $");
+__RCSID("$NetBSD: interrupt.c,v 1.2 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -42,6 +44,7 @@ __RCSID("$NetBSD: interrupt.c,v 1.1 2023
 
 #include <machine/locore.h>
 #include <machine/machdep.h>
+#include <machine/sbi.h>
 
 #include <riscv/dev/plicvar.h>
 
@@ -133,3 +136,59 @@ intr_disestablish(void *ih)
 	KASSERT(!cpu_intr_p());
 	KASSERT(!cpu_softintr_p());
 }
+
+
+#ifdef MULTIPROCESSOR
+__CTASSERT(NIPIS < 16);
+
+int
+riscv_ipi_intr(void *arg)
+{
+	struct cpu_info * const ci = curcpu();
+	membar_acquire();
+
+	csr_sip_clear(SIP_SSIP);	/* clean pending interrupt status */
+
+	unsigned long pending;
+	while ((pending = atomic_swap_ulong(&ci->ci_request_ipis, 0)) != 0) {
+		membar_acquire();
+		atomic_or_ulong(&ci->ci_active_ipis, pending);
+
+		ipi_process(ci, pending);
+
+		atomic_and_ulong(&ci->ci_active_ipis, pending);
+	}
+
+	return 1;
+}
+
+int
+cpu_send_ipi(struct cpu_info *ci, int req)
+{
+	KASSERT(req < NIPIS);
+	if (ci == NULL) {
+		CPU_INFO_ITERATOR cii;
+		for (CPU_INFO_FOREACH(cii, ci)) {
+			if (ci != curcpu()) {
+				cpu_send_ipi(ci, req);
+			}
+		}
+		return 0;
+	}
+	const uint32_t ipi_mask = __BIT(req);
+
+	membar_release();
+	atomic_or_ulong(&ci->ci_request_ipis, ipi_mask);
+
+	membar_release();
+	unsigned long hartmask = 0;
+	const cpuid_t hartid = ci->ci_cpuid;
+	KASSERT(hartid < sizeof(unsigned long) * NBBY);
+	hartmask |= __BIT(hartid);
+	struct sbiret sbiret = sbi_send_ipi(hartmask, 0);
+
+	KASSERT(sbiret.error == SBI_SUCCESS);
+
+	return 0;
+}
+#endif	/* MULTIPROCESSOR */

Index: src/sys/arch/riscv/riscv/cpu_subr.c
diff -u src/sys/arch/riscv/riscv/cpu_subr.c:1.2 src/sys/arch/riscv/riscv/cpu_subr.c:1.3
--- src/sys/arch/riscv/riscv/cpu_subr.c:1.2	Wed Nov  4 07:09:46 2020
+++ src/sys/arch/riscv/riscv/cpu_subr.c	Mon Jun 12 19:04:14 2023
@@ -1,11 +1,11 @@
-/*	$NetBSD: cpu_subr.c,v 1.2 2020/11/04 07:09:46 skrll Exp $	*/
+/*	$NetBSD: cpu_subr.c,v 1.3 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
- * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Matt Thomas of 3am Software Foundry.
+ * by Nick Hudson
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,8 +29,402 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
+#include "opt_ddb.h"
+#include "opt_multiprocessor.h"
+#include "opt_riscv_debug.h"
 
-__RCSID("$NetBSD: cpu_subr.c,v 1.2 2020/11/04 07:09:46 skrll Exp $");
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.3 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
+#include <sys/atomic.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/reboot.h>
+#include <sys/xcall.h>
+
+#include <machine/db_machdep.h>
+#include <machine/sbi.h>
+
+#ifdef DDB
+#include <ddb/db_output.h>
+#endif
+
+#ifdef VERBOSE_INIT_RISCV
+#define VPRINTF(...)	printf(__VA_ARGS__)
+#else
+#define VPRINTF(...)	__nothing
+#endif
+
+#ifdef MULTIPROCESSOR
+#define NCPUINFO	MAXCPUS
+#else
+#define NCPUINFO	1
+#endif /* MULTIPROCESSOR */
+
+unsigned long cpu_hartid[NCPUINFO] = {
+	[0 ... NCPUINFO - 1] = ~0,
+};
+
+#ifdef MULTIPROCESSOR
+
+kcpuset_t *cpus_halted;
+kcpuset_t *cpus_hatched;
+kcpuset_t *cpus_paused;
+kcpuset_t *cpus_resumed;
+kcpuset_t *cpus_running;
+
+#define	CPUINDEX_DIVISOR	(sizeof(u_long) * NBBY)
+
+#define N howmany(MAXCPUS, CPUINDEX_DIVISOR)
+
+/* cpu_hatch_ipi needs fixing for > 1 */
+CTASSERT(N == 1);
+volatile u_long riscv_cpu_hatched[N] __cacheline_aligned = { };
+volatile u_long riscv_cpu_mbox[N] __cacheline_aligned = { };
+u_int riscv_cpu_max = 1;
+
+/* IPI all APs to GO! */
+static void
+cpu_ipi_aps(void)
+{
+	unsigned long hartmask = 0;
+	// BP is index 0
+	for (size_t i = 1; i < ncpu; i++) {
+		const cpuid_t hartid = cpu_hartid[i];
+		KASSERT(hartid < sizeof(unsigned long) * NBBY);
+		hartmask |= __BIT(hartid);
+	}
+	struct sbiret sbiret = sbi_send_ipi(hartmask, 0);
+
+	KASSERT(sbiret.error == SBI_SUCCESS);
+}
+
+void
+cpu_boot_secondary_processors(void)
+{
+	u_int cpuno;
+
+	if ((boothowto & RB_MD1) != 0)
+		return;
+
+	VPRINTF("%s: starting secondary processors\n", __func__);
+
+	/*
+	 * send mbox to have secondary processors do cpu_hatch()
+	 * store-release matches locore.S
+	 */
+	asm volatile("fence rw,w");
+	for (size_t n = 0; n < __arraycount(riscv_cpu_mbox); n++)
+		atomic_or_ulong(&riscv_cpu_mbox[n], riscv_cpu_hatched[n]);
+	cpu_ipi_aps();
+
+	/* wait for all cpus to have done cpu_hatch() */
+	for (cpuno = 1; cpuno < ncpu; cpuno++) {
+		if (!cpu_hatched_p(cpuno))
+			continue;
+
+		const size_t off = cpuno / CPUINDEX_DIVISOR;
+		const u_long bit = __BIT(cpuno % CPUINDEX_DIVISOR);
+
+		/* load-acquire matches cpu_clr_mbox */
+		while (atomic_load_acquire(&riscv_cpu_mbox[off]) & bit) {
+			/* spin - it shouldn't be long */
+			;
+		}
+	}
+
+	VPRINTF("%s: secondary processors hatched\n", __func__);
+}
+
+bool
+cpu_hatched_p(u_int cpuindex)
+{
+	const u_int off = cpuindex / CPUINDEX_DIVISOR;
+	const u_int bit = cpuindex % CPUINDEX_DIVISOR;
+
+	/* load-acquire matches cpu_set_hatched */
+	return (atomic_load_acquire(&riscv_cpu_hatched[off]) & __BIT(bit)) != 0;
+}
+
+
+void
+cpu_set_hatched(int cpuindex)
+{
+
+	const size_t off = cpuindex / CPUINDEX_DIVISOR;
+	const u_long bit = __BIT(cpuindex % CPUINDEX_DIVISOR);
+
+	/* store-release matches cpu_hatched_p */
+	asm volatile("fence rw, w" ::: "memory");
+	atomic_or_ulong(&riscv_cpu_hatched[off], bit);
+
+	asm volatile("fence w, rw" ::: "memory");
+}
+
+void
+cpu_clr_mbox(int cpuindex)
+{
+
+	const size_t off = cpuindex / CPUINDEX_DIVISOR;
+	const u_long bit = __BIT(cpuindex % CPUINDEX_DIVISOR);
+
+	/* store-release matches locore.S */
+	asm volatile("fence rw,w" ::: "memory");
+	atomic_and_ulong(&riscv_cpu_mbox[off], ~bit);
+
+	asm volatile("fence w, rw"  ::: "memory");
+}
+
+
+void
+cpu_broadcast_ipi(int tag)
+{
+
+	/*
+	 * No reason to remove ourselves since multicast_ipi will do that
+	 * for us.
+	 */
+	cpu_multicast_ipi(cpus_running, tag);
+}
+
+void
+cpu_multicast_ipi(const kcpuset_t *kcp, int tag)
+{
+	struct cpu_info * const ci = curcpu();
+	kcpuset_t *kcp2 = ci->ci_multicastcpus;
+
+	if (kcpuset_match(cpus_running, ci->ci_data.cpu_kcpuset))
+		return;
+
+	kcpuset_copy(kcp2, kcp);
+	kcpuset_remove(kcp2, ci->ci_data.cpu_kcpuset);
+	for (unsigned int cii; (cii = kcpuset_ffs(kcp2)) != 0; ) {
+		kcpuset_clear(kcp2, --cii);
+		(void)cpu_send_ipi(cpu_lookup(cii), tag);
+	}
+}
+
+static void
+cpu_ipi_wait(const char *s, const kcpuset_t *watchset, const kcpuset_t *wanted)
+{
+	bool done = false;
+	struct cpu_info * const ci = curcpu();
+	kcpuset_t *kcp = ci->ci_watchcpus;
+
+	/* some finite amount of time */
+
+	for (u_long limit = curcpu()->ci_cpu_freq / 10; !done && limit--; ) {
+		kcpuset_copy(kcp, watchset);
+		kcpuset_intersect(kcp, wanted);
+		done = kcpuset_match(kcp, wanted);
+	}
+
+	if (!done) {
+		cpuid_t cii;
+		kcpuset_copy(kcp, wanted);
+		kcpuset_remove(kcp, watchset);
+		if ((cii = kcpuset_ffs(kcp)) != 0) {
+			printf("Failed to %s:", s);
+			do {
+				kcpuset_clear(kcp, --cii);
+				printf(" cpu%lu", cii);
+			} while ((cii = kcpuset_ffs(kcp)) != 0);
+			printf("\n");
+		}
+	}
+}
+
+/*
+ * Halt this cpu
+ */
+void
+cpu_halt(void)
+{
+	cpuid_t cii = cpu_index(curcpu());
+
+	printf("cpu%lu: shutting down\n", cii);
+	kcpuset_atomic_set(cpus_halted, cii);
+	spl0();		/* allow interrupts e.g. further ipi ? */
+	for (;;) ;	/* spin */
+
+	/* NOTREACHED */
+}
+
+/*
+ * Halt all running cpus, excluding current cpu.
+ */
+void
+cpu_halt_others(void)
+{
+	kcpuset_t *kcp;
+
+	// If we are the only CPU running, there's nothing to do.
+	if (kcpuset_match(cpus_running, curcpu()->ci_data.cpu_kcpuset))
+		return;
+
+	// Get all running CPUs
+	kcpuset_clone(&kcp, cpus_running);
+	// Remove ourself
+	kcpuset_remove(kcp, curcpu()->ci_data.cpu_kcpuset);
+	// Remove any halted CPUs
+	kcpuset_remove(kcp, cpus_halted);
+	// If there are CPUs left, send the IPIs
+	if (!kcpuset_iszero(kcp)) {
+		cpu_multicast_ipi(kcp, IPI_HALT);
+		cpu_ipi_wait("halt", cpus_halted, kcp);
+	}
+	kcpuset_destroy(kcp);
+
+	/*
+	 * TBD
+	 * Depending on available firmware methods, other cpus will
+	 * either shut down themselves, or spin and wait for us to
+	 * stop them.
+	 */
+}
+
+/*
+ * Pause this cpu
+ */
+void
+cpu_pause(void	)
+{
+	const int s = splhigh();
+	cpuid_t cii = cpu_index(curcpu());
+
+	if (__predict_false(cold)) {
+		splx(s);
+		return;
+	}
+
+	do {
+		kcpuset_atomic_set(cpus_paused, cii);
+		do {
+			;
+		} while (kcpuset_isset(cpus_paused, cii));
+		kcpuset_atomic_set(cpus_resumed, cii);
+#if defined(DDB)
+		if (ddb_running_on_this_cpu_p())
+			cpu_Debugger();
+		if (ddb_running_on_any_cpu_p())
+			continue;
+#endif
+	} while (false);
+
+	splx(s);
+}
+
+/*
+ * Pause all running cpus, excluding current cpu.
+ */
+void
+cpu_pause_others(void)
+{
+	struct cpu_info * const ci = curcpu();
+
+	if (cold || kcpuset_match(cpus_running, ci->ci_data.cpu_kcpuset))
+		return;
+
+	kcpuset_t *kcp = ci->ci_ddbcpus;
+
+	kcpuset_copy(kcp, cpus_running);
+	kcpuset_remove(kcp, ci->ci_data.cpu_kcpuset);
+	kcpuset_remove(kcp, cpus_paused);
+
+	cpu_broadcast_ipi(IPI_SUSPEND);
+	cpu_ipi_wait("pause", cpus_paused, kcp);
+}
+
+/*
+ * Resume a single cpu
+ */
+void
+cpu_resume(cpuid_t cii)
+{
+
+	if (__predict_false(cold))
+		return;
+
+	struct cpu_info * const ci = curcpu();
+	kcpuset_t *kcp = ci->ci_ddbcpus;
+
+	kcpuset_set(kcp, cii);
+	kcpuset_atomicly_remove(cpus_resumed, cpus_resumed);
+	kcpuset_atomic_clear(cpus_paused, cii);
+
+	cpu_ipi_wait("resume", cpus_resumed, kcp);
+}
+
+/*
+ * Resume all paused cpus.
+ */
+void
+cpu_resume_others(void)
+{
+
+	if (__predict_false(cold))
+		return;
+
+	struct cpu_info * const ci = curcpu();
+	kcpuset_t *kcp = ci->ci_ddbcpus;
+
+	kcpuset_atomicly_remove(cpus_resumed, cpus_resumed);
+	kcpuset_copy(kcp, cpus_paused);
+	kcpuset_atomicly_remove(cpus_paused, cpus_paused);
+
+	/* CPUs awake on cpus_paused clear */
+	cpu_ipi_wait("resume", cpus_resumed, kcp);
+}
+
+bool
+cpu_is_paused(cpuid_t cii)
+{
+
+	return !cold && kcpuset_isset(cpus_paused, cii);
+}
+
+#ifdef DDB
+void
+cpu_debug_dump(void)
+{
+	CPU_INFO_ITERATOR cii;
+	struct cpu_info *ci;
+	char running, hatched, paused, resumed, halted;
+	db_printf("CPU CPUID STATE CPUINFO            CPL INT MTX IPIS(A/R)\n");
+	for (CPU_INFO_FOREACH(cii, ci)) {
+		hatched = (kcpuset_isset(cpus_hatched, cpu_index(ci)) ? 'H' : '-');
+		running = (kcpuset_isset(cpus_running, cpu_index(ci)) ? 'R' : '-');
+		paused  = (kcpuset_isset(cpus_paused,  cpu_index(ci)) ? 'P' : '-');
+		resumed = (kcpuset_isset(cpus_resumed, cpu_index(ci)) ? 'r' : '-');
+		halted  = (kcpuset_isset(cpus_halted,  cpu_index(ci)) ? 'h' : '-');
+		db_printf("%3d 0x%03lx %c%c%c%c%c %p "
+			"%3d %3d %3d "
+			"0x%02lx/0x%02lx\n",
+			cpu_index(ci), ci->ci_cpuid,
+			running, hatched, paused, resumed, halted,
+			ci, ci->ci_cpl, ci->ci_intr_depth, ci->ci_mtx_count,
+			ci->ci_active_ipis, ci->ci_request_ipis);
+	}
+}
+#endif
+
+void
+xc_send_ipi(struct cpu_info *ci)
+{
+	KASSERT(kpreempt_disabled());
+	KASSERT(curcpu() != ci);
+
+	cpu_send_ipi(ci, IPI_XCALL);
+}
+
+void
+cpu_ipi(struct cpu_info *ci)
+{
+	KASSERT(kpreempt_disabled());
+	KASSERT(curcpu() != ci);
+
+	cpu_send_ipi(ci, IPI_GENERIC);
+}
+
+#endif
Index: src/sys/arch/riscv/riscv/db_interface.c
diff -u src/sys/arch/riscv/riscv/db_interface.c:1.2 src/sys/arch/riscv/riscv/db_interface.c:1.3
--- src/sys/arch/riscv/riscv/db_interface.c:1.2	Wed Oct 26 23:38:08 2022
+++ src/sys/arch/riscv/riscv/db_interface.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_interface.c,v 1.2 2022/10/26 23:38:08 riastradh Exp $	*/
+/*	$NetBSD: db_interface.c,v 1.3 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*
  * Mach Operating System
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.2 2022/10/26 23:38:08 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.3 2023/06/12 19:04:14 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_multiprocessor.h"
@@ -118,20 +118,23 @@ kdb_trap(int type, db_regs_t *regs)
 	} else {
 		if (old_ddb_cpu != cpu_me) {
 			KASSERT(cpu_is_paused(cpu_me));
-			cpu_pause(regs);
+			cpu_pause();
 			splx(s);
 			return 1;
 		}
 	}
-	KASSERT(! cpu_is_paused(cpu_me));
+	KASSERT(!cpu_is_paused(cpu_me));
 #endif
+	struct cpu_info * const ci = curcpu();
 
 	ddb_regs = *regs;
+	ci->ci_ddb_regs = &ddb_regs;
 	db_active++;
 	cnpollc(1);
 	db_trap(type, 0 /*code*/);
 	cnpollc(0);
 	db_active--;
+	ci->ci_ddb_regs = NULL;
 	*regs = ddb_regs;
 
 #if defined(MULTIPROCESSOR)
@@ -140,7 +143,7 @@ kdb_trap(int type, db_regs_t *regs)
 	} else {
 		cpu_resume(ddb_cpu);
 		if (first_in_ddb)
-			cpu_pause(regs);
+			cpu_pause();
 	}
 #endif
 

Index: src/sys/arch/riscv/riscv/db_machdep.c
diff -u src/sys/arch/riscv/riscv/db_machdep.c:1.10 src/sys/arch/riscv/riscv/db_machdep.c:1.11
--- src/sys/arch/riscv/riscv/db_machdep.c:1.10	Wed Oct 12 07:53:56 2022
+++ src/sys/arch/riscv/riscv/db_machdep.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_machdep.c,v 1.10 2022/10/12 07:53:56 simonb Exp $	*/
+/*	$NetBSD: db_machdep.c,v 1.11 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__RCSID("$NetBSD: db_machdep.c,v 1.10 2022/10/12 07:53:56 simonb Exp $");
+__RCSID("$NetBSD: db_machdep.c,v 1.11 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
 
@@ -89,7 +89,6 @@ int
 db_rw_ddbreg(const struct db_variable *vp, db_expr_t *valp, int rw)
 {
 	struct trapframe * const tf = curcpu()->ci_ddb_regs;
-	KASSERT(db_regs <= vp && vp < db_regs + __arraycount(db_regs));
 	const uintptr_t addr = (uintptr_t)tf + (uintptr_t)vp->valuep;
 	if (vp->modif != NULL && vp->modif[0] == 'i') {
 		if (rw == DB_VAR_GET) {

Index: src/sys/arch/riscv/riscv/genassym.cf
diff -u src/sys/arch/riscv/riscv/genassym.cf:1.14 src/sys/arch/riscv/riscv/genassym.cf:1.15
--- src/sys/arch/riscv/riscv/genassym.cf:1.14	Sun May  7 12:41:49 2023
+++ src/sys/arch/riscv/riscv/genassym.cf	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-#	$NetBSD: genassym.cf,v 1.14 2023/05/07 12:41:49 skrll Exp $
+#	$NetBSD: genassym.cf,v 1.15 2023/06/12 19:04:14 skrll Exp $
 
 #-
 # Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -65,6 +65,10 @@ define	SIE_SEIE	SIE_SEIE
 define	SIE_STIE	SIE_STIE
 define	SIE_SSIE	SIE_SSIE
 
+define	SIP_SEIP	SIP_SEIP
+define	SIP_STIP	SIP_STIP
+define	SIP_SSIP	SIP_SSIP
+
 define	CAUSE_SYSCALL	CAUSE_SYSCALL
 
 ifdef _LP64
@@ -85,7 +89,7 @@ define	IPL_SOFTBIO	IPL_SOFTBIO
 define	IPL_SOFTCLOCK	IPL_SOFTCLOCK
 define	IPL_NONE	IPL_NONE
 
-#define	CPU_MAXNUM	CPU_MAXNUM
+define	MAXCPUS		MAXCPUS
 
 define	TF_LEN		sizeof(struct trapframe)
 define	TF_RA		offsetof(struct trapframe, tf_reg[_X_RA])

Index: src/sys/arch/riscv/riscv/locore.S
diff -u src/sys/arch/riscv/riscv/locore.S:1.41 src/sys/arch/riscv/riscv/locore.S:1.42
--- src/sys/arch/riscv/riscv/locore.S:1.41	Sun May  7 12:41:49 2023
+++ src/sys/arch/riscv/riscv/locore.S	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: locore.S,v 1.41 2023/05/07 12:41:49 skrll Exp $ */
+/* $NetBSD: locore.S,v 1.42 2023/06/12 19:04:14 skrll Exp $ */
 
 /*-
  * Copyright (c) 2014, 2022 The NetBSD Foundation, Inc.
@@ -30,13 +30,20 @@
  */
 
 #include "opt_console.h"
+#include "opt_multiprocessor.h"
 #include "opt_riscv_debug.h"
 
 #include <machine/asm.h>
 #include "assym.h"
 
-	.globl	_C_LABEL(exception_userexit)
-	.globl	_C_LABEL(cpu_Debugger_insn)
+#define BOOT_AP_STACKSIZE	1024	/* size of temporary stack for APs */
+#define NBBY_SHIFT		3	/* log2(8 bits per byte) */
+
+#define PRINTS(string)		\
+	call	locore_prints	; \
+	.asciz string		; \
+	.align 3		; \
+
 
 #if defined(VERBOSE_INIT_RISCV)
 
@@ -78,18 +85,6 @@ ENTRY_NP(start)
 	li	s0, SR_FS
 	csrc	sstatus, s0		// disable FP
 
-	/*
-	 * atomically swap a non-zero value into hart_boot.  If we see zero
-	 * we won in race to become BP.
-	 */
-	li	s1, 1
-	la	s0, hart_boot
-
-	amoswap.w s0, s1, (s0)
-	bnez	s0, mpentry
-	/*
-	 * The BP only executes from here on.
-	 */
 	mv	s10, a0			// copy hartid
 	mv	s11, a1			// copy dtb PA
 
@@ -375,12 +370,189 @@ vstart:
 END(start)
 
 
-ENTRY(mpentry)
+#if defined(MULTIPROCESSOR)
+
+// a0 is hartid
+// a1 is the cookie from sbi_hart_start
+ENTRY(cpu_mpstart)
+	mv	s10, a0			// copy hartid
+	mv	s11, a1			// copy sbi_hart_start cookie
+
+	/*
+	 * resolve our cpuindex. each hartid is stored in
+	 * extern unsigned long cpu_hartid[MAXCPUS]
+	 */
+	PTR_LA	t0, _C_LABEL(cpu_hartid)
+	li	t6, MAXCPUS
+	li	t1, 0
 1:
+	addi	t1, t1, 1
+	bgeu	t1, t6, toomanyharts	/* cpuindex >= MAXCPUS ? */
+
+	slli	t2, t1, LONG_SCALESHIFT
+	add	t2, t0, t2
+	LONG_L	t3, 0(t2)		/* cpu_hartid[cpuindex] */
+	bne	t3, s10, 1b
+
+	mv	s9, t1			/* s9 = cpuindex */
+
+	/*
+	 * s9 = cpuindex
+	 */
+
+	/* set stack pointer for boot */
+	li	t1, BOOT_AP_STACKSIZE		// XXXNH do a shift
+	mul	t1, s9, t1
+	PTR_LA	t0, _C_LABEL(bootstk)
+	/* sp = bootstk + (BOOT_AP_STACKSIZE * cpuindex) */
+	add	sp, t0, t1
+
+
+	/*
+	 * Calculate the difference between the VA and PA for start and
+	 * keep in s8.
+	 */
+	PTR_LA	t0, start
+	PTR_L	s8, .Lstart
+
+	sub	s8, s8, t0
+
+#ifdef _LP64
+	PTR_LA	s4, _C_LABEL(l2_pte)
+#else
+	PTR_LA	s4, _C_LABEL(l1_pte)
+#endif
+
+	// s4 is satp address....
+	// s8 is kern_vtopdiff
+	//
+
+	/* Set supervisor trap vector base register */
+	PTR_LA	t0, vmpstart
+	add	t0, t0, s8
+	csrw	stvec, t0
+
+	/* Set supervisor address translation and protection register */
+	srli	t1, s4, PGSHIFT
+#ifdef _LP64
+	li	t0, SATP_MODE_SV39
+#else
+	li	t0, SATP_MODE_SV32
+#endif
+	or	t0, t0, t1
+	sfence.vma
+	csrw	satp, t0
+
+	.align 2
+	.global vmpstart
+vmpstart:
+	// MMU is on!
+	csrw	sscratch, zero		// zero in sscratch to mark kernel
+
+	/* Set the global pointer */
+	.option push
+	.option norelax
+	lla	gp, __global_pointer$
+	.option pop
+
+	/* Set SP to VA */
+	add	sp, sp, s8
+
+	/* Set supervisor trap vector base register with ipi_handler */
+	PTR_LA	a0, _C_LABEL(ipi_handler)
+	csrw	stvec, a0
+	csrsi	sie, SIE_SSIE
+	csrsi	sstatus, SR_SIE		// enable interrupts
+
+	li	tp, 0
+	mv	a0, s9
+	call	_C_LABEL(cpu_init_secondary_processor)
+
+	/* t3 = __BIT(cpuindex % (sizeof(u_long) * NBBY)) */
+	li	t3, 1
+	andi	t0, s9, (1U << (LONG_SCALESHIFT + NBBY_SHIFT)) - 1
+	sll	t3, t3, t0
+
+	/* t4 = &riscv_cpu_mbox[cpuindex / (sizeof(u_long) * NBBY)] */
+	PTR_LA	t0, _C_LABEL(riscv_cpu_mbox)
+	srli	t1, s9, LONG_SCALESHIFT + NBBY_SHIFT
+	slli	t1, t1, LONG_SCALESHIFT
+	add	t4, t0, t1
+
+	/* wait for the mailbox start bit to become true */
+1:
+	fence	rw, r		/* matches cpu_boot_secondary_processors */
+	LONG_L	t0, 0(t4)
+	and	t0, t0, t3
+	bne	t0, zero, 9f
 	wfi
 	j	1b
-END(mpentry)
+9:
+
+	/* Set supervisor trap vector base register */
+	PTR_LA	a0, _C_LABEL(cpu_exception_handler)
+	csrw	stvec, a0
+
+	li	t0, CI_SIZE
+	mul	t0, s9, t0
+	PTR_LA	t1, _C_LABEL(cpu_info_store)
+	add	a0, t0, t1		/* a0 = &cpu_info_store[cpuindex] */
+
+	/*
+	 * set curlwp (tp and curcpu()->ci_curlwp) now we know the
+	 * idle lwp from curcpu()->ci_idlelwp
+	 */
+	PTR_L	tp, CI_IDLELWP(a0)	/* tp = curcpu()->ci_idlelwp */
+	PTR_S	tp, CI_CURLWP(a0)	/* curlwp is idlelwp */
+
+	/* get my stack from lwp */
+	PTR_L	t2, L_PCB(tp)		/* t2 = lwp_getpcb(idlelwp) */
+	li	t3, UPAGES * PAGE_SIZE
+	add	t2, t2, t3
+	addi	sp, t2, -TF_LEN		/* sp = pcb + USPACE - TF_LEN */
+
+	li	s0, 0			/* trace back starts here (fp = 0) */
+	PTR_L	a0, L_CPU(tp)		/* curlwp->l_cpu */
+	call	_C_LABEL(cpu_hatch)
+
+	li	s0, 0			// zero frame pointer
+	tail	idle_loop
+	/* No return from idle_loop */
+END(cpu_mpstart)
+
+
+toomanyharts:
+	PRINTS("too many harts, or hart id doens't exist in cpu_hart[]\n")
+1:	wfi
+	j	1b
+
+/*
+ * A very basic exception handler to just return when an IPI comes in during
+ * AP bringup.
+ *
+ * The handler address needs to have bottom two bits as zero.
+ */
+	.align 2
+
+ipi_handler:
+	csrrw	tp, sscratch, tp	// swap scratch and thread pointer
+	bnez	tp, 1f			//   tp != 0, something went wrong.
+
+	csrr	tp, scause		// get cause
+	bgez	tp, 2f			// MSB is set if interrupt
+
+	csrw	sip, zero		// clear all interrupts
 
+	csrrw	tp, sscratch, zero	// get back our thread pointer
+	sret
+
+1:
+	wfi
+	j	1b
+2:
+	wfi
+	j	2b
+#endif
 
 	.align 3
 .Lstart:
@@ -436,6 +608,16 @@ ENTRY_NP(clear_bss)
 END(clear_bss)
 
 
+	.globl  _C_LABEL(cpu_Debugger_insn)
+	.globl  _C_LABEL(cpu_Debugger_ret)
+
+ENTRY_NP(cpu_Debugger)
+cpu_Debugger_insn:
+	ebreak
+cpu_Debugger_ret:
+	ret
+END(cpu_Debugger)
+
 #if defined(VERBOSE_INIT_RISCV)
 ENTRY_NP(locore_prints)
 	addi	sp, sp, -(SZREG * 2)
@@ -533,6 +715,11 @@ END(locore_printxnl)
 hart_boot:
 	.word	0
 
+	/*
+	 * Allocate some memory after the kernel image for stacks and
+	 * bootstrap L1PT
+	 */
+
 	.section "_init_memory", "aw", %nobits
 	.align PGSHIFT
 	.global _C_LABEL(lwp0uspace)
@@ -540,21 +727,10 @@ _C_LABEL(lwp0uspace):
 	.space	UPAGES * PAGE_SIZE
 bootstk:
 
-
-	/*
-	 * Allocate some memory after the kernel image for stacks and
-	 * bootstrap L1PT
-	 */
-	.align PGSHIFT
-#if 0
-.global start_stacks_bottom
-	.global start_stacks_top
-start_stacks_bottom:
-	.space	INIT_ARM_TOTAL_STACK
-start_stacks_top:
+#ifdef MULTIPROCESSOR
+	.space	BOOT_AP_STACKSIZE * (MAXCPUS - 1)
 #endif
 
-
 	.section "_init_memory", "aw", %nobits
 	.align PGSHIFT
 mmutables_start:
@@ -570,9 +746,3 @@ l1_pte:
 	.space PAGE_SIZE
 mmutables_end:
 
-
-ENTRY_NP(cpu_Debugger)
-cpu_Debugger_insn:
-	sbreak
-	ret
-END(cpu_Debugger)

Index: src/sys/arch/riscv/riscv/pmap_machdep.c
diff -u src/sys/arch/riscv/riscv/pmap_machdep.c:1.17 src/sys/arch/riscv/riscv/pmap_machdep.c:1.18
--- src/sys/arch/riscv/riscv/pmap_machdep.c:1.17	Sat Jun 10 07:02:26 2023
+++ src/sys/arch/riscv/riscv/pmap_machdep.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap_machdep.c,v 1.17 2023/06/10 07:02:26 skrll Exp $ */
+/* $NetBSD: pmap_machdep.c,v 1.18 2023/06/12 19:04:14 skrll Exp $ */
 
 /*
  * Copyright (c) 2014, 2019, 2021 The NetBSD Foundation, Inc.
@@ -31,11 +31,12 @@
  */
 
 #include "opt_riscv_debug.h"
+#include "opt_multiprocessor.h"
 
 #define	__PMAP_PRIVATE
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pmap_machdep.c,v 1.17 2023/06/10 07:02:26 skrll Exp $");
+__RCSID("$NetBSD: pmap_machdep.c,v 1.18 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/buf.h>
@@ -161,13 +162,20 @@ pmap_md_ok_to_steal_p(const uvm_physseg_
 	return true;
 }
 
+#ifdef MULTIPROCESSOR
+void
+pmap_md_tlb_info_attach(struct pmap_tlb_info *ti, struct cpu_info *ci)
+{
+}
+#endif
+
 
 void
 pmap_md_xtab_activate(struct pmap *pmap, struct lwp *l)
 {
 //	UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
 
-//	struct cpu_info * const ci = curcpu();
+	struct cpu_info * const ci = curcpu();
 	struct pmap_asid_info * const pai = PMAP_PAI(pmap, cpu_tlb_info(ci));
 
 	uint64_t satp =
@@ -297,6 +305,12 @@ pmap_bootstrap(vaddr_t vstart, vaddr_t v
 	VPRINTF("common ");
 	pmap_bootstrap_common();
 
+#ifdef MULTIPROCESSOR
+	VPRINTF("cpusets ");
+	struct cpu_info * const ci = curcpu();
+	kcpuset_create(&ci->ci_shootdowncpus, true);
+#endif
+
 	VPRINTF("bs_pde %p ", bootstrap_pde);
 
 //	kend = (kend + 0x200000 - 1) & -0x200000;
@@ -416,88 +430,3 @@ pmap_kenter_range(vaddr_t va, paddr_t pa
 
 	return 0;
 }
-
-
-/* -------------------------------------------------------------------------- */
-
-tlb_asid_t
-tlb_get_asid(void)
-{
-	return csr_asid_read();
-}
-
-void
-tlb_set_asid(tlb_asid_t asid, struct pmap *pm)
-{
-	csr_asid_write(asid);
-}
-
-#if 0
-void    tlb_invalidate_all(void);
-void    tlb_invalidate_globals(void);
-#endif
-
-void
-tlb_invalidate_asids(tlb_asid_t lo, tlb_asid_t hi)
-{
-	for (; lo <= hi; lo++) {
-		__asm __volatile("sfence.vma zero, %[asid]"
-		    : /* output operands */
-		    : [asid] "r" (lo)
-		    : "memory");
-	}
-}
-void
-tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid)
-{
-	if (asid == KERNEL_PID) {
-		__asm __volatile("sfence.vma %[va]"
-		    : /* output operands */
-		    : [va] "r" (va)
-		    : "memory");
-	} else {
-		__asm __volatile("sfence.vma %[va], %[asid]"
-		    : /* output operands */
-		    : [va] "r" (va), [asid] "r" (asid)
-		    : "memory");
-	}
-}
-
-bool
-tlb_update_addr(vaddr_t va, tlb_asid_t asid, pt_entry_t pte, bool insert_p)
-{
-	if (asid == KERNEL_PID) {
-		__asm __volatile("sfence.vma %[va]"
-		    : /* output operands */
-		    : [va] "r" (va)
-		    : "memory");
-	} else {
-		__asm __volatile("sfence.vma %[va], %[asid]"
-		    : /* output operands */
-		    : [va] "r" (va), [asid] "r" (asid)
-		    : "memory");
-	}
-	return true;
-}
-
-u_int
-tlb_record_asids(u_long *ptr, tlb_asid_t asid_max)
-{
-	memset(ptr, 0xff, PMAP_TLB_NUM_PIDS / NBBY);
-	ptr[0] = -2UL;
-
-	return PMAP_TLB_NUM_PIDS - 1;
-}
-
-void
-tlb_walk(void *ctx, bool (*func)(void *, vaddr_t, tlb_asid_t, pt_entry_t))
-{
-	/* no way to view the TLB */
-}
-
-#if 0
-void    tlb_enter_addr(size_t, const struct tlbmask *);
-void    tlb_read_entry(size_t, struct tlbmask *);
-void    tlb_write_entry(size_t, const struct tlbmask *);
-void    tlb_dump(void (*)(const char *, ...));
-#endif

Index: src/sys/arch/riscv/riscv/riscv_machdep.c
diff -u src/sys/arch/riscv/riscv/riscv_machdep.c:1.28 src/sys/arch/riscv/riscv/riscv_machdep.c:1.29
--- src/sys/arch/riscv/riscv/riscv_machdep.c:1.28	Sun May 28 12:56:56 2023
+++ src/sys/arch/riscv/riscv/riscv_machdep.c	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: riscv_machdep.c,v 1.28 2023/05/28 12:56:56 skrll Exp $	*/
+/*	$NetBSD: riscv_machdep.c,v 1.29 2023/06/12 19:04:14 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2014, 2019, 2022 The NetBSD Foundation, Inc.
@@ -31,10 +31,11 @@
 
 #include "opt_ddb.h"
 #include "opt_modular.h"
+#include "opt_multiprocessor.h"
 #include "opt_riscv_debug.h"
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: riscv_machdep.c,v 1.28 2023/05/28 12:56:56 skrll Exp $");
+__RCSID("$NetBSD: riscv_machdep.c,v 1.29 2023/06/12 19:04:14 skrll Exp $");
 
 #include <sys/param.h>
 
@@ -372,14 +373,13 @@ cpu_signotify(struct lwp *l)
 
 	if (l->l_cpu != curcpu()) {
 #ifdef MULTIPROCESSOR
-		cpu_send_ipi(ci, IPI_AST);
+		cpu_send_ipi(l->l_cpu, IPI_AST);
 #endif
 	} else {
 		l->l_md.md_astpending = 1; 	/* force call to ast() */
 	}
 }
 
-
 void
 cpu_need_proftick(struct lwp *l)
 {
@@ -520,6 +520,26 @@ cpu_startup(void)
 	format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
 	printf("avail memory = %s\n", pbuf);
 
+#ifdef MULTIPROCESSOR
+	kcpuset_create(&cpus_halted, true);
+	KASSERT(cpus_halted != NULL);
+
+	kcpuset_create(&cpus_hatched, true);
+	KASSERT(cpus_hatched != NULL);
+
+	kcpuset_create(&cpus_paused, true);
+	KASSERT(cpus_paused != NULL);
+
+	kcpuset_create(&cpus_resumed, true);
+	KASSERT(cpus_resumed != NULL);
+
+	kcpuset_create(&cpus_running, true);
+	KASSERT(cpus_running != NULL);
+
+	kcpuset_set(cpus_hatched, cpu_number());
+	kcpuset_set(cpus_running, cpu_number());
+#endif
+
 	fdtbus_intr_init();
 }
 
@@ -689,7 +709,7 @@ init_riscv(register_t hartid, paddr_t dt
 	fdtbus_init(fdt_data);
 
 	/* Lookup platform specific backend */
-	const struct fdt_platform *plat = fdt_platform_find();
+	const struct fdt_platform * const plat = fdt_platform_find();
 	if (plat == NULL)
 		panic("Kernel does not support this device");
 
@@ -871,6 +891,16 @@ init_riscv(register_t hartid, paddr_t dt
 
 	/* Finish setting up lwp0 on our end before we call main() */
 	riscv_init_lwp0_uarea();
+
+
+	error = 0;
+	if ((boothowto & RB_MD1) == 0) {
+		VPRINTF("mpstart\n");
+		if (plat->fp_mpstart)
+			error = plat->fp_mpstart();
+	}
+	if (error)
+		printf("AP startup problems\n");
 }
 
 
@@ -930,8 +960,6 @@ dump_ln_table(paddr_t pdp_pa, int topbit
 	}
 }
 
-#endif
-
 void
 pt_dump(void (*pr)(const char *, ...) __printflike(1, 2))
 {
@@ -958,6 +986,7 @@ pt_dump(void (*pr)(const char *, ...) __
 	dump_ln_table(satp_pa, topbit, level, 0, pr);
 #endif
 }
+#endif
 
 void
 consinit(void)

Index: src/sys/arch/riscv/riscv/spl.S
diff -u src/sys/arch/riscv/riscv/spl.S:1.7 src/sys/arch/riscv/riscv/spl.S:1.8
--- src/sys/arch/riscv/riscv/spl.S:1.7	Sat Jun 10 09:18:50 2023
+++ src/sys/arch/riscv/riscv/spl.S	Mon Jun 12 19:04:14 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: spl.S,v 1.7 2023/06/10 09:18:50 skrll Exp $ */
+/* $NetBSD: spl.S,v 1.8 2023/06/12 19:04:14 skrll Exp $ */
 
 /*-
  * Copyright (c) 2014,2023 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 #include <machine/asm.h>
 #include "assym.h"
 
-__RCSID("$NetBSD: spl.S,v 1.7 2023/06/10 09:18:50 skrll Exp $")
+__RCSID("$NetBSD: spl.S,v 1.8 2023/06/12 19:04:14 skrll Exp $")
 
 #define SZINT	(1 << INT_SCALESHIFT)
 
@@ -50,9 +50,9 @@ _C_LABEL(ipl_sie_map):
 	.word	SIE_SEIE | SIE_STIE			/* IPL_SCHED */
 	.word	SIE_SEIE | SIE_STIE | SIE_SSIE		/* IPL_HIGH */
 
+
 ENTRY_NP(splx)
 	// a0 = new IPL
-//	csrci	sstatus, SR_SIE		// disable interrupts
 	PTR_L	a3, L_CPU(tp)		// get curcpu()
 	INT_L	t0, CI_CPL(a3)		// get current IPL
 	bge	a0, t0, 2f
@@ -68,13 +68,6 @@ ENTRY_NP(splx)
 	// a0 = new ipl
 	INT_S	a0, CI_CPL(a3)		// change IPL
 	csrs	sie, a1
-#if 0
-	beqz	t0, 2f
-
-	//call riscv_do_pending_irqs
-2:
-	csrsi	sstatus, SR_SIE		// enable interrupts
-#endif
 
 #ifdef __HAVE_FAST_SOFTINTS
 	INT_L	t4, CI_SOFTINTS(a3)	// get softint mask
@@ -87,21 +80,20 @@ ENTRY_NP(splx)
 	tail	_C_LABEL(softint_deliver)
 3:
 #endif /* __HAVE_FAST_SOFTINTS */
+2:
 	ret				// return (or do softints)
 END(splx)
 
+
 #if IPL_NONE != 0
 #error IPL_NONE is not 0
 #endif
 ENTRY_NP(spl0)
-//	csrci	sstatus, SR_SIE		// disable interrupts
 	PTR_L	a3, L_CPU(tp)		// get curcpu()
 	INT_S	zero, CI_CPL(a3)	// set current IPL to IPL_NONE
 	li	t2, (SIE_SEIE | SIE_STIE | SIE_SSIE)
 	csrs	sie, t2
 
-	//call riscv_do_pending_irqs
-
 	csrsi	sstatus, SR_SIE		// enable interrupts
 #ifdef __HAVE_FAST_SOFTINTS
 	// spl0() is only called rarely so the overhead of always calling
@@ -113,14 +105,31 @@ ENTRY_NP(spl0)
 END(spl0)
 
 
+ENTRY(splintr)
+	csrr	 t0, sip
 
+	li	 t1, IPL_NONE
+	andi	 t0, t0, (SIP_SEIP | SIP_STIP | SIP_SSIP)
+	beq	 t0, zero, 1f	// If nothing is pending return IPL_NONE
 
+	PTR_LA	 t3, _C_LABEL(ipl_sie_map)
 
-
-
-
-
-
+	li	 t1, IPL_VM
+	li	 t2, IPL_HIGH + 1
+2:
+	INT_L	 t5, IPL_VM * (1 << INT_SCALESHIFT)(t3)
+	PTR_ADDI t3, t3, 1 << INT_SCALESHIFT
+	not	 t5, t5
+	and	 t5, t5, t0
+	beq	 t5, zero, 1f
+	addi	 t1, t1, 1
+	bne	 t1, t2, 2b
+
+1:
+	LONG_S	 t0, 0(a0)
+	mv	 a0, t1
+	jr	 ra
+END(splintr)
 
 
 ENTRY_NP(splsoftclock)
@@ -129,44 +138,41 @@ ENTRY_NP(splsoftclock)
 	j	_splraise
 END(splsoftclock)
 
+
 ENTRY_NP(splsoftbio)
 	li	t1, IPL_SOFTBIO
 	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_SOFTBIO
 	j	_splraise
 END(splsoftbio)
 
+
 ENTRY_NP(splsoftnet)
 	li	t1, IPL_SOFTNET
 	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_SOFTNET
 	j	_splraise
 END(splsoftnet)
 
+
 ENTRY_NP(splsoftserial)
 	li	t1, IPL_SOFTSERIAL
 	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_SOFTSERIAL
 	j	_splraise
 END(splsoftserial)
 
+
 ENTRY_NP(splvm)
 	li	t1, IPL_VM
 	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_VM
 	j	_splraise
 END(splvm)
 
+
 ENTRY_NP(splsched)
 	li	t1, IPL_SCHED
 	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_SCHED
 	j	_splraise
 END(splsched)
 
-#if 0
-ENTRY_NP(splddb)
-	li	t1, IPL_DDB
-	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_DDB
-	j	_splraise
-END(splddb)
-#endif
-
 ENTRY_NP(splhigh)
 	li	t1, IPL_HIGH
 	INT_L	t0, _C_LABEL(ipl_sie_map) + SZINT * IPL_HIGH
@@ -174,7 +180,6 @@ ENTRY_NP(splhigh)
 END(splhigh)
 
 
-
 ENTRY_NP(splraise)
 	// a0 = new higher IPL
 	mv	t1, a0
@@ -184,13 +189,11 @@ ENTRY_NP(splraise)
 	INT_L	t0, 0(a1)
 
 _splraise:
-//	csrc	sstatus, SR_SIE		// disable interrupts
 	PTR_L	a3, L_CPU(tp)		// get curcpu()
 	INT_L	a0, CI_CPL(a3)		// get current IPL
 	bge	a0, t1, 2f		// already at same or higher?
 	csrc	sie, t0			//
 	INT_S	t1, CI_CPL(a3)		// change IPL
 2:
-//	csrsi	sstatus, SR_SIE		// enable interrupts
 	ret
 END(splraise)

Added files:

Index: src/sys/arch/riscv/fdt/riscv_fdtvar.h
diff -u /dev/null src/sys/arch/riscv/fdt/riscv_fdtvar.h:1.1
--- /dev/null	Mon Jun 12 19:04:14 2023
+++ src/sys/arch/riscv/fdt/riscv_fdtvar.h	Mon Jun 12 19:04:13 2023
@@ -0,0 +1,41 @@
+/* $NetBSD: riscv_fdtvar.h,v 1.1 2023/06/12 19:04:13 skrll Exp $ */
+
+/*-
+ * Copyright (c) 2023 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Nick Hudson
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _RISCV_RISCV_FDTVAR_H
+#define _RISCV_RISCV_FDTVAR_H
+
+void	riscv_fdt_cpu_bootstrap(void);
+int	riscv_fdt_cpu_mpstart(void);
+void	riscv_fdt_cpu_hatch_register(void *, void (*)(void *, struct cpu_info *));
+void	riscv_fdt_cpu_hatch(struct cpu_info *);
+
+#endif /* !_RISCV_RISCV_FDTVAR_H */

Index: src/sys/arch/riscv/riscv/ipifuncs.c
diff -u /dev/null src/sys/arch/riscv/riscv/ipifuncs.c:1.1
--- /dev/null	Mon Jun 12 19:04:14 2023
+++ src/sys/arch/riscv/riscv/ipifuncs.c	Mon Jun 12 19:04:14 2023
@@ -0,0 +1,168 @@
+/*	$NetBSD: ipifuncs.c,v 1.1 2023/06/12 19:04:14 skrll Exp $	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.1 2023/06/12 19:04:14 skrll Exp $");
+
+#include <sys/param.h>
+
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/ipi.h>
+#include <sys/xcall.h>
+
+#include <uvm/uvm_extern.h>
+#include <uvm/pmap/pmap_synci.h>
+#include <uvm/pmap/pmap_tlb.h>
+
+static void ipi_halt(void) __dead;
+
+static const char * const ipi_names[] = {
+	[IPI_NOP]	= "ipi nop",
+	[IPI_AST]	= "ipi ast",
+	[IPI_SHOOTDOWN]	= "ipi shootdown",
+	[IPI_SYNCICACHE]= "ipi isync",
+	[IPI_KPREEMPT]	= "ipi kpreempt",
+	[IPI_SUSPEND]	= "ipi suspend",
+	[IPI_HALT]	= "ipi halt",
+	[IPI_XCALL]	= "ipi xcall",
+	[IPI_GENERIC]	= "ipi generic",
+};
+
+static void
+ipi_nop(struct cpu_info *ci)
+{
+	/*
+	 * This is just a reason to get an interrupt so we get
+	 * kicked out of cpu_idle().
+	 */
+}
+
+static void
+ipi_ast(struct cpu_info *ci)
+{
+	ci->ci_onproc->l_md.md_astpending = 1;
+}
+
+static void
+ipi_shootdown(struct cpu_info *ci)
+{
+	pmap_tlb_shootdown_process();
+}
+
+static inline void
+ipi_syncicache(struct cpu_info *ci)
+{
+	pmap_tlb_syncicache_wanted(ci);
+}
+
+#ifdef __HAVE_PREEMPTION
+static inline void
+ipi_kpreempt(struct cpu_info *ci)
+{
+	softint_trigger(SOFTINT_KPREEMPT);
+}
+#endif
+
+/*
+ * Process cpu stop-self event.
+ * XXX could maybe add/use locoresw halt function?
+ */
+static void
+ipi_halt(void)
+{
+	const u_int my_cpu = cpu_number();
+	printf("cpu%u: shutting down\n", my_cpu);
+	kcpuset_set(cpus_halted, my_cpu);
+	splhigh();
+	for (;;)
+		;
+	/* NOTREACHED */
+}
+
+void
+ipi_process(struct cpu_info *ci, unsigned long ipi_mask)
+{
+	KASSERT(cpu_intr_p());
+
+	if (ipi_mask & __BIT(IPI_NOP)) {
+		ci->ci_evcnt_per_ipi[IPI_NOP].ev_count++;
+		ipi_nop(ci);
+	}
+	if (ipi_mask & __BIT(IPI_AST)) {
+		ci->ci_evcnt_per_ipi[IPI_AST].ev_count++;
+		ipi_ast(ci);
+	}
+	if (ipi_mask & __BIT(IPI_SHOOTDOWN)) {
+		ci->ci_evcnt_per_ipi[IPI_SHOOTDOWN].ev_count++;
+		ipi_shootdown(ci);
+	}
+	if (ipi_mask & __BIT(IPI_SYNCICACHE)) {
+		ci->ci_evcnt_per_ipi[IPI_SYNCICACHE].ev_count++;
+		ipi_syncicache(ci);
+	}
+	if (ipi_mask & __BIT(IPI_SUSPEND)) {
+		ci->ci_evcnt_per_ipi[IPI_SUSPEND].ev_count++;
+		cpu_pause();
+	}
+	if (ipi_mask & __BIT(IPI_HALT)) {
+		ci->ci_evcnt_per_ipi[IPI_HALT].ev_count++;
+		ipi_halt();
+	}
+	if (ipi_mask & __BIT(IPI_XCALL)) {
+		ci->ci_evcnt_per_ipi[IPI_XCALL].ev_count++;
+		xc_ipi_handler();
+	}
+	if (ipi_mask & __BIT(IPI_GENERIC)) {
+		ci->ci_evcnt_per_ipi[IPI_GENERIC].ev_count++;
+		ipi_cpu_handler();
+	}
+#ifdef __HAVE_PREEMPTION
+	if (ipi_mask & __BIT(IPI_KPREEMPT)) {
+		ci->ci_evcnt_per_ipi[IPI_KPREEMPT].ev_count++;
+		ipi_kpreempt(ci);
+	}
+#endif
+}
+
+void
+ipi_init(struct cpu_info *ci)
+{
+	evcnt_attach_dynamic(&ci->ci_evcnt_all_ipis, EVCNT_TYPE_INTR,
+	    NULL, device_xname(ci->ci_dev), "ipi");
+
+	for (size_t i = 0; i < NIPIS; i++) {
+		KASSERTMSG(ipi_names[i] != NULL, "%zu", i);
+		evcnt_attach_dynamic(&ci->ci_evcnt_per_ipi[i], EVCNT_TYPE_INTR,
+		    NULL, device_xname(ci->ci_dev), ipi_names[i]);
+	}
+}
Index: src/sys/arch/riscv/riscv/riscv_tlb.c
diff -u /dev/null src/sys/arch/riscv/riscv/riscv_tlb.c:1.1
--- /dev/null	Mon Jun 12 19:04:14 2023
+++ src/sys/arch/riscv/riscv/riscv_tlb.c	Mon Jun 12 19:04:14 2023
@@ -0,0 +1,127 @@
+/* $NetBSD: riscv_tlb.c,v 1.1 2023/06/12 19:04:14 skrll Exp $ */
+
+/*
+ * Copyright (c) 2014, 2019, 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas (of 3am Software Foundry), Maxime Villard, and
+ * Nick Hudson.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opt_riscv_debug.h"
+#include "opt_multiprocessor.h"
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: riscv_tlb.c,v 1.1 2023/06/12 19:04:14 skrll Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <uvm/uvm.h>
+
+tlb_asid_t
+tlb_get_asid(void)
+{
+	return csr_asid_read();
+}
+
+void
+tlb_set_asid(tlb_asid_t asid, struct pmap *pm)
+{
+	csr_asid_write(asid);
+}
+
+void
+tlb_invalidate_all(void)
+{
+	asm volatile("sfence.vma"
+	    : /* output operands */
+	    : /* input operands */
+	    : "memory");
+}
+
+void
+tlb_invalidate_globals(void)
+{
+	tlb_invalidate_all();
+}
+
+void
+tlb_invalidate_asids(tlb_asid_t lo, tlb_asid_t hi)
+{
+	for (; lo <= hi; lo++) {
+		asm volatile("sfence.vma zero, %[asid]"
+		    : /* output operands */
+		    : [asid] "r" (lo)
+		    : "memory");
+	}
+}
+void
+tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid)
+{
+	if (asid == KERNEL_PID) {
+		asm volatile("sfence.vma %[va]"
+		    : /* output operands */
+		    : [va] "r" (va)
+		    : "memory");
+	} else {
+		asm volatile("sfence.vma %[va], %[asid]"
+		    : /* output operands */
+		    : [va] "r" (va), [asid] "r" (asid)
+		    : "memory");
+	}
+}
+
+bool
+tlb_update_addr(vaddr_t va, tlb_asid_t asid, pt_entry_t pte, bool insert_p)
+{
+	if (asid == KERNEL_PID) {
+		asm volatile("sfence.vma %[va]"
+		    : /* output operands */
+		    : [va] "r" (va)
+		    : "memory");
+	} else {
+		asm volatile("sfence.vma %[va], %[asid]"
+		    : /* output operands */
+		    : [va] "r" (va), [asid] "r" (asid)
+		    : "memory");
+	}
+	return true;
+}
+
+u_int
+tlb_record_asids(u_long *ptr, tlb_asid_t asid_max)
+{
+	memset(ptr, 0xff, PMAP_TLB_NUM_PIDS / NBBY);
+	ptr[0] = -2UL;
+
+	return PMAP_TLB_NUM_PIDS - 1;
+}
+
+void
+tlb_walk(void *ctx, bool (*func)(void *, vaddr_t, tlb_asid_t, pt_entry_t))
+{
+	/* no way to view the TLB */
+}

Reply via email to