slb_low.S 8.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Low-level SLB routines
 *
 * Copyright (C) 2004 David Gibson <dwg@au.ibm.com>, IBM
 *
 * Based on earlier C version:
 * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
 *    Copyright (c) 2001 Dave Engebretsen
 * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
 *
 *  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; either version
 *  2 of the License, or (at your option) any later version.
 */

#include <asm/processor.h>
#include <asm/ppc_asm.h>
19
#include <asm/asm-offsets.h>
L
Linus Torvalds 已提交
20
#include <asm/cputable.h>
21 22 23
#include <asm/page.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
24
#include <asm/firmware.h>
L
Linus Torvalds 已提交
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
/*
 * This macro generates asm code to compute the VSID scramble
 * function.  Used in slb_allocate() and do_stab_bolted.  The function
 * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
 *
 *	rt = register containing the proto-VSID and into which the
 *		VSID will be stored
 *	rx = scratch register (clobbered)
 *	rf = flags
 *
 *	- rt and rx must be different registers
 *	- The answer will end up in the low VSID_BITS bits of rt.  The higher
 *	  bits may contain other garbage, so you may need to mask the
 *	  result.
 */
#define ASM_VSID_SCRAMBLE(rt, rx, rf, size)				\
	lis	rx,VSID_MULTIPLIER_##size@h;				\
	ori	rx,rx,VSID_MULTIPLIER_##size@l;				\
	mulld	rt,rt,rx;		/* rt = rt * MULTIPLIER */	\
/*									\
 * powermac get slb fault before feature fixup, so make 65 bit part     \
 * the default part of feature fixup					\
 */									\
BEGIN_MMU_FTR_SECTION							\
	srdi	rx,rt,VSID_BITS_65_##size;				\
	clrldi	rt,rt,(64-VSID_BITS_65_##size);				\
	add	rt,rt,rx;						\
	addi	rx,rt,1;						\
	srdi	rx,rx,VSID_BITS_65_##size;				\
	add	rt,rt,rx;						\
	rldimi	rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_65_##size)); \
MMU_FTR_SECTION_ELSE							\
	srdi	rx,rt,VSID_BITS_##size;					\
	clrldi	rt,rt,(64-VSID_BITS_##size);				\
	add	rt,rt,rx;		/* add high and low bits */	\
	addi	rx,rt,1;						\
	srdi	rx,rx,VSID_BITS_##size;	/* extract 2^VSID_BITS bit */	\
	add	rt,rt,rx;						\
	rldimi	rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_##size)); \
ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_68_BIT_VA)


68
/* void slb_allocate(unsigned long ea);
L
Linus Torvalds 已提交
69 70 71 72
 *
 * Create an SLB entry for the given EA (user or kernel).
 * 	r3 = faulting address, r13 = PACA
 *	r9, r10, r11 are clobbered by this function
73
 *	r3 is preserved.
L
Linus Torvalds 已提交
74 75
 * No other registers are examined or changed.
 */
76
_GLOBAL(slb_allocate)
77 78 79 80
	/*
	 * check for bad kernel/user address
	 * (ea & ~REGION_MASK) >= PGTABLE_RANGE
	 */
81
	rldicr. r9,r3,4,(63 - H_PGTABLE_EADDR_SIZE - 4)
82
	bne-	8f
L
Linus Torvalds 已提交
83 84

	srdi	r9,r3,60		/* get region */
85
	srdi	r10,r3,SID_SHIFT	/* get esid */
86
	cmpldi	cr7,r9,0xc		/* cmp PAGE_OFFSET for later use */
L
Linus Torvalds 已提交
87

88
	/* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */
L
Linus Torvalds 已提交
89 90
	blt	cr7,0f			/* user or kernel? */

91
	/* Check if hitting the linear mapping or some other kernel space
92 93 94 95 96 97
	*/
	bne	cr7,1f

	/* Linear mapping encoding bits, the "li" instruction below will
	 * be patched by the kernel at boot
	 */
98 99
.globl slb_miss_kernel_load_linear
slb_miss_kernel_load_linear:
100
	li	r11,0
A
Aneesh Kumar K.V 已提交
101
	/*
102
	 * context = (ea >> 60) - (0xc - 1)
103
	 * r9 = region id.
A
Aneesh Kumar K.V 已提交
104
	 */
105
	subi	r9,r9,KERNEL_REGION_CONTEXT_OFFSET
106

P
Paul Mackerras 已提交
107
BEGIN_FTR_SECTION
108
	b	.Lslb_finish_load
109
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
110
	b	.Lslb_finish_load_1T
111

112 113 114 115
1:
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	cmpldi	cr0,r9,0xf
	bne	1f
116
/* Check virtual memmap region. To be patched at kernel boot */
117 118
.globl slb_miss_kernel_load_vmemmap
slb_miss_kernel_load_vmemmap:
119 120 121 122 123
	li	r11,0
	b	6f
1:
#endif /* CONFIG_SPARSEMEM_VMEMMAP */

124 125
	/* vmalloc mapping gets the encoding from the PACA as the mapping
	 * can be demoted from 64K -> 4K dynamically on some machines
126
	 */
127
	clrldi	r11,r10,48
128
	cmpldi	r11,(H_VMALLOC_SIZE >> 28) - 1
129 130
	bgt	5f
	lhz	r11,PACAVMALLOCSLLP(r13)
P
Paul Mackerras 已提交
131
	b	6f
132
5:
133
	/* IO mapping */
134 135
.globl slb_miss_kernel_load_io
slb_miss_kernel_load_io:
136
	li	r11,0
P
Paul Mackerras 已提交
137
6:
A
Aneesh Kumar K.V 已提交
138
	/*
139
	 * context = (ea >> 60) - (0xc - 1)
140
	 * r9 = region id.
A
Aneesh Kumar K.V 已提交
141
	 */
142
	subi	r9,r9,KERNEL_REGION_CONTEXT_OFFSET
143

P
Paul Mackerras 已提交
144
BEGIN_FTR_SECTION
145
	b	.Lslb_finish_load
146
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
147
	b	.Lslb_finish_load_1T
148

149 150 151 152
0:	/*
	 * For userspace addresses, make sure this is region 0.
	 */
	cmpdi	r9, 0
153 154 155 156 157 158 159
	bne-	8f
        /*
         * user space make sure we are within the allowed limit
	 */
	ld	r11,PACA_ADDR_LIMIT(r13)
	cmpld	r3,r11
	bge-	8f
160

161 162 163 164 165 166 167 168 169 170 171
	/* when using slices, we extract the psize off the slice bitmaps
	 * and then we need to get the sllp encoding off the mmu_psize_defs
	 * array.
	 *
	 * XXX This is a bit inefficient especially for the normal case,
	 * so we should try to implement a fast path for the standard page
	 * size using the old sllp value so we avoid the array. We cannot
	 * really do dynamic patching unfortunately as processes might flip
	 * between 4k and 64k standard page size
	 */
#ifdef CONFIG_PPC_MM_SLICES
172
	/* r10 have esid */
173
	cmpldi	r10,16
174
	/* below SLICE_LOW_TOP */
175
	blt	5f
176 177 178 179 180 181 182 183 184 185
	/*
	 * Handle hpsizes,
	 * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index
	 */
	srdi    r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */
	addi	r9,r11,PACAHIGHSLICEPSIZE
	lbzx	r9,r13,r9		/* r9 is hpsizes[r11] */
	/* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */
	rldicl	r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63
	b	6f
186

187 188 189 190 191 192 193 194 195 196
5:
	/*
	 * Handle lpsizes
	 * r9 is get_paca()->context.low_slices_psize, r11 is index
	 */
	ld	r9,PACALOWSLICESPSIZE(r13)
	mr	r11,r10
6:
	sldi	r11,r11,2  /* index * 4 */
	/* Extract the psize and multiply to get an array offset */
197 198 199
	srd	r9,r9,r11
	andi.	r9,r9,0xf
	mulli	r9,r9,MMUPSIZEDEFSIZE
200

201 202 203 204 205 206 207 208 209
	/* Now get to the array and obtain the sllp
	 */
	ld	r11,PACATOC(r13)
	ld	r11,mmu_psize_defs@got(r11)
	add	r11,r11,r9
	ld	r11,MMUPSIZESLLP(r11)
	ori	r11,r11,SLB_VSID_USER
#else
	/* paca context sllp already contains the SLB_VSID_USER bits */
210
	lhz	r11,PACACONTEXTSLLP(r13)
211 212
#endif /* CONFIG_PPC_MM_SLICES */

213
	ld	r9,PACACONTEXTID(r13)
P
Paul Mackerras 已提交
214 215
BEGIN_FTR_SECTION
	cmpldi	r10,0x1000
216
	bge	.Lslb_finish_load_1T
217
END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
218
	b	.Lslb_finish_load
219

220 221 222
8:	/* invalid EA - return an error indication */
	crset	4*cr0+eq		/* indicate failure */
	blr
223 224 225 226

/*
 * Finish loading of an SLB entry and return
 *
227
 * r3 = EA, r9 = context, r10 = ESID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET
228
 */
229
.Lslb_finish_load:
230
	rldimi  r10,r9,ESID_BITS,0
231
	ASM_VSID_SCRAMBLE(r10,r9,r11,256M)
232 233 234 235 236 237 238
	/* r3 = EA, r11 = VSID data */
	/*
	 * Find a slot, round robin. Previously we tried to find a
	 * free slot first but that took too long. Unfortunately we
 	 * dont have any LRU information to help us choose a slot.
 	 */

239 240 241
	mr	r9,r3

	/* slb_finish_load_1T continues here. r9=EA with non-ESID bits clear */
P
Paul Mackerras 已提交
242
7:	ld	r10,PACASTABRR(r13)
243
	addi	r10,r10,1
244
	/* This gets soft patched on boot. */
245 246
.globl slb_compare_rr_to_size
slb_compare_rr_to_size:
247
	cmpldi	r10,0
248 249 250 251 252 253 254 255

	blt+	4f
	li	r10,SLB_NUM_BOLTED

4:
	std	r10,PACASTABRR(r13)

3:
256 257
	rldimi	r9,r10,0,36		/* r9  = EA[0:35] | entry */
	oris	r10,r9,SLB_ESID_V@h	/* r10 = r9 | SLB_ESID_V */
258

259
	/* r9 = ESID data, r11 = VSID data */
L
Linus Torvalds 已提交
260 261 262 263 264 265 266

	/*
	 * No need for an isync before or after this slbmte. The exception
	 * we enter with and the rfid we exit with are context synchronizing.
	 */
	slbmte	r11,r10

267 268 269
	/* we're done for kernel addresses */
	crclr	4*cr0+eq		/* set result to "success" */
	bgelr	cr7
L
Linus Torvalds 已提交
270 271

	/* Update the slb cache */
272 273
	lhz	r9,PACASLBCACHEPTR(r13)	/* offset = paca->slb_cache_ptr */
	cmpldi	r9,SLB_CACHE_ENTRIES
L
Linus Torvalds 已提交
274 275 276
	bge	1f

	/* still room in the slb cache */
277
	sldi	r11,r9,2		/* r11 = offset * sizeof(u32) */
278 279 280
	srdi    r10,r10,28		/* get the 36 bits of the ESID */
	add	r11,r11,r13		/* r11 = (u32 *)paca + offset */
	stw	r10,PACASLBCACHE(r11)	/* paca->slb_cache[offset] = esid */
281
	addi	r9,r9,1			/* offset++ */
L
Linus Torvalds 已提交
282 283
	b	2f
1:					/* offset >= SLB_CACHE_ENTRIES */
284
	li	r9,SLB_CACHE_ENTRIES+1
L
Linus Torvalds 已提交
285
2:
286
	sth	r9,PACASLBCACHEPTR(r13)	/* paca->slb_cache_ptr = offset */
287
	crclr	4*cr0+eq		/* set result to "success" */
L
Linus Torvalds 已提交
288 289
	blr

P
Paul Mackerras 已提交
290 291 292
/*
 * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return.
 *
293
 * r3 = EA, r9 = context, r10 = ESID(256MB), r11 = flags, clobbers r9
P
Paul Mackerras 已提交
294
 */
295
.Lslb_finish_load_1T:
296
	srdi	r10,r10,(SID_SHIFT_1T - SID_SHIFT)	/* get 1T ESID */
297
	rldimi  r10,r9,ESID_BITS_1T,0
298
	ASM_VSID_SCRAMBLE(r10,r9,r11,1T)
299 300 301 302
	/*
	 * bits above VSID_BITS_1T need to be ignored from r10
	 * also combine VSID and flags
	 */
303

P
Paul Mackerras 已提交
304 305 306 307
	li	r10,MMU_SEGSIZE_1T
	rldimi	r11,r10,SLB_VSID_SSIZE_SHIFT,0	/* insert segment size */

	/* r3 = EA, r11 = VSID data */
308
	clrrdi	r9,r3,SID_SHIFT_1T	/* clear out non-ESID bits */
P
Paul Mackerras 已提交
309 310
	b	7b

311

312
_ASM_NOKPROBE_SYMBOL(slb_allocate)
313 314 315 316 317 318
_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_linear)
_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_io)
_ASM_NOKPROBE_SYMBOL(slb_compare_rr_to_size)
#ifdef CONFIG_SPARSEMEM_VMEMMAP
_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_vmemmap)
#endif