/branches/sparc/kernel/kernel.config |
---|
76,9 → 76,10 |
@ "opteron" Opteron |
! [ARCH=amd64] MACHINE (choice) |
# CPU type |
@ "us" UltraSPARC I-II subarchitecture |
@ "us3" UltraSPARC III-IV subarchitecture |
# UltraSPARC (sub)architecture |
@ "us" UltraSPARC I-II |
@ "us3" UltraSPARC III-IV |
@ "sun4v" Niagara (sun4v) |
! [ARCH=sparc64] MACHINE (choice) |
# Machine type |
/branches/sparc/kernel/arch/sparc64/include/regdef.h |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/include/sun4v/regdef.h |
---|
0,0 → 1,68 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* Copyright (c) 2008 Pavel Rimsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4v_REGDEF_H_ |
#define KERN_sparc64_sun4v_REGDEF_H_ |
#define PSTATE_PRIV_BIT (1 << 2) |
/* |
#define PSTATE_IE_BIT (1 << 1) |
#define PSTATE_AM_BIT (1 << 3) |
#define PSTATE_AG_BIT (1 << 0) |
#define PSTATE_IG_BIT (1 << 11) |
#define PSTATE_MG_BIT (1 << 10) |
#define PSTATE_PRIV_BIT (1 << 2) |
#define PSTATE_PEF_BIT (1 << 4) |
#define TSTATE_PSTATE_SHIFT 8 |
#define TSTATE_PRIV_BIT (PSTATE_PRIV_BIT << TSTATE_PSTATE_SHIFT) |
#define TSTATE_IE_BIT (PSTATE_IE_BIT << TSTATE_PSTATE_SHIFT) |
#define TSTATE_PEF_BIT (PSTATE_PEF_BIT << TSTATE_PSTATE_SHIFT) |
#define TSTATE_CWP_MASK 0x1f |
#define WSTATE_NORMAL(n) (n) |
#define WSTATE_OTHER(n) ((n) << 3) |
*/ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/sun4v/hypercall.h |
---|
0,0 → 1,184 |
/* |
* Copyright (c) 2008 Pavel Rimsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** |
* @file |
* @brief Macros, constants and functions needed to perform a call to the |
* hypervisor API. For details and terminology see this document: |
* UltraSPARC Virtual Machine Specification (The Hypervisor API |
* specification for Logical Domains). |
* |
*/ |
#ifndef KERN_sparc64_sun4v_HYPERCALL_H_ |
#define KERN_sparc64_sun4v_HYPERCALL_H_ |
/* SW trap numbers for hyperfast traps */ |
#define FAST_TRAP 0x80 |
#define MMU_MAP_ADDR 0x83 |
#define MMU_UNMAP_ADDR 0x84 |
/* function codes for fast traps */ |
#define MACH_DESC 0x01 |
#define CPU_START 0x10 |
#define CPU_STOP 0x11 |
#define CPU_YIELD 0x12 |
#define CPU_MYID 0x16 |
#define CPU_STATE 0x17 |
#define CPU_SET_RTBA 0x18 |
#define CPU_GET_RTBA 0x19 |
#define MMU_TSB_CTX0 0x20 |
#define MMU_TSB_CTXNON0 0x21 |
#define MMU_DEMAP_PAGE 0x22 |
#define MMU_DEMAP_CTX 0x23 |
#define MMU_DEMAP_ALL 0x24 |
#define MMU_MAP_PERM_ADDR 0x25 |
#define MMU_FAULT_AREA_CONF 0x26 |
#define MMU_ENABLE 0x27 |
#define MMU_UNMAP_PERM_ADDR 0x28 |
#define MMU_TSB_CTX0_INFO 0x29 |
#define MMU_TSB_CTXNON0_INFO 0x2a |
#define MMU_FAULT_AREA_INFO 0x2b |
#define CPU_MONDO_SEND 0x42 |
#define CONS_GETCHAR 0x60 |
#define CONS_PUTCHAR 0x61 |
/** |
* Performs a hyperfast hypervisor API call from the assembly language code. |
* Expects the registers %o1-%o4 are properly filled with the arguments of the |
* call. |
* |
* @param function_number hyperfast call function number |
*/ |
#define __HYPERCALL_FAST(function_number) \ |
set function_number, %o5; \ |
ta FAST_TRAP; |
/** |
* Performs a fast hypervisor API call from the assembly language code. |
* Expects the registers %o1-%o4 are properly filled with the arguments of the |
* call. |
* |
* @param sw_trap_number software trap number |
*/ |
#define __HYPERCALL_HYPERFAST(sw_trap_number) \ |
ta (sw_trap_number); |
#ifndef __ASM__ |
/* |
* Macros to be used from the C-language code; __hypercall_fastN performs |
* a fast hypervisor API call taking exactly N arguments. |
*/ |
#define __hypercall_fast0(function_number) \ |
__hypercall_fast(0, 0, 0, 0, 0, function_number) |
#define __hypercall_fast1(function_number, p1) \ |
__hypercall_fast(p1, 0, 0, 0, 0, function_number) |
#define __hypercall_fast2(function_number, p1, p2) \ |
__hypercall_fast(p1, p2, 0, 0, 0, function_number) |
#define __hypercall_fast3(function_number, p1, p2, p3) \ |
__hypercall_fast(p1, p2, p3, 0, 0, function_number) |
#define __hypercall_fast4(function_number, p1, p2, p3, p4) \ |
__hypercall_fast(p1, p2, p3, p4, 0, function_number) |
#define __hypercall_fast5(function_number, p1, p2, p3, p4, p5) \ |
__hypercall_fast(p1, p2, p3, p4, p5, function_number) |
/** |
* Performs a fast hypervisor API call. |
* |
* @param p1 the 1st argument of the hypervisor API call |
* @param p2 the 2nd argument of the hypervisor API call |
* @param p3 the 3rd argument of the hypervisor API call |
* @param p4 the 4th argument of the hypervisor API call |
* @param p5 the 5th argument of the hypervisor API call |
* @param function_number function number of the call |
*/ |
static inline uint64_t |
__hypercall_fast(const uint64_t p1, const uint64_t p2, const uint64_t p3, |
const uint64_t p4, const uint64_t p5, const uint64_t function_number) |
{ |
register uint64_t a6 asm("o5") = function_number; |
register uint64_t a1 asm("o0") = p1; |
register uint64_t a2 asm("o1") = p2; |
register uint64_t a3 asm("o2") = p3; |
register uint64_t a4 asm("o3") = p4; |
register uint64_t a5 asm("o4") = p5; |
asm volatile ( |
"ta %7\n" |
: "=r" (a1) |
: "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), |
"i" (FAST_TRAP) |
: "memory" |
); |
return a1; |
} |
/** |
* Performs a hyperfast hypervisor API call. |
* |
* @param p1 the 1st argument of the hypervisor API call |
* @param p2 the 2nd argument of the hypervisor API call |
* @param p3 the 3rd argument of the hypervisor API call |
* @param p4 the 4th argument of the hypervisor API call |
* @param p5 the 5th argument of the hypervisor API call |
* @param sw_trap_number software trap number |
*/ |
static inline uint64_t |
__hypercall_hyperfast(const uint64_t p1, const uint64_t p2, const uint64_t p3, |
const uint64_t p4, const uint64_t p5, const uint64_t sw_trap_number) |
{ |
register uint64_t a1 asm("o0") = p1; |
register uint64_t a2 asm("o1") = p2; |
register uint64_t a3 asm("o2") = p3; |
register uint64_t a4 asm("o3") = p4; |
register uint64_t a5 asm("o4") = p5; |
asm volatile ( |
"ta %6\n" |
: "=r" (a1) |
: "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5), |
"i" (sw_trap_number) |
: "memory" |
); |
return a1; |
} |
#endif /* ASM */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/interrupt.h |
---|
37,7 → 37,7 |
#define KERN_sparc64_INTERRUPT_H_ |
#include <arch/types.h> |
#include <arch/regdef.h> |
#include <arch/sun4u/regdef.h> |
#define IVT_ITEMS 15 |
#define IVT_FIRST 1 |
/branches/sparc/kernel/arch/sparc64/include/arch.h |
---|
39,9 → 39,6 |
#define ASI_AIUP 0x10 /** Access to primary context with user privileges. */ |
#define ASI_AIUS 0x11 /** Access to secondary context with user privileges. */ |
#define ASI_NUCLEUS_QUAD_LDD 0x24 /** ASI for 16-byte atomic loads. */ |
#define ASI_DCACHE_TAG 0x47 /** ASI D-Cache Tag. */ |
#define ASI_ICBUS_CONFIG 0x4a /** ASI of the UPA_CONFIG/FIREPLANE_CONFIG register. */ |
#define NWINDOWS 8 /** Number of register window sets. */ |
/branches/sparc/kernel/arch/sparc64/include/trap/mmu.h |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/include/trap/sun4v/mmu.h |
---|
0,0 → 1,85 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* Copyright (c) 2008 Pavel Rimsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64interrupt |
* @{ |
*/ |
/** |
* @file |
* @brief This file contains fast MMU trap handlers. |
*/ |
#ifndef KERN_sparc64_sun4v_MMU_TRAP_H_ |
#define KERN_sparc64_sun4v_MMU_TRAP_H_ |
#include <arch/stack.h> |
#include <arch/sun4v/regdef.h> |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4v/mmu.h> |
#include <arch/mm/sun4v/tte.h> |
#include <arch/trap/regwin.h> |
#ifdef CONFIG_TSB |
#include <arch/mm/tsb.h> |
#endif |
#define TT_FAST_INSTRUCTION_ACCESS_MMU_MISS 0x64 |
#define TT_FAST_DATA_ACCESS_MMU_MISS 0x68 |
#define TT_FAST_DATA_ACCESS_PROTECTION 0x6c |
#define FAST_MMU_HANDLER_SIZE 128 |
#ifdef __ASM__ |
.macro FAST_INSTRUCTION_ACCESS_MMU_MISS_HANDLER |
.endm |
/* |
* So far it is here only to process the trap which occurs when the kernel |
* needs to access the bootinfo structure, which is placed in the bootloader |
* memory (i.e. before address 0x400000). |
*/ |
.macro FAST_DATA_ACCESS_MMU_MISS_HANDLER tl |
set 0x8000, %o0 |
set 0x0, %o1 |
setx 0x80000000804087c3, %g1, %o2 |
set 0x3, %o3 |
ta 0x83 |
retry |
.endm |
.macro FAST_DATA_ACCESS_PROTECTION_HANDLER tl |
.endm |
#endif /* __ASM__ */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/trap/sun4u/mmu.h |
---|
0,0 → 1,184 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64interrupt |
* @{ |
*/ |
/** |
* @file |
* @brief This file contains fast MMU trap handlers. |
*/ |
#ifndef KERN_sparc64_sun4u_MMU_TRAP_H_ |
#define KERN_sparc64_sun4u_MMU_TRAP_H_ |
#include <arch/stack.h> |
#include <arch/sun4u/regdef.h> |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4u/tlb.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/mm/sun4u/tte.h> |
#include <arch/trap/regwin.h> |
#include <arch/sun4u/arch.h> |
#ifdef CONFIG_TSB |
#include <arch/mm/tsb.h> |
#endif |
#define TT_FAST_INSTRUCTION_ACCESS_MMU_MISS 0x64 |
#define TT_FAST_DATA_ACCESS_MMU_MISS 0x68 |
#define TT_FAST_DATA_ACCESS_PROTECTION 0x6c |
#define FAST_MMU_HANDLER_SIZE 128 |
#ifdef __ASM__ |
.macro FAST_INSTRUCTION_ACCESS_MMU_MISS_HANDLER |
/* |
* First, try to refill TLB from TSB. |
*/ |
#ifdef CONFIG_TSB |
ldxa [%g0] ASI_IMMU, %g1 ! read TSB Tag Target Register |
ldxa [%g0] ASI_IMMU_TSB_8KB_PTR_REG, %g2 ! read TSB 8K Pointer |
ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %g4 ! 16-byte atomic load into %g4 and %g5 |
cmp %g1, %g4 ! is this the entry we are looking for? |
bne,pn %xcc, 0f |
nop |
stxa %g5, [%g0] ASI_ITLB_DATA_IN_REG ! copy mapping from ITSB to ITLB |
retry |
#endif |
0: |
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_AG_BIT, %pstate |
PREEMPTIBLE_HANDLER fast_instruction_access_mmu_miss |
.endm |
.macro FAST_DATA_ACCESS_MMU_MISS_HANDLER tl |
/* |
* First, try to refill TLB from TSB. |
*/ |
#ifdef CONFIG_TSB |
ldxa [%g0] ASI_DMMU, %g1 ! read TSB Tag Target Register |
srlx %g1, TSB_TAG_TARGET_CONTEXT_SHIFT, %g2 ! is this a kernel miss? |
brz,pn %g2, 0f |
ldxa [%g0] ASI_DMMU_TSB_8KB_PTR_REG, %g3 ! read TSB 8K Pointer |
ldda [%g3] ASI_NUCLEUS_QUAD_LDD, %g4 ! 16-byte atomic load into %g4 and %g5 |
cmp %g1, %g4 ! is this the entry we are looking for? |
bne,pn %xcc, 0f |
nop |
stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG ! copy mapping from DTSB to DTLB |
retry |
#endif |
/* |
* Second, test if it is the portion of the kernel address space |
* which is faulting. If that is the case, immediately create |
* identity mapping for that page in DTLB. VPN 0 is excluded from |
* this treatment. |
* |
* Note that branch-delay slots are used in order to save space. |
*/ |
0: |
mov VA_DMMU_TAG_ACCESS, %g1 |
ldxa [%g1] ASI_DMMU, %g1 ! read the faulting Context and VPN |
set TLB_TAG_ACCESS_CONTEXT_MASK, %g2 |
andcc %g1, %g2, %g3 ! get Context |
bnz 0f ! Context is non-zero |
andncc %g1, %g2, %g3 ! get page address into %g3 |
bz 0f ! page address is zero |
sethi %hi(kernel_8k_tlb_data_template), %g2 |
ldx [%g2 + %lo(kernel_8k_tlb_data_template)], %g2 |
or %g3, %g2, %g2 |
stxa %g2, [%g0] ASI_DTLB_DATA_IN_REG ! identity map the kernel page |
retry |
/* |
* Third, catch and handle special cases when the trap is caused by |
* the userspace register window spill or fill handler. In case |
* one of these two traps caused this trap, we just lower the trap |
* level and service the DTLB miss. In the end, we restart |
* the offending SAVE or RESTORE. |
*/ |
0: |
.if (\tl > 0) |
wrpr %g0, 1, %tl |
.endif |
/* |
* Switch from the MM globals. |
*/ |
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_AG_BIT, %pstate |
/* |
* Read the Tag Access register for the higher-level handler. |
* This is necessary to survive nested DTLB misses. |
*/ |
mov VA_DMMU_TAG_ACCESS, %g2 |
ldxa [%g2] ASI_DMMU, %g2 |
/* |
* g2 will be passed as an argument to fast_data_access_mmu_miss(). |
*/ |
PREEMPTIBLE_HANDLER fast_data_access_mmu_miss |
.endm |
.macro FAST_DATA_ACCESS_PROTECTION_HANDLER tl |
/* |
* The same special case as in FAST_DATA_ACCESS_MMU_MISS_HANDLER. |
*/ |
.if (\tl > 0) |
wrpr %g0, 1, %tl |
.endif |
/* |
* Switch from the MM globals. |
*/ |
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_AG_BIT, %pstate |
/* |
* Read the Tag Access register for the higher-level handler. |
* This is necessary to survive nested DTLB misses. |
*/ |
mov VA_DMMU_TAG_ACCESS, %g2 |
ldxa [%g2] ASI_DMMU, %g2 |
/* |
* g2 will be passed as an argument to fast_data_access_mmu_miss(). |
*/ |
PREEMPTIBLE_HANDLER fast_data_access_protection |
.endm |
#endif /* __ASM__ */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/mm/tte.h |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/include/mm/mmu.h |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/include/mm/sun4v/tte.h |
---|
0,0 → 1,53 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64mm |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4v_TTE_H_ |
#define KERN_sparc64_sun4v_TTE_H_ |
#define TTE_V_SHIFT 63 /**< valid */ |
#define TTE_TADDR_SHIFT 13 /**< target address */ |
#define TTE_CP_SHIFT 10 /**< cacheable physically */ |
#define TTE_CV_SHIFT 9 /**< caheable virtually */ |
#define TTE_P_SHIFT 8 /**< privileged */ |
#define TTE_EP_SHIFT 7 /**< execute permission */ |
#define TTE_W_SHIFT 6 /**< writable */ |
#define TTE_SZ_SHIFT 0 /**< size */ |
#define MMU_FLAG_ITLB 2 /**< operation applies to ITLB */ |
#define MMU_FLAG_DTLB 1 /**< operation applies to DTLB */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/mm/sun4v/mmu.h |
---|
0,0 → 1,45 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* Copyright (c) 2008 Pavel Rimsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64mm |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4v_MMU_H_ |
#define KERN_sparc64_sun4v_MMU_H_ |
#define VA_PRIMARY_CONTEXT_REG 0x8 /**< DMMU primary context registeri VA. */ |
#define ASI_PRIMARY_CONTEXT_REG 0x21 /**< DMMU primary context register ASI. */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/mm/tlb.h |
---|
35,17 → 35,6 |
#ifndef KERN_sparc64_TLB_H_ |
#define KERN_sparc64_TLB_H_ |
#if defined (US) |
#define ITLB_ENTRY_COUNT 64 |
#define DTLB_ENTRY_COUNT 64 |
#define DTLB_MAX_LOCKED_ENTRIES DTLB_ENTRY_COUNT |
#endif |
/** TLB_DSMALL is the only of the three DMMUs that can hold locked entries. */ |
#if defined (US3) |
#define DTLB_MAX_LOCKED_ENTRIES 16 |
#endif |
#define MEM_CONTEXT_KERNEL 0 |
#define MEM_CONTEXT_TEMP 1 |
55,635 → 44,9 |
#define PAGESIZE_512K 2 |
#define PAGESIZE_4M 3 |
/** Bit width of the TLB-locked portion of kernel address space. */ |
#define KERNEL_PAGE_WIDTH 22 /* 4M */ |
/* TLB Demap Operation types. */ |
#define TLB_DEMAP_PAGE 0 |
#define TLB_DEMAP_CONTEXT 1 |
#if defined (US3) |
#define TLB_DEMAP_ALL 2 |
#endif |
#define TLB_DEMAP_TYPE_SHIFT 6 |
/* TLB Demap Operation Context register encodings. */ |
#define TLB_DEMAP_PRIMARY 0 |
#define TLB_DEMAP_SECONDARY 1 |
#define TLB_DEMAP_NUCLEUS 2 |
/* There are more TLBs in one MMU in US3, their codes are defined here. */ |
#if defined (US3) |
/* D-MMU: one small (16-entry) TLB and two big (512-entry) TLBs */ |
#define TLB_DSMALL 0 |
#define TLB_DBIG_0 2 |
#define TLB_DBIG_1 3 |
/* I-MMU: one small (16-entry) TLB and one big TLB */ |
#define TLB_ISMALL 0 |
#define TLB_IBIG 2 |
#endif |
#define TLB_DEMAP_CONTEXT_SHIFT 4 |
/* TLB Tag Access shifts */ |
#define TLB_TAG_ACCESS_CONTEXT_SHIFT 0 |
#define TLB_TAG_ACCESS_CONTEXT_MASK ((1 << 13) - 1) |
#define TLB_TAG_ACCESS_VPN_SHIFT 13 |
#ifndef __ASM__ |
#include <arch/mm/tte.h> |
#include <arch/mm/mmu.h> |
#include <arch/mm/page.h> |
#include <arch/asm.h> |
#include <arch/barrier.h> |
#include <arch/types.h> |
#include <arch/register.h> |
#include <arch/cpu.h> |
union tlb_context_reg { |
uint64_t v; |
struct { |
unsigned long : 51; |
unsigned context : 13; /**< Context/ASID. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_context_reg tlb_context_reg_t; |
/** I-/D-TLB Data In/Access Register type. */ |
typedef tte_data_t tlb_data_t; |
/** I-/D-TLB Data Access Address in Alternate Space. */ |
#if defined (US) |
union tlb_data_access_addr { |
uint64_t value; |
struct { |
uint64_t : 55; |
unsigned tlb_entry : 6; |
unsigned : 3; |
} __attribute__ ((packed)); |
}; |
typedef union tlb_data_access_addr dtlb_data_access_addr_t; |
typedef union tlb_data_access_addr dtlb_tag_read_addr_t; |
typedef union tlb_data_access_addr itlb_data_access_addr_t; |
typedef union tlb_data_access_addr itlb_tag_read_addr_t; |
#elif defined (US3) |
/* |
* In US3, I-MMU and D-MMU have different formats of the data |
* access register virtual address. In the corresponding |
* structures the member variable for the entry number is |
* called "local_tlb_entry" - it contrasts with the "tlb_entry" |
* for the US data access register VA structure. The rationale |
* behind this is to prevent careless mistakes in the code |
* caused by setting only the entry number and not the TLB |
* number in the US3 code (when taking the code from US). |
*/ |
union dtlb_data_access_addr { |
uint64_t value; |
struct { |
uint64_t : 45; |
unsigned : 1; |
unsigned tlb_number : 2; |
unsigned : 4; |
unsigned local_tlb_entry : 9; |
unsigned : 3; |
} __attribute__ ((packed)); |
}; |
typedef union dtlb_data_access_addr dtlb_data_access_addr_t; |
typedef union dtlb_data_access_addr dtlb_tag_read_addr_t; |
union itlb_data_access_addr { |
uint64_t value; |
struct { |
uint64_t : 45; |
unsigned : 1; |
unsigned tlb_number : 2; |
unsigned : 6; |
unsigned local_tlb_entry : 7; |
unsigned : 3; |
} __attribute__ ((packed)); |
}; |
typedef union itlb_data_access_addr itlb_data_access_addr_t; |
typedef union itlb_data_access_addr itlb_tag_read_addr_t; |
#endif |
/** I-/D-TLB Tag Read Register. */ |
union tlb_tag_read_reg { |
uint64_t value; |
struct { |
uint64_t vpn : 51; /**< Virtual Address bits 63:13. */ |
unsigned context : 13; /**< Context identifier. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_tag_read_reg tlb_tag_read_reg_t; |
typedef union tlb_tag_read_reg tlb_tag_access_reg_t; |
/** TLB Demap Operation Address. */ |
union tlb_demap_addr { |
uint64_t value; |
struct { |
uint64_t vpn: 51; /**< Virtual Address bits 63:13. */ |
#if defined (US) |
unsigned : 6; /**< Ignored. */ |
unsigned type : 1; /**< The type of demap operation. */ |
#elif defined (US3) |
unsigned : 5; /**< Ignored. */ |
unsigned type: 2; /**< The type of demap operation. */ |
#endif |
unsigned context : 2; /**< Context register selection. */ |
unsigned : 4; /**< Zero. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_demap_addr tlb_demap_addr_t; |
/** TLB Synchronous Fault Status Register. */ |
union tlb_sfsr_reg { |
uint64_t value; |
struct { |
#if defined (US) |
unsigned long : 40; /**< Implementation dependent. */ |
unsigned asi : 8; /**< ASI. */ |
unsigned : 2; |
unsigned ft : 7; /**< Fault type. */ |
#elif defined (US3) |
unsigned long : 39; /**< Implementation dependent. */ |
unsigned nf : 1; /**< Non-faulting load. */ |
unsigned asi : 8; /**< ASI. */ |
unsigned tm : 1; /**< I-TLB miss. */ |
unsigned : 3; /**< Reserved. */ |
unsigned ft : 5; /**< Fault type. */ |
#endif |
unsigned e : 1; /**< Side-effect bit. */ |
unsigned ct : 2; /**< Context Register selection. */ |
unsigned pr : 1; /**< Privilege bit. */ |
unsigned w : 1; /**< Write bit. */ |
unsigned ow : 1; /**< Overwrite bit. */ |
unsigned fv : 1; /**< Fault Valid bit. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_sfsr_reg tlb_sfsr_reg_t; |
#if defined (US3) |
/* |
* Functions for determining the number of entries in TLBs. They either return |
* a constant value or a value based on the CPU autodetection. |
*/ |
/** |
* Determine the number of entries in the DMMU's small TLB. |
*/ |
static inline uint16_t tlb_dsmall_size(void) |
{ |
return 16; |
} |
/** |
* Determine the number of entries in each DMMU's big TLB. |
*/ |
static inline uint16_t tlb_dbig_size(void) |
{ |
return 512; |
} |
/** |
* Determine the number of entries in the IMMU's small TLB. |
*/ |
static inline uint16_t tlb_ismall_size(void) |
{ |
return 16; |
} |
/** |
* Determine the number of entries in the IMMU's big TLB. |
*/ |
static inline uint16_t tlb_ibig_size(void) |
{ |
if (((ver_reg_t) ver_read()).impl == IMPL_ULTRASPARCIV_PLUS) |
return 512; |
else |
return 128; |
} |
#endif |
/** Read MMU Primary Context Register. |
* |
* @return Current value of Primary Context Register. |
*/ |
static inline uint64_t mmu_primary_context_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_PRIMARY_CONTEXT_REG); |
} |
/** Write MMU Primary Context Register. |
* |
* @param v New value of Primary Context Register. |
*/ |
static inline void mmu_primary_context_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_PRIMARY_CONTEXT_REG, v); |
flush_pipeline(); |
} |
/** Read MMU Secondary Context Register. |
* |
* @return Current value of Secondary Context Register. |
*/ |
static inline uint64_t mmu_secondary_context_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_SECONDARY_CONTEXT_REG); |
} |
/** Write MMU Primary Context Register. |
* |
* @param v New value of Primary Context Register. |
*/ |
static inline void mmu_secondary_context_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_SECONDARY_CONTEXT_REG, v); |
flush_pipeline(); |
} |
#if defined (US) |
/** Read IMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Data Access |
* Register. |
*/ |
static inline uint64_t itlb_data_access_read(index_t entry) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write IMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void itlb_data_access_write(index_t entry, uint64_t value) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value); |
flush_pipeline(); |
} |
/** Read DMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Data Access |
* Register. |
*/ |
static inline uint64_t dtlb_data_access_read(index_t entry) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write DMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void dtlb_data_access_write(index_t entry, uint64_t value) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
asi_u64_write(ASI_DTLB_DATA_ACCESS_REG, reg.value, value); |
membar(); |
} |
/** Read IMMU TLB Tag Read Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Tag Read Register. |
*/ |
static inline uint64_t itlb_tag_read_read(index_t entry) |
{ |
itlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_TAG_READ_REG, tag.value); |
} |
/** Read DMMU TLB Tag Read Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Tag Read Register. |
*/ |
static inline uint64_t dtlb_tag_read_read(index_t entry) |
{ |
dtlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value); |
} |
#elif defined (US3) |
/** Read IMMU TLB Data Access Register. |
* |
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Data Access |
* Register. |
*/ |
static inline uint64_t itlb_data_access_read(int tlb, index_t entry) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write IMMU TLB Data Access Register. |
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG) |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void itlb_data_access_write(int tlb, index_t entry, |
uint64_t value) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value); |
flush_pipeline(); |
} |
/** Read DMMU TLB Data Access Register. |
* |
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG, TLB_DBIG) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Data Access |
* Register. |
*/ |
static inline uint64_t dtlb_data_access_read(int tlb, index_t entry) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write DMMU TLB Data Access Register. |
* |
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1) |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void dtlb_data_access_write(int tlb, index_t entry, |
uint64_t value) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
asi_u64_write(ASI_DTLB_DATA_ACCESS_REG, reg.value, value); |
membar(); |
} |
/** Read IMMU TLB Tag Read Register. |
* |
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Tag Read Register. |
*/ |
static inline uint64_t itlb_tag_read_read(int tlb, index_t entry) |
{ |
itlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_number = tlb; |
tag.local_tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_TAG_READ_REG, tag.value); |
} |
/** Read DMMU TLB Tag Read Register. |
* |
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Tag Read Register. |
*/ |
static inline uint64_t dtlb_tag_read_read(int tlb, index_t entry) |
{ |
dtlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_number = tlb; |
tag.local_tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value); |
} |
#endif |
/** Write IMMU TLB Tag Access Register. |
* |
* @param v Value to be written. |
*/ |
static inline void itlb_tag_access_write(uint64_t v) |
{ |
asi_u64_write(ASI_IMMU, VA_IMMU_TAG_ACCESS, v); |
flush_pipeline(); |
} |
/** Read IMMU TLB Tag Access Register. |
* |
* @return Current value of IMMU TLB Tag Access Register. |
*/ |
static inline uint64_t itlb_tag_access_read(void) |
{ |
return asi_u64_read(ASI_IMMU, VA_IMMU_TAG_ACCESS); |
} |
/** Write DMMU TLB Tag Access Register. |
* |
* @param v Value to be written. |
*/ |
static inline void dtlb_tag_access_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_DMMU_TAG_ACCESS, v); |
membar(); |
} |
/** Read DMMU TLB Tag Access Register. |
* |
* @return Current value of DMMU TLB Tag Access Register. |
*/ |
static inline uint64_t dtlb_tag_access_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_DMMU_TAG_ACCESS); |
} |
/** Write IMMU TLB Data in Register. |
* |
* @param v Value to be written. |
*/ |
static inline void itlb_data_in_write(uint64_t v) |
{ |
asi_u64_write(ASI_ITLB_DATA_IN_REG, 0, v); |
flush_pipeline(); |
} |
/** Write DMMU TLB Data in Register. |
* |
* @param v Value to be written. |
*/ |
static inline void dtlb_data_in_write(uint64_t v) |
{ |
asi_u64_write(ASI_DTLB_DATA_IN_REG, 0, v); |
membar(); |
} |
/** Read ITLB Synchronous Fault Status Register. |
* |
* @return Current content of I-SFSR register. |
*/ |
static inline uint64_t itlb_sfsr_read(void) |
{ |
return asi_u64_read(ASI_IMMU, VA_IMMU_SFSR); |
} |
/** Write ITLB Synchronous Fault Status Register. |
* |
* @param v New value of I-SFSR register. |
*/ |
static inline void itlb_sfsr_write(uint64_t v) |
{ |
asi_u64_write(ASI_IMMU, VA_IMMU_SFSR, v); |
flush_pipeline(); |
} |
/** Read DTLB Synchronous Fault Status Register. |
* |
* @return Current content of D-SFSR register. |
*/ |
static inline uint64_t dtlb_sfsr_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_DMMU_SFSR); |
} |
/** Write DTLB Synchronous Fault Status Register. |
* |
* @param v New value of D-SFSR register. |
*/ |
static inline void dtlb_sfsr_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_DMMU_SFSR, v); |
membar(); |
} |
/** Read DTLB Synchronous Fault Address Register. |
* |
* @return Current content of D-SFAR register. |
*/ |
static inline uint64_t dtlb_sfar_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_DMMU_SFAR); |
} |
/** Perform IMMU TLB Demap Operation. |
* |
* @param type Selects between context and page demap (and entire MMU |
* demap on US3). |
* @param context_encoding Specifies which Context register has Context ID for |
* demap. |
* @param page Address which is on the page to be demapped. |
*/ |
static inline void itlb_demap(int type, int context_encoding, uintptr_t page) |
{ |
tlb_demap_addr_t da; |
page_address_t pg; |
da.value = 0; |
pg.address = page; |
da.type = type; |
da.context = context_encoding; |
da.vpn = pg.vpn; |
/* da.value is the address within the ASI */ |
asi_u64_write(ASI_IMMU_DEMAP, da.value, 0); |
flush_pipeline(); |
} |
/** Perform DMMU TLB Demap Operation. |
* |
* @param type Selects between context and page demap (and entire MMU |
* demap on US3). |
* @param context_encoding Specifies which Context register has Context ID for |
* demap. |
* @param page Address which is on the page to be demapped. |
*/ |
static inline void dtlb_demap(int type, int context_encoding, uintptr_t page) |
{ |
tlb_demap_addr_t da; |
page_address_t pg; |
da.value = 0; |
pg.address = page; |
da.type = type; |
da.context = context_encoding; |
da.vpn = pg.vpn; |
/* da.value is the address within the ASI */ |
asi_u64_write(ASI_DMMU_DEMAP, da.value, 0); |
membar(); |
} |
extern void fast_instruction_access_mmu_miss(unative_t, istate_t *); |
extern void fast_data_access_mmu_miss(tlb_tag_access_reg_t, istate_t *); |
extern void fast_data_access_protection(tlb_tag_access_reg_t , istate_t *); |
extern void dtlb_insert_mapping(uintptr_t, uintptr_t, int, bool, bool); |
extern void dump_sfsr_and_sfar(void); |
#endif /* !def __ASM__ */ |
#endif |
/branches/sparc/kernel/arch/sparc64/include/mm/as.h |
---|
35,7 → 35,7 |
#ifndef KERN_sparc64_AS_H_ |
#define KERN_sparc64_AS_H_ |
#include <arch/mm/tte.h> |
#include <arch/mm/sun4u/tte.h> |
#define KERNEL_ADDRESS_SPACE_SHADOWED_ARCH 1 |
/branches/sparc/kernel/arch/sparc64/include/mm/tsb.h |
---|
51,8 → 51,8 |
#ifndef __ASM__ |
#include <arch/mm/tte.h> |
#include <arch/mm/mmu.h> |
#include <arch/mm/sun4u/tte.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/types.h> |
/** TSB Base register. */ |
/branches/sparc/kernel/arch/sparc64/include/mm/sun4u/tte.h |
---|
0,0 → 1,104 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64mm |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4u_TTE_H_ |
#define KERN_sparc64_sun4u_TTE_H_ |
#define TTE_G (1 << 0) |
#define TTE_W (1 << 1) |
#define TTE_P (1 << 2) |
#define TTE_E (1 << 3) |
#define TTE_CV (1 << 4) |
#define TTE_CP (1 << 5) |
#define TTE_L (1 << 6) |
#define TTE_V_SHIFT 63 |
#define TTE_SIZE_SHIFT 61 |
#ifndef __ASM__ |
#include <arch/types.h> |
/* TTE tag's VA_tag field contains bits <63:VA_TAG_PAGE_SHIFT> of the VA */ |
#define VA_TAG_PAGE_SHIFT 22 |
/** Translation Table Entry - Tag. */ |
union tte_tag { |
uint64_t value; |
struct { |
unsigned g : 1; /**< Global. */ |
unsigned : 2; /**< Reserved. */ |
unsigned context : 13; /**< Context identifier. */ |
unsigned : 6; /**< Reserved. */ |
uint64_t va_tag : 42; /**< Virtual Address Tag, bits 63:22. */ |
} __attribute__ ((packed)); |
}; |
typedef union tte_tag tte_tag_t; |
/** Translation Table Entry - Data. */ |
union tte_data { |
uint64_t value; |
struct { |
unsigned v : 1; /**< Valid. */ |
unsigned size : 2; /**< Page size of this entry. */ |
unsigned nfo : 1; /**< No-Fault-Only. */ |
unsigned ie : 1; /**< Invert Endianness. */ |
unsigned soft2 : 9; /**< Software defined field. */ |
#if defined (US) |
unsigned diag : 9; /**< Diagnostic data. */ |
unsigned pfn : 28; /**< Physical Address bits, bits 40:13. */ |
#elif defined (US3) |
unsigned : 7; /**< Reserved. */ |
unsigned pfn : 30; /**< Physical Address bits, bits 42:13 */ |
#endif |
unsigned soft : 6; /**< Software defined field. */ |
unsigned l : 1; /**< Lock. */ |
unsigned cp : 1; /**< Cacheable in physically indexed cache. */ |
unsigned cv : 1; /**< Cacheable in virtually indexed cache. */ |
unsigned e : 1; /**< Side-effect. */ |
unsigned p : 1; /**< Privileged. */ |
unsigned w : 1; /**< Writable. */ |
unsigned g : 1; /**< Global. */ |
} __attribute__ ((packed)); |
}; |
typedef union tte_data tte_data_t; |
#endif /* !def __ASM__ */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/mm/sun4u/mmu.h |
---|
0,0 → 1,123 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64mm |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4u_MMU_H_ |
#define KERN_sparc64_sun4u_MMU_H_ |
#if defined(US) |
/* LSU Control Register ASI. */ |
#define ASI_LSU_CONTROL_REG 0x45 /**< Load/Store Unit Control Register. */ |
#endif |
/* I-MMU ASIs. */ |
#define ASI_IMMU 0x50 |
#define ASI_IMMU_TSB_8KB_PTR_REG 0x51 |
#define ASI_IMMU_TSB_64KB_PTR_REG 0x52 |
#define ASI_ITLB_DATA_IN_REG 0x54 |
#define ASI_ITLB_DATA_ACCESS_REG 0x55 |
#define ASI_ITLB_TAG_READ_REG 0x56 |
#define ASI_IMMU_DEMAP 0x57 |
/* Virtual Addresses within ASI_IMMU. */ |
#define VA_IMMU_TSB_TAG_TARGET 0x0 /**< IMMU TSB tag target register. */ |
#define VA_IMMU_SFSR 0x18 /**< IMMU sync fault status register. */ |
#define VA_IMMU_TSB_BASE 0x28 /**< IMMU TSB base register. */ |
#define VA_IMMU_TAG_ACCESS 0x30 /**< IMMU TLB tag access register. */ |
#if defined (US3) |
#define VA_IMMU_PRIMARY_EXTENSION 0x48 /**< IMMU TSB primary extension register */ |
#define VA_IMMU_NUCLEUS_EXTENSION 0x58 /**< IMMU TSB nucleus extension register */ |
#endif |
/* D-MMU ASIs. */ |
#define ASI_DMMU 0x58 |
#define ASI_DMMU_TSB_8KB_PTR_REG 0x59 |
#define ASI_DMMU_TSB_64KB_PTR_REG 0x5a |
#define ASI_DMMU_TSB_DIRECT_PTR_REG 0x5b |
#define ASI_DTLB_DATA_IN_REG 0x5c |
#define ASI_DTLB_DATA_ACCESS_REG 0x5d |
#define ASI_DTLB_TAG_READ_REG 0x5e |
#define ASI_DMMU_DEMAP 0x5f |
/* Virtual Addresses within ASI_DMMU. */ |
#define VA_DMMU_TSB_TAG_TARGET 0x0 /**< DMMU TSB tag target register. */ |
#define VA_PRIMARY_CONTEXT_REG 0x8 /**< DMMU primary context register. */ |
#define VA_SECONDARY_CONTEXT_REG 0x10 /**< DMMU secondary context register. */ |
#define VA_DMMU_SFSR 0x18 /**< DMMU sync fault status register. */ |
#define VA_DMMU_SFAR 0x20 /**< DMMU sync fault address register. */ |
#define VA_DMMU_TSB_BASE 0x28 /**< DMMU TSB base register. */ |
#define VA_DMMU_TAG_ACCESS 0x30 /**< DMMU TLB tag access register. */ |
#define VA_DMMU_VA_WATCHPOINT_REG 0x38 /**< DMMU VA data watchpoint register. */ |
#define VA_DMMU_PA_WATCHPOINT_REG 0x40 /**< DMMU PA data watchpoint register. */ |
#if defined (US3) |
#define VA_DMMU_PRIMARY_EXTENSION 0x48 /**< DMMU TSB primary extension register */ |
#define VA_DMMU_SECONDARY_EXTENSION 0x50 /**< DMMU TSB secondary extension register */ |
#define VA_DMMU_NUCLEUS_EXTENSION 0x58 /**< DMMU TSB nucleus extension register */ |
#endif |
#ifndef __ASM__ |
#include <arch/asm.h> |
#include <arch/barrier.h> |
#include <arch/types.h> |
#if defined(US) |
/** LSU Control Register. */ |
typedef union { |
uint64_t value; |
struct { |
unsigned : 23; |
unsigned pm : 8; |
unsigned vm : 8; |
unsigned pr : 1; |
unsigned pw : 1; |
unsigned vr : 1; |
unsigned vw : 1; |
unsigned : 1; |
unsigned fm : 16; |
unsigned dm : 1; /**< D-MMU enable. */ |
unsigned im : 1; /**< I-MMU enable. */ |
unsigned dc : 1; /**< D-Cache enable. */ |
unsigned ic : 1; /**< I-Cache enable. */ |
} __attribute__ ((packed)); |
} lsu_cr_reg_t; |
#endif /* US */ |
#endif /* !def __ASM__ */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/mm/sun4u/tlb.h |
---|
0,0 → 1,681 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64mm |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4u_TLB_H_ |
#define KERN_sparc64_sun4u_TLB_H_ |
#if defined (US) |
#define ITLB_ENTRY_COUNT 64 |
#define DTLB_ENTRY_COUNT 64 |
#define DTLB_MAX_LOCKED_ENTRIES DTLB_ENTRY_COUNT |
#endif |
/** TLB_DSMALL is the only of the three DMMUs that can hold locked entries. */ |
#if defined (US3) |
#define DTLB_MAX_LOCKED_ENTRIES 16 |
#endif |
/** Bit width of the TLB-locked portion of kernel address space. */ |
#define KERNEL_PAGE_WIDTH 22 /* 4M */ |
/* TLB Demap Operation types. */ |
#define TLB_DEMAP_PAGE 0 |
#define TLB_DEMAP_CONTEXT 1 |
#if defined (US3) |
#define TLB_DEMAP_ALL 2 |
#endif |
#define TLB_DEMAP_TYPE_SHIFT 6 |
/* TLB Demap Operation Context register encodings. */ |
#define TLB_DEMAP_PRIMARY 0 |
#define TLB_DEMAP_SECONDARY 1 |
#define TLB_DEMAP_NUCLEUS 2 |
/* There are more TLBs in one MMU in US3, their codes are defined here. */ |
#if defined (US3) |
/* D-MMU: one small (16-entry) TLB and two big (512-entry) TLBs */ |
#define TLB_DSMALL 0 |
#define TLB_DBIG_0 2 |
#define TLB_DBIG_1 3 |
/* I-MMU: one small (16-entry) TLB and one big TLB */ |
#define TLB_ISMALL 0 |
#define TLB_IBIG 2 |
#endif |
#define TLB_DEMAP_CONTEXT_SHIFT 4 |
/* TLB Tag Access shifts */ |
#define TLB_TAG_ACCESS_CONTEXT_SHIFT 0 |
#define TLB_TAG_ACCESS_CONTEXT_MASK ((1 << 13) - 1) |
#define TLB_TAG_ACCESS_VPN_SHIFT 13 |
#ifndef __ASM__ |
#include <arch/mm/sun4u/tte.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/mm/page.h> |
#include <arch/asm.h> |
#include <arch/barrier.h> |
#include <arch/types.h> |
#include <arch/register.h> |
#include <arch/cpu.h> |
union tlb_context_reg { |
uint64_t v; |
struct { |
unsigned long : 51; |
unsigned context : 13; /**< Context/ASID. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_context_reg tlb_context_reg_t; |
/** I-/D-TLB Data In/Access Register type. */ |
typedef tte_data_t tlb_data_t; |
/** I-/D-TLB Data Access Address in Alternate Space. */ |
#if defined (US) |
union tlb_data_access_addr { |
uint64_t value; |
struct { |
uint64_t : 55; |
unsigned tlb_entry : 6; |
unsigned : 3; |
} __attribute__ ((packed)); |
}; |
typedef union tlb_data_access_addr dtlb_data_access_addr_t; |
typedef union tlb_data_access_addr dtlb_tag_read_addr_t; |
typedef union tlb_data_access_addr itlb_data_access_addr_t; |
typedef union tlb_data_access_addr itlb_tag_read_addr_t; |
#elif defined (US3) |
/* |
* In US3, I-MMU and D-MMU have different formats of the data |
* access register virtual address. In the corresponding |
* structures the member variable for the entry number is |
* called "local_tlb_entry" - it contrast with the "tlb_entry" |
* for the US data access register VA structure. The rationale |
* behind this is to prevent careless mistakes in the code |
* caused by setting only the entry number and not the TLB |
* number in the US3 code (when taking the code from US). |
*/ |
union dtlb_data_access_addr { |
uint64_t value; |
struct { |
uint64_t : 45; |
unsigned : 1; |
unsigned tlb_number : 2; |
unsigned : 4; |
unsigned local_tlb_entry : 9; |
unsigned : 3; |
} __attribute__ ((packed)); |
}; |
typedef union dtlb_data_access_addr dtlb_data_access_addr_t; |
typedef union dtlb_data_access_addr dtlb_tag_read_addr_t; |
union itlb_data_access_addr { |
uint64_t value; |
struct { |
uint64_t : 45; |
unsigned : 1; |
unsigned tlb_number : 2; |
unsigned : 6; |
unsigned local_tlb_entry : 7; |
unsigned : 3; |
} __attribute__ ((packed)); |
}; |
typedef union itlb_data_access_addr itlb_data_access_addr_t; |
typedef union itlb_data_access_addr itlb_tag_read_addr_t; |
#endif |
/** I-/D-TLB Tag Read Register. */ |
union tlb_tag_read_reg { |
uint64_t value; |
struct { |
uint64_t vpn : 51; /**< Virtual Address bits 63:13. */ |
unsigned context : 13; /**< Context identifier. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_tag_read_reg tlb_tag_read_reg_t; |
typedef union tlb_tag_read_reg tlb_tag_access_reg_t; |
/** TLB Demap Operation Address. */ |
union tlb_demap_addr { |
uint64_t value; |
struct { |
uint64_t vpn: 51; /**< Virtual Address bits 63:13. */ |
#if defined (US) |
unsigned : 6; /**< Ignored. */ |
unsigned type : 1; /**< The type of demap operation. */ |
#elif defined (US3) |
unsigned : 5; /**< Ignored. */ |
unsigned type: 2; /**< The type of demap operation. */ |
#endif |
unsigned context : 2; /**< Context register selection. */ |
unsigned : 4; /**< Zero. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_demap_addr tlb_demap_addr_t; |
/** TLB Synchronous Fault Status Register. */ |
union tlb_sfsr_reg { |
uint64_t value; |
struct { |
#if defined (US) |
unsigned long : 40; /**< Implementation dependent. */ |
unsigned asi : 8; /**< ASI. */ |
unsigned : 2; |
unsigned ft : 7; /**< Fault type. */ |
#elif defined (US3) |
unsigned long : 39; /**< Implementation dependent. */ |
unsigned nf : 1; /**< Non-faulting load. */ |
unsigned asi : 8; /**< ASI. */ |
unsigned tm : 1; /**< I-TLB miss. */ |
unsigned : 3; /**< Reserved. */ |
unsigned ft : 5; /**< Fault type. */ |
#endif |
unsigned e : 1; /**< Side-effect bit. */ |
unsigned ct : 2; /**< Context Register selection. */ |
unsigned pr : 1; /**< Privilege bit. */ |
unsigned w : 1; /**< Write bit. */ |
unsigned ow : 1; /**< Overwrite bit. */ |
unsigned fv : 1; /**< Fault Valid bit. */ |
} __attribute__ ((packed)); |
}; |
typedef union tlb_sfsr_reg tlb_sfsr_reg_t; |
#if defined (US3) |
/* |
* Functions for determining the number of entries in TLBs. They either return |
* a constant value or a value based on the CPU autodetection. |
*/ |
/** |
* Determine the number od entries in the DMMU's small TLB. |
*/ |
static inline uint16_t tlb_dsmall_size(void) |
{ |
return 16; |
} |
/** |
* Determine the number od entries in each DMMU's big TLB. |
*/ |
static inline uint16_t tlb_dbig_size(void) |
{ |
return 512; |
} |
/** |
* Determine the number od entries in the IMMU's small TLB. |
*/ |
static inline uint16_t tlb_ismall_size(void) |
{ |
return 16; |
} |
/** |
* Determine the number od entries in the IMMU's big TLB. |
*/ |
static inline uint16_t tlb_ibig_size(void) |
{ |
if (((ver_reg_t) ver_read()).impl == IMPL_ULTRASPARCIV_PLUS) |
return 512; |
else |
return 128; |
} |
#endif |
/** Read MMU Primary Context Register. |
* |
* @return Current value of Primary Context Register. |
*/ |
static inline uint64_t mmu_primary_context_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_PRIMARY_CONTEXT_REG); |
} |
/** Write MMU Primary Context Register. |
* |
* @param v New value of Primary Context Register. |
*/ |
static inline void mmu_primary_context_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_PRIMARY_CONTEXT_REG, v); |
flush_pipeline(); |
} |
/** Read MMU Secondary Context Register. |
* |
* @return Current value of Secondary Context Register. |
*/ |
static inline uint64_t mmu_secondary_context_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_SECONDARY_CONTEXT_REG); |
} |
/** Write MMU Primary Context Register. |
* |
* @param v New value of Primary Context Register. |
*/ |
static inline void mmu_secondary_context_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_SECONDARY_CONTEXT_REG, v); |
flush_pipeline(); |
} |
#if defined (US) |
/** Read IMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Data Access Register. |
*/ |
static inline uint64_t itlb_data_access_read(index_t entry) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write IMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void itlb_data_access_write(index_t entry, uint64_t value) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value); |
flush_pipeline(); |
} |
/** Read DMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Data Access Register. |
*/ |
static inline uint64_t dtlb_data_access_read(index_t entry) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write DMMU TLB Data Access Register. |
* |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void dtlb_data_access_write(index_t entry, uint64_t value) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_entry = entry; |
asi_u64_write(ASI_DTLB_DATA_ACCESS_REG, reg.value, value); |
membar(); |
} |
/** Read IMMU TLB Tag Read Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Tag Read Register. |
*/ |
static inline uint64_t itlb_tag_read_read(index_t entry) |
{ |
itlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_TAG_READ_REG, tag.value); |
} |
/** Read DMMU TLB Tag Read Register. |
* |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Tag Read Register. |
*/ |
static inline uint64_t dtlb_tag_read_read(index_t entry) |
{ |
dtlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value); |
} |
#elif defined (US3) |
/** Read IMMU TLB Data Access Register. |
* |
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Data Access Register. |
*/ |
static inline uint64_t itlb_data_access_read(int tlb, index_t entry) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write IMMU TLB Data Access Register. |
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG) |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void itlb_data_access_write(int tlb, index_t entry, |
uint64_t value) |
{ |
itlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value); |
flush_pipeline(); |
} |
/** Read DMMU TLB Data Access Register. |
* |
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG, TLB_DBIG) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Data Access Register. |
*/ |
static inline uint64_t dtlb_data_access_read(int tlb, index_t entry) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_DATA_ACCESS_REG, reg.value); |
} |
/** Write DMMU TLB Data Access Register. |
* |
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1) |
* @param entry TLB Entry index. |
* @param value Value to be written. |
*/ |
static inline void dtlb_data_access_write(int tlb, index_t entry, |
uint64_t value) |
{ |
dtlb_data_access_addr_t reg; |
reg.value = 0; |
reg.tlb_number = tlb; |
reg.local_tlb_entry = entry; |
asi_u64_write(ASI_DTLB_DATA_ACCESS_REG, reg.value, value); |
membar(); |
} |
/** Read IMMU TLB Tag Read Register. |
* |
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified IMMU TLB Tag Read Register. |
*/ |
static inline uint64_t itlb_tag_read_read(int tlb, index_t entry) |
{ |
itlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_number = tlb; |
tag.local_tlb_entry = entry; |
return asi_u64_read(ASI_ITLB_TAG_READ_REG, tag.value); |
} |
/** Read DMMU TLB Tag Read Register. |
* |
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1) |
* @param entry TLB Entry index. |
* |
* @return Current value of specified DMMU TLB Tag Read Register. |
*/ |
static inline uint64_t dtlb_tag_read_read(int tlb, index_t entry) |
{ |
dtlb_tag_read_addr_t tag; |
tag.value = 0; |
tag.tlb_number = tlb; |
tag.local_tlb_entry = entry; |
return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value); |
} |
#endif |
/** Write IMMU TLB Tag Access Register. |
* |
* @param v Value to be written. |
*/ |
static inline void itlb_tag_access_write(uint64_t v) |
{ |
asi_u64_write(ASI_IMMU, VA_IMMU_TAG_ACCESS, v); |
flush_pipeline(); |
} |
/** Read IMMU TLB Tag Access Register. |
* |
* @return Current value of IMMU TLB Tag Access Register. |
*/ |
static inline uint64_t itlb_tag_access_read(void) |
{ |
return asi_u64_read(ASI_IMMU, VA_IMMU_TAG_ACCESS); |
} |
/** Write DMMU TLB Tag Access Register. |
* |
* @param v Value to be written. |
*/ |
static inline void dtlb_tag_access_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_DMMU_TAG_ACCESS, v); |
membar(); |
} |
/** Read DMMU TLB Tag Access Register. |
* |
* @return Current value of DMMU TLB Tag Access Register. |
*/ |
static inline uint64_t dtlb_tag_access_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_DMMU_TAG_ACCESS); |
} |
/** Write IMMU TLB Data in Register. |
* |
* @param v Value to be written. |
*/ |
static inline void itlb_data_in_write(uint64_t v) |
{ |
asi_u64_write(ASI_ITLB_DATA_IN_REG, 0, v); |
flush_pipeline(); |
} |
/** Write DMMU TLB Data in Register. |
* |
* @param v Value to be written. |
*/ |
static inline void dtlb_data_in_write(uint64_t v) |
{ |
asi_u64_write(ASI_DTLB_DATA_IN_REG, 0, v); |
membar(); |
} |
/** Read ITLB Synchronous Fault Status Register. |
* |
* @return Current content of I-SFSR register. |
*/ |
static inline uint64_t itlb_sfsr_read(void) |
{ |
return asi_u64_read(ASI_IMMU, VA_IMMU_SFSR); |
} |
/** Write ITLB Synchronous Fault Status Register. |
* |
* @param v New value of I-SFSR register. |
*/ |
static inline void itlb_sfsr_write(uint64_t v) |
{ |
asi_u64_write(ASI_IMMU, VA_IMMU_SFSR, v); |
flush_pipeline(); |
} |
/** Read DTLB Synchronous Fault Status Register. |
* |
* @return Current content of D-SFSR register. |
*/ |
static inline uint64_t dtlb_sfsr_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_DMMU_SFSR); |
} |
/** Write DTLB Synchronous Fault Status Register. |
* |
* @param v New value of D-SFSR register. |
*/ |
static inline void dtlb_sfsr_write(uint64_t v) |
{ |
asi_u64_write(ASI_DMMU, VA_DMMU_SFSR, v); |
membar(); |
} |
/** Read DTLB Synchronous Fault Address Register. |
* |
* @return Current content of D-SFAR register. |
*/ |
static inline uint64_t dtlb_sfar_read(void) |
{ |
return asi_u64_read(ASI_DMMU, VA_DMMU_SFAR); |
} |
/** Perform IMMU TLB Demap Operation. |
* |
* @param type |
* Selects between context and page demap |
* (and entire MMU demap on US3). |
* @param context_encoding Specifies which Context register has Context ID for |
* demap. |
* @param page Address which is on the page to be demapped. |
*/ |
static inline void itlb_demap(int type, int context_encoding, uintptr_t page) |
{ |
tlb_demap_addr_t da; |
page_address_t pg; |
da.value = 0; |
pg.address = page; |
da.type = type; |
da.context = context_encoding; |
da.vpn = pg.vpn; |
asi_u64_write(ASI_IMMU_DEMAP, da.value, 0); /* da.value is the |
* address within the |
* ASI */ |
flush_pipeline(); |
} |
/** Perform DMMU TLB Demap Operation. |
* |
* @param type |
* Selects between context and page demap |
* (and entire MMU demap on US3). |
* @param context_encoding Specifies which Context register has Context ID for |
* demap. |
* @param page Address which is on the page to be demapped. |
*/ |
static inline void dtlb_demap(int type, int context_encoding, uintptr_t page) |
{ |
tlb_demap_addr_t da; |
page_address_t pg; |
da.value = 0; |
pg.address = page; |
da.type = type; |
da.context = context_encoding; |
da.vpn = pg.vpn; |
asi_u64_write(ASI_DMMU_DEMAP, da.value, 0); /* da.value is the |
* address within the |
* ASI */ |
membar(); |
} |
extern void fast_instruction_access_mmu_miss(unative_t unused, istate_t *istate); |
extern void fast_data_access_mmu_miss(tlb_tag_access_reg_t tag, istate_t *istate); |
extern void fast_data_access_protection(tlb_tag_access_reg_t tag , istate_t *istate); |
extern void dtlb_insert_mapping(uintptr_t page, uintptr_t frame, int pagesize, bool locked, bool cacheable); |
extern void dump_sfsr_and_sfar(void); |
#endif /* !def __ASM__ */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/register.h |
---|
35,7 → 35,7 |
#ifndef KERN_sparc64_REGISTER_H_ |
#define KERN_sparc64_REGISTER_H_ |
#include <arch/regdef.h> |
#include <arch/sun4u/regdef.h> |
#include <arch/types.h> |
/** Version Register. */ |
/branches/sparc/kernel/arch/sparc64/include/cpu.h |
---|
56,8 → 56,9 |
#include <arch/types.h> |
#include <typedefs.h> |
#include <arch/register.h> |
#include <arch/regdef.h> |
#include <arch/sun4u/regdef.h> |
#include <arch/asm.h> |
#include <arch/sun4u/arch.h> |
#ifdef CONFIG_SMP |
#include <arch/mm/cache.h> |
88,6 → 89,9 |
return icbus_config & 0x1f; |
else |
return icbus_config & 0x3ff; |
#else |
panic("Not implemented for this architecture."); |
return 0; |
#endif |
} |
/branches/sparc/kernel/arch/sparc64/include/drivers/niagara.h |
---|
0,0 → 1,45 |
/* |
* Copyright (c) 2008 Pavel Rimsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_NIAGARA_H |
#define KERN_sparc64_NIAGARA_H |
void niagara_grab(void); |
void niagara_release(void); |
void niagara_init(void); |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/sun4u/regdef.h |
---|
0,0 → 1,67 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_sun4u_REGDEF_H_ |
#define KERN_sparc64_sun4u_REGDEF_H_ |
#define PSTATE_IE_BIT (1 << 1) |
#define PSTATE_AM_BIT (1 << 3) |
#define PSTATE_AG_BIT (1 << 0) |
#define PSTATE_IG_BIT (1 << 11) |
#define PSTATE_MG_BIT (1 << 10) |
#define PSTATE_PRIV_BIT (1 << 2) |
#define PSTATE_PEF_BIT (1 << 4) |
#define TSTATE_PSTATE_SHIFT 8 |
#define TSTATE_PRIV_BIT (PSTATE_PRIV_BIT << TSTATE_PSTATE_SHIFT) |
#define TSTATE_IE_BIT (PSTATE_IE_BIT << TSTATE_PSTATE_SHIFT) |
#define TSTATE_PEF_BIT (PSTATE_PEF_BIT << TSTATE_PSTATE_SHIFT) |
#define TSTATE_CWP_MASK 0x1f |
#define WSTATE_NORMAL(n) (n) |
#define WSTATE_OTHER(n) ((n) << 3) |
/* |
* The following definitions concern the UPA_CONFIG register on US and the |
* FIREPLANE_CONFIG register on US3. |
*/ |
#define ICBUS_CONFIG_MID_SHIFT 17 |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/include/sun4u/arch.h |
---|
0,0 → 1,47 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** |
* @file |
* @brief Various sun4u-specific macros. |
*/ |
#ifndef KERN_sparc64_sun4u_ARCH_H_ |
#define KERN_sparc64_sun4u_ARCH_H_ |
#define ASI_NUCLEUS_QUAD_LDD 0x24 /** ASI for 16-byte atomic loads. */ |
#define ASI_DCACHE_TAG 0x47 /** ASI D-Cache Tag. */ |
#define ASI_ICBUS_CONFIG 0x4a /** ASI of the UPA_CONFIG/FIREPLANE_CONFIG register. */ |
#endif |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/Makefile.inc |
---|
85,14 → 85,31 |
endif |
ifeq ($(MACHINE),us) |
DEFS += -DUS |
USARCH = sun4u |
DEFS += -DUS |
endif |
ifeq ($(MACHINE),us3) |
USARCH = sun4u |
DEFS += -DUS3 |
endif |
ifeq ($(MACHINE),sun4v) |
USARCH = sun4v |
DEFS += -DSUN4V |
DEFS += -DUS3 # TODO: do not forget to remove this line, it is here only to make the code compilable even when the sun4v port is not fully implemented yet |
endif |
# common for sun4u and sun4v |
ARCH_SOURCES = \ |
arch/$(ARCH)/src/$(USARCH)/start.S \ |
arch/$(ARCH)/src/trap/$(USARCH)/trap_table.S \ |
arch/$(ARCH)/src/$(USARCH)/asm.S \ |
arch/$(ARCH)/src/$(USARCH)/sparc64.c |
# sun4u-specific, not #ifdef'd yet in order to make the code compilable |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/cpu/cpu.c \ |
arch/$(ARCH)/src/asm.S \ |
arch/$(ARCH)/src/panic.S \ |
105,12 → 122,9 |
arch/$(ARCH)/src/mm/frame.c \ |
arch/$(ARCH)/src/mm/page.c \ |
arch/$(ARCH)/src/mm/tlb.c \ |
arch/$(ARCH)/src/sparc64.c \ |
arch/$(ARCH)/src/start.S \ |
arch/$(ARCH)/src/proc/scheduler.c \ |
arch/$(ARCH)/src/proc/thread.c \ |
arch/$(ARCH)/src/trap/mmu.S \ |
arch/$(ARCH)/src/trap/trap_table.S \ |
arch/$(ARCH)/src/trap/trap.c \ |
arch/$(ARCH)/src/trap/exception.c \ |
arch/$(ARCH)/src/trap/interrupt.c \ |
121,6 → 135,11 |
arch/$(ARCH)/src/drivers/sgcn.c \ |
arch/$(ARCH)/src/drivers/pci.c |
# sun4v-specific sources |
ifeq ($(USARCH),sun4v) |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/drivers/niagara.c |
endif |
ifeq ($(CONFIG_SMP),y) |
ARCH_SOURCES += \ |
/branches/sparc/kernel/arch/sparc64/src/sparc64.c |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/src/start.S |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/src/sun4v/asm.S |
---|
0,0 → 1,47 |
# |
# Copyright (c) 2008 Pavel Rimsky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - 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. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# 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. |
# |
.text |
/* TODO: remove it as soon as there is a scheduler for sun4v. It is here only to make the code compilable/ */ |
.global write_to_ag_g6 |
write_to_ag_g6: |
.global write_to_ag_g7 |
write_to_ag_g7: |
.global write_to_ig_g6 |
write_to_ig_g6: |
.global read_from_ag_g7 |
read_from_ag_g7: |
.global switch_to_userspace |
switch_to_userspace: |
/branches/sparc/kernel/arch/sparc64/src/sun4v/sparc64.c |
---|
0,0 → 1,170 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#include <arch.h> |
#include <debug.h> |
#include <config.h> |
#include <arch/trap/trap.h> |
#include <arch/console.h> |
#include <proc/thread.h> |
#include <console/console.h> |
#include <arch/boot/boot.h> |
#include <arch/arch.h> |
#include <arch/asm.h> |
#include <arch/mm/page.h> |
#include <arch/stack.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <userspace.h> |
#include <ddi/irq.h> |
#include <print.h> |
#include <arch/drivers/niagara.h> |
bootinfo_t bootinfo; |
/** Perform sparc64 specific initialization before main_bsp() is called. */ |
void arch_pre_main(void) |
{ |
niagara_init(); |
/* Copy init task info. */ |
init.cnt = bootinfo.taskmap.count; |
uint32_t i; |
for (i = 0; i < bootinfo.taskmap.count; i++) { |
init.tasks[i].addr = (uintptr_t) bootinfo.taskmap.tasks[i].addr; |
init.tasks[i].size = bootinfo.taskmap.tasks[i].size; |
} |
/* Copy boot allocations info. */ |
ballocs.base = bootinfo.ballocs.base; |
ballocs.size = bootinfo.ballocs.size; |
ofw_tree_init(bootinfo.ofw_root); |
} |
/** Perform sparc64 specific initialization before mm is initialized. */ |
void arch_pre_mm_init(void) |
{ |
if (config.cpu_active == 1) |
trap_init(); |
} |
/** Perform sparc64 specific initialization afterr mm is initialized. */ |
void arch_post_mm_init(void) |
{ |
if (config.cpu_active == 1) { |
/* |
* We have 2^11 different interrupt vectors. |
* But we only create 128 buckets. |
*/ |
irq_init(1 << 11, 128); |
standalone_sparc64_console_init(); |
} |
} |
void arch_post_cpu_init(void) |
{ |
} |
void arch_pre_smp_init(void) |
{ |
} |
void arch_post_smp_init(void) |
{ |
static thread_t *t = NULL; |
if (!t) { |
/* |
* Create thread that polls keyboard. |
*/ |
t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll", true); |
if (!t) |
panic("cannot create kkbdpoll\n"); |
thread_ready(t); |
} |
} |
/** Calibrate delay loop. |
* |
* On sparc64, we implement delay() by waiting for the TICK register to |
* reach a pre-computed value, as opposed to performing some pre-computed |
* amount of instructions of known duration. We set the delay_loop_const |
* to 1 in order to neutralize the multiplication done by delay(). |
*/ |
void calibrate_delay_loop(void) |
{ |
CPU->delay_loop_const = 1; |
} |
/** Wait several microseconds. |
* |
* We assume that interrupts are already disabled. |
* |
* @param t Microseconds to wait. |
*/ |
void asm_delay_loop(const uint32_t usec) |
{ |
uint64_t stop = tick_read() + (uint64_t) usec * (uint64_t) |
CPU->arch.clock_frequency / 1000000; |
while (tick_read() < stop) |
; |
} |
/** Switch to userspace. */ |
void userspace(uspace_arg_t *kernel_uarg) |
{ |
switch_to_userspace((uintptr_t) kernel_uarg->uspace_entry, |
((uintptr_t) kernel_uarg->uspace_stack) + STACK_SIZE |
- (ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT) + STACK_BIAS), |
(uintptr_t) kernel_uarg->uspace_uarg); |
for (;;) |
; |
/* not reached */ |
} |
void arch_reboot(void) |
{ |
// TODO |
while (1); |
} |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/src/sun4v/start.S |
---|
0,0 → 1,245 |
# |
# Copyright (c) 2005 Jakub Jermar |
# Copyright (c) 2008 Pavel Rimsky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - 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. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# 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. |
# |
#include <arch/arch.h> |
#include <arch/stack.h> |
#include <arch/sun4v/regdef.h> |
#include <arch/sun4v/hypercall.h> |
#include <arch/mm/sun4v/tte.h> |
#include <arch/mm/sun4v/mmu.h> |
#include <arch/mm/tlb.h> |
.register %g2, #scratch |
.register %g3, #scratch |
.section K_TEXT_START, "ax" |
#define BSP_FLAG 1 |
#define PHYSMEM_ADDR_SIZE 56 |
/* |
* SILO for an unknown reason loads the image to MAPPING_OFFSET + 0x4000 bytes |
* from the start of the physical memory. We pretend that the physical memory |
* starts MAPPING_OFFSET bytes further than it actually does. |
*/ |
#define MAPPING_OFFSET 0x400000 |
/* |
* Flags set in the TTE data entry mapping the kernel. |
*/ |
#ifdef CONFIG_VIRT_IDX_DCACHE |
#define TTE_FLAGS \ |
(1 << TTE_V_SHIFT) \ |
| (1 << TTE_EP_SHIFT) \ |
| (1 << TTE_CP_SHIFT) \ |
| (1 << TTE_CV_SHIFT) \ |
| (1 << TTE_P_SHIFT) \ |
| (1 << TTE_W_SHIFT) |
#else |
#define TTE_FLAGS \ |
(1 << TTE_V_SHIFT) \ |
| (1 << TTE_EP_SHIFT) \ |
| (1 << TTE_CP_SHIFT) \ |
| (1 << TTE_P_SHIFT) \ |
| (1 << TTE_W_SHIFT) |
#endif |
/* |
* Fills a register with a TTE Data item. The item will map the given virtual |
* address to a real address which will be computed by adding the starting |
* address of the physical memory to the virtual address. |
* |
* parameters: |
* addr: virtual address to be mapped |
* rphysmem_start: register containing the starting address of the |
* physical memory |
* rtmp1: a register to be used as temporary |
* rtmp2: a register to be used as temporary |
* rd: register where the result will be saved |
*/ |
#define TTE_DATA(addr, rphysmem_start, rtmp1, rtmp2, rd) \ |
setx TTE_FLAGS | PAGESIZE_4M, rtmp1, rd; \ |
add rd, rphysmem_start, rd; \ |
setx (addr), rtmp1, rtmp2; \ |
add rd, rtmp2, rd; |
/* |
* Here is where the kernel is passed control from the boot loader. |
* |
* The registers are expected to be in this state: |
* - %o0 starting address of physical memory + bootstrap processor flag |
* bits 63...1: physical memory starting address / 2 |
* bit 0: non-zero on BSP processor, zero on AP processors |
* - %o1 bootinfo structure address (BSP only) |
* - %o2 bootinfo structure size (BSP only) |
* |
* Moreover, we depend on boot having established the following environment: |
* - TLBs are on |
* - identity mapping for the kernel image |
*/ |
.global kernel_image_start |
kernel_image_start: |
mov BSP_FLAG, %l0 |
and %o0, %l0, %l7 ! l7 <= bootstrap processor? |
andn %o0, %l0, %l6 ! l6 <= start of physical memory |
or %o1, %g0, %l1 |
or %o2, %g0, %l2 |
! Get bits (PHYSMEM_ADDR_SIZE - 1):13 of physmem_base. |
srlx %l6, 13, %l5 |
! l5 <= physmem_base[(PHYSMEM_ADDR_SIZE - 1):13] |
sllx %l5, 13 + (63 - (PHYSMEM_ADDR_SIZE - 1)), %l5 |
srlx %l5, 63 - (PHYSMEM_ADDR_SIZE - 1), %l5 |
! pretend the physical memory starts further |
set MAPPING_OFFSET, %g2 |
add %l5, %g2, %l5 |
/* |
* Setup basic runtime environment. |
*/ |
wrpr %g0, NWINDOWS - 2, %cansave ! set maximum saveable windows |
wrpr %g0, 0, %canrestore ! get rid of windows we will |
! never need again |
wrpr %g0, 0, %otherwin ! make sure the window state is |
! consistent |
wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent needless clean_window |
! traps for kernel |
wrpr %g0, 0, %wstate ! use default spill/fill trap |
wrpr %g0, 0, %tl ! TL = 0, primary context |
! register is used |
wrpr %g0, PSTATE_PRIV_BIT, %pstate ! disable interrupts and disable |
! 32-bit address masking |
wrpr %g0, 0, %pil ! intialize %pil |
/* |
* Switch to kernel trap table. |
*/ |
sethi %hi(trap_table), %g1 |
wrpr %g1, %lo(trap_table), %tba |
/* |
* Take over the MMU. |
*/ |
! map kernel in context 1 |
set kernel_image_start, %o0 ! virt. address |
set 1, %o1 ! context |
TTE_DATA(kernel_image_start, %l5, %g2, %g3, %o2) ! TTE data |
set MMU_FLAG_DTLB | MMU_FLAG_ITLB, %o3 ! MMU flags |
__HYPERCALL_HYPERFAST(MMU_MAP_ADDR) |
! switch to context 1 |
set 1, %o0 |
set VA_PRIMARY_CONTEXT_REG, %o1 |
stxa %o0, [%o1] ASI_PRIMARY_CONTEXT_REG |
! demap all in context 0 |
set 0, %o0 ! reserved |
set 0, %o1 ! reserved |
set 0, %o2 ! context |
set MMU_FLAG_DTLB | MMU_FLAG_ITLB, %o3 ! MMU flags |
__HYPERCALL_FAST(MMU_DEMAP_CTX) |
! install permanent mapping for kernel in context 0 |
set kernel_image_start, %o0 ! virtual address |
set 0, %o1 ! context |
TTE_DATA(kernel_image_start, %l5, %g2, %g3, %o2) ! TTE data |
set MMU_FLAG_DTLB | MMU_FLAG_ITLB, %o3 ! MMU flags |
__HYPERCALL_FAST(MMU_MAP_PERM_ADDR) |
! switch to context 0 |
mov 0, %o0 |
set VA_PRIMARY_CONTEXT_REG, %o1 |
stxa %o0, [%o1] ASI_PRIMARY_CONTEXT_REG |
! demap all in context 1 (cleanup) |
set 0, %o0 ! reserved |
set 0, %o1 ! reserved |
set 1, %o2 ! context |
set MMU_FLAG_DTLB | MMU_FLAG_ITLB, %o3 ! MMU flags |
__HYPERCALL_FAST(MMU_DEMAP_CTX) |
/* |
* Save physmem_base for use by the mm subsystem. |
* %l6 contains starting physical address |
*/ |
sethi %hi(physmem_base), %l4 |
stx %l6, [%l4 + %lo(physmem_base)] |
/* |
* So far, we have not touched the stack. |
* It is a good idea to set the kernel stack to a known state now. |
*/ |
sethi %hi(temporary_boot_stack), %sp |
or %sp, %lo(temporary_boot_stack), %sp |
sub %sp, STACK_BIAS, %sp |
or %l1, %g0, %o1 |
or %l2, %g0, %o2 |
sethi %hi(bootinfo), %o0 |
call memcpy ! copy bootinfo |
or %o0, %lo(bootinfo), %o0 |
call arch_pre_main |
nop |
call main_bsp |
nop |
/* Not reached. */ |
0: |
ba 0b |
nop |
.section K_DATA_START, "aw", @progbits |
#define INITIAL_STACK_SIZE 1024 |
.align STACK_ALIGNMENT |
.space INITIAL_STACK_SIZE |
.align STACK_ALIGNMENT |
temporary_boot_stack: |
.space STACK_WINDOW_SAVE_AREA_SIZE |
.data |
.align 8 |
.global physmem_base ! copy of the physical memory base address |
physmem_base: |
.quad 0 |
/branches/sparc/kernel/arch/sparc64/src/asm.S |
---|
28,8 → 28,6 |
#include <arch/arch.h> |
#include <arch/stack.h> |
#include <arch/regdef.h> |
#include <arch/mm/mmu.h> |
.text |
229,83 → 227,3 |
nop |
.macro WRITE_ALTERNATE_REGISTER reg, bit |
rdpr %pstate, %g1 ! save PSTATE.PEF |
wrpr %g0, (\bit | PSTATE_PRIV_BIT), %pstate |
mov %o0, \reg |
wrpr %g0, PSTATE_PRIV_BIT, %pstate |
retl |
wrpr %g1, 0, %pstate ! restore PSTATE.PEF |
.endm |
.macro READ_ALTERNATE_REGISTER reg, bit |
rdpr %pstate, %g1 ! save PSTATE.PEF |
wrpr %g0, (\bit | PSTATE_PRIV_BIT), %pstate |
mov \reg, %o0 |
wrpr %g0, PSTATE_PRIV_BIT, %pstate |
retl |
wrpr %g1, 0, %pstate ! restore PSTATE.PEF |
.endm |
.global write_to_ag_g6 |
write_to_ag_g6: |
WRITE_ALTERNATE_REGISTER %g6, PSTATE_AG_BIT |
.global write_to_ag_g7 |
write_to_ag_g7: |
WRITE_ALTERNATE_REGISTER %g7, PSTATE_AG_BIT |
.global write_to_ig_g6 |
write_to_ig_g6: |
WRITE_ALTERNATE_REGISTER %g6, PSTATE_IG_BIT |
.global read_from_ag_g7 |
read_from_ag_g7: |
READ_ALTERNATE_REGISTER %g7, PSTATE_AG_BIT |
/** Switch to userspace. |
* |
* %o0 Userspace entry address. |
* %o1 Userspace stack pointer address. |
* %o2 Userspace address of uarg structure. |
*/ |
.global switch_to_userspace |
switch_to_userspace: |
save %o1, -STACK_WINDOW_SAVE_AREA_SIZE, %sp |
flushw |
wrpr %g0, 0, %cleanwin ! avoid information leak |
mov %i2, %o0 ! uarg |
xor %o1, %o1, %o1 ! %o1 is defined to hold pcb_ptr |
! set it to 0 |
clr %i2 |
clr %i3 |
clr %i4 |
clr %i5 |
clr %i6 |
wrpr %g0, 1, %tl ! enforce mapping via nucleus |
rdpr %cwp, %g1 |
wrpr %g1, TSTATE_IE_BIT, %tstate |
wrpr %i0, 0, %tnpc |
/* |
* Set primary context according to secondary context. |
* Secondary context has been already installed by |
* higher-level functions. |
*/ |
wr %g0, ASI_DMMU, %asi |
ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1 |
stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi |
flush %i7 |
/* |
* Spills and fills will be handled by the userspace handlers. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate |
done ! jump to userspace |
/branches/sparc/kernel/arch/sparc64/src/trap/trap_table.S |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/src/trap/exception.c |
---|
35,6 → 35,7 |
#include <arch/trap/exception.h> |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4u/tlb.h> |
#include <arch/interrupt.h> |
#include <interrupt.h> |
#include <arch/asm.h> |
/branches/sparc/kernel/arch/sparc64/src/trap/mmu.S |
---|
36,7 → 36,7 |
.text |
#include <arch/trap/mmu.h> |
#include <arch/trap/sun4u/mmu.h> |
#include <arch/trap/trap_table.h> |
#include <arch/regdef.h> |
#include <arch/sun4u/regdef.h> |
/branches/sparc/kernel/arch/sparc64/src/trap/sun4v/trap_table.S |
---|
0,0 → 1,854 |
# |
# Copyright (c) 2005 Jakub Jermar |
# Copyright (c) 2008 Pavel Rimsky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - 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. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# 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. |
# |
/** |
* @file |
* @brief This file contains kernel trap table. |
*/ |
.register %g2, #scratch |
.register %g3, #scratch |
.text |
#include <arch/trap/trap_table.h> |
#include <arch/trap/regwin.h> |
#include <arch/trap/interrupt.h> |
#include <arch/trap/exception.h> |
#include <arch/trap/syscall.h> |
#include <arch/trap/sun4v/mmu.h> |
#include <arch/mm/sun4v/mmu.h> |
#include <arch/mm/page.h> |
#include <arch/stack.h> |
#include <arch/sun4v/regdef.h> |
#define TABLE_SIZE TRAP_TABLE_SIZE |
#define ENTRY_SIZE TRAP_TABLE_ENTRY_SIZE |
/* |
* Kernel trap table. |
*/ |
.align TABLE_SIZE |
.global trap_table |
trap_table: |
/* TT = 0x08, TL = 0, instruction_access_exception */ |
.org trap_table + TT_INSTRUCTION_ACCESS_EXCEPTION*ENTRY_SIZE |
.global instruction_access_exception_tl0 |
instruction_access_exception_tl0: |
/*wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER instruction_access_exception*/ |
/* TT = 0x0a, TL = 0, instruction_access_error */ |
.org trap_table + TT_INSTRUCTION_ACCESS_ERROR*ENTRY_SIZE |
.global instruction_access_error_tl0 |
instruction_access_error_tl0: |
PREEMPTIBLE_HANDLER instruction_access_error |
/* TT = 0x10, TL = 0, illegal_instruction */ |
.org trap_table + TT_ILLEGAL_INSTRUCTION*ENTRY_SIZE |
.global illegal_instruction_tl0 |
illegal_instruction_tl0: |
PREEMPTIBLE_HANDLER illegal_instruction |
/* TT = 0x11, TL = 0, privileged_opcode */ |
.org trap_table + TT_PRIVILEGED_OPCODE*ENTRY_SIZE |
.global privileged_opcode_tl0 |
privileged_opcode_tl0: |
PREEMPTIBLE_HANDLER privileged_opcode |
/* TT = 0x12, TL = 0, unimplemented_LDD */ |
.org trap_table + TT_UNIMPLEMENTED_LDD*ENTRY_SIZE |
.global unimplemented_LDD_tl0 |
unimplemented_LDD_tl0: |
PREEMPTIBLE_HANDLER unimplemented_LDD |
/* TT = 0x13, TL = 0, unimplemented_STD */ |
.org trap_table + TT_UNIMPLEMENTED_STD*ENTRY_SIZE |
.global unimplemented_STD_tl0 |
unimplemented_STD_tl0: |
PREEMPTIBLE_HANDLER unimplemented_STD |
/* TT = 0x20, TL = 0, fb_disabled handler */ |
.org trap_table + TT_FP_DISABLED*ENTRY_SIZE |
.global fb_disabled_tl0 |
fp_disabled_tl0: |
PREEMPTIBLE_HANDLER fp_disabled |
/* TT = 0x21, TL = 0, fb_exception_ieee_754 handler */ |
.org trap_table + TT_FP_EXCEPTION_IEEE_754*ENTRY_SIZE |
.global fb_exception_ieee_754_tl0 |
fp_exception_ieee_754_tl0: |
PREEMPTIBLE_HANDLER fp_exception_ieee_754 |
/* TT = 0x22, TL = 0, fb_exception_other handler */ |
.org trap_table + TT_FP_EXCEPTION_OTHER*ENTRY_SIZE |
.global fb_exception_other_tl0 |
fp_exception_other_tl0: |
PREEMPTIBLE_HANDLER fp_exception_other |
/* TT = 0x23, TL = 0, tag_overflow */ |
.org trap_table + TT_TAG_OVERFLOW*ENTRY_SIZE |
.global tag_overflow_tl0 |
tag_overflow_tl0: |
PREEMPTIBLE_HANDLER tag_overflow |
/* TT = 0x24, TL = 0, clean_window handler */ |
.org trap_table + TT_CLEAN_WINDOW*ENTRY_SIZE |
.global clean_window_tl0 |
clean_window_tl0: |
CLEAN_WINDOW_HANDLER |
/* TT = 0x28, TL = 0, division_by_zero */ |
.org trap_table + TT_DIVISION_BY_ZERO*ENTRY_SIZE |
.global division_by_zero_tl0 |
division_by_zero_tl0: |
PREEMPTIBLE_HANDLER division_by_zero |
/* TT = 0x30, TL = 0, data_access_exception */ |
.org trap_table + TT_DATA_ACCESS_EXCEPTION*ENTRY_SIZE |
.global data_access_exception_tl0 |
data_access_exception_tl0: |
/*wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER data_access_exception*/ |
/* TT = 0x32, TL = 0, data_access_error */ |
.org trap_table + TT_DATA_ACCESS_ERROR*ENTRY_SIZE |
.global data_access_error_tl0 |
data_access_error_tl0: |
PREEMPTIBLE_HANDLER data_access_error |
/* TT = 0x34, TL = 0, mem_address_not_aligned */ |
.org trap_table + TT_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global mem_address_not_aligned_tl0 |
mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER mem_address_not_aligned |
/* TT = 0x35, TL = 0, LDDF_mem_address_not_aligned */ |
.org trap_table + TT_LDDF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global LDDF_mem_address_not_aligned_tl0 |
LDDF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER LDDF_mem_address_not_aligned |
/* TT = 0x36, TL = 0, STDF_mem_address_not_aligned */ |
.org trap_table + TT_STDF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global STDF_mem_address_not_aligned_tl0 |
STDF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER STDF_mem_address_not_aligned |
/* TT = 0x37, TL = 0, privileged_action */ |
.org trap_table + TT_PRIVILEGED_ACTION*ENTRY_SIZE |
.global privileged_action_tl0 |
privileged_action_tl0: |
PREEMPTIBLE_HANDLER privileged_action |
/* TT = 0x38, TL = 0, LDQF_mem_address_not_aligned */ |
.org trap_table + TT_LDQF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global LDQF_mem_address_not_aligned_tl0 |
LDQF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER LDQF_mem_address_not_aligned |
/* TT = 0x39, TL = 0, STQF_mem_address_not_aligned */ |
.org trap_table + TT_STQF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global STQF_mem_address_not_aligned_tl0 |
STQF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER STQF_mem_address_not_aligned |
/* TT = 0x41, TL = 0, interrupt_level_1 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_1*ENTRY_SIZE |
.global interrupt_level_1_handler_tl0 |
interrupt_level_1_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 1 |
/* TT = 0x42, TL = 0, interrupt_level_2 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_2*ENTRY_SIZE |
.global interrupt_level_2_handler_tl0 |
interrupt_level_2_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 2 |
/* TT = 0x43, TL = 0, interrupt_level_3 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_3*ENTRY_SIZE |
.global interrupt_level_3_handler_tl0 |
interrupt_level_3_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 3 |
/* TT = 0x44, TL = 0, interrupt_level_4 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_4*ENTRY_SIZE |
.global interrupt_level_4_handler_tl0 |
interrupt_level_4_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 4 |
/* TT = 0x45, TL = 0, interrupt_level_5 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_5*ENTRY_SIZE |
.global interrupt_level_5_handler_tl0 |
interrupt_level_5_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 5 |
/* TT = 0x46, TL = 0, interrupt_level_6 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_6*ENTRY_SIZE |
.global interrupt_level_6_handler_tl0 |
interrupt_level_6_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 6 |
/* TT = 0x47, TL = 0, interrupt_level_7 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_7*ENTRY_SIZE |
.global interrupt_level_7_handler_tl0 |
interrupt_level_7_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 7 |
/* TT = 0x48, TL = 0, interrupt_level_8 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_8*ENTRY_SIZE |
.global interrupt_level_8_handler_tl0 |
interrupt_level_8_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 8 |
/* TT = 0x49, TL = 0, interrupt_level_9 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_9*ENTRY_SIZE |
.global interrupt_level_9_handler_tl0 |
interrupt_level_9_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 9 |
/* TT = 0x4a, TL = 0, interrupt_level_10 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_10*ENTRY_SIZE |
.global interrupt_level_10_handler_tl0 |
interrupt_level_10_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 10 |
/* TT = 0x4b, TL = 0, interrupt_level_11 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_11*ENTRY_SIZE |
.global interrupt_level_11_handler_tl0 |
interrupt_level_11_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 11 |
/* TT = 0x4c, TL = 0, interrupt_level_12 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_12*ENTRY_SIZE |
.global interrupt_level_12_handler_tl0 |
interrupt_level_12_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 12 |
/* TT = 0x4d, TL = 0, interrupt_level_13 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_13*ENTRY_SIZE |
.global interrupt_level_13_handler_tl0 |
interrupt_level_13_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 13 |
/* TT = 0x4e, TL = 0, interrupt_level_14 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_14*ENTRY_SIZE |
.global interrupt_level_14_handler_tl0 |
interrupt_level_14_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 14 |
/* TT = 0x4f, TL = 0, interrupt_level_15 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_15*ENTRY_SIZE |
.global interrupt_level_15_handler_tl0 |
interrupt_level_15_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 15 |
/* TT = 0x60, TL = 0, interrupt_vector_trap handler */ |
.org trap_table + TT_INTERRUPT_VECTOR_TRAP*ENTRY_SIZE |
.global interrupt_vector_trap_handler_tl0 |
interrupt_vector_trap_handler_tl0: |
INTERRUPT_VECTOR_TRAP_HANDLER |
/* TT = 0x64, TL = 0, fast_instruction_access_MMU_miss */ |
.org trap_table + TT_FAST_INSTRUCTION_ACCESS_MMU_MISS*ENTRY_SIZE |
.global fast_instruction_access_mmu_miss_handler_tl0 |
fast_instruction_access_mmu_miss_handler_tl0: |
/*FAST_INSTRUCTION_ACCESS_MMU_MISS_HANDLER*/ |
/* TT = 0x68, TL = 0, fast_data_access_MMU_miss */ |
.org trap_table + TT_FAST_DATA_ACCESS_MMU_MISS*ENTRY_SIZE |
.global fast_data_access_mmu_miss_handler_tl0 |
fast_data_access_mmu_miss_handler_tl0: |
FAST_DATA_ACCESS_MMU_MISS_HANDLER 0 |
/* TT = 0x6c, TL = 0, fast_data_access_protection */ |
.org trap_table + TT_FAST_DATA_ACCESS_PROTECTION*ENTRY_SIZE |
.global fast_data_access_protection_handler_tl0 |
fast_data_access_protection_handler_tl0: |
/*FAST_DATA_ACCESS_PROTECTION_HANDLER 0*/ |
/* TT = 0x80, TL = 0, spill_0_normal handler */ |
.org trap_table + TT_SPILL_0_NORMAL*ENTRY_SIZE |
.global spill_0_normal_tl0 |
spill_0_normal_tl0: |
SPILL_NORMAL_HANDLER_KERNEL |
/* TT = 0x84, TL = 0, spill_1_normal handler */ |
.org trap_table + TT_SPILL_1_NORMAL*ENTRY_SIZE |
.global spill_1_normal_tl0 |
spill_1_normal_tl0: |
SPILL_NORMAL_HANDLER_USERSPACE |
/* TT = 0x88, TL = 0, spill_2_normal handler */ |
.org trap_table + TT_SPILL_2_NORMAL*ENTRY_SIZE |
.global spill_2_normal_tl0 |
spill_2_normal_tl0: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xa0, TL = 0, spill_0_other handler */ |
.org trap_table + TT_SPILL_0_OTHER*ENTRY_SIZE |
.global spill_0_other_tl0 |
spill_0_other_tl0: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xc0, TL = 0, fill_0_normal handler */ |
.org trap_table + TT_FILL_0_NORMAL*ENTRY_SIZE |
.global fill_0_normal_tl0 |
fill_0_normal_tl0: |
FILL_NORMAL_HANDLER_KERNEL |
/* TT = 0xc4, TL = 0, fill_1_normal handler */ |
.org trap_table + TT_FILL_1_NORMAL*ENTRY_SIZE |
.global fill_1_normal_tl0 |
fill_1_normal_tl0: |
FILL_NORMAL_HANDLER_USERSPACE |
/* TT = 0x100 - 0x17f, TL = 0, trap_instruction_0 - trap_instruction_7f */ |
.irp cur, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\ |
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\ |
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\ |
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,\ |
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\ |
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,\ |
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,\ |
127 |
.org trap_table + (TT_TRAP_INSTRUCTION_0+\cur)*ENTRY_SIZE |
.global trap_instruction_\cur\()_tl0 |
trap_instruction_\cur\()_tl0: |
ba trap_instruction_handler |
mov \cur, %g2 |
.endr |
/* |
* Handlers for TL>0. |
*/ |
/* TT = 0x08, TL > 0, instruction_access_exception */ |
.org trap_table + (TT_INSTRUCTION_ACCESS_EXCEPTION+512)*ENTRY_SIZE |
.global instruction_access_exception_tl1 |
instruction_access_exception_tl1: |
/*wrpr %g0, 1, %tl |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER instruction_access_exception*/ |
/* TT = 0x0a, TL > 0, instruction_access_error */ |
.org trap_table + (TT_INSTRUCTION_ACCESS_ERROR+512)*ENTRY_SIZE |
.global instruction_access_error_tl1 |
instruction_access_error_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER instruction_access_error |
/* TT = 0x10, TL > 0, illegal_instruction */ |
.org trap_table + (TT_ILLEGAL_INSTRUCTION+512)*ENTRY_SIZE |
.global illegal_instruction_tl1 |
illegal_instruction_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER illegal_instruction |
/* TT = 0x24, TL > 0, clean_window handler */ |
.org trap_table + (TT_CLEAN_WINDOW+512)*ENTRY_SIZE |
.global clean_window_tl1 |
clean_window_tl1: |
CLEAN_WINDOW_HANDLER |
/* TT = 0x28, TL > 0, division_by_zero */ |
.org trap_table + (TT_DIVISION_BY_ZERO+512)*ENTRY_SIZE |
.global division_by_zero_tl1 |
division_by_zero_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER division_by_zero |
/* TT = 0x30, TL > 0, data_access_exception */ |
.org trap_table + (TT_DATA_ACCESS_EXCEPTION+512)*ENTRY_SIZE |
.global data_access_exception_tl1 |
data_access_exception_tl1: |
/*wrpr %g0, 1, %tl |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER data_access_exception*/ |
/* TT = 0x32, TL > 0, data_access_error */ |
.org trap_table + (TT_DATA_ACCESS_ERROR+512)*ENTRY_SIZE |
.global data_access_error_tl1 |
data_access_error_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER data_access_error |
/* TT = 0x34, TL > 0, mem_address_not_aligned */ |
.org trap_table + (TT_MEM_ADDRESS_NOT_ALIGNED+512)*ENTRY_SIZE |
.global mem_address_not_aligned_tl1 |
mem_address_not_aligned_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER mem_address_not_aligned |
/* TT = 0x68, TL > 0, fast_data_access_MMU_miss */ |
.org trap_table + (TT_FAST_DATA_ACCESS_MMU_MISS+512)*ENTRY_SIZE |
.global fast_data_access_mmu_miss_handler_tl1 |
fast_data_access_mmu_miss_handler_tl1: |
FAST_DATA_ACCESS_MMU_MISS_HANDLER 1 |
/* TT = 0x6c, TL > 0, fast_data_access_protection */ |
.org trap_table + (TT_FAST_DATA_ACCESS_PROTECTION+512)*ENTRY_SIZE |
.global fast_data_access_protection_handler_tl1 |
fast_data_access_protection_handler_tl1: |
/*FAST_DATA_ACCESS_PROTECTION_HANDLER 1*/ |
/* TT = 0x80, TL > 0, spill_0_normal handler */ |
.org trap_table + (TT_SPILL_0_NORMAL+512)*ENTRY_SIZE |
.global spill_0_normal_tl1 |
spill_0_normal_tl1: |
SPILL_NORMAL_HANDLER_KERNEL |
/* TT = 0x88, TL > 0, spill_2_normal handler */ |
.org trap_table + (TT_SPILL_2_NORMAL+512)*ENTRY_SIZE |
.global spill_2_normal_tl1 |
spill_2_normal_tl1: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xa0, TL > 0, spill_0_other handler */ |
.org trap_table + (TT_SPILL_0_OTHER+512)*ENTRY_SIZE |
.global spill_0_other_tl1 |
spill_0_other_tl1: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xc0, TL > 0, fill_0_normal handler */ |
.org trap_table + (TT_FILL_0_NORMAL+512)*ENTRY_SIZE |
.global fill_0_normal_tl1 |
fill_0_normal_tl1: |
FILL_NORMAL_HANDLER_KERNEL |
.align TABLE_SIZE |
#define NOT(x) ((x) == 0) |
/* Preemptible trap handler for TL=1. |
* |
* This trap handler makes arrangements to make calling of scheduler() from |
* within a trap context possible. It is called from several other trap |
* handlers. |
* |
* This function can be entered either with interrupt globals or alternate |
* globals. Memory management trap handlers are obliged to switch to one of |
* those global sets prior to calling this function. Register window management |
* functions are not allowed to modify the alternate global registers. |
* |
* The kernel is designed to work on trap levels 0 - 4. For instance, the |
* following can happen: |
* TL0: kernel thread runs (CANSAVE=0, kernel stack not in DTLB) |
* TL1: preemptible trap handler started after a tick interrupt |
* TL2: preemptible trap handler did SAVE |
* TL3: spill handler touched the kernel stack |
* TL4: hardware or software failure |
* |
* Input registers: |
* %g1 Address of function to call if this is not a syscall. |
* %g2 First argument for the function. |
* %g6 Pre-set as kernel stack base if trap from userspace. |
* %g7 Pre-set as address of the userspace window buffer. |
*/ |
.macro PREEMPTIBLE_HANDLER_TEMPLATE is_syscall |
#if 0 |
/* |
* ASSERT(%tl == 1) |
*/ |
rdpr %tl, %g3 |
cmp %g3, 1 |
be 1f |
nop |
0: ba 0b ! this is for debugging, if we ever get here |
nop ! it will be easy to find |
1: |
.if NOT(\is_syscall) |
rdpr %tstate, %g3 |
/* |
* One of the ways this handler can be invoked is after a nested MMU trap from |
* either spill_1_normal or fill_1_normal traps. Both of these traps manipulate |
* the CWP register. We deal with the situation by simulating the MMU trap |
* on TL=1 and restart the respective SAVE or RESTORE instruction once the MMU |
* trap is resolved. However, because we are in the wrong window from the |
* perspective of the MMU trap, we need to synchronize CWP with CWP from TL=0. |
*/ |
and %g3, TSTATE_CWP_MASK, %g4 |
wrpr %g4, 0, %cwp ! resynchronize CWP |
andcc %g3, TSTATE_PRIV_BIT, %g0 ! if this trap came from the privileged mode... |
bnz 0f ! ...skip setting of kernel stack and primary context |
nop |
.endif |
/* |
* Normal window spills will go to the userspace window buffer. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(2), %wstate |
wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent unnecessary clean_window exceptions |
/* |
* Switch to kernel stack. The old stack is |
* automatically saved in the old window's %sp |
* and the new window's %fp. |
*/ |
save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp |
.if \is_syscall |
/* |
* Copy arguments for the syscall to the new window. |
*/ |
mov %i0, %o0 |
mov %i1, %o1 |
mov %i2, %o2 |
mov %i3, %o3 |
mov %i4, %o4 |
mov %i5, %o5 |
.endif |
/* |
* Mark the CANRESTORE windows as OTHER windows. |
*/ |
rdpr %canrestore, %l0 |
wrpr %l0, %otherwin |
wrpr %g0, %canrestore |
/* |
* Switch to primary context 0. |
*/ |
mov VA_PRIMARY_CONTEXT_REG, %l0 |
stxa %g0, [%l0] ASI_DMMU |
rd %pc, %l0 |
flush %l0 |
.if NOT(\is_syscall) |
ba 1f |
nop |
0: |
save %sp, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp |
/* |
* At this moment, we are using the kernel stack |
* and have successfully allocated a register window. |
*/ |
1: |
.endif |
/* |
* Other window spills will go to the userspace window buffer |
* and normal spills will go to the kernel stack. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(0), %wstate |
/* |
* Copy arguments. |
*/ |
mov %g1, %l0 |
.if NOT(\is_syscall) |
mov %g2, %o0 |
.else |
! store the syscall number on the stack as 7th argument |
stx %g2, [%sp + STACK_WINDOW_SAVE_AREA_SIZE + STACK_BIAS + STACK_ARG6] |
.endif |
/* |
* Save TSTATE, TPC and TNPC aside. |
*/ |
rdpr %tstate, %g1 |
rdpr %tpc, %g2 |
rdpr %tnpc, %g3 |
rd %y, %g4 |
stx %g1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE] |
stx %g2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC] |
stx %g3, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC] |
/* |
* Save the Y register. |
* This register is deprecated according to SPARC V9 specification |
* and is only present for backward compatibility with previous |
* versions of the SPARC architecture. |
* Surprisingly, gcc makes use of this register without a notice. |
*/ |
stx %g4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y] |
wrpr %g0, 0, %tl |
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_PEF_BIT, %pstate |
SAVE_GLOBALS |
.if NOT(\is_syscall) |
/* |
* Call the higher-level handler and pass istate as second parameter. |
*/ |
call %l0 |
add %sp, PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC, %o1 |
.else |
/* |
* Call the higher-level syscall handler. |
*/ |
call syscall_handler |
nop |
mov %o0, %i0 ! copy the value returned by the syscall |
.endif |
RESTORE_GLOBALS |
rdpr %pstate, %l1 ! we must preserve the PEF bit |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
wrpr %g0, 1, %tl |
/* |
* Read TSTATE, TPC and TNPC from saved copy. |
*/ |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE], %g1 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC], %g2 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC], %g3 |
/* |
* Copy PSTATE.PEF to the in-register copy of TSTATE. |
*/ |
and %l1, PSTATE_PEF_BIT, %l1 |
sllx %l1, TSTATE_PSTATE_SHIFT, %l1 |
sethi %hi(TSTATE_PEF_BIT), %g4 |
andn %g1, %g4, %g1 |
or %g1, %l1, %g1 |
/* |
* Restore TSTATE, TPC and TNPC from saved copies. |
*/ |
wrpr %g1, 0, %tstate |
wrpr %g2, 0, %tpc |
wrpr %g3, 0, %tnpc |
/* |
* Restore Y. |
*/ |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y], %g4 |
wr %g4, %y |
/* |
* If OTHERWIN is zero, then all the userspace windows have been |
* spilled to kernel memory (i.e. register window buffer). Moreover, |
* if the scheduler was called in the meantime, all valid windows |
* belonging to other threads were spilled by context_restore(). |
* If OTHERWIN is non-zero, then some userspace windows are still |
* valid. Others might have been spilled. However, the CWP pointer |
* needs no fixing because the scheduler had not been called. |
*/ |
rdpr %otherwin, %l0 |
brnz %l0, 0f |
nop |
/* |
* OTHERWIN == 0 |
*/ |
/* |
* If TSTATE.CWP + 1 == CWP, then we still do not have to fix CWP. |
*/ |
and %g1, TSTATE_CWP_MASK, %l0 |
inc %l0 |
and %l0, NWINDOWS - 1, %l0 ! %l0 mod NWINDOWS |
rdpr %cwp, %l1 |
cmp %l0, %l1 |
bz 0f ! CWP is ok |
nop |
/* |
* Fix CWP. |
* In order to recapitulate, the input registers in the current |
* window are the output registers of the window to which we want |
* to restore. Because the fill trap fills only input and local |
* registers of a window, we need to preserve those output |
* registers manually. |
*/ |
mov %sp, %g2 |
stx %i0, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0] |
stx %i1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1] |
stx %i2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I2] |
stx %i3, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I3] |
stx %i4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I4] |
stx %i5, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I5] |
stx %i6, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6] |
stx %i7, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7] |
wrpr %l0, 0, %cwp |
mov %g2, %sp |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0], %i0 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1], %i1 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I2], %i2 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I3], %i3 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I4], %i4 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I5], %i5 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6], %i6 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7], %i7 |
/* |
* OTHERWIN != 0 or fall-through from the OTHERWIN == 0 case. |
* The CWP has already been restored to the value it had after the SAVE |
* at the beginning of this function. |
*/ |
0: |
.if NOT(\is_syscall) |
rdpr %tstate, %g1 |
andcc %g1, TSTATE_PRIV_BIT, %g0 ! if we are not returning to userspace..., |
bnz 1f ! ...skip restoring userspace windows |
nop |
.endif |
/* |
* Spills and fills will be processed by the {spill,fill}_1_normal |
* handlers. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate |
/* |
* Set primary context according to secondary context. |
*/ |
wr %g0, ASI_DMMU, %asi |
ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1 |
stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi |
rd %pc, %g1 |
flush %g1 |
rdpr %cwp, %g1 |
rdpr %otherwin, %g2 |
/* |
* Skip all OTHERWIN windows and descend to the first window |
* in the userspace window buffer. |
*/ |
sub %g1, %g2, %g3 |
dec %g3 |
and %g3, NWINDOWS - 1, %g3 |
wrpr %g3, 0, %cwp |
/* |
* CWP is now in the window last saved in the userspace window buffer. |
* Fill all windows stored in the buffer. |
*/ |
clr %g4 |
0: andcc %g7, UWB_ALIGNMENT - 1, %g0 ! alignment check |
bz 0f ! %g7 is UWB_ALIGNMENT-aligned, no more windows to refill |
nop |
add %g7, -STACK_WINDOW_SAVE_AREA_SIZE, %g7 |
ldx [%g7 + L0_OFFSET], %l0 |
ldx [%g7 + L1_OFFSET], %l1 |
ldx [%g7 + L2_OFFSET], %l2 |
ldx [%g7 + L3_OFFSET], %l3 |
ldx [%g7 + L4_OFFSET], %l4 |
ldx [%g7 + L5_OFFSET], %l5 |
ldx [%g7 + L6_OFFSET], %l6 |
ldx [%g7 + L7_OFFSET], %l7 |
ldx [%g7 + I0_OFFSET], %i0 |
ldx [%g7 + I1_OFFSET], %i1 |
ldx [%g7 + I2_OFFSET], %i2 |
ldx [%g7 + I3_OFFSET], %i3 |
ldx [%g7 + I4_OFFSET], %i4 |
ldx [%g7 + I5_OFFSET], %i5 |
ldx [%g7 + I6_OFFSET], %i6 |
ldx [%g7 + I7_OFFSET], %i7 |
dec %g3 |
and %g3, NWINDOWS - 1, %g3 |
wrpr %g3, 0, %cwp ! switch to the preceeding window |
ba 0b |
inc %g4 |
0: |
/* |
* Switch back to the proper current window and adjust |
* OTHERWIN, CANRESTORE, CANSAVE and CLEANWIN. |
*/ |
wrpr %g1, 0, %cwp |
add %g4, %g2, %g2 |
cmp %g2, NWINDOWS - 2 |
bg 2f ! fix the CANRESTORE=NWINDOWS-1 anomaly |
mov NWINDOWS - 2, %g1 ! use dealy slot for both cases |
sub %g1, %g2, %g1 |
wrpr %g0, 0, %otherwin |
wrpr %g1, 0, %cansave ! NWINDOWS - 2 - CANRESTORE |
wrpr %g2, 0, %canrestore ! OTHERWIN + windows in the buffer |
wrpr %g2, 0, %cleanwin ! avoid information leak |
1: |
restore |
.if \is_syscall |
done |
.else |
retry |
.endif |
/* |
* We got here in order to avoid inconsistency of the window state registers. |
* If the: |
* |
* save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp |
* |
* instruction trapped and spilled a register window into the userspace |
* window buffer, we have just restored NWINDOWS - 1 register windows. |
* However, CANRESTORE can be only NWINDOW - 2 at most. |
* |
* The solution is to manually switch to (CWP - 1) mod NWINDOWS |
* and set the window state registers so that: |
* |
* CANRESTORE = NWINDOWS - 2 |
* CLEANWIN = NWINDOWS - 2 |
* CANSAVE = 0 |
* OTHERWIN = 0 |
* |
* The RESTORE instruction is therfore to be skipped. |
*/ |
2: |
wrpr %g0, 0, %otherwin |
wrpr %g0, 0, %cansave |
wrpr %g1, 0, %canrestore |
wrpr %g1, 0, %cleanwin |
rdpr %cwp, %g1 |
dec %g1 |
and %g1, NWINDOWS - 1, %g1 |
wrpr %g1, 0, %cwp ! CWP-- |
.if \is_syscall |
done |
.else |
retry |
.endif |
#endif |
.endm |
.global preemptible_handler |
preemptible_handler: |
PREEMPTIBLE_HANDLER_TEMPLATE 0 |
.global trap_instruction_handler |
trap_instruction_handler: |
PREEMPTIBLE_HANDLER_TEMPLATE 1 |
/branches/sparc/kernel/arch/sparc64/src/trap/trap.c |
---|
38,7 → 38,7 |
#include <arch/trap/regwin.h> |
#include <arch/trap/exception.h> |
#include <arch/trap/interrupt.h> |
#include <arch/trap/mmu.h> |
#include <arch/trap/sun4u/mmu.h> |
#include <arch/asm.h> |
#include <memstr.h> |
#include <debug.h> |
/branches/sparc/kernel/arch/sparc64/src/trap/sun4u/trap_table.S |
---|
0,0 → 1,851 |
# |
# Copyright (c) 2005 Jakub Jermar |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - 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. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# 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. |
# |
/** |
* @file |
* @brief This file contains kernel trap table. |
*/ |
.register %g2, #scratch |
.register %g3, #scratch |
.text |
#include <arch/trap/trap_table.h> |
#include <arch/trap/regwin.h> |
#include <arch/trap/interrupt.h> |
#include <arch/trap/exception.h> |
#include <arch/trap/syscall.h> |
#include <arch/trap/sun4u/mmu.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/mm/page.h> |
#include <arch/stack.h> |
#include <arch/sun4u/regdef.h> |
#define TABLE_SIZE TRAP_TABLE_SIZE |
#define ENTRY_SIZE TRAP_TABLE_ENTRY_SIZE |
/* |
* Kernel trap table. |
*/ |
.align TABLE_SIZE |
.global trap_table |
trap_table: |
/* TT = 0x08, TL = 0, instruction_access_exception */ |
.org trap_table + TT_INSTRUCTION_ACCESS_EXCEPTION*ENTRY_SIZE |
.global instruction_access_exception_tl0 |
instruction_access_exception_tl0: |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER instruction_access_exception |
/* TT = 0x0a, TL = 0, instruction_access_error */ |
.org trap_table + TT_INSTRUCTION_ACCESS_ERROR*ENTRY_SIZE |
.global instruction_access_error_tl0 |
instruction_access_error_tl0: |
PREEMPTIBLE_HANDLER instruction_access_error |
/* TT = 0x10, TL = 0, illegal_instruction */ |
.org trap_table + TT_ILLEGAL_INSTRUCTION*ENTRY_SIZE |
.global illegal_instruction_tl0 |
illegal_instruction_tl0: |
PREEMPTIBLE_HANDLER illegal_instruction |
/* TT = 0x11, TL = 0, privileged_opcode */ |
.org trap_table + TT_PRIVILEGED_OPCODE*ENTRY_SIZE |
.global privileged_opcode_tl0 |
privileged_opcode_tl0: |
PREEMPTIBLE_HANDLER privileged_opcode |
/* TT = 0x12, TL = 0, unimplemented_LDD */ |
.org trap_table + TT_UNIMPLEMENTED_LDD*ENTRY_SIZE |
.global unimplemented_LDD_tl0 |
unimplemented_LDD_tl0: |
PREEMPTIBLE_HANDLER unimplemented_LDD |
/* TT = 0x13, TL = 0, unimplemented_STD */ |
.org trap_table + TT_UNIMPLEMENTED_STD*ENTRY_SIZE |
.global unimplemented_STD_tl0 |
unimplemented_STD_tl0: |
PREEMPTIBLE_HANDLER unimplemented_STD |
/* TT = 0x20, TL = 0, fb_disabled handler */ |
.org trap_table + TT_FP_DISABLED*ENTRY_SIZE |
.global fb_disabled_tl0 |
fp_disabled_tl0: |
PREEMPTIBLE_HANDLER fp_disabled |
/* TT = 0x21, TL = 0, fb_exception_ieee_754 handler */ |
.org trap_table + TT_FP_EXCEPTION_IEEE_754*ENTRY_SIZE |
.global fb_exception_ieee_754_tl0 |
fp_exception_ieee_754_tl0: |
PREEMPTIBLE_HANDLER fp_exception_ieee_754 |
/* TT = 0x22, TL = 0, fb_exception_other handler */ |
.org trap_table + TT_FP_EXCEPTION_OTHER*ENTRY_SIZE |
.global fb_exception_other_tl0 |
fp_exception_other_tl0: |
PREEMPTIBLE_HANDLER fp_exception_other |
/* TT = 0x23, TL = 0, tag_overflow */ |
.org trap_table + TT_TAG_OVERFLOW*ENTRY_SIZE |
.global tag_overflow_tl0 |
tag_overflow_tl0: |
PREEMPTIBLE_HANDLER tag_overflow |
/* TT = 0x24, TL = 0, clean_window handler */ |
.org trap_table + TT_CLEAN_WINDOW*ENTRY_SIZE |
.global clean_window_tl0 |
clean_window_tl0: |
CLEAN_WINDOW_HANDLER |
/* TT = 0x28, TL = 0, division_by_zero */ |
.org trap_table + TT_DIVISION_BY_ZERO*ENTRY_SIZE |
.global division_by_zero_tl0 |
division_by_zero_tl0: |
PREEMPTIBLE_HANDLER division_by_zero |
/* TT = 0x30, TL = 0, data_access_exception */ |
.org trap_table + TT_DATA_ACCESS_EXCEPTION*ENTRY_SIZE |
.global data_access_exception_tl0 |
data_access_exception_tl0: |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER data_access_exception |
/* TT = 0x32, TL = 0, data_access_error */ |
.org trap_table + TT_DATA_ACCESS_ERROR*ENTRY_SIZE |
.global data_access_error_tl0 |
data_access_error_tl0: |
PREEMPTIBLE_HANDLER data_access_error |
/* TT = 0x34, TL = 0, mem_address_not_aligned */ |
.org trap_table + TT_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global mem_address_not_aligned_tl0 |
mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER mem_address_not_aligned |
/* TT = 0x35, TL = 0, LDDF_mem_address_not_aligned */ |
.org trap_table + TT_LDDF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global LDDF_mem_address_not_aligned_tl0 |
LDDF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER LDDF_mem_address_not_aligned |
/* TT = 0x36, TL = 0, STDF_mem_address_not_aligned */ |
.org trap_table + TT_STDF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global STDF_mem_address_not_aligned_tl0 |
STDF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER STDF_mem_address_not_aligned |
/* TT = 0x37, TL = 0, privileged_action */ |
.org trap_table + TT_PRIVILEGED_ACTION*ENTRY_SIZE |
.global privileged_action_tl0 |
privileged_action_tl0: |
PREEMPTIBLE_HANDLER privileged_action |
/* TT = 0x38, TL = 0, LDQF_mem_address_not_aligned */ |
.org trap_table + TT_LDQF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global LDQF_mem_address_not_aligned_tl0 |
LDQF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER LDQF_mem_address_not_aligned |
/* TT = 0x39, TL = 0, STQF_mem_address_not_aligned */ |
.org trap_table + TT_STQF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE |
.global STQF_mem_address_not_aligned_tl0 |
STQF_mem_address_not_aligned_tl0: |
PREEMPTIBLE_HANDLER STQF_mem_address_not_aligned |
/* TT = 0x41, TL = 0, interrupt_level_1 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_1*ENTRY_SIZE |
.global interrupt_level_1_handler_tl0 |
interrupt_level_1_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 1 |
/* TT = 0x42, TL = 0, interrupt_level_2 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_2*ENTRY_SIZE |
.global interrupt_level_2_handler_tl0 |
interrupt_level_2_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 2 |
/* TT = 0x43, TL = 0, interrupt_level_3 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_3*ENTRY_SIZE |
.global interrupt_level_3_handler_tl0 |
interrupt_level_3_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 3 |
/* TT = 0x44, TL = 0, interrupt_level_4 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_4*ENTRY_SIZE |
.global interrupt_level_4_handler_tl0 |
interrupt_level_4_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 4 |
/* TT = 0x45, TL = 0, interrupt_level_5 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_5*ENTRY_SIZE |
.global interrupt_level_5_handler_tl0 |
interrupt_level_5_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 5 |
/* TT = 0x46, TL = 0, interrupt_level_6 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_6*ENTRY_SIZE |
.global interrupt_level_6_handler_tl0 |
interrupt_level_6_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 6 |
/* TT = 0x47, TL = 0, interrupt_level_7 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_7*ENTRY_SIZE |
.global interrupt_level_7_handler_tl0 |
interrupt_level_7_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 7 |
/* TT = 0x48, TL = 0, interrupt_level_8 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_8*ENTRY_SIZE |
.global interrupt_level_8_handler_tl0 |
interrupt_level_8_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 8 |
/* TT = 0x49, TL = 0, interrupt_level_9 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_9*ENTRY_SIZE |
.global interrupt_level_9_handler_tl0 |
interrupt_level_9_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 9 |
/* TT = 0x4a, TL = 0, interrupt_level_10 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_10*ENTRY_SIZE |
.global interrupt_level_10_handler_tl0 |
interrupt_level_10_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 10 |
/* TT = 0x4b, TL = 0, interrupt_level_11 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_11*ENTRY_SIZE |
.global interrupt_level_11_handler_tl0 |
interrupt_level_11_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 11 |
/* TT = 0x4c, TL = 0, interrupt_level_12 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_12*ENTRY_SIZE |
.global interrupt_level_12_handler_tl0 |
interrupt_level_12_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 12 |
/* TT = 0x4d, TL = 0, interrupt_level_13 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_13*ENTRY_SIZE |
.global interrupt_level_13_handler_tl0 |
interrupt_level_13_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 13 |
/* TT = 0x4e, TL = 0, interrupt_level_14 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_14*ENTRY_SIZE |
.global interrupt_level_14_handler_tl0 |
interrupt_level_14_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 14 |
/* TT = 0x4f, TL = 0, interrupt_level_15 handler */ |
.org trap_table + TT_INTERRUPT_LEVEL_15*ENTRY_SIZE |
.global interrupt_level_15_handler_tl0 |
interrupt_level_15_handler_tl0: |
INTERRUPT_LEVEL_N_HANDLER 15 |
/* TT = 0x60, TL = 0, interrupt_vector_trap handler */ |
.org trap_table + TT_INTERRUPT_VECTOR_TRAP*ENTRY_SIZE |
.global interrupt_vector_trap_handler_tl0 |
interrupt_vector_trap_handler_tl0: |
INTERRUPT_VECTOR_TRAP_HANDLER |
/* TT = 0x64, TL = 0, fast_instruction_access_MMU_miss */ |
.org trap_table + TT_FAST_INSTRUCTION_ACCESS_MMU_MISS*ENTRY_SIZE |
.global fast_instruction_access_mmu_miss_handler_tl0 |
fast_instruction_access_mmu_miss_handler_tl0: |
FAST_INSTRUCTION_ACCESS_MMU_MISS_HANDLER |
/* TT = 0x68, TL = 0, fast_data_access_MMU_miss */ |
.org trap_table + TT_FAST_DATA_ACCESS_MMU_MISS*ENTRY_SIZE |
.global fast_data_access_mmu_miss_handler_tl0 |
fast_data_access_mmu_miss_handler_tl0: |
FAST_DATA_ACCESS_MMU_MISS_HANDLER 0 |
/* TT = 0x6c, TL = 0, fast_data_access_protection */ |
.org trap_table + TT_FAST_DATA_ACCESS_PROTECTION*ENTRY_SIZE |
.global fast_data_access_protection_handler_tl0 |
fast_data_access_protection_handler_tl0: |
FAST_DATA_ACCESS_PROTECTION_HANDLER 0 |
/* TT = 0x80, TL = 0, spill_0_normal handler */ |
.org trap_table + TT_SPILL_0_NORMAL*ENTRY_SIZE |
.global spill_0_normal_tl0 |
spill_0_normal_tl0: |
SPILL_NORMAL_HANDLER_KERNEL |
/* TT = 0x84, TL = 0, spill_1_normal handler */ |
.org trap_table + TT_SPILL_1_NORMAL*ENTRY_SIZE |
.global spill_1_normal_tl0 |
spill_1_normal_tl0: |
SPILL_NORMAL_HANDLER_USERSPACE |
/* TT = 0x88, TL = 0, spill_2_normal handler */ |
.org trap_table + TT_SPILL_2_NORMAL*ENTRY_SIZE |
.global spill_2_normal_tl0 |
spill_2_normal_tl0: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xa0, TL = 0, spill_0_other handler */ |
.org trap_table + TT_SPILL_0_OTHER*ENTRY_SIZE |
.global spill_0_other_tl0 |
spill_0_other_tl0: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xc0, TL = 0, fill_0_normal handler */ |
.org trap_table + TT_FILL_0_NORMAL*ENTRY_SIZE |
.global fill_0_normal_tl0 |
fill_0_normal_tl0: |
FILL_NORMAL_HANDLER_KERNEL |
/* TT = 0xc4, TL = 0, fill_1_normal handler */ |
.org trap_table + TT_FILL_1_NORMAL*ENTRY_SIZE |
.global fill_1_normal_tl0 |
fill_1_normal_tl0: |
FILL_NORMAL_HANDLER_USERSPACE |
/* TT = 0x100 - 0x17f, TL = 0, trap_instruction_0 - trap_instruction_7f */ |
.irp cur, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\ |
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\ |
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\ |
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,\ |
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\ |
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,\ |
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,\ |
127 |
.org trap_table + (TT_TRAP_INSTRUCTION_0+\cur)*ENTRY_SIZE |
.global trap_instruction_\cur\()_tl0 |
trap_instruction_\cur\()_tl0: |
ba trap_instruction_handler |
mov \cur, %g2 |
.endr |
/* |
* Handlers for TL>0. |
*/ |
/* TT = 0x08, TL > 0, instruction_access_exception */ |
.org trap_table + (TT_INSTRUCTION_ACCESS_EXCEPTION+512)*ENTRY_SIZE |
.global instruction_access_exception_tl1 |
instruction_access_exception_tl1: |
wrpr %g0, 1, %tl |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER instruction_access_exception |
/* TT = 0x0a, TL > 0, instruction_access_error */ |
.org trap_table + (TT_INSTRUCTION_ACCESS_ERROR+512)*ENTRY_SIZE |
.global instruction_access_error_tl1 |
instruction_access_error_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER instruction_access_error |
/* TT = 0x10, TL > 0, illegal_instruction */ |
.org trap_table + (TT_ILLEGAL_INSTRUCTION+512)*ENTRY_SIZE |
.global illegal_instruction_tl1 |
illegal_instruction_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER illegal_instruction |
/* TT = 0x24, TL > 0, clean_window handler */ |
.org trap_table + (TT_CLEAN_WINDOW+512)*ENTRY_SIZE |
.global clean_window_tl1 |
clean_window_tl1: |
CLEAN_WINDOW_HANDLER |
/* TT = 0x28, TL > 0, division_by_zero */ |
.org trap_table + (TT_DIVISION_BY_ZERO+512)*ENTRY_SIZE |
.global division_by_zero_tl1 |
division_by_zero_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER division_by_zero |
/* TT = 0x30, TL > 0, data_access_exception */ |
.org trap_table + (TT_DATA_ACCESS_EXCEPTION+512)*ENTRY_SIZE |
.global data_access_exception_tl1 |
data_access_exception_tl1: |
wrpr %g0, 1, %tl |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
PREEMPTIBLE_HANDLER data_access_exception |
/* TT = 0x32, TL > 0, data_access_error */ |
.org trap_table + (TT_DATA_ACCESS_ERROR+512)*ENTRY_SIZE |
.global data_access_error_tl1 |
data_access_error_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER data_access_error |
/* TT = 0x34, TL > 0, mem_address_not_aligned */ |
.org trap_table + (TT_MEM_ADDRESS_NOT_ALIGNED+512)*ENTRY_SIZE |
.global mem_address_not_aligned_tl1 |
mem_address_not_aligned_tl1: |
wrpr %g0, 1, %tl |
PREEMPTIBLE_HANDLER mem_address_not_aligned |
/* TT = 0x68, TL > 0, fast_data_access_MMU_miss */ |
.org trap_table + (TT_FAST_DATA_ACCESS_MMU_MISS+512)*ENTRY_SIZE |
.global fast_data_access_mmu_miss_handler_tl1 |
fast_data_access_mmu_miss_handler_tl1: |
FAST_DATA_ACCESS_MMU_MISS_HANDLER 1 |
/* TT = 0x6c, TL > 0, fast_data_access_protection */ |
.org trap_table + (TT_FAST_DATA_ACCESS_PROTECTION+512)*ENTRY_SIZE |
.global fast_data_access_protection_handler_tl1 |
fast_data_access_protection_handler_tl1: |
FAST_DATA_ACCESS_PROTECTION_HANDLER 1 |
/* TT = 0x80, TL > 0, spill_0_normal handler */ |
.org trap_table + (TT_SPILL_0_NORMAL+512)*ENTRY_SIZE |
.global spill_0_normal_tl1 |
spill_0_normal_tl1: |
SPILL_NORMAL_HANDLER_KERNEL |
/* TT = 0x88, TL > 0, spill_2_normal handler */ |
.org trap_table + (TT_SPILL_2_NORMAL+512)*ENTRY_SIZE |
.global spill_2_normal_tl1 |
spill_2_normal_tl1: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xa0, TL > 0, spill_0_other handler */ |
.org trap_table + (TT_SPILL_0_OTHER+512)*ENTRY_SIZE |
.global spill_0_other_tl1 |
spill_0_other_tl1: |
SPILL_TO_USPACE_WINDOW_BUFFER |
/* TT = 0xc0, TL > 0, fill_0_normal handler */ |
.org trap_table + (TT_FILL_0_NORMAL+512)*ENTRY_SIZE |
.global fill_0_normal_tl1 |
fill_0_normal_tl1: |
FILL_NORMAL_HANDLER_KERNEL |
.align TABLE_SIZE |
#define NOT(x) ((x) == 0) |
/* Preemptible trap handler for TL=1. |
* |
* This trap handler makes arrangements to make calling of scheduler() from |
* within a trap context possible. It is called from several other trap |
* handlers. |
* |
* This function can be entered either with interrupt globals or alternate |
* globals. Memory management trap handlers are obliged to switch to one of |
* those global sets prior to calling this function. Register window management |
* functions are not allowed to modify the alternate global registers. |
* |
* The kernel is designed to work on trap levels 0 - 4. For instance, the |
* following can happen: |
* TL0: kernel thread runs (CANSAVE=0, kernel stack not in DTLB) |
* TL1: preemptible trap handler started after a tick interrupt |
* TL2: preemptible trap handler did SAVE |
* TL3: spill handler touched the kernel stack |
* TL4: hardware or software failure |
* |
* Input registers: |
* %g1 Address of function to call if this is not a syscall. |
* %g2 First argument for the function. |
* %g6 Pre-set as kernel stack base if trap from userspace. |
* %g7 Pre-set as address of the userspace window buffer. |
*/ |
.macro PREEMPTIBLE_HANDLER_TEMPLATE is_syscall |
/* |
* ASSERT(%tl == 1) |
*/ |
rdpr %tl, %g3 |
cmp %g3, 1 |
be 1f |
nop |
0: ba 0b ! this is for debugging, if we ever get here |
nop ! it will be easy to find |
1: |
.if NOT(\is_syscall) |
rdpr %tstate, %g3 |
/* |
* One of the ways this handler can be invoked is after a nested MMU trap from |
* either spill_1_normal or fill_1_normal traps. Both of these traps manipulate |
* the CWP register. We deal with the situation by simulating the MMU trap |
* on TL=1 and restart the respective SAVE or RESTORE instruction once the MMU |
* trap is resolved. However, because we are in the wrong window from the |
* perspective of the MMU trap, we need to synchronize CWP with CWP from TL=0. |
*/ |
and %g3, TSTATE_CWP_MASK, %g4 |
wrpr %g4, 0, %cwp ! resynchronize CWP |
andcc %g3, TSTATE_PRIV_BIT, %g0 ! if this trap came from the privileged mode... |
bnz 0f ! ...skip setting of kernel stack and primary context |
nop |
.endif |
/* |
* Normal window spills will go to the userspace window buffer. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(2), %wstate |
wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent unnecessary clean_window exceptions |
/* |
* Switch to kernel stack. The old stack is |
* automatically saved in the old window's %sp |
* and the new window's %fp. |
*/ |
save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp |
.if \is_syscall |
/* |
* Copy arguments for the syscall to the new window. |
*/ |
mov %i0, %o0 |
mov %i1, %o1 |
mov %i2, %o2 |
mov %i3, %o3 |
mov %i4, %o4 |
mov %i5, %o5 |
.endif |
/* |
* Mark the CANRESTORE windows as OTHER windows. |
*/ |
rdpr %canrestore, %l0 |
wrpr %l0, %otherwin |
wrpr %g0, %canrestore |
/* |
* Switch to primary context 0. |
*/ |
mov VA_PRIMARY_CONTEXT_REG, %l0 |
stxa %g0, [%l0] ASI_DMMU |
rd %pc, %l0 |
flush %l0 |
.if NOT(\is_syscall) |
ba 1f |
nop |
0: |
save %sp, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp |
/* |
* At this moment, we are using the kernel stack |
* and have successfully allocated a register window. |
*/ |
1: |
.endif |
/* |
* Other window spills will go to the userspace window buffer |
* and normal spills will go to the kernel stack. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(0), %wstate |
/* |
* Copy arguments. |
*/ |
mov %g1, %l0 |
.if NOT(\is_syscall) |
mov %g2, %o0 |
.else |
! store the syscall number on the stack as 7th argument |
stx %g2, [%sp + STACK_WINDOW_SAVE_AREA_SIZE + STACK_BIAS + STACK_ARG6] |
.endif |
/* |
* Save TSTATE, TPC and TNPC aside. |
*/ |
rdpr %tstate, %g1 |
rdpr %tpc, %g2 |
rdpr %tnpc, %g3 |
rd %y, %g4 |
stx %g1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE] |
stx %g2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC] |
stx %g3, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC] |
/* |
* Save the Y register. |
* This register is deprecated according to SPARC V9 specification |
* and is only present for backward compatibility with previous |
* versions of the SPARC architecture. |
* Surprisingly, gcc makes use of this register without a notice. |
*/ |
stx %g4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y] |
wrpr %g0, 0, %tl |
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_PEF_BIT, %pstate |
SAVE_GLOBALS |
.if NOT(\is_syscall) |
/* |
* Call the higher-level handler and pass istate as second parameter. |
*/ |
call %l0 |
add %sp, PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC, %o1 |
.else |
/* |
* Call the higher-level syscall handler. |
*/ |
call syscall_handler |
nop |
mov %o0, %i0 ! copy the value returned by the syscall |
.endif |
RESTORE_GLOBALS |
rdpr %pstate, %l1 ! we must preserve the PEF bit |
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate |
wrpr %g0, 1, %tl |
/* |
* Read TSTATE, TPC and TNPC from saved copy. |
*/ |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE], %g1 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC], %g2 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC], %g3 |
/* |
* Copy PSTATE.PEF to the in-register copy of TSTATE. |
*/ |
and %l1, PSTATE_PEF_BIT, %l1 |
sllx %l1, TSTATE_PSTATE_SHIFT, %l1 |
sethi %hi(TSTATE_PEF_BIT), %g4 |
andn %g1, %g4, %g1 |
or %g1, %l1, %g1 |
/* |
* Restore TSTATE, TPC and TNPC from saved copies. |
*/ |
wrpr %g1, 0, %tstate |
wrpr %g2, 0, %tpc |
wrpr %g3, 0, %tnpc |
/* |
* Restore Y. |
*/ |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y], %g4 |
wr %g4, %y |
/* |
* If OTHERWIN is zero, then all the userspace windows have been |
* spilled to kernel memory (i.e. register window buffer). Moreover, |
* if the scheduler was called in the meantime, all valid windows |
* belonging to other threads were spilled by context_restore(). |
* If OTHERWIN is non-zero, then some userspace windows are still |
* valid. Others might have been spilled. However, the CWP pointer |
* needs no fixing because the scheduler had not been called. |
*/ |
rdpr %otherwin, %l0 |
brnz %l0, 0f |
nop |
/* |
* OTHERWIN == 0 |
*/ |
/* |
* If TSTATE.CWP + 1 == CWP, then we still do not have to fix CWP. |
*/ |
and %g1, TSTATE_CWP_MASK, %l0 |
inc %l0 |
and %l0, NWINDOWS - 1, %l0 ! %l0 mod NWINDOWS |
rdpr %cwp, %l1 |
cmp %l0, %l1 |
bz 0f ! CWP is ok |
nop |
/* |
* Fix CWP. |
* In order to recapitulate, the input registers in the current |
* window are the output registers of the window to which we want |
* to restore. Because the fill trap fills only input and local |
* registers of a window, we need to preserve those output |
* registers manually. |
*/ |
mov %sp, %g2 |
stx %i0, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0] |
stx %i1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1] |
stx %i2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I2] |
stx %i3, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I3] |
stx %i4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I4] |
stx %i5, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I5] |
stx %i6, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6] |
stx %i7, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7] |
wrpr %l0, 0, %cwp |
mov %g2, %sp |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0], %i0 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1], %i1 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I2], %i2 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I3], %i3 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I4], %i4 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I5], %i5 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6], %i6 |
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7], %i7 |
/* |
* OTHERWIN != 0 or fall-through from the OTHERWIN == 0 case. |
* The CWP has already been restored to the value it had after the SAVE |
* at the beginning of this function. |
*/ |
0: |
.if NOT(\is_syscall) |
rdpr %tstate, %g1 |
andcc %g1, TSTATE_PRIV_BIT, %g0 ! if we are not returning to userspace..., |
bnz 1f ! ...skip restoring userspace windows |
nop |
.endif |
/* |
* Spills and fills will be processed by the {spill,fill}_1_normal |
* handlers. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate |
/* |
* Set primary context according to secondary context. |
*/ |
wr %g0, ASI_DMMU, %asi |
ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1 |
stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi |
rd %pc, %g1 |
flush %g1 |
rdpr %cwp, %g1 |
rdpr %otherwin, %g2 |
/* |
* Skip all OTHERWIN windows and descend to the first window |
* in the userspace window buffer. |
*/ |
sub %g1, %g2, %g3 |
dec %g3 |
and %g3, NWINDOWS - 1, %g3 |
wrpr %g3, 0, %cwp |
/* |
* CWP is now in the window last saved in the userspace window buffer. |
* Fill all windows stored in the buffer. |
*/ |
clr %g4 |
0: andcc %g7, UWB_ALIGNMENT - 1, %g0 ! alignment check |
bz 0f ! %g7 is UWB_ALIGNMENT-aligned, no more windows to refill |
nop |
add %g7, -STACK_WINDOW_SAVE_AREA_SIZE, %g7 |
ldx [%g7 + L0_OFFSET], %l0 |
ldx [%g7 + L1_OFFSET], %l1 |
ldx [%g7 + L2_OFFSET], %l2 |
ldx [%g7 + L3_OFFSET], %l3 |
ldx [%g7 + L4_OFFSET], %l4 |
ldx [%g7 + L5_OFFSET], %l5 |
ldx [%g7 + L6_OFFSET], %l6 |
ldx [%g7 + L7_OFFSET], %l7 |
ldx [%g7 + I0_OFFSET], %i0 |
ldx [%g7 + I1_OFFSET], %i1 |
ldx [%g7 + I2_OFFSET], %i2 |
ldx [%g7 + I3_OFFSET], %i3 |
ldx [%g7 + I4_OFFSET], %i4 |
ldx [%g7 + I5_OFFSET], %i5 |
ldx [%g7 + I6_OFFSET], %i6 |
ldx [%g7 + I7_OFFSET], %i7 |
dec %g3 |
and %g3, NWINDOWS - 1, %g3 |
wrpr %g3, 0, %cwp ! switch to the preceeding window |
ba 0b |
inc %g4 |
0: |
/* |
* Switch back to the proper current window and adjust |
* OTHERWIN, CANRESTORE, CANSAVE and CLEANWIN. |
*/ |
wrpr %g1, 0, %cwp |
add %g4, %g2, %g2 |
cmp %g2, NWINDOWS - 2 |
bg 2f ! fix the CANRESTORE=NWINDOWS-1 anomaly |
mov NWINDOWS - 2, %g1 ! use dealy slot for both cases |
sub %g1, %g2, %g1 |
wrpr %g0, 0, %otherwin |
wrpr %g1, 0, %cansave ! NWINDOWS - 2 - CANRESTORE |
wrpr %g2, 0, %canrestore ! OTHERWIN + windows in the buffer |
wrpr %g2, 0, %cleanwin ! avoid information leak |
1: |
restore |
.if \is_syscall |
done |
.else |
retry |
.endif |
/* |
* We got here in order to avoid inconsistency of the window state registers. |
* If the: |
* |
* save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp |
* |
* instruction trapped and spilled a register window into the userspace |
* window buffer, we have just restored NWINDOWS - 1 register windows. |
* However, CANRESTORE can be only NWINDOW - 2 at most. |
* |
* The solution is to manually switch to (CWP - 1) mod NWINDOWS |
* and set the window state registers so that: |
* |
* CANRESTORE = NWINDOWS - 2 |
* CLEANWIN = NWINDOWS - 2 |
* CANSAVE = 0 |
* OTHERWIN = 0 |
* |
* The RESTORE instruction is therfore to be skipped. |
*/ |
2: |
wrpr %g0, 0, %otherwin |
wrpr %g0, 0, %cansave |
wrpr %g1, 0, %canrestore |
wrpr %g1, 0, %cleanwin |
rdpr %cwp, %g1 |
dec %g1 |
and %g1, NWINDOWS - 1, %g1 |
wrpr %g1, 0, %cwp ! CWP-- |
.if \is_syscall |
done |
.else |
retry |
.endif |
.endm |
.global preemptible_handler |
preemptible_handler: |
PREEMPTIBLE_HANDLER_TEMPLATE 0 |
.global trap_instruction_handler |
trap_instruction_handler: |
PREEMPTIBLE_HANDLER_TEMPLATE 1 |
/branches/sparc/kernel/arch/sparc64/src/mm/tlb.c |
---|
33,12 → 33,13 |
*/ |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4u/tlb.h> |
#include <mm/tlb.h> |
#include <mm/as.h> |
#include <mm/asid.h> |
#include <arch/mm/frame.h> |
#include <arch/mm/page.h> |
#include <arch/mm/mmu.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/interrupt.h> |
#include <interrupt.h> |
#include <arch.h> |
/branches/sparc/kernel/arch/sparc64/src/mm/as.c |
---|
34,6 → 34,7 |
#include <arch/mm/as.h> |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4u/tlb.h> |
#include <genarch/mm/page_ht.h> |
#include <genarch/mm/asid_fifo.h> |
#include <debug.h> |
/branches/sparc/kernel/arch/sparc64/src/mm/cache.S |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#include <arch/arch.h> |
#include <arch/sun4u/arch.h> |
#include <arch/mm/cache_spec.h> |
#define DCACHE_TAG_SHIFT 2 |
/branches/sparc/kernel/arch/sparc64/src/mm/page.c |
---|
34,6 → 34,7 |
#include <arch/mm/page.h> |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4u/tlb.h> |
#include <genarch/mm/page_ht.h> |
#include <mm/frame.h> |
#include <arch/mm/frame.h> |
/branches/sparc/kernel/arch/sparc64/src/drivers/niagara.c |
---|
0,0 → 1,88 |
/* |
* Copyright (c) 2008 Pavel Rimsky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** |
* @file |
* @brief Niagara input/output driver based on hypervisor calls. |
*/ |
#include <arch/drivers/niagara.h> |
#include <console/chardev.h> |
#include <console/console.h> |
#include <arch/sun4v/hypercall.h> |
/* functions referenced from definitions of I/O operations structures */ |
static void niagara_putchar(chardev_t *, const char); |
/** character device operations */ |
static chardev_operations_t niagara_ops = { |
.write = niagara_putchar |
}; |
/** Niagara character device */ |
chardev_t niagara_io; |
/** Writes a single character to the standard output. */ |
static void niagara_putchar(struct chardev * cd, const char c) |
{ |
__hypercall_fast1(CONS_PUTCHAR, c); |
if (c == '\n') |
__hypercall_fast1(CONS_PUTCHAR, '\r'); |
} |
/** |
* Grabs the input for kernel. |
*/ |
void niagara_grab(void) |
{ |
} |
/** |
* Releases the input so that userspace can use it. |
*/ |
void niagara_release(void) |
{ |
} |
/** |
* Initializes the input/output subsystem so that the Niagara standard |
* input/output is used. |
*/ |
void niagara_init(void) |
{ |
chardev_initialize("niagara_io", &niagara_io, &niagara_ops); |
stdin = &niagara_io; |
stdout = &niagara_io; |
} |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/src/sun4u/asm.S |
---|
0,0 → 1,117 |
# |
# Copyright (c) 2005 Jakub Jermar |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - 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. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# 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. |
# |
#include <arch/arch.h> |
#include <arch/stack.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/sun4u/regdef.h> |
.text |
.register %g2, #scratch |
.register %g3, #scratch |
.macro WRITE_ALTERNATE_REGISTER reg, bit |
rdpr %pstate, %g1 ! save PSTATE.PEF |
wrpr %g0, (\bit | PSTATE_PRIV_BIT), %pstate |
mov %o0, \reg |
wrpr %g0, PSTATE_PRIV_BIT, %pstate |
retl |
wrpr %g1, 0, %pstate ! restore PSTATE.PEF |
.endm |
.macro READ_ALTERNATE_REGISTER reg, bit |
rdpr %pstate, %g1 ! save PSTATE.PEF |
wrpr %g0, (\bit | PSTATE_PRIV_BIT), %pstate |
mov \reg, %o0 |
wrpr %g0, PSTATE_PRIV_BIT, %pstate |
retl |
wrpr %g1, 0, %pstate ! restore PSTATE.PEF |
.endm |
.global write_to_ag_g6 |
write_to_ag_g6: |
WRITE_ALTERNATE_REGISTER %g6, PSTATE_AG_BIT |
.global write_to_ag_g7 |
write_to_ag_g7: |
WRITE_ALTERNATE_REGISTER %g7, PSTATE_AG_BIT |
.global write_to_ig_g6 |
write_to_ig_g6: |
WRITE_ALTERNATE_REGISTER %g6, PSTATE_IG_BIT |
.global read_from_ag_g7 |
read_from_ag_g7: |
READ_ALTERNATE_REGISTER %g7, PSTATE_AG_BIT |
/** Switch to userspace. |
* |
* %o0 Userspace entry address. |
* %o1 Userspace stack pointer address. |
* %o2 Userspace address of uarg structure. |
*/ |
.global switch_to_userspace |
switch_to_userspace: |
save %o1, -STACK_WINDOW_SAVE_AREA_SIZE, %sp |
flushw |
wrpr %g0, 0, %cleanwin ! avoid information leak |
mov %i2, %o0 ! uarg |
xor %o1, %o1, %o1 ! %o1 is defined to hold pcb_ptr |
! set it to 0 |
clr %i2 |
clr %i3 |
clr %i4 |
clr %i5 |
clr %i6 |
wrpr %g0, 1, %tl ! enforce mapping via nucleus |
rdpr %cwp, %g1 |
wrpr %g1, TSTATE_IE_BIT, %tstate |
wrpr %i0, 0, %tnpc |
/* |
* Set primary context according to secondary context. |
* Secondary context has been already installed by |
* higher-level functions. |
*/ |
wr %g0, ASI_DMMU, %asi |
ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1 |
stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi |
flush %i7 |
/* |
* Spills and fills will be handled by the userspace handlers. |
*/ |
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate |
done ! jump to userspace |
/branches/sparc/kernel/arch/sparc64/src/sun4u/sparc64.c |
---|
0,0 → 1,168 |
/* |
* Copyright (c) 2005 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - 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. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* 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. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#include <arch.h> |
#include <debug.h> |
#include <config.h> |
#include <arch/trap/trap.h> |
#include <arch/console.h> |
#include <proc/thread.h> |
#include <console/console.h> |
#include <arch/boot/boot.h> |
#include <arch/arch.h> |
#include <arch/asm.h> |
#include <arch/mm/page.h> |
#include <arch/stack.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <userspace.h> |
#include <ddi/irq.h> |
#include <print.h> |
#include <arch/drivers/niagara.h> |
bootinfo_t bootinfo; |
/** Perform sparc64 specific initialization before main_bsp() is called. */ |
void arch_pre_main(void) |
{ |
/* Copy init task info. */ |
init.cnt = bootinfo.taskmap.count; |
uint32_t i; |
for (i = 0; i < bootinfo.taskmap.count; i++) { |
init.tasks[i].addr = (uintptr_t) bootinfo.taskmap.tasks[i].addr; |
init.tasks[i].size = bootinfo.taskmap.tasks[i].size; |
} |
/* Copy boot allocations info. */ |
ballocs.base = bootinfo.ballocs.base; |
ballocs.size = bootinfo.ballocs.size; |
ofw_tree_init(bootinfo.ofw_root); |
} |
/** Perform sparc64 specific initialization before mm is initialized. */ |
void arch_pre_mm_init(void) |
{ |
if (config.cpu_active == 1) |
trap_init(); |
} |
/** Perform sparc64 specific initialization afterr mm is initialized. */ |
void arch_post_mm_init(void) |
{ |
if (config.cpu_active == 1) { |
/* |
* We have 2^11 different interrupt vectors. |
* But we only create 128 buckets. |
*/ |
irq_init(1 << 11, 128); |
standalone_sparc64_console_init(); |
} |
} |
void arch_post_cpu_init(void) |
{ |
} |
void arch_pre_smp_init(void) |
{ |
} |
void arch_post_smp_init(void) |
{ |
static thread_t *t = NULL; |
if (!t) { |
/* |
* Create thread that polls keyboard. |
*/ |
t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll", true); |
if (!t) |
panic("cannot create kkbdpoll\n"); |
thread_ready(t); |
} |
} |
/** Calibrate delay loop. |
* |
* On sparc64, we implement delay() by waiting for the TICK register to |
* reach a pre-computed value, as opposed to performing some pre-computed |
* amount of instructions of known duration. We set the delay_loop_const |
* to 1 in order to neutralize the multiplication done by delay(). |
*/ |
void calibrate_delay_loop(void) |
{ |
CPU->delay_loop_const = 1; |
} |
/** Wait several microseconds. |
* |
* We assume that interrupts are already disabled. |
* |
* @param t Microseconds to wait. |
*/ |
void asm_delay_loop(const uint32_t usec) |
{ |
uint64_t stop = tick_read() + (uint64_t) usec * (uint64_t) |
CPU->arch.clock_frequency / 1000000; |
while (tick_read() < stop) |
; |
} |
/** Switch to userspace. */ |
void userspace(uspace_arg_t *kernel_uarg) |
{ |
switch_to_userspace((uintptr_t) kernel_uarg->uspace_entry, |
((uintptr_t) kernel_uarg->uspace_stack) + STACK_SIZE |
- (ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT) + STACK_BIAS), |
(uintptr_t) kernel_uarg->uspace_uarg); |
for (;;) |
; |
/* not reached */ |
} |
void arch_reboot(void) |
{ |
// TODO |
while (1); |
} |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/src/sun4u/start.S |
---|
0,0 → 1,399 |
# |
# Copyright (c) 2005 Jakub Jermar |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - 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. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# 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. |
# |
#include <arch/arch.h> |
#include <arch/sun4u/arch.h> |
#include <arch/cpu.h> |
#include <arch/sun4u/regdef.h> |
#include <arch/boot/boot.h> |
#include <arch/stack.h> |
#include <arch/mm/sun4u/mmu.h> |
#include <arch/mm/tlb.h> |
#include <arch/mm/sun4u/tlb.h> |
#include <arch/mm/sun4u/tte.h> |
#ifdef CONFIG_SMP |
#include <arch/context_offset.h> |
#endif |
.register %g2, #scratch |
.register %g3, #scratch |
.section K_TEXT_START, "ax" |
#define BSP_FLAG 1 |
/* |
* 2^PHYSMEM_ADDR_SIZE is the size of the physical address space on |
* a given processor. |
*/ |
#if defined (US) |
#define PHYSMEM_ADDR_SIZE 41 |
#elif defined (US3) |
#define PHYSMEM_ADDR_SIZE 43 |
#endif |
/* |
* Here is where the kernel is passed control from the boot loader. |
* |
* The registers are expected to be in this state: |
* - %o0 starting address of physical memory + bootstrap processor flag |
* bits 63...1: physical memory starting address / 2 |
* bit 0: non-zero on BSP processor, zero on AP processors |
* - %o1 bootinfo structure address (BSP only) |
* - %o2 bootinfo structure size (BSP only) |
* |
* Moreover, we depend on boot having established the following environment: |
* - TLBs are on |
* - identity mapping for the kernel image |
*/ |
.global kernel_image_start |
kernel_image_start: |
mov BSP_FLAG, %l0 |
and %o0, %l0, %l7 ! l7 <= bootstrap processor? |
andn %o0, %l0, %l6 ! l6 <= start of physical memory |
! Get bits (PHYSMEM_ADDR_SIZE - 1):13 of physmem_base. |
srlx %l6, 13, %l5 |
! l5 <= physmem_base[(PHYSMEM_ADDR_SIZE - 1):13] |
sllx %l5, 13 + (63 - (PHYSMEM_ADDR_SIZE - 1)), %l5 |
srlx %l5, 63 - (PHYSMEM_ADDR_SIZE - 1), %l5 |
/* |
* Setup basic runtime environment. |
*/ |
wrpr %g0, NWINDOWS - 2, %cansave ! set maximum saveable windows |
wrpr %g0, 0, %canrestore ! get rid of windows we will |
! never need again |
wrpr %g0, 0, %otherwin ! make sure the window state is |
! consistent |
wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent needless clean_window |
! traps for kernel |
wrpr %g0, 0, %wstate ! use default spill/fill trap |
wrpr %g0, 0, %tl ! TL = 0, primary context |
! register is used |
wrpr %g0, PSTATE_PRIV_BIT, %pstate ! disable interrupts and disable |
! 32-bit address masking |
wrpr %g0, 0, %pil ! intialize %pil |
/* |
* Switch to kernel trap table. |
*/ |
sethi %hi(trap_table), %g1 |
wrpr %g1, %lo(trap_table), %tba |
/* |
* Take over the DMMU by installing locked TTE entry identically |
* mapping the first 4M of memory. |
* |
* In case of DMMU, no FLUSH instructions need to be issued. Because of |
* that, the old DTLB contents can be demapped pretty straightforwardly |
* and without causing any traps. |
*/ |
wr %g0, ASI_DMMU, %asi |
#define SET_TLB_DEMAP_CMD(r1, context_id) \ |
set (TLB_DEMAP_CONTEXT << TLB_DEMAP_TYPE_SHIFT) | (context_id << \ |
TLB_DEMAP_CONTEXT_SHIFT), %r1 |
! demap context 0 |
SET_TLB_DEMAP_CMD(g1, TLB_DEMAP_NUCLEUS) |
stxa %g0, [%g1] ASI_DMMU_DEMAP |
membar #Sync |
#define SET_TLB_TAG(r1, context) \ |
set VMA | (context << TLB_TAG_ACCESS_CONTEXT_SHIFT), %r1 |
! write DTLB tag |
SET_TLB_TAG(g1, MEM_CONTEXT_KERNEL) |
stxa %g1, [VA_DMMU_TAG_ACCESS] %asi |
membar #Sync |
#ifdef CONFIG_VIRT_IDX_DCACHE |
#define TTE_LOW_DATA(imm) (TTE_CP | TTE_CV | TTE_P | LMA | (imm)) |
#else /* CONFIG_VIRT_IDX_DCACHE */ |
#define TTE_LOW_DATA(imm) (TTE_CP | TTE_P | LMA | (imm)) |
#endif /* CONFIG_VIRT_IDX_DCACHE */ |
#define SET_TLB_DATA(r1, r2, imm) \ |
set TTE_LOW_DATA(imm), %r1; \ |
or %r1, %l5, %r1; \ |
mov PAGESIZE_4M, %r2; \ |
sllx %r2, TTE_SIZE_SHIFT, %r2; \ |
or %r1, %r2, %r1; \ |
mov 1, %r2; \ |
sllx %r2, TTE_V_SHIFT, %r2; \ |
or %r1, %r2, %r1; |
! write DTLB data and install the kernel mapping |
SET_TLB_DATA(g1, g2, TTE_L | TTE_W) ! use non-global mapping |
stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG |
membar #Sync |
/* |
* Because we cannot use global mappings (because we want to have |
* separate 64-bit address spaces for both the kernel and the |
* userspace), we prepare the identity mapping also in context 1. This |
* step is required by the code installing the ITLB mapping. |
*/ |
! write DTLB tag of context 1 (i.e. MEM_CONTEXT_TEMP) |
SET_TLB_TAG(g1, MEM_CONTEXT_TEMP) |
stxa %g1, [VA_DMMU_TAG_ACCESS] %asi |
membar #Sync |
! write DTLB data and install the kernel mapping in context 1 |
SET_TLB_DATA(g1, g2, TTE_W) ! use non-global mapping |
stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG |
membar #Sync |
/* |
* Now is time to take over the IMMU. Unfortunatelly, it cannot be done |
* as easily as the DMMU, because the IMMU is mapping the code it |
* executes. |
* |
* [ Note that brave experiments with disabling the IMMU and using the |
* DMMU approach failed after a dozen of desparate days with only little |
* success. ] |
* |
* The approach used here is inspired from OpenBSD. First, the kernel |
* creates IMMU mapping for itself in context 1 (MEM_CONTEXT_TEMP) and |
* switches to it. Context 0 (MEM_CONTEXT_KERNEL) can be demapped |
* afterwards and replaced with the kernel permanent mapping. Finally, |
* the kernel switches back to context 0 and demaps context 1. |
* |
* Moreover, the IMMU requires use of the FLUSH instructions. But that |
* is OK because we always use operands with addresses already mapped by |
* the taken over DTLB. |
*/ |
set kernel_image_start, %g5 |
! write ITLB tag of context 1 |
SET_TLB_TAG(g1, MEM_CONTEXT_TEMP) |
mov VA_DMMU_TAG_ACCESS, %g2 |
stxa %g1, [%g2] ASI_IMMU |
flush %g5 |
! write ITLB data and install the temporary mapping in context 1 |
SET_TLB_DATA(g1, g2, 0) ! use non-global mapping |
stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG |
flush %g5 |
! switch to context 1 |
mov MEM_CONTEXT_TEMP, %g1 |
stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi ! ASI_DMMU is correct here !!! |
flush %g5 |
! demap context 0 |
SET_TLB_DEMAP_CMD(g1, TLB_DEMAP_NUCLEUS) |
stxa %g0, [%g1] ASI_IMMU_DEMAP |
flush %g5 |
! write ITLB tag of context 0 |
SET_TLB_TAG(g1, MEM_CONTEXT_KERNEL) |
mov VA_DMMU_TAG_ACCESS, %g2 |
stxa %g1, [%g2] ASI_IMMU |
flush %g5 |
! write ITLB data and install the permanent kernel mapping in context 0 |
SET_TLB_DATA(g1, g2, TTE_L) ! use non-global mapping |
stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG |
flush %g5 |
! enter nucleus - using context 0 |
wrpr %g0, 1, %tl |
! demap context 1 |
SET_TLB_DEMAP_CMD(g1, TLB_DEMAP_PRIMARY) |
stxa %g0, [%g1] ASI_IMMU_DEMAP |
flush %g5 |
! set context 0 in the primary context register |
stxa %g0, [VA_PRIMARY_CONTEXT_REG] %asi ! ASI_DMMU is correct here !!! |
flush %g5 |
! leave nucleus - using primary context, i.e. context 0 |
wrpr %g0, 0, %tl |
brz %l7, 1f ! skip if you are not the bootstrap CPU |
nop |
/* |
* Save physmem_base for use by the mm subsystem. |
* %l6 contains starting physical address |
*/ |
sethi %hi(physmem_base), %l4 |
stx %l6, [%l4 + %lo(physmem_base)] |
/* |
* Precompute kernel 8K TLB data template. |
* %l5 contains starting physical address |
* bits [(PHYSMEM_ADDR_SIZE - 1):13] |
*/ |
sethi %hi(kernel_8k_tlb_data_template), %l4 |
ldx [%l4 + %lo(kernel_8k_tlb_data_template)], %l3 |
or %l3, %l5, %l3 |
stx %l3, [%l4 + %lo(kernel_8k_tlb_data_template)] |
/* |
* Flush D-Cache. |
*/ |
call dcache_flush |
nop |
/* |
* So far, we have not touched the stack. |
* It is a good idea to set the kernel stack to a known state now. |
*/ |
sethi %hi(temporary_boot_stack), %sp |
or %sp, %lo(temporary_boot_stack), %sp |
sub %sp, STACK_BIAS, %sp |
sethi 0x42142, %g0 |
sethi %hi(bootinfo), %o0 |
call memcpy ! copy bootinfo |
or %o0, %lo(bootinfo), %o0 |
call arch_pre_main |
nop |
call main_bsp |
nop |
/* Not reached. */ |
0: |
ba 0b |
nop |
1: |
#ifdef CONFIG_SMP |
/* |
* Determine the width of the MID and save its mask to %g3. The width |
* is |
* * 5 for US and US-IIIi, |
* * 10 for US3 except US-IIIi. |
*/ |
#if defined(US) |
mov 0x1f, %g3 |
#elif defined(US3) |
mov 0x3ff, %g3 |
rdpr %ver, %g2 |
sllx %g2, 16, %g2 |
srlx %g2, 48, %g2 |
cmp %g2, IMPL_ULTRASPARCIII_I |
move %xcc, 0x1f, %g3 |
#endif |
/* |
* Read MID from the processor. |
*/ |
ldxa [%g0] ASI_ICBUS_CONFIG, %g1 |
srlx %g1, ICBUS_CONFIG_MID_SHIFT, %g1 |
and %g1, %g3, %g1 |
/* |
* Active loop for APs until the BSP picks them up. A processor cannot |
* leave the loop until the global variable 'waking_up_mid' equals its |
* MID. |
*/ |
set waking_up_mid, %g2 |
2: |
ldx [%g2], %g3 |
cmp %g3, %g1 |
bne 2b |
nop |
/* |
* Configure stack for the AP. |
* The AP is expected to use the stack saved |
* in the ctx global variable. |
*/ |
set ctx, %g1 |
add %g1, OFFSET_SP, %g1 |
ldx [%g1], %o6 |
call main_ap |
nop |
/* Not reached. */ |
#endif |
0: |
ba 0b |
nop |
.section K_DATA_START, "aw", @progbits |
/* |
* Create small stack to be used by the bootstrap processor. It is going to be |
* used only for a very limited period of time, but we switch to it anyway, |
* just to be sure we are properly initialized. |
*/ |
#define INITIAL_STACK_SIZE 1024 |
.align STACK_ALIGNMENT |
.space INITIAL_STACK_SIZE |
.align STACK_ALIGNMENT |
temporary_boot_stack: |
.space STACK_WINDOW_SAVE_AREA_SIZE |
.data |
.align 8 |
.global physmem_base ! copy of the physical memory base address |
physmem_base: |
.quad 0 |
/* |
* This variable is used by the fast_data_MMU_miss trap handler. In runtime, it |
* is further modified to reflect the starting address of physical memory. |
*/ |
.global kernel_8k_tlb_data_template |
kernel_8k_tlb_data_template: |
#ifdef CONFIG_VIRT_IDX_DCACHE |
.quad ((1 << TTE_V_SHIFT) | (PAGESIZE_8K << TTE_SIZE_SHIFT) | TTE_CP | \ |
TTE_CV | TTE_P | TTE_W) |
#else /* CONFIG_VIRT_IDX_DCACHE */ |
.quad ((1 << TTE_V_SHIFT) | (PAGESIZE_8K << TTE_SIZE_SHIFT) | TTE_CP | \ |
TTE_P | TTE_W) |
#endif /* CONFIG_VIRT_IDX_DCACHE */ |