#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mips_machdep.c,v 1.310 2026/07/01 17:01:43 rkujawa Exp $");
#define __INTR_PRIVATE
#include "opt_cputype.h"
#include "opt_compat_netbsd32.h"
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/intr.h>
#include <sys/exec.h>
#include <sys/reboot.h>
#include <sys/module.h>
#include <sys/mount.h>
#include <sys/lwp.h>
#include <sys/sysctl.h>
#include <sys/msgbuf.h>
#include <sys/conf.h>
#include <sys/core.h>
#include <sys/device.h>
#include <sys/kcore.h>
#include <sys/kmem.h>
#include <sys/ras.h>
#include <sys/cpu.h>
#include <sys/atomic.h>
#include <sys/ucontext.h>
#include <sys/bitops.h>
#include <mips/kcore.h>
#ifdef COMPAT_NETBSD32
#include <compat/netbsd32/netbsd32.h>
#endif
#include <uvm/uvm.h>
#include <uvm/uvm_physseg.h>
#include <dev/cons.h>
#include <dev/mm.h>
#include <mips/pcb.h>
#include <mips/cache.h>
#include <mips/frame.h>
#include <mips/regnum.h>
#include <mips/mips_opcode.h>
#include <mips/cpu.h>
#include <mips/locore.h>
#include <mips/psl.h>
#include <mips/pte.h>
#include <mips/userret.h>
#ifdef __HAVE_BOOTINFO_H
#include <machine/bootinfo.h>
#endif
#ifdef MIPS64_OCTEON
#include <mips/cavium/octeonvar.h>
#endif
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
#include <mips/mipsNN.h>
#define _MKINSN(a,b,c,d,e) ((uint32_t)(((a) << 26)|((b) << 21)|((c) << 16)|((d) << 11)|(e)))
#ifdef _LP64
#define _LOAD_V0_L_PRIVATE_A0 _MKINSN(OP_LD, _R_A0, _R_V0, 0, offsetof(lwp_t, l_private))
#define _MTC0_V0_USERLOCAL _MKINSN(OP_COP0, OP_DMT, _R_V0, MIPS_COP_0_TLB_CONTEXT, 2)
#else
#define _LOAD_V0_L_PRIVATE_A0 _MKINSN(OP_LW, _R_A0, _R_V0, 0, offsetof(lwp_t, l_private))
#define _MTC0_V0_USERLOCAL _MKINSN(OP_COP0, OP_MT, _R_V0, MIPS_COP_0_TLB_CONTEXT, 2)
#endif
#define JR_RA _MKINSN(OP_SPECIAL, _R_RA, 0, 0, OP_JR)
#endif
int cpu_dumpsize(void);
u_long cpu_dump_mempagecnt(void);
int cpu_dump(void);
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
static void mips_watchpoint_init(void);
#endif
#if defined(_LP64) && defined(ENABLE_MIPS_16KB_PAGE)
vaddr_t mips_vm_maxuser_address = MIPS_VM_MAXUSER_ADDRESS;
#endif
#if defined(MIPS3_PLUS)
uint32_t mips3_cp0_tlb_page_mask_probe(void);
uint64_t mips3_cp0_tlb_entry_hi_probe(void);
uint64_t mips3_cp0_tlb_entry_lo_probe(void);
static void mips3_tlb_probe(void);
#endif
#if defined(MIPS1)
static void mips1_vector_init(const struct splsw *);
extern const struct locoresw mips1_locoresw;
extern const mips_locore_jumpvec_t mips1_locore_vec;
#endif
#if defined(MIPS3)
static void mips3_vector_init(const struct splsw *);
extern const struct locoresw mips3_locoresw;
extern const mips_locore_jumpvec_t mips3_locore_vec;
#endif
#if defined(MIPS3_LOONGSON2)
static void loongson2_vector_init(const struct splsw *);
extern const struct locoresw loongson2_locoresw;
extern const mips_locore_jumpvec_t loongson2_locore_vec;
#endif
#if defined(MIPS32)
static void mips32_vector_init(const struct splsw *);
extern const struct locoresw mips32_locoresw;
extern const mips_locore_jumpvec_t mips32_locore_vec;
#endif
#if defined(MIPS32R2)
static void mips32r2_vector_init(const struct splsw *);
extern const struct locoresw mips32r2_locoresw;
extern const mips_locore_jumpvec_t mips32r2_locore_vec;
#endif
#if defined(MIPS64)
static void mips64_vector_init(const struct splsw *);
extern const struct locoresw mips64_locoresw;
extern const mips_locore_jumpvec_t mips64_locore_vec;
#endif
#if defined(MIPS64R2)
extern const struct locoresw mips64r2_locoresw;
extern const mips_locore_jumpvec_t mips64r2_locore_vec;
#endif
#if defined(PARANOIA)
void std_splsw_test(void);
#endif
mips_locore_jumpvec_t mips_locore_jumpvec;
struct locoresw mips_locoresw;
extern const struct splsw std_splsw;
struct splsw mips_splsw;
struct mips_options mips_options = {
.mips_cpu_id = 0xffffffff,
.mips_fpu_id = 0xffffffff,
};
void * msgbufaddr;
void (*cpu_reset_address)(void);
char machine[] = MACHINE;
char machine_arch[] = MACHINE_ARCH;
#define MIPS32_FLAGS CPU_MIPS_R4K_MMU | CPU_MIPS_CAUSE_IV | CPU_MIPS_USE_WAIT
#define MIPS64_FLAGS MIPS32_FLAGS
static const struct pridtab cputab[] = {
{ 0, MIPS_R2000, -1, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_LLSC, 0, 0, "MIPS R2000 CPU" },
{ 0, MIPS_R3000, MIPS_REV_R2000A, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_LLSC, 0, 0, "MIPS R2000A CPU" },
{ 0, MIPS_R3000, MIPS_REV_R3000, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_LLSC, 0, 0, "MIPS R3000 CPU" },
{ 0, MIPS_R3000, MIPS_REV_R3000A, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_LLSC, 0, 0, "MIPS R3000A CPU" },
{ 0, MIPS_R6000, -1, -1, CPU_ARCH_MIPS2, 32,
MIPS_NOT_SUPP, 0, 0, "MIPS R6000 CPU" },
{ 0, MIPS_R4000, MIPS_REV_R4000_A, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R4000 CPU" },
{ 0, MIPS_R4000, MIPS_REV_R4000_B, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R4000 CPU" },
{ 0, MIPS_R4000, MIPS_REV_R4000_C, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R4000 CPU" },
{ 0, MIPS_R4000, MIPS_REV_R4400_A, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R4400 CPU" },
{ 0, MIPS_R4000, MIPS_REV_R4400_B, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R4400 CPU" },
{ 0, MIPS_R4000, MIPS_REV_R4400_C, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R4400 CPU" },
{ 0, MIPS_R3LSI, -1, -1, CPU_ARCH_MIPS1, -1,
MIPS_NOT_SUPP, 0, 0, "LSI Logic R3000 derivative" },
{ 0, MIPS_R6000A, -1, -1, CPU_ARCH_MIPS2, 32,
MIPS_NOT_SUPP, 0, 0, "MIPS R6000A CPU" },
{ 0, MIPS_R3IDT, -1, -1, CPU_ARCH_MIPS1, -1,
MIPS_NOT_SUPP, 0, 0, "IDT R3041 or RC36100 CPU" },
{ 0, MIPS_R4100, -1, -1, CPU_ARCH_MIPS3, 32,
CPU_MIPS_R4K_MMU | CPU_MIPS_NO_LLSC, 0, 0,
"NEC VR4100 CPU" },
{ 0, MIPS_R4200, -1, -1, CPU_ARCH_MIPS3, -1,
MIPS_NOT_SUPP | CPU_MIPS_R4K_MMU, 0, 0,
"NEC VR4200 CPU" },
{ 0, MIPS_R4300, -1, -1, CPU_ARCH_MIPS3, 32,
CPU_MIPS_R4K_MMU, 0, 0, "NEC VR4300 CPU" },
{ 0, MIPS_R4600, -1, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"QED R4600 Orion CPU" },
{ 0, MIPS_R4700, -1, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU, 0, 0, "QED R4700 Orion CPU" },
{ 0, MIPS_R8000, -1, -1, CPU_ARCH_MIPS4, 384,
MIPS_NOT_SUPP | CPU_MIPS_R4K_MMU, 0, 0,
"MIPS R8000 Blackbird/TFP CPU" },
{ 0, MIPS_R10000, -1, -1, CPU_ARCH_MIPS4, 64,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R10000 CPU" },
{ 0, MIPS_R12000, -1, -1, CPU_ARCH_MIPS4, 64,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R12000 CPU" },
{ 0, MIPS_R14000, -1, -1, CPU_ARCH_MIPS4, 64,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R14000 CPU" },
{ 0, MIPS_R4650, 0, -1, CPU_ARCH_MIPS3, -1,
MIPS_NOT_SUPP , 0, 0, "QED R4650 CPU" },
{ 0, MIPS_TX3900, MIPS_REV_TX3912, -1, CPU_ARCH_MIPS1, 32,
CPU_MIPS_NO_LLSC, 0, 0, "Toshiba TX3912 CPU" },
{ 0, MIPS_TX3900, MIPS_REV_TX3922, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_LLSC, 0, 0, "Toshiba TX3922 CPU" },
{ 0, MIPS_TX3900, MIPS_REV_TX3927, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_LLSC, 0, 0, "Toshiba TX3927 CPU" },
{ 0, MIPS_R5000, -1, -1, CPU_ARCH_MIPS4, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"MIPS R5000 CPU" },
{ 0, MIPS_RM5200, -1, -1, CPU_ARCH_MIPS4, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_CAUSE_IV | CPU_MIPS_DOUBLE_COUNT |
CPU_MIPS_USE_WAIT, 0, 0, "QED RM5200 CPU" },
{ 0, MIPS_RM7000, -1, -1, CPU_ARCH_MIPS4, 48,
MIPS_NOT_SUPP | CPU_MIPS_CAUSE_IV | CPU_MIPS_DOUBLE_COUNT |
CPU_MIPS_USE_WAIT, 0, 0, "QED RM7000 CPU" },
{ 0, MIPS_RC32300, -1, -1, CPU_ARCH_MIPS3, 16,
MIPS_NOT_SUPP | CPU_MIPS_R4K_MMU, 0, 0,
"IDT RC32300 CPU" },
{ 0, MIPS_RC32364, -1, -1, CPU_ARCH_MIPS3, 16,
MIPS_NOT_SUPP | CPU_MIPS_R4K_MMU, 0, 0,
"IDT RC32364 CPU" },
{ 0, MIPS_RC64470, -1, -1, CPU_ARCH_MIPSx, -1,
MIPS_NOT_SUPP | CPU_MIPS_R4K_MMU, 0, 0,
"IDT RC64474/RC64475 CPU" },
{ 0, MIPS_R5400, -1, -1, CPU_ARCH_MIPSx, -1,
MIPS_NOT_SUPP | CPU_MIPS_R4K_MMU, 0, 0,
"NEC VR5400 CPU" },
{ 0, MIPS_R5900, -1, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_NO_LLSC | CPU_MIPS_R4K_MMU, 0, 0,
"Toshiba R5900 CPU" },
{ 0, MIPS_TX4900, MIPS_REV_TX4927, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"Toshiba TX4927 CPU" },
{ 0, MIPS_TX4900, -1, -1, CPU_ARCH_MIPS3, 48,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT, 0, 0,
"Toshiba TX4900 CPU" },
#ifdef ENABLE_MIPS_16KB_PAGE
#define MIPS_LOONGSON2_CCA 0
#else
#define MIPS_LOONGSON2_CCA (CPU_MIPS_HAVE_SPECIAL_CCA | \
(2 << CPU_MIPS_CACHED_CCA_SHIFT))
#endif
{ 0, MIPS_LOONGSON2, MIPS_REV_LOONGSON2E, -1, CPU_ARCH_MIPS3, 64,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT | CPU_MIPS_LOONGSON2
| MIPS_LOONGSON2_CCA, 0, 0, "ICT Loongson 2E CPU" },
{ 0, MIPS_LOONGSON2, MIPS_REV_LOONGSON2F, -1, CPU_ARCH_MIPS3, 64,
CPU_MIPS_R4K_MMU | CPU_MIPS_DOUBLE_COUNT | CPU_MIPS_LOONGSON2
| MIPS_LOONGSON2_CCA, 0, 0, "ICT Loongson 2F CPU" },
#if 0
{ 0, MIPS_R3SONY, -1, -1, CPU_ARCH_MIPS1, -1,
MIPS_NOT_SUPP, 0, 0, "SONY R3000 derivative" },
{ 0, MIPS_R3NKK, -1, -1, CPU_ARCH_MIPS1, -1,
MIPS_NOT_SUPP, 0, 0, "NKK R3000 derivative" },
#endif
{ MIPS_PRID_CID_MTI, MIPS_4Kc, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT, 0, 0, "4Kc" },
{ MIPS_PRID_CID_MTI, MIPS_4KEc, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT, 0, 0, "4KEc" },
{ MIPS_PRID_CID_MTI, MIPS_4KEc_R2, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT, 0, 0, "4KEc (Rev 2)" },
{ MIPS_PRID_CID_MTI, MIPS_4KSc, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT, 0, 0, "4KSc" },
{ MIPS_PRID_CID_MTI, MIPS_5Kc, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_DOUBLE_COUNT, 0, 0, "5Kc" },
{ MIPS_PRID_CID_MTI, MIPS_20Kc, -1, -1, -1, 0,
MIPS64_FLAGS, 0, 0, "20Kc" },
{ MIPS_PRID_CID_MTI, MIPS_25Kf, -1, -1, -1, 0,
MIPS64_FLAGS, 0, 0, "25Kf" },
{ MIPS_PRID_CID_MTI, MIPS_24K, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG7,
0, "24K" },
{ MIPS_PRID_CID_MTI, MIPS_24KE, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG7,
0, "24KE" },
{ MIPS_PRID_CID_MTI, MIPS_34K, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG7,
0, "34K" },
{ MIPS_PRID_CID_MTI, MIPS_74K, -1, -1, -1, 0,
CPU_MIPS_HAVE_SPECIAL_CCA | (0 << CPU_MIPS_CACHED_CCA_SHIFT) |
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG6 | MIPS_CP0FL_CONFIG7,
0, "74K" },
{ MIPS_PRID_CID_MTI, MIPS_1004K, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG6 | MIPS_CP0FL_CONFIG7,
0, "1004K" },
{ MIPS_PRID_CID_MTI, MIPS_1074K, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG6 | MIPS_CP0FL_CONFIG7,
0, "1074K" },
{ MIPS_PRID_CID_BROADCOM, MIPS_BCM3302, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT, 0, 0, "BCM3302" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV1, -1, MIPS_AU1000, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1000 (Rev 1 core)" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV2, -1, MIPS_AU1000, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1000 (Rev 2 core)" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV1, -1, MIPS_AU1100, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1100 (Rev 1 core)" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV2, -1, MIPS_AU1100, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1100 (Rev 2 core)" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV1, -1, MIPS_AU1500, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1500 (Rev 1 core)" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV2, -1, MIPS_AU1500, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1500 (Rev 2 core)" },
{ MIPS_PRID_CID_ALCHEMY, MIPS_AU_REV2, -1, MIPS_AU1550, -1, 0,
MIPS32_FLAGS | CPU_MIPS_NO_WAIT | CPU_MIPS_I_D_CACHE_COHERENT, 0, 0,
"Au1550 (Rev 2 core)" },
{ MIPS_PRID_CID_SIBYTE, MIPS_SB1, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT |
CPU_MIPS_HAVE_SPECIAL_CCA |
(CCA_SB_CACHEABLE_COHERENT << CPU_MIPS_CACHED_CCA_SHIFT), 0, 0,
"SB-1" },
{ MIPS_PRID_CID_SIBYTE, MIPS_SB1_11, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT |
CPU_MIPS_HAVE_SPECIAL_CCA |
(CCA_SB_CACHEABLE_COHERENT << CPU_MIPS_CACHED_CCA_SHIFT), 0, 0,
"SB-1 (0x11)" },
{ MIPS_PRID_CID_RMI, MIPS_XLR732B, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLR|MIPS_CIDFL_RMI_CPUS(8,4)|MIPS_CIDFL_RMI_L2(2MB),
"XLR732B" },
{ MIPS_PRID_CID_RMI, MIPS_XLR732C, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLR|MIPS_CIDFL_RMI_CPUS(8,4)|MIPS_CIDFL_RMI_L2(2MB),
"XLR732C" },
{ MIPS_PRID_CID_RMI, MIPS_XLS616, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(4,4)|MIPS_CIDFL_RMI_L2(1MB),
"XLS616" },
{ MIPS_PRID_CID_RMI, MIPS_XLS416, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(4,4)|MIPS_CIDFL_RMI_L2(1MB),
"XLS416" },
{ MIPS_PRID_CID_RMI, MIPS_XLS408, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(2,4)|MIPS_CIDFL_RMI_L2(1MB),
"XLS408" },
{ MIPS_PRID_CID_RMI, MIPS_XLS408LITE, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(2,4)|MIPS_CIDFL_RMI_L2(1MB),
"XLS408lite" },
{ MIPS_PRID_CID_RMI, MIPS_XLS404LITE, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(1,4)|MIPS_CIDFL_RMI_L2(512KB),
"XLS404lite" },
{ MIPS_PRID_CID_RMI, MIPS_XLS208, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(2,4)|MIPS_CIDFL_RMI_L2(512KB),
"XLS208" },
{ MIPS_PRID_CID_RMI, MIPS_XLS204, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(1,4)|MIPS_CIDFL_RMI_L2(256KB),
"XLS204" },
{ MIPS_PRID_CID_RMI, MIPS_XLS108, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(2,4)|MIPS_CIDFL_RMI_L2(512KB),
"XLS108" },
{ MIPS_PRID_CID_RMI, MIPS_XLS104, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR |
CPU_MIPS_I_D_CACHE_COHERENT | CPU_MIPS_HAVE_MxCR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EIRR | MIPS_CP0FL_EIMR | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG7,
CIDFL_RMI_TYPE_XLS|MIPS_CIDFL_RMI_CPUS(1,4)|MIPS_CIDFL_RMI_L2(256KB),
"XLS104" },
{ MIPS_PRID_CID_CAVIUM, MIPS_CN31XX, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE | MIPS_CP0FL_CONFIG |
MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 | MIPS_CP0FL_CONFIG3,
0,
"CN31xx" },
{ MIPS_PRID_CID_CAVIUM, MIPS_CN30XX, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE | MIPS_CP0FL_CONFIG |
MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 | MIPS_CP0FL_CONFIG3,
0,
"CN30xx" },
{ MIPS_PRID_CID_CAVIUM, MIPS_CN50XX, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR,
MIPS_CP0FL_USE |
MIPS_CP0FL_EBASE | MIPS_CP0FL_CONFIG |
MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 | MIPS_CP0FL_CONFIG3,
0,
"CN50xx" },
{ MIPS_PRID_CID_CAVIUM, MIPS_CN68XX, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR,
MIPS_CP0FL_USE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG4,
0,
"CN68xx" },
{ MIPS_PRID_CID_CAVIUM, MIPS_CN70XX, -1, -1, -1, 0,
MIPS64_FLAGS | CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_NO_LLADDR,
MIPS_CP0FL_USE | MIPS_CP0FL_EBASE |
MIPS_CP0FL_CONFIG | MIPS_CP0FL_CONFIG1 | MIPS_CP0FL_CONFIG2 |
MIPS_CP0FL_CONFIG3 | MIPS_CP0FL_CONFIG4 | MIPS_CP0FL_CONFIG5 |
MIPS_CP0FL_CONFIG6 | MIPS_CP0FL_CONFIG7,
0,
"CN70xx/CN71xx" },
{ MIPS_PRID_CID_MICROSOFT, MIPS_eMIPS, 1, -1, CPU_ARCH_MIPS1, 64,
CPU_MIPS_NO_WAIT, 0, 0, "eMIPS CPU" },
{ MIPS_PRID_CID_INGENIC, MIPS_XBURST, -1, -1, -1, 0,
MIPS32_FLAGS | CPU_MIPS_DOUBLE_COUNT,
0, 0, "XBurst" },
{ 0, 0, 0, 0, 0, 0,
0, 0, 0, NULL }
};
static const struct pridtab fputab[] = {
{ 0, MIPS_SOFT, -1, 0, 0, 0, 0, 0, 0, "software emulated floating point" },
{ 0, MIPS_R2360, -1, 0, 0, 0, 0, 0, 0, "MIPS R2360 Floating Point Board" },
{ 0, MIPS_R2010, -1, 0, 0, 0, 0, 0, 0, "MIPS R2010 FPC" },
{ 0, MIPS_R3010, -1, 0, 0, 0, 0, 0, 0, "MIPS R3010 FPC" },
{ 0, MIPS_R6010, -1, 0, 0, 0, 0, 0, 0, "MIPS R6010 FPC" },
{ 0, MIPS_R4010, -1, 0, 0, 0, 0, 0, 0, "MIPS R4010 FPC" },
};
static const char * const cidnames[] = {
"Prehistoric",
"MIPS",
"Broadcom",
"Alchemy",
"SiByte",
"SandCraft",
"Phillips",
"Toshiba or Microsoft",
"LSI",
"(unannounced)",
"(unannounced)",
"Lexra",
"RMI",
"Cavium",
};
#define ncidnames __arraycount(cidnames)
#if defined(MIPS1)
static void
mips1_vector_init(const struct splsw *splsw)
{
extern char mips1_utlb_miss[], mips1_utlb_miss_end[];
extern char mips1_exception[], mips1_exception_end[];
if (mips1_utlb_miss_end - mips1_utlb_miss > 0x80)
panic("startup: UTLB vector code too large");
if (mips1_exception_end - mips1_exception > 0x80)
panic("startup: general exception vector code too large");
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC, mips1_utlb_miss,
mips1_exception_end - mips1_utlb_miss);
mips_locore_jumpvec = mips1_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
}
#endif
#if defined(MIPS3)
static void
mips3_vector_init(const struct splsw *splsw)
{
extern char mips3_exception[], mips3_exception_end[];
extern char mips3_tlb_miss[];
extern char mips3_xtlb_miss[];
extern char mips3_cache[];
if (mips3_xtlb_miss - mips3_tlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"UTLB");
if (mips3_cache - mips3_xtlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"XTLB");
if (mips3_exception - mips3_cache != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"Cache error");
if (mips3_exception_end - mips3_exception > 0x80)
panic("startup: %s vector code too large",
"General exception");
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC, mips3_tlb_miss,
mips3_exception_end - mips3_tlb_miss);
mips_locore_jumpvec = mips3_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
mips_cp0_status_write(mips_cp0_status_read() & ~MIPS_SR_BEV);
}
#endif
#if defined(MIPS3_LOONGSON2)
static void
loongson2_vector_init(const struct splsw *splsw)
{
extern char loongson2_exception[], loongson2_exception_end[];
extern char loongson2_tlb_miss[];
extern char loongson2_xtlb_miss[];
extern char loongson2_cache[];
if (loongson2_xtlb_miss - loongson2_tlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"UTLB");
if (loongson2_cache - loongson2_xtlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"XTLB");
if (loongson2_exception - loongson2_cache != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"Cache error");
if (loongson2_exception_end - loongson2_exception > 0x80)
panic("startup: %s vector code too large",
"General exception");
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC, loongson2_tlb_miss,
loongson2_exception_end - loongson2_tlb_miss);
mips_locore_jumpvec = loongson2_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
mips_cp0_status_write(mips_cp0_status_read() & ~MIPS_SR_BEV);
}
#endif
#if defined(MIPS32)
static void
mips32_vector_init(const struct splsw *splsw)
{
extern char mips32_exception[];
extern char mips32_tlb_miss[];
extern char mips32_cache[];
extern char mips32_intr[], mips32_intr_end[];
if (mips32_cache - mips32_tlb_miss != 0x100)
panic("startup: %s vector code not 128 bytes in length",
"UTLB");
if (mips32_exception - mips32_cache != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"Cache error");
if (mips32_intr - mips32_exception != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"General exception");
if (mips32_intr_end - mips32_intr > 0x80)
panic("startup: %s vector code too large",
"interrupt exception");
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC, mips32_tlb_miss,
mips32_intr_end - mips32_tlb_miss);
mips_locore_jumpvec = mips32_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
mips_cp0_status_write(mips_cp0_status_read() & ~MIPS_SR_BEV);
mips_watchpoint_init();
}
#endif
#if defined(MIPS32R2)
static void
mips32r2_vector_init(const struct splsw *splsw)
{
extern char mips32r2_exception[];
extern char mips32r2_tlb_miss[];
extern char mips32r2_cache[];
extern char mips32r2_intr[], mips32r2_intr_end[];
if (mips32r2_cache - mips32r2_tlb_miss != 0x100)
panic("startup: %s vector code not 128 bytes in length",
"UTLB");
if (mips32r2_exception - mips32r2_cache != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"Cache error");
if (mips32r2_intr - mips32r2_exception != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"General exception");
if (mips32r2_intr_end - mips32r2_intr > 0x80)
panic("startup: %s vector code too large",
"interrupt exception");
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC, mips32r2_tlb_miss,
mips32r2_intr_end - mips32r2_tlb_miss);
if (mipsNN_cp0_config2_read() & MIPSNN_CFG2_M) {
const uint32_t cfg3 = mipsNN_cp0_config3_read();
if (cfg3 & MIPSNN_CFG3_ULRI) {
mips_options.mips_cpu_flags |= CPU_MIPS_HAVE_USERLOCAL;
}
if (cfg3 & MIPSNN_CFG3_DSP2P) {
mips_options.mips_cpu_flags |= CPU_MIPS_HAVE_DSP;
}
}
if (!MIPS_HAS_USERLOCAL) {
extern uint32_t mips32r2_cpu_switch_resume[];
for (uint32_t *insnp = mips32r2_cpu_switch_resume;; insnp++) {
KASSERT(insnp[0] != JR_RA);
if (insnp[0] == _LOAD_V0_L_PRIVATE_A0
&& insnp[1] == _MTC0_V0_USERLOCAL) {
insnp[0] = JR_RA;
insnp[1] = 0;
break;
}
}
}
mips_locore_jumpvec = mips32r2_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
mips_cp0_status_write(mips_cp0_status_read() & ~MIPS_SR_BEV);
mips_watchpoint_init();
}
#endif
#if defined(MIPS64)
static void
mips64_vector_init(const struct splsw *splsw)
{
extern char mips64_exception[];
extern char mips64_tlb_miss[];
extern char mips64_xtlb_miss[];
extern char mips64_cache[];
extern char mips64_intr[], mips64_intr_end[];
if (mips64_xtlb_miss - mips64_tlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"UTLB");
if (mips64_cache - mips64_xtlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"XTLB");
if (mips64_exception - mips64_cache != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"Cache error");
if (mips64_intr - mips64_exception != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"General exception");
if (mips64_intr_end - mips64_intr > 0x80)
panic("startup: %s vector code too large",
"interrupt exception");
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC, mips64_tlb_miss,
mips64_intr_end - mips64_tlb_miss);
mips_locore_jumpvec = mips64_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
mips_cp0_status_write(mips_cp0_status_read() & ~MIPS_SR_BEV);
mips_watchpoint_init();
}
#endif
#if defined(MIPS64R2)
void
mips64r2_vector_init(const struct splsw *splsw)
{
extern char mips64r2_exception[];
extern char mips64r2_tlb_miss[];
extern char mips64r2_xtlb_miss[];
extern char mips64r2_cache[];
extern char mips64r2_intr[], mips64r2_intr_end[];
if (mips64r2_xtlb_miss - mips64r2_tlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"UTLB");
if (mips64r2_cache - mips64r2_xtlb_miss != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"XTLB");
if (mips64r2_exception - mips64r2_cache != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"Cache error");
if (mips64r2_intr - mips64r2_exception != 0x80)
panic("startup: %s vector code not 128 bytes in length",
"General exception");
if (mips64r2_intr_end - mips64r2_intr > 0x80)
panic("startup: %s vector code too large",
"interrupt exception");
const intptr_t ebase = (intptr_t)mipsNN_cp0_ebase_read();
const int cpunum = ebase & MIPS_EBASE_CPUNUM;
memcpy((void *)(intptr_t)(ebase & ~MIPS_EBASE_CPUNUM), mips64r2_tlb_miss,
mips64r2_intr_end - mips64r2_tlb_miss);
if (mipsNN_cp0_config2_read() & MIPSNN_CFG2_M) {
const uint32_t cfg3 = mipsNN_cp0_config3_read();
if (cfg3 & MIPSNN_CFG3_ULRI) {
mips_options.mips_cpu_flags |= CPU_MIPS_HAVE_USERLOCAL;
}
if (cfg3 & MIPSNN_CFG3_DSP2P) {
mips_options.mips_cpu_flags |= CPU_MIPS_HAVE_DSP;
}
}
if (!MIPS_HAS_USERLOCAL && cpunum == 0) {
extern uint32_t mips64r2_cpu_switch_resume[];
for (uint32_t *insnp = mips64r2_cpu_switch_resume;; insnp++) {
KASSERT(insnp[0] != JR_RA);
if (insnp[0] == _LOAD_V0_L_PRIVATE_A0
&& insnp[1] == _MTC0_V0_USERLOCAL) {
insnp[0] = JR_RA;
insnp[1] = 0;
break;
}
}
}
if (cpunum == 0)
mips_locore_jumpvec = mips64r2_locore_vec;
mips_icache_sync_all();
mips_dcache_wbinv_all();
mips_cp0_status_write(mips_cp0_status_read() & ~MIPS_SR_BEV);
mips_watchpoint_init();
}
#endif
void
mips_vector_init(const struct splsw *splsw, bool multicpu_p)
{
struct mips_options * const opts = &mips_options;
const struct pridtab *ct;
const mips_prid_t cpu_id = opts->mips_cpu_id;
for (ct = cputab; ct->cpu_name != NULL; ct++) {
if (MIPS_PRID_CID(cpu_id) != ct->cpu_cid ||
MIPS_PRID_IMPL(cpu_id) != ct->cpu_pid)
continue;
if (ct->cpu_rev >= 0 &&
MIPS_PRID_REV(cpu_id) != ct->cpu_rev)
continue;
if (ct->cpu_copts >= 0 &&
MIPS_PRID_COPTS(cpu_id) != ct->cpu_copts)
continue;
opts->mips_cpu = ct;
opts->mips_cpu_arch = ct->cpu_isa;
opts->mips_num_tlb_entries = ct->cpu_ntlb;
break;
}
if (opts->mips_cpu == NULL)
panic("CPU type (0x%x) not supported", cpu_id);
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
if (MIPS_PRID_CID(cpu_id) != 0) {
uint32_t cfg, cfg1, cfg4;
cfg = mips3_cp0_config_read();
cfg1 = mipsNN_cp0_config1_read();
if (opts->mips_cpu->cpu_cp0flags & MIPS_CP0FL_CONFIG4)
cfg4 = mipsNN_cp0_config4_read();
else
cfg4 = 0;
switch (MIPSNN_GET(CFG_AT, cfg)) {
case MIPSNN_CFG_AT_MIPS32:
opts->mips_cpu_arch = CPU_ARCH_MIPS32;
break;
case MIPSNN_CFG_AT_MIPS64:
opts->mips_cpu_arch = CPU_ARCH_MIPS64;
break;
case MIPSNN_CFG_AT_MIPS64S:
default:
panic("MIPS32/64 architecture type %d not supported",
MIPSNN_GET(CFG_AT, cfg));
}
switch (MIPSNN_GET(CFG_AR, cfg)) {
case MIPSNN_CFG_AR_REV1:
break;
case MIPSNN_CFG_AR_REV2:
switch (opts->mips_cpu_arch) {
case CPU_ARCH_MIPS32:
opts->mips_cpu_arch = CPU_ARCH_MIPS32R2;
break;
case CPU_ARCH_MIPS64:
opts->mips_cpu_arch = CPU_ARCH_MIPS64R2;
break;
default:
printf("WARNING: MIPS32/64 arch %d revision %d "
"unknown!\n", opts->mips_cpu_arch,
MIPSNN_GET(CFG_AR, cfg));
break;
}
break;
default:
printf("WARNING: MIPS32/64 arch revision %d "
"unknown!\n", MIPSNN_GET(CFG_AR, cfg));
break;
}
switch (MIPSNN_GET(CFG_MT, cfg)) {
case MIPSNN_CFG_MT_TLB:
opts->mips_num_tlb_entries = MIPSNN_CFG1_MS(cfg1);
if (__SHIFTOUT(cfg4, MIPSNN_CFG4_MMU_EXT_DEF) ==
MIPSNN_CFG4_MMU_EXT_DEF_MMU) {
opts->mips_num_tlb_entries +=
__SHIFTOUT(cfg4, MIPSNN_CFG4_MMU_SIZE_EXT) <<
popcount(MIPSNN_CFG1_MS_MASK);
}
break;
case MIPSNN_CFG_MT_NONE:
case MIPSNN_CFG_MT_BAT:
case MIPSNN_CFG_MT_FIXED:
default:
panic("MIPS32/64 MMU type %d not supported",
MIPSNN_GET(CFG_MT, cfg));
}
}
#endif
if (opts->mips_cpu_arch < 1)
panic("Unknown CPU ISA for CPU type 0x%x", cpu_id);
if (opts->mips_num_tlb_entries < 1)
panic("Unknown number of TLBs for CPU type 0x%x", cpu_id);
opts->mips_cpu_flags = opts->mips_cpu->cpu_flags;
opts->mips_has_r4k_mmu = (opts->mips_cpu_flags & CPU_MIPS_R4K_MMU) != 0;
opts->mips_has_llsc = (opts->mips_cpu_flags & CPU_MIPS_NO_LLSC) == 0;
#if defined(MIPS3_4100)
if (MIPS_PRID_IMPL(cpu_id) == MIPS_R4100)
opts->mips3_pg_shift = MIPS3_4100_PG_SHIFT;
else
#endif
opts->mips3_pg_shift = MIPS3_DEFAULT_PG_SHIFT;
opts->mips3_cca_devmem = CCA_UNCACHED;
if (opts->mips_cpu_flags & CPU_MIPS_HAVE_SPECIAL_CCA) {
uint32_t cca;
cca = (opts->mips_cpu_flags & CPU_MIPS_CACHED_CCA_MASK) >>
CPU_MIPS_CACHED_CCA_SHIFT;
opts->mips3_pg_cached = MIPS3_CCA_TO_PG(cca);
#ifndef __mips_o32
opts->mips3_xkphys_cached = MIPS_PHYS_TO_XKPHYS(cca, 0);
#endif
} else {
opts->mips3_pg_cached = MIPS3_DEFAULT_PG_CACHED;
#ifndef __mips_o32
opts->mips3_xkphys_cached = MIPS3_DEFAULT_XKPHYS_CACHED;
#endif
}
#ifdef __HAVE_MIPS_MACHDEP_CACHE_CONFIG
mips_machdep_cache_config();
#endif
if (splsw == NULL) {
mips_splsw = std_splsw;
#ifdef PARANOIA
std_splsw_test();
#endif
} else {
mips_splsw = *splsw;
}
mips_config_cache();
#ifdef MULTIPROCESSOR
if (multicpu_p) {
mips_locore_atomicvec = mips_llsc_locore_atomicvec;
}
#endif
switch (opts->mips_cpu_arch) {
#if defined(MIPS1)
case CPU_ARCH_MIPS1:
(*mips1_locore_vec.ljv_tlb_invalidate_all)();
mips1_vector_init(splsw);
mips_locoresw = mips1_locoresw;
break;
#endif
#if defined(MIPS3)
case CPU_ARCH_MIPS3:
case CPU_ARCH_MIPS4:
mips3_tlb_probe();
#if defined(MIPS3_4100)
if (MIPS_PRID_IMPL(cpu_id) == MIPS_R4100)
mips3_cp0_pg_mask_write(MIPS4100_PG_SIZE_TO_MASK(PAGE_SIZE));
else
#endif
mips3_cp0_pg_mask_write(MIPS3_PG_SIZE_TO_MASK(PAGE_SIZE));
mips3_cp0_wired_write(0);
#if defined(MIPS3_LOONGSON2)
if (opts->mips_cpu_flags & CPU_MIPS_LOONGSON2) {
(*loongson2_locore_vec.ljv_tlb_invalidate_all)();
mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
loongson2_vector_init(splsw);
mips_locoresw = loongson2_locoresw;
opts->mips3_cca_devmem = CCA_ACCEL;
break;
}
#endif
(*mips3_locore_vec.ljv_tlb_invalidate_all)();
mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
mips3_vector_init(splsw);
mips_locoresw = mips3_locoresw;
break;
#endif
#if defined(MIPS32)
case CPU_ARCH_MIPS32:
mips3_tlb_probe();
mips3_cp0_pg_mask_write(MIPS3_PG_SIZE_TO_MASK(PAGE_SIZE));
mips3_cp0_wired_write(0);
(*mips32_locore_vec.ljv_tlb_invalidate_all)();
mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
mips32_vector_init(splsw);
mips_locoresw = mips32_locoresw;
break;
#endif
#if defined(MIPS32R2)
case CPU_ARCH_MIPS32R2:
mips3_tlb_probe();
mips3_cp0_pg_mask_write(MIPS3_PG_SIZE_TO_MASK(PAGE_SIZE));
mips3_cp0_wired_write(0);
(*mips32r2_locore_vec.ljv_tlb_invalidate_all)();
mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
mips32r2_vector_init(splsw);
mips_locoresw = mips32r2_locoresw;
break;
#endif
#if defined(MIPS64)
case CPU_ARCH_MIPS64: {
mips3_tlb_probe();
mips3_cp0_pg_mask_write(MIPS3_PG_SIZE_TO_MASK(PAGE_SIZE));
mips3_cp0_wired_write(0);
(*mips64_locore_vec.ljv_tlb_invalidate_all)();
mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
mips64_vector_init(splsw);
mips_locoresw = mips64_locoresw;
break;
}
#endif
#if defined(MIPS64R2)
case CPU_ARCH_MIPS64R2: {
mips3_tlb_probe();
mips3_cp0_pg_mask_write(MIPS3_PG_SIZE_TO_MASK(PAGE_SIZE));
mips3_cp0_wired_write(0);
(*mips64r2_locore_vec.ljv_tlb_invalidate_all)();
mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
mips64r2_vector_init(splsw);
mips_locoresw = mips64r2_locoresw;
break;
}
#endif
default:
printf("cpu_arch 0x%x: not supported\n", opts->mips_cpu_arch);
cpu_reboot(RB_HALT, NULL);
}
extern uint32_t _ftext[];
extern uint32_t _etext[];
mips_fixup_stubs(_ftext, _etext);
#if (MIPS3 + MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
if ((opts->mips_cpu_flags & CPU_MIPS_USE_WAIT) &&
!(opts->mips_cpu_flags & CPU_MIPS_NO_WAIT))
mips_locoresw.lsw_cpu_idle = mips_wait_idle;
#endif
}
void
mips_set_wbflush(void (*flush_fn)(void))
{
mips_locoresw.lsw_wbflush = flush_fn;
(*flush_fn)();
}
#if defined(MIPS3_PLUS)
static void
mips3_tlb_probe(void)
{
struct mips_options * const opts = &mips_options;
opts->mips3_tlb_pg_mask = mips3_cp0_tlb_page_mask_probe();
if (CPUIS64BITS) {
opts->mips3_tlb_vpn_mask = mips3_cp0_tlb_entry_hi_probe();
opts->mips3_tlb_vpn_mask |= PAGE_MASK;
opts->mips3_tlb_vpn_mask <<= 2;
opts->mips3_tlb_vpn_mask >>= 2;
opts->mips3_tlb_pfn_mask = mips3_cp0_tlb_entry_lo_probe();
#if defined(_LP64) && defined(ENABLE_MIPS_16KB_PAGE)
if (mips_vm_maxuser_address > opts->mips3_tlb_vpn_mask + 1)
mips_vm_maxuser_address = opts->mips3_tlb_vpn_mask + 1;
#endif
}
}
#endif
static const char *
wayname(int ways)
{
static char buf[sizeof("xxx-way set-associative")];
#ifdef DIAGNOSTIC
if (ways > 999)
panic("mips cache - too many ways (%d)", ways);
#endif
switch (ways) {
case 0:
return "fully set-associative";
case 1:
return "direct-mapped";
default:
snprintf(buf, sizeof(buf), "%d-way set-associative", ways);
return buf;
}
}
void
cpu_identify(device_t dev)
{
const struct mips_options * const opts = &mips_options;
const struct mips_cache_info * const mci = &mips_cache_info;
const mips_prid_t cpu_id = opts->mips_cpu_id;
const mips_prid_t fpu_id = opts->mips_fpu_id;
static const char * const wtnames[] = {
"write-back",
"write-through",
};
const char *cpuname, *fpuname;
int i;
cpuname = opts->mips_cpu->cpu_name;
#ifdef MIPS64_OCTEON
if (MIPS_PRID_CID(cpu_id) == MIPS_PRID_CID_CAVIUM) {
cpuname = octeon_cpu_model(cpu_id);
}
#endif
fpuname = NULL;
for (i = 0; i < sizeof(fputab)/sizeof(fputab[0]); i++) {
if (MIPS_PRID_CID(fpu_id) == fputab[i].cpu_cid &&
MIPS_PRID_IMPL(fpu_id) == fputab[i].cpu_pid) {
fpuname = fputab[i].cpu_name;
break;
}
}
if (fpuname == NULL && MIPS_PRID_IMPL(fpu_id) == MIPS_PRID_IMPL(cpu_id))
fpuname = "built-in FPU";
if (MIPS_PRID_IMPL(cpu_id) == MIPS_R4700)
fpuname = "built-in FPU";
if (MIPS_PRID_IMPL(cpu_id) == MIPS_RC64470)
fpuname = "built-in FPU";
#ifdef MIPSNN
if (CPUISMIPSNN) {
uint32_t cfg1;
switch (MIPS_PRID_CID(cpu_id)) {
case MIPS_PRID_CID_SIBYTE:
case MIPS_PRID_CID_CAVIUM:
cfg1 = mipsNN_cp0_config1_read();
if (cfg1 & MIPSNN_CFG1_FP)
fpuname = "built-in FPU";
break;
}
}
#endif
if (opts->mips_cpu->cpu_cid != 0) {
if (opts->mips_cpu->cpu_cid <= ncidnames)
aprint_normal("%s ", cidnames[opts->mips_cpu->cpu_cid]);
else if (opts->mips_cpu->cpu_cid == MIPS_PRID_CID_INGENIC) {
aprint_normal("Ingenic ");
} else {
aprint_normal("Unknown Company ID - 0x%x",
opts->mips_cpu->cpu_cid);
aprint_normal_dev(dev, "");
}
}
if (cpuname != NULL)
aprint_normal("%s (0x%x)", cpuname, cpu_id);
else
aprint_normal("unknown CPU type (0x%x)", cpu_id);
if (MIPS_PRID_CID(cpu_id) == MIPS_PRID_CID_PREHISTORIC)
aprint_normal(" Rev. %d.%d", MIPS_PRID_REV_MAJ(cpu_id),
MIPS_PRID_REV_MIN(cpu_id));
else
aprint_normal(" Rev. %d", MIPS_PRID_REV(cpu_id));
if (fpuname != NULL)
aprint_normal(" with %s", fpuname);
else
aprint_normal(" with unknown FPC type (0x%x)", fpu_id);
if (opts->mips_fpu_id != 0) {
if (MIPS_PRID_CID(cpu_id) == MIPS_PRID_CID_PREHISTORIC)
aprint_normal(" Rev. %d.%d", MIPS_PRID_REV_MAJ(fpu_id),
MIPS_PRID_REV_MIN(fpu_id));
else
aprint_normal(" Rev. %d", MIPS_PRID_REV(fpu_id));
}
if (opts->mips_cpu_flags & MIPS_HAS_DSP) {
aprint_normal(" and DSPv2");
}
aprint_normal("\n");
if (MIPS_PRID_CID(cpu_id) == MIPS_PRID_CID_PREHISTORIC &&
MIPS_PRID_RSVD(cpu_id) != 0) {
aprint_normal_dev(dev,
"NOTE: top 8 bits of prehistoric PRID not 0!\n");
aprint_normal_dev(dev, "Please mail port-mips@NetBSD.org "
"with %s dmesg lines.\n", device_xname(dev));
}
switch (opts->mips_cpu_arch) {
#if defined(MIPS1)
case CPU_ARCH_MIPS1:
if (mci->mci_picache_size)
aprint_normal_dev(dev, "%dKB/%dB %s Instruction cache, "
"%d TLB entries\n", mci->mci_picache_size / 1024,
mci->mci_picache_line_size,
wayname(mci->mci_picache_ways),
opts->mips_num_tlb_entries);
else
aprint_normal_dev(dev, "%d TLB entries\n",
opts->mips_num_tlb_entries);
if (mci->mci_pdcache_size)
aprint_normal_dev(dev, "%dKB/%dB %s %s Data cache\n",
mci->mci_pdcache_size / 1024,
mci->mci_pdcache_line_size,
wayname(mci->mci_pdcache_ways),
wtnames[mci->mci_pdcache_write_through]);
break;
#endif
#if (MIPS3 + MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
case CPU_ARCH_MIPS3:
case CPU_ARCH_MIPS4:
case CPU_ARCH_MIPS32:
case CPU_ARCH_MIPS32R2:
case CPU_ARCH_MIPS64:
case CPU_ARCH_MIPS64R2: {
const char *sufx = "KMGTPE";
uint32_t pg_mask;
aprint_normal_dev(dev, "%d TLB entries",
opts->mips_num_tlb_entries);
#if !defined(__mips_o32)
if (CPUIS64BITS) {
int64_t pfn_mask;
i = ffs(~(opts->mips3_tlb_vpn_mask >> 31)) + 30;
aprint_normal(", %d%cB (%d-bit) VAs",
1 << (i % 10), sufx[(i / 10) - 1], i);
for (i = 64, pfn_mask = opts->mips3_tlb_pfn_mask << 6;
pfn_mask > 0; i--, pfn_mask <<= 1)
;
aprint_normal(", %d%cB (%d-bit) PAs",
1 << (i % 10), sufx[(i / 10) - 1], i);
}
#endif
for (i = 4, pg_mask = opts->mips3_tlb_pg_mask >> 13;
pg_mask != 0; ) {
if ((pg_mask & 3) != 3)
break;
pg_mask >>= 2;
i *= 4;
if (i == 1024) {
i = 1;
sufx++;
}
}
aprint_normal(", %d%cB max page size\n", i, sufx[0]);
if (mci->mci_picache_size)
aprint_normal_dev(dev,
"%dKB/%dB %s L1 instruction cache\n",
mci->mci_picache_size / 1024,
mci->mci_picache_line_size,
wayname(mci->mci_picache_ways));
if (mci->mci_pdcache_size)
aprint_normal_dev(dev,
"%dKB/%dB %s %s %sL1 data cache\n",
mci->mci_pdcache_size / 1024,
mci->mci_pdcache_line_size,
wayname(mci->mci_pdcache_ways),
wtnames[mci->mci_pdcache_write_through],
((opts->mips_cpu_flags & CPU_MIPS_D_CACHE_COHERENT)
? "coherent " : ""));
if (mci->mci_sdcache_line_size)
aprint_normal_dev(dev,
"%dKB/%dB %s %s L2 %s cache\n",
mci->mci_sdcache_size / 1024,
mci->mci_sdcache_line_size,
wayname(mci->mci_sdcache_ways),
wtnames[mci->mci_sdcache_write_through],
mci->mci_scache_unified ? "unified" : "data");
break;
}
#endif
default:
panic("cpu_identify: impossible");
}
}
void
setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
{
struct trapframe * const tf = l->l_md.md_utf;
struct proc * const p = l->l_proc;
KASSERTMSG((stack & STACK_ALIGNBYTES) == 0, "stack=%"PRIxVADDR, stack);
memset(tf, 0, sizeof(*tf));
tf->tf_regs[_R_SP] = (intptr_t)stack & ~STACK_ALIGNBYTES;
tf->tf_regs[_R_PC] = (intptr_t)pack->ep_entry & ~3;
tf->tf_regs[_R_T9] = (intptr_t)pack->ep_entry & ~3;
tf->tf_regs[_R_SR] = PSL_USERSET;
#if !defined(__mips_o32)
if (p->p_md.md_abi == _MIPS_BSD_API_N32
&& (CPUISMIPS64 || CPUISMIPS64R2)) {
tf->tf_regs[_R_SR] |= MIPS_SR_PX;
} else if (p->p_md.md_abi != _MIPS_BSD_API_O32) {
tf->tf_regs[_R_SR] |= MIPS_SR_UX;
}
if (_MIPS_SIM_NEWABI_P(p->p_md.md_abi))
tf->tf_regs[_R_SR] |= MIPS3_SR_FR;
#endif
#ifdef _LP64
if (p->p_md.md_abi == _MIPS_BSD_API_N32
|| p->p_md.md_abi == _MIPS_BSD_API_O32) {
p->p_flag |= PK_32;
} else {
p->p_flag &= ~PK_32;
}
#endif
tf->tf_regs[_R_A0] = (intptr_t)stack;
tf->tf_regs[_R_A1] = 0;
tf->tf_regs[_R_A2] = 0;
tf->tf_regs[_R_A3] = p->p_psstrp;
l->l_md.md_ss_addr = 0;
}
#ifdef __HAVE_BOOTINFO_H
static int
sysctl_machdep_booted_kernel(SYSCTLFN_ARGS)
{
struct btinfo_bootpath *bibp;
struct sysctlnode node;
bibp = lookup_bootinfo(BTINFO_BOOTPATH);
if(!bibp)
return(ENOENT);
node = *rnode;
node.sysctl_data = bibp->bootpath;
node.sysctl_size = sizeof(bibp->bootpath);
return (sysctl_lookup(SYSCTLFN_CALL(&node)));
}
#endif
SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
{
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "machdep", NULL,
NULL, 0, NULL, 0,
CTL_MACHDEP, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRUCT, "console_device", NULL,
sysctl_consdev, 0, NULL, sizeof(dev_t),
CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
#ifdef __HAVE_BOOTINFO_H
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "booted_kernel", NULL,
sysctl_machdep_booted_kernel, 0, NULL, 0,
CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL);
#endif
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "root_device", NULL,
sysctl_root_device, 0, NULL, 0,
CTL_MACHDEP, CPU_ROOT_DEVICE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
CTLTYPE_INT, "llsc", NULL,
NULL, MIPS_HAS_LLSC, NULL, 0,
CTL_MACHDEP, CPU_LLSC, CTL_EOL);
#ifdef MIPS3_LOONGSON2
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
CTLTYPE_INT, "loongson-mmi", NULL,
NULL, MIPS_HAS_LMMI, NULL, 0,
CTL_MACHDEP, CPU_LMMI, CTL_EOL);
#endif
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
CTLTYPE_INT, "fpu_present", NULL,
NULL,
#ifdef NOFPU
0,
#else
1,
#endif
NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL);
}
extern phys_ram_seg_t mem_clusters[];
extern int mem_cluster_cnt;
u_int32_t dumpmag = 0x8fca0101;
int dumpsize = 0;
long dumplo = 0;
struct pcb dumppcb;
int
cpu_dumpsize(void)
{
int size;
size = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)) +
ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t));
if (roundup(size, dbtob(1)) != dbtob(1))
return (-1);
return (1);
}
u_long
cpu_dump_mempagecnt(void)
{
u_long i, n;
n = 0;
for (i = 0; i < mem_cluster_cnt; i++)
n += atop(mem_clusters[i].size);
return (n);
}
int
cpu_dump(void)
{
int (*dump)(dev_t, daddr_t, void *, size_t);
char buf[dbtob(1)];
kcore_seg_t *segp;
cpu_kcore_hdr_t *cpuhdrp;
phys_ram_seg_t *memsegp;
const struct bdevsw *bdev;
int i;
bdev = bdevsw_lookup(dumpdev);
if (bdev == NULL)
return (ENXIO);
dump = bdev->d_dump;
memset(buf, 0, sizeof buf);
segp = (kcore_seg_t *)buf;
cpuhdrp = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(*segp))];
memsegp = (phys_ram_seg_t *)&buf[ ALIGN(sizeof(*segp)) +
ALIGN(sizeof(*cpuhdrp))];
CORE_SETMAGIC(*segp, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
segp->c_size = dbtob(1) - ALIGN(sizeof(*segp));
if (MIPS_HAS_R4K_MMU) {
cpuhdrp->archlevel = 3;
cpuhdrp->pg_shift = MIPS3_PG_SHIFT;
cpuhdrp->pg_frame = MIPS3_PG_FRAME;
cpuhdrp->pg_v = MIPS3_PG_V;
} else {
cpuhdrp->archlevel = 1;
cpuhdrp->pg_shift = MIPS1_PG_SHIFT;
cpuhdrp->pg_frame = MIPS1_PG_FRAME;
cpuhdrp->pg_v = MIPS1_PG_V;
}
cpuhdrp->sysmappa = MIPS_KSEG0_TO_PHYS(curcpu()->ci_pmap_kern_segtab);
cpuhdrp->nmemsegs = mem_cluster_cnt;
for (i = 0; i < mem_cluster_cnt; i++) {
memsegp[i].start = mem_clusters[i].start;
memsegp[i].size = mem_clusters[i].size;
}
return (dump(dumpdev, dumplo, (void *)buf, dbtob(1)));
}
void
cpu_dumpconf(void)
{
int nblks, dumpblks;
if (dumpdev == NODEV)
goto bad;
nblks = bdev_size(dumpdev);
if (nblks <= ctod(1))
goto bad;
dumpblks = cpu_dumpsize();
if (dumpblks < 0)
goto bad;
dumpblks += ctod(cpu_dump_mempagecnt());
if (dumpblks > (nblks - ctod(1)))
goto bad;
dumplo = nblks - dumpblks;
dumpsize = cpu_dump_mempagecnt();
return;
bad:
dumpsize = 0;
}
#define BYTES_PER_DUMP PAGE_SIZE
void
dumpsys(void)
{
u_long totalbytesleft, bytes, i, n, memcl;
u_long maddr;
int psize;
daddr_t blkno;
const struct bdevsw *bdev;
int (*dump)(dev_t, daddr_t, void *, size_t);
int error;
savectx(&dumppcb);
if (dumpdev == NODEV)
return;
bdev = bdevsw_lookup(dumpdev);
if (bdev == NULL || bdev->d_psize == NULL)
return;
if (dumpsize == 0)
cpu_dumpconf();
if (dumplo <= 0) {
printf("\ndump to dev %u,%u not possible\n", major(dumpdev),
minor(dumpdev));
return;
}
printf("\ndumping to dev %u,%u offset %ld\n", major(dumpdev),
minor(dumpdev), dumplo);
psize = bdev_size(dumpdev);
printf("dump ");
if (psize == -1) {
printf("area unavailable\n");
return;
}
if ((error = cpu_dump()) != 0)
goto err;
totalbytesleft = ptoa(cpu_dump_mempagecnt());
blkno = dumplo + cpu_dumpsize();
dump = bdev->d_dump;
error = 0;
for (memcl = 0; memcl < mem_cluster_cnt; memcl++) {
maddr = mem_clusters[memcl].start;
bytes = mem_clusters[memcl].size;
for (i = 0; i < bytes; i += n, totalbytesleft -= n) {
void *maddr_va;
if ((totalbytesleft % (1024*1024)) == 0)
printf_nolog("%ld ",
totalbytesleft / (1024 * 1024));
n = bytes - i;
if (n > BYTES_PER_DUMP)
n = BYTES_PER_DUMP;
#ifdef _LP64
maddr_va = (void *)MIPS_PHYS_TO_XKPHYS_CACHED(maddr);
#else
maddr_va = (void *)MIPS_PHYS_TO_KSEG0(maddr);
#endif
error = (*dump)(dumpdev, blkno, maddr_va, n);
if (error)
goto err;
maddr += n;
blkno += btodb(n);
}
}
err:
switch (error) {
case ENXIO:
printf("device bad\n");
break;
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("area improper\n");
break;
case EIO:
printf("i/o error\n");
break;
case EINTR:
printf("aborted from console\n");
break;
case 0:
printf("succeeded\n");
break;
default:
printf("error %d\n", error);
break;
}
printf("\n\n");
delay(5000000);
}
void
mips_init_msgbuf(void)
{
vsize_t sz = (vsize_t)round_page(MSGBUFSIZE);
vsize_t reqsz = sz;
uvm_physseg_t bank = uvm_physseg_get_last();
#ifndef _LP64
for (; uvm_physseg_valid_p(bank); bank = uvm_physseg_get_prev(bank)) {
if (uvm_physseg_get_avail_start(bank) + atop(sz) <= atop(MIPS_PHYS_MASK))
break;
}
#endif
paddr_t start = uvm_physseg_get_start(bank);
paddr_t end = uvm_physseg_get_end(bank);
if ((end - start) < atop(sz))
sz = ptoa(end - start);
end -= atop(sz);
uvm_physseg_unplug(end, atop(sz));
#ifdef _LP64
msgbufaddr = (void *) MIPS_PHYS_TO_XKPHYS_CACHED(ptoa(end));
#else
msgbufaddr = (void *) MIPS_PHYS_TO_KSEG0(ptoa(end));
#endif
initmsgbuf(msgbufaddr, sz);
if (sz != reqsz)
printf("WARNING: %"PRIdVSIZE" bytes not available for msgbuf "
"in last cluster (%"PRIdVSIZE" used)\n", reqsz, sz);
}
void
mips_init_lwp0_uarea(void)
{
struct lwp * const l = &lwp0;
vaddr_t v;
if (l->l_addr == NULL) {
v = uvm_pageboot_alloc(USPACE);
uvm_lwp_setuarea(&lwp0, v);
} else {
v = (vaddr_t)l->l_addr;
}
l->l_md.md_utf = (struct trapframe *)(v + USPACE) - 1;
struct pcb * const pcb = lwp_getpcb(l);
memset(l->l_md.md_utf, 0, sizeof(*l->l_md.md_utf));
memset(pcb, 0, sizeof(*pcb));
pcb->pcb_context.val[_L_SR] = MIPS_SR_INT_IE
| (ipl_sr_map.sr_bits[IPL_SCHED] ^ MIPS_INT_MASK);
#ifdef __mips_n32
pcb->pcb_context.val[_L_SR] |= MIPS_SR_KX;
l->l_md.md_utf->tf_regs[_R_SR] = MIPS_SR_KX;
#endif
#ifdef _LP64
pcb->pcb_context.val[_L_SR] |= MIPS_SR_KX | MIPS_SR_UX;
l->l_md.md_utf->tf_regs[_R_SR] = MIPS_SR_KX | MIPS_SR_UX;
#endif
}
int mips_poolpage_vmfreelist = VM_FREELIST_DEFAULT;
#define HALFGIG ((paddr_t)512 * 1024 * 1024)
#define FOURGIG ((paddr_t)4 * 1024 * 1024 * 1024)
void
mips_page_physload(vaddr_t vkernstart, vaddr_t vkernend,
const phys_ram_seg_t *segs, size_t nseg,
const struct mips_vmfreelist *flp, size_t nfl)
{
const paddr_t kernstart = MIPS_KSEG0_TO_PHYS(trunc_page(vkernstart));
const paddr_t kernend = MIPS_KSEG0_TO_PHYS(round_page(vkernend));
#if defined(VM_FREELIST_FIRST4G) || defined(VM_FREELIST_FIRST512M)
#ifdef VM_FREELIST_FIRST512M
bool need512m = false;
#endif
#ifdef VM_FREELIST_FIRST4G
bool need4g = false;
#endif
for (size_t i = 0; i < nseg; i++) {
#ifdef VM_FREELIST_FIRST4G
if (round_page(segs[i].start + segs[i].size) > FOURGIG) {
need4g = true;
}
#endif
#ifdef VM_FREELIST_FIRST512M
if (round_page(segs[i].start + segs[i].size) > HALFGIG) {
need512m = true;
#if !defined(_LP64)
mips_poolpage_vmfreelist = VM_FREELIST_FIRST512M;
#endif
}
#endif
}
#endif
for (; nseg-- > 0; segs++) {
paddr_t segstart = round_page(segs->start);
const paddr_t segfinish = trunc_page(segs->start + segs->size);
if (segstart >= segfinish) {
printf("phys segment: %#"PRIxPADDR" @ %#"PRIxPADDR
" (short)\n", (paddr_t)segs->size, segstart);
continue;
}
printf("phys segment: %#"PRIxPADDR" @ %#"PRIxPADDR"\n",
segfinish - segstart, segstart);
if (segstart == 0) {
segstart = PAGE_SIZE;
}
while (segstart < segfinish) {
int freelist = -1;
paddr_t segend = segfinish;
for (size_t i = 0; i < nfl; i++) {
if (segstart >= flp[i].fl_end
|| segend <= flp[i].fl_start)
continue;
if (segstart < flp[i].fl_start) {
segstart = flp[i].fl_start;
break;
}
freelist = flp->fl_freelist;
if (segend > flp[i].fl_end)
segend = flp[i].fl_end;
break;
}
if (freelist == -1) {
#ifdef VM_FREELIST_FIRST512M
if (need512m && segstart < HALFGIG) {
freelist = VM_FREELIST_FIRST512M;
if (segend > HALFGIG)
segend = HALFGIG;
} else
#endif
#ifdef VM_FREELIST_FIRST4G
if (need4g && segstart < FOURGIG) {
freelist = VM_FREELIST_FIRST4G;
if (segend > FOURGIG)
segend = FOURGIG;
} else
#endif
freelist = VM_FREELIST_DEFAULT;
}
if (segstart < kernend && segend > kernstart) {
if (segstart < kernstart) {
segend = kernstart;
} else if (segend > kernend) {
segstart = kernend;
} else {
printf("skipping %#"PRIxPADDR" @ %#"PRIxPADDR" (kernel)\n",
segend - segstart, segstart);
break;
}
}
printf("adding %#"PRIxPADDR" @ %#"PRIxPADDR" to freelist %d\n",
segend - segstart, segstart, freelist);
paddr_t first = atop(segstart);
paddr_t last = atop(segend);
uvm_page_physload(first, last, first, last, freelist);
segstart = segend;
}
}
}
void
startlwp(void *arg)
{
ucontext_t * const uc = arg;
lwp_t * const l = curlwp;
int error __diagused;
error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
KASSERT(error == 0);
kmem_free(uc, sizeof(ucontext_t));
userret(l);
}
#ifdef COMPAT_NETBSD32
void
startlwp32(void *arg)
{
ucontext32_t * const uc = arg;
lwp_t * const l = curlwp;
int error __diagused;
error = cpu_setmcontext32(l, &uc->uc_mcontext, uc->uc_flags);
KASSERT(error == 0);
kmem_free(uc, sizeof(ucontext_t));
userret(l);
}
#endif
#ifdef PARANOIA
void
std_splsw_test(void)
{
struct cpu_info * const ci = curcpu();
const uint32_t * const sr_map = ipl_sr_map.sr_bits;
uint32_t status = mips_cp0_status_read();
uint32_t sr_bits;
int s;
KASSERT((status & MIPS_SR_INT_IE) == 0);
sr_bits = sr_map[IPL_NONE];
splx(IPL_NONE);
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT(status == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_NONE);
s = splsoftclock();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_SOFTCLOCK]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_SOFTCLOCK);
KASSERT(s == IPL_NONE);
s = splsoftbio();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_SOFTBIO]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_SOFTBIO);
KASSERT(s == IPL_SOFTCLOCK);
s = splsoftnet();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_SOFTNET]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_SOFTNET);
KASSERT(s == IPL_SOFTBIO);
s = splsoftserial();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_SOFTSERIAL]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_SOFTSERIAL);
KASSERT(s == IPL_SOFTNET);
s = splvm();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_VM]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_VM);
KASSERT(s == IPL_SOFTSERIAL);
s = splsched();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_SCHED]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_SCHED);
KASSERT(s == IPL_VM);
s = splhigh();
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[IPL_HIGH]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_HIGH);
KASSERT(s == IPL_SCHED);
splx(IPL_NONE);
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT(status == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_NONE);
for (int r = IPL_SOFTCLOCK; r <= IPL_HIGH; r++) {
KASSERT((sr_map[r] & sr_bits) == sr_bits);
sr_bits |= sr_map[r];
s = splraise(r);
KASSERT(s == IPL_NONE);
for (int t = r; t <= IPL_HIGH; t++) {
int o = splraise(t);
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[t]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == t);
KASSERT(o == r);
splx(o);
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[r]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == r);
}
splx(s);
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT((status ^ sr_map[s]) == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == s);
}
status = mips_cp0_status_read() & MIPS_INT_MASK;
KASSERT(status == MIPS_INT_MASK);
KASSERT(ci->ci_cpl == IPL_NONE);
}
#endif
bool
mm_md_direct_mapped_phys(paddr_t pa, vaddr_t *vap)
{
#ifdef _LP64
if (MIPS_XKSEG_P(pa)) {
*vap = MIPS_PHYS_TO_XKPHYS_CACHED(pa);
return true;
}
#endif
if (MIPS_KSEG0_P(pa)) {
*vap = MIPS_PHYS_TO_KSEG0(pa);
return true;
}
return false;
}
bool
mm_md_page_color(paddr_t pa, int *colorp)
{
if (MIPS_CACHE_VIRTUAL_ALIAS) {
struct vm_page * const pg = PHYS_TO_VM_PAGE(pa);
KASSERT(pg != NULL);
struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg);
*colorp = atop(mdpg->mdpg_first.pv_va);
return !mips_cache_badalias(pa, mdpg->mdpg_first.pv_va);
}
*colorp = 0;
return true;
}
int
mm_md_physacc(paddr_t pa, vm_prot_t prot)
{
return (pa < ctob(physmem)) ? 0 : EFAULT;
}
int
mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled)
{
const vaddr_t v = (vaddr_t)ptr;
#ifdef _LP64
extern char end[];
if (v < MIPS_PHYS_TO_XKPHYS_CACHED(0)) {
return EFAULT;
}
if (v < MIPS_PHYS_TO_XKPHYS_CACHED(pmap_limits.avail_end +
mips_round_page(MSGBUFSIZE))) {
*handled = true;
return 0;
}
if (MIPS_KSEG0_P(v) && v < (vaddr_t)end) {
*handled = true;
return 0;
}
#else
if (v < MIPS_KSEG0_START) {
return EFAULT;
}
if (v < MIPS_PHYS_TO_KSEG0(pmap_limits.avail_end +
mips_round_page(MSGBUFSIZE))) {
*handled = true;
return 0;
}
if (v < MIPS_KSEG2_START) {
return EFAULT;
}
#endif
*handled = false;
return 0;
}
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
static void
mips_watchpoint_init(void)
{
curcpu()->ci_cpuwatch_count = cpuwatch_discover();
}
#endif
void
cpu_spawn_return(struct lwp *l)
{
userret(l);
}