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-2004 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/ibm44x.h> 39#include <asm/cputable.h> 40#include <asm/ppc_asm.h> 41#include "ppc_defs.h" 42 43/* 44 * Preprocessor Defines 45 */ 46 47#define STND_EXC 0 48#define CRIT_EXC 1 49 50#ifdef CONFIG_440A 51#define MCHK_EXC 2 52#define __SPRN_MCSRR0 SPRN_MCSRR0 53#define __SPRN_MCSRR1 SPRN_MCSRR1 54#else 55#define MCHK_EXC CRIT_EXC 56#define __SPRN_MCSRR0 SPRN_CSRR0 57#define __SPRN_MCSRR1 SPRN_CSRR1 58#endif 59 60/* 61 * Macros 62 */ 63 64#define SET_IVOR(vector_number, vector_label) \ 65 li r26,vector_label@l; \ 66 mtspr SPRN_IVOR##vector_number,r26; \ 67 sync 68 69/* As with the other PowerPC ports, it is expected that when code 70 * execution begins here, the following registers contain valid, yet 71 * optional, information: 72 * 73 * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) 74 * r4 - Starting address of the init RAM disk 75 * r5 - Ending address of the init RAM disk 76 * r6 - Start of kernel command line string (e.g. "mem=128") 77 * r7 - End of kernel command line string 78 * 79 */ 80 .text 81_GLOBAL(_stext) 82_GLOBAL(_start) 83 /* 84 * Reserve a word at a fixed location to store the address 85 * of abatron_pteptrs 86 */ 87 nop 88 89/* 90 * Save parameters we are passed 91 */ 92 mr r31,r3 93 mr r30,r4 94 mr r29,r5 95 mr r28,r6 96 mr r27,r7 97 li r24,0 /* CPU number */ 98 99/* 100 * Set up the initial MMU state 101 * 102 * We are still executing code at the virtual address 103 * mappings set by the firmware for the base of RAM. 104 * 105 * We first invalidate all TLB entries but the one 106 * we are running from. We then load the KERNELBASE 107 * mappings so we can begin to use kernel addresses 108 * natively and so the interrupt vector locations are 109 * permanently pinned (necessary since Book E 110 * implementations always have translation enabled). 111 * 112 * TODO: Use the known TLB entry we are running from to 113 * determine which physical region we are located 114 * in. This can be used to determine where in RAM 115 * (on a shared CPU system) or PCI memory space 116 * (on a DRAMless system) we are located. 117 * For now, we assume a perfect world which means 118 * we are located at the base of DRAM (physical 0). 119 */ 120 121/* 122 * Search TLB for entry that we are currently using. 123 * Invalidate all entries but the one we are using. 124 */ 125 /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ 126 mfspr r3,SPRN_MMUCR /* Get MMUCR */ 127 lis r4,PPC44x_MMUCR_STS@h 128 ori r4,r4,PPC44x_MMUCR_TID@l /* Create mask */ 129 andc r3,r3,r4 /* Clear out TID/STS bits */ 130 mfspr r4,SPRN_PID /* Get PID */ 131 or r3,r3,r4 /* Set TID bits */ 132 mfmsr r5 /* Get MSR */ 133 andi. r5,r5,MSR_IS@l /* TS=1? */ 134 beq wmmucr /* If not, leave STS=0 */ 135 oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ 136wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ 137 sync 138 139 bl invstr /* Find our address */ 140invstr: mflr r5 /* Make it accessible */ 141 tlbsx r23,0,r5 /* Find entry we are in */ 142 li r4,0 /* Start at TLB entry 0 */ 143 li r3,0 /* Set PAGEID inval value */ 1441: cmpw r23,r4 /* Is this our entry? */ 145 beq skpinv /* If so, skip the inval */ 146 tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ 147skpinv: addi r4,r4,1 /* Increment */ 148 cmpwi r4,64 /* Are we done? */ 149 bne 1b /* If not, repeat */ 150 isync /* If so, context change */ 151 152/* 153 * Configure and load pinned entries into TLB slots 62 and 63. 154 */ 155 156 lis r3,KERNELBASE@h /* Load the kernel virtual address */ 157 ori r3,r3,KERNELBASE@l 158 159 /* Kernel is at the base of RAM */ 160 li r4, 0 /* Load the kernel physical address */ 161 162 /* Load the kernel PID = 0 */ 163 li r0,0 164 mtspr SPRN_PID,r0 165 sync 166 167 /* Load the kernel TID = 0 */ 168 mfspr r5,SPRN_MMUCR 169 lis r6, PPC44x_MMUCR_TID@h 170 ori r6,r6,PPC44x_MMUCR_TID@l 171 andc r5,r5,r6 172 mtspr SPRN_MMUCR,r5 173 sync 174 175 /* pageid fields */ 176 clrrwi r3,r3,10 /* Mask off the effective page number */ 177 ori r3,r3,(PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M)) 178 179 /* xlat fields */ 180 clrrwi r4,r4,10 /* Mask off the real page number */ 181 /* ERPN is 0 for first 4GB page */ 182 183 /* attrib fields */ 184 /* Added guarded bit to protect against speculative loads/stores */ 185 li r5,0 186 ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) 187 188 li r0,62 /* TLB slot 62 */ 189 190 tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ 191 tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ 192 tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ 193 194 /* Force context change */ 195 mfmsr r0 196 mtspr SRR1, r0 197 lis r0,3f@h 198 ori r0,r0,3f@l 199 mtspr SRR0,r0 200 sync 201 rfi 202 203 /* If necessary, invalidate original entry we used */ 2043: cmpwi r23,62 205 beq 4f 206 li r6,0 207 tlbwe r6,r23,PPC44x_TLB_PAGEID 208 sync 209 2104: ori r3,r3,PPC44x_TLB_TS /* TS = 1 */ 211 212 li r0,63 /* TLB slot 63 */ 213 214 tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ 215 tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ 216 tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ 217 218#ifdef CONFIG_SERIAL_TEXT_DEBUG 219 /* 220 * Add temporary UART mapping for early debug. This 221 * mapping must be identical to that used by the early 222 * bootloader code since the same asm/serial.h parameters 223 * are used for polled operation. 224 */ 225 /* pageid fields */ 226 lis r3,0xe000 227 ori r3,r3,(PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M)) 228 229 /* xlat fields */ 230 lis r4,0x4000 /* RPN is 0x40000000 */ 231 ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */ 232 233 /* attrib fields */ 234 li r5,0 235 ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G) 236 237 li r0,60 /* TLB slot 60 */ 238 239 tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ 240 tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ 241 tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ 242 243 ori r3,r3,PPC44x_TLB_TS /* Translation state 1 */ 244 245 li r0,61 /* TLB slot 61 */ 246 247 tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ 248 tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ 249 tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ 250#endif /* CONFIG_SERIAL_TEXT_DEBUG */ 251 252 /* Force context change */ 253 isync 254 255 /* Establish the interrupt vector offsets */ 256 SET_IVOR(0, CriticalInput); 257 SET_IVOR(1, MachineCheck); 258 SET_IVOR(2, DataStorage); 259 SET_IVOR(3, InstructionStorage); 260 SET_IVOR(4, ExternalInput); 261 SET_IVOR(5, Alignment); 262 SET_IVOR(6, Program); 263 SET_IVOR(7, FloatingPointUnavailable); 264 SET_IVOR(8, SystemCall); 265 SET_IVOR(9, AuxillaryProcessorUnavailable); 266 SET_IVOR(10, Decrementer); 267 SET_IVOR(11, FixedIntervalTimer); 268 SET_IVOR(12, WatchdogTimer); 269 SET_IVOR(13, DataTLBError); 270 SET_IVOR(14, InstructionTLBError); 271 SET_IVOR(15, Debug); 272 273 /* Establish the interrupt vector base */ 274 lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ 275 mtspr SPRN_IVPR,r4 276 277 /* 278 * This is where the main kernel code starts. 279 */ 280 281 /* ptr to current */ 282 lis r2,init_task_union@h 283 ori r2,r2,init_task_union@l 284 285 /* ptr to current thread */ 286 addi r4,r2,THREAD /* init task's THREAD */ 287 mtspr SPRG3,r4 288 li r3,0 289 mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ 290 291 /* stack */ 292 addi r1,r2,TASK_UNION_SIZE 293 li r0,0 294 stwu r0,-STACK_FRAME_OVERHEAD(r1) 295 296 bl early_init 297 298/* 299 * Decide what sort of machine this is and initialize the MMU. 300 */ 301 mr r3,r31 302 mr r4,r30 303 mr r5,r29 304 mr r6,r28 305 mr r7,r27 306 bl machine_init 307 bl MMU_init 308 309 /* Setup PTE pointers for the Abatron bdiGDB */ 310 lis r6, swapper_pg_dir@h 311 ori r6, r6, swapper_pg_dir@l 312 lis r5, abatron_pteptrs@h 313 ori r5, r5, abatron_pteptrs@l 314 lis r4, KERNELBASE@h 315 ori r4, r4, KERNELBASE@l 316 stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ 317 stw r6, 0(r5) 318 319 /* Let's move on */ 320 lis r4,start_kernel@h 321 ori r4,r4,start_kernel@l 322 lis r3,MSR_KERNEL@h 323 ori r3,r3,MSR_KERNEL@l 324 mtspr SRR0,r4 325 mtspr SRR1,r3 326 rfi /* change context and jump to start_kernel */ 327 328/* 329 * Interrupt vector entry code 330 * 331 * The Book E MMUs are always on so we don't need to handle 332 * interrupts in real mode as with previous PPC processors. In 333 * this case we handle interrupts in the kernel virtual address 334 * space. 335 * 336 * Interrupt vectors are dynamically placed relative to the 337 * interrupt prefix as determined by the address of interrupt_base. 338 * The interrupt vectors offsets are programmed using the labels 339 * for each interrupt vector entry. 340 * 341 * Interrupt vectors must be aligned on a 16 byte boundary. 342 * We align on a 32 byte cache line boundary for good measure. 343 */ 344 345#define COMMON_PROLOG \ 3460: mtspr SPRN_SPRG0,r20; /* We need r20, move it to SPRG0 */\ 347 mtspr SPRN_SPRG1,r21; /* We need r21, move it to SPRG1 */\ 348 mfcr r20; /* We need the CR, move it to r20 */\ 349 mfspr r21,SPRN_SPRG2; /* Exception stack to use */\ 350 cmpwi cr0,r21,0; /* From user mode or RTAS? */\ 351 bne 1f; /* Not RTAS, branch */\ 352 mr r21, r1; /* Move vka in r1 to r21 */\ 353 subi r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame */\ 3541: stw r20,_CCR(r21); /* Save CR on the stack */\ 355 stw r22,GPR22(r21); /* Save r22 on the stack */\ 356 stw r23,GPR23(r21); /* r23 Save on the stack */\ 357 mfspr r20,SPRN_SPRG0; /* Get r20 back out of SPRG0 */\ 358 stw r20,GPR20(r21); /* Save r20 on the stack */\ 359 mfspr r22,SPRN_SPRG1; /* Get r21 back out of SPRG0 */\ 360 stw r22,GPR21(r21); /* Save r21 on the stack */\ 361 mflr r20; \ 362 stw r20,_LINK(r21); /* Save LR on the stack */\ 363 mfctr r22; \ 364 stw r22,_CTR(r21); /* Save CTR on the stack */\ 365 mfspr r20,XER; \ 366 stw r20,_XER(r21); /* Save XER on the stack */ 367 368#define COMMON_EPILOG \ 369 stw r0,GPR0(r21); /* Save r0 on the stack */\ 370 stw r1,GPR1(r21); /* Save r1 on the stack */\ 371 stw r2,GPR2(r21); /* Save r2 on the stack */\ 372 stw r1,0(r21); \ 373 mr r1,r21; /* Set-up new kernel stack pointer */\ 374 SAVE_4GPRS(3, r21); /* Save r3 through r6 on the stack */\ 375 SAVE_GPR(7, r21); /* Save r7 on the stack */ 376 377#define STND_EXCEPTION_PROLOG \ 378 COMMON_PROLOG; \ 379 mfspr r22,SPRN_SRR0; /* Faulting instruction address */\ 380 lis r20,MSR_WE@h; \ 381 mfspr r23,SPRN_SRR1; /* MSR at the time of fault */\ 382 andc r23,r23,r20; /* disable processor wait state */\ 383 COMMON_EPILOG; 384 385#define CRIT_EXCEPTION_PROLOG \ 386 COMMON_PROLOG; \ 387 mfspr r22,SPRN_CSRR0; /* Faulting instruction address */\ 388 lis r20,MSR_WE@h; \ 389 mfspr r23,SPRN_CSRR1; /* MSR at the time of fault */\ 390 andc r23,r23,r20; /* disable processor wait state */\ 391 COMMON_EPILOG; 392 393#define START_EXCEPTION(label) \ 394 .align 5; \ 395label: 396 397#define FINISH_EXCEPTION(n, func) \ 398 bl transfer_to_handler; \ 399 .long func; \ 400 .long ret_from_except; \ 401 .long n 402 403#define STND_EXCEPTION(n, label, func) \ 404 START_EXCEPTION(label) \ 405 STND_EXCEPTION_PROLOG; \ 406 addi r3,r1,STACK_FRAME_OVERHEAD; \ 407 li r7,STND_EXC; \ 408 li r20,MSR_KERNEL; \ 409 FINISH_EXCEPTION(n, func) 410 411#define CRIT_EXCEPTION(n, label, func) \ 412 START_EXCEPTION(label) \ 413 CRIT_EXCEPTION_PROLOG; \ 414 addi r3,r1,STACK_FRAME_OVERHEAD; \ 415 li r7,CRIT_EXC; \ 416 li r20,MSR_KERNEL; \ 417 FINISH_EXCEPTION(n, func) 418 419interrupt_base: 420 421 /* Critical Input Interrupt */ 422 CRIT_EXCEPTION(0x100, CriticalInput,UnknownException); 423 424 /* Machine Check Interrupt */ 425 /* TODO: provide bus error register status */ 426 START_EXCEPTION(MachineCheck) 427 COMMON_PROLOG; 428 mfspr r22,__SPRN_MCSRR0 /* Faulting instruction address */ 429 lis r20,MSR_WE@h 430 mfspr r23,__SPRN_MCSRR1 /* MSR at the time of fault */ 431 andc r23,r23,r20 /* disable processor wait state */ 432 COMMON_EPILOG; 433#ifdef CONFIG_440A 434 lis r20,MCSR_MCS@h 435 mfspr r4,SPRN_MCSR /* We may want to access original 436 MCSR as arg2 in the future. --ebs */ 437 mtspr SPRN_MCSR,r20 /* Clear Machine Check Summary field */ 438#endif 439 mfspr r5,SPRN_ESR /* Grab the ESR, save it */ 440 stw r5,_ESR(r21) 441 addi r3,r1,STACK_FRAME_OVERHEAD 442 li r7,MCHK_EXC 443 li r20,MSR_KERNEL 444 FINISH_EXCEPTION(0x200, MachineCheckException) 445 446 /* Data Storage Interrupt */ 447 START_EXCEPTION(DataStorage) 448 mtspr SPRG0, r20 /* Save some working registers */ 449 mtspr SPRG1, r21 450 mtspr SPRG4W, r22 451 mtspr SPRG5W, r23 452 mtspr SPRG6W, r24 453 mfcr r21 454 mtspr SPRG7W, r21 455 456 /* 457 * Check if it was a store fault, if not then bail 458 * because a user tried to access a kernel or 459 * read-protected page. Otherwise, get the 460 * offending address and handle it. 461 */ 462 mfspr r20, SPRN_ESR 463 andis. r20, r20, ESR_DST@h 464 beq 2f 465 466 mfspr r20, SPRN_DEAR /* Get faulting address */ 467 468 /* If we are faulting a kernel address, we have to use the 469 * kernel page tables. 470 */ 471 andis. r21, r20, 0x8000 472 beq 3f 473 lis r21, swapper_pg_dir@h 474 ori r21, r21, swapper_pg_dir@l 475 476 mfspr r22,SPRN_MMUCR /* Set TID to 0 */ 477 li r23,PPC44x_MMUCR_TID@l 478 andc r22,r22,r23 479 mtspr SPRN_MMUCR,r22 480 481 b 4f 482 483 /* Get the PGD for the current thread */ 4843: 485 mfspr r21,SPRG3 486 lwz r21,PGDIR(r21) 487 488 /* Load MMUCR with our PID and STS=<current TS> */ 489 mfspr r22,SPRN_MMUCR /* Get MMUCR */ 490 lis r23,PPC44x_MMUCR_STS@h 491 ori r23,r23,PPC44x_MMUCR_TID@l /* Create mask */ 492 andc r22,r22,r23 /* Clear out TID/STS bits */ 493 mfspr r23,SPRN_PID /* Get PID */ 494 or r22,r22,r23 /* Set TID bits */ 495 mfspr r24,SPRN_SRR1 /* Get SRR1 */ 496 andi. r24,r24,MSR_IS@l /* TS=1? */ 497 beq 4f /* If not, leave STS=0 */ 498 oris r22,r22,PPC44x_MMUCR_STS@h /* Set STS=1 */ 499 mtspr SPRN_MMUCR,r22 5004: 501 rlwinm r22, r20, 13, 19, 29 /* Compute pgdir/pmd offset */ 502 lwzx r21, r22, r21 /* Get pgd/pmd entry */ 503 rlwinm. r22, r21, 0, 0, 20 /* Extract pt base address */ 504 beq 2f /* Bail if no table */ 505 506 rlwimi r22, r20, 23, 20, 28 /* Compute pte address */ 507 lwz r21, 4(r22) /* Get pte entry */ 508 509 andi. r23, r21, _PAGE_RW /* Is it writeable? */ 510 beq 2f /* Bail if not */ 511 512 /* Update 'changed'. 513 */ 514 ori r21, r21, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE 515 stw r21, 4(r22) /* Update Linux page table */ 516 517 /* FIXME: Staticly setting some permissions */ 518 li r23, 0x003f /* Set UX,UW,UR,SX,SW,SR */ 519 andi. r21,r21,0xffff /* Clear MS 16 bits */ 520 /* FIXME: Force attributes */ 521 ori r21,r21, 0x0100 /* Set G */ 522 /* FIXME: Already set in PTE */ 523 rlwimi r21,r23,0,26,31 /* Insert static perms */ 524 525 lis r23,0xffff 526 ori r23,r23,0x0fff /* Set U0-U3 mask */ 527 and r21,r21,r23 /* Clear U0-U3 */ 528 529 /* find the TLB index that caused the fault. It has to be here. */ 530 tlbsx r24, 0, r20 531 532 tlbwe r21, r24, PPC44x_TLB_ATTRIB /* Write ATTRIB */ 533 534 /* Done...restore registers and get out of here. 535 */ 536 mfspr r21, SPRG7R 537 mtcr r21 538 mfspr r24, SPRG6R 539 mfspr r23, SPRG5R 540 mfspr r22, SPRG4R 541 542 mfspr r21, SPRG1 543 mfspr r20, SPRG0 544 rfi /* Force context change */ 545 5462: 547 /* 548 * The bailout. Restore registers to pre-exception conditions 549 * and call the heavyweights to help us out. 550 */ 551 mfspr r21, SPRG7R 552 mtcr r21 553 mfspr r24, SPRG6R 554 mfspr r23, SPRG5R 555 mfspr r22, SPRG4R 556 557 mfspr r21, SPRG1 558 mfspr r20, SPRG0 559 b data_access 560 561 /* Instruction Storage Interrupt */ 562 START_EXCEPTION(InstructionStorage) 563 STND_EXCEPTION_PROLOG 564 mfspr r5,SPRN_ESR /* Grab the ESR, save it */ 565 stw r5,_ESR(r21) 566 mr r4,r22 /* Pass SRR0 as arg2 */ 567 li r5,0 /* Pass zero as arg3 */ 568 addi r3,r1,STACK_FRAME_OVERHEAD 569 li r7,STND_EXC 570 li r20,MSR_KERNEL 571 rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ 572 FINISH_EXCEPTION(0x400, do_page_fault)/* do_page_fault(regs, SRR0, SRR1) */ 573 574 /* External Input Interrupt */ 575 START_EXCEPTION(ExternalInput) 576 STND_EXCEPTION_PROLOG 577 addi r3,r1,STACK_FRAME_OVERHEAD 578 li r7,STND_EXC 579 li r20,MSR_KERNEL 580 li r4,0 581 bl transfer_to_handler 582_GLOBAL(do_IRQ_intercept) 583 .long do_IRQ 584 .long ret_from_intercept 585 .long 0x500 586 587 /* Alignment Interrupt */ 588 START_EXCEPTION(Alignment) 589 STND_EXCEPTION_PROLOG 590 mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ 591 stw r4,_DEAR(r21) 592 addi r3,r1,STACK_FRAME_OVERHEAD 593 li r7,STND_EXC 594 li r20,MSR_KERNEL 595 rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ 596 FINISH_EXCEPTION(0x600, AlignmentException) 597 598 /* Program Interrupt */ 599 START_EXCEPTION(Program) 600 STND_EXCEPTION_PROLOG 601 mfspr r4,SPRN_ESR /* Grab the ESR, save it */ 602 stw r4,_ESR(r21) 603 addi r3,r1,STACK_FRAME_OVERHEAD 604 li r7,STND_EXC 605 li r20,MSR_KERNEL 606 rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ 607 FINISH_EXCEPTION(0x700, ProgramCheckException) 608 609 /* Floating Point Unavailable Interrupt */ 610 STND_EXCEPTION(0x2010, FloatingPointUnavailable,UnknownException); 611 612 /* System Call Interrupt */ 613 START_EXCEPTION(SystemCall) 614 STND_EXCEPTION_PROLOG 615 stw r3,ORIG_GPR3(r21) 616 li r7,STND_EXC 617 li r20,MSR_KERNEL 618 rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ 619 FINISH_EXCEPTION(0xc00, DoSyscall) 620 621 /* Auxillary Processor Unavailable */ 622 STND_EXCEPTION(0x2020, AuxillaryProcessorUnavailable,UnknownException); 623 624 /* Decrementer Interrupt */ 625 START_EXCEPTION(Decrementer) 626 STND_EXCEPTION_PROLOG 627 lis r0,TSR_DIS@h /* Setup the DEC interrupt mask */ 628 mtspr SPRN_TSR,r0 /* Clear the DEC interrupt */ 629 addi r3,r1,STACK_FRAME_OVERHEAD 630 li r7,STND_EXC 631 li r20,MSR_KERNEL 632 bl transfer_to_handler 633_GLOBAL(timer_interrupt_intercept) 634 .long timer_interrupt 635 .long ret_from_intercept 636 .long 0x1000 637 638 /* Fixed Internal Timer Interrupt */ 639 /* TODO: Add FIT support */ 640 STND_EXCEPTION(0x1010, FixedIntervalTimer,UnknownException); 641 642 /* Watchdog Timer Interrupt */ 643 /* TODO: Add watchdog support */ 644 CRIT_EXCEPTION(0x1020, WatchdogTimer,UnknownException); 645 646 /* Data TLB Error Interrupt */ 647 START_EXCEPTION(DataTLBError) 648 mtspr SPRG0, r20 /* Save some working registers */ 649 mtspr SPRG1, r21 650 mtspr SPRG4W, r22 651 mtspr SPRG5W, r23 652 mtspr SPRG6W, r24 653 mfcr r21 654 mtspr SPRG7W, r21 655 mfspr r20, SPRN_DEAR /* Get faulting address */ 656 657 /* If we are faulting a kernel address, we have to use the 658 * kernel page tables. 659 */ 660 andis. r21, r20, 0x8000 661 beq 3f 662 lis r21, swapper_pg_dir@h 663 ori r21, r21, swapper_pg_dir@l 664 665 mfspr r22,SPRN_MMUCR /* Set TID to 0 */ 666 li r23,PPC44x_MMUCR_TID@l 667 andc r22,r22,r23 668 mtspr SPRN_MMUCR,r22 669 670 b 4f 671 672 /* Get the PGD for the current thread */ 6733: 674 mfspr r21,SPRG3 675 lwz r21,PGDIR(r21) 676 677 /* Load PID into MMUCR TID */ 678 li r23,PPC44x_MMUCR_TID@l /* Create mask */ 679 andc r22,r22,r23 /* Clear out TID/STS bits */ 680 mfspr r23,SPRN_PID /* Get PID */ 681 or r22,r22,r23 682 mtspr SPRN_MMUCR,r22 6834: 684 rlwinm r22, r20, 13, 19, 29 /* Compute pgdir/pmd offset */ 685 lwzx r21, r22, r21 /* Get pgd/pmd entry */ 686 rlwinm. r22, r21, 0, 0, 20 /* Extract pt base address */ 687 beq 2f /* Bail if no table */ 688 689 rlwimi r22, r20, 23, 20, 28 /* Compute pte address */ 690 lwz r21, 4(r22) /* Get pte entry */ 691 andi. r23, r21, _PAGE_PRESENT /* Is the page present? */ 692 beq 2f /* Bail if not present */ 693 694 ori r21, r21, _PAGE_ACCESSED 695 stw r21, 4(r22) 696 697 /* Jump to common tlb load */ 698 b finish_tlb_load 699 7002: 701 /* The bailout. Restore registers to pre-exception conditions 702 * and call the heavyweights to help us out. 703 */ 704 mfspr r21, SPRG7R 705 mtcr r21 706 mfspr r24, SPRG6R 707 mfspr r23, SPRG5R 708 mfspr r22, SPRG4R 709 mfspr r21, SPRG1 710 mfspr r20, SPRG0 711 b data_access 712 713 /* Instruction TLB Error Interrupt */ 714 /* 715 * Nearly the same as above, except we get our 716 * information from different registers and bailout 717 * to a different point. 718 */ 719 START_EXCEPTION(InstructionTLBError) 720 mtspr SPRG0, r20 /* Save some working registers */ 721 mtspr SPRG1, r21 722 mtspr SPRG4W, r22 723 mtspr SPRG5W, r23 724 mtspr SPRG6W, r24 725 mfcr r21 726 mtspr SPRG7W, r21 727 mfspr r20, SRR0 /* Get faulting address */ 728 729 /* If we are faulting a kernel address, we have to use the 730 * kernel page tables. 731 */ 732 andis. r21, r20, 0x8000 733 beq 3f 734 lis r21, swapper_pg_dir@h 735 ori r21, r21, swapper_pg_dir@l 736 737 mfspr r22,SPRN_MMUCR /* Set TID to 0 */ 738 li r23,PPC44x_MMUCR_TID@l 739 andc r22,r22,r23 740 mtspr SPRN_MMUCR,r22 741 742 b 4f 743 744 /* Get the PGD for the current thread */ 7453: 746 mfspr r21,SPRG3 747 lwz r21,PGDIR(r21) 748 749 /* Load PID into MMUCR TID */ 750 li r23,PPC44x_MMUCR_TID@l /* Create mask */ 751 andc r22,r23,r23 /* Clear out TID/STS bits */ 752 mfspr r23,SPRN_PID /* Get PID */ 753 or r22,r22,r23 754 mtspr SPRN_MMUCR,r22 755 7564: 757 rlwinm r22, r20, 13, 19, 29 /* Compute pgdir/pmd offset */ 758 lwzx r21, r22, r21 /* Get pgd/pmd entry */ 759 rlwinm. r22, r21, 0, 0, 20 /* Extract pt base address */ 760 beq 2f /* Bail if no table */ 761 762 rlwimi r22, r20, 23, 20, 28 /* Compute pte address */ 763 lwz r21, 4(r22) /* Get pte entry */ 764 andi. r23, r21, _PAGE_PRESENT /* Is the page present? */ 765 beq 2f /* Bail if not present */ 766 767 ori r21, r21, _PAGE_ACCESSED 768 stw r21, 4(r22) 769 770 /* Jump to common TLB load point */ 771 b finish_tlb_load 772 7732: 774 /* The bailout. Restore registers to pre-exception conditions 775 * and call the heavyweights to help us out. 776 */ 777 mfspr r21, SPRG7R 778 mtcr r21 779 mfspr r24, SPRG6R 780 mfspr r23, SPRG5R 781 mfspr r22, SPRG4R 782 mfspr r21, SPRG1 783 mfspr r20, SPRG0 784 b InstructionStorage 785 786/* Check for a single step debug exception while in an exception 787 * handler before state has been saved. This is to catch the case 788 * where an instruction that we are trying to single step causes 789 * an exception (eg ITLB/DTLB miss) and thus the first instruction of 790 * the exception handler generates a single step debug exception. 791 * 792 * If we get a debug trap on the first instruction of an exception handler, 793 * we reset the MSR_DE in the _exception handlers_ MSR (the debug trap is 794 * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). 795 * The exception handler was handling a non-critical interrupt, so it will 796 * save (and later restore) the MSR via SPRN_SRR1, which will still have 797 * the MSR_DE bit set. 798 */ 799 /* Debug Interrupt */ 800 START_EXCEPTION(Debug) 801 /* This first instruction was already executed by the exception 802 * handler and must be the first instruction of every exception 803 * handler. 804 */ 805 mtspr SPRN_SPRG0,r20 /* Save some working registers... */ 806 mtspr SPRN_SPRG1,r21 807 mtspr SPRN_SPRG4W,r22 808 mfcr r20 /* ..and the cr because we change it */ 809 810 mfspr r21,SPRN_CSRR1 /* MSR at the time of fault */ 811 andi. r21,r21,MSR_PR 812 bne+ 2f /* trapped from problem state */ 813 814 mfspr r21,SPRN_CSRR0 /* Faulting instruction address */ 815 lis r22, KERNELBASE@h 816 ori r22, r22, KERNELBASE@l 817 cmplw r21,r22 818 blt+ 2f /* addr below exception vectors */ 819 820 lis r22, Debug@h 821 ori r22, r22, Debug@l 822 cmplw r21,r22 823 bgt+ 2f /* addr above TLB exception vectors */ 824 825 lis r21,DBSR_IC@h /* Remove the trap status */ 826 mtspr SPRN_DBSR,r21 827 828 mfspr r21,SPRN_CSRR1 829 rlwinm r21,r21,0,23,21 /* clear MSR_DE */ 830 mtspr SPRN_CSRR1, r21 /* restore MSR at rcfi without DE */ 831 832 mtcrf 0xff,r20 /* restore registers */ 833 mfspr r22,SPRN_SPRG4R 834 mfspr r21,SPRN_SPRG1 835 mfspr r20,SPRN_SPRG0 836 837 sync 838 rfci /* return to the exception handler */ 839 b . /* prevent prefetch past rfci */ 840 8412: 842 mtcrf 0xff,r20 /* restore registers */ 843 mfspr r22,SPRN_SPRG4R 844 mfspr r21,SPRN_SPRG1 845 mfspr r20,SPRN_SPRG0 846 847 CRIT_EXCEPTION_PROLOG 848 addi r3,r1,STACK_FRAME_OVERHEAD 849 li r7,CRIT_EXC; 850 li r20,MSR_KERNEL 851 FINISH_EXCEPTION(0x2000, DebugException) 852 853/* 854 * Local functions 855 */ 856 857 /* 858 * Data TLB exceptions will bail out to this point 859 * if they can't resolve the lightweight TLB fault. 860 */ 861data_access: 862 STND_EXCEPTION_PROLOG 863 mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ 864 stw r5,_ESR(r21) 865 mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ 866 stw r4,_DEAR(r21) 867 addi r3,r1,STACK_FRAME_OVERHEAD 868 li r7,STND_EXC 869 li r20,MSR_KERNEL 870 rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ 871 FINISH_EXCEPTION(0x800, do_page_fault) /* do_page_fault(regs, ESR, DEAR) */ 872 873/* 874 * Both the instruction and data TLB miss get to this 875 * point to load the TLB. 876 * r20 - EA of fault 877 * r21 - available to use 878 * r22 - Pointer to the 64-bit PTE 879 * r23 - available to use 880 * r24 - available to use 881 * MMUCR - loaded with proper value when we get here 882 * Upon exit, we reload everything and RFI. 883 */ 884finish_tlb_load: 885 /* 886 * We set execute, because we don't have the granularity to 887 * properly set this at the page level (Linux problem). 888 * If shared is set, we cause a zero PID->TID load. 889 * Many of these bits are software only. Bits we don't set 890 * here we (properly should) assume have the appropriate value. 891 */ 892 893 /* Load the next available TLB index */ 894 lis r23, tlb_44x_index@h 895 ori r23, r23, tlb_44x_index@l 896 lwz r24, 0(r23) 897 /* Load the TLB high watermark */ 898 lis r23, tlb_44x_hwater@h 899 ori r23, r23, tlb_44x_hwater@l 900 lwz r21, 0(r23) 901 902 903 /* Increment, rollover, and store TLB index */ 904 addi r24, r24, 1 905 cmpw 0, r24, r21 /* reserve entries 62-63 for kernel */ 906 ble 7f 907 li r24, 0 9087: 909 /* Load the next available TLB index */ 910 lis r23, tlb_44x_index@h 911 ori r23, r23, tlb_44x_index@l 912 stw r24, 0(r23) 913 9146: 915 lwz r23, 0(r22) /* Get MS word of PTE */ 916 lwz r21, 4(r22) /* Get LS word of PTE */ 917 rlwimi r23, r21, 0, 0 , 19 /* Insert RPN */ 918 tlbwe r23, r24, PPC44x_TLB_XLAT /* Write XLAT */ 919 920 /* 921 * Create PAGEID. This is the faulting address plus 922 * a set of static bits. The static bits are page 923 * size and valid. Bits 20 and 21 should be zero 924 * for a page size of 4KB. 925 */ 926 li r22, 0x0210 /* Set size and valid */ 927 mfspr r23, SPRN_SRR1 /* Get SRR1 */ 928 andi. r23, r23, MSR_IS@l 929 beq 7f 930 ori r22, r22, PPC44x_TLB_TS@l /* Set TS=1 */ 9317: rlwimi r20, r22, 0, 20, 31 /* Insert statics */ 932 tlbwe r20, r24, PPC44x_TLB_PAGEID /* Write PAGEID */ 933 934 /* FIXME: Staticly setting some permissions */ 935 li r23, 0x002d /* Set UX,UR,SX,SR */ 936 andi. r21, r21, 0xffff /* Clear MS 16 bits */ 937 andi. r22, r21, 0x0002 /* _PAGE_HWWRITE? */ 938 beq 8f 939 ori r23, r23, 0x0002 /* Set SW */ 940 /* FIXME: Force attributes */ 9418: ori r21, r21, 0x0100 /* Set G */ 942 /* FIXME: Already set in PTE */ 943 rlwimi r21, r23, 0, 26, 31 /* Insert static perms */ 944 945 lis r23,0xffff 946 ori r23,r23,0x0fff /* Set U0-U3 mask */ 947 and r21,r21,r23 /* Clear U0-U3 */ 948 tlbwe r21, r24, PPC44x_TLB_ATTRIB /* Write ATTRIB */ 949 950 /* Done...restore registers and get out of here. 951 */ 952 mfspr r21, SPRG7R 953 mtcr r21 954 mfspr r24, SPRG6R 955 mfspr r23, SPRG5R 956 mfspr r22, SPRG4R 957 mfspr r21, SPRG1 958 mfspr r20, SPRG0 959 rfi /* Force context change */ 960 961/* 962 * Global functions 963 */ 964 965/* 966 * extern void giveup_altivec(struct task_struct *prev) 967 * 968 * The 44x core does not have an AltiVec unit. 969 */ 970_GLOBAL(giveup_altivec) 971 blr 972 973/* 974 * extern void giveup_fpu(struct task_struct *prev) 975 * 976 * The 44x core does not have an FPU. 977 */ 978_GLOBAL(giveup_fpu) 979 blr 980 981/* 982 * extern void abort(void) 983 * 984 * At present, this routine just applies a system reset. 985 */ 986_GLOBAL(abort) 987 mfspr r13,SPRN_DBCR0 988 oris r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h 989 mtspr SPRN_DBCR0,r13 990 991_GLOBAL(set_context) 992 993#ifdef CONFIG_BDI_SWITCH 994 /* Context switch the PTE pointer for the Abatron BDI2000. 995 * The PGDIR is the second parameter. 996 */ 997 lis r5, abatron_pteptrs@h 998 ori r5, r5, abatron_pteptrs@l 999 stw r4, 0x4(r5) 1000#endif 1001 mtspr SPRN_PID,r3 1002 isync /* Force context change */ 1003 blr 1004 1005/* 1006 * This code finishes saving the registers to the exception frame 1007 * and jumps to the appropriate handler for the exception, turning 1008 * on address translation. 1009 */ 1010_GLOBAL(transfer_to_handler) 1011 stw r22,_NIP(r21) /* Save the faulting IP on the stack */ 1012 stw r23,_MSR(r21) /* Save the exception MSR on stack */ 1013 SAVE_4GPRS(8, r21) /* Save r8 through r11 on the stack */ 1014 SAVE_8GPRS(12, r21) /* Save r12 through r19 on the stack */ 1015 SAVE_8GPRS(24, r21) /* Save r24 through r31 on the stack */ 1016 andi. r23,r23,MSR_PR /* Is this from user space? */ 1017 mfspr r23,SPRN_SPRG3 /* If from user, fix up THREAD.regs */ 1018 beq 2f /* No, it is from the kernel; branch. */ 1019 mfspr r24,SPRN_DBCR0 1020 stw r24,THREAD_DBCR0(r23) /* Save Debug Control in thread_struct */ 1021 addi r24,r1,STACK_FRAME_OVERHEAD 1022 stw r24,PT_REGS(r23) 10232: addi r2,r23,-THREAD /* Set r2 to current thread */ 1024 mflr r23 1025 lwz r24,8(r23) /* Emulate classic PPC vectors */ 1026 stw r24,TRAP(r21) 1027 li r22,RESULT 1028 /* No need to put an erratum #77 workaround here 1029 because interrupts are currently disabled */ 1030 stwcx. r22,r22,r21 /* Clear the reservation */ 1031 li r22,0 1032 stw r22,RESULT(r21) 1033 mtspr SPRN_SPRG2,r22 /* r1 is now the kernel stack pointer */ 1034 addi r24,r2,TASK_STRUCT_SIZE /* Check for kernel stack overflow */ 1035 cmplw cr0,r1,r2 1036 cmplw cr1,r1,r24 1037 crand cr1,cr1,cr4 1038 bgt- stack_ovf /* If r2 < r1 < r2 + TASK_STRUCT_SIZE */ 1039 lwz r24,0(r23) /* Virtual address of the handler */ 1040 lwz r23,4(r23) /* Handler return pointer */ 1041 cmpwi cr0,r7,STND_EXC /* What type of exception is this? */ 1042 bne 3f /* It is a critical/machine check exception... */ 1043 1044 /* Standard exception jump path 1045 */ 1046 1047 /* We have to recover r7 from the register save stack. 1048 * It was used to indicate standard/critical exception. In 1049 * the case of a standard exception that is the system call 1050 * trap, it may have originally contained one of the syscall 1051 * parameters and we have to get it back now. 1052 */ 1053 lwz r7,GPR7(r21) 1054 mtspr SPRN_SRR0,r24 /* Set up the instruction pointer */ 1055 mtspr SPRN_SRR1,r20 /* Set up the machine state register */ 1056 mtlr r23 /* Set up the return pointer */ 1057 SYNC 1058 rfi 1059 1060 /* Critical/Machine check exception jump path 1061 */ 10623: cmpwi r7,CRIT_EXC /* Critical or machine check ? */ 1063 mtlr r23 /* Set up the return pointer */ 1064 bne 4f 1065 mtspr SPRN_CSRR0,r24 /* Set up the instruction pointer */ 1066 mtspr SPRN_CSRR1,r20 /* Set up the machine state register */ 1067 SYNC 1068 rfci 1069 10704: mtspr SPRN_MCSRR0,r24 /* Set up the instruction pointer */ 1071 mtspr SPRN_MCSRR1,r20 /* Set up the machine state register */ 1072 SYNC 1073 RFMCI 1074 1075/* On kernel stack overlow, load up an initial stack pointer and call 1076 * StackOverflow(regs), which should NOT return. 1077 */ 1078 1079stack_ovf: 1080 addi r3,r1,STACK_FRAME_OVERHEAD 1081 lis r1,init_task_union@ha 1082 addi r1,r1,init_task_union@l 1083 addi r1,r1,TASK_UNION_SIZE - STACK_FRAME_OVERHEAD 1084 lis r24,StackOverflow@ha 1085 addi r24,r24,StackOverflow@l 1086 li r20,MSR_KERNEL 1087 mtspr SPRN_SRR0,r24 1088 mtspr SPRN_SRR1,r20 1089 SYNC 1090 rfi 1091 1092/* 1093 * We put a few things here that have to be page-aligned. This stuff 1094 * goes at the beginning of the data segment, which is page-aligned. 1095 */ 1096 .data 1097_GLOBAL(sdata) 1098_GLOBAL(empty_zero_page) 1099 .space 4096 1100 1101/* 1102 * To support >32-bit physical addresses, we use an 8KB pgdir. 1103 */ 1104_GLOBAL(swapper_pg_dir) 1105 .space 8192 1106 1107/* 1108 * This space gets a copy of optional info passed to us by the bootstrap 1109 * which is used to pass parameters into the kernel like root=/dev/sda1, etc. 1110 */ 1111_GLOBAL(cmd_line) 1112 .space 512 1113 1114/* 1115 * Room for two PTE pointers, usually the kernel and current user pointers 1116 * to their respective root page table. 1117 */ 1118abatron_pteptrs: 1119 .space 8 1120