| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 1 | /* | 
 | 2 |  * arch/ppc/kernel/head_44x.S | 
 | 3 |  * | 
 | 4 |  * Kernel execution entry point code. | 
 | 5 |  * | 
 | 6 |  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org> | 
 | 7 |  *      Initial PowerPC version. | 
 | 8 |  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu> | 
 | 9 |  *      Rewritten for PReP | 
 | 10 |  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> | 
 | 11 |  *      Low-level exception handers, MMU support, and rewrite. | 
 | 12 |  *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net> | 
 | 13 |  *      PowerPC 8xx modifications. | 
 | 14 |  *    Copyright (c) 1998-1999 TiVo, Inc. | 
 | 15 |  *      PowerPC 403GCX modifications. | 
 | 16 |  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> | 
 | 17 |  *      PowerPC 403GCX/405GP modifications. | 
 | 18 |  *    Copyright 2000 MontaVista Software Inc. | 
 | 19 |  *	PPC405 modifications | 
 | 20 |  *      PowerPC 403GCX/405GP modifications. | 
 | 21 |  * 	Author: MontaVista Software, Inc. | 
 | 22 |  *         	frank_rowand@mvista.com or source@mvista.com | 
 | 23 |  * 	   	debbie_chu@mvista.com | 
 | 24 |  *    Copyright 2002-2005 MontaVista Software, Inc. | 
 | 25 |  *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org> | 
 | 26 |  * | 
 | 27 |  * This program is free software; you can redistribute  it and/or modify it | 
 | 28 |  * under  the terms of  the GNU General  Public License as published by the | 
 | 29 |  * Free Software Foundation;  either version 2 of the  License, or (at your | 
 | 30 |  * option) any later version. | 
 | 31 |  */ | 
 | 32 |  | 
 | 33 | #include <linux/config.h> | 
 | 34 | #include <asm/processor.h> | 
 | 35 | #include <asm/page.h> | 
 | 36 | #include <asm/mmu.h> | 
 | 37 | #include <asm/pgtable.h> | 
 | 38 | #include <asm/ibm4xx.h> | 
 | 39 | #include <asm/ibm44x.h> | 
 | 40 | #include <asm/cputable.h> | 
 | 41 | #include <asm/thread_info.h> | 
 | 42 | #include <asm/ppc_asm.h> | 
 | 43 | #include <asm/asm-offsets.h> | 
 | 44 | #include "head_booke.h" | 
 | 45 |  | 
 | 46 |  | 
 | 47 | /* As with the other PowerPC ports, it is expected that when code | 
 | 48 |  * execution begins here, the following registers contain valid, yet | 
 | 49 |  * optional, information: | 
 | 50 |  * | 
 | 51 |  *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) | 
 | 52 |  *   r4 - Starting address of the init RAM disk | 
 | 53 |  *   r5 - Ending address of the init RAM disk | 
 | 54 |  *   r6 - Start of kernel command line string (e.g. "mem=128") | 
 | 55 |  *   r7 - End of kernel command line string | 
 | 56 |  * | 
 | 57 |  */ | 
 | 58 | 	.text | 
 | 59 | _GLOBAL(_stext) | 
 | 60 | _GLOBAL(_start) | 
 | 61 | 	/* | 
 | 62 | 	 * Reserve a word at a fixed location to store the address | 
 | 63 | 	 * of abatron_pteptrs | 
 | 64 | 	 */ | 
 | 65 | 	nop | 
 | 66 | /* | 
 | 67 |  * Save parameters we are passed | 
 | 68 |  */ | 
 | 69 | 	mr	r31,r3 | 
 | 70 | 	mr	r30,r4 | 
 | 71 | 	mr	r29,r5 | 
 | 72 | 	mr	r28,r6 | 
 | 73 | 	mr	r27,r7 | 
 | 74 | 	li	r24,0		/* CPU number */ | 
 | 75 |  | 
 | 76 | /* | 
 | 77 |  * Set up the initial MMU state | 
 | 78 |  * | 
 | 79 |  * We are still executing code at the virtual address | 
 | 80 |  * mappings set by the firmware for the base of RAM. | 
 | 81 |  * | 
 | 82 |  * We first invalidate all TLB entries but the one | 
 | 83 |  * we are running from.  We then load the KERNELBASE | 
 | 84 |  * mappings so we can begin to use kernel addresses | 
 | 85 |  * natively and so the interrupt vector locations are | 
 | 86 |  * permanently pinned (necessary since Book E | 
 | 87 |  * implementations always have translation enabled). | 
 | 88 |  * | 
 | 89 |  * TODO: Use the known TLB entry we are running from to | 
 | 90 |  *	 determine which physical region we are located | 
 | 91 |  *	 in.  This can be used to determine where in RAM | 
 | 92 |  *	 (on a shared CPU system) or PCI memory space | 
 | 93 |  *	 (on a DRAMless system) we are located. | 
 | 94 |  *       For now, we assume a perfect world which means | 
 | 95 |  *	 we are located at the base of DRAM (physical 0). | 
 | 96 |  */ | 
 | 97 |  | 
 | 98 | /* | 
 | 99 |  * Search TLB for entry that we are currently using. | 
 | 100 |  * Invalidate all entries but the one we are using. | 
 | 101 |  */ | 
 | 102 | 	/* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ | 
 | 103 | 	mfspr	r3,SPRN_PID			/* Get PID */ | 
 | 104 | 	mfmsr	r4				/* Get MSR */ | 
 | 105 | 	andi.	r4,r4,MSR_IS@l			/* TS=1? */ | 
 | 106 | 	beq	wmmucr				/* If not, leave STS=0 */ | 
 | 107 | 	oris	r3,r3,PPC44x_MMUCR_STS@h	/* Set STS=1 */ | 
 | 108 | wmmucr:	mtspr	SPRN_MMUCR,r3			/* Put MMUCR */ | 
 | 109 | 	sync | 
 | 110 |  | 
 | 111 | 	bl	invstr				/* Find our address */ | 
 | 112 | invstr:	mflr	r5				/* Make it accessible */ | 
 | 113 | 	tlbsx	r23,0,r5			/* Find entry we are in */ | 
 | 114 | 	li	r4,0				/* Start at TLB entry 0 */ | 
 | 115 | 	li	r3,0				/* Set PAGEID inval value */ | 
 | 116 | 1:	cmpw	r23,r4				/* Is this our entry? */ | 
 | 117 | 	beq	skpinv				/* If so, skip the inval */ | 
 | 118 | 	tlbwe	r3,r4,PPC44x_TLB_PAGEID		/* If not, inval the entry */ | 
 | 119 | skpinv:	addi	r4,r4,1				/* Increment */ | 
 | 120 | 	cmpwi	r4,64				/* Are we done? */ | 
 | 121 | 	bne	1b				/* If not, repeat */ | 
 | 122 | 	isync					/* If so, context change */ | 
 | 123 |  | 
 | 124 | /* | 
 | 125 |  * Configure and load pinned entry into TLB slot 63. | 
 | 126 |  */ | 
 | 127 |  | 
 | 128 | 	lis	r3,KERNELBASE@h		/* Load the kernel virtual address */ | 
 | 129 | 	ori	r3,r3,KERNELBASE@l | 
 | 130 |  | 
 | 131 | 	/* Kernel is at the base of RAM */ | 
 | 132 | 	li r4, 0			/* Load the kernel physical address */ | 
 | 133 |  | 
 | 134 | 	/* Load the kernel PID = 0 */ | 
 | 135 | 	li	r0,0 | 
 | 136 | 	mtspr	SPRN_PID,r0 | 
 | 137 | 	sync | 
 | 138 |  | 
 | 139 | 	/* Initialize MMUCR */ | 
 | 140 | 	li	r5,0 | 
 | 141 | 	mtspr	SPRN_MMUCR,r5 | 
 | 142 | 	sync | 
 | 143 |  | 
 | 144 |  	/* pageid fields */ | 
 | 145 | 	clrrwi	r3,r3,10		/* Mask off the effective page number */ | 
 | 146 | 	ori	r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M | 
 | 147 |  | 
 | 148 | 	/* xlat fields */ | 
 | 149 | 	clrrwi	r4,r4,10		/* Mask off the real page number */ | 
 | 150 | 					/* ERPN is 0 for first 4GB page */ | 
 | 151 |  | 
 | 152 | 	/* attrib fields */ | 
 | 153 | 	/* Added guarded bit to protect against speculative loads/stores */ | 
 | 154 | 	li	r5,0 | 
 | 155 | 	ori	r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) | 
 | 156 |  | 
 | 157 |         li      r0,63                    /* TLB slot 63 */ | 
 | 158 |  | 
 | 159 | 	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */ | 
 | 160 | 	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */ | 
 | 161 | 	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */ | 
 | 162 |  | 
 | 163 | 	/* Force context change */ | 
 | 164 | 	mfmsr	r0 | 
 | 165 | 	mtspr	SPRN_SRR1, r0 | 
 | 166 | 	lis	r0,3f@h | 
 | 167 | 	ori	r0,r0,3f@l | 
 | 168 | 	mtspr	SPRN_SRR0,r0 | 
 | 169 | 	sync | 
 | 170 | 	rfi | 
 | 171 |  | 
 | 172 | 	/* If necessary, invalidate original entry we used */ | 
 | 173 | 3:	cmpwi	r23,63 | 
 | 174 | 	beq	4f | 
 | 175 | 	li	r6,0 | 
 | 176 | 	tlbwe   r6,r23,PPC44x_TLB_PAGEID | 
 | 177 | 	isync | 
 | 178 |  | 
 | 179 | 4: | 
 | 180 | #ifdef CONFIG_SERIAL_TEXT_DEBUG | 
 | 181 | 	/* | 
 | 182 | 	 * Add temporary UART mapping for early debug. | 
 | 183 | 	 * We can map UART registers wherever we want as long as they don't | 
 | 184 | 	 * interfere with other system mappings (e.g. with pinned entries). | 
 | 185 | 	 * For an example of how we handle this - see ocotea.h.       --ebs | 
 | 186 | 	 */ | 
 | 187 |  	/* pageid fields */ | 
 | 188 | 	lis	r3,UART0_IO_BASE@h | 
 | 189 | 	ori	r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K | 
 | 190 |  | 
 | 191 | 	/* xlat fields */ | 
 | 192 | 	lis	r4,UART0_PHYS_IO_BASE@h		/* RPN depends on SoC */ | 
 | 193 | #ifndef CONFIG_440EP | 
 | 194 | 	ori	r4,r4,0x0001		/* ERPN is 1 for second 4GB page */ | 
 | 195 | #endif | 
 | 196 |  | 
 | 197 | 	/* attrib fields */ | 
 | 198 | 	li	r5,0 | 
 | 199 | 	ori	r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G) | 
 | 200 |  | 
 | 201 |         li      r0,0                    /* TLB slot 0 */ | 
 | 202 |  | 
 | 203 | 	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */ | 
 | 204 | 	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */ | 
 | 205 | 	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */ | 
 | 206 |  | 
 | 207 | 	/* Force context change */ | 
 | 208 | 	isync | 
 | 209 | #endif /* CONFIG_SERIAL_TEXT_DEBUG */ | 
 | 210 |  | 
 | 211 | 	/* Establish the interrupt vector offsets */ | 
 | 212 | 	SET_IVOR(0,  CriticalInput); | 
 | 213 | 	SET_IVOR(1,  MachineCheck); | 
 | 214 | 	SET_IVOR(2,  DataStorage); | 
 | 215 | 	SET_IVOR(3,  InstructionStorage); | 
 | 216 | 	SET_IVOR(4,  ExternalInput); | 
 | 217 | 	SET_IVOR(5,  Alignment); | 
 | 218 | 	SET_IVOR(6,  Program); | 
 | 219 | 	SET_IVOR(7,  FloatingPointUnavailable); | 
 | 220 | 	SET_IVOR(8,  SystemCall); | 
 | 221 | 	SET_IVOR(9,  AuxillaryProcessorUnavailable); | 
 | 222 | 	SET_IVOR(10, Decrementer); | 
 | 223 | 	SET_IVOR(11, FixedIntervalTimer); | 
 | 224 | 	SET_IVOR(12, WatchdogTimer); | 
 | 225 | 	SET_IVOR(13, DataTLBError); | 
 | 226 | 	SET_IVOR(14, InstructionTLBError); | 
 | 227 | 	SET_IVOR(15, Debug); | 
 | 228 |  | 
 | 229 | 	/* Establish the interrupt vector base */ | 
 | 230 | 	lis	r4,interrupt_base@h	/* IVPR only uses the high 16-bits */ | 
 | 231 | 	mtspr	SPRN_IVPR,r4 | 
 | 232 |  | 
 | 233 | #ifdef CONFIG_440EP | 
 | 234 | 	/* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */ | 
 | 235 | 	mfspr	r2,SPRN_CCR0 | 
 | 236 | 	lis	r3,0xffef | 
 | 237 | 	ori	r3,r3,0xffff | 
 | 238 | 	and	r2,r2,r3 | 
 | 239 | 	mtspr	SPRN_CCR0,r2 | 
 | 240 | 	isync | 
 | 241 | #endif | 
 | 242 |  | 
 | 243 | 	/* | 
 | 244 | 	 * This is where the main kernel code starts. | 
 | 245 | 	 */ | 
 | 246 |  | 
 | 247 | 	/* ptr to current */ | 
 | 248 | 	lis	r2,init_task@h | 
 | 249 | 	ori	r2,r2,init_task@l | 
 | 250 |  | 
 | 251 | 	/* ptr to current thread */ | 
 | 252 | 	addi	r4,r2,THREAD	/* init task's THREAD */ | 
 | 253 | 	mtspr	SPRN_SPRG3,r4 | 
 | 254 |  | 
 | 255 | 	/* stack */ | 
 | 256 | 	lis	r1,init_thread_union@h | 
 | 257 | 	ori	r1,r1,init_thread_union@l | 
 | 258 | 	li	r0,0 | 
 | 259 | 	stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) | 
 | 260 |  | 
 | 261 | 	bl	early_init | 
 | 262 |  | 
 | 263 | /* | 
 | 264 |  * Decide what sort of machine this is and initialize the MMU. | 
 | 265 |  */ | 
 | 266 | 	mr	r3,r31 | 
 | 267 | 	mr	r4,r30 | 
 | 268 | 	mr	r5,r29 | 
 | 269 | 	mr	r6,r28 | 
 | 270 | 	mr	r7,r27 | 
 | 271 | 	bl	machine_init | 
 | 272 | 	bl	MMU_init | 
 | 273 |  | 
 | 274 | 	/* Setup PTE pointers for the Abatron bdiGDB */ | 
 | 275 | 	lis	r6, swapper_pg_dir@h | 
 | 276 | 	ori	r6, r6, swapper_pg_dir@l | 
 | 277 | 	lis	r5, abatron_pteptrs@h | 
 | 278 | 	ori	r5, r5, abatron_pteptrs@l | 
 | 279 | 	lis	r4, KERNELBASE@h | 
 | 280 | 	ori	r4, r4, KERNELBASE@l | 
 | 281 | 	stw	r5, 0(r4)	/* Save abatron_pteptrs at a fixed location */ | 
 | 282 | 	stw	r6, 0(r5) | 
 | 283 |  | 
 | 284 | 	/* Let's move on */ | 
 | 285 | 	lis	r4,start_kernel@h | 
 | 286 | 	ori	r4,r4,start_kernel@l | 
 | 287 | 	lis	r3,MSR_KERNEL@h | 
 | 288 | 	ori	r3,r3,MSR_KERNEL@l | 
 | 289 | 	mtspr	SPRN_SRR0,r4 | 
 | 290 | 	mtspr	SPRN_SRR1,r3 | 
 | 291 | 	rfi			/* change context and jump to start_kernel */ | 
 | 292 |  | 
 | 293 | /* | 
 | 294 |  * Interrupt vector entry code | 
 | 295 |  * | 
 | 296 |  * The Book E MMUs are always on so we don't need to handle | 
 | 297 |  * interrupts in real mode as with previous PPC processors. In | 
 | 298 |  * this case we handle interrupts in the kernel virtual address | 
 | 299 |  * space. | 
 | 300 |  * | 
 | 301 |  * Interrupt vectors are dynamically placed relative to the | 
 | 302 |  * interrupt prefix as determined by the address of interrupt_base. | 
 | 303 |  * The interrupt vectors offsets are programmed using the labels | 
 | 304 |  * for each interrupt vector entry. | 
 | 305 |  * | 
 | 306 |  * Interrupt vectors must be aligned on a 16 byte boundary. | 
 | 307 |  * We align on a 32 byte cache line boundary for good measure. | 
 | 308 |  */ | 
 | 309 |  | 
 | 310 | interrupt_base: | 
 | 311 | 	/* Critical Input Interrupt */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 312 | 	CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 313 |  | 
 | 314 | 	/* Machine Check Interrupt */ | 
 | 315 | #ifdef CONFIG_440A | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 316 | 	MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 317 | #else | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 318 | 	CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 319 | #endif | 
 | 320 |  | 
 | 321 | 	/* Data Storage Interrupt */ | 
 | 322 | 	START_EXCEPTION(DataStorage) | 
 | 323 | 	mtspr	SPRN_SPRG0, r10		/* Save some working registers */ | 
 | 324 | 	mtspr	SPRN_SPRG1, r11 | 
 | 325 | 	mtspr	SPRN_SPRG4W, r12 | 
 | 326 | 	mtspr	SPRN_SPRG5W, r13 | 
 | 327 | 	mfcr	r11 | 
 | 328 | 	mtspr	SPRN_SPRG7W, r11 | 
 | 329 |  | 
 | 330 | 	/* | 
 | 331 | 	 * Check if it was a store fault, if not then bail | 
 | 332 | 	 * because a user tried to access a kernel or | 
 | 333 | 	 * read-protected page.  Otherwise, get the | 
 | 334 | 	 * offending address and handle it. | 
 | 335 | 	 */ | 
 | 336 | 	mfspr	r10, SPRN_ESR | 
 | 337 | 	andis.	r10, r10, ESR_ST@h | 
 | 338 | 	beq	2f | 
 | 339 |  | 
 | 340 | 	mfspr	r10, SPRN_DEAR		/* Get faulting address */ | 
 | 341 |  | 
 | 342 | 	/* If we are faulting a kernel address, we have to use the | 
 | 343 | 	 * kernel page tables. | 
 | 344 | 	 */ | 
 | 345 | 	lis	r11, TASK_SIZE@h | 
 | 346 | 	cmplw	r10, r11 | 
 | 347 | 	blt+	3f | 
 | 348 | 	lis	r11, swapper_pg_dir@h | 
 | 349 | 	ori	r11, r11, swapper_pg_dir@l | 
 | 350 |  | 
 | 351 | 	mfspr   r12,SPRN_MMUCR | 
 | 352 | 	rlwinm	r12,r12,0,0,23		/* Clear TID */ | 
 | 353 |  | 
 | 354 | 	b	4f | 
 | 355 |  | 
 | 356 | 	/* Get the PGD for the current thread */ | 
 | 357 | 3: | 
 | 358 | 	mfspr	r11,SPRN_SPRG3 | 
 | 359 | 	lwz	r11,PGDIR(r11) | 
 | 360 |  | 
 | 361 | 	/* Load PID into MMUCR TID */ | 
 | 362 | 	mfspr	r12,SPRN_MMUCR		/* Get MMUCR */ | 
 | 363 | 	mfspr   r13,SPRN_PID		/* Get PID */ | 
 | 364 | 	rlwimi	r12,r13,0,24,31		/* Set TID */ | 
 | 365 |  | 
 | 366 | 4: | 
 | 367 | 	mtspr   SPRN_MMUCR,r12 | 
 | 368 |  | 
 | 369 | 	rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */ | 
 | 370 | 	lwzx    r11, r12, r11           /* Get pgd/pmd entry */ | 
 | 371 | 	rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */ | 
 | 372 | 	beq     2f                      /* Bail if no table */ | 
 | 373 |  | 
 | 374 | 	rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */ | 
 | 375 | 	lwz     r11, 4(r12)             /* Get pte entry */ | 
 | 376 |  | 
 | 377 | 	andi.	r13, r11, _PAGE_RW	/* Is it writeable? */ | 
 | 378 | 	beq	2f			/* Bail if not */ | 
 | 379 |  | 
 | 380 | 	/* Update 'changed'. | 
 | 381 | 	*/ | 
 | 382 | 	ori	r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE | 
 | 383 | 	stw	r11, 4(r12)		/* Update Linux page table */ | 
 | 384 |  | 
 | 385 | 	li	r13, PPC44x_TLB_SR@l	/* Set SR */ | 
 | 386 | 	rlwimi	r13, r11, 29, 29, 29	/* SX = _PAGE_HWEXEC */ | 
 | 387 | 	rlwimi	r13, r11, 0, 30, 30	/* SW = _PAGE_RW */ | 
 | 388 | 	rlwimi	r13, r11, 29, 28, 28	/* UR = _PAGE_USER */ | 
 | 389 | 	rlwimi	r12, r11, 31, 26, 26	/* (_PAGE_USER>>1)->r12 */ | 
 | 390 | 	rlwimi	r12, r11, 29, 30, 30	/* (_PAGE_USER>>3)->r12 */ | 
 | 391 | 	and	r12, r12, r11		/* HWEXEC/RW & USER */ | 
 | 392 | 	rlwimi	r13, r12, 0, 26, 26	/* UX = HWEXEC & USER */ | 
 | 393 | 	rlwimi	r13, r12, 3, 27, 27	/* UW = RW & USER */ | 
 | 394 |  | 
 | 395 | 	rlwimi	r11,r13,0,26,31		/* Insert static perms */ | 
 | 396 |  | 
 | 397 | 	rlwinm	r11,r11,0,20,15		/* Clear U0-U3 */ | 
 | 398 |  | 
 | 399 | 	/* find the TLB index that caused the fault.  It has to be here. */ | 
 | 400 | 	tlbsx	r10, 0, r10 | 
 | 401 |  | 
 | 402 | 	tlbwe	r11, r10, PPC44x_TLB_ATTRIB	/* Write ATTRIB */ | 
 | 403 |  | 
 | 404 | 	/* Done...restore registers and get out of here. | 
 | 405 | 	*/ | 
 | 406 | 	mfspr	r11, SPRN_SPRG7R | 
 | 407 | 	mtcr	r11 | 
 | 408 | 	mfspr	r13, SPRN_SPRG5R | 
 | 409 | 	mfspr	r12, SPRN_SPRG4R | 
 | 410 |  | 
 | 411 | 	mfspr	r11, SPRN_SPRG1 | 
 | 412 | 	mfspr	r10, SPRN_SPRG0 | 
 | 413 | 	rfi			/* Force context change */ | 
 | 414 |  | 
 | 415 | 2: | 
 | 416 | 	/* | 
 | 417 | 	 * The bailout.  Restore registers to pre-exception conditions | 
 | 418 | 	 * and call the heavyweights to help us out. | 
 | 419 | 	 */ | 
 | 420 | 	mfspr	r11, SPRN_SPRG7R | 
 | 421 | 	mtcr	r11 | 
 | 422 | 	mfspr	r13, SPRN_SPRG5R | 
 | 423 | 	mfspr	r12, SPRN_SPRG4R | 
 | 424 |  | 
 | 425 | 	mfspr	r11, SPRN_SPRG1 | 
 | 426 | 	mfspr	r10, SPRN_SPRG0 | 
 | 427 | 	b	data_access | 
 | 428 |  | 
 | 429 | 	/* Instruction Storage Interrupt */ | 
 | 430 | 	INSTRUCTION_STORAGE_EXCEPTION | 
 | 431 |  | 
 | 432 | 	/* External Input Interrupt */ | 
 | 433 | 	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) | 
 | 434 |  | 
 | 435 | 	/* Alignment Interrupt */ | 
 | 436 | 	ALIGNMENT_EXCEPTION | 
 | 437 |  | 
 | 438 | 	/* Program Interrupt */ | 
 | 439 | 	PROGRAM_EXCEPTION | 
 | 440 |  | 
 | 441 | 	/* Floating Point Unavailable Interrupt */ | 
 | 442 | #ifdef CONFIG_PPC_FPU | 
 | 443 | 	FP_UNAVAILABLE_EXCEPTION | 
 | 444 | #else | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 445 | 	EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 446 | #endif | 
 | 447 |  | 
 | 448 | 	/* System Call Interrupt */ | 
 | 449 | 	START_EXCEPTION(SystemCall) | 
 | 450 | 	NORMAL_EXCEPTION_PROLOG | 
 | 451 | 	EXC_XFER_EE_LITE(0x0c00, DoSyscall) | 
 | 452 |  | 
 | 453 | 	/* Auxillary Processor Unavailable Interrupt */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 454 | 	EXCEPTION(0x2020, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 455 |  | 
 | 456 | 	/* Decrementer Interrupt */ | 
 | 457 | 	DECREMENTER_EXCEPTION | 
 | 458 |  | 
 | 459 | 	/* Fixed Internal Timer Interrupt */ | 
 | 460 | 	/* TODO: Add FIT support */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 461 | 	EXCEPTION(0x1010, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 462 |  | 
 | 463 | 	/* Watchdog Timer Interrupt */ | 
 | 464 | 	/* TODO: Add watchdog support */ | 
 | 465 | #ifdef CONFIG_BOOKE_WDT | 
 | 466 | 	CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException) | 
 | 467 | #else | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 468 | 	CRITICAL_EXCEPTION(0x1020, WatchdogTimer, unknown_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 469 | #endif | 
 | 470 |  | 
 | 471 | 	/* Data TLB Error Interrupt */ | 
 | 472 | 	START_EXCEPTION(DataTLBError) | 
 | 473 | 	mtspr	SPRN_SPRG0, r10		/* Save some working registers */ | 
 | 474 | 	mtspr	SPRN_SPRG1, r11 | 
 | 475 | 	mtspr	SPRN_SPRG4W, r12 | 
 | 476 | 	mtspr	SPRN_SPRG5W, r13 | 
 | 477 | 	mfcr	r11 | 
 | 478 | 	mtspr	SPRN_SPRG7W, r11 | 
 | 479 | 	mfspr	r10, SPRN_DEAR		/* Get faulting address */ | 
 | 480 |  | 
 | 481 | 	/* If we are faulting a kernel address, we have to use the | 
 | 482 | 	 * kernel page tables. | 
 | 483 | 	 */ | 
 | 484 | 	lis	r11, TASK_SIZE@h | 
 | 485 | 	cmplw	r10, r11 | 
 | 486 | 	blt+	3f | 
 | 487 | 	lis	r11, swapper_pg_dir@h | 
 | 488 | 	ori	r11, r11, swapper_pg_dir@l | 
 | 489 |  | 
 | 490 | 	mfspr	r12,SPRN_MMUCR | 
 | 491 | 	rlwinm	r12,r12,0,0,23		/* Clear TID */ | 
 | 492 |  | 
 | 493 | 	b	4f | 
 | 494 |  | 
 | 495 | 	/* Get the PGD for the current thread */ | 
 | 496 | 3: | 
 | 497 | 	mfspr	r11,SPRN_SPRG3 | 
 | 498 | 	lwz	r11,PGDIR(r11) | 
 | 499 |  | 
 | 500 | 	/* Load PID into MMUCR TID */ | 
 | 501 | 	mfspr	r12,SPRN_MMUCR | 
 | 502 | 	mfspr   r13,SPRN_PID		/* Get PID */ | 
 | 503 | 	rlwimi	r12,r13,0,24,31		/* Set TID */ | 
 | 504 |  | 
 | 505 | 4: | 
 | 506 | 	mtspr	SPRN_MMUCR,r12 | 
 | 507 |  | 
 | 508 | 	rlwinm 	r12, r10, 13, 19, 29	/* Compute pgdir/pmd offset */ | 
 | 509 | 	lwzx	r11, r12, r11		/* Get pgd/pmd entry */ | 
 | 510 | 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */ | 
 | 511 | 	beq	2f			/* Bail if no table */ | 
 | 512 |  | 
 | 513 | 	rlwimi	r12, r10, 23, 20, 28	/* Compute pte address */ | 
 | 514 | 	lwz	r11, 4(r12)		/* Get pte entry */ | 
 | 515 | 	andi.	r13, r11, _PAGE_PRESENT	/* Is the page present? */ | 
 | 516 | 	beq	2f			/* Bail if not present */ | 
 | 517 |  | 
 | 518 | 	ori	r11, r11, _PAGE_ACCESSED | 
 | 519 | 	stw	r11, 4(r12) | 
 | 520 |  | 
 | 521 | 	 /* Jump to common tlb load */ | 
 | 522 | 	b	finish_tlb_load | 
 | 523 |  | 
 | 524 | 2: | 
 | 525 | 	/* The bailout.  Restore registers to pre-exception conditions | 
 | 526 | 	 * and call the heavyweights to help us out. | 
 | 527 | 	 */ | 
 | 528 | 	mfspr	r11, SPRN_SPRG7R | 
 | 529 | 	mtcr	r11 | 
 | 530 | 	mfspr	r13, SPRN_SPRG5R | 
 | 531 | 	mfspr	r12, SPRN_SPRG4R | 
 | 532 | 	mfspr	r11, SPRN_SPRG1 | 
 | 533 | 	mfspr	r10, SPRN_SPRG0 | 
 | 534 | 	b	data_access | 
 | 535 |  | 
 | 536 | 	/* Instruction TLB Error Interrupt */ | 
 | 537 | 	/* | 
 | 538 | 	 * Nearly the same as above, except we get our | 
 | 539 | 	 * information from different registers and bailout | 
 | 540 | 	 * to a different point. | 
 | 541 | 	 */ | 
 | 542 | 	START_EXCEPTION(InstructionTLBError) | 
 | 543 | 	mtspr	SPRN_SPRG0, r10		/* Save some working registers */ | 
 | 544 | 	mtspr	SPRN_SPRG1, r11 | 
 | 545 | 	mtspr	SPRN_SPRG4W, r12 | 
 | 546 | 	mtspr	SPRN_SPRG5W, r13 | 
 | 547 | 	mfcr	r11 | 
 | 548 | 	mtspr	SPRN_SPRG7W, r11 | 
 | 549 | 	mfspr	r10, SPRN_SRR0		/* Get faulting address */ | 
 | 550 |  | 
 | 551 | 	/* If we are faulting a kernel address, we have to use the | 
 | 552 | 	 * kernel page tables. | 
 | 553 | 	 */ | 
 | 554 | 	lis	r11, TASK_SIZE@h | 
 | 555 | 	cmplw	r10, r11 | 
 | 556 | 	blt+	3f | 
 | 557 | 	lis	r11, swapper_pg_dir@h | 
 | 558 | 	ori	r11, r11, swapper_pg_dir@l | 
 | 559 |  | 
 | 560 | 	mfspr	r12,SPRN_MMUCR | 
 | 561 | 	rlwinm	r12,r12,0,0,23		/* Clear TID */ | 
 | 562 |  | 
 | 563 | 	b	4f | 
 | 564 |  | 
 | 565 | 	/* Get the PGD for the current thread */ | 
 | 566 | 3: | 
 | 567 | 	mfspr	r11,SPRN_SPRG3 | 
 | 568 | 	lwz	r11,PGDIR(r11) | 
 | 569 |  | 
 | 570 | 	/* Load PID into MMUCR TID */ | 
 | 571 | 	mfspr	r12,SPRN_MMUCR | 
 | 572 | 	mfspr   r13,SPRN_PID		/* Get PID */ | 
 | 573 | 	rlwimi	r12,r13,0,24,31		/* Set TID */ | 
 | 574 |  | 
 | 575 | 4: | 
 | 576 | 	mtspr	SPRN_MMUCR,r12 | 
 | 577 |  | 
 | 578 | 	rlwinm	r12, r10, 13, 19, 29	/* Compute pgdir/pmd offset */ | 
 | 579 | 	lwzx	r11, r12, r11		/* Get pgd/pmd entry */ | 
 | 580 | 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */ | 
 | 581 | 	beq	2f			/* Bail if no table */ | 
 | 582 |  | 
 | 583 | 	rlwimi	r12, r10, 23, 20, 28	/* Compute pte address */ | 
 | 584 | 	lwz	r11, 4(r12)		/* Get pte entry */ | 
 | 585 | 	andi.	r13, r11, _PAGE_PRESENT	/* Is the page present? */ | 
 | 586 | 	beq	2f			/* Bail if not present */ | 
 | 587 |  | 
 | 588 | 	ori	r11, r11, _PAGE_ACCESSED | 
 | 589 | 	stw	r11, 4(r12) | 
 | 590 |  | 
 | 591 | 	/* Jump to common TLB load point */ | 
 | 592 | 	b	finish_tlb_load | 
 | 593 |  | 
 | 594 | 2: | 
 | 595 | 	/* The bailout.  Restore registers to pre-exception conditions | 
 | 596 | 	 * and call the heavyweights to help us out. | 
 | 597 | 	 */ | 
 | 598 | 	mfspr	r11, SPRN_SPRG7R | 
 | 599 | 	mtcr	r11 | 
 | 600 | 	mfspr	r13, SPRN_SPRG5R | 
 | 601 | 	mfspr	r12, SPRN_SPRG4R | 
 | 602 | 	mfspr	r11, SPRN_SPRG1 | 
 | 603 | 	mfspr	r10, SPRN_SPRG0 | 
 | 604 | 	b	InstructionStorage | 
 | 605 |  | 
 | 606 | 	/* Debug Interrupt */ | 
 | 607 | 	DEBUG_EXCEPTION | 
 | 608 |  | 
 | 609 | /* | 
 | 610 |  * Local functions | 
 | 611 |  */ | 
 | 612 | 	/* | 
 | 613 | 	 * Data TLB exceptions will bail out to this point | 
 | 614 | 	 * if they can't resolve the lightweight TLB fault. | 
 | 615 | 	 */ | 
 | 616 | data_access: | 
 | 617 | 	NORMAL_EXCEPTION_PROLOG | 
 | 618 | 	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */ | 
 | 619 | 	stw	r5,_ESR(r11) | 
 | 620 | 	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */ | 
 | 621 | 	EXC_XFER_EE_LITE(0x0300, handle_page_fault) | 
 | 622 |  | 
 | 623 | /* | 
 | 624 |  | 
 | 625 |  * Both the instruction and data TLB miss get to this | 
 | 626 |  * point to load the TLB. | 
 | 627 |  * 	r10 - EA of fault | 
 | 628 |  * 	r11 - available to use | 
 | 629 |  *	r12 - Pointer to the 64-bit PTE | 
 | 630 |  *	r13 - available to use | 
 | 631 |  *	MMUCR - loaded with proper value when we get here | 
 | 632 |  *	Upon exit, we reload everything and RFI. | 
 | 633 |  */ | 
 | 634 | finish_tlb_load: | 
 | 635 | 	/* | 
 | 636 | 	 * We set execute, because we don't have the granularity to | 
 | 637 | 	 * properly set this at the page level (Linux problem). | 
 | 638 | 	 * If shared is set, we cause a zero PID->TID load. | 
 | 639 | 	 * Many of these bits are software only.  Bits we don't set | 
 | 640 | 	 * here we (properly should) assume have the appropriate value. | 
 | 641 | 	 */ | 
 | 642 |  | 
 | 643 | 	/* Load the next available TLB index */ | 
 | 644 | 	lis	r13, tlb_44x_index@ha | 
 | 645 | 	lwz	r13, tlb_44x_index@l(r13) | 
 | 646 | 	/* Load the TLB high watermark */ | 
 | 647 | 	lis	r11, tlb_44x_hwater@ha | 
 | 648 | 	lwz	r11, tlb_44x_hwater@l(r11) | 
 | 649 |  | 
 | 650 | 	/* Increment, rollover, and store TLB index */ | 
 | 651 | 	addi	r13, r13, 1 | 
 | 652 | 	cmpw	0, r13, r11			/* reserve entries */ | 
 | 653 | 	ble	7f | 
 | 654 | 	li	r13, 0 | 
 | 655 | 7: | 
 | 656 | 	/* Store the next available TLB index */ | 
 | 657 | 	lis	r11, tlb_44x_index@ha | 
 | 658 | 	stw	r13, tlb_44x_index@l(r11) | 
 | 659 |  | 
 | 660 | 	lwz	r11, 0(r12)			/* Get MS word of PTE */ | 
 | 661 | 	lwz	r12, 4(r12)			/* Get LS word of PTE */ | 
 | 662 | 	rlwimi	r11, r12, 0, 0 , 19		/* Insert RPN */ | 
 | 663 | 	tlbwe	r11, r13, PPC44x_TLB_XLAT	/* Write XLAT */ | 
 | 664 |  | 
 | 665 | 	/* | 
 | 666 | 	 * Create PAGEID. This is the faulting address, | 
 | 667 | 	 * page size, and valid flag. | 
 | 668 | 	 */ | 
 | 669 | 	li	r11, PPC44x_TLB_VALID | PPC44x_TLB_4K | 
 | 670 | 	rlwimi	r10, r11, 0, 20, 31		/* Insert valid and page size */ | 
 | 671 | 	tlbwe	r10, r13, PPC44x_TLB_PAGEID	/* Write PAGEID */ | 
 | 672 |  | 
 | 673 | 	li	r10, PPC44x_TLB_SR@l		/* Set SR */ | 
 | 674 | 	rlwimi	r10, r12, 0, 30, 30		/* Set SW = _PAGE_RW */ | 
 | 675 | 	rlwimi	r10, r12, 29, 29, 29		/* SX = _PAGE_HWEXEC */ | 
 | 676 | 	rlwimi	r10, r12, 29, 28, 28		/* UR = _PAGE_USER */ | 
 | 677 | 	rlwimi	r11, r12, 31, 26, 26		/* (_PAGE_USER>>1)->r12 */ | 
 | 678 | 	and	r11, r12, r11			/* HWEXEC & USER */ | 
 | 679 | 	rlwimi	r10, r11, 0, 26, 26		/* UX = HWEXEC & USER */ | 
 | 680 |  | 
 | 681 | 	rlwimi	r12, r10, 0, 26, 31		/* Insert static perms */ | 
 | 682 | 	rlwinm	r12, r12, 0, 20, 15		/* Clear U0-U3 */ | 
 | 683 | 	tlbwe	r12, r13, PPC44x_TLB_ATTRIB	/* Write ATTRIB */ | 
 | 684 |  | 
 | 685 | 	/* Done...restore registers and get out of here. | 
 | 686 | 	*/ | 
 | 687 | 	mfspr	r11, SPRN_SPRG7R | 
 | 688 | 	mtcr	r11 | 
 | 689 | 	mfspr	r13, SPRN_SPRG5R | 
 | 690 | 	mfspr	r12, SPRN_SPRG4R | 
 | 691 | 	mfspr	r11, SPRN_SPRG1 | 
 | 692 | 	mfspr	r10, SPRN_SPRG0 | 
 | 693 | 	rfi					/* Force context change */ | 
 | 694 |  | 
 | 695 | /* | 
 | 696 |  * Global functions | 
 | 697 |  */ | 
 | 698 |  | 
 | 699 | /* | 
 | 700 |  * extern void giveup_altivec(struct task_struct *prev) | 
 | 701 |  * | 
 | 702 |  * The 44x core does not have an AltiVec unit. | 
 | 703 |  */ | 
 | 704 | _GLOBAL(giveup_altivec) | 
 | 705 | 	blr | 
 | 706 |  | 
 | 707 | /* | 
 | 708 |  * extern void giveup_fpu(struct task_struct *prev) | 
 | 709 |  * | 
 | 710 |  * The 44x core does not have an FPU. | 
 | 711 |  */ | 
 | 712 | #ifndef CONFIG_PPC_FPU | 
 | 713 | _GLOBAL(giveup_fpu) | 
 | 714 | 	blr | 
 | 715 | #endif | 
 | 716 |  | 
 | 717 | /* | 
 | 718 |  * extern void abort(void) | 
 | 719 |  * | 
 | 720 |  * At present, this routine just applies a system reset. | 
 | 721 |  */ | 
 | 722 | _GLOBAL(abort) | 
 | 723 |         mfspr   r13,SPRN_DBCR0 | 
 | 724 |         oris    r13,r13,DBCR0_RST_SYSTEM@h | 
 | 725 |         mtspr   SPRN_DBCR0,r13 | 
 | 726 |  | 
 | 727 | _GLOBAL(set_context) | 
 | 728 |  | 
 | 729 | #ifdef CONFIG_BDI_SWITCH | 
 | 730 | 	/* Context switch the PTE pointer for the Abatron BDI2000. | 
 | 731 | 	 * The PGDIR is the second parameter. | 
 | 732 | 	 */ | 
 | 733 | 	lis	r5, abatron_pteptrs@h | 
 | 734 | 	ori	r5, r5, abatron_pteptrs@l | 
 | 735 | 	stw	r4, 0x4(r5) | 
 | 736 | #endif | 
 | 737 | 	mtspr	SPRN_PID,r3 | 
 | 738 | 	isync			/* Force context change */ | 
 | 739 | 	blr | 
 | 740 |  | 
 | 741 | /* | 
 | 742 |  * We put a few things here that have to be page-aligned. This stuff | 
 | 743 |  * goes at the beginning of the data segment, which is page-aligned. | 
 | 744 |  */ | 
 | 745 | 	.data | 
| Kumar Gala | ea703ce | 2005-10-11 23:54:00 -0500 | [diff] [blame] | 746 | 	.align	12 | 
 | 747 | 	.globl	sdata | 
 | 748 | sdata: | 
 | 749 | 	.globl	empty_zero_page | 
 | 750 | empty_zero_page: | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 751 | 	.space	4096 | 
 | 752 |  | 
 | 753 | /* | 
 | 754 |  * To support >32-bit physical addresses, we use an 8KB pgdir. | 
 | 755 |  */ | 
| Kumar Gala | ea703ce | 2005-10-11 23:54:00 -0500 | [diff] [blame] | 756 | 	.globl	swapper_pg_dir | 
 | 757 | swapper_pg_dir: | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 758 | 	.space	8192 | 
 | 759 |  | 
 | 760 | /* Reserved 4k for the critical exception stack & 4k for the machine | 
 | 761 |  * check stack per CPU for kernel mode exceptions */ | 
 | 762 | 	.section .bss | 
 | 763 |         .align 12 | 
 | 764 | exception_stack_bottom: | 
 | 765 | 	.space	BOOKE_EXCEPTION_STACK_SIZE | 
| Kumar Gala | ea703ce | 2005-10-11 23:54:00 -0500 | [diff] [blame] | 766 | 	.globl	exception_stack_top | 
 | 767 | exception_stack_top: | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 768 |  | 
 | 769 | /* | 
 | 770 |  * This space gets a copy of optional info passed to us by the bootstrap | 
 | 771 |  * which is used to pass parameters into the kernel like root=/dev/sda1, etc. | 
 | 772 |  */ | 
| Kumar Gala | ea703ce | 2005-10-11 23:54:00 -0500 | [diff] [blame] | 773 | 	.globl	cmd_line | 
 | 774 | cmd_line: | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 775 | 	.space	512 | 
 | 776 |  | 
 | 777 | /* | 
 | 778 |  * Room for two PTE pointers, usually the kernel and current user pointers | 
 | 779 |  * to their respective root page table. | 
 | 780 |  */ | 
 | 781 | abatron_pteptrs: | 
 | 782 | 	.space	8 |