| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 1 | /* | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 2 | * Kernel execution entry point code. | 
|  | 3 | * | 
|  | 4 | *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org> | 
|  | 5 | *      Initial PowerPC version. | 
|  | 6 | *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu> | 
|  | 7 | *      Rewritten for PReP | 
|  | 8 | *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> | 
|  | 9 | *      Low-level exception handers, MMU support, and rewrite. | 
|  | 10 | *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net> | 
|  | 11 | *      PowerPC 8xx modifications. | 
|  | 12 | *    Copyright (c) 1998-1999 TiVo, Inc. | 
|  | 13 | *      PowerPC 403GCX modifications. | 
|  | 14 | *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> | 
|  | 15 | *      PowerPC 403GCX/405GP modifications. | 
|  | 16 | *    Copyright 2000 MontaVista Software Inc. | 
|  | 17 | *	PPC405 modifications | 
|  | 18 | *      PowerPC 403GCX/405GP modifications. | 
|  | 19 | * 	Author: MontaVista Software, Inc. | 
|  | 20 | *         	frank_rowand@mvista.com or source@mvista.com | 
|  | 21 | * 	   	debbie_chu@mvista.com | 
|  | 22 | *    Copyright 2002-2005 MontaVista Software, Inc. | 
|  | 23 | *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org> | 
|  | 24 | * | 
|  | 25 | * This program is free software; you can redistribute  it and/or modify it | 
|  | 26 | * under  the terms of  the GNU General  Public License as published by the | 
|  | 27 | * Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 28 | * option) any later version. | 
|  | 29 | */ | 
|  | 30 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 31 | #include <asm/processor.h> | 
|  | 32 | #include <asm/page.h> | 
|  | 33 | #include <asm/mmu.h> | 
|  | 34 | #include <asm/pgtable.h> | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 35 | #include <asm/cputable.h> | 
|  | 36 | #include <asm/thread_info.h> | 
|  | 37 | #include <asm/ppc_asm.h> | 
|  | 38 | #include <asm/asm-offsets.h> | 
|  | 39 | #include "head_booke.h" | 
|  | 40 |  | 
|  | 41 |  | 
|  | 42 | /* As with the other PowerPC ports, it is expected that when code | 
|  | 43 | * execution begins here, the following registers contain valid, yet | 
|  | 44 | * optional, information: | 
|  | 45 | * | 
|  | 46 | *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) | 
|  | 47 | *   r4 - Starting address of the init RAM disk | 
|  | 48 | *   r5 - Ending address of the init RAM disk | 
|  | 49 | *   r6 - Start of kernel command line string (e.g. "mem=128") | 
|  | 50 | *   r7 - End of kernel command line string | 
|  | 51 | * | 
|  | 52 | */ | 
| Kumar Gala | 748a768 | 2007-09-13 15:42:35 -0500 | [diff] [blame] | 53 | .section	.text.head, "ax" | 
|  | 54 | _ENTRY(_stext); | 
|  | 55 | _ENTRY(_start); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 56 | /* | 
|  | 57 | * Reserve a word at a fixed location to store the address | 
|  | 58 | * of abatron_pteptrs | 
|  | 59 | */ | 
|  | 60 | nop | 
|  | 61 | /* | 
|  | 62 | * Save parameters we are passed | 
|  | 63 | */ | 
|  | 64 | mr	r31,r3 | 
|  | 65 | mr	r30,r4 | 
|  | 66 | mr	r29,r5 | 
|  | 67 | mr	r28,r6 | 
|  | 68 | mr	r27,r7 | 
|  | 69 | li	r24,0		/* CPU number */ | 
|  | 70 |  | 
|  | 71 | /* | 
|  | 72 | * Set up the initial MMU state | 
|  | 73 | * | 
|  | 74 | * We are still executing code at the virtual address | 
|  | 75 | * mappings set by the firmware for the base of RAM. | 
|  | 76 | * | 
|  | 77 | * We first invalidate all TLB entries but the one | 
|  | 78 | * we are running from.  We then load the KERNELBASE | 
|  | 79 | * mappings so we can begin to use kernel addresses | 
|  | 80 | * natively and so the interrupt vector locations are | 
|  | 81 | * permanently pinned (necessary since Book E | 
|  | 82 | * implementations always have translation enabled). | 
|  | 83 | * | 
|  | 84 | * TODO: Use the known TLB entry we are running from to | 
|  | 85 | *	 determine which physical region we are located | 
|  | 86 | *	 in.  This can be used to determine where in RAM | 
|  | 87 | *	 (on a shared CPU system) or PCI memory space | 
|  | 88 | *	 (on a DRAMless system) we are located. | 
|  | 89 | *       For now, we assume a perfect world which means | 
|  | 90 | *	 we are located at the base of DRAM (physical 0). | 
|  | 91 | */ | 
|  | 92 |  | 
|  | 93 | /* | 
|  | 94 | * Search TLB for entry that we are currently using. | 
|  | 95 | * Invalidate all entries but the one we are using. | 
|  | 96 | */ | 
|  | 97 | /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ | 
|  | 98 | mfspr	r3,SPRN_PID			/* Get PID */ | 
|  | 99 | mfmsr	r4				/* Get MSR */ | 
|  | 100 | andi.	r4,r4,MSR_IS@l			/* TS=1? */ | 
|  | 101 | beq	wmmucr				/* If not, leave STS=0 */ | 
|  | 102 | oris	r3,r3,PPC44x_MMUCR_STS@h	/* Set STS=1 */ | 
|  | 103 | wmmucr:	mtspr	SPRN_MMUCR,r3			/* Put MMUCR */ | 
|  | 104 | sync | 
|  | 105 |  | 
|  | 106 | bl	invstr				/* Find our address */ | 
|  | 107 | invstr:	mflr	r5				/* Make it accessible */ | 
|  | 108 | tlbsx	r23,0,r5			/* Find entry we are in */ | 
|  | 109 | li	r4,0				/* Start at TLB entry 0 */ | 
|  | 110 | li	r3,0				/* Set PAGEID inval value */ | 
|  | 111 | 1:	cmpw	r23,r4				/* Is this our entry? */ | 
|  | 112 | beq	skpinv				/* If so, skip the inval */ | 
|  | 113 | tlbwe	r3,r4,PPC44x_TLB_PAGEID		/* If not, inval the entry */ | 
|  | 114 | skpinv:	addi	r4,r4,1				/* Increment */ | 
|  | 115 | cmpwi	r4,64				/* Are we done? */ | 
|  | 116 | bne	1b				/* If not, repeat */ | 
|  | 117 | isync					/* If so, context change */ | 
|  | 118 |  | 
|  | 119 | /* | 
|  | 120 | * Configure and load pinned entry into TLB slot 63. | 
|  | 121 | */ | 
|  | 122 |  | 
| David Gibson | 57d7909 | 2007-04-30 14:06:25 +1000 | [diff] [blame] | 123 | lis	r3,PAGE_OFFSET@h | 
|  | 124 | ori	r3,r3,PAGE_OFFSET@l | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 125 |  | 
|  | 126 | /* Kernel is at the base of RAM */ | 
|  | 127 | li r4, 0			/* Load the kernel physical address */ | 
|  | 128 |  | 
|  | 129 | /* Load the kernel PID = 0 */ | 
|  | 130 | li	r0,0 | 
|  | 131 | mtspr	SPRN_PID,r0 | 
|  | 132 | sync | 
|  | 133 |  | 
|  | 134 | /* Initialize MMUCR */ | 
|  | 135 | li	r5,0 | 
|  | 136 | mtspr	SPRN_MMUCR,r5 | 
|  | 137 | sync | 
|  | 138 |  | 
|  | 139 | /* pageid fields */ | 
|  | 140 | clrrwi	r3,r3,10		/* Mask off the effective page number */ | 
|  | 141 | ori	r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M | 
|  | 142 |  | 
|  | 143 | /* xlat fields */ | 
|  | 144 | clrrwi	r4,r4,10		/* Mask off the real page number */ | 
|  | 145 | /* ERPN is 0 for first 4GB page */ | 
|  | 146 |  | 
|  | 147 | /* attrib fields */ | 
|  | 148 | /* Added guarded bit to protect against speculative loads/stores */ | 
|  | 149 | li	r5,0 | 
|  | 150 | ori	r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) | 
|  | 151 |  | 
|  | 152 | li      r0,63                    /* TLB slot 63 */ | 
|  | 153 |  | 
|  | 154 | tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */ | 
|  | 155 | tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */ | 
|  | 156 | tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */ | 
|  | 157 |  | 
|  | 158 | /* Force context change */ | 
|  | 159 | mfmsr	r0 | 
|  | 160 | mtspr	SPRN_SRR1, r0 | 
|  | 161 | lis	r0,3f@h | 
|  | 162 | ori	r0,r0,3f@l | 
|  | 163 | mtspr	SPRN_SRR0,r0 | 
|  | 164 | sync | 
|  | 165 | rfi | 
|  | 166 |  | 
|  | 167 | /* If necessary, invalidate original entry we used */ | 
|  | 168 | 3:	cmpwi	r23,63 | 
|  | 169 | beq	4f | 
|  | 170 | li	r6,0 | 
|  | 171 | tlbwe   r6,r23,PPC44x_TLB_PAGEID | 
|  | 172 | isync | 
|  | 173 |  | 
|  | 174 | 4: | 
| David Gibson | d9b55a0 | 2007-05-08 12:59:31 +1000 | [diff] [blame] | 175 | #ifdef CONFIG_PPC_EARLY_DEBUG_44x | 
|  | 176 | /* Add UART mapping for early debug. */ | 
|  | 177 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 178 | /* pageid fields */ | 
| David Gibson | d9b55a0 | 2007-05-08 12:59:31 +1000 | [diff] [blame] | 179 | lis	r3,PPC44x_EARLY_DEBUG_VIRTADDR@h | 
|  | 180 | ori	r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 181 |  | 
|  | 182 | /* xlat fields */ | 
| David Gibson | d9b55a0 | 2007-05-08 12:59:31 +1000 | [diff] [blame] | 183 | lis	r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h | 
|  | 184 | ori	r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 185 |  | 
|  | 186 | /* attrib fields */ | 
| David Gibson | d9b55a0 | 2007-05-08 12:59:31 +1000 | [diff] [blame] | 187 | li	r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) | 
|  | 188 | li      r0,62                    /* TLB slot 0 */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 189 |  | 
| David Gibson | d9b55a0 | 2007-05-08 12:59:31 +1000 | [diff] [blame] | 190 | tlbwe	r3,r0,PPC44x_TLB_PAGEID | 
|  | 191 | tlbwe	r4,r0,PPC44x_TLB_XLAT | 
|  | 192 | tlbwe	r5,r0,PPC44x_TLB_ATTRIB | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 193 |  | 
|  | 194 | /* Force context change */ | 
|  | 195 | isync | 
| David Gibson | d9b55a0 | 2007-05-08 12:59:31 +1000 | [diff] [blame] | 196 | #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 197 |  | 
|  | 198 | /* Establish the interrupt vector offsets */ | 
|  | 199 | SET_IVOR(0,  CriticalInput); | 
|  | 200 | SET_IVOR(1,  MachineCheck); | 
|  | 201 | SET_IVOR(2,  DataStorage); | 
|  | 202 | SET_IVOR(3,  InstructionStorage); | 
|  | 203 | SET_IVOR(4,  ExternalInput); | 
|  | 204 | SET_IVOR(5,  Alignment); | 
|  | 205 | SET_IVOR(6,  Program); | 
|  | 206 | SET_IVOR(7,  FloatingPointUnavailable); | 
|  | 207 | SET_IVOR(8,  SystemCall); | 
|  | 208 | SET_IVOR(9,  AuxillaryProcessorUnavailable); | 
|  | 209 | SET_IVOR(10, Decrementer); | 
|  | 210 | SET_IVOR(11, FixedIntervalTimer); | 
|  | 211 | SET_IVOR(12, WatchdogTimer); | 
|  | 212 | SET_IVOR(13, DataTLBError); | 
|  | 213 | SET_IVOR(14, InstructionTLBError); | 
| Kumar Gala | eb0cd5f | 2008-04-09 06:06:11 -0500 | [diff] [blame] | 214 | SET_IVOR(15, DebugCrit); | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 215 |  | 
|  | 216 | /* Establish the interrupt vector base */ | 
|  | 217 | lis	r4,interrupt_base@h	/* IVPR only uses the high 16-bits */ | 
|  | 218 | mtspr	SPRN_IVPR,r4 | 
|  | 219 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 220 | /* | 
|  | 221 | * This is where the main kernel code starts. | 
|  | 222 | */ | 
|  | 223 |  | 
|  | 224 | /* ptr to current */ | 
|  | 225 | lis	r2,init_task@h | 
|  | 226 | ori	r2,r2,init_task@l | 
|  | 227 |  | 
|  | 228 | /* ptr to current thread */ | 
|  | 229 | addi	r4,r2,THREAD	/* init task's THREAD */ | 
|  | 230 | mtspr	SPRN_SPRG3,r4 | 
|  | 231 |  | 
|  | 232 | /* stack */ | 
|  | 233 | lis	r1,init_thread_union@h | 
|  | 234 | ori	r1,r1,init_thread_union@l | 
|  | 235 | li	r0,0 | 
|  | 236 | stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) | 
|  | 237 |  | 
|  | 238 | bl	early_init | 
|  | 239 |  | 
|  | 240 | /* | 
|  | 241 | * Decide what sort of machine this is and initialize the MMU. | 
|  | 242 | */ | 
|  | 243 | mr	r3,r31 | 
|  | 244 | mr	r4,r30 | 
|  | 245 | mr	r5,r29 | 
|  | 246 | mr	r6,r28 | 
|  | 247 | mr	r7,r27 | 
|  | 248 | bl	machine_init | 
|  | 249 | bl	MMU_init | 
|  | 250 |  | 
|  | 251 | /* Setup PTE pointers for the Abatron bdiGDB */ | 
|  | 252 | lis	r6, swapper_pg_dir@h | 
|  | 253 | ori	r6, r6, swapper_pg_dir@l | 
|  | 254 | lis	r5, abatron_pteptrs@h | 
|  | 255 | ori	r5, r5, abatron_pteptrs@l | 
|  | 256 | lis	r4, KERNELBASE@h | 
|  | 257 | ori	r4, r4, KERNELBASE@l | 
|  | 258 | stw	r5, 0(r4)	/* Save abatron_pteptrs at a fixed location */ | 
|  | 259 | stw	r6, 0(r5) | 
|  | 260 |  | 
|  | 261 | /* Let's move on */ | 
|  | 262 | lis	r4,start_kernel@h | 
|  | 263 | ori	r4,r4,start_kernel@l | 
|  | 264 | lis	r3,MSR_KERNEL@h | 
|  | 265 | ori	r3,r3,MSR_KERNEL@l | 
|  | 266 | mtspr	SPRN_SRR0,r4 | 
|  | 267 | mtspr	SPRN_SRR1,r3 | 
|  | 268 | rfi			/* change context and jump to start_kernel */ | 
|  | 269 |  | 
|  | 270 | /* | 
|  | 271 | * Interrupt vector entry code | 
|  | 272 | * | 
|  | 273 | * The Book E MMUs are always on so we don't need to handle | 
|  | 274 | * interrupts in real mode as with previous PPC processors. In | 
|  | 275 | * this case we handle interrupts in the kernel virtual address | 
|  | 276 | * space. | 
|  | 277 | * | 
|  | 278 | * Interrupt vectors are dynamically placed relative to the | 
|  | 279 | * interrupt prefix as determined by the address of interrupt_base. | 
|  | 280 | * The interrupt vectors offsets are programmed using the labels | 
|  | 281 | * for each interrupt vector entry. | 
|  | 282 | * | 
|  | 283 | * Interrupt vectors must be aligned on a 16 byte boundary. | 
|  | 284 | * We align on a 32 byte cache line boundary for good measure. | 
|  | 285 | */ | 
|  | 286 |  | 
|  | 287 | interrupt_base: | 
|  | 288 | /* Critical Input Interrupt */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 289 | CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 290 |  | 
|  | 291 | /* Machine Check Interrupt */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 292 | CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) | 
| Benjamin Herrenschmidt | 47c0bd1 | 2007-12-21 15:39:21 +1100 | [diff] [blame] | 293 | MCHECK_EXCEPTION(0x0210, MachineCheckA, machine_check_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 294 |  | 
|  | 295 | /* Data Storage Interrupt */ | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 296 | DATA_STORAGE_EXCEPTION | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 297 |  | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 298 | /* Instruction Storage Interrupt */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 299 | INSTRUCTION_STORAGE_EXCEPTION | 
|  | 300 |  | 
|  | 301 | /* External Input Interrupt */ | 
|  | 302 | EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) | 
|  | 303 |  | 
|  | 304 | /* Alignment Interrupt */ | 
|  | 305 | ALIGNMENT_EXCEPTION | 
|  | 306 |  | 
|  | 307 | /* Program Interrupt */ | 
|  | 308 | PROGRAM_EXCEPTION | 
|  | 309 |  | 
|  | 310 | /* Floating Point Unavailable Interrupt */ | 
|  | 311 | #ifdef CONFIG_PPC_FPU | 
|  | 312 | FP_UNAVAILABLE_EXCEPTION | 
|  | 313 | #else | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 314 | EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 315 | #endif | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 316 | /* System Call Interrupt */ | 
|  | 317 | START_EXCEPTION(SystemCall) | 
|  | 318 | NORMAL_EXCEPTION_PROLOG | 
|  | 319 | EXC_XFER_EE_LITE(0x0c00, DoSyscall) | 
|  | 320 |  | 
|  | 321 | /* Auxillary Processor Unavailable Interrupt */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 322 | EXCEPTION(0x2020, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 323 |  | 
|  | 324 | /* Decrementer Interrupt */ | 
|  | 325 | DECREMENTER_EXCEPTION | 
|  | 326 |  | 
|  | 327 | /* Fixed Internal Timer Interrupt */ | 
|  | 328 | /* TODO: Add FIT support */ | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 329 | EXCEPTION(0x1010, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 330 |  | 
|  | 331 | /* Watchdog Timer Interrupt */ | 
|  | 332 | /* TODO: Add watchdog support */ | 
|  | 333 | #ifdef CONFIG_BOOKE_WDT | 
|  | 334 | CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException) | 
|  | 335 | #else | 
| Stephen Rothwell | dc1c1ca | 2005-10-01 18:43:42 +1000 | [diff] [blame] | 336 | CRITICAL_EXCEPTION(0x1020, WatchdogTimer, unknown_exception) | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 337 | #endif | 
|  | 338 |  | 
|  | 339 | /* Data TLB Error Interrupt */ | 
|  | 340 | START_EXCEPTION(DataTLBError) | 
|  | 341 | mtspr	SPRN_SPRG0, r10		/* Save some working registers */ | 
|  | 342 | mtspr	SPRN_SPRG1, r11 | 
|  | 343 | mtspr	SPRN_SPRG4W, r12 | 
|  | 344 | mtspr	SPRN_SPRG5W, r13 | 
|  | 345 | mfcr	r11 | 
|  | 346 | mtspr	SPRN_SPRG7W, r11 | 
|  | 347 | mfspr	r10, SPRN_DEAR		/* Get faulting address */ | 
|  | 348 |  | 
|  | 349 | /* If we are faulting a kernel address, we have to use the | 
|  | 350 | * kernel page tables. | 
|  | 351 | */ | 
| Kumar Gala | 8a13c4f | 2007-10-11 13:36:52 -0500 | [diff] [blame] | 352 | lis	r11, PAGE_OFFSET@h | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 353 | cmplw	r10, r11 | 
|  | 354 | blt+	3f | 
|  | 355 | lis	r11, swapper_pg_dir@h | 
|  | 356 | ori	r11, r11, swapper_pg_dir@l | 
|  | 357 |  | 
|  | 358 | mfspr	r12,SPRN_MMUCR | 
|  | 359 | rlwinm	r12,r12,0,0,23		/* Clear TID */ | 
|  | 360 |  | 
|  | 361 | b	4f | 
|  | 362 |  | 
|  | 363 | /* Get the PGD for the current thread */ | 
|  | 364 | 3: | 
|  | 365 | mfspr	r11,SPRN_SPRG3 | 
|  | 366 | lwz	r11,PGDIR(r11) | 
|  | 367 |  | 
|  | 368 | /* Load PID into MMUCR TID */ | 
|  | 369 | mfspr	r12,SPRN_MMUCR | 
|  | 370 | mfspr   r13,SPRN_PID		/* Get PID */ | 
|  | 371 | rlwimi	r12,r13,0,24,31		/* Set TID */ | 
|  | 372 |  | 
|  | 373 | 4: | 
|  | 374 | mtspr	SPRN_MMUCR,r12 | 
|  | 375 |  | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 376 | /* Mask of required permission bits. Note that while we | 
|  | 377 | * do copy ESR:ST to _PAGE_RW position as trying to write | 
|  | 378 | * to an RO page is pretty common, we don't do it with | 
|  | 379 | * _PAGE_DIRTY. We could do it, but it's a fairly rare | 
|  | 380 | * event so I'd rather take the overhead when it happens | 
|  | 381 | * rather than adding an instruction here. We should measure | 
|  | 382 | * whether the whole thing is worth it in the first place | 
|  | 383 | * as we could avoid loading SPRN_ESR completely in the first | 
|  | 384 | * place... | 
|  | 385 | * | 
|  | 386 | * TODO: Is it worth doing that mfspr & rlwimi in the first | 
|  | 387 | *       place or can we save a couple of instructions here ? | 
|  | 388 | */ | 
|  | 389 | mfspr	r12,SPRN_ESR | 
|  | 390 | li	r13,_PAGE_PRESENT|_PAGE_ACCESSED | 
|  | 391 | rlwimi	r13,r12,10,30,30 | 
|  | 392 |  | 
|  | 393 | /* Load the PTE */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 394 | rlwinm 	r12, r10, 13, 19, 29	/* Compute pgdir/pmd offset */ | 
|  | 395 | lwzx	r11, r12, r11		/* Get pgd/pmd entry */ | 
|  | 396 | rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */ | 
|  | 397 | beq	2f			/* Bail if no table */ | 
|  | 398 |  | 
|  | 399 | rlwimi	r12, r10, 23, 20, 28	/* Compute pte address */ | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 400 | lwz	r11, 0(r12)		/* Get high word of pte entry */ | 
|  | 401 | lwz	r12, 4(r12)		/* Get low word of pte entry */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 402 |  | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 403 | lis	r10,tlb_44x_index@ha | 
|  | 404 |  | 
|  | 405 | andc.	r13,r13,r12		/* Check permission */ | 
|  | 406 |  | 
|  | 407 | /* Load the next available TLB index */ | 
|  | 408 | lwz	r13,tlb_44x_index@l(r10) | 
|  | 409 |  | 
|  | 410 | bne	2f			/* Bail if permission mismach */ | 
|  | 411 |  | 
|  | 412 | /* Increment, rollover, and store TLB index */ | 
|  | 413 | addi	r13,r13,1 | 
|  | 414 |  | 
|  | 415 | /* Compare with watermark (instruction gets patched) */ | 
|  | 416 | .globl tlb_44x_patch_hwater_D | 
|  | 417 | tlb_44x_patch_hwater_D: | 
|  | 418 | cmpwi	0,r13,1			/* reserve entries */ | 
|  | 419 | ble	5f | 
|  | 420 | li	r13,0 | 
|  | 421 | 5: | 
|  | 422 | /* Store the next available TLB index */ | 
|  | 423 | stw	r13,tlb_44x_index@l(r10) | 
|  | 424 |  | 
|  | 425 | /* Re-load the faulting address */ | 
|  | 426 | mfspr	r10,SPRN_DEAR | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 427 |  | 
|  | 428 | /* Jump to common tlb load */ | 
|  | 429 | b	finish_tlb_load | 
|  | 430 |  | 
|  | 431 | 2: | 
|  | 432 | /* The bailout.  Restore registers to pre-exception conditions | 
|  | 433 | * and call the heavyweights to help us out. | 
|  | 434 | */ | 
|  | 435 | mfspr	r11, SPRN_SPRG7R | 
|  | 436 | mtcr	r11 | 
|  | 437 | mfspr	r13, SPRN_SPRG5R | 
|  | 438 | mfspr	r12, SPRN_SPRG4R | 
|  | 439 | mfspr	r11, SPRN_SPRG1 | 
|  | 440 | mfspr	r10, SPRN_SPRG0 | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 441 | b	DataStorage | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 442 |  | 
|  | 443 | /* Instruction TLB Error Interrupt */ | 
|  | 444 | /* | 
|  | 445 | * Nearly the same as above, except we get our | 
|  | 446 | * information from different registers and bailout | 
|  | 447 | * to a different point. | 
|  | 448 | */ | 
|  | 449 | START_EXCEPTION(InstructionTLBError) | 
|  | 450 | mtspr	SPRN_SPRG0, r10		/* Save some working registers */ | 
|  | 451 | mtspr	SPRN_SPRG1, r11 | 
|  | 452 | mtspr	SPRN_SPRG4W, r12 | 
|  | 453 | mtspr	SPRN_SPRG5W, r13 | 
|  | 454 | mfcr	r11 | 
|  | 455 | mtspr	SPRN_SPRG7W, r11 | 
|  | 456 | mfspr	r10, SPRN_SRR0		/* Get faulting address */ | 
|  | 457 |  | 
|  | 458 | /* If we are faulting a kernel address, we have to use the | 
|  | 459 | * kernel page tables. | 
|  | 460 | */ | 
| Kumar Gala | 8a13c4f | 2007-10-11 13:36:52 -0500 | [diff] [blame] | 461 | lis	r11, PAGE_OFFSET@h | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 462 | cmplw	r10, r11 | 
|  | 463 | blt+	3f | 
|  | 464 | lis	r11, swapper_pg_dir@h | 
|  | 465 | ori	r11, r11, swapper_pg_dir@l | 
|  | 466 |  | 
|  | 467 | mfspr	r12,SPRN_MMUCR | 
|  | 468 | rlwinm	r12,r12,0,0,23		/* Clear TID */ | 
|  | 469 |  | 
|  | 470 | b	4f | 
|  | 471 |  | 
|  | 472 | /* Get the PGD for the current thread */ | 
|  | 473 | 3: | 
|  | 474 | mfspr	r11,SPRN_SPRG3 | 
|  | 475 | lwz	r11,PGDIR(r11) | 
|  | 476 |  | 
|  | 477 | /* Load PID into MMUCR TID */ | 
|  | 478 | mfspr	r12,SPRN_MMUCR | 
|  | 479 | mfspr   r13,SPRN_PID		/* Get PID */ | 
|  | 480 | rlwimi	r12,r13,0,24,31		/* Set TID */ | 
|  | 481 |  | 
|  | 482 | 4: | 
|  | 483 | mtspr	SPRN_MMUCR,r12 | 
|  | 484 |  | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 485 | /* Make up the required permissions */ | 
|  | 486 | li	r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC | 
|  | 487 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 488 | rlwinm	r12, r10, 13, 19, 29	/* Compute pgdir/pmd offset */ | 
|  | 489 | lwzx	r11, r12, r11		/* Get pgd/pmd entry */ | 
|  | 490 | rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */ | 
|  | 491 | beq	2f			/* Bail if no table */ | 
|  | 492 |  | 
|  | 493 | rlwimi	r12, r10, 23, 20, 28	/* Compute pte address */ | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 494 | lwz	r11, 0(r12)		/* Get high word of pte entry */ | 
|  | 495 | lwz	r12, 4(r12)		/* Get low word of pte entry */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 496 |  | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 497 | lis	r10,tlb_44x_index@ha | 
|  | 498 |  | 
|  | 499 | andc.	r13,r13,r12		/* Check permission */ | 
|  | 500 |  | 
|  | 501 | /* Load the next available TLB index */ | 
|  | 502 | lwz	r13,tlb_44x_index@l(r10) | 
|  | 503 |  | 
|  | 504 | bne	2f			/* Bail if permission mismach */ | 
|  | 505 |  | 
|  | 506 | /* Increment, rollover, and store TLB index */ | 
|  | 507 | addi	r13,r13,1 | 
|  | 508 |  | 
|  | 509 | /* Compare with watermark (instruction gets patched) */ | 
|  | 510 | .globl tlb_44x_patch_hwater_I | 
|  | 511 | tlb_44x_patch_hwater_I: | 
|  | 512 | cmpwi	0,r13,1			/* reserve entries */ | 
|  | 513 | ble	5f | 
|  | 514 | li	r13,0 | 
|  | 515 | 5: | 
|  | 516 | /* Store the next available TLB index */ | 
|  | 517 | stw	r13,tlb_44x_index@l(r10) | 
|  | 518 |  | 
|  | 519 | /* Re-load the faulting address */ | 
|  | 520 | mfspr	r10,SPRN_SRR0 | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 521 |  | 
|  | 522 | /* Jump to common TLB load point */ | 
|  | 523 | b	finish_tlb_load | 
|  | 524 |  | 
|  | 525 | 2: | 
|  | 526 | /* The bailout.  Restore registers to pre-exception conditions | 
|  | 527 | * and call the heavyweights to help us out. | 
|  | 528 | */ | 
|  | 529 | mfspr	r11, SPRN_SPRG7R | 
|  | 530 | mtcr	r11 | 
|  | 531 | mfspr	r13, SPRN_SPRG5R | 
|  | 532 | mfspr	r12, SPRN_SPRG4R | 
|  | 533 | mfspr	r11, SPRN_SPRG1 | 
|  | 534 | mfspr	r10, SPRN_SPRG0 | 
|  | 535 | b	InstructionStorage | 
|  | 536 |  | 
|  | 537 | /* Debug Interrupt */ | 
| Kumar Gala | eb0cd5f | 2008-04-09 06:06:11 -0500 | [diff] [blame] | 538 | DEBUG_CRIT_EXCEPTION | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 539 |  | 
|  | 540 | /* | 
|  | 541 | * Local functions | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 542 | */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 543 |  | 
|  | 544 | /* | 
|  | 545 |  | 
|  | 546 | * Both the instruction and data TLB miss get to this | 
|  | 547 | * point to load the TLB. | 
|  | 548 | * 	r10 - EA of fault | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 549 | * 	r11 - PTE high word value | 
|  | 550 | *	r12 - PTE low word value | 
|  | 551 | *	r13 - TLB index | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 552 | *	MMUCR - loaded with proper value when we get here | 
|  | 553 | *	Upon exit, we reload everything and RFI. | 
|  | 554 | */ | 
|  | 555 | finish_tlb_load: | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 556 | /* Combine RPN & ERPN an write WS 0 */ | 
|  | 557 | rlwimi	r11,r12,0,0,19 | 
|  | 558 | tlbwe	r11,r13,PPC44x_TLB_XLAT | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 559 |  | 
|  | 560 | /* | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 561 | * Create WS1. This is the faulting address (EPN), | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 562 | * page size, and valid flag. | 
|  | 563 | */ | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 564 | li	r11,PPC44x_TLB_VALID | PPC44x_TLB_4K | 
|  | 565 | rlwimi	r10,r11,0,20,31			/* Insert valid and page size*/ | 
|  | 566 | tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 567 |  | 
| Benjamin Herrenschmidt | 1bc54c0 | 2008-07-08 15:54:40 +1000 | [diff] [blame] | 568 | /* And WS 2 */ | 
|  | 569 | li	r10,0xf85			/* Mask to apply from PTE */ | 
|  | 570 | rlwimi	r10,r12,29,30,30		/* DIRTY -> SW position */ | 
|  | 571 | and	r11,r12,r10			/* Mask PTE bits to keep */ | 
|  | 572 | andi.	r10,r12,_PAGE_USER		/* User page ? */ | 
|  | 573 | beq	1f				/* nope, leave U bits empty */ | 
|  | 574 | rlwimi	r11,r11,3,26,28			/* yes, copy S bits to U */ | 
|  | 575 | 1:	tlbwe	r11,r13,PPC44x_TLB_ATTRIB	/* Write ATTRIB */ | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 576 |  | 
|  | 577 | /* Done...restore registers and get out of here. | 
|  | 578 | */ | 
|  | 579 | mfspr	r11, SPRN_SPRG7R | 
|  | 580 | mtcr	r11 | 
|  | 581 | mfspr	r13, SPRN_SPRG5R | 
|  | 582 | mfspr	r12, SPRN_SPRG4R | 
|  | 583 | mfspr	r11, SPRN_SPRG1 | 
|  | 584 | mfspr	r10, SPRN_SPRG0 | 
|  | 585 | rfi					/* Force context change */ | 
|  | 586 |  | 
|  | 587 | /* | 
|  | 588 | * Global functions | 
|  | 589 | */ | 
|  | 590 |  | 
|  | 591 | /* | 
| Benjamin Herrenschmidt | 47c0bd1 | 2007-12-21 15:39:21 +1100 | [diff] [blame] | 592 | * Adjust the machine check IVOR on 440A cores | 
|  | 593 | */ | 
|  | 594 | _GLOBAL(__fixup_440A_mcheck) | 
|  | 595 | li	r3,MachineCheckA@l | 
|  | 596 | mtspr	SPRN_IVOR1,r3 | 
|  | 597 | sync | 
|  | 598 | blr | 
|  | 599 |  | 
|  | 600 | /* | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 601 | * extern void giveup_altivec(struct task_struct *prev) | 
|  | 602 | * | 
|  | 603 | * The 44x core does not have an AltiVec unit. | 
|  | 604 | */ | 
|  | 605 | _GLOBAL(giveup_altivec) | 
|  | 606 | blr | 
|  | 607 |  | 
|  | 608 | /* | 
|  | 609 | * extern void giveup_fpu(struct task_struct *prev) | 
|  | 610 | * | 
|  | 611 | * The 44x core does not have an FPU. | 
|  | 612 | */ | 
|  | 613 | #ifndef CONFIG_PPC_FPU | 
|  | 614 | _GLOBAL(giveup_fpu) | 
|  | 615 | blr | 
|  | 616 | #endif | 
|  | 617 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 618 | _GLOBAL(set_context) | 
|  | 619 |  | 
|  | 620 | #ifdef CONFIG_BDI_SWITCH | 
|  | 621 | /* Context switch the PTE pointer for the Abatron BDI2000. | 
|  | 622 | * The PGDIR is the second parameter. | 
|  | 623 | */ | 
|  | 624 | lis	r5, abatron_pteptrs@h | 
|  | 625 | ori	r5, r5, abatron_pteptrs@l | 
|  | 626 | stw	r4, 0x4(r5) | 
|  | 627 | #endif | 
|  | 628 | mtspr	SPRN_PID,r3 | 
|  | 629 | isync			/* Force context change */ | 
|  | 630 | blr | 
|  | 631 |  | 
|  | 632 | /* | 
|  | 633 | * We put a few things here that have to be page-aligned. This stuff | 
|  | 634 | * goes at the beginning of the data segment, which is page-aligned. | 
|  | 635 | */ | 
|  | 636 | .data | 
| Kumar Gala | ea703ce | 2005-10-11 23:54:00 -0500 | [diff] [blame] | 637 | .align	12 | 
|  | 638 | .globl	sdata | 
|  | 639 | sdata: | 
|  | 640 | .globl	empty_zero_page | 
|  | 641 | empty_zero_page: | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 642 | .space	4096 | 
|  | 643 |  | 
|  | 644 | /* | 
|  | 645 | * To support >32-bit physical addresses, we use an 8KB pgdir. | 
|  | 646 | */ | 
| Kumar Gala | ea703ce | 2005-10-11 23:54:00 -0500 | [diff] [blame] | 647 | .globl	swapper_pg_dir | 
|  | 648 | swapper_pg_dir: | 
| Kumar Gala | bee86f1 | 2007-12-06 13:11:04 -0600 | [diff] [blame] | 649 | .space	PGD_TABLE_SIZE | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 650 |  | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 651 | /* | 
| Paul Mackerras | 14cf11a | 2005-09-26 16:04:21 +1000 | [diff] [blame] | 652 | * Room for two PTE pointers, usually the kernel and current user pointers | 
|  | 653 | * to their respective root page table. | 
|  | 654 | */ | 
|  | 655 | abatron_pteptrs: | 
|  | 656 | .space	8 |