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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
|
/*
* Creation Date: <2000/07/11 03:38:32 samuel>
* Time-stamp: <2001/04/12 16:02:34 samuel>
*
* <splitmode.S>
*
* Handles splitmode (MSR_IR != MSR_DR)
*
* Copyright (C) 2000, 2001 Samuel Rydh (samuel@ibrium.se)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation
*
*/
//////////////////////////////////////////////////////////////
// Performance Measurements:
//
// Load/store to NIP segment in splitmode:
//
// OLD: 0.81 MHz (on a 350 MHz G3)
// NEW: 1.4 MHz
/////////////////////////////////////////////////////////////
// prepare_splitmode
//
// srr0: mac-nip
//
// Fill in splitmode segment register table. The segment
// register containing xNIP is set up for instruction access
// (if xNIP does not hold nip, an extra ISI exception will
// occur). The instruction segment is protected from
// data access through the use of a DBAT register.
//
// It MUST be safe to call this function even if we
// are *not* in splitmode.
//
// M: r0,r3-r5
prepare_splitmode:
li r3,0
stw r3,K_PREPARE_SPLITMODE(r1)
lwz r4,K_IN_SPLITMODE(r1)
cmpwi r4,kSplitAlgorithmFast
bnelr
// fill split mode table with data segment registers
lwz r3,K_SR_DATA(r1) // physical addr
addi r4,r1,K_SPLIT_SR_BASE-4
li r5,16
mfctr r0 // save ctr in r0
mtctr r5
addi r3,r3,-4
1: lwzu r5,4(r3)
oris r5,r5,0x1000 // no-execute segment bit
stwu r5,4(r4)
bdnz 1b
mtctr r0 // restore ctr
// insert instruction mode segment
mfsrr0 r0 // NIP
rlwinm r3,r0,0,0,3
stw r3,K_SPLIT_NIP_SEGMENT(r1)
rlwinm r3,r0,4+2,26,29 // r3 = offset, ((sr & 0xf000000) >> 28 ) * 4
lwz r5,K_SR_INST(r1)
lwzx r5,r3,r5 // segment register for instructions
addi r4,r1,K_SPLIT_SR_BASE
stwx r5,r3,r4
// and protect it with DBAT0.
//
// The supervisor valid bit must be cleared
// - we don't want to block get_opcode.
rlwinm r3,r0,0,0,3 // segment base
ori r3,r3,0x1ffd // user valid bit | 256MB mask
stw r3,K_DBAT0U(r1)
li r4,0
stw r4,K_DBAT0L(r1) // pp=0, wimg=0
blr
///////////////////////////////////////////////////////////////////
// split_sr_no_execute
//
// srr0: mac-nip
//
// An instruction is to be fetched from one of the no-execute
// segments. This function reinitializes the segment registers.
//
// M: r0, r3-r5
split_sr_no_execute:
mfsrr1 r4 // Guarded access or no-execute?
rlwinm. r0,r4,0,3,3
beqlr+
lwz r3,K_IN_SPLITMODE(r1) // in splitmode?
cmpwi r3,kSplitAlgorithmFast
bnelr // might be a guarded PTE
mfsrr0 r5
rlwinm r3,r5,0,0,3 // segment
lwz r4,K_SPLIT_NIP_SEGMENT(r1)
cmpw r3,r4
beqlr // guarded PTE/mac-guarded segment
bl prepare_splitmode // r0,r3-r5 (srr0=NIP)
bl reload_sr // r3-r5
b exception_return
//////////////////////////////////////////////////////////////////
// splitmode_dsi
//
// srr0: NIP
//
// An DSI exception occured (DBAT protection violation).
// That is, a load/store instruction targeted the segment
// instructions was fetched from.
//
// Safe to modify: r0,r2-r5, (lr)
splitmode_dsi:
lwz r4,K_IN_SPLITMODE(r1) // In splitmode?
cmpwi r4,kSplitAlgorithmFast
bnelr+
mfdsisr r3 // DBAT/page protection violation?
rlwinm. r0,r3,0,4,4
beqlr- // If not, it does not concern us
mfdar r3 // Normal page protected exception?
rlwinm r3,r3,0,0,3 // data segment
lwz r4,K_SPLIT_NIP_SEGMENT(r1) // the instruction segment?
cmpw r4,r3
bnelr // exit - not in the instruction segment
//////////////////////////////////
// Handle splitmode write, r4=seg#
//////////////////////////////////
// Store splitmode instruction
LI_PHYS( r2,split_store_patch ) // r2 = addr of split_store_patch
lwz r3,xINST_OPCODE(r1)
stw r3,0(r2) // store instruction
// Set segment registers to data only and start flushing the cache
mfsrin r0,r4 // r0 = old segment register
dcbst 0,r2
rlwinm r3,r4,4+2,26,29 // offset = ((sr & 0xf000000) >> 28 ) * 4
lwz r5,K_SR_DATA(r1)
lwzx r3,r3,r5
oris r3,r3,0x4000 // Set supervisor key bit (Ks)
mtsrin r3,r4
stw r0,K_TMP_SCRATCH0(r1) // save old segment register
bl secint_splitmode // Setup secondary exception handler
mfsrr0 r0 // r0 = NIP
sync // Finish flushing the cache
icbi 0,r2
sync // an explicit isync should not be needed due to the rfi
mtsrr0 r2 // The simplest thing is to do an RFI
LOADI r3,MSR_EE | MSR_PR | MSR_IR | MSR_SE
lwz r4,x_MSR(r1)
stw r0,xNIP(r1)
andc r4,r4,r3
mtsrr1 r4
xGPR_LOAD_RANGE r2,r5 // Restore registers (except r1)
xGPR_LOAD r0,r1
rfi
split_store_patch:
nop
mtsprg0 r1 // restore MSR
li r1,MSR_ME
mtmsr r1
isync
mfsprg3 r1 // and stack pointer
xGPR_SAVE_RANGE r2,r5
mfsprg0 r2 // r1 - to be saved
lwz r3,xNIP(r1) // restore srr0, srr1 and segment register
stw r2,xGPR1(r1)
mtsrr0 r3
lwz r4,x_MSR(r1)
stw r0,xGPR0(r1)
mtsrr1 r4
lwz r2,K_TMP_SCRATCH0(r1)
mtsrin r2,r3
b emulation_done
//////////////////////////////////////////////////////////////////////
// secint_splitmode:
// r1: stack (sprg1 = old r1)
// r3: vector index (sprg0 = old r3)
// srr0/srr1: kernel nip/msr
//
// xGPR(0-5) are valid (unless this is a trace exception)
secint_splitmode:
blrl
lwz r5,xNIP(r1) // r5 = NIP, Restore NIP & MSR
mtsrr0 r5
lwz r0,x_MSR(r1)
mtsrr1 r0
cmpwi r3,0x300 // ** DSI **
bne- 1f
mfsrin r2,r5 // r5 = NIP
rlwinm r2,r2,0,2,0 // Clear Ks [bit1] (supervisor key bit)
mtsrin r2,r5
bl save_middle_regs // Note: If dsi_cont ever returns immediately,
bl check_io_page // we will need to fix the segment registers before
b dsi_cont // the last dsi_cont branch.
1: lwz r2,K_TMP_SCRATCH0(r1) // We might return immediately...
mtsrin r2,r5
cmpwi r3,0x600 // ** Alignment **
bne 2f
bl save_middle_regs
b alignment_cont
2: cmpwi r3,0x800 // ** FPU Unavailable **
beq fpu_cont
cmpwi r3,0xf20 // ** AltiVec Unavailable **
beq altivec_cont
DEBUGGER_SAVE( 0x5918 ) // ERROR...
////////////////////////////////////////////////////////////////////////
// invalidate_splitmode( kernel_vars_t *kv )
//
// This function must be called whenever the segment registers are
// modified. A flag is set which will force a refresh of the slitmode
// segment registers (at mac context switch in). We could rewrite this
// in C but it might be better to keep things centralized.
GLOBAL_SYMBOL(r__invalidate_splitmode_sr):
lwz r4,K_IN_SPLITMODE(r3)
cmpwi r4,kSplitAlgorithmFast
bnelr
1: li r5,1
stw r5,K_PREPARE_SPLITMODE(r3)
blr
|