diff options
Diffstat (limited to 'sys/arch/mips64')
-rw-r--r-- | sys/arch/mips64/conf/files.mips64 | 14 | ||||
-rw-r--r-- | sys/arch/mips64/include/asm.h | 35 | ||||
-rw-r--r-- | sys/arch/mips64/include/cache.h | 9 | ||||
-rw-r--r-- | sys/arch/mips64/include/cpu.h | 77 | ||||
-rw-r--r-- | sys/arch/mips64/include/mips_opcode.h | 3 | ||||
-rw-r--r-- | sys/arch/mips64/include/pte.h | 29 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cache_tfp.c | 194 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cache_tfp_subr.S | 98 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/context.S | 17 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cp0access.S | 24 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cpu.c | 9 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/db_disasm.c | 55 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/db_machdep.c | 108 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/exception_tfp.S | 409 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/lcore_access.S | 44 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/mips64_machdep.c | 25 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/pmap.c | 21 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/tlb_tfp.S | 297 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/tlbhandler.S | 11 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/trap.c | 146 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/vm_machdep.c | 4 |
21 files changed, 1489 insertions, 140 deletions
diff --git a/sys/arch/mips64/conf/files.mips64 b/sys/arch/mips64/conf/files.mips64 index d49a3c47652..f9540f1f7ef 100644 --- a/sys/arch/mips64/conf/files.mips64 +++ b/sys/arch/mips64/conf/files.mips64 @@ -1,7 +1,7 @@ -# $OpenBSD: files.mips64,v 1.20 2012/06/23 21:56:06 miod Exp $ +# $OpenBSD: files.mips64,v 1.21 2012/09/29 21:37:01 miod Exp $ file arch/mips64/mips64/arcbios.c arcbios -file arch/mips64/mips64/clock.c +file arch/mips64/mips64/clock.c clock file arch/mips64/mips64/cpu.c file arch/mips64/mips64/interrupt.c file arch/mips64/mips64/mem.c @@ -15,17 +15,21 @@ file arch/mips64/mips64/trap.c file arch/mips64/mips64/vm_machdep.c file arch/mips64/mips64/cache_loongson2.c cpu_loongson2 +file arch/mips64/mips64/cache_octeon.c cpu_octeon file arch/mips64/mips64/cache_r4k.c cpu_r4000 file arch/mips64/mips64/cache_r5k.c cpu_r5000 | cpu_rm7000 file arch/mips64/mips64/cache_r10k.c cpu_r10000 -file arch/mips64/mips64/cache_octeon.c cpu_octeon +file arch/mips64/mips64/cache_tfp.c cpu_r8000 +file arch/mips64/mips64/cache_tfp_subr.S cpu_r8000 file arch/mips64/mips64/context.S file arch/mips64/mips64/cp0access.S -file arch/mips64/mips64/exception.S +file arch/mips64/mips64/exception.S !cpu_r8000 +file arch/mips64/mips64/exception_tfp.S cpu_r8000 file arch/mips64/mips64/fp_emulate.c file arch/mips64/mips64/lcore_access.S file arch/mips64/mips64/lcore_float.S -file arch/mips64/mips64/tlbhandler.S +file arch/mips64/mips64/tlbhandler.S !cpu_r8000 +file arch/mips64/mips64/tlb_tfp.S cpu_r8000 file arch/mips64/mips64/db_disasm.c ddb file arch/mips64/mips64/db_machdep.c ddb diff --git a/sys/arch/mips64/include/asm.h b/sys/arch/mips64/include/asm.h index 8de2128eb92..127ad53528b 100644 --- a/sys/arch/mips64/include/asm.h +++ b/sys/arch/mips64/include/asm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: asm.h,v 1.17 2012/09/29 19:02:25 miod Exp $ */ +/* $OpenBSD: asm.h,v 1.18 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2001-2002 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -174,12 +174,29 @@ #define PTR_VAL .dword #endif +/* + * The following macros are here to benefit the R8000 processor: + * - all coprocessor 0 control registers are 64-bit + * - the regular nop (sll zero, zero, 0) has the drawback of using the + * shifter, potentially breaking instruction dispatch if occuring after + * another instruction using the shifter. + */ +#ifdef CPU_R8000 +#define SSNOP sll zero, zero, 1 /* ``ssnop'' */ +#define NOP PTR_ADDU zero, zero, zero /* real nop for R8000 */ +#define DMFC0 SSNOP; dmfc0 +#define DMTC0 SSNOP; dmtc0 +#define MFC0 SSNOP; dmfc0 +#define MTC0 SSNOP; dmtc0 +#define ERET eret; mul k0, k0; mflo k0 +#else #define NOP nop #define DMFC0 dmfc0 #define DMTC0 dmtc0 #define MFC0 mfc0 #define MTC0 mtc0 #define ERET sync; eret +#endif /* * Define -pg profile entry code. @@ -330,6 +347,22 @@ x: ; \ #define TLB_HAZARD NOP; NOP; NOP; NOP #endif +#ifdef CPU_R8000 +/* + * The R8000 needs a lot of care inserting proper superscalar dispatch breaks + * to prevent unwanted side-effects or avoid collisions on the internal MiscBus + * and the E and W stages of the pipelines. + * + * The following settings are a bit pessimistic, but better run safely than + * not at all. + */ +#define PRE_MFC0_ADDR_HAZARD .align 5; SSNOP +#define MFC0_HAZARD SSNOP +#define MTC0_HAZARD SSNOP; SSNOP; SSNOP +#define MTC0_SR_IE_HAZARD MTC0_HAZARD; SSNOP +#define MTC0_SR_CU_HAZARD MTC0_HAZARD; SSNOP +#endif + /* Hazard between {d,}mfc0 of COP_0_VADDR */ #ifndef PRE_MFC0_ADDR_HAZARD #define PRE_MFC0_ADDR_HAZARD /* nothing */ diff --git a/sys/arch/mips64/include/cache.h b/sys/arch/mips64/include/cache.h index 300b6b4d00f..7942cd9838b 100644 --- a/sys/arch/mips64/include/cache.h +++ b/sys/arch/mips64/include/cache.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cache.h,v 1.4 2012/06/24 20:20:37 miod Exp $ */ +/* $OpenBSD: cache.h,v 1.5 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2012 Miodrag Vallat. @@ -66,6 +66,11 @@ CACHE_PROTOS(Mips4k) CACHE_PROTOS(Mips5k) /* + * MIPS (SGI, really) R8000. + */ +CACHE_PROTOS(tfp) + +/* * MIPS/NEC R10000/R120000/R140000/R16000. */ CACHE_PROTOS(Mips10k) @@ -75,7 +80,7 @@ CACHE_PROTOS(Mips10k) * bus_dmamap_sync()]. */ #define CACHE_SYNC_R 0 /* WB invalidate, WT invalidate */ -#define CACHE_SYNC_W 1 /* WB writeback + invalidate, WT unaffected */ +#define CACHE_SYNC_W 1 /* WB writeback, WT unaffected */ #define CACHE_SYNC_X 2 /* WB writeback + invalidate, WT invalidate */ extern vaddr_t cache_valias_mask; diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h index 8ca4a8fe90b..7e7a17e89d1 100644 --- a/sys/arch/mips64/include/cpu.h +++ b/sys/arch/mips64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.88 2012/09/29 19:42:30 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.89 2012/09/29 21:37:03 miod Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -149,16 +149,37 @@ #define SR_INT_MASK_4 0x00004000 #define SR_INT_MASK_5 0x00008000 +/* R8000-specific bits */ +#define SR_SERIALIZE_FPU 0x0000010000000000 +#define SR_KPGSZ_SHIFT 36 +#define SR_UPGSZ_SHIFT 32 +#define SR_PGSZ_4K 0 +#define SR_PGSZ_8K 1 +#define SR_PGSZ_16K 2 +#define SR_PGSZ_64K 3 +#define SR_PGSZ_1M 4 +#define SR_PGSZ_4M 5 +#define SR_PGSZ_16M 6 +#define SR_PGSZ_MASK 0x0f + #define SR_INT_MASK_6 0x00010000 #define SR_INT_MASK_7 0x00020000 #define SR_INT_MASK_8 0x00040000 +#ifdef CPU_R8000 +#define SR_XX 0x00000040 +#define SR_KSU_MASK 0x00000010 +#define SR_KSU_USER 0x00000010 +#define SR_KSU_KERNEL 0x00000000 +#define SR_INT_MASK 0x0007ff00 +#else #define SR_XX 0x80000000 #define SR_KSU_MASK 0x00000018 #define SR_KSU_USER 0x00000010 #define SR_KSU_SUPER 0x00000008 #define SR_KSU_KERNEL 0x00000000 #define SR_INT_MASK 0x0000ff00 +#endif /* * Interrupt control register in RM7000. Expansion of interrupts. @@ -179,10 +200,17 @@ * Cause register. */ +#ifdef CPU_R8000 +#define CR_BR_DELAY 0x8000000000000000 +#define CR_EXC_CODE 0x000000f8 +#define CR_EXC_CODE_SHIFT 3 +#define CR_COP_ERR 0x10000000 +#else #define CR_BR_DELAY 0x80000000 #define CR_EXC_CODE 0x0000007c #define CR_EXC_CODE_SHIFT 2 #define CR_COP_ERR 0x30000000 +#endif #define CR_COP1_ERR 0x10000000 #define CR_COP2_ERR 0x20000000 #define CR_COP3_ERR 0x20000000 @@ -194,16 +222,26 @@ #define CR_INT_3 0x00002000 #define CR_INT_4 0x00004000 #define CR_INT_5 0x00008000 -/* Following on RM7000 */ +/* Following on RM7000 and R8000 */ #define CR_INT_6 0x00010000 #define CR_INT_7 0x00020000 #define CR_INT_8 0x00040000 +/* Following on RM7000 */ #define CR_INT_9 0x00080000 #define CR_INT_HARD 0x000ffc00 #define CR_INT_TIMR 0x00100000 /* 12 Timer */ #define CR_INT_PERF 0x00200000 /* 13 Performance counter */ - +/* R8000 specific */ +#define CR_FPE 0x01000000 +#define CR_VCE 0x02000000 +#define CR_BERR 0x04000000 +#define CR_NMI 0x08000000 + +#ifdef CPU_R8000 +#define CR_INT_MASK 0x0407ff00 /* contains CR_BERR */ +#else #define CR_INT_MASK 0x003fff00 +#endif /* * Config register. @@ -218,11 +256,20 @@ * Location of exception vectors. */ +#ifdef CPU_R8000 +#define RESET_EXC_VEC PHYS_TO_XKPHYS(0x1fc00000, CCA_NC) +/* all the others are relative to COP_0_TRAPBASE */ +/* #define UTLB_MISS_EXC_VEC 0x00000000 */ +/* #define KV1TLB_MISS_EXC_VEC 0x00000400 */ +/* #define KV0TLB_MISS_EXC_VEC 0x00000800 */ +/* #define GEN_EXC_VEC 0x00000c00 */ +#else #define RESET_EXC_VEC (CKSEG1_BASE + 0x1fc00000) #define TLB_MISS_EXC_VEC (CKSEG1_BASE + 0x00000000) #define XTLB_MISS_EXC_VEC (CKSEG1_BASE + 0x00000080) #define CACHE_ERR_EXC_VEC (CKSEG1_BASE + 0x00000100) #define GEN_EXC_VEC (CKSEG1_BASE + 0x00000180) +#endif /* * Coprocessor 0 registers @@ -257,6 +304,22 @@ #define COP_0_TAG_HI $29 #define COP_0_ERROR_PC $30 +/* R8000 specific */ +#define COP_0_TLB_SET $0 +#define COP_0_TLB_LO $2 +#define COP_0_UBASE $4 +#define COP_0_SHIFTAMT $5 +#define COP_0_TRAPBASE $6 +#define COP_0_BAD_PADDR $7 +#define COP_0_VADDR $8 +#define COP_0_WORK0 $18 +#define COP_0_WORK1 $19 +#define COP_0_PBASE $20 +#define COP_0_GBASE $21 +#define COP_0_TFP_TLB_WIRED $24 +#define COP_0_DCACHE $28 +#define COP_0_ICACHE $29 + /* RM7000 specific */ #define COP_0_WATCH_1 $18 #define COP_0_WATCH_2 $19 @@ -281,7 +344,7 @@ /* * COP_0_COUNT speed divider. */ -#if defined(CPU_OCTEON) +#if defined(CPU_OCTEON) || defined(CPU_R8000) #define CP0_CYCLE_DIVIDER 1 #else #define CP0_CYCLE_DIVIDER 2 @@ -499,7 +562,12 @@ void cp0_calibrate(struct cpu_info *); #define aston(p) p->p_md.md_astpending = 1 +#ifdef CPU_R8000 +#define mips_sync() __asm__ __volatile__ ("lw $0, 0(%0)" :: \ + "r" (PHYS_TO_XKPHYS(0, CCA_NC)) : "memory") +#else #define mips_sync() __asm__ __volatile__ ("sync" ::: "memory") +#endif #endif /* _KERNEL && !_LOCORE */ @@ -562,6 +630,7 @@ void tlb_asid_wrap(struct cpu_info *); void tlb_flush(int); void tlb_flush_addr(vaddr_t); void tlb_init(unsigned int); +void tlb_set_gbase(vaddr_t, vsize_t); void tlb_set_page_mask(uint32_t); void tlb_set_pid(u_int); void tlb_set_wired(uint32_t); diff --git a/sys/arch/mips64/include/mips_opcode.h b/sys/arch/mips64/include/mips_opcode.h index 816fcd6eb23..cf04aa23a43 100644 --- a/sys/arch/mips64/include/mips_opcode.h +++ b/sys/arch/mips64/include/mips_opcode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mips_opcode.h,v 1.7 2012/04/21 19:13:14 miod Exp $ */ +/* $OpenBSD: mips_opcode.h,v 1.8 2012/09/29 21:37:03 miod Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -306,6 +306,7 @@ typedef union { #define OP_MTH 007 #define OP_BC 010 #define OP_C0MISC 020 /* cop0 only */ +#define OP_TFP_C0MISC 030 /* cop0 only on R8000 */ /* * Values for the 'rt' field when 'op' == OP_COPz. diff --git a/sys/arch/mips64/include/pte.h b/sys/arch/mips64/include/pte.h index 7f329e4983d..377ea98fd28 100644 --- a/sys/arch/mips64/include/pte.h +++ b/sys/arch/mips64/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.14 2012/09/29 19:11:08 miod Exp $ */ +/* $OpenBSD: pte.h,v 1.15 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -38,7 +38,7 @@ */ /* - * R4000 hardware page table entries + * R4000 and R8000 hardware page table entries */ #ifndef _LOCORE @@ -62,22 +62,40 @@ typedef u_int32_t pt_entry_t; /* Mips page table entry */ #endif /* _LOCORE */ /* entryhi values */ +#ifndef CPU_R8000 #define PG_HVPN (-2 * PAGE_SIZE) /* Hardware page number mask */ #define PG_ODDPG PAGE_SIZE +#endif /* !R8000 */ /* Address space ID */ +#ifdef CPU_R8000 +#define PG_ASID_MASK 0x0000000000000ff0 +#define PG_ASID_SHIFT 4 +#define ICACHE_ASID_SHIFT 40 +#define MIN_USER_ASID 0 +#else #define PG_ASID_MASK 0x00000000000000ff #define PG_ASID_SHIFT 0 #define MIN_USER_ASID 1 +#endif #define PG_ASID_COUNT 256 /* Number of available ASID */ /* entrylo values */ +#ifdef CPU_R8000 +#define PG_WIRED 0x00000010 /* SW */ +#define PG_RO 0x00000020 /* SW */ +#define PG_G 0x00000000 /* no such concept for R8000 */ +#define PG_V 0x00000080 +#define PG_M 0x00000100 +#define PG_CCA_SHIFT 9 +#else #define PG_WIRED 0x80000000 /* SW */ #define PG_RO 0x40000000 /* SW */ #define PG_G 0x00000001 /* HW */ #define PG_V 0x00000002 #define PG_M 0x00000004 #define PG_CCA_SHIFT 3 +#endif #define PG_NV 0x00000000 #define PG_UNCACHED (CCA_NC << PG_CCA_SHIFT) @@ -93,13 +111,19 @@ typedef u_int32_t pt_entry_t; /* Mips page table entry */ #define PG_CWPAGE (PG_V | PG_CACHED) /* Not w-prot but clean */ #define PG_IOPAGE (PG_G | PG_V | PG_M | PG_UNCACHED) +#ifdef CPU_R8000 +#define PG_FRAME 0xfffff000 +#define PG_SHIFT 0 +#else #define PG_FRAME 0x3fffffc0 #define PG_FRAMEBITS 30 #define PG_SHIFT 6 +#endif #define pfn_to_pad(pa) ((((paddr_t)pa) & PG_FRAME) << PG_SHIFT) #define vad_to_pfn(va) (((va) >> PG_SHIFT) & PG_FRAME) +#ifndef CPU_R8000 #define PG_SIZE_4K 0x00000000 #define PG_SIZE_16K 0x00006000 #define PG_SIZE_64K 0x0001e000 @@ -112,6 +136,7 @@ typedef u_int32_t pt_entry_t; /* Mips page table entry */ #elif PAGE_SHIFT == 14 #define TLB_PAGE_MASK PG_SIZE_16K #endif +#endif /* !R8000 */ #if defined(_KERNEL) && !defined(_LOCORE) diff --git a/sys/arch/mips64/mips64/cache_tfp.c b/sys/arch/mips64/mips64/cache_tfp.c new file mode 100644 index 00000000000..dee235aed34 --- /dev/null +++ b/sys/arch/mips64/mips64/cache_tfp.c @@ -0,0 +1,194 @@ +/* $OpenBSD: cache_tfp.c,v 1.1 2012/09/29 21:37:03 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * R8000 cache routines. + * + * These routines only handle the L1 cache found onboard the R8000. + * The L2 (Streaming Cache) cache handling is apparently quite different + * accross R8000-based designs (well... the two of them: IP21 and IP26), + * and is handled on a per-platform basis. + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <mips64/cache.h> +#include <machine/cpu.h> + +#include <uvm/uvm_extern.h> + +void tfp_dctw_zero(vaddr_t); +void tfp_inval_icache(vsize_t); + +#define TFP_DCTW_STEP 16UL /* 4 words per tag */ + +void +tfp_ConfigCache(struct cpu_info *ci) +{ + register_t cfg; + + cfg = cp0_get_config(); + + /* + * XXX It would make sense to trust the configuration register, + * XXX but at least on my system it would report a 32KB I$, while + * XXX ARCS reports the architected 16KB. + * XXX Better not trust anything from the configuration register, + * XXX then. + */ +#if 0 + if (cfg & (1 << 5)) /* IB */ + ci->ci_l1instcacheline = 32; + else + ci->ci_l1instcacheline = 16; + ci->ci_l1instcachesize = (1 << 11) << ((cfg >> 9) & 0x07); /* IC */ + + if (cfg & (1 << 4)) /* DB */ + ci->ci_l1datacacheline = 32; + else + ci->ci_l1datacacheline = 16; + ci->ci_l1datacachesize = (1 << 12) << ((cfg >> 6) & 0x07); /* DC */ +#else + ci->ci_l1instcacheline = 32; + ci->ci_l1datacacheline = 32; + ci->ci_l1instcachesize = 16384; + ci->ci_l1datacachesize = 16384; +#endif + + /* R8000 L1 caches are direct */ + ci->ci_cacheways = 1; + ci->ci_l1instcacheset = ci->ci_l1instcachesize; + ci->ci_l1datacacheset = ci->ci_l1datacachesize; + + cache_valias_mask = + (max(ci->ci_l1instcachesize, ci->ci_l1datacachesize) - 1) & + ~PAGE_MASK; + + /* R8000 L2 cache are platform-specific, and not covered here */ + ci->ci_l2line = 0; + ci->ci_l2size = 0; + ci->ci_l3size = 0; + + ci->ci_SyncCache = tfp_SyncCache; + ci->ci_InvalidateICache = tfp_InvalidateICache; + ci->ci_SyncDCachePage = tfp_SyncDCachePage; + ci->ci_HitSyncDCache = tfp_HitSyncDCache; + ci->ci_HitInvalidateDCache = tfp_HitInvalidateDCache; + ci->ci_IOSyncDCache = tfp_IOSyncDCache; +} + +/* + * Writeback and invalidate all caches. + */ +void +tfp_SyncCache(struct cpu_info *ci) +{ + vaddr_t va, eva; + register_t sr; + + tfp_InvalidateICache(ci, 0, ci->ci_l1instcachesize); + + sr = disableintr(); + va = ci->ci_l1datacachesize; + for (va = 0; va < eva; va += TFP_DCTW_STEP) + tfp_dctw_zero(va); + setsr(sr); +} + +/* + * Invalidate I$ for the given range. + */ +void +tfp_InvalidateICache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va; + vsize_t sz; + void (*inval_subr)(vsize_t); + + if (_sz >= ci->ci_l1instcachesize) { + tfp_inval_icache(ci->ci_l1instcachesize); + } else { + /* extend the range to multiple of 32 bytes */ + va = _va & ~(32UL - 1); + sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - va; + + /* compute cache offset */ + va &= (ci->ci_l1instcachesize - 1); + inval_subr = (void (*)(vsize_t)) + ((vaddr_t)tfp_inval_icache + va); + (*inval_subr)(sz); + } +} + +/* + * Writeback D$ for the given page. + */ +void +tfp_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) +{ + /* nothing to do, D$ is write-through */ +} + +/* + * Writeback D$ for the given range. + */ +void +tfp_HitSyncDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + /* nothing to do, D$ is write-through */ +} + +/* + * Invalidate D$ for the given range. + */ +void +tfp_HitInvalidateDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va, eva; + vsize_t sz; + register_t sr; + + /* extend the range to multiples of the D$ tag span */ + va = _va & ~(TFP_DCTW_STEP - 1); + sz = ((_va + _sz + TFP_DCTW_STEP - 1) & ~(TFP_DCTW_STEP - 1)) - va; + + sr = disableintr(); + for (eva = va + sz; va < eva; va += TFP_DCTW_STEP) + tfp_dctw_zero(va); + setsr(sr); +} + +/* + * Backend for bus_dmamap_sync(). Enforce coherency of the given range + * by performing the necessary cache writeback and/or invalidate + * operations. + */ +void +tfp_IOSyncDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz, int how) +{ + switch (how) { + case CACHE_SYNC_R: + case CACHE_SYNC_X: + tfp_HitInvalidateDCache(ci, _va, _sz); + break; + case CACHE_SYNC_W: + /* nothing to do */ + break; + } +} diff --git a/sys/arch/mips64/mips64/cache_tfp_subr.S b/sys/arch/mips64/mips64/cache_tfp_subr.S new file mode 100644 index 00000000000..1f9ef4aaa73 --- /dev/null +++ b/sys/arch/mips64/mips64/cache_tfp_subr.S @@ -0,0 +1,98 @@ +/* $OpenBSD: cache_tfp_subr.S,v 1.1 2012/09/29 21:37:03 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <machine/param.h> +#include <machine/asm.h> +#include <machine/cpu.h> + +#include "assym.h" + + .set mips4 + .set noreorder + +/* + * The R8000 processor does not have documented cache maintainance + * instructions. While this is not really a problem for D$, which is + * write-through and physically tagged, this is a problem for I$, + * which is virtually tagged. + * + * Since there is no way to invalidate I$, the best we can do is + * override existing cache lines to evict them from the cache. + * + * The following routine will attempt to do so. It spans the whole I$ + * cache size, and may be invoked from any offset multiple of 32 bytes + * (in case a smaller portion of the cache needs to be invalidated). + * + * void tfp_inval_icache(register_t size) + */ + .align 14 +LEAF(tfp_inval_icache, 0) /* { */ + +#define ICACHE_CHUNK_INVALIDATE \ + beqz a0, 9f; \ + NOP; \ + NOP; \ + NOP; \ + subu a0, 32; \ + NOP; \ + NOP; \ + NOP + +#define ICACHE_256B_INVALIDATE \ + ICACHE_CHUNK_INVALIDATE; ICACHE_CHUNK_INVALIDATE; \ + ICACHE_CHUNK_INVALIDATE; ICACHE_CHUNK_INVALIDATE; \ + ICACHE_CHUNK_INVALIDATE; ICACHE_CHUNK_INVALIDATE; \ + ICACHE_CHUNK_INVALIDATE; ICACHE_CHUNK_INVALIDATE; + +#define ICACHE_2KB_INVALIDATE \ + ICACHE_256B_INVALIDATE; ICACHE_256B_INVALIDATE; \ + ICACHE_256B_INVALIDATE; ICACHE_256B_INVALIDATE; \ + ICACHE_256B_INVALIDATE; ICACHE_256B_INVALIDATE; \ + ICACHE_256B_INVALIDATE; ICACHE_256B_INVALIDATE + +#define ICACHE_16KB_INVALIDATE \ + ICACHE_2KB_INVALIDATE; ICACHE_2KB_INVALIDATE; \ + ICACHE_2KB_INVALIDATE; ICACHE_2KB_INVALIDATE; \ + ICACHE_2KB_INVALIDATE; ICACHE_2KB_INVALIDATE; \ + ICACHE_2KB_INVALIDATE; ICACHE_2KB_INVALIDATE + + ICACHE_16KB_INVALIDATE + + bnez a0, tfp_inval_icache /* wrap around */ + NOP +9: + j ra + NOP +END(tfp_inval_icache) /* } */ + +/* + * Clear the D$ cache tag for the given address. + * Interrupts must be disabled (to be free to alter the Vaddr register). + */ + +#define DCTW .align 4; .word 0x4300000a; SSNOP; SSNOP; SSNOP + +LEAF(tfp_dctw_zero, 0) /* { */ + DMTC0 a0, COP_0_VADDR + MTC0_HAZARD + DMTC0 zero, COP_0_DCACHE + MTC0_HAZARD + DCTW + j ra + NOP +END(tfp_dctw_zero) /* } */ diff --git a/sys/arch/mips64/mips64/context.S b/sys/arch/mips64/mips64/context.S index 01da9b764a4..846ab4d223c 100644 --- a/sys/arch/mips64/mips64/context.S +++ b/sys/arch/mips64/mips64/context.S @@ -1,4 +1,4 @@ -/* $OpenBSD: context.S,v 1.49 2012/09/29 19:11:08 miod Exp $ */ +/* $OpenBSD: context.S,v 1.50 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -96,8 +96,15 @@ NON_LEAF(cpu_switchto_asm, FRAMESZ(CF_SZ), ra) REG_S ra, CF_RA_OFFS(sp) .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ)) +#ifdef CPU_R8000 /* XXX everywhere where MFC0_HAZARD is not empty */ + MFC0 v0, COP_0_STATUS_REG + MFC0_HAZARD + beqz a0, 1f + NOP +#else beqz a0, 1f MFC0 v0, COP_0_STATUS_REG +#endif REG_S s0, PCB_CONTEXT+0*REGSZ(t3) # do a 'savectx()' REG_S s1, PCB_CONTEXT+1*REGSZ(t3) @@ -152,8 +159,16 @@ NON_LEAF(cpu_switchto_asm, FRAMESZ(CF_SZ), ra) PTR_ADDU t1, t1, v0 #endif lw v0, PM_ASID(t1) # ->pm_asid[cpuid].pma_asid +#ifdef CPU_R8000 + PTR_L t0, PCB_SEGTAB(t3) # save pcb_segtab for + DMTC0 t0, COP_0_UBASE # Utlbmiss handler + MTC0_HAZARD +#endif #if UPAGES > 1 /* { */ +#ifdef CPU_R8000 +#error Your processor has just been eaten by a grue. +#endif or v0, t3 dmtc0 v0, COP_0_TLB_HI # init high entry (tlbid) diff --git a/sys/arch/mips64/mips64/cp0access.S b/sys/arch/mips64/mips64/cp0access.S index c0918228142..e4bd7891380 100644 --- a/sys/arch/mips64/mips64/cp0access.S +++ b/sys/arch/mips64/mips64/cp0access.S @@ -1,4 +1,4 @@ -/* $OpenBSD: cp0access.S,v 1.17 2012/09/29 19:02:26 miod Exp $ */ +/* $OpenBSD: cp0access.S,v 1.18 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -191,12 +191,34 @@ LEAF(cp0_get_count, 0) NOP END(cp0_get_count) +#ifndef CPU_R8000 LEAF(cp0_set_compare, 0) MTC0 a0, COP_0_COMPARE MTC0_HAZARD j ra NOP END(cp0_set_compare) +#endif + +#ifdef CPU_R8000 +LEAF(cp0_reset_cause, 0) + DMFC0 v0, COP_0_CAUSE_REG + MFC0_HAZARD + or v0, a0 + xor v0, a0 + DMTC0 v0, COP_0_CAUSE_REG + MTC0_HAZARD + j ra + NOP +END(cp0_reset_cause) + +LEAF(cp0_set_trapbase, 0) + DMTC0 a0, COP_0_TRAPBASE + MTC0_HAZARD + j ra + NOP +END(cp0_set_trapbase) +#endif #ifdef notused LEAF(cp0_getperfcount, 0) diff --git a/sys/arch/mips64/mips64/cpu.c b/sys/arch/mips64/mips64/cpu.c index e7b7e3a19c8..b57e00dfb8e 100644 --- a/sys/arch/mips64/mips64/cpu.c +++ b/sys/arch/mips64/mips64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.47 2012/09/29 19:25:28 miod Exp $ */ +/* $OpenBSD: cpu.c,v 1.48 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 1997-2004 Opsycon AB (www.opsycon.se) @@ -157,6 +157,9 @@ cpuattach(struct device *parent, struct device *dev, void *aux) printf("PMC-Sierra RM7000A CPU"); cpu_is_rm7k++; break; + case MIPS_R8000: + printf("MIPS R8000 CPU"); + break; case MIPS_RM9000: printf("PMC-Sierra RM9000 CPU"); break; @@ -239,6 +242,9 @@ cpuattach(struct device *parent, struct device *dev, void *aux) case MIPS_RM7000: printf("RM7000 FPC"); break; + case MIPS_R8000: + printf("R8010 FPU"); + break; case MIPS_RM9000: printf("RM9000 FPC"); break; @@ -291,6 +297,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux) printf(", L2 %dKB 2 way", ci->ci_l2size / 1024); break; case MIPS_RM7000: + case MIPS_R8000: case MIPS_RM9000: case MIPS_LOONGSON2: printf(", L2 %dKB 4 way", ci->ci_l2size / 1024); diff --git a/sys/arch/mips64/mips64/db_disasm.c b/sys/arch/mips64/mips64/db_disasm.c index d96f4d42693..975a0a505f5 100644 --- a/sys/arch/mips64/mips64/db_disasm.c +++ b/sys/arch/mips64/mips64/db_disasm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_disasm.c,v 1.15 2011/04/04 16:58:28 miod Exp $ */ +/* $OpenBSD: db_disasm.c,v 1.16 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2010 Miodrag Vallat. @@ -51,7 +51,7 @@ * SUCH DAMAGE. * * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 - * $Id: db_disasm.c,v 1.15 2011/04/04 16:58:28 miod Exp $ + * $Id: db_disasm.c,v 1.16 2012/09/29 21:37:03 miod Exp $ */ #ifdef _KERNEL @@ -460,41 +460,22 @@ static const char *cop0_miscname[64] = { NULL, NULL, - "wait", /* RM5200 */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "wait" /* RM5200 */ +}; +static const char *cop0_tfp_miscname[64] = { NULL, + "tlbr", + "tlbw", NULL, NULL, NULL, - NULL, - NULL, - NULL, + "tlbwr", NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL + "tlbp", + "dctr", + "dctw" }; static const char *cop0_reg0[32] = { @@ -854,7 +835,19 @@ unknown: i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' '); goto pr_displ; case OP_C0MISC: - insn = cop0_miscname[i.FRType.func]; + if (i.FRType.func < nitems(cop0_miscname)) + insn = cop0_miscname[i.FRType.func]; + else + insn = NULL; + if (insn == NULL) + goto unknown; + else + (*pr)("%s", insn); + case OP_TFP_C0MISC: + if (i.FRType.func < nitems(cop0_tfp_miscname)) + insn = cop0_tfp_miscname[i.FRType.func]; + else + insn = NULL; if (insn == NULL) goto unknown; else diff --git a/sys/arch/mips64/mips64/db_machdep.c b/sys/arch/mips64/mips64/db_machdep.c index 5011f330b11..684d6edd389 100644 --- a/sys/arch/mips64/mips64/db_machdep.c +++ b/sys/arch/mips64/mips64/db_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_machdep.c,v 1.35 2012/04/21 12:20:30 miod Exp $ */ +/* $OpenBSD: db_machdep.c,v 1.36 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 1998-2003 Opsycon AB (www.opsycon.se) @@ -64,6 +64,7 @@ void kdbpokew(vaddr_t, uint16_t); void kdbpokeb(vaddr_t, uint8_t); int kdb_trap(int, struct trap_frame *); +void db_print_tlb(uint, uint64_t); void db_trap_trace_cmd(db_expr_t, int, db_expr_t, char *); void db_dump_tlb_cmd(db_expr_t, int, db_expr_t, char *); @@ -458,8 +459,46 @@ db_trap_trace_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *m) trapDump("ddb trap trace"); } +void +db_print_tlb(uint tlbno, uint64_t tlblo) +{ + paddr_t pa; +#ifndef CPU_R8000 + /* short description of coherency attributes */ + static const char *attr[] = { + "CCA 0", + "CCA 1", + "NC ", + "C ", + "CEX ", + "CEXW ", + "CCA 6", + "NCACC" + }; +#endif + + pa = pfn_to_pad(tlblo); +#ifdef CPU_R8000 + pa |= ptoa(tlbno % 128); +#endif + if (tlblo & PG_V) { + db_printf("%016lx ", pa); + db_printf("%c", tlblo & PG_M ? 'M' : ' '); +#ifndef CPU_R8000 + db_printf("%c", tlblo & PG_G ? 'G' : ' '); + db_printf("%s ", attr[(tlblo >> 3) & 7]); +#endif + } else { + db_printf("invalid "); + } +} + /* * Dump TLB contents. + * Syntax: machine tlb [/p asid] [/c] [tlb#] + * /p: only display tlb entries matching the given asid + * /c: check for duplicate entries + * tlb#: display <count> entries starting from this index */ void db_dump_tlb_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *m) @@ -467,27 +506,29 @@ db_dump_tlb_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *m) int tlbno, last, check, pid; struct tlb_entry tlb, tlbp; struct cpu_info *ci = curcpu(); -char *attr[] = { - "WTNA", "WTA ", "UCBL", "CWB ", "RES ", "RES ", "UCNB", "BPAS" -}; pid = -1; if (m[0] == 'p') { - if (have_addr && addr < 256) { + if (have_addr && addr < PG_ASID_COUNT) { pid = addr; - tlbno = 0; - count = ci->ci_hw.tlbsize; } + tlbno = 0; + count = ci->ci_hw.tlbsize; } else if (m[0] == 'c') { last = ci->ci_hw.tlbsize; for (tlbno = 0; tlbno < last; tlbno++) { tlb_read(tlbno, &tlb); for (check = tlbno + 1; check < last; check++) { tlb_read(check, &tlbp); -if ((tlbp.tlb_hi == tlb.tlb_hi && (tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V)) || -(pfn_to_pad(tlb.tlb_lo0) == pfn_to_pad(tlbp.tlb_lo0) && tlb.tlb_lo0 & PG_V) || -(pfn_to_pad(tlb.tlb_lo1) == pfn_to_pad(tlbp.tlb_lo1) && tlb.tlb_lo1 & PG_V)) { + if ((tlbp.tlb_hi == tlb.tlb_hi && + (tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V)) || + (pfn_to_pad(tlb.tlb_lo0) == + pfn_to_pad(tlbp.tlb_lo0) && + tlb.tlb_lo0 & PG_V) || + (pfn_to_pad(tlb.tlb_lo1) == + pfn_to_pad(tlbp.tlb_lo1) && + tlb.tlb_lo1 & PG_V)) { db_printf("MATCH:\n"); db_dump_tlb_cmd(tlbno, 1, 1, ""); db_dump_tlb_cmd(check, 1, 1, ""); @@ -504,40 +545,39 @@ if ((tlbp.tlb_hi == tlb.tlb_hi && (tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V)) || } } last = tlbno + count; + if (last > ci->ci_hw.tlbsize) + last = ci->ci_hw.tlbsize; if (pid == -1) db_printf("current asid: %d\n", tlb_get_pid()); - for (; tlbno < ci->ci_hw.tlbsize && tlbno < last; tlbno++) { + for (; tlbno < last; tlbno++) { tlb_read(tlbno, &tlb); - if (pid >= 0 && (tlb.tlb_hi & 0xff) != pid) + if (pid >= 0 && + (tlb.tlb_hi & PG_ASID_MASK) != (pid << PG_ASID_SHIFT)) continue; if (tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V) { - db_printf("%2d v=%16llx", tlbno, tlb.tlb_hi & ~0xffL); - db_printf("/%02x ", tlb.tlb_hi & 0xff); - - if (tlb.tlb_lo0 & PG_V) { - db_printf("%16llx ", pfn_to_pad(tlb.tlb_lo0)); - db_printf("%c", tlb.tlb_lo0 & PG_M ? 'M' : ' '); - db_printf("%c", tlb.tlb_lo0 & PG_G ? 'G' : ' '); - db_printf("%s ", attr[(tlb.tlb_lo0 >> 3) & 7]); - } else { - db_printf("invalid "); - } + vaddr_t va; + uint asid; + + asid = (tlb.tlb_hi & PG_ASID_MASK) >> PG_ASID_SHIFT; + va = tlb.tlb_hi & ~((vaddr_t)PG_ASID_MASK); +#ifdef CPU_R8000 + if ((int64_t)va < 0) + asid = 0; /* KV1 addresses ignore ASID */ + va |= ptoa((tlbno ^ asid) % 128); +#endif + db_printf("%3d v=%016llx", tlbno, va); + db_printf("/%02x ", asid); - if (tlb.tlb_lo1 & PG_V) { - db_printf("%16llx ", pfn_to_pad(tlb.tlb_lo1)); - db_printf("%c", tlb.tlb_lo1 & PG_M ? 'M' : ' '); - db_printf("%c", tlb.tlb_lo1 & PG_G ? 'G' : ' '); - db_printf("%s ", attr[(tlb.tlb_lo1 >> 3) & 7]); - } else { - db_printf("invalid "); - } + db_print_tlb(tlbno, tlb.tlb_lo0); +#ifndef CPU_R8000 + db_print_tlb(tlbno, tlb.tlb_lo1); db_printf(" sz=%x", tlb.tlb_mask); - } - else if (pid < 0) { - db_printf("%2d v=invalid ", tlbno); +#endif + } else if (pid < 0) { + db_printf("%3d v=invalid ", tlbno); } db_printf("\n"); } diff --git a/sys/arch/mips64/mips64/exception_tfp.S b/sys/arch/mips64/mips64/exception_tfp.S new file mode 100644 index 00000000000..97a85f148c4 --- /dev/null +++ b/sys/arch/mips64/mips64/exception_tfp.S @@ -0,0 +1,409 @@ +/* $OpenBSD: exception_tfp.S,v 1.1 2012/09/29 21:37:03 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * k_general and u_general are heavily based upon their counterparts in + * exception.S under the following licence terms: + */ +/* + * Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * 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 AUTHOR ``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 AUTHOR 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. + * + */ + +/* + * Trap handling subpage for R8000 systems. + */ + +#include <machine/param.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/pte.h> +#include <machine/regnum.h> +#include <machine/cpustate.h> + +#include "assym.h" + +#define TLBW .align 4; .word 0x43000002 + + .set mips4 + .set noreorder + + .text + + .align 12 + .globl tfp_trapbase +tfp_trapbase: + + /* + * 000: tlb miss handler for U region + */ + .align 10 + + .ent utlb_miss, 0 +utlb_miss: + .set noat + .align 4 + PRE_MFC0_ADDR_HAZARD + DMFC0 k0, COP_0_VADDR + MFC0_HAZARD + DMTC0 k0, COP_0_WORK0 + MTC0_HAZARD + PTR_SRL k0, SEGSHIFT + sltiu k1, k0, PMAP_SEGTABSIZE + beqz k1, _inv_seg + NOP + DMFC0 k1, COP_0_UBASE # PCB_SEGTAB(CI_CURPROCPADDR(curcpu)) + MFC0_HAZARD + PTR_SLL k0, LOGREGSZ + PTR_ADDU k1, k0 + PTR_L k1, 0(k1) # get pointer to page table + DMFC0 k0, COP_0_WORK0 # saved COP_0_VADDR + MFC0_HAZARD + beqz k1, _inv_seg + PTR_SRL k0, PAGE_SHIFT - 2 + andi k0, ((NPTEPG / 2) - 1) << 2 + PTR_ADDU k1, k0 + lwu k0, 0(k1) # get pte + DMTC0 k0, COP_0_TLB_LO + MTC0_HAZARD + TLBW + ERET + +_inv_seg: + DMFC0 k0, COP_0_STATUS_REG + MFC0_HAZARD + andi k0, SR_KSU_USER + bnez k0, u_general + NOP + b k_general + NOP + + .set at + .end utlb_miss + + /* + * 400: tlb miss handler for KV0 region + */ + .align 10 + + .ent kv0tlb_miss, 0 +kv0tlb_miss: + .set noat + /* + * Since we do not set up KV0 mappings, fall through directly + * into the `invalid address' fault handling. + */ + .align 4 + b _inv_seg + NOP + .set at + .end kv0tlb_miss + + /* + * 800: tlb miss handler for KV1 region + */ + .align 10 + + .ent kv1tlb_miss, 0 +kv1tlb_miss: + .set noat + .align 4 + PRE_MFC0_ADDR_HAZARD + DMFC0 k0, COP_0_VADDR + MFC0_HAZARD + DMFC0 k1, COP_0_STATUS_REG + MFC0_HAZARD + andi k1, SR_KSU_USER + bnez k1, u_general + LA k1, VM_MIN_KERNEL_ADDRESS + PTR_SUBU k0, k1 + DMFC0 k1, COP_0_WORK1 # Sysmapsize + MFC0_HAZARD + PTR_SRL k0, PAGE_SHIFT + sltu k1, k0, k1 + beqz k1, k_general + PTR_SLL k0, 2 + DMFC0 k1, COP_0_GBASE # Sysmap + MFC0_HAZARD + PTR_ADDU k1, k0 + lwu k0, 0(k1) # get pte + DMTC0 k0, COP_0_TLB_LO + MTC0_HAZARD + TLBW + ERET + .set at + .end kv1tlb_miss + + /* + * C00: tlb miss exception while servicing an exception + * tlb invalid exception + * tlb modified exception + * all other exceptions + */ + .align 10 + .ent exception, 0 +exception: + .set noat + .align 4 + DMFC0 k0, COP_0_STATUS_REG + MFC0_HAZARD + andi k0, SR_KSU_USER + DMFC0 k1, COP_0_CAUSE_REG + MFC0_HAZARD + bnez k0, u_general + and k1, CR_EXC_CODE + + LA k0, k_exception_table + PTR_ADDU k0, k1 + PTR_L k1, 0(k0) + j k1 + NOP + + .set at + .end exception + + /* + * Handle a TLB invalid exception from kernel mode. This implies there + * is a TLB match, but currently not valid. Check if the pte is now + * valid and update, or pass the mess to the regular exception handler. + */ +k_tlb_inv: + .set noat + .align 4 + PRE_MFC0_ADDR_HAZARD + DMFC0 k0, COP_0_VADDR + MFC0_HAZARD + LA k1, VM_MIN_KERNEL_ADDRESS + PTR_SUBU k0, k1 + DMFC0 k1, COP_0_WORK1 # Sysmapsize + MFC0_HAZARD + PTR_SRL k0, PAGE_SHIFT + sltu k1, k0, k1 + beqz k1, k_general + PTR_SLL k0, 2 + DMFC0 k1, COP_0_GBASE # Sysmap + MFC0_HAZARD + PTR_ADDU k1, k0 + lwu k0, 0(k1) # get pte + andi k1, k0, PG_V + beqz k1, k_general # if not valid + NOP + + DMTC0 k0, COP_0_TLB_LO + MTC0_HAZARD + TLBW + ERET + .set at + +k_exception_table: + PTR_VAL k_general # interrupt + PTR_VAL k_general # TLB modification + PTR_VAL k_tlb_inv + PTR_VAL k_tlb_inv + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + PTR_VAL k_general + + .align 5 +NNON_LEAF(u_general, FRAMESZ(CF_SZ), ra) + .set noat + .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ)) + + GET_CPU_INFO(k1, k0) + PTR_L k0, CI_CURPROCPADDR(k1) + SAVE_CPU(k0, 0) + SAVE_CPU_SREG(k0, 0) + PTR_ADDU sp, k0, USPACE-FRAMESZ(CF_SZ) + LA gp, _gp + .set at + and t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) + DMTC0 t0, COP_0_STATUS_REG + MTC0_SR_IE_HAZARD + + jal trap + PTR_S a3, CF_RA_OFFS(sp) # for debugging + + DMFC0 t0, COP_0_STATUS_REG # enable interrupts before checking + ori t0, SR_INT_ENAB # for ast. + DMTC0 t0, COP_0_STATUS_REG + MTC0_SR_IE_HAZARD + +0: + GET_CPU_INFO(t1, t0) + PTR_L t0, CI_CURPROC(t1) + lw v0, P_ASTPENDING(t0) # any pending AST? + beq v0, zero, 4f + NOP + + jal ast + NOP + + b 0b + NOP + +4: + DMFC0 t0, COP_0_STATUS_REG # disable interrupts + MFC0_HAZARD + ori t0, SR_INT_ENAB + xori t0, SR_INT_ENAB + DMTC0 t0, COP_0_STATUS_REG + MTC0_SR_IE_HAZARD + + ori t0, SR_EXL # restoring to user mode. + DMTC0 t0, COP_0_STATUS_REG # must set exception level bit. + MTC0_SR_IE_HAZARD + + # t1 is curcpu() from earlier + move k1, t1 + PTR_L k0, CI_CURPROCPADDR(k1) + RESTORE_REG(a3, CPL, k0, 0) + sw a3, CI_IPL(k1) + .set noat + RESTORE_CPU_SREG(k0, 0) + RESTORE_REG(a0, PC, k0, 0) + RESTORE_CPU(k0, 0) + RESTORE_REG(sp, SP, k0, 0) + LI k0, 0 + LI k1, 0 + ERET + .set at +END(u_general) + + .align 5 +NNON_LEAF(k_general, FRAMESZ(KERN_EXC_FRAME_SIZE), ra) + .globl k_intr # for trap.c peace of mind +k_intr: + .set noat + .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(KERN_EXC_FRAME_SIZE)) + +#ifdef DEBUG + GET_CPU_INFO(k1, k0) + PTR_L k1, CI_CURPROCPADDR(k1) + PTR_SUBU k0, sp, k1 + sltiu k0, 2048 + beqz k0, 8f + NOP + + LA a0, start - FRAMESZ(CF_SZ) - 4 * REGSZ + move a6, sp + move sp, a0 + DMFC0 a1, COP_0_EXC_PC + MFC0_HAZARD + LA a0, 1f + PRE_MFC0_ADDR_HAZARD + DMFC0 a3, COP_0_VADDR + MFC0_HAZARD + DMFC0 a4, COP_0_STATUS_REG + MFC0_HAZARD + DMFC0 a5, COP_0_CAUSE_REG + MFC0_HAZARD + jal printf + move a2, ra + + LA sp, start-FRAMESZ(CF_SZ) +#ifdef DDB + LA a0, 2f + jal trapDump + NOP +#endif + PANIC("kernel stack overflow") + + .data +1: + .asciiz "\rtfptrap: PC %p RA %p ADR %p\nSR %p CR %p SP %p\n" +2: + .asciiz "stack oflow" + + .text +8: +#endif + + PTR_SUB k0, sp, FRAMESZ(KERN_EXC_FRAME_SIZE) + SAVE_CPU(k0, CF_RA_OFFS) +#if defined(DDB) + SAVE_CPU_SREG(k0, CF_RA_OFFS) +#endif + .set at + move sp, k0 # Already on kernel stack + LA gp, _gp + and t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) + DMTC0 t0, COP_0_STATUS_REG + MTC0_SR_IE_HAZARD + PTR_S a0, 0(sp) + jal trap + PTR_S a3, CF_RA_OFFS + KERN_REG_SIZE(sp) + + DMFC0 t0, COP_0_STATUS_REG # disable interrupts + MFC0_HAZARD + ori t0, SR_INT_ENAB + xori t0, SR_INT_ENAB + DMTC0 t0, COP_0_STATUS_REG + MTC0_SR_IE_HAZARD + + .set noat + RESTORE_REG(a0, PC, sp, CF_RA_OFFS) + RESTORE_CPU(sp, CF_RA_OFFS) + PTR_ADDU sp, sp, FRAMESZ(KERN_EXC_FRAME_SIZE) + ERET + .set at +END(k_general) diff --git a/sys/arch/mips64/mips64/lcore_access.S b/sys/arch/mips64/mips64/lcore_access.S index 1986f1e39db..c625d29e4e5 100644 --- a/sys/arch/mips64/mips64/lcore_access.S +++ b/sys/arch/mips64/mips64/lcore_access.S @@ -1,4 +1,4 @@ -/* $OpenBSD: lcore_access.S,v 1.22 2012/09/29 19:02:26 miod Exp $ */ +/* $OpenBSD: lcore_access.S,v 1.23 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -296,24 +296,30 @@ LEAF(guarded_read_1, 0) GET_CPU_INFO(t1, t0) PTR_L t3, CI_CURPROCPADDR(t1) +#ifndef CPU_R8000 li a3, SR_BOOT_EXC_VEC MFC0 a2, COP_0_STATUS_REG or a4, a2, a3 xor a4, a4, a3 +#endif li v0, KT_GUARDERR lw v1, PCB_ONFAULT(t3) sw v0, PCB_ONFAULT(t3) +#ifndef CPU_R8000 MTC0 a4, COP_0_STATUS_REG MTC0_HAZARD +#endif lb v0, 0(a0) sb v0, 0(a1) +#ifndef CPU_R8000 MTC0 a2, COP_0_STATUS_REG MTC0_HAZARD - +#endif + sw v1, PCB_ONFAULT(t3) j ra move v0, zero @@ -323,24 +329,30 @@ LEAF(guarded_read_2, 0) GET_CPU_INFO(t1, t0) PTR_L t3, CI_CURPROCPADDR(t1) +#ifndef CPU_R8000 li a3, SR_BOOT_EXC_VEC MFC0 a2, COP_0_STATUS_REG or a4, a2, a3 xor a4, a4, a3 +#endif li v0, KT_GUARDERR lw v1, PCB_ONFAULT(t3) sw v0, PCB_ONFAULT(t3) +#ifndef CPU_R8000 MTC0 a4, COP_0_STATUS_REG MTC0_HAZARD +#endif lh v0, 0(a0) sh v0, 0(a1) - + +#ifndef CPU_R8000 MTC0 a2, COP_0_STATUS_REG MTC0_HAZARD - +#endif + sw v1, PCB_ONFAULT(t3) j ra move v0, zero @@ -350,24 +362,30 @@ LEAF(guarded_read_4, 0) GET_CPU_INFO(t1, t0) PTR_L t3, CI_CURPROCPADDR(t1) +#ifndef CPU_R8000 li a3, SR_BOOT_EXC_VEC MFC0 a2, COP_0_STATUS_REG or a4, a2, a3 xor a4, a4, a3 +#endif li v0, KT_GUARDERR lw v1, PCB_ONFAULT(t3) sw v0, PCB_ONFAULT(t3) +#ifndef CPU_R8000 MTC0 a4, COP_0_STATUS_REG MTC0_HAZARD +#endif lw v0, 0(a0) sw v0, 0(a1) - + +#ifndef CPU_R8000 MTC0 a2, COP_0_STATUS_REG MTC0_HAZARD - +#endif + sw v1, PCB_ONFAULT(t3) j ra move v0, zero @@ -377,32 +395,40 @@ LEAF(guarded_write_4, 0) GET_CPU_INFO(t1, t0) PTR_L t3, CI_CURPROCPADDR(t1) +#ifndef CPU_R8000 li a3, SR_BOOT_EXC_VEC MFC0 a2, COP_0_STATUS_REG or a4, a2, a3 xor a4, a4, a3 +#endif li v0, KT_GUARDERR lw v1, PCB_ONFAULT(t3) sw v0, PCB_ONFAULT(t3) +#ifndef CPU_R8000 MTC0 a4, COP_0_STATUS_REG MTC0_HAZARD +#endif sw a1, 0(a0) - + +#ifndef CPU_R8000 MTC0 a2, COP_0_STATUS_REG MTC0_HAZARD - +#endif + sw v1, PCB_ONFAULT(t3) j ra move v0, zero END(guarded_write_4) _guarderr: +#ifndef CPU_R8000 MTC0 a2, COP_0_STATUS_REG MTC0_HAZARD - +#endif + sw v1, PCB_ONFAULT(t3) j ra li v0, EFAULT # return error diff --git a/sys/arch/mips64/mips64/mips64_machdep.c b/sys/arch/mips64/mips64/mips64_machdep.c index 7986e780344..ae3eb2f64fc 100644 --- a/sys/arch/mips64/mips64/mips64_machdep.c +++ b/sys/arch/mips64/mips64/mips64_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mips64_machdep.c,v 1.6 2012/09/29 19:29:05 miod Exp $ */ +/* $OpenBSD: mips64_machdep.c,v 1.7 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2009, 2010, 2012 Miodrag Vallat. @@ -126,7 +126,12 @@ build_trampoline(vaddr_t addr, vaddr_t dest) * Prototype status registers value for userland processes. */ register_t protosr = SR_FR_32 | SR_XX | SR_UX | SR_KSU_USER | SR_EXL | - SR_KX | SR_INT_ENAB; +#ifdef CPU_R8000 + SR_SERIALIZE_FPU | +#else + SR_KX | +#endif + SR_INT_ENAB; /* * Set registers on exec for native exec format. For o64/64. @@ -195,7 +200,20 @@ exec_md_map(struct proc *p, struct exec_package *pack) void tlb_init(unsigned int tlbsize) { +#ifdef CPU_R8000 + register_t sr; + + sr = getsr(); + sr &= ~(((uint64_t)SR_PGSZ_MASK << SR_KPGSZ_SHIFT) | + ((uint64_t)SR_PGSZ_MASK << SR_UPGSZ_SHIFT)); + sr |= ((uint64_t)SR_PGSZ_16K << SR_KPGSZ_SHIFT) | + ((uint64_t)SR_PGSZ_16K << SR_UPGSZ_SHIFT); + protosr |= ((uint64_t)SR_PGSZ_16K << SR_KPGSZ_SHIFT) | + ((uint64_t)SR_PGSZ_16K << SR_UPGSZ_SHIFT); + setsr(sr); +#else tlb_set_page_mask(TLB_PAGE_MASK); +#endif tlb_set_wired(0); tlb_flush(tlbsize); #if UPAGES > 1 @@ -210,6 +228,9 @@ void tlb_asid_wrap(struct cpu_info *ci) { tlb_flush(ci->ci_hw.tlbsize); +#ifdef CPU_R8000 + Mips_InvalidateICache(ci, 0, ci->ci_l1instcachesize); +#endif } /* diff --git a/sys/arch/mips64/mips64/pmap.c b/sys/arch/mips64/mips64/pmap.c index c2b198ff87f..bccff8c741d 100644 --- a/sys/arch/mips64/mips64/pmap.c +++ b/sys/arch/mips64/mips64/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.64 2012/09/29 19:11:08 miod Exp $ */ +/* $OpenBSD: pmap.c,v 1.65 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -344,7 +344,9 @@ void pmap_bootstrap(void) { u_int i; +#ifndef CPU_R8000 pt_entry_t *spte; +#endif /* * Create a mapping table for kernel virtual memory. This @@ -357,8 +359,10 @@ pmap_bootstrap(void) Sysmapsize = (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / PAGE_SIZE; +#ifndef CPU_R8000 if (Sysmapsize & 1) Sysmapsize++; /* force even number of pages */ +#endif Sysmap = (pt_entry_t *) uvm_pageboot_alloc(sizeof(pt_entry_t) * Sysmapsize); @@ -371,6 +375,7 @@ pmap_bootstrap(void) simple_lock_init(&pmap_kernel()->pm_lock); pmap_kernel()->pm_count = 1; +#ifndef CPU_R8000 /* * The 64 bit Mips architecture stores the AND result * of the Global bits in the pte pair in the on chip @@ -381,6 +386,10 @@ pmap_bootstrap(void) */ for (i = Sysmapsize, spte = Sysmap; i != 0; i--, spte++) *spte = PG_G; +#else + bzero(Sysmap, sizeof(pt_entry_t) * Sysmapsize); +#endif + tlb_set_gbase((vaddr_t)Sysmap, Sysmapsize); for (i = 0; i < MAXCPUS; i++) { pmap_asid_info[i].pma_asidgen = 1; @@ -436,12 +445,14 @@ pmap_steal_memory(vsize_t size, vaddr_t *vstartp, vaddr_t *vendp) *vendp = virtual_end; #ifdef __sgi__ +#ifndef CPU_R8000 /* * Return a CKSEG0 address whenever possible. */ if (pa + size < CKSEG_SIZE) va = PHYS_TO_CKSEG0(pa); else +#endif va = PHYS_TO_XKPHYS(pa, CCA_CACHED); #else va = PHYS_TO_XKPHYS(pa, CCA_CACHED); @@ -555,7 +566,7 @@ pmap_destroy(pmap_t pmap) #ifdef PARANOIA for (j = 0; j < NPTEPG; j++) { if (pte[j] != PG_NV) - panic("pmap_destroy: segmap not empty"); + panic("pmap_destroy: segmap %p not empty at index %d", pte, j); } #endif pool_put(&pmap_pg_pool, pte); @@ -1137,12 +1148,14 @@ pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap) if (pmap == pmap_kernel()) { if (IS_XKPHYS(va)) pa = XKPHYS_TO_PHYS(va); +#ifndef CPU_R8000 else if (va >= (vaddr_t)CKSEG0_BASE && va < (vaddr_t)CKSEG0_BASE + CKSEG_SIZE) pa = CKSEG0_TO_PHYS(va); else if (va >= (vaddr_t)CKSEG1_BASE && va < (vaddr_t)CKSEG1_BASE + CKSEG_SIZE) pa = CKSEG1_TO_PHYS(va); +#endif else { #ifdef DIAGNOSTIC if (va < VM_MIN_KERNEL_ADDRESS || @@ -1754,12 +1767,14 @@ pmap_map_direct(vm_page_t pg) vaddr_t va; #ifdef __sgi__ +#ifndef CPU_R8000 /* * Return a CKSEG0 address whenever possible. */ if (pa < CKSEG_SIZE) va = PHYS_TO_CKSEG0(pa); else +#endif va = PHYS_TO_XKPHYS(pa, CCA_CACHED); #else va = PHYS_TO_XKPHYS(pa, CCA_CACHED); @@ -1775,9 +1790,11 @@ pmap_unmap_direct(vaddr_t va) vm_page_t pg; #ifdef __sgi__ +#ifndef CPU_R8000 if (va >= CKSEG0_BASE) pa = CKSEG0_TO_PHYS(va); else +#endif pa = XKPHYS_TO_PHYS(va); #else pa = XKPHYS_TO_PHYS(va); diff --git a/sys/arch/mips64/mips64/tlb_tfp.S b/sys/arch/mips64/mips64/tlb_tfp.S new file mode 100644 index 00000000000..4fd6b9c0777 --- /dev/null +++ b/sys/arch/mips64/mips64/tlb_tfp.S @@ -0,0 +1,297 @@ +/* $OpenBSD: tlb_tfp.S,v 1.1 2012/09/29 21:37:03 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <machine/param.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/pte.h> + +#include "assym.h" + +#define TLBR .align 4; .word 0x43000001; SSNOP; SSNOP; SSNOP; SSNOP +#define TLBW .align 4; .word 0x43000002; SSNOP; SSNOP; SSNOP +#define TLBP .align 4; .word 0x43000008; SSNOP; SSNOP; SSNOP; SSNOP + +#ifdef TLB_DEBUG +#define TLBOP(crounha) Xtlb_##crounha +#else +#define TLBOP(crounha) tlb_##crounha +#endif + + .set mips4 + .set noreorder + +/* + * void tlb_flush(int); + * Flush all the TLB entries. Argument is ignored (128x3 layout is hardcoded). + * Assumes there are no wired entries. + */ +LEAF(TLBOP(flush), 0) /* { */ + DMFC0 v1, COP_0_STATUS_REG # Save the status register. + MFC0_HAZARD + ori v0, v1, SR_INT_ENAB + xori v0, SR_INT_ENAB + DMTC0 v0, COP_0_STATUS_REG # Disable interrupts + MTC0_SR_IE_HAZARD + + LI v0, 01 + dsll v0, v0, 62 # KV0 base + DMFC0 a2, COP_0_TLB_HI # Read current ASID + MFC0_HAZARD + LI a1, 2 # TLB set counter +1: + DMTC0 a1, COP_0_TLB_SET + MTC0_HAZARD + LI a0, 127 # TLB index counter +2: + DMTC0 zero, COP_0_TLB_LO + MTC0_HAZARD + DMTC0 v0, COP_0_TLB_HI + MTC0_HAZARD + DMTC0 v0, COP_0_VADDR + MTC0_HAZARD + + TLBW + beqz a0, 3f + addu v0, PAGE_SIZE # Make sure no duplicates will exist + b 2b + subu a0, 1 +3: + beqz a1, 4f + NOP + b 1b + subu a1, 1 +4: + DMTC0 a2, COP_0_TLB_HI # Restore current ASID + MTC0_HAZARD + MTC0_SR_IE_HAZARD + DMTC0 v1, COP_0_STATUS_REG # Restore the status register + MTC0_SR_IE_HAZARD + + j ra + NOP +END(TLBOP(flush)) /* } */ + +/* + * void tlb_flush_addr(vaddr_t); + * Flush matching TLB entry, if any, for the given address and ASID (the + * ASID bits are in the same position as in EntryHi). + */ +LEAF(TLBOP(flush_addr), 0) /* { */ + DMFC0 v1, COP_0_STATUS_REG # Save the status register. + MFC0_HAZARD + ori v0, v1, SR_INT_ENAB + xori v0, v0, SR_INT_ENAB + DMTC0 v0, COP_0_STATUS_REG # Disable interrupts + MTC0_SR_IE_HAZARD + DMFC0 a2, COP_0_TLB_HI # Read current ASID + MFC0_HAZARD + + /* + * NOTE: I used to only write the ASID bits of TLB_HI and not bother + * about the VPN bits (since we are about to invalidate that entry + * anyway), with this: + * and a1, a0, PG_ASID_MASK + * DMTC0 a1, COP_0_TLB_HI + * + * It turns out that this was a VERY BAD idea. Doing this seems to + * work, but leaves the TLB in an inconsistent state (although + * reading the TLB entry afterwards does not report anything wrong), + * and eventually causes TLBX exceptions - although, at the time of + * the exception, the TLB values obtained by TLBR are consistent and + * no duplicate is to be found. + * -- miod + */ + DMTC0 a0, COP_0_TLB_HI + MTC0_HAZARD + DMTC0 a0, COP_0_VADDR + MTC0_HAZARD + + TLBP + DMFC0 v0, COP_0_TLB_SET + MFC0_HAZARD + + bltz v0, 1f # Missing + NOP + + DMTC0 zero, COP_0_TLB_LO + MTC0_HAZARD + TLBW + +1: + DMTC0 a2, COP_0_TLB_HI # restore PID + MTC0_HAZARD + DMTC0 v1, COP_0_STATUS_REG # Restore the status register + MTC0_SR_IE_HAZARD + j ra + NOP +END(TLBOP(flush_addr)) /* } */ + +/* + * void tlb_update(vaddr_t, register_t); + * Update (or create) TLB entry for given address and ASID, and PTE. + */ +LEAF(TLBOP(update), 0) /* { */ + DMFC0 v1, COP_0_STATUS_REG # Save the status register. + MFC0_HAZARD + ori v0, v1, SR_INT_ENAB + xori v0, v0, SR_INT_ENAB + DMTC0 v0, COP_0_STATUS_REG # Disable interrupts + MTC0_SR_IE_HAZARD + DMFC0 a2, COP_0_TLB_HI # Read current ASID + MFC0_HAZARD + + DMTC0 a0, COP_0_TLB_HI + MTC0_HAZARD + DMTC0 a0, COP_0_VADDR + MTC0_HAZARD + + TLBP + DMFC0 v0, COP_0_TLB_SET + MFC0_HAZARD + + bgez v0, 1f + NOP + + /* Page not found: pick a random set */ + DMFC0 v0, COP_0_COUNT + MFC0_HAZARD + and v0, 3 + beqz v0, 9f + NOP + subu v0, 1 +9: + DMTC0 v0, COP_0_TLB_SET + MTC0_HAZARD + +1: + DMTC0 a1, COP_0_TLB_LO + MTC0_HAZARD + TLBW + + DMTC0 a2, COP_0_TLB_HI # restore PID + MTC0_HAZARD + DMTC0 v1, COP_0_STATUS_REG # Restore the status register + MTC0_SR_IE_HAZARD + + j ra + NOP +END(TLBOP(update)) /* } */ + +/* + * void tlb_read(int, struct tlb_entry *); + * Read the given TLB entry. On R8000, only the tlb_hi and tlb_lo0 fields are + * filled. + */ +LEAF(tlb_read, 0) /* { */ + DMFC0 v1, COP_0_STATUS_REG # Save the status register. + MFC0_HAZARD + ori v0, v1, SR_INT_ENAB + xori v0, v0, SR_INT_ENAB + DMTC0 v0, COP_0_STATUS_REG # Disable interrupts + MTC0_SR_IE_HAZARD + + DMFC0 a3, COP_0_TLB_HI # Get current PID + MFC0_HAZARD + + DMTC0 zero, COP_0_TLB_HI # Force ASID to zero so we don't need + MTC0_HAZARD # to hash the index + + dsrl a2, a0, 7 + DMTC0 a2, COP_0_TLB_SET + MTC0_HAZARD + dsll a0, PAGE_SHIFT + DMTC0 a0, COP_0_VADDR + MTC0_HAZARD + + TLBR + + DMFC0 a0, COP_0_TLB_HI + MFC0_HAZARD + DMFC0 a2, COP_0_TLB_LO + MFC0_HAZARD + + DMTC0 a3, COP_0_TLB_HI + MTC0_HAZARD + DMTC0 v1, COP_0_STATUS_REG # Restore the status register + MTC0_SR_IE_HAZARD + + sd a0, 8(a1) # tlb_hi + j ra + sd a2, 16(a1) # tlb_lo0 +END(tlb_read) /* } */ + +/* + * uint tlb_get_pid(void); + * Read the current TLB ASID. + */ +LEAF(tlb_get_pid, 0) /* { */ + DMFC0 v0, COP_0_TLB_HI # get PID + MFC0_HAZARD + and v0, PG_ASID_MASK + j ra + dsrl v0, PG_ASID_SHIFT +END(tlb_get_pid) /* } */ + +/* + * void tlb_set_pid(uint); + * Set the current TLB ASID. + */ +LEAF(TLBOP(set_pid), 0) /* { */ + DMFC0 v1, COP_0_STATUS_REG # Save the status register. + MFC0_HAZARD + ori v0, v1, SR_INT_ENAB + xori v0, v0, SR_INT_ENAB + DMTC0 v0, COP_0_STATUS_REG # Disable interrupts + MTC0_SR_IE_HAZARD + + dsll a1, a0, ICACHE_ASID_SHIFT + dsll a0, PG_ASID_SHIFT + DMTC0 a0, COP_0_TLB_HI + MTC0_HAZARD + DMTC0 a1, COP_0_ICACHE + MTC0_HAZARD + + DMTC0 v1, COP_0_STATUS_REG # Restore the status register + MTC0_SR_IE_HAZARD + + j ra + NOP +END(TLBOP(set_pid)) /* } */ + +/* + * void tlb_set_wired(uint32_t); + */ +LEAF(tlb_set_wired, 0) /* { */ + DMTC0 a0, COP_0_TFP_TLB_WIRED + MTC0_HAZARD + j ra + NOP +END(tlb_set_wired) /* } */ + +/* + * void tlb_set_gbase(vaddr_t, vsize_t); + */ +LEAF(tlb_set_gbase, 0) /* { */ + DMTC0 a0, COP_0_GBASE + MTC0_HAZARD + DMTC0 a1, COP_0_WORK1 + MTC0_HAZARD + j ra + NOP +END(tlb_set_gbase) /* } */ diff --git a/sys/arch/mips64/mips64/tlbhandler.S b/sys/arch/mips64/mips64/tlbhandler.S index dc46298b7b4..8ce1d03e0d6 100644 --- a/sys/arch/mips64/mips64/tlbhandler.S +++ b/sys/arch/mips64/mips64/tlbhandler.S @@ -1,4 +1,4 @@ -/* $OpenBSD: tlbhandler.S,v 1.36 2012/09/29 19:02:26 miod Exp $ */ +/* $OpenBSD: tlbhandler.S,v 1.37 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 1995-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -609,3 +609,12 @@ LEAF(tlb_set_page_mask, 0) j ra nop END(tlb_set_page_mask) + +/* + * Initialize the kernel page table pointer. + * This is a no-op on non-R8000 processors. + */ +LEAF(tlb_set_gbase, 0) + j ra + nop +END(tlb_set_gbase) diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c index bc0a3deea5f..ddd72637ce8 100644 --- a/sys/arch/mips64/mips64/trap.c +++ b/sys/arch/mips64/mips64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.86 2012/09/29 19:24:31 miod Exp $ */ +/* $OpenBSD: trap.c,v 1.87 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -129,6 +129,8 @@ extern int kdb_trap(int, db_regs_t *); #endif void ast(void); +extern void interrupt(struct trap_frame *); +void itsa(struct trap_frame *, struct cpu_info *, struct proc *, int); void trap(struct trap_frame *); #ifdef PTRACE int ptrace_read_insn(struct proc *, vaddr_t, uint32_t *); @@ -168,19 +170,21 @@ void trap(struct trap_frame *trapframe) { struct cpu_info *ci = curcpu(); - int type, i; - unsigned ucode = 0; struct proc *p = ci->ci_curproc; - vm_prot_t ftype; - extern vaddr_t onfault_table[]; - int onfault; - int typ = 0; - union sigval sv; - - trapdebug_enter(ci, trapframe, -1); + int type; type = (trapframe->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; + +#if defined(CPU_R8000) && !defined(DEBUG_INTERRUPT) + if (type != T_INT) +#endif + trapdebug_enter(ci, trapframe, -1); + +#ifdef CPU_R8000 + if (type != T_INT && type != T_SYSCALL) +#else if (type != T_SYSCALL) +#endif atomic_add_int(&uvmexp.traps, 1); if (USERMODE(trapframe->sr)) { type |= T_USER; @@ -190,7 +194,14 @@ trap(struct trap_frame *trapframe) * Enable hardware interrupts if they were on before the trap; * enable IPI interrupts only otherwise. */ - if (type != T_BREAK) { + switch (type) { +#ifdef CPU_R8000 + case T_INT: + case T_INT | T_USER: +#endif + case T_BREAK: + break; + default: if (ISSET(trapframe->sr, SR_INT_ENAB)) enableintr(); else { @@ -198,8 +209,66 @@ trap(struct trap_frame *trapframe) ENABLEIPI(); #endif } + break; } +#ifdef CPU_R8000 + /* + * Some exception causes on R8000 are actually detected by external + * circuitry, and as such are reported as external interrupts. + * On R8000 kernels, external interrupts vector to trap() instead of + * interrupt(), so that we can process these particular exceptions + * as if they were triggered as regular exceptions. + */ + if ((type & ~T_USER) == T_INT) { + /* + * Similar reality check as done in interrupt(), in case + * an interrupt occured between a write to COP_0_STATUS_REG + * and it taking effect. + */ + if (!ISSET(trapframe->sr, SR_INT_ENAB)) + return; + + if (trapframe->cause & CR_VCE) { +#ifndef DEBUG_INTERRUPT + trapdebug_enter(ci, trapframe, -1); +#endif + panic("VCE or TLBX"); + } + if (trapframe->cause & CR_FPE) { +#ifndef DEBUG_INTERRUPT + trapdebug_enter(ci, trapframe, -1); +#endif + itsa(trapframe, ci, p, T_FPE | (type & T_USER)); + cp0_reset_cause(CR_FPE); + } + if (trapframe->cause & CR_INT_MASK) + interrupt(trapframe); + + return; /* no userret */ + } else +#endif + itsa(trapframe, ci, p, type); + + if (type & T_USER) + userret(p); +} + +/* + * Handle a single exception. + */ +void +itsa(struct trap_frame *trapframe, struct cpu_info *ci, struct proc *p, + int type) +{ + int i; + unsigned ucode = 0; + vm_prot_t ftype; + extern vaddr_t onfault_table[]; + int onfault; + int typ = 0; + union sigval sv; + switch (type) { case T_TLB_MOD: /* check for kernel address */ @@ -267,9 +336,7 @@ trap(struct trap_frame *trapframe) panic("trap: utlbmod: unmanaged page"); pmap_set_modify(pg); KERNEL_UNLOCK(); - if (!USERMODE(trapframe->sr)) - return; - goto out; + return; } case T_TLB_LD_MISS: @@ -349,11 +416,8 @@ fault_common: rv = EFAULT; } KERNEL_UNLOCK(); - if (rv == 0) { - if (!USERMODE(trapframe->sr)) - return; - goto out; - } + if (rv == 0) + return; if (!USERMODE(trapframe->sr)) { if (onfault != 0) { p->p_addr->u_pcb.pcb_onfault = 0; @@ -363,9 +427,6 @@ fault_common: goto err; } -#ifdef ADEBUG -printf("SIG-SEGV @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapframe->ra); -#endif ucode = ftype; i = SIGSEGV; typ = SEGV_MAPERR; @@ -377,18 +438,12 @@ printf("SIG-SEGV @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr ucode = 0; /* XXX should be VM_PROT_something */ i = SIGBUS; typ = BUS_ADRALN; -#ifdef ADEBUG -printf("SIG-BUSA @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapframe->ra); -#endif break; case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ ucode = 0; /* XXX should be VM_PROT_something */ i = SIGBUS; typ = BUS_OBJERR; -#ifdef ADEBUG -printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapframe->ra); -#endif break; case T_SYSCALL+T_USER: @@ -584,7 +639,7 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr (void)uvm_map_protect(map, p->p_md.md_fppgva, p->p_md.md_fppgva + PAGE_SIZE, UVM_PROT_NONE, FALSE); - goto out; + return; } /* FALLTHROUGH */ #endif @@ -593,7 +648,6 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr i = SIGTRAP; break; } - break; } @@ -609,7 +663,7 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr #ifdef RM7K_PERFCNTR if (rm7k_watchintr(trapframe)) { /* Return to user, don't add any more overhead */ - goto out; + return; } #endif i = SIGTRAP; @@ -643,7 +697,7 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr trapframe->a2, trapframe->a3); locr0->v0 = -result; /* Return to user, don't add any more overhead */ - goto out; + return; } else #endif /* @@ -683,7 +737,7 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr #else enable_fpu(p); #endif - goto out; + return; case T_FPE: printf("FPU Trap: PC %x CR %x SR %x\n", @@ -692,7 +746,7 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr case T_FPE+T_USER: MipsFPTrap(trapframe); - goto out; + return; case T_OVFLOW+T_USER: i = SIGFPE; @@ -770,11 +824,6 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr KERNEL_LOCK(); trapsignal(p, i, ucode, typ, sv); KERNEL_UNLOCK(); -out: - /* - * Note: we should only get here if returning to user mode. - */ - userret(p); } void @@ -836,10 +885,17 @@ trapDump(const char *msg) if (ptrp->cause == 0) break; +#ifdef CPU_R8000 + (*pr)("%s: PC %p CR 0x%016lx SR 0x%011lx\n", + trap_type[(ptrp->cause & CR_EXC_CODE) >> + CR_EXC_CODE_SHIFT], + ptrp->pc, ptrp->cause, ptrp->status); +#else (*pr)("%s: PC %p CR 0x%08lx SR 0x%08lx\n", trap_type[(ptrp->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT], ptrp->pc, ptrp->cause, ptrp->status); +#endif (*pr)(" RA %p SP %p ADR %p\n", ptrp->ra, ptrp->sp, ptrp->vadr); } @@ -1099,9 +1155,15 @@ stacktrace(regs) stacktrace_subr(regs, 6, printf); } +#ifdef CPU_R8000 +#define VALID_ADDRESS(va) \ + (((va) >= VM_MIN_KERNEL_ADDRESS && (va) < VM_MAX_KERNEL_ADDRESS) || \ + IS_XKPHYS(va)) +#else #define VALID_ADDRESS(va) \ (((va) >= VM_MIN_KERNEL_ADDRESS && (va) < VM_MAX_KERNEL_ADDRESS) || \ IS_XKPHYS(va) || ((va) >= CKSEG0_BASE && (va) < CKSEG1_BASE)) +#endif void stacktrace_subr(struct trap_frame *regs, int count, @@ -1279,10 +1341,10 @@ loop: (*pr)(" ra %p sp %p, sz %d\n", ra, sp, stksize); if (subr == (vaddr_t)k_intr || subr == (vaddr_t)k_general) { - if (subr == (vaddr_t)k_intr) - (*pr)("(KERNEL INTERRUPT)\n"); - else + if (subr == (vaddr_t)k_general) (*pr)("(KERNEL TRAP)\n"); + else + (*pr)("(KERNEL INTERRUPT)\n"); sp = *(register_t *)sp; pc = ((struct trap_frame *)sp)->pc; ra = ((struct trap_frame *)sp)->ra; diff --git a/sys/arch/mips64/mips64/vm_machdep.c b/sys/arch/mips64/mips64/vm_machdep.c index ff823b6aea9..71b53aa0bfa 100644 --- a/sys/arch/mips64/mips64/vm_machdep.c +++ b/sys/arch/mips64/mips64/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.25 2012/03/19 21:56:49 miod Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.26 2012/09/29 21:37:03 miod Exp $ */ /* * Copyright (c) 1988 University of Utah. * Copyright (c) 1992, 1993 @@ -77,12 +77,14 @@ cpu_fork(p1, p2, stack, stacksize, func, arg) p2->p_md.md_uarea = (vaddr_t)p2->p_addr; pmap_extract(pmap_kernel(), p2->p_md.md_uarea, &pa); #ifdef __sgi__ +#ifndef CPU_R8000 /* * Return a CKSEG0 address whenever possible. */ if (pa < CKSEG_SIZE) p2->p_addr = (void *)PHYS_TO_CKSEG0(pa); else +#endif p2->p_addr = (void *)PHYS_TO_XKPHYS(pa, CCA_CACHED); #else p2->p_addr = (void *)PHYS_TO_XKPHYS(pa, CCA_CACHED); |