Changeset View
Changeset View
Standalone View
Standalone View
sys/mips/mips/exception.S
Show First 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | dtrace_invop_calltrap_addr: | ||||
.text | .text | ||||
#endif | #endif | ||||
/* | /* | ||||
* Reasonable limit | * Reasonable limit | ||||
*/ | */ | ||||
#define INTRCNT_COUNT 256 | #define INTRCNT_COUNT 256 | ||||
/* | |||||
* General MIPS CPU state for exceptions: | |||||
* | |||||
* EPC Register will point to the instruction that caused fault, unless the | |||||
* faulting instruction was in a branch delay slot. In that case, it will | |||||
* point to the branch before the branch delay slot instruction. | |||||
* | |||||
* The cause register will contain what caused the exception and some state | |||||
* about the interrupt. | |||||
* | |||||
* The status register contains information about the status of the CPU such | |||||
* as: Kernel/User mode bit, interrupt enable bit. | |||||
* | |||||
* The BadVaddr register contains the virtual address that cause the last | |||||
* exception. | |||||
* | |||||
* The Context register contains the lower 22 bits of the VPN (starting at | |||||
* bit 4) that cause the last exception except bit0 and bit1 are zero. The | |||||
* upper bits (bits 23 to 31 for MIPS32 and bits 23 to 63) are set under | |||||
* kernel control (i.e. point to the page table). The Context/XContext | |||||
* registers are not currently used by FreeBSD. | |||||
*/ | |||||
/* | /* | ||||
*---------------------------------------------------------------------------- | *---------------------------------------------------------------------------- | ||||
* | * | ||||
* MipsTLBMiss -- | * MipsTLBMiss -- | ||||
* | * | ||||
* Vector code for the TLB-miss exception vector 0x80000000. | * Vector code for the TLB-miss exception vector 0x80000000. | ||||
* | * | ||||
Show All 9 Lines | VECTOR(MipsTLBMiss, unknown) | ||||
j MipsDoTLBMiss | j MipsDoTLBMiss | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address | MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address | ||||
.set pop | .set pop | ||||
VECTOR_END(MipsTLBMiss) | VECTOR_END(MipsTLBMiss) | ||||
/* | /* | ||||
*---------------------------------------------------------------------------- | *---------------------------------------------------------------------------- | ||||
* | * | ||||
* MipsDoTLBMiss -- | * MipsDoTLBMiss -- (UTLB miss) | ||||
* | * | ||||
* This is the real TLB Miss Handler code. | * This is the real TLB Miss Handler code. A miss was generated when the | ||||
* access is to kuseg and there was not matching mapping loaded into the TLB. | |||||
* 'segbase' points to the base of the segment table for user processes. | * 'segbase' points to the base of the segment table for user processes. | ||||
* | * | ||||
* The CPU does the following for an UTLB miss: | |||||
* - Sets the EPC register. | |||||
* - Sets the Cause register. | |||||
* - Sets the Status register. Shifts K/U and IE bits over one and clears | |||||
* the current Kernel/User and Interrupt Enable bits. So the processor | |||||
* is in kernel mode with the interupts turned off. | |||||
* - Sets BadVaddr register. | |||||
* - Sets the Context/XContext register(s). | |||||
* - Sets the TLB EntryHi register to contain VPN of the faulting address. | |||||
* | |||||
* Don't check for invalid pte's here. We load them as well and | * Don't check for invalid pte's here. We load them as well and | ||||
* let the processor trap to load the correct value after service. | * let the processor trap to load the correct value after service. | ||||
* | |||||
* XXX This really needs to be changed to a linear page table and use the | |||||
* Context and XContext registers. That is really what it was designed for. | |||||
*---------------------------------------------------------------------------- | *---------------------------------------------------------------------------- | ||||
*/ | */ | ||||
.set push | .set push | ||||
.set noat | .set noat | ||||
MipsDoTLBMiss: | MipsDoTLBMiss: | ||||
bltz k0, 1f #02: k0<0 -> 1f (kernel fault) | bltz k0, 1f #02: k0<0 -> 1f (kernel fault) | ||||
PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) | PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) | ||||
GET_CPU_PCPU(k1) | GET_CPU_PCPU(k1) | ||||
PTR_L k1, PC_SEGBASE(k1) | PTR_L k1, PC_SEGBASE(k1) | ||||
beqz k1, 2f #05: make sure segbase is not null | beqz k1, 2f #05: make sure segbase is not null | ||||
andi k0, k0, PDEPTRMASK #06: k0=seg offset | andi k0, k0, PDEPTRMASK #06: k0=seg offset | ||||
PTR_ADDU k1, k0, k1 #07: k1=seg entry address | PTR_ADDU k1, k0, k1 #07: k1=seg entry address | ||||
PTR_L k1, 0(k1) #08: k1=seg entry | PTR_L k1, 0(k1) #08: k1=seg entry | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) | MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) | ||||
beq k1, zero, 2f #0a: ==0 -- no page table | beq k1, zero, 2f #0a: ==0 -- no page table | ||||
#ifdef __mips_n64 | #ifdef __mips_n64 | ||||
PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN | PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN | ||||
andi k0, k0, PDEPTRMASK # k0=pde offset | andi k0, k0, PDEPTRMASK # k0=pde offset | ||||
PTR_ADDU k1, k0, k1 # k1=pde entry address | PTR_ADDU k0, k0, k1 # k1=pde entry address | ||||
PTR_L k1, 0(k1) # k1=pde entry | PTR_L k1, 0(k0) # k1=pde entry | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | |||||
beq k1, zero, 2f # ==0 -- no page table | beq k1, zero, 2f # ==0 -- no page table | ||||
nop | |||||
#ifdef MIPS64_NEW_PMAP | |||||
# Check for superpage | |||||
GET_SUPERPAGE_IDX(k1) # k1=superpage index from PTE | |||||
beq k1, zero, not_superpage # ==0 -- not superpage | |||||
PTR_L k1, 0(k0) # k1=pde entry (delay slot) | |||||
# Set the referenced bit in the PDE if valid. | |||||
# | |||||
# XXX Setting the referenced bit here saves a fault later but it | |||||
# may not be safe to do so. Therefore, just take the fault to set | |||||
# the reference bit. | |||||
# IF_VALID_SET_REFBIT(k1, k0, 0, 1) | |||||
# The PDE is actually a superpage PTE. Store it in the TLB lo0 reg. | |||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO0 # lo0 is loaded | |||||
COP0_SYNC | |||||
# Compute the PFN for the TLB lo1 register from k1(=PTE for TLB lo0). | |||||
GET_ODD_1M_PFN_FROM_EVEN(k1) # k1=Odd PFN in PTE postion | |||||
# Get hard TLB flag bits. | |||||
PTR_L k0, 0(k0) # k0=pde entry (again) | |||||
GET_HW_TLB_FLAGS(k0) # k0=hw TLB flag bits | |||||
or k1, k1, k0 # k1=PTE=PFN | hwflg bits | |||||
# Load it into the TLB Lo1 register. | |||||
#CLEAR_PTE_SWBITS(k1) # No SW bits to clear | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded | |||||
COP0_SYNC | |||||
# Load the TLB PageMask for 1M pages. | |||||
dli k0, TLBMASK_1M_PAGE # PageMask for 1M Page | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_PG_MASK # PageMask is loaded | |||||
COP0_SYNC | |||||
tlbwr # write to tlb | |||||
HAZARD_DELAY | |||||
PTE_MTC0 zero, MIPS_COP_0_TLB_PG_MASK # zero out PageMask reg | |||||
COP0_SYNC | |||||
eret # return from exception | |||||
not_superpage: | |||||
#endif /* MIPS64_NEW_PMAP */ | |||||
#endif | #endif | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | |||||
PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) | PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) | ||||
andi k0, k0, PTE2MASK #0c: k0=page tab offset | andi k0, k0, PTE2MASK #0c: k0=page tab offset | ||||
PTR_ADDU k1, k1, k0 #0d: k1=pte address | PTR_ADDU k1, k1, k0 #0d: k1=pte address | ||||
PTE_L k0, 0(k1) #0e: k0=lo0 pte | |||||
PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte | PTE_L k0, 0(k1) # k0=lo0 pte | ||||
# Set the referenced bit in the PDE if valid. | |||||
# | |||||
# XXX Setting the referenced bit here saves a fault later but it | |||||
# may not be safe to do so. Therefore, just take the fault to set | |||||
# the reference bit. | |||||
# IF_VALID_SET_REFBIT(k0, k1, 0, 2) | |||||
CLEAR_PTE_SWBITS(k0) | CLEAR_PTE_SWBITS(k0) | ||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded | PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded | ||||
COP0_SYNC | COP0_SYNC | ||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded | PTE_L k0, PTESIZE(k1) # k0=lo1 pte | ||||
# Set the referenced bit in the PDE if valid. | |||||
# | |||||
# XXX Setting the referenced bit here saves a fault later but it | |||||
# may not be safe to do so. Therefore, just take the fault to set | |||||
# the reference bit. | |||||
# IF_VALID_SET_REFBIT(k0, k1, 0, 3) | |||||
CLEAR_PTE_SWBITS(k0) | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded | |||||
COP0_SYNC | COP0_SYNC | ||||
tlbwr #1a: write to tlb | tlbwr #1a: write to tlb | ||||
HAZARD_DELAY | HAZARD_DELAY | ||||
eret #1f: retUrn from exception | eret #1f: retUrn from exception | ||||
1: j MipsTLBMissException #20: kernel exception | 1: j MipsTLBMissException #20: kernel exception | ||||
nop #21: branch delay slot | nop #21: branch delay slot | ||||
2: j SlowFault #22: no page table present | 2: j SlowFault #22: no page table present | ||||
nop #23: branch delay slot | nop #23: branch delay slot | ||||
.set pop | .set pop | ||||
/* | /* | ||||
* This code is copied to the general exception vector address to | * This code is copied to the general exception vector address to | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | #define CLEAR_STATUS \ | ||||
mfc0 a0, MIPS_COP_0_STATUS ;\ | mfc0 a0, MIPS_COP_0_STATUS ;\ | ||||
li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ | li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ | ||||
and a0, a0, a2 ; \ | and a0, a0, a2 ; \ | ||||
mtc0 a0, MIPS_COP_0_STATUS ; \ | mtc0 a0, MIPS_COP_0_STATUS ; \ | ||||
ITLBNOPFIX | ITLBNOPFIX | ||||
#endif | #endif | ||||
/* | /* | ||||
* Save CPU and CP0 register state. | * Save CPU and CP0 register state when taking an exception in kernel mode. | ||||
* | * | ||||
* This is straightforward except for saving the exception program | * This is straightforward except for saving the exception program | ||||
* counter. The ddb backtrace code looks for the first instruction | * counter. The ddb backtrace code looks for the first instruction | ||||
* matching the form "sw ra, (off)sp" to figure out the address of the | * matching the form "sw ra, (off)sp" to figure out the address of the | ||||
* calling function. So we must make sure that we save the exception | * calling function. So we must make sure that we save the exception | ||||
* PC by staging it through 'ra' as opposed to any other register. | * PC by staging it through 'ra' as opposed to any other register. | ||||
*/ | */ | ||||
#define SAVE_CPU \ | #define SAVE_CPU \ | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | */ | ||||
mfc0 a0, MIPS_COP_0_STATUS | mfc0 a0, MIPS_COP_0_STATUS | ||||
and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) | and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) | ||||
RESTORE_REG(a1, SR, sp) | RESTORE_REG(a1, SR, sp) | ||||
and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) | and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) | ||||
or a1, a1, a0 | or a1, a1, a0 | ||||
SAVE_REG(a1, SR, sp) | SAVE_REG(a1, SR, sp) | ||||
RESTORE_CPU # v0 contains the return address. | RESTORE_CPU # v0 contains the return address. | ||||
sync | sync | ||||
eret | eret | ||||
.set at | .set at | ||||
END(MipsKernGenException) | END(MipsKernGenException) | ||||
/*---------------------------------------------------------------------------- | /*---------------------------------------------------------------------------- | ||||
* | * | ||||
* MipsUserGenException -- | * MipsUserGenException -- | ||||
▲ Show 20 Lines • Show All 462 Lines • ▼ Show 20 Lines | 2: /* Validate page directory pointer. */ | ||||
beqz k1, 3f | beqz k1, 3f | ||||
nop | nop | ||||
#ifdef __mips_n64 | #ifdef __mips_n64 | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR | MFC0 k0, MIPS_COP_0_BAD_VADDR | ||||
PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost) | PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost) | ||||
beq k1, zero, MipsKernGenException # ==0 -- no pde tab | beq k1, zero, MipsKernGenException # ==0 -- no pde tab | ||||
andi k0, k0, PDEPTRMASK # k0=pde offset | andi k0, k0, PDEPTRMASK # k0=pde offset | ||||
PTR_ADDU k1, k0, k1 # k1=pde entry address | PTR_ADDU k0, k0, k1 # k0=pde entry address | ||||
PTR_L k1, 0(k1) # k1=pde entry | PTR_L k1, 0(k0) # k1=pde entry | ||||
/* Validate pde table pointer. */ | /* Validate pde table pointer. */ | ||||
beqz k1, 3f | beqz k1, 3f | ||||
nop | nop | ||||
#ifdef MIPS64_NEW_PMAP | |||||
# Check for superpage | |||||
GET_SUPERPAGE_IDX(k1) # k1=superpage index from PTE | |||||
beq k1, zero, not_spg # ==0 -- not superpage | |||||
PTR_L k1, 0(k0) # k1=pde entry (delay slot) | |||||
/* Validate page table entry. */ | |||||
andi k1, PTE_VR | |||||
beqz k1, 3f | |||||
nop | |||||
# The PDE is actually a superpage PTE. Store it in the TLB lo0 reg. | |||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO0 # lo0 is loaded | |||||
COP0_SYNC | |||||
# Compute the PFN for the TLB lo1 register from k1(=PTE for TLB lo0). | |||||
GET_ODD_1M_PFN_FROM_EVEN(k1) # k1=Odd PFN in PTE postion | |||||
# Get hard TLB flag bits. | |||||
PTR_L k0, 0(k0) # k0=pde entry (again) | |||||
GET_HW_TLB_FLAGS(k0) # k0=hw TLB flag bits | |||||
or k1, k1, k0 # k1=PTE=PFN | hwflg bits | |||||
# Load it into the TLB Lo1 register. | |||||
# CLEAR_PTE_SWBITS(k1) # No SW bits to clear | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded | |||||
COP0_SYNC | |||||
# Load the TLB PageMask for 1M pages. | |||||
dli k0, TLBMASK_1M_PAGE # PageMask for 1M Page | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_PG_MASK # PageMask is loaded | |||||
COP0_SYNC | |||||
b tlb_insert_entry | |||||
nop | |||||
not_spg: | |||||
#endif /* MIPS64_NEW_PMAP */ | |||||
#endif | #endif | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | ||||
PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN | PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN | ||||
andi k0, k0, PTEMASK # k0=page tab offset | andi k0, k0, PTEMASK # k0=page tab offset | ||||
PTR_ADDU k1, k1, k0 # k1=pte address | PTR_ADDU k1, k1, k0 # k1=pte address | ||||
PTE_L k0, 0(k1) # k0=this PTE | PTE_L k0, 0(k1) # k0=this PTE | ||||
/* Validate page table entry. */ | /* Validate page table entry. */ | ||||
andi k0, PTE_V | andi k0, PTE_VR | ||||
beqz k0, 3f | beqz k0, 3f | ||||
nop | nop | ||||
/* Check whether this is an even or odd entry. */ | /* Check whether this is an even or odd entry. */ | ||||
andi k0, k1, PTESIZE | andi k0, k1, PTESIZE | ||||
bnez k0, odd_page | bnez k0, odd_page | ||||
nop | nop | ||||
PTE_L k0, 0(k1) | PTE_L k0, 0(k1) | ||||
PTE_L k1, PTESIZE(k1) | |||||
CLEAR_PTE_SWBITS(k0) | CLEAR_PTE_SWBITS(k0) | ||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 | PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 | ||||
COP0_SYNC | COP0_SYNC | ||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 | PTE_L k0, PTESIZE(k1) | ||||
CLEAR_PTE_SWBITS(k0) | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO1 | |||||
COP0_SYNC | COP0_SYNC | ||||
b tlb_insert_entry | b tlb_insert_entry | ||||
nop | nop | ||||
odd_page: | odd_page: | ||||
PTE_L k0, -PTESIZE(k1) | PTE_L k0, -PTESIZE(k1) | ||||
PTE_L k1, 0(k1) | |||||
CLEAR_PTE_SWBITS(k0) | CLEAR_PTE_SWBITS(k0) | ||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 | PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 | ||||
COP0_SYNC | COP0_SYNC | ||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 | PTE_L k0, 0(k1) | ||||
CLEAR_PTE_SWBITS(k0) | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO1 | |||||
COP0_SYNC | COP0_SYNC | ||||
tlb_insert_entry: | tlb_insert_entry: | ||||
tlbp | tlbp | ||||
HAZARD_DELAY | HAZARD_DELAY | ||||
mfc0 k0, MIPS_COP_0_TLB_INDEX | mfc0 k0, MIPS_COP_0_TLB_INDEX | ||||
bltz k0, tlb_insert_random | bltz k0, tlb_insert_random | ||||
nop | nop | ||||
tlbwi | tlbwi | ||||
PTE_MTC0 zero, MIPS_COP_0_TLB_PG_MASK | |||||
COP0_SYNC | |||||
eret | eret | ||||
ssnop | ssnop | ||||
tlb_insert_random: | tlb_insert_random: | ||||
tlbwr | tlbwr | ||||
PTE_MTC0 zero, MIPS_COP_0_TLB_PG_MASK | |||||
COP0_SYNC | |||||
eret | eret | ||||
ssnop | ssnop | ||||
3: | 3: | ||||
/* | /* | ||||
* Branch to the comprehensive exception processing. | * Branch to the comprehensive exception processing. | ||||
*/ | */ | ||||
mfc0 k1, MIPS_COP_0_STATUS | mfc0 k1, MIPS_COP_0_STATUS | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | LEAF_NOPROFILE(MipsTLBMissException) | ||||
andi k0, k0, PDEPTRMASK #06: k0=seg offset | andi k0, k0, PDEPTRMASK #06: k0=seg offset | ||||
PTR_ADDU k1, k0, k1 # k1=seg entry address | PTR_ADDU k1, k0, k1 # k1=seg entry address | ||||
PTR_L k1, 0(k1) # k1=seg entry | PTR_L k1, 0(k1) # k1=seg entry | ||||
MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | ||||
beq k1, zero, MipsKernGenException # ==0 -- no page table | beq k1, zero, MipsKernGenException # ==0 -- no page table | ||||
#ifdef __mips_n64 | #ifdef __mips_n64 | ||||
PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN | PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN | ||||
andi k0, k0, PDEPTRMASK # k0=pde offset | andi k0, k0, PDEPTRMASK # k0=pde offset | ||||
PTR_ADDU k1, k0, k1 # k1=pde entry address | PTR_ADDU k0, k0, k1 # k1=pde entry address | ||||
PTR_L k1, 0(k1) # k1=pde entry | PTR_L k1, 0(k0) # k1=pde entry | ||||
#ifdef MIPS64_NEW_PMAP | |||||
# Check for superpage | |||||
GET_SUPERPAGE_IDX(k1) # k1=superpage index from PTE | |||||
beq k1, zero, not_kspg # ==0 -- not superpage | |||||
PTR_L k1, 0(k0) # k1=pde entry (delay slot) | |||||
# XXX Reference bit emulation | |||||
# The PDE is actually a superpage PTE. Store it in the TLB lo0 reg. | |||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO0 # lo0 is loaded | |||||
COP0_SYNC | |||||
# Compute the PFN for the TLB lo1 register from k1(=PTE for TLB lo0). | |||||
GET_ODD_1M_PFN_FROM_EVEN(k1) # k1=Odd PFN in PTE postion | |||||
# Get hard TLB flag bits. | |||||
PTR_L k0, 0(k0) # k0=pde entry (again) | |||||
GET_HW_TLB_FLAGS(k0) # k0=hw TLB flag bits | |||||
or k1, k1, k0 # k1=PTE=PFN | hwflg bits | |||||
# Load it into the TLB Lo1 register. | |||||
#CLEAR_PTE_SWBITS(k1) # No SW Bits to clear | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded | |||||
COP0_SYNC | |||||
# Load the TLB PageMask for 1M pages. | |||||
dli k0, TLBMASK_1M_PAGE # PageMask for 1M Page | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_PG_MASK # PageMask is loaded | |||||
COP0_SYNC | |||||
tlbwr # write to tlb | |||||
HAZARD_DELAY | |||||
PTE_MTC0 zero, MIPS_COP_0_TLB_PG_MASK # zero out PageMask reg | |||||
COP0_SYNC | |||||
eret # return from exception | |||||
not_kspg: | |||||
#endif /* MIPS64_NEW_PMAP */ | |||||
MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) | ||||
beq k1, zero, MipsKernGenException # ==0 -- no page table | beq k1, zero, MipsKernGenException # ==0 -- no page table | ||||
#endif | #endif | ||||
PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN | PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN | ||||
andi k0, k0, PTE2MASK # k0=page tab offset | andi k0, k0, PTE2MASK # k0=page tab offset | ||||
PTR_ADDU k1, k1, k0 # k1=pte address | PTR_ADDU k1, k1, k0 # k1=pte address | ||||
PTE_L k0, 0(k1) # k0=lo0 pte | PTE_L k0, 0(k1) # k0=lo0 pte | ||||
PTE_L k1, PTESIZE(k1) # k1=lo1 pte | |||||
# XXX Reference bit emulation | |||||
CLEAR_PTE_SWBITS(k0) | CLEAR_PTE_SWBITS(k0) | ||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded | PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded | ||||
COP0_SYNC | COP0_SYNC | ||||
CLEAR_PTE_SWBITS(k1) | |||||
PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded | PTE_L k0, PTESIZE(k1) # k0=lo1 pte | ||||
CLEAR_PTE_SWBITS(k0) | |||||
PTE_MTC0 k0, MIPS_COP_0_TLB_LO1 # lo1 is loaded | |||||
COP0_SYNC | COP0_SYNC | ||||
tlbwr # write to tlb | tlbwr # write to tlb | ||||
HAZARD_DELAY | HAZARD_DELAY | ||||
eret # return from exception | eret # return from exception | ||||
.set at | .set at | ||||
END(MipsTLBMissException) | END(MipsTLBMissException) | ||||
/*---------------------------------------------------------------------------- | /*---------------------------------------------------------------------------- | ||||
▲ Show 20 Lines • Show All 186 Lines • Show Last 20 Lines |